/*! cash-dom 1.3.5, https://github.com/kenwheeler/cash @license MIT */
if (typeof Component !== 'function') {
  (function (factory) {
    window.cash = factory();
  })(function () {
    var doc = document, win = window, ArrayProto = Array.prototype, slice = ArrayProto.slice, filter = ArrayProto.filter, push = ArrayProto.push;

    var noop = function () { }, isFunction = function (item) {
      // @see https://crbug.com/568448
      return typeof item === typeof noop && item.call;
    }, isString = function (item) {
      return typeof item === typeof "";
    };

    var idMatch = /^#[\w-]*$/, classMatch = /^\.[\w-]*$/, htmlMatch = /<.+>/, singlet = /^\w+$/;

    function find (selector, context) {
      context = context || doc;
      var elems = (classMatch.test(selector) ? context.getElementsByClassName(selector.slice(1)) : singlet.test(selector) ? context.getElementsByTagName(selector) : context.querySelectorAll(selector));
      return elems;
    }

    var frag;
    function parseHTML (str) {
      if (!frag) {
        frag = doc.implementation.createHTMLDocument(null);
        var base = frag.createElement("base");
        base.href = doc.location.href;
        frag.head.appendChild(base);
      }

      frag.body.innerHTML = str;

      return frag.body.childNodes;
    }

    function onReady (fn) {
      if (doc.readyState !== "loading") {
        fn();
      } else {
        doc.addEventListener("DOMContentLoaded", fn);
      }
    }

    function Init (selector, context) {
      if (!selector) {
        return this;
      }

      // If already a cash collection, don't do any further processing
      if (selector.cash && selector !== win) {
        return selector;
      }

      var elems = selector, i = 0, length;

      if (isString(selector)) {
        elems = (idMatch.test(selector) ?
          // If an ID use the faster getElementById check
          doc.getElementById(selector.slice(1)) : htmlMatch.test(selector) ?
            // If HTML, parse it into real elements
            parseHTML(selector) :
            // else use `find`
            find(selector, context));

        // If function, use as shortcut for DOM ready
      } else if (isFunction(selector)) {
        onReady(selector); return this;
      }

      if (!elems) {
        return this;
      }

      // If a single DOM element is passed in or received via ID, return the single element
      if (elems.nodeType || elems === win) {
        this[0] = elems;
        this.length = 1;
      } else {
        // Treat like an array and loop through each item.
        length = this.length = elems.length;
        for (; i < length; i++) {
          this[i] = elems[i];
        }
      }

      return this;
    }

    function cash (selector, context) {
      return new Init(selector, context);
    }

    var fn = cash.fn = cash.prototype = Init.prototype = { // jshint ignore:line
      cash: true,
      length: 0,
      push: push,
      splice: ArrayProto.splice,
      map: ArrayProto.map,
      init: Init
    };

    Object.defineProperty(fn, "constructor", { value: cash });

    cash.parseHTML = parseHTML;
    cash.noop = noop;
    cash.isFunction = isFunction;
    cash.isString = isString;

    cash.extend = fn.extend = function (target) {
      target = target || {};

      var args = slice.call(arguments), length = args.length, i = 1;

      if (args.length === 1) {
        target = this;
        i = 0;
      }

      for (; i < length; i++) {
        if (!args[i]) {
          continue;
        }
        for (var key in args[i]) {
          if (args[i].hasOwnProperty(key)) {
            target[key] = args[i][key];
          }
        }
      }

      return target;
    };

    function each (collection, callback) {
      var l = collection.length, i = 0;

      for (; i < l; i++) {
        if (callback.call(collection[i], collection[i], i, collection) === false) {
          break;
        }
      }
    }

    function matches (el, selector) {
      var m = el && (el.matches || el.webkitMatchesSelector || el.mozMatchesSelector || el.msMatchesSelector || el.oMatchesSelector);
      return !!m && m.call(el, selector);
    }

    function getCompareFunction (selector) {
      return (
        /* Use browser's `matches` function if string */
        isString(selector) ? matches :
          /* Match a cash element */
          selector.cash ? function (el) {
            return selector.is(el);
          } :
            /* Direct comparison */
            function (el, selector) {
              return el === selector;
            });
    }

    function unique (collection) {
      return cash(slice.call(collection).filter(function (item, index, self) {
        return self.indexOf(item) === index;
      }));
    }

    cash.extend({
      merge: function (first, second) {
        var len = +second.length, i = first.length, j = 0;

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

        first.length = i;
        return first;
      },

      each: each,
      matches: matches,
      unique: unique,
      isArray: Array.isArray,
      isNumeric: function (n) {
        return !isNaN(parseFloat(n)) && isFinite(n);
      }

    });

    var uid = cash.uid = "_cash" + Date.now();

    function getDataCache (node) {
      return (node[uid] = node[uid] || {});
    }

    function setData (node, key, value) {
      return (getDataCache(node)[key] = value);
    }

    function getData (node, key) {
      var c = getDataCache(node);
      if (c[key] === undefined) {
        c[key] = node.dataset ? node.dataset[key] : cash(node).attr("data-" + key);
      }
      return c[key];
    }

    function removeData (node, key) {
      var c = getDataCache(node);
      if (c) {
        delete c[key];
      } else if (node.dataset) {
        delete node.dataset[key];
      } else {
        cash(node).removeAttr("data-" + name);
      }
    }

    fn.extend({
      data: function (name, value) {
        if (isString(name)) {
          return (value === undefined ? getData(this[0], name) : this.each(function (v) {
            return setData(v, name, value);
          }));
        }

        for (var key in name) {
          this.data(key, name[key]);
        }

        return this;
      },

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

    });

    var notWhiteMatch = /\S+/g;

    function getClasses (c) {
      return isString(c) && c.match(notWhiteMatch);
    }

    function hasClass (v, c) {
      return (v.classList ? v.classList.contains(c) : new RegExp("(^| )" + c + "( |$)", "gi").test(v.className));
    }

    function addClass (v, c, spacedName) {
      if (v.classList) {
        v.classList.add(c);
      } else if (spacedName.indexOf(" " + c + " ")) {
        v.className += " " + c;
      }
    }

    function removeClass (v, c) {
      if (v.classList) {
        v.classList.remove(c);
      } else {
        v.className = v.className.replace(c, "");
      }
    }

    fn.extend({
      addClass: function (c) {
        var classes = getClasses(c);

        return (classes ? this.each(function (v) {
          var spacedName = " " + v.className + " ";
          each(classes, function (c) {
            addClass(v, c, spacedName);
          });
        }) : this);
      },

      attr: function (name, value) {
        if (!name) {
          return undefined;
        }

        if (isString(name)) {
          if (value === undefined) {
            return this[0] ? this[0].getAttribute ? this[0].getAttribute(name) : this[0][name] : undefined;
          }

          return this.each(function (v) {
            if (v.setAttribute) {
              v.setAttribute(name, value);
            } else {
              v[name] = value;
            }
          });
        }

        for (var key in name) {
          this.attr(key, name[key]);
        }

        return this;
      },

      hasClass: function (c) {
        var check = false, classes = getClasses(c);
        if (classes && classes.length) {
          this.each(function (v) {
            check = hasClass(v, classes[0]);
            return !check;
          });
        }
        return check;
      },

      prop: function (name, value) {
        if (isString(name)) {
          return (value === undefined ? this[0][name] : this.each(function (v) {
            v[name] = value;
          }));
        }

        for (var key in name) {
          this.prop(key, name[key]);
        }

        return this;
      },

      removeAttr: function (name) {
        return this.each(function (v) {
          if (v.removeAttribute) {
            v.removeAttribute(name);
          } else {
            delete v[name];
          }
        });
      },

      removeClass: function (c) {
        if (!arguments.length) {
          return this.attr("class", "");
        }
        var classes = getClasses(c);
        return (classes ? this.each(function (v) {
          each(classes, function (c) {
            removeClass(v, c);
          });
        }) : this);
      },

      removeProp: function (name) {
        return this.each(function (v) {
          delete v[name];
        });
      },

      toggleClass: function (c, state) {
        if (state !== undefined) {
          return this[state ? "addClass" : "removeClass"](c);
        }
        var classes = getClasses(c);
        return (classes ? this.each(function (v) {
          var spacedName = " " + v.className + " ";
          each(classes, function (c) {
            if (hasClass(v, c)) {
              removeClass(v, c);
            } else {
              addClass(v, c, spacedName);
            }
          });
        }) : this);
      }
    });

    fn.extend({
      add: function (selector, context) {
        return unique(cash.merge(this, cash(selector, context)));
      },

      each: function (callback) {
        each(this, callback);
        return this;
      },

      eq: function (index) {
        return cash(this.get(index));
      },

      filter: function (selector) {
        if (!selector) {
          return this;
        }

        var comparator = (isFunction(selector) ? selector : getCompareFunction(selector));

        return cash(filter.call(this, function (e) {
          return comparator(e, selector);
        }));
      },

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

      get: function (index) {
        if (index === undefined) {
          return slice.call(this);
        }
        return (index < 0 ? this[index + this.length] : this[index]);
      },

      index: function (elem) {
        var child = elem ? cash(elem)[0] : this[0], collection = elem ? this : cash(child).parent().children();
        return slice.call(collection).indexOf(child);
      },

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

    });

    var camelCase = (function () {
      var camelRegex = /(?:^\w|[A-Z]|\b\w)/g, whiteSpace = /[\s-_]+/g;
      return function (str) {
        return str.replace(camelRegex, function (letter, index) {
          return letter[index === 0 ? "toLowerCase" : "toUpperCase"]();
        }).replace(whiteSpace, "");
      };
    }());

    var getPrefixedProp = (function () {
      var cache = {}, doc = document, div = doc.createElement("div"), style = div.style;

      return function (prop) {
        prop = camelCase(prop);
        if (cache[prop]) {
          return cache[prop];
        }

        var ucProp = prop.charAt(0).toUpperCase() + prop.slice(1), prefixes = ["webkit", "moz", "ms", "o"], props = (prop + " " + (prefixes).join(ucProp + " ") + ucProp).split(" ");

        each(props, function (p) {
          if (p in style) {
            cache[p] = prop = cache[prop] = p;
            return false;
          }
        });

        return cache[prop];
      };
    }());

    cash.prefixedProp = getPrefixedProp;
    cash.camelCase = camelCase;

    fn.extend({
      css: function (prop, value) {
        if (isString(prop)) {
          prop = getPrefixedProp(prop);
          return (arguments.length > 1 ? this.each(function (v) {
            return v.style[prop] = value;
          }) : win.getComputedStyle(this[0])[prop]);
        }

        for (var key in prop) {
          this.css(key, prop[key]);
        }

        return this;
      }

    });

    function compute (el, prop) {
      return parseInt(win.getComputedStyle(el[0], null)[prop], 10) || 0;
    }

    each(["Width", "Height"], function (v) {
      var lower = v.toLowerCase();

      fn[lower] = function () {
        return this[0].getBoundingClientRect()[lower];
      };

      fn["inner" + v] = function () {
        return this[0]["client" + v];
      };

      fn["outer" + v] = function (margins) {
        return this[0]["offset" + v] + (margins ? compute(this, "margin" + (v === "Width" ? "Left" : "Top")) + compute(this, "margin" + (v === "Width" ? "Right" : "Bottom")) : 0);
      };
    });

    function registerEvent (node, eventName, callback) {
      var eventCache = getData(node, "_cashEvents") || setData(node, "_cashEvents", {});
      eventCache[eventName] = eventCache[eventName] || [];
      eventCache[eventName].push(callback);
      node.addEventListener(eventName, callback);
    }

    function removeEvent (node, eventName, callback) {
      var events = getData(node, "_cashEvents"), eventCache = (events && events[eventName]), index;

      if (!eventCache) {
        return;
      }

      if (callback) {
        node.removeEventListener(eventName, callback);
        index = eventCache.indexOf(callback);
        if (index >= 0) {
          eventCache.splice(index, 1);
        }
      } else {
        each(eventCache, function (event) {
          node.removeEventListener(eventName, event);
        });
        eventCache = [];
      }
    }

    fn.extend({
      off: function (eventName, callback) {
        return this.each(function (v) {
          return removeEvent(v, eventName, callback);
        });
      },

      on: function (eventName, delegate, callback, runOnce) {
        // jshint ignore:line
        var originalCallback;
        if (!isString(eventName)) {
          for (var key in eventName) {
            this.on(key, delegate, eventName[key]);
          }
          return this;
        }

        if (isFunction(delegate)) {
          callback = delegate;
          delegate = null;
        }

        if (eventName === "ready") {
          onReady(callback);
          return this;
        }

        if (delegate) {
          originalCallback = callback;
          callback = function (e) {
            var t = e.target;
            while (!matches(t, delegate)) {
              if (t === this || t === null) {
                return (t = false);
              }

              t = t.parentNode;
            }

            if (t) {
              originalCallback.call(t, e);
            }
          };
        }

        return this.each(function (v) {
          var finalCallback = callback;
          if (runOnce) {
            finalCallback = function () {
              callback.apply(this, arguments);
              removeEvent(v, eventName, finalCallback);
            };
          }
          registerEvent(v, eventName, finalCallback);
        });
      },

      one: function (eventName, delegate, callback) {
        return this.on(eventName, delegate, callback, true);
      },

      ready: onReady,

      /**
       * Modified
       * Triggers browser event
       * @param String eventName
       * @param Object data - Add properties to event object
       */
      trigger: function (eventName, data) {
        if (document.createEvent) {
          let evt = document.createEvent('HTMLEvents');
          evt.initEvent(eventName, true, false);
          evt = this.extend(evt, data);
          return this.each(function (v) {
            return v.dispatchEvent(evt);
          });
        }
      }

    });

    function encode (name, value) {
      return "&" + encodeURIComponent(name) + "=" + encodeURIComponent(value).replace(/%20/g, "+");
    }

    function getSelectMultiple_ (el) {
      var values = [];
      each(el.options, function (o) {
        if (o.selected) {
          values.push(o.value);
        }
      });
      return values.length ? values : null;
    }

    function getSelectSingle_ (el) {
      var selectedIndex = el.selectedIndex;
      return selectedIndex >= 0 ? el.options[selectedIndex].value : null;
    }

    function getValue (el) {
      var type = el.type;
      if (!type) {
        return null;
      }
      switch (type.toLowerCase()) {
        case "select-one":
          return getSelectSingle_(el);
        case "select-multiple":
          return getSelectMultiple_(el);
        case "radio":
          return (el.checked) ? el.value : null;
        case "checkbox":
          return (el.checked) ? el.value : null;
        default:
          return el.value ? el.value : null;
      }
    }

    fn.extend({
      serialize: function () {
        var query = "";

        each(this[0].elements || this, function (el) {
          if (el.disabled || el.tagName === "FIELDSET") {
            return;
          }
          var name = el.name;
          switch (el.type.toLowerCase()) {
            case "file":
            case "reset":
            case "submit":
            case "button":
              break;
            case "select-multiple":
              var values = getValue(el);
              if (values !== null) {
                each(values, function (value) {
                  query += encode(name, value);
                });
              }
              break;
            default:
              var value = getValue(el);
              if (value !== null) {
                query += encode(name, value);
              }
          }
        });

        return query.substr(1);
      },

      val: function (value) {
        if (value === undefined) {
          return getValue(this[0]);
        }

        return this.each(function (v) {
          return v.value = value;
        });
      }

    });

    function insertElement (el, child, prepend) {
      if (prepend) {
        var first = el.childNodes[0];
        el.insertBefore(child, first);
      } else {
        el.appendChild(child);
      }
    }

    function insertContent (parent, child, prepend) {
      var str = isString(child);

      if (!str && child.length) {
        each(child, function (v) {
          return insertContent(parent, v, prepend);
        });
        return;
      }

      each(parent, str ? function (v) {
        return v.insertAdjacentHTML(prepend ? "afterbegin" : "beforeend", child);
      } : function (v, i) {
        return insertElement(v, (i === 0 ? child : child.cloneNode(true)), prepend);
      });
    }

    fn.extend({
      after: function (selector) {
        cash(selector).insertAfter(this);
        return this;
      },

      append: function (content) {
        insertContent(this, content);
        return this;
      },

      appendTo: function (parent) {
        insertContent(cash(parent), this);
        return this;
      },

      before: function (selector) {
        cash(selector).insertBefore(this);
        return this;
      },

      clone: function () {
        return cash(this.map(function (v) {
          return v.cloneNode(true);
        }));
      },

      empty: function () {
        this.html("");
        return this;
      },

      html: function (content) {
        if (content === undefined) {
          return this[0].innerHTML;
        }
        var source = (content.nodeType ? content[0].outerHTML : content);
        return this.each(function (v) {
          return v.innerHTML = source;
        });
      },

      insertAfter: function (selector) {
        var _this = this;


        cash(selector).each(function (el, i) {
          var parent = el.parentNode, sibling = el.nextSibling;
          _this.each(function (v) {
            parent.insertBefore((i === 0 ? v : v.cloneNode(true)), sibling);
          });
        });

        return this;
      },

      insertBefore: function (selector) {
        var _this2 = this;
        cash(selector).each(function (el, i) {
          var parent = el.parentNode;
          _this2.each(function (v) {
            parent.insertBefore((i === 0 ? v : v.cloneNode(true)), el);
          });
        });
        return this;
      },

      prepend: function (content) {
        insertContent(this, content, true);
        return this;
      },

      prependTo: function (parent) {
        insertContent(cash(parent), this, true);
        return this;
      },

      remove: function () {
        return this.each(function (v) {
          if (!!v.parentNode) {
            return v.parentNode.removeChild(v);
          }
        });
      },

      text: function (content) {
        if (content === undefined) {
          return this[0].textContent;
        }
        return this.each(function (v) {
          return v.textContent = content;
        });
      }

    });

    var docEl = doc.documentElement;

    fn.extend({
      position: function () {
        var el = this[0];
        return {
          left: el.offsetLeft,
          top: el.offsetTop
        };
      },

      offset: function () {
        var rect = this[0].getBoundingClientRect();
        return {
          top: rect.top + win.pageYOffset - docEl.clientTop,
          left: rect.left + win.pageXOffset - docEl.clientLeft
        };
      },

      offsetParent: function () {
        return cash(this[0].offsetParent);
      }

    });

    fn.extend({
      children: function (selector) {
        var elems = [];
        this.each(function (el) {
          push.apply(elems, el.children);
        });
        elems = unique(elems);

        return (!selector ? elems : elems.filter(function (v) {
          return matches(v, selector);
        }));
      },

      closest: function (selector) {
        if (!selector || this.length < 1) {
          return cash();
        }
        if (this.is(selector)) {
          return this.filter(selector);
        }
        return this.parent().closest(selector);
      },

      is: function (selector) {
        if (!selector) {
          return false;
        }

        var match = false, comparator = getCompareFunction(selector);

        this.each(function (el) {
          match = comparator(el, selector);
          return !match;
        });

        return match;
      },

      find: function (selector) {
        if (!selector || selector.nodeType) {
          return cash(selector && this.has(selector).length ? selector : null);
        }

        var elems = [];
        this.each(function (el) {
          push.apply(elems, find(selector, el));
        });

        return unique(elems);
      },

      has: function (selector) {
        var comparator = (isString(selector) ? function (el) {
          return find(selector, el).length !== 0;
        } : function (el) {
          return el.contains(selector);
        });

        return this.filter(comparator);
      },

      next: function () {
        return cash(this[0].nextElementSibling);
      },

      not: function (selector) {
        if (!selector) {
          return this;
        }

        var comparator = getCompareFunction(selector);

        return this.filter(function (el) {
          return !comparator(el, selector);
        });
      },

      parent: function () {
        var result = [];

        this.each(function (item) {
          if (item && item.parentNode) {
            result.push(item.parentNode);
          }
        });

        return unique(result);
      },

      parents: function (selector) {
        var last, result = [];

        this.each(function (item) {
          last = item;

          while (last && last.parentNode && last !== doc.body.parentNode) {
            last = last.parentNode;

            if (!selector || (selector && matches(last, selector))) {
              result.push(last);
            }
          }
        });

        return unique(result);
      },

      prev: function () {
        return cash(this[0].previousElementSibling);
      },

      siblings: function (selector) {
        var collection = this.parent().children(selector), el = this[0];

        return collection.filter(function (i) {
          return i !== el;
        });
      }

    });


    return cash;
  });

  class Component {
    /**
     * Generic constructor for all components
     * @constructor
     * @param {Element} el
     * @param {Object} options
     */
    constructor (classDef, el, options) {
      // Display error if el is valid HTML Element
      if (!(el instanceof Element)) {
        console.error(Error(el + ' is not an HTML Element'));
      }

      // If exists, destroy and reinitialize in child
      let ins = classDef.getInstance(el);
      if (!!ins) {
        ins.destroy();
      }

      this.el = el;
      this.$el = cash(el);
    }

    /**
     * Initializes components
     * @param {class} classDef
     * @param {Element | NodeList | jQuery} els
     * @param {Object} options
     */
    static init (classDef, els, options) {
      let instances = null;
      if (els instanceof Element) {
        instances = new classDef(els, options);
      } else if (!!els && (els.jquery || els.cash || els instanceof NodeList)) {
        let instancesArr = [];
        for (let i = 0; i < els.length; i++) {
          instancesArr.push(new classDef(els[i], options));
        }
        instances = instancesArr;
      }

      return instances;
    }
  }

  // Required for Meteor package, the use of window prevents export by Meteor
  (function (window) {
    if (window.Package) {
      M = {};
    } else {
      window.M = {};
    }

    // Check for jQuery
    M.jQueryLoaded = !!window.jQuery;
  })(window);

  // AMD
  if (typeof define === 'function' && define.amd) {
    define('M', [], function () {
      return M;
    });

    // Common JS
  } else if (typeof exports !== 'undefined' && !exports.nodeType) {
    if (typeof module !== 'undefined' && !module.nodeType && module.exports) {
      exports = module.exports = M;
    }
    exports.default = M;
  }

  M.version = '1.0.0';

  M.keys = {
    TAB: 9,
    ENTER: 13,
    ESC: 27,
    ARROW_UP: 38,
    ARROW_DOWN: 40
  };

  /**
   * TabPress Keydown handler
   */
  M.tabPressed = false;
  M.keyDown = false;
  let docHandleKeydown = function (e) {
    M.keyDown = true;
    if (e.which === M.keys.TAB || e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) {
      M.tabPressed = true;
    }
  };
  let docHandleKeyup = function (e) {
    M.keyDown = false;
    if (e.which === M.keys.TAB || e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) {
      M.tabPressed = false;
    }
  };
  let docHandleFocus = function (e) {
    if (M.keyDown) {
      document.body.classList.add('keyboard-focused');
    }
  };
  let docHandleBlur = function (e) {
    document.body.classList.remove('keyboard-focused');
  };
  document.addEventListener('keydown', docHandleKeydown, true);
  document.addEventListener('keyup', docHandleKeyup, true);
  document.addEventListener('focus', docHandleFocus, true);
  document.addEventListener('blur', docHandleBlur, true);

  /**
   * Initialize jQuery wrapper for plugin
   * @param {Class} plugin  javascript class
   * @param {string} pluginName  jQuery plugin name
   * @param {string} classRef  Class reference name
   */
  M.initializeJqueryWrapper = function (plugin, pluginName, classRef) {
    jQuery.fn[pluginName] = function (methodOrOptions) {
      // Call plugin method if valid method name is passed in
      if (plugin.prototype[methodOrOptions]) {
        let params = Array.prototype.slice.call(arguments, 1);

        // Getter methods
        if (methodOrOptions.slice(0, 3) === 'get') {
          let instance = this.first()[0][classRef];
          return instance[methodOrOptions].apply(instance, params);
        }

        // Void methods
        return this.each(function () {
          let instance = this[classRef];
          instance[methodOrOptions].apply(instance, params);
        });

        // Initialize plugin if options or no argument is passed in
      } else if (typeof methodOrOptions === 'object' || !methodOrOptions) {
        plugin.init(this, arguments[0]);
        return this;
      }

      // Return error if an unrecognized  method name is passed in
      jQuery.error(`Method ${methodOrOptions} does not exist on jQuery.${pluginName}`);
    };
  };

  /**
   * Automatically initialize components
   * @param {Element} context  DOM Element to search within for components
   */
  M.AutoInit = function (context) {
    // Use document.body if no context is given
    let root = !!context ? context : document.body;

    let registry = {
      // Autocomplete: root.querySelectorAll('.autocomplete:not(.no-autoinit)'),
      // Carousel: root.querySelectorAll('.carousel:not(.no-autoinit)'),
      // Chips: root.querySelectorAll('.chips:not(.no-autoinit)'),
      Collapsible: root.querySelectorAll('.collapsible:not(.no-autoinit)'),
      // Datepicker: root.querySelectorAll('.datepicker:not(.no-autoinit)'),
      Dropdown: root.querySelectorAll('.dropdown-trigger:not(.no-autoinit)'),
      // Materialbox: root.querySelectorAll('.materialboxed:not(.no-autoinit)'),
      Modal: root.querySelectorAll('.modal:not(.no-autoinit)'),
      // Parallax: root.querySelectorAll('.parallax:not(.no-autoinit)'),
      // Pushpin: root.querySelectorAll('.pushpin:not(.no-autoinit)'),
      // ScrollSpy: root.querySelectorAll('.scrollspy:not(.no-autoinit)'),
      FormSelect: root.querySelectorAll('select:not(.no-autoinit)'),
      // Sidenav: root.querySelectorAll('.sidenav:not(.no-autoinit)'),
      // Tabs: root.querySelectorAll('.tabs:not(.no-autoinit)'),
      TapTarget: root.querySelectorAll('.tap-target:not(.no-autoinit)')
      // Timepicker: root.querySelectorAll('.timepicker:not(.no-autoinit)')
      // Tooltip: root.querySelectorAll('.tooltipped:not(.no-autoinit)'),
      // FloatingActionButton: root.querySelectorAll('.fixed-action-btn:not(.no-autoinit)')
    };

    for (let pluginName in registry) {
      let plugin = M[pluginName];
      plugin.init(registry[pluginName]);
    }
  };

  /**
   * Generate approximated selector string for a jQuery object
   * @param {jQuery} obj  jQuery object to be parsed
   * @returns {string}
   */
  M.objectSelectorString = function (obj) {
    let tagStr = obj.prop('tagName') || '';
    let idStr = obj.attr('id') || '';
    let classStr = obj.attr('class') || '';
    return (tagStr + idStr + classStr).replace(/\s/g, '');
  };

  // Unique Random ID
  M.guid = (function () {
    function s4 () {
      return Math.floor((1 + Math.random()) * 0x10000)
        .toString(16)
        .substring(1);
    }
    return function () {
      return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
    };
  })();

  /**
   * Escapes hash from special characters
   * @param {string} hash  String returned from this.hash
   * @returns {string}
   */
  M.escapeHash = function (hash) {
    return hash.replace(/(:|\.|\[|\]|,|=|\/)/g, '\\$1');
  };

  M.elementOrParentIsFixed = function (element) {
    let $element = $(element);
    let $checkElements = $element.add($element.parents());
    let isFixed = false;
    $checkElements.each(function () {
      if ($(this).css('position') === 'fixed') {
        isFixed = true;
        return false;
      }
    });
    return isFixed;
  };

  /**
   * @typedef {Object} Edges
   * @property {Boolean} top  If the top edge was exceeded
   * @property {Boolean} right  If the right edge was exceeded
   * @property {Boolean} bottom  If the bottom edge was exceeded
   * @property {Boolean} left  If the left edge was exceeded
   */

  /**
   * @typedef {Object} Bounding
   * @property {Number} left  left offset coordinate
   * @property {Number} top  top offset coordinate
   * @property {Number} width
   * @property {Number} height
   */

  /**
   * Escapes hash from special characters
   * @param {Element} container  Container element that acts as the boundary
   * @param {Bounding} bounding  element bounding that is being checked
   * @param {Number} offset  offset from edge that counts as exceeding
   * @returns {Edges}
   */
  M.checkWithinContainer = function (container, bounding, offset) {
    let edges = {
      top: false,
      right: false,
      bottom: false,
      left: false
    };

    let containerRect = container.getBoundingClientRect();
    // If body element is smaller than viewport, use viewport height instead.
    let containerBottom = container === document.body ? Math.max(containerRect.bottom, window.innerHeight) : containerRect.bottom;

    let scrollLeft = container.scrollLeft;
    let scrollTop = container.scrollTop;

    let scrolledX = bounding.left - scrollLeft;
    let scrolledY = bounding.top - scrollTop;

    // Check for container and viewport for each edge
    if (scrolledX < containerRect.left + offset || scrolledX < offset) {
      edges.left = true;
    }

    if (scrolledX + bounding.width > containerRect.right - offset || scrolledX + bounding.width > window.innerWidth - offset) {
      edges.right = true;
    }

    if (scrolledY < containerRect.top + offset || scrolledY < offset) {
      edges.top = true;
    }

    if (scrolledY + bounding.height > containerBottom - offset || scrolledY + bounding.height > window.innerHeight - offset) {
      edges.bottom = true;
    }

    return edges;
  };

  M.checkPossibleAlignments = function (el, container, bounding, offset) {
    let canAlign = {
      top: true,
      right: true,
      bottom: true,
      left: true,
      spaceOnTop: null,
      spaceOnRight: null,
      spaceOnBottom: null,
      spaceOnLeft: null
    };

    let containerAllowsOverflow = getComputedStyle(container).overflow === 'visible';
    let containerRect = container.getBoundingClientRect();
    let containerHeight = Math.min(containerRect.height, window.innerHeight);
    let containerWidth = Math.min(containerRect.width, window.innerWidth);
    let elOffsetRect = el.getBoundingClientRect();

    let scrollLeft = container.scrollLeft;
    let scrollTop = container.scrollTop;

    let scrolledX = bounding.left - scrollLeft;
    let scrolledYTopEdge = bounding.top - scrollTop;
    let scrolledYBottomEdge = bounding.top + elOffsetRect.height - scrollTop;

    // Check for container and viewport for left
    canAlign.spaceOnRight = !containerAllowsOverflow ? containerWidth - (scrolledX + bounding.width) : window.innerWidth - (elOffsetRect.left + bounding.width);
    if (canAlign.spaceOnRight < 0) {
      canAlign.left = false;
    }

    // Check for container and viewport for Right
    canAlign.spaceOnLeft = !containerAllowsOverflow ? scrolledX - bounding.width + elOffsetRect.width : elOffsetRect.right - bounding.width;
    if (canAlign.spaceOnLeft < 0) {
      canAlign.right = false;
    }

    // Check for container and viewport for Top
    canAlign.spaceOnBottom = !containerAllowsOverflow ? containerHeight - (scrolledYTopEdge + bounding.height + offset) : window.innerHeight - (elOffsetRect.top + bounding.height + offset);
    if (canAlign.spaceOnBottom < 0) {
      canAlign.top = false;
    }

    // Check for container and viewport for Bottom
    canAlign.spaceOnTop = !containerAllowsOverflow ? scrolledYBottomEdge - (bounding.height - offset) : elOffsetRect.bottom - (bounding.height + offset);
    if (canAlign.spaceOnTop < 0) {
      canAlign.bottom = false;
    }

    return canAlign;
  };

  M.getOverflowParent = function (element) {
    if (element == null) {
      return null;
    }

    if (element === document.body || getComputedStyle(element).overflow !== 'visible') {
      return element;
    }

    return M.getOverflowParent(element.parentElement);
  };

  /**
   * Gets id of component from a trigger
   * @param {Element} trigger  trigger
   * @returns {string}
   */
  M.getIdFromTrigger = function (trigger) {
    let id = trigger.getAttribute('data-target');
    if (!id) {
      id = trigger.getAttribute('href');
      if (id) {
        id = id.slice(1);
      } else {
        id = '';
      }
    }
    return id;
  };

  /**
   * Multi browser support for document scroll top
   * @returns {Number}
   */
  M.getDocumentScrollTop = function () {
    return window.pageYOffset || document.documentElement.scrollTop || document.body.scrollTop || 0;
  };

  /**
   * Multi browser support for document scroll left
   * @returns {Number}
   */
  M.getDocumentScrollLeft = function () {
    return window.pageXOffset || document.documentElement.scrollLeft || document.body.scrollLeft || 0;
  };

  /**
   * @typedef {Object} Edges
   * @property {Boolean} top  If the top edge was exceeded
   * @property {Boolean} right  If the right edge was exceeded
   * @property {Boolean} bottom  If the bottom edge was exceeded
   * @property {Boolean} left  If the left edge was exceeded
   */

  /**
   * @typedef {Object} Bounding
   * @property {Number} left  left offset coordinate
   * @property {Number} top  top offset coordinate
   * @property {Number} width
   * @property {Number} height
   */

  /**
   * Get time in ms
   * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
   * @type {function}
   * @return {number}
   */
  let getTime =
    Date.now ||
    function () {
      return new Date().getTime();
    };

  /**
   * Returns a function, that, when invoked, will only be triggered at most once
   * during a given window of time. Normally, the throttled function will run
   * as much as it can, without ever going more than once per `wait` duration;
   * but if you'd like to disable the execution on the leading edge, pass
   * `{leading: false}`. To disable execution on the trailing edge, ditto.
   * @license https://raw.github.com/jashkenas/underscore/master/LICENSE
   * @param {function} func
   * @param {number} wait
   * @param {Object=} options
   * @returns {Function}
   */
  M.throttle = function (func, wait, options) {
    let context, args, result;
    let timeout = null;
    let previous = 0;
    options || (options = {});
    let later = function () {
      previous = options.leading === false ? 0 : getTime();
      timeout = null;
      result = func.apply(context, args);
      context = args = null;
    };
    return function () {
      let now = getTime();
      if (!previous && options.leading === false) previous = now;
      let remaining = wait - (now - previous);
      context = this;
      args = arguments;
      if (remaining <= 0) {
        clearTimeout(timeout);
        timeout = null;
        previous = now;
        result = func.apply(context, args);
        context = args = null;
      } else if (!timeout && options.trailing !== false) {
        timeout = setTimeout(later, remaining);
      }
      return result;
    };
  };

  /*
   v2.2.0
   2017 Julian Garnier
   Released under the MIT license
  */
  var $jscomp = {
    scope: {}
  };

  $jscomp.defineProperty = "function" == typeof Object.defineProperties ? Object.defineProperty : function (e, r, p) {
    if (p.get || p.set) throw new TypeError("ES3 does not support getters and setters.");
    e != Array.prototype && e != Object.prototype && (e[r] = p.value);
  };

  $jscomp.getGlobal = function (e) {
    return "undefined" != typeof window && window === e ? e : "undefined" != typeof global && null != global ? global : e;
  };

  $jscomp.global = $jscomp.getGlobal(this);

  $jscomp.SYMBOL_PREFIX = "jscomp_symbol_";

  $jscomp.initSymbol = function () {
    $jscomp.initSymbol = function () { };
    $jscomp.global.Symbol || ($jscomp.global.Symbol = $jscomp.Symbol);
  };

  $jscomp.symbolCounter_ = 0;

  $jscomp.Symbol = function (e) {
    return $jscomp.SYMBOL_PREFIX + (e || "") + $jscomp.symbolCounter_++;
  };

  $jscomp.initSymbolIterator = function () {
    $jscomp.initSymbol();
    var e = $jscomp.global.Symbol.iterator;
    e || (e = $jscomp.global.Symbol.iterator = $jscomp.global.Symbol("iterator"));
    "function" != typeof Array.prototype[e] && $jscomp.defineProperty(Array.prototype, e, {
      configurable: !0,
      writable: !0,
      value: function () {
        return $jscomp.arrayIterator(this);
      }
    });
    $jscomp.initSymbolIterator = function () { };
  };

  $jscomp.arrayIterator = function (e) {
    var r = 0;
    return $jscomp.iteratorPrototype(function () {
      return r < e.length ? {
        done: !1,
        value: e[r++]
      } : {
        done: !0
      };
    });
  };

  $jscomp.iteratorPrototype = function (e) {
    $jscomp.initSymbolIterator();
    e = {
      next: e
    };
    e[$jscomp.global.Symbol.iterator] = function () {
      return this;
    };
    return e;
  };

  $jscomp.array = $jscomp.array || {};

  $jscomp.iteratorFromArray = function (e, r) {
    $jscomp.initSymbolIterator();
    e instanceof String && (e += "");
    var p = 0, m = {
      next: function () {
        if (p < e.length) {
          var u = p++;
          return {
            value: r(u, e[u]),
            done: !1
          };
        }
        m.next = function () {
          return {
            done: !0,
            value: void 0
          };
        };
        return m.next();
      }
    };
    m[Symbol.iterator] = function () {
      return m;
    };
    return m;
  };

  $jscomp.polyfill = function (e, r, p, m) {
    if (r) {
      p = $jscomp.global;
      e = e.split(".");
      for (m = 0; m < e.length - 1; m++) {
        var u = e[m];
        u in p || (p[u] = {});
        p = p[u];
      }
      e = e[e.length - 1];
      m = p[e];
      r = r(m);
      r != m && null != r && $jscomp.defineProperty(p, e, {
        configurable: !0,
        writable: !0,
        value: r
      });
    }
  };

  $jscomp.polyfill("Array.prototype.keys", function (e) {
    return e ? e : function () {
      return $jscomp.iteratorFromArray(this, function (e) {
        return e;
      });
    };
  }, "es6-impl", "es3");

  var $jscomp$this = this;

  (function (r) {
    M.anime = r();
  })(function () {
    function e (a) {
      if (!h.col(a)) try {
        return document.querySelectorAll(a);
      } catch (c) { }
    }
    function r (a, c) {
      for (var d = a.length, b = 2 <= arguments.length ? arguments[1] : void 0, f = [], n = 0; n < d; n++) if (n in a) {
        var k = a[n];
        c.call(b, k, n, a) && f.push(k);
      }
      return f;
    }
    function p (a) {
      return a.reduce(function (a, d) {
        return a.concat(h.arr(d) ? p(d) : d);
      }, []);
    }
    function m (a) {
      if (h.arr(a)) return a;
      h.str(a) && (a = e(a) || a);
      return a instanceof NodeList || a instanceof HTMLCollection ? [].slice.call(a) : [a];
    }
    function u (a, c) {
      return a.some(function (a) {
        return a === c;
      });
    }
    function C (a) {
      var c = {}, d;
      for (d in a) c[d] = a[d];
      return c;
    }
    function D (a, c) {
      var d = C(a), b;
      for (b in a) d[b] = c.hasOwnProperty(b) ? c[b] : a[b];
      return d;
    }
    function z (a, c) {
      var d = C(a), b;
      for (b in c) d[b] = h.und(a[b]) ? c[b] : a[b];
      return d;
    }
    function T (a) {
      a = a.replace(/^#?([a-f\d])([a-f\d])([a-f\d])$/i, function (a, c, d, k) {
        return c + c + d + d + k + k;
      });
      var c = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(a);
      a = parseInt(c[1], 16);
      var d = parseInt(c[2], 16), c = parseInt(c[3], 16);
      return "rgba(" + a + "," + d + "," + c + ",1)";
    }
    function U (a) {
      function c (a, c, b) {
        0 > b && (b += 1);
        1 < b && --b;
        return b < 1 / 6 ? a + 6 * (c - a) * b : .5 > b ? c : b < 2 / 3 ? a + (c - a) * (2 / 3 - b) * 6 : a;
      }
      var d = /hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/g.exec(a) || /hsla\((\d+),\s*([\d.]+)%,\s*([\d.]+)%,\s*([\d.]+)\)/g.exec(a);
      a = parseInt(d[1]) / 360;
      var b = parseInt(d[2]) / 100, f = parseInt(d[3]) / 100, d = d[4] || 1;
      if (0 == b) f = b = a = f; else {
        var n = .5 > f ? f * (1 + b) : f + b - f * b, k = 2 * f - n, f = c(k, n, a + 1 / 3), b = c(k, n, a);
        a = c(k, n, a - 1 / 3);
      }
      return "rgba(" + 255 * f + "," + 255 * b + "," + 255 * a + "," + d + ")";
    }
    function y (a) {
      if (a = /([\+\-]?[0-9#\.]+)(%|px|pt|em|rem|in|cm|mm|ex|ch|pc|vw|vh|vmin|vmax|deg|rad|turn)?$/.exec(a)) return a[2];
    }
    function V (a) {
      if (-1 < a.indexOf("translate") || "perspective" === a) return "px";
      if (-1 < a.indexOf("rotate") || -1 < a.indexOf("skew")) return "deg";
    }
    function I (a, c) {
      return h.fnc(a) ? a(c.target, c.id, c.total) : a;
    }
    function E (a, c) {
      if (c in a.style) return getComputedStyle(a).getPropertyValue(c.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase()) || "0";
    }
    function J (a, c) {
      if (h.dom(a) && u(W, c)) return "transform";
      if (h.dom(a) && (a.getAttribute(c) || h.svg(a) && a[c])) return "attribute";
      if (h.dom(a) && "transform" !== c && E(a, c)) return "css";
      if (null != a[c]) return "object";
    }
    function X (a, c) {
      var d = V(c), d = -1 < c.indexOf("scale") ? 1 : 0 + d;
      a = a.style.transform;
      if (!a) return d;
      for (var b = [], f = [], n = [], k = /(\w+)\((.+?)\)/g; b = k.exec(a);) f.push(b[1]),
        n.push(b[2]);
      a = r(n, function (a, b) {
        return f[b] === c;
      });
      return a.length ? a[0] : d;
    }
    function K (a, c) {
      switch (J(a, c)) {
        case "transform":
          return X(a, c);

        case "css":
          return E(a, c);

        case "attribute":
          return a.getAttribute(c);
      }
      return a[c] || 0;
    }
    function L (a, c) {
      var d = /^(\*=|\+=|-=)/.exec(a);
      if (!d) return a;
      var b = y(a) || 0;
      c = parseFloat(c);
      a = parseFloat(a.replace(d[0], ""));
      switch (d[0][0]) {
        case "+":
          return c + a + b;

        case "-":
          return c - a + b;

        case "*":
          return c * a + b;
      }
    }
    function F (a, c) {
      return Math.sqrt(Math.pow(c.x - a.x, 2) + Math.pow(c.y - a.y, 2));
    }
    function M (a) {
      a = a.points;
      for (var c = 0, d, b = 0; b < a.numberOfItems; b++) {
        var f = a.getItem(b);
        0 < b && (c += F(d, f));
        d = f;
      }
      return c;
    }
    function N (a) {
      if (a.getTotalLength) return a.getTotalLength();
      switch (a.tagName.toLowerCase()) {
        case "circle":
          return 2 * Math.PI * a.getAttribute("r");

        case "rect":
          return 2 * a.getAttribute("width") + 2 * a.getAttribute("height");

        case "line":
          return F({
            x: a.getAttribute("x1"),
            y: a.getAttribute("y1")
          }, {
            x: a.getAttribute("x2"),
            y: a.getAttribute("y2")
          });

        case "polyline":
          return M(a);

        case "polygon":
          var c = a.points;
          return M(a) + F(c.getItem(c.numberOfItems - 1), c.getItem(0));
      }
    }
    function Y (a, c) {
      function d (b) {
        b = void 0 === b ? 0 : b;
        return a.el.getPointAtLength(1 <= c + b ? c + b : 0);
      }
      var b = d(), f = d(-1), n = d(1);
      switch (a.property) {
        case "x":
          return b.x;

        case "y":
          return b.y;

        case "angle":
          return 180 * Math.atan2(n.y - f.y, n.x - f.x) / Math.PI;
      }
    }
    function O (a, c) {
      var d = /-?\d*\.?\d+/g, b;
      b = h.pth(a) ? a.totalLength : a;
      if (h.col(b)) if (h.rgb(b)) {
        var f = /rgb\((\d+,\s*[\d]+,\s*[\d]+)\)/g.exec(b);
        b = f ? "rgba(" + f[1] + ",1)" : b;
      } else b = h.hex(b) ? T(b) : h.hsl(b) ? U(b) : void 0; else f = (f = y(b)) ? b.substr(0, b.length - f.length) : b,
        b = c && !/\s/g.test(b) ? f + c : f;
      b += "";
      return {
        original: b,
        numbers: b.match(d) ? b.match(d).map(Number) : [0],
        strings: h.str(a) || c ? b.split(d) : []
      };
    }
    function P (a) {
      a = a ? p(h.arr(a) ? a.map(m) : m(a)) : [];
      return r(a, function (a, d, b) {
        return b.indexOf(a) === d;
      });
    }
    function Z (a) {
      var c = P(a);
      return c.map(function (a, b) {
        return {
          target: a,
          id: b,
          total: c.length
        };
      });
    }
    function aa (a, c) {
      var d = C(c);
      if (h.arr(a)) {
        var b = a.length;
        2 !== b || h.obj(a[0]) ? h.fnc(c.duration) || (d.duration = c.duration / b) : a = {
          value: a
        };
      }
      return m(a).map(function (a, b) {
        b = b ? 0 : c.delay;
        a = h.obj(a) && !h.pth(a) ? a : {
          value: a
        };
        h.und(a.delay) && (a.delay = b);
        return a;
      }).map(function (a) {
        return z(a, d);
      });
    }
    function ba (a, c) {
      var d = {}, b;
      for (b in a) {
        var f = I(a[b], c);
        h.arr(f) && (f = f.map(function (a) {
          return I(a, c);
        }), 1 === f.length && (f = f[0]));
        d[b] = f;
      }
      d.duration = parseFloat(d.duration);
      d.delay = parseFloat(d.delay);
      return d;
    }
    function ca (a) {
      return h.arr(a) ? A.apply(this, a) : Q[a];
    }
    function da (a, c) {
      var d;
      return a.tweens.map(function (b) {
        b = ba(b, c);
        var f = b.value, e = K(c.target, a.name), k = d ? d.to.original : e, k = h.arr(f) ? f[0] : k, w = L(h.arr(f) ? f[1] : f, k), e = y(w) || y(k) || y(e);
        b.from = O(k, e);
        b.to = O(w, e);
        b.start = d ? d.end : a.offset;
        b.end = b.start + b.delay + b.duration;
        b.easing = ca(b.easing);
        b.elasticity = (1e3 - Math.min(Math.max(b.elasticity, 1), 999)) / 1e3;
        b.isPath = h.pth(f);
        b.isColor = h.col(b.from.original);
        b.isColor && (b.round = 1);
        return d = b;
      });
    }
    function ea (a, c) {
      return r(p(a.map(function (a) {
        return c.map(function (b) {
          var c = J(a.target, b.name);
          if (c) {
            var d = da(b, a);
            b = {
              type: c,
              property: b.name,
              animatable: a,
              tweens: d,
              duration: d[d.length - 1].end,
              delay: d[0].delay
            };
          } else b = void 0;
          return b;
        });
      })), function (a) {
        return !h.und(a);
      });
    }
    function R (a, c, d, b) {
      var f = "delay" === a;
      return c.length ? (f ? Math.min : Math.max).apply(Math, c.map(function (b) {
        return b[a];
      })) : f ? b.delay : d.offset + b.delay + b.duration;
    }
    function fa (a) {
      var c = D(ga, a), d = D(S, a), b = Z(a.targets), f = [], e = z(c, d), k;
      for (k in a) e.hasOwnProperty(k) || "targets" === k || f.push({
        name: k,
        offset: e.offset,
        tweens: aa(a[k], d)
      });
      a = ea(b, f);
      return z(c, {
        children: [],
        animatables: b,
        animations: a,
        duration: R("duration", a, c, d),
        delay: R("delay", a, c, d)
      });
    }
    function q (a) {
      function c () {
        return window.Promise && new Promise(function (a) {
          return p = a;
        });
      }
      function d (a) {
        return g.reversed ? g.duration - a : a;
      }
      function b (a) {
        for (var b = 0, c = {}, d = g.animations, f = d.length; b < f;) {
          var e = d[b], k = e.animatable, h = e.tweens, n = h.length - 1, l = h[n];
          n && (l = r(h, function (b) {
            return a < b.end;
          })[0] || l);
          for (var h = Math.min(Math.max(a - l.start - l.delay, 0), l.duration) / l.duration, w = isNaN(h) ? 1 : l.easing(h, l.elasticity), h = l.to.strings, p = l.round, n = [], m = void 0, m = l.to.numbers.length, t = 0; t < m; t++) {
            var x = void 0, x = l.to.numbers[t], q = l.from.numbers[t], x = l.isPath ? Y(l.value, w * x) : q + w * (x - q);
            p && (l.isColor && 2 < t || (x = Math.round(x * p) / p));
            n.push(x);
          }
          if (l = h.length) for (m = h[0], w = 0; w < l; w++) p = h[w + 1], t = n[w], isNaN(t) || (m = p ? m + (t + p) : m + (t + " ")); else m = n[0];
          ha[e.type](k.target, e.property, m, c, k.id);
          e.currentValue = m;
          b++;
        }
        if (b = Object.keys(c).length) for (d = 0; d < b; d++) H || (H = E(document.body, "transform") ? "transform" : "-webkit-transform"),
          g.animatables[d].target.style[H] = c[d].join(" ");
        g.currentTime = a;
        g.progress = a / g.duration * 100;
      }
      function f (a) {
        if (g[a]) g[a](g);
      }
      function e () {
        g.remaining && !0 !== g.remaining && g.remaining--;
      }
      function k (a) {
        var k = g.duration, n = g.offset, w = n + g.delay, r = g.currentTime, x = g.reversed, q = d(a);
        if (g.children.length) {
          var u = g.children, v = u.length;
          if (q >= g.currentTime) for (var G = 0; G < v; G++) u[G].seek(q); else for (; v--;) u[v].seek(q);
        }
        if (q >= w || !k) g.began || (g.began = !0, f("begin")), f("run");
        if (q > n && q < k) b(q); else if (q <= n && 0 !== r && (b(0), x && e()), q >= k && r !== k || !k) b(k),
          x || e();
        f("update");
        a >= k && (g.remaining ? (t = h, "alternate" === g.direction && (g.reversed = !g.reversed)) : (g.pause(),
          g.completed || (g.completed = !0, f("complete"), "Promise" in window && (p(), m = c()))),
          l = 0);
      }
      a = void 0 === a ? {} : a;
      var h, t, l = 0, p = null, m = c(), g = fa(a);
      g.reset = function () {
        var a = g.direction, c = g.loop;
        g.currentTime = 0;
        g.progress = 0;
        g.paused = !0;
        g.began = !1;
        g.completed = !1;
        g.reversed = "reverse" === a;
        g.remaining = "alternate" === a && 1 === c ? 2 : c;
        b(0);
        for (a = g.children.length; a--;) g.children[a].reset();
      };
      g.tick = function (a) {
        h = a;
        t || (t = h);
        k((l + h - t) * q.speed);
      };
      g.seek = function (a) {
        k(d(a));
      };
      g.pause = function () {
        var a = v.indexOf(g);
        -1 < a && v.splice(a, 1);
        g.paused = !0;
      };
      g.play = function () {
        g.paused && (g.paused = !1, t = 0, l = d(g.currentTime), v.push(g), B || ia());
      };
      g.reverse = function () {
        g.reversed = !g.reversed;
        t = 0;
        l = d(g.currentTime);
      };
      g.restart = function () {
        g.pause();
        g.reset();
        g.play();
      };
      g.finished = m;
      g.reset();
      g.autoplay && g.play();
      return g;
    }
    var ga = {
      update: void 0,
      begin: void 0,
      run: void 0,
      complete: void 0,
      loop: 1,
      direction: "normal",
      autoplay: !0,
      offset: 0
    }, S = {
      duration: 1e3,
      delay: 0,
      easing: "easeOutElastic",
      elasticity: 500,
      round: 0
    }, W = "translateX translateY translateZ rotate rotateX rotateY rotateZ scale scaleX scaleY scaleZ skewX skewY perspective".split(" "), H, h = {
      arr: function (a) {
        return Array.isArray(a);
      },
      obj: function (a) {
        return -1 < Object.prototype.toString.call(a).indexOf("Object");
      },
      pth: function (a) {
        return h.obj(a) && a.hasOwnProperty("totalLength");
      },
      svg: function (a) {
        return a instanceof SVGElement;
      },
      dom: function (a) {
        return a.nodeType || h.svg(a);
      },
      str: function (a) {
        return "string" === typeof a;
      },
      fnc: function (a) {
        return "function" === typeof a;
      },
      und: function (a) {
        return "undefined" === typeof a;
      },
      hex: function (a) {
        return /(^#[0-9A-F]{6}$)|(^#[0-9A-F]{3}$)/i.test(a);
      },
      rgb: function (a) {
        return /^rgb/.test(a);
      },
      hsl: function (a) {
        return /^hsl/.test(a);
      },
      col: function (a) {
        return h.hex(a) || h.rgb(a) || h.hsl(a);
      }
    }, A = function () {
      function a (a, d, b) {
        return (((1 - 3 * b + 3 * d) * a + (3 * b - 6 * d)) * a + 3 * d) * a;
      }
      return function (c, d, b, f) {
        if (0 <= c && 1 >= c && 0 <= b && 1 >= b) {
          var e = new Float32Array(11);
          if (c !== d || b !== f) for (var k = 0; 11 > k; ++k) e[k] = a(.1 * k, c, b);
          return function (k) {
            if (c === d && b === f) return k;
            if (0 === k) return 0;
            if (1 === k) return 1;
            for (var h = 0, l = 1; 10 !== l && e[l] <= k; ++l) h += .1;
            --l;
            var l = h + (k - e[l]) / (e[l + 1] - e[l]) * .1, n = 3 * (1 - 3 * b + 3 * c) * l * l + 2 * (3 * b - 6 * c) * l + 3 * c;
            if (.001 <= n) {
              for (h = 0; 4 > h; ++h) {
                n = 3 * (1 - 3 * b + 3 * c) * l * l + 2 * (3 * b - 6 * c) * l + 3 * c;
                if (0 === n) break;
                var m = a(l, c, b) - k, l = l - m / n;
              }
              k = l;
            } else if (0 === n) k = l; else {
              var l = h, h = h + .1, g = 0;
              do {
                m = l + (h - l) / 2, n = a(m, c, b) - k, 0 < n ? h = m : l = m;
              } while (1e-7 < Math.abs(n) && 10 > ++g);
              k = m;
            }
            return a(k, d, f);
          };
        }
      };
    }(), Q = function () {
      function a (a, b) {
        return 0 === a || 1 === a ? a : -Math.pow(2, 10 * (a - 1)) * Math.sin(2 * (a - 1 - b / (2 * Math.PI) * Math.asin(1)) * Math.PI / b);
      }
      var c = "Quad Cubic Quart Quint Sine Expo Circ Back Elastic".split(" "), d = {
        In: [[.55, .085, .68, .53], [.55, .055, .675, .19], [.895, .03, .685, .22], [.755, .05, .855, .06], [.47, 0, .745, .715], [.95, .05, .795, .035], [.6, .04, .98, .335], [.6, -.28, .735, .045], a],
        Out: [[.25, .46, .45, .94], [.215, .61, .355, 1], [.165, .84, .44, 1], [.23, 1, .32, 1], [.39, .575, .565, 1], [.19, 1, .22, 1], [.075, .82, .165, 1], [.175, .885, .32, 1.275], function (b, c) {
          return 1 - a(1 - b, c);
        }],
        InOut: [[.455, .03, .515, .955], [.645, .045, .355, 1], [.77, 0, .175, 1], [.86, 0, .07, 1], [.445, .05, .55, .95], [1, 0, 0, 1], [.785, .135, .15, .86], [.68, -.55, .265, 1.55], function (b, c) {
          return .5 > b ? a(2 * b, c) / 2 : 1 - a(-2 * b + 2, c) / 2;
        }]
      }, b = {
        linear: A(.25, .25, .75, .75)
      }, f = {}, e;
      for (e in d) f.type = e, d[f.type].forEach(function (a) {
        return function (d, f) {
          b["ease" + a.type + c[f]] = h.fnc(d) ? d : A.apply($jscomp$this, d);
        };
      }(f)), f = {
        type: f.type
      };
      return b;
    }(), ha = {
      css: function (a, c, d) {
        return a.style[c] = d;
      },
      attribute: function (a, c, d) {
        return a.setAttribute(c, d);
      },
      object: function (a, c, d) {
        return a[c] = d;
      },
      transform: function (a, c, d, b, f) {
        b[f] || (b[f] = []);
        b[f].push(c + "(" + d + ")");
      }
    }, v = [], B = 0, ia = function () {
      function a () {
        B = requestAnimationFrame(c);
      }
      function c (c) {
        var b = v.length;
        if (b) {
          for (var d = 0; d < b;) v[d] && v[d].tick(c), d++;
          a();
        } else cancelAnimationFrame(B), B = 0;
      }
      return a;
    }();
    q.version = "2.2.0";
    q.speed = 1;
    q.running = v;
    q.remove = function (a) {
      a = P(a);
      for (var c = v.length; c--;) for (var d = v[c], b = d.animations, f = b.length; f--;) u(a, b[f].animatable.target) && (b.splice(f, 1),
        b.length || d.pause());
    };
    q.getValue = K;
    q.path = function (a, c) {
      var d = h.str(a) ? e(a)[0] : a, b = c || 100;
      return function (a) {
        return {
          el: d,
          property: a,
          totalLength: N(d) * (b / 100)
        };
      };
    };
    q.setDashoffset = function (a) {
      var c = N(a);
      a.setAttribute("stroke-dasharray", c);
      return c;
    };
    q.bezier = A;
    q.easings = Q;
    q.timeline = function (a) {
      var c = q(a);
      c.pause();
      c.duration = 0;
      c.add = function (d) {
        c.children.forEach(function (a) {
          a.began = !0;
          a.completed = !0;
        });
        m(d).forEach(function (b) {
          var d = z(b, D(S, a || {}));
          d.targets = d.targets || a.targets;
          b = c.duration;
          var e = d.offset;
          d.autoplay = !1;
          d.direction = c.direction;
          d.offset = h.und(e) ? b : L(e, b);
          c.began = !0;
          c.completed = !0;
          c.seek(d.offset);
          d = q(d);
          d.began = !0;
          d.completed = !0;
          d.duration > b && (c.duration = d.duration);
          c.children.push(d);
        });
        c.seek(0);
        c.reset();
        c.autoplay && c.restart();
        return c;
      };
      return c;
    };
    q.random = function (a, c) {
      return Math.floor(Math.random() * (c - a + 1)) + a;
    };
    return q;
  });
  (function ($, anim) {
    'use strict';

    let _defaults = {
      accordion: true,
      onOpenStart: undefined,
      onOpenEnd: undefined,
      onCloseStart: undefined,
      onCloseEnd: undefined,
      inDuration: 300,
      outDuration: 300
    };

    /**
     * @class
     *
     */
    class Collapsible extends Component {
      /**
       * Construct Collapsible instance
       * @constructor
       * @param {Element} el
       * @param {Object} options
       */
      constructor (el, options) {
        super(Collapsible, el, options);

        this.el.M_Collapsible = this;

        /**
         * Options for the collapsible
         * @member Collapsible#options
         * @prop {Boolean} [accordion=false] - Type of the collapsible
         * @prop {Function} onOpenStart - Callback function called before collapsible is opened
         * @prop {Function} onOpenEnd - Callback function called after collapsible is opened
         * @prop {Function} onCloseStart - Callback function called before collapsible is closed
         * @prop {Function} onCloseEnd - Callback function called after collapsible is closed
         * @prop {Number} inDuration - Transition in duration in milliseconds.
         * @prop {Number} outDuration - Transition duration in milliseconds.
         */
        this.options = $.extend({}, Collapsible.defaults, options);

        // Setup tab indices
        this.$headers = this.$el.children('li').children('.collapsible-header');
        this.$headers.attr('tabindex', 0);

        this._setupEventHandlers();

        // Open first active
        let $activeBodies = this.$el.children('li.active').children('.collapsible-body');
        if (this.options.accordion) {
          // Handle Accordion
          $activeBodies.first().css('display', 'block');
        } else {
          // Handle Expandables
          $activeBodies.css('display', 'block');
        }
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_Collapsible;
      }

      /**
       * Teardown component
       */
      destroy () {
        this._removeEventHandlers();
        this.el.M_Collapsible = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        this._handleCollapsibleClickBound = this._handleCollapsibleClick.bind(this);
        this._handleCollapsibleKeydownBound = this._handleCollapsibleKeydown.bind(this);
        this.el.addEventListener('click', this._handleCollapsibleClickBound);
        this.$headers.each((header) => {
          header.addEventListener('keydown', this._handleCollapsibleKeydownBound);
        });
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        this.el.removeEventListener('click', this._handleCollapsibleClickBound);
        this.$headers.each((header) => {
          header.removeEventListener('keydown', this._handleCollapsibleKeydownBound);
        });
      }

      /**
       * Handle Collapsible Click
       * @param {Event} e
       */
      _handleCollapsibleClick (e) {
        let $header = $(e.target).closest('.collapsible-header');
        if (e.target && $header.length) {
          let $collapsible = $header.closest('.collapsible');
          if ($collapsible[0] === this.el) {
            let $collapsibleLi = $header.closest('li');
            let $collapsibleLis = $collapsible.children('li');
            let isActive = $collapsibleLi[0].classList.contains('active');
            let index = $collapsibleLis.index($collapsibleLi);

            if (isActive) {
              this.close(index);
            } else {
              this.open(index);
            }
          }
        }
      }

      /**
       * Handle Collapsible Keydown
       * @param {Event} e
       */
      _handleCollapsibleKeydown (e) {
        if (e.keyCode === 13) {
          this._handleCollapsibleClickBound(e);
        }
      }

      /**
       * Animate in collapsible slide
       * @param {Number} index - 0th index of slide
       */
      _animateIn (index) {
        let $collapsibleLi = this.$el.children('li').eq(index);
        if ($collapsibleLi.length) {
          let $body = $collapsibleLi.children('.collapsible-body');

          anim.remove($body[0]);
          $body.css({
            display: 'block',
            overflow: 'hidden',
            height: 0,
            paddingTop: '',
            paddingBottom: ''
          });

          let pTop = $body.css('padding-top');
          let pBottom = $body.css('padding-bottom');
          let finalHeight = $body[0].scrollHeight;
          $body.css({
            paddingTop: 0,
            paddingBottom: 0
          });

          anim({
            targets: $body[0],
            height: finalHeight,
            paddingTop: pTop,
            paddingBottom: pBottom,
            duration: this.options.inDuration,
            easing: 'easeInOutCubic',
            complete: (anim) => {
              $body.css({
                overflow: '',
                paddingTop: '',
                paddingBottom: '',
                height: ''
              });

              // onOpenEnd callback
              if (typeof this.options.onOpenEnd === 'function') {
                this.options.onOpenEnd.call(this, $collapsibleLi[0]);
              }
            }
          });
        }
      }

      /**
       * Animate out collapsible slide
       * @param {Number} index - 0th index of slide to open
       */
      _animateOut (index) {
        let $collapsibleLi = this.$el.children('li').eq(index);
        if ($collapsibleLi.length) {
          let $body = $collapsibleLi.children('.collapsible-body');
          anim.remove($body[0]);
          $body.css('overflow', 'hidden');
          anim({
            targets: $body[0],
            height: 0,
            paddingTop: 0,
            paddingBottom: 0,
            duration: this.options.outDuration,
            easing: 'easeInOutCubic',
            complete: () => {
              $body.css({
                height: '',
                overflow: '',
                padding: '',
                display: ''
              });

              // onCloseEnd callback
              if (typeof this.options.onCloseEnd === 'function') {
                this.options.onCloseEnd.call(this, $collapsibleLi[0]);
              }
            }
          });
        }
      }

      /**
       * Open Collapsible
       * @param {Number} index - 0th index of slide
       */
      open (index) {
        let $collapsibleLi = this.$el.children('li').eq(index);
        if ($collapsibleLi.length && !$collapsibleLi[0].classList.contains('active')) {
          // onOpenStart callback
          if (typeof this.options.onOpenStart === 'function') {
            this.options.onOpenStart.call(this, $collapsibleLi[0]);
          }

          // Handle accordion behavior
          if (this.options.accordion) {
            let $collapsibleLis = this.$el.children('li');
            let $activeLis = this.$el.children('li.active');
            $activeLis.each((el) => {
              let index = $collapsibleLis.index($(el));
              this.close(index);
            });
          }

          // Animate in
          $collapsibleLi[0].classList.add('active');
          this._animateIn(index);
        }
      }

      /**
       * Close Collapsible
       * @param {Number} index - 0th index of slide
       */
      close (index) {
        let $collapsibleLi = this.$el.children('li').eq(index);
        if ($collapsibleLi.length && $collapsibleLi[0].classList.contains('active')) {
          // onCloseStart callback
          if (typeof this.options.onCloseStart === 'function') {
            this.options.onCloseStart.call(this, $collapsibleLi[0]);
          }

          // Animate out
          $collapsibleLi[0].classList.remove('active');
          this._animateOut(index);
        }
      }
    }

    M.Collapsible = Collapsible;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(Collapsible, 'collapsible', 'M_Collapsible');
    }
  })(cash, M.anime);

  (function ($, anim) {
    'use strict';

    let _defaults = {
      alignment: 'left',
      autoFocus: true,
      constrainWidth: true,
      container: null,
      coverTrigger: true,
      closeOnClick: true,
      hover: false,
      inDuration: 150,
      outDuration: 250,
      onOpenStart: null,
      onOpenEnd: null,
      onCloseStart: null,
      onCloseEnd: null,
      onItemClick: null
    };

    /**
     * @class
     */
    class Dropdown extends Component {
      constructor (el, options) {
        super(Dropdown, el, options);

        this.el.M_Dropdown = this;
        Dropdown._dropdowns.push(this);

        this.id = M.getIdFromTrigger(el);
        this.dropdownEl = document.getElementById(this.id);
        this.$dropdownEl = $(this.dropdownEl);

        /**
         * Options for the dropdown
         * @member Dropdown#options
         * @prop {String} [alignment='left'] - Edge which the dropdown is aligned to
         * @prop {Boolean} [autoFocus=true] - Automatically focus dropdown el for keyboard
         * @prop {Boolean} [constrainWidth=true] - Constrain width to width of the button
         * @prop {Element} container - Container element to attach dropdown to (optional)
         * @prop {Boolean} [coverTrigger=true] - Place dropdown over trigger
         * @prop {Boolean} [closeOnClick=true] - Close on click of dropdown item
         * @prop {Boolean} [hover=false] - Open dropdown on hover
         * @prop {Number} [inDuration=150] - Duration of open animation in ms
         * @prop {Number} [outDuration=250] - Duration of close animation in ms
         * @prop {Function} onOpenStart - Function called when dropdown starts opening
         * @prop {Function} onOpenEnd - Function called when dropdown finishes opening
         * @prop {Function} onCloseStart - Function called when dropdown starts closing
         * @prop {Function} onCloseEnd - Function called when dropdown finishes closing
         */
        this.options = $.extend({}, Dropdown.defaults, options);

        /**
         * Describes open/close state of dropdown
         * @type {Boolean}
         */
        this.isOpen = false;

        /**
         * Describes if dropdown content is scrollable
         * @type {Boolean}
         */
        this.isScrollable = false;

        /**
         * Describes if touch moving on dropdown content
         * @type {Boolean}
         */
        this.isTouchMoving = false;

        this.focusedIndex = -1;
        this.filterQuery = [];

        // Move dropdown-content after dropdown-trigger
        if (!!this.options.container) {
          $(this.options.container).append(this.dropdownEl);
        } else {
          this.$el.after(this.dropdownEl);
        }

        this._makeDropdownFocusable();
        this._resetFilterQueryBound = this._resetFilterQuery.bind(this);
        this._handleDocumentClickBound = this._handleDocumentClick.bind(this);
        this._handleDocumentTouchmoveBound = this._handleDocumentTouchmove.bind(this);
        this._handleDropdownClickBound = this._handleDropdownClick.bind(this);
        this._handleDropdownKeydownBound = this._handleDropdownKeydown.bind(this);
        this._handleTriggerKeydownBound = this._handleTriggerKeydown.bind(this);
        this._setupEventHandlers();
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_Dropdown;
      }

      /**
       * Teardown component
       */
      destroy () {
        this._resetDropdownStyles();
        this._removeEventHandlers();
        Dropdown._dropdowns.splice(Dropdown._dropdowns.indexOf(this), 1);
        this.el.M_Dropdown = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        // Trigger keydown handler
        this.el.addEventListener('keydown', this._handleTriggerKeydownBound);

        // Item click handler
        this.dropdownEl.addEventListener('click', this._handleDropdownClickBound);

        // Hover event handlers
        if (this.options.hover) {
          this._handleMouseEnterBound = this._handleMouseEnter.bind(this);
          this.el.addEventListener('mouseenter', this._handleMouseEnterBound);
          this._handleMouseLeaveBound = this._handleMouseLeave.bind(this);
          this.el.addEventListener('mouseleave', this._handleMouseLeaveBound);
          this.dropdownEl.addEventListener('mouseleave', this._handleMouseLeaveBound);

          // Click event handlers
        } else {
          this._handleClickBound = this._handleClick.bind(this);
          this.el.addEventListener('click', this._handleClickBound);
        }
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        this.el.removeEventListener('keydown', this._handleTriggerKeydownBound);
        this.dropdownEl.removeEventListener('click', this._handleDropdownClickBound);

        if (this.options.hover) {
          this.el.removeEventListener('mouseenter', this._handleMouseEnterBound);
          this.el.removeEventListener('mouseleave', this._handleMouseLeaveBound);
          this.dropdownEl.removeEventListener('mouseleave', this._handleMouseLeaveBound);
        } else {
          this.el.removeEventListener('click', this._handleClickBound);
        }
      }

      _setupTemporaryEventHandlers () {
        // Use capture phase event handler to prevent click
        document.body.addEventListener('click', this._handleDocumentClickBound, true);
        document.body.addEventListener('touchend', this._handleDocumentClickBound);
        document.body.addEventListener('touchmove', this._handleDocumentTouchmoveBound);
        this.dropdownEl.addEventListener('keydown', this._handleDropdownKeydownBound);
      }

      _removeTemporaryEventHandlers () {
        // Use capture phase event handler to prevent click
        document.body.removeEventListener('click', this._handleDocumentClickBound, true);
        document.body.removeEventListener('touchend', this._handleDocumentClickBound);
        document.body.removeEventListener('touchmove', this._handleDocumentTouchmoveBound);
        this.dropdownEl.removeEventListener('keydown', this._handleDropdownKeydownBound);
      }

      _handleClick (e) {
        e.preventDefault();
        this.open();
      }

      _handleMouseEnter () {
        this.open();
      }

      _handleMouseLeave (e) {
        let toEl = e.toElement || e.relatedTarget;
        let leaveToDropdownContent = !!$(toEl).closest('.dropdown-content').length;
        let leaveToActiveDropdownTrigger = false;

        let $closestTrigger = $(toEl).closest('.dropdown-trigger');
        if (
          $closestTrigger.length &&
          !!$closestTrigger[0].M_Dropdown &&
          $closestTrigger[0].M_Dropdown.isOpen
        ) {
          leaveToActiveDropdownTrigger = true;
        }

        // Close hover dropdown if mouse did not leave to either active dropdown-trigger or dropdown-content
        if (!leaveToActiveDropdownTrigger && !leaveToDropdownContent) {
          this.close();
        }
      }

      _handleDocumentClick (e) {
        let $target = $(e.target);
        if (
          this.options.closeOnClick &&
          $target.closest('.dropdown-content').length &&
          !this.isTouchMoving
        ) {
          // isTouchMoving to check if scrolling on mobile.
          setTimeout(() => {
            this.close();
          }, 0);
        } else if (
          $target.closest('.dropdown-trigger').length ||
          !$target.closest('.dropdown-content').length
        ) {
          setTimeout(() => {
            this.close();
          }, 0);
        }
        this.isTouchMoving = false;
      }

      _handleTriggerKeydown (e) {
        // ARROW DOWN OR ENTER WHEN SELECT IS CLOSED - open Dropdown
        if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ENTER) && !this.isOpen) {
          e.preventDefault();
          this.open();
        }
      }

      /**
       * Handle Document Touchmove
       * @param {Event} e
       */
      _handleDocumentTouchmove (e) {
        let $target = $(e.target);
        if ($target.closest('.dropdown-content').length) {
          this.isTouchMoving = true;
        }
      }

      /**
       * Handle Dropdown Click
       * @param {Event} e
       */
      _handleDropdownClick (e) {
        // onItemClick callback
        if (typeof this.options.onItemClick === 'function') {
          let itemEl = $(e.target).closest('li')[0];
          this.options.onItemClick.call(this, itemEl);
        }
      }

      /**
       * Handle Dropdown Keydown
       * @param {Event} e
       */
      _handleDropdownKeydown (e) {
        if (e.which === M.keys.TAB) {
          e.preventDefault();
          this.close();

          // Navigate down dropdown list
        } else if ((e.which === M.keys.ARROW_DOWN || e.which === M.keys.ARROW_UP) && this.isOpen) {
          e.preventDefault();
          let direction = e.which === M.keys.ARROW_DOWN ? 1 : -1;
          let newFocusedIndex = this.focusedIndex;
          let foundNewIndex = false;
          do {
            newFocusedIndex = newFocusedIndex + direction;

            if (
              !!this.dropdownEl.children[newFocusedIndex] &&
              this.dropdownEl.children[newFocusedIndex].tabIndex !== -1
            ) {
              foundNewIndex = true;
              break;
            }
          } while (newFocusedIndex < this.dropdownEl.children.length && newFocusedIndex >= 0);

          if (foundNewIndex) {
            this.focusedIndex = newFocusedIndex;
            this._focusFocusedItem();
          }

          // ENTER selects choice on focused item
        } else if (e.which === M.keys.ENTER && this.isOpen) {
          // Search for <a> and <button>
          let focusedElement = this.dropdownEl.children[this.focusedIndex];
          let $activatableElement = $(focusedElement)
            .find('a, button')
            .first();

          // Click a or button tag if exists, otherwise click li tag
          if (!!$activatableElement.length) {
            $activatableElement[0].click();
          } else if (!!focusedElement) {
            focusedElement.click();
          }

          // Close dropdown on ESC
        } else if (e.which === M.keys.ESC && this.isOpen) {
          e.preventDefault();
          this.close();
        }

        // CASE WHEN USER TYPE LETTERS
        let letter = String.fromCharCode(e.which).toLowerCase(),
          nonLetters = [9, 13, 27, 38, 40];
        if (letter && nonLetters.indexOf(e.which) === -1) {
          this.filterQuery.push(letter);

          let string = this.filterQuery.join(''),
            newOptionEl = $(this.dropdownEl)
              .find('li')
              .filter((el) => {
                return (
                  $(el)
                    .text()
                    .toLowerCase()
                    .indexOf(string) === 0
                );
              })[0];

          if (newOptionEl) {
            this.focusedIndex = $(newOptionEl).index();
            this._focusFocusedItem();
          }
        }

        this.filterTimeout = setTimeout(this._resetFilterQueryBound, 1000);
      }

      /**
       * Setup dropdown
       */
      _resetFilterQuery () {
        this.filterQuery = [];
      }

      _resetDropdownStyles () {
        this.$dropdownEl.css({
          display: '',
          width: '',
          height: '',
          left: '',
          top: '',
          'transform-origin': '',
          transform: '',
          opacity: ''
        });
      }

      _makeDropdownFocusable () {
        // Needed for arrow key navigation
        this.dropdownEl.tabIndex = 0;

        // Only set tabindex if it hasn't been set by user
        $(this.dropdownEl)
          .children()
          .each(function (el) {
            if (!el.getAttribute('tabindex')) {
              el.setAttribute('tabindex', 0);
            }
          });
      }

      _focusFocusedItem () {
        if (
          this.focusedIndex >= 0 &&
          this.focusedIndex < this.dropdownEl.children.length &&
          this.options.autoFocus
        ) {
          this.dropdownEl.children[this.focusedIndex].focus();
        }
      }

      _getDropdownPosition () {
        let offsetParentBRect = this.el.offsetParent.getBoundingClientRect();
        let triggerBRect = this.el.getBoundingClientRect();
        let dropdownBRect = this.dropdownEl.getBoundingClientRect();

        let idealHeight = dropdownBRect.height;
        let idealWidth = dropdownBRect.width;
        let idealXPos = triggerBRect.left - dropdownBRect.left;
        let idealYPos = triggerBRect.top - dropdownBRect.top;

        let dropdownBounds = {
          left: idealXPos,
          top: idealYPos,
          height: idealHeight,
          width: idealWidth
        };

        // Countainer here will be closest ancestor with overflow: hidden
        let closestOverflowParent = !!this.dropdownEl.offsetParent
          ? this.dropdownEl.offsetParent
          : this.dropdownEl.parentNode;

        let alignments = M.checkPossibleAlignments(
          this.el,
          closestOverflowParent,
          dropdownBounds,
          this.options.coverTrigger ? 0 : triggerBRect.height
        );

        let verticalAlignment = 'top';
        let horizontalAlignment = this.options.alignment;
        idealYPos += this.options.coverTrigger ? 0 : triggerBRect.height;

        // Reset isScrollable
        this.isScrollable = false;

        if (!alignments.top) {
          if (alignments.bottom) {
            verticalAlignment = 'bottom';
          } else {
            this.isScrollable = true;

            // Determine which side has most space and cutoff at correct height
            if (alignments.spaceOnTop > alignments.spaceOnBottom) {
              verticalAlignment = 'bottom';
              idealHeight += alignments.spaceOnTop;
              idealYPos -= alignments.spaceOnTop;
            } else {
              idealHeight += alignments.spaceOnBottom;
            }
          }
        }

        // If preferred horizontal alignment is possible
        if (!alignments[horizontalAlignment]) {
          let oppositeAlignment = horizontalAlignment === 'left' ? 'right' : 'left';
          if (alignments[oppositeAlignment]) {
            horizontalAlignment = oppositeAlignment;
          } else {
            // Determine which side has most space and cutoff at correct height
            if (alignments.spaceOnLeft > alignments.spaceOnRight) {
              horizontalAlignment = 'right';
              idealWidth += alignments.spaceOnLeft;
              idealXPos -= alignments.spaceOnLeft;
            } else {
              horizontalAlignment = 'left';
              idealWidth += alignments.spaceOnRight;
            }
          }
        }

        if (verticalAlignment === 'bottom') {
          idealYPos =
            idealYPos - dropdownBRect.height + (this.options.coverTrigger ? triggerBRect.height : 0);
        }
        if (horizontalAlignment === 'right') {
          idealXPos = idealXPos - dropdownBRect.width + triggerBRect.width;
        }
        return {
          x: idealXPos,
          y: idealYPos,
          verticalAlignment: verticalAlignment,
          horizontalAlignment: horizontalAlignment,
          height: idealHeight,
          width: idealWidth
        };
      }

      /**
       * Animate in dropdown
       */
      _animateIn () {
        anim.remove(this.dropdownEl);
        anim({
          targets: this.dropdownEl,
          opacity: {
            value: [0, 1],
            easing: 'easeOutQuad'
          },
          scaleX: [0.3, 1],
          scaleY: [0.3, 1],
          duration: this.options.inDuration,
          easing: 'easeOutQuint',
          complete: (anim) => {
            if (this.options.autoFocus) {
              this.dropdownEl.focus();
            }

            // onOpenEnd callback
            if (typeof this.options.onOpenEnd === 'function') {
              this.options.onOpenEnd.call(this, this.el);
            }
          }
        });
      }

      /**
       * Animate out dropdown
       */
      _animateOut () {
        anim.remove(this.dropdownEl);
        anim({
          targets: this.dropdownEl,
          opacity: {
            value: 0,
            easing: 'easeOutQuint'
          },
          scaleX: 0.3,
          scaleY: 0.3,
          duration: this.options.outDuration,
          easing: 'easeOutQuint',
          complete: (anim) => {
            this._resetDropdownStyles();

            // onCloseEnd callback
            if (typeof this.options.onCloseEnd === 'function') {
              this.options.onCloseEnd.call(this, this.el);
            }
          }
        });
      }

      /**
       * Place dropdown
       */
      _placeDropdown () {
        // Set width before calculating positionInfo
        let idealWidth = this.options.constrainWidth
          ? this.el.getBoundingClientRect().width
          : this.dropdownEl.getBoundingClientRect().width;
        this.dropdownEl.style.width = idealWidth + 'px';

        let positionInfo = this._getDropdownPosition();
        this.dropdownEl.style.left = positionInfo.x + 'px';
        this.dropdownEl.style.top = positionInfo.y + 'px';
        this.dropdownEl.style.height = positionInfo.height + 'px';
        this.dropdownEl.style.width = positionInfo.width + 'px';
        this.dropdownEl.style.transformOrigin = `${positionInfo.horizontalAlignment === 'left' ? '0' : '100%'
          } ${positionInfo.verticalAlignment === 'top' ? '0' : '100%'}`;
      }

      /**
       * Open Dropdown
       */
      open () {
        if (this.isOpen) {
          return;
        }
        this.isOpen = true;

        // onOpenStart callback
        if (typeof this.options.onOpenStart === 'function') {
          this.options.onOpenStart.call(this, this.el);
        }

        // Reset styles
        this._resetDropdownStyles();
        this.dropdownEl.style.display = 'block';

        this._placeDropdown();
        this._animateIn();
        this._setupTemporaryEventHandlers();
      }

      /**
       * Close Dropdown
       */
      close () {
        if (!this.isOpen) {
          return;
        }
        this.isOpen = false;
        this.focusedIndex = -1;

        // onCloseStart callback
        if (typeof this.options.onCloseStart === 'function') {
          this.options.onCloseStart.call(this, this.el);
        }

        this._animateOut();
        this._removeTemporaryEventHandlers();

        if (this.options.autoFocus) {
          this.el.focus();
        }
      }

      /**
       * Recalculate dimensions
       */
      recalculateDimensions () {
        if (this.isOpen) {
          this.$dropdownEl.css({
            width: '',
            height: '',
            left: '',
            top: '',
            'transform-origin': ''
          });
          this._placeDropdown();
        }
      }
    }

    /**
     * @static
     * @memberof Dropdown
     */
    Dropdown._dropdowns = [];

    M.Dropdown = Dropdown;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(Dropdown, 'dropdown', 'M_Dropdown');
    }
  })(cash, M.anime);

  (function ($, anim) {
    'use strict';

    let _defaults = {
      opacity: 0.5,
      inDuration: 250,
      outDuration: 250,
      onOpenStart: null,
      onOpenEnd: null,
      onCloseStart: null,
      onCloseEnd: null,
      preventScrolling: true,
      dismissible: true,
      startingTop: '4%',
      endingTop: '10%'
    };

    /**
     * @class
     *
     */
    class Modal extends Component {
      /**
       * Construct Modal instance and set up overlay
       * @constructor
       * @param {Element} el
       * @param {Object} options
       */
      constructor (el, options) {
        super(Modal, el, options);

        this.el.M_Modal = this;

        /**
         * Options for the modal
         * @member Modal#options
         * @prop {Number} [opacity=0.5] - Opacity of the modal overlay
         * @prop {Number} [inDuration=250] - Length in ms of enter transition
         * @prop {Number} [outDuration=250] - Length in ms of exit transition
         * @prop {Function} onOpenStart - Callback function called before modal is opened
         * @prop {Function} onOpenEnd - Callback function called after modal is opened
         * @prop {Function} onCloseStart - Callback function called before modal is closed
         * @prop {Function} onCloseEnd - Callback function called after modal is closed
         * @prop {Boolean} [dismissible=true] - Allow modal to be dismissed by keyboard or overlay click
         * @prop {String} [startingTop='4%'] - startingTop
         * @prop {String} [endingTop='10%'] - endingTop
         */
        this.options = $.extend({}, Modal.defaults, options);

        /**
         * Describes open/close state of modal
         * @type {Boolean}
         */
        this.isOpen = false;

        this.id = this.$el.attr('id');
        this._openingTrigger = undefined;
        this.$overlay = $('<div class="modal-overlay"></div>');
        this.el.tabIndex = 0;
        this._nthModalOpened = 0;

        Modal._count++;
        this._setupEventHandlers();
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_Modal;
      }

      /**
       * Teardown component
       */
      destroy () {
        Modal._count--;
        this._removeEventHandlers();
        this.el.removeAttribute('style');
        this.$overlay.remove();
        this.el.M_Modal = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        this._handleOverlayClickBound = this._handleOverlayClick.bind(this);
        this._handleModalCloseClickBound = this._handleModalCloseClick.bind(this);

        if (Modal._count === 1) {
          document.body.addEventListener('click', this._handleTriggerClick);
        }
        this.$overlay[0].addEventListener('click', this._handleOverlayClickBound);
        this.el.addEventListener('click', this._handleModalCloseClickBound);
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        if (Modal._count === 0) {
          document.body.removeEventListener('click', this._handleTriggerClick);
        }
        this.$overlay[0].removeEventListener('click', this._handleOverlayClickBound);
        this.el.removeEventListener('click', this._handleModalCloseClickBound);
      }

      /**
       * Handle Trigger Click
       * @param {Event} e
       */
      _handleTriggerClick (e) {
        let $trigger = $(e.target).closest('.modal-trigger');
        if ($trigger.length) {
          let modalId = M.getIdFromTrigger($trigger[0]);
          let modalInstance = document.getElementById(modalId).M_Modal;
          if (modalInstance) {
            modalInstance.open($trigger);
          }
          e.preventDefault();
        }
      }

      /**
       * Handle Overlay Click
       */
      _handleOverlayClick () {
        if (this.options.dismissible) {
          this.close();
        }
      }

      /**
       * Handle Modal Close Click
       * @param {Event} e
       */
      _handleModalCloseClick (e) {
        let $closeTrigger = $(e.target).closest('.modal-close');
        if ($closeTrigger.length) {
          this.close();
        }
      }

      /**
       * Handle Keydown
       * @param {Event} e
       */
      _handleKeydown (e) {
        // ESC key
        if (e.keyCode === 27 && this.options.dismissible) {
          this.close();
        }
      }

      /**
       * Handle Focus
       * @param {Event} e
       */
      _handleFocus (e) {
        // Only trap focus if this modal is the last model opened (prevents loops in nested modals).
        if (!this.el.contains(e.target) && this._nthModalOpened === Modal._modalsOpen) {
          this.el.focus();
        }
      }

      /**
       * Animate in modal
       */
      _animateIn () {
        // Set initial styles
        $.extend(this.el.style, {
          display: 'block',
          opacity: 0
        });
        $.extend(this.$overlay[0].style, {
          display: 'block',
          opacity: 0
        });

        // Animate overlay
        anim({
          targets: this.$overlay[0],
          opacity: this.options.opacity,
          duration: this.options.inDuration,
          easing: 'easeOutQuad'
        });

        // Define modal animation options
        let enterAnimOptions = {
          targets: this.el,
          duration: this.options.inDuration,
          easing: 'easeOutCubic',
          // Handle modal onOpenEnd callback
          complete: () => {
            if (typeof this.options.onOpenEnd === 'function') {
              this.options.onOpenEnd.call(this, this.el, this._openingTrigger);
            }
          }
        };

        // Bottom sheet animation
        if (this.el.classList.contains('bottom-sheet')) {
          $.extend(enterAnimOptions, {
            bottom: 0,
            opacity: 1
          });
          anim(enterAnimOptions);

          // Normal modal animation
        } else {
          $.extend(enterAnimOptions, {
            top: [this.options.startingTop, this.options.endingTop],
            opacity: 1,
            scaleX: [0.8, 1],
            scaleY: [0.8, 1]
          });
          anim(enterAnimOptions);
        }
      }

      /**
       * Animate out modal
       */
      _animateOut () {
        // Animate overlay
        anim({
          targets: this.$overlay[0],
          opacity: 0,
          duration: this.options.outDuration,
          easing: 'easeOutQuart'
        });

        // Define modal animation options
        let exitAnimOptions = {
          targets: this.el,
          duration: this.options.outDuration,
          easing: 'easeOutCubic',
          // Handle modal ready callback
          complete: () => {
            this.el.style.display = 'none';
            this.$overlay.remove();

            // Call onCloseEnd callback
            if (typeof this.options.onCloseEnd === 'function') {
              this.options.onCloseEnd.call(this, this.el);
            }
          }
        };

        // Bottom sheet animation
        if (this.el.classList.contains('bottom-sheet')) {
          $.extend(exitAnimOptions, {
            bottom: '-100%',
            opacity: 0
          });
          anim(exitAnimOptions);

          // Normal modal animation
        } else {
          $.extend(exitAnimOptions, {
            top: [this.options.endingTop, this.options.startingTop],
            opacity: 0,
            scaleX: 0.8,
            scaleY: 0.8
          });
          anim(exitAnimOptions);
        }
      }

      /**
       * Open Modal
       * @param {cash} [$trigger]
       */
      open ($trigger) {
        if (this.isOpen) {
          return;
        }

        this.isOpen = true;
        Modal._modalsOpen++;
        this._nthModalOpened = Modal._modalsOpen;

        // Set Z-Index based on number of currently open modals
        this.$overlay[0].style.zIndex = 1000 + Modal._modalsOpen * 2;
        this.el.style.zIndex = 1000 + Modal._modalsOpen * 2 + 1;

        // Set opening trigger, undefined indicates modal was opened by javascript
        this._openingTrigger = !!$trigger ? $trigger[0] : undefined;

        // onOpenStart callback
        if (typeof this.options.onOpenStart === 'function') {
          this.options.onOpenStart.call(this, this.el, this._openingTrigger);
        }

        if (this.options.preventScrolling) {
          document.body.style.overflow = 'hidden';
        }

        this.el.classList.add('open');
        this.el.insertAdjacentElement('afterend', this.$overlay[0]);

        if (this.options.dismissible) {
          this._handleKeydownBound = this._handleKeydown.bind(this);
          this._handleFocusBound = this._handleFocus.bind(this);
          document.addEventListener('keydown', this._handleKeydownBound);
          document.addEventListener('focus', this._handleFocusBound, true);
        }

        anim.remove(this.el);
        anim.remove(this.$overlay[0]);
        this._animateIn();

        // Focus modal
        this.el.focus();

        return this;
      }

      /**
       * Close Modal
       */
      close () {
        if (!this.isOpen) {
          return;
        }

        this.isOpen = false;
        Modal._modalsOpen--;
        this._nthModalOpened = 0;

        // Call onCloseStart callback
        if (typeof this.options.onCloseStart === 'function') {
          this.options.onCloseStart.call(this, this.el);
        }

        this.el.classList.remove('open');

        // Enable body scrolling only if there are no more modals open.
        if (Modal._modalsOpen === 0) {
          document.body.style.overflow = '';
        }

        if (this.options.dismissible) {
          document.removeEventListener('keydown', this._handleKeydownBound);
          document.removeEventListener('focus', this._handleFocusBound, true);
        }

        anim.remove(this.el);
        anim.remove(this.$overlay[0]);
        this._animateOut();
        return this;
      }
    }

    /**
     * @static
     * @memberof Modal
     */
    Modal._modalsOpen = 0;

    /**
     * @static
     * @memberof Modal
     */
    Modal._count = 0;

    M.Modal = Modal;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(Modal, 'modal', 'M_Modal');
    }
  })(cash, M.anime);

  /*!
   * Waves v0.6.4
   * http://fian.my.id/Waves
   *
   * Copyright 2014 Alfiana E. Sibuea and other contributors
   * Released under the MIT license
   * https://github.com/fians/Waves/blob/master/LICENSE
   */

  ; (function (window) {
    'use strict';

    var Waves = Waves || {};
    var $$ = document.querySelectorAll.bind(document);

    // Find exact position of element
    function isWindow (obj) {
      return obj !== null && obj === obj.window;
    }

    function getWindow (elem) {
      return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView;
    }

    function offset (elem) {
      var docElem, win,
        box = { top: 0, left: 0 },
        doc = elem && elem.ownerDocument;

      docElem = doc.documentElement;

      if (typeof elem.getBoundingClientRect !== typeof undefined) {
        box = elem.getBoundingClientRect();
      }
      win = getWindow(doc);
      return {
        top: box.top + win.pageYOffset - docElem.clientTop,
        left: box.left + win.pageXOffset - docElem.clientLeft
      };
    }

    function convertStyle (obj) {
      var style = '';

      for (var a in obj) {
        if (obj.hasOwnProperty(a)) {
          style += (a + ':' + obj[a] + ';');
        }
      }

      return style;
    }

    var Effect = {

      // Effect delay
      duration: 750,

      show: function (e, element) {

        // Disable right click
        if (e.button === 2) {
          return false;
        }

        var el = element || this;

        // Create ripple
        var ripple = document.createElement('div');
        ripple.className = 'waves-ripple';
        el.appendChild(ripple);

        // Get click coordinate and element witdh
        var pos = offset(el);
        var relativeY = (e.pageY - pos.top);
        var relativeX = (e.pageX - pos.left);
        var scale = 'scale(' + ((el.clientWidth / 100) * 10) + ')';

        // Support for touch devices
        if ('touches' in e) {
          relativeY = (e.touches[0].pageY - pos.top);
          relativeX = (e.touches[0].pageX - pos.left);
        }

        // Attach data to element
        ripple.setAttribute('data-hold', Date.now());
        ripple.setAttribute('data-scale', scale);
        ripple.setAttribute('data-x', relativeX);
        ripple.setAttribute('data-y', relativeY);

        // Set ripple position
        var rippleStyle = {
          'top': relativeY + 'px',
          'left': relativeX + 'px'
        };

        ripple.className = ripple.className + ' waves-notransition';
        ripple.setAttribute('style', convertStyle(rippleStyle));
        ripple.className = ripple.className.replace('waves-notransition', '');

        // Scale the ripple
        rippleStyle['-webkit-transform'] = scale;
        rippleStyle['-moz-transform'] = scale;
        rippleStyle['-ms-transform'] = scale;
        rippleStyle['-o-transform'] = scale;
        rippleStyle.transform = scale;
        rippleStyle.opacity = '1';

        rippleStyle['-webkit-transition-duration'] = Effect.duration + 'ms';
        rippleStyle['-moz-transition-duration'] = Effect.duration + 'ms';
        rippleStyle['-o-transition-duration'] = Effect.duration + 'ms';
        rippleStyle['transition-duration'] = Effect.duration + 'ms';

        rippleStyle['-webkit-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
        rippleStyle['-moz-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
        rippleStyle['-o-transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';
        rippleStyle['transition-timing-function'] = 'cubic-bezier(0.250, 0.460, 0.450, 0.940)';

        ripple.setAttribute('style', convertStyle(rippleStyle));
      },

      hide: function (e) {
        TouchHandler.touchup(e);

        var el = this;
        var width = el.clientWidth * 1.4;

        // Get first ripple
        var ripple = null;
        var ripples = el.getElementsByClassName('waves-ripple');
        if (ripples.length > 0) {
          ripple = ripples[ripples.length - 1];
        } else {
          return false;
        }

        var relativeX = ripple.getAttribute('data-x');
        var relativeY = ripple.getAttribute('data-y');
        var scale = ripple.getAttribute('data-scale');

        // Get delay beetween mousedown and mouse leave
        var diff = Date.now() - Number(ripple.getAttribute('data-hold'));
        var delay = 350 - diff;

        if (delay < 0) {
          delay = 0;
        }

        // Fade out ripple after delay
        setTimeout(function () {
          var style = {
            'top': relativeY + 'px',
            'left': relativeX + 'px',
            'opacity': '0',

            // Duration
            '-webkit-transition-duration': Effect.duration + 'ms',
            '-moz-transition-duration': Effect.duration + 'ms',
            '-o-transition-duration': Effect.duration + 'ms',
            'transition-duration': Effect.duration + 'ms',
            '-webkit-transform': scale,
            '-moz-transform': scale,
            '-ms-transform': scale,
            '-o-transform': scale,
            'transform': scale,
          };

          ripple.setAttribute('style', convertStyle(style));

          setTimeout(function () {
            try {
              el.removeChild(ripple);
            } catch (e) {
              return false;
            }
          }, Effect.duration);
        }, delay);
      },

      // Little hack to make <input> can perform waves effect
      wrapInput: function (elements) {
        for (var a = 0; a < elements.length; a++) {
          var el = elements[a];

          if (el.tagName.toLowerCase() === 'input') {
            var parent = el.parentNode;

            // If input already have parent just pass through
            if (parent.tagName.toLowerCase() === 'i' && parent.className.indexOf('waves-effect') !== -1) {
              continue;
            }

            // Put element class and style to the specified parent
            var wrapper = document.createElement('i');
            wrapper.className = el.className + ' waves-input-wrapper';

            var elementStyle = el.getAttribute('style');

            if (!elementStyle) {
              elementStyle = '';
            }

            wrapper.setAttribute('style', elementStyle);

            el.className = 'waves-button-input';
            el.removeAttribute('style');

            // Put element as child
            parent.replaceChild(wrapper, el);
            wrapper.appendChild(el);
          }
        }
      }
    };


    /**
     * Disable mousedown event for 500ms during and after touch
     */
    var TouchHandler = {
      /* uses an integer rather than bool so there's no issues with
       * needing to clear timeouts if another touch event occurred
       * within the 500ms. Cannot mouseup between touchstart and
       * touchend, nor in the 500ms after touchend. */
      touches: 0,
      allowEvent: function (e) {
        var allow = true;

        if (e.type === 'touchstart') {
          TouchHandler.touches += 1; //push
        } else if (e.type === 'touchend' || e.type === 'touchcancel') {
          setTimeout(function () {
            if (TouchHandler.touches > 0) {
              TouchHandler.touches -= 1; //pop after 500ms
            }
          }, 500);
        } else if (e.type === 'mousedown' && TouchHandler.touches > 0) {
          allow = false;
        }

        return allow;
      },
      touchup: function (e) {
        TouchHandler.allowEvent(e);
      }
    };


    /**
     * Delegated click handler for .waves-effect element.
     * returns null when .waves-effect element not in "click tree"
     */
    function getWavesEffectElement (e) {
      if (TouchHandler.allowEvent(e) === false) {
        return null;
      }

      var element = null;
      var target = e.target || e.srcElement;

      while (target.parentNode !== null) {
        if (!(target instanceof SVGElement) && target.className.indexOf('waves-effect') !== -1) {
          element = target;
          break;
        }
        target = target.parentNode;
      }
      return element;
    }

    /**
     * Bubble the click and show effect if .waves-effect elem was found
     */
    function showEffect (e) {
      var element = getWavesEffectElement(e);

      if (element !== null) {
        Effect.show(e, element);

        if ('ontouchstart' in window) {
          element.addEventListener('touchend', Effect.hide, false);
          element.addEventListener('touchcancel', Effect.hide, false);
        }

        element.addEventListener('mouseup', Effect.hide, false);
        element.addEventListener('mouseleave', Effect.hide, false);
        element.addEventListener('dragend', Effect.hide, false);
      }
    }

    Waves.displayEffect = function (options) {
      options = options || {};

      if ('duration' in options) {
        Effect.duration = options.duration;
      }

      //Wrap input inside <i> tag
      Effect.wrapInput($$('.waves-effect'));

      if ('ontouchstart' in window) {
        document.body.addEventListener('touchstart', showEffect, false);
      }

      document.body.addEventListener('mousedown', showEffect, false);
    };

    /**
     * Attach Waves to an input element (or any element which doesn't
     * bubble mouseup/mousedown events).
     *   Intended to be used with dynamically loaded forms/inputs, or
     * where the user doesn't want a delegated click handler.
     */
    Waves.attach = function (element) {
      //FUTURE: automatically add waves classes and allow users
      // to specify them with an options param? Eg. light/classic/button
      if (element.tagName.toLowerCase() === 'input') {
        Effect.wrapInput([element]);
        element = element.parentNode;
      }

      if ('ontouchstart' in window) {
        element.addEventListener('touchstart', showEffect, false);
      }

      element.addEventListener('mousedown', showEffect, false);
    };

    window.Waves = Waves;

    document.addEventListener('DOMContentLoaded', function () {
      Waves.displayEffect();
    }, false);

  })(window);

  (function ($) {
    // Function to update labels of text fields
    M.updateTextFields = function () {
      let input_selector =
        'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea';
      $(input_selector).each(function (element, index) {
        let $this = $(this);
        if (
          element.value.length > 0 ||
          $(element).is(':focus') ||
          element.autofocus ||
          $this.attr('placeholder') !== null
        ) {
          $this.siblings('label').addClass('active');
        } else if (element.validity) {
          $this.siblings('label').toggleClass('active', element.validity.badInput === true);
        } else {
          $this.siblings('label').removeClass('active');
        }
      });
    };

    M.validate_field = function (object) {
      let hasLength = object.attr('data-length') !== null;
      let lenAttr = parseInt(object.attr('data-length'));
      let len = object[0].value.length;

      if (len === 0 && object[0].validity.badInput === false && !object.is(':required')) {
        if (object.hasClass('validate')) {
          object.removeClass('valid');
          object.removeClass('invalid');
        }
      } else {
        if (object.hasClass('validate')) {
          // Check for character counter attributes
          if (
            (object.is(':valid') && hasLength && len <= lenAttr) ||
            (object.is(':valid') && !hasLength)
          ) {
            object.removeClass('invalid');
            object.addClass('valid');
          } else {
            object.removeClass('valid');
            object.addClass('invalid');
          }
        }
      }
    };

    M.textareaAutoResize = function ($textarea) {
      // Wrap if native element
      if ($textarea instanceof Element) {
        $textarea = $($textarea);
      }

      if (!$textarea.length) {
        console.error('No textarea element found');
        return;
      }

      // Textarea Auto Resize
      let hiddenDiv = $('.hiddendiv').first();
      if (!hiddenDiv.length) {
        hiddenDiv = $('<div class="hiddendiv common"></div>');
        $('body').append(hiddenDiv);
      }

      // Set font properties of hiddenDiv
      let fontFamily = $textarea.css('font-family');
      let fontSize = $textarea.css('font-size');
      let lineHeight = $textarea.css('line-height');

      // Firefox can't handle padding shorthand.
      let paddingTop = $textarea.css('padding-top');
      let paddingRight = $textarea.css('padding-right');
      let paddingBottom = $textarea.css('padding-bottom');
      let paddingLeft = $textarea.css('padding-left');

      if (fontSize) {
        hiddenDiv.css('font-size', fontSize);
      }
      if (fontFamily) {
        hiddenDiv.css('font-family', fontFamily);
      }
      if (lineHeight) {
        hiddenDiv.css('line-height', lineHeight);
      }
      if (paddingTop) {
        hiddenDiv.css('padding-top', paddingTop);
      }
      if (paddingRight) {
        hiddenDiv.css('padding-right', paddingRight);
      }
      if (paddingBottom) {
        hiddenDiv.css('padding-bottom', paddingBottom);
      }
      if (paddingLeft) {
        hiddenDiv.css('padding-left', paddingLeft);
      }

      // Set original-height, if none
      if (!$textarea.data('original-height')) {
        $textarea.data('original-height', $textarea.height());
      }

      if ($textarea.attr('wrap') === 'off') {
        hiddenDiv.css('overflow-wrap', 'normal').css('white-space', 'pre');
      }

      hiddenDiv.text($textarea[0].value + '\n');
      let content = hiddenDiv.html().replace(/\n/g, '<br>');
      hiddenDiv.html(content);

      // When textarea is hidden, width goes crazy.
      // Approximate with half of window size

      if ($textarea[0].offsetWidth > 0 && $textarea[0].offsetHeight > 0) {
        hiddenDiv.css('width', $textarea.width() + 'px');
      } else {
        hiddenDiv.css('width', window.innerWidth / 2 + 'px');
      }

      /**
       * Resize if the new height is greater than the
       * original height of the textarea
       */
      if ($textarea.data('original-height') <= hiddenDiv.innerHeight()) {
        $textarea.css('height', hiddenDiv.innerHeight() + 'px');
      } else if ($textarea[0].value.length < $textarea.data('previous-length')) {
        /**
         * In case the new height is less than original height, it
         * means the textarea has less text than before
         * So we set the height to the original one
         */
        $textarea.css('height', $textarea.data('original-height') + 'px');
      }
      $textarea.data('previous-length', $textarea[0].value.length);
    };

    $(document).ready(function () {
      // Text based inputs
      let input_selector =
        'input[type=text], input[type=password], input[type=email], input[type=url], input[type=tel], input[type=number], input[type=search], input[type=date], input[type=time], textarea';

      // Add active if form auto complete
      $(document).on('change', input_selector, function () {
        if (this.value.length !== 0 || $(this).attr('placeholder') !== null) {
          $(this)
            .siblings('label')
            .addClass('active');
        }
        M.validate_field($(this));
      });

      // Add active if input element has been pre-populated on document ready
      $(document).ready(function () {
        M.updateTextFields();
      });

      // HTML DOM FORM RESET handling
      $(document).on('reset', function (e) {
        let formReset = $(e.target);
        if (formReset.is('form')) {
          formReset
            .find(input_selector)
            .removeClass('valid')
            .removeClass('invalid');
          formReset.find(input_selector).each(function (e) {
            if (this.value.length) {
              $(this)
                .siblings('label')
                .removeClass('active');
            }
          });

          // Reset select (after native reset)
          setTimeout(function () {
            formReset.find('select').each(function () {
              // check if initialized
              if (this.M_FormSelect) {
                $(this).trigger('change');
              }
            });
          }, 0);
        }
      });

      /**
       * Add active when element has focus
       * @param {Event} e
       */
      document.addEventListener(
        'focus',
        function (e) {
          if ($(e.target).is(input_selector)) {
            $(e.target)
              .siblings('label, .prefix')
              .addClass('active');
          }
        },
        true
      );

      /**
       * Remove active when element is blurred
       * @param {Event} e
       */
      document.addEventListener(
        'blur',
        function (e) {
          let $inputElement = $(e.target);
          if ($inputElement.is(input_selector)) {
            let selector = '.prefix';

            if (
              $inputElement[0].value.length === 0 &&
              $inputElement[0].validity.badInput !== true &&
              $inputElement.attr('placeholder') === null
            ) {
              selector += ', label';
            }
            $inputElement.siblings(selector).removeClass('active');
            M.validate_field($inputElement);
          }
        },
        true
      );

      // Radio and Checkbox focus class
      let radio_checkbox = 'input[type=radio], input[type=checkbox]';
      $(document).on('keyup', radio_checkbox, function (e) {
        // TAB, check if tabbing to radio or checkbox.
        if (e.which === M.keys.TAB) {
          $(this).addClass('tabbed');
          let $this = $(this);
          $this.one('blur', function (e) {
            $(this).removeClass('tabbed');
          });
          return;
        }
      });

      let text_area_selector = '.materialize-textarea';
      $(text_area_selector).each(function () {
        let $textarea = $(this);
        /**
         * Resize textarea on document load after storing
         * the original height and the original length
         */
        $textarea.data('original-height', $textarea.height());
        $textarea.data('previous-length', this.value.length);
        M.textareaAutoResize($textarea);
      });

      $(document).on('keyup', text_area_selector, function () {
        M.textareaAutoResize($(this));
      });
      $(document).on('keydown', text_area_selector, function () {
        M.textareaAutoResize($(this));
      });

      // File Input Path
      $(document).on('change', '.file-field input[type="file"]', function () {
        let file_field = $(this).closest('.file-field');
        let path_input = file_field.find('input.file-path');
        let files = $(this)[0].files;
        let file_names = [];
        for (let i = 0; i < files.length; i++) {
          file_names.push(files[i].name);
        }
        path_input[0].value = file_names.join(', ');
        path_input.trigger('change');
      });
    }); // End of $(document).ready
  })(cash);

  (function ($, anim) {
    'use strict';

    let _defaults = {
      direction: 'top',
      hoverEnabled: true,
      toolbarEnabled: false
    };

    $.fn.reverse = [].reverse;

    /**
     * @class
     *
     */
    class FloatingActionButton extends Component {
      /**
       * Construct FloatingActionButton instance
       * @constructor
       * @param {Element} el
       * @param {Object} options
       */
      constructor (el, options) {
        super(FloatingActionButton, el, options);

        this.el.M_FloatingActionButton = this;

        /**
         * Options for the fab
         * @member FloatingActionButton#options
         * @prop {Boolean} [direction] - Direction fab menu opens
         * @prop {Boolean} [hoverEnabled=true] - Enable hover vs click
         * @prop {Boolean} [toolbarEnabled=false] - Enable toolbar transition
         */
        this.options = $.extend({}, FloatingActionButton.defaults, options);

        this.isOpen = false;
        this.$anchor = this.$el.children('a').first();
        this.$menu = this.$el.children('ul').first();
        this.$floatingBtns = this.$el.find('ul .btn-floating');
        this.$floatingBtnsReverse = this.$el.find('ul .btn-floating').reverse();
        this.offsetY = 0;
        this.offsetX = 0;

        this.$el.addClass(`direction-${this.options.direction}`);
        if (this.options.direction === 'top') {
          this.offsetY = 40;
        } else if (this.options.direction === 'right') {
          this.offsetX = -40;
        } else if (this.options.direction === 'bottom') {
          this.offsetY = -40;
        } else {
          this.offsetX = 40;
        }
        this._setupEventHandlers();
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_FloatingActionButton;
      }

      /**
       * Teardown component
       */
      destroy () {
        this._removeEventHandlers();
        this.el.M_FloatingActionButton = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        this._handleFABClickBound = this._handleFABClick.bind(this);
        this._handleOpenBound = this.open.bind(this);
        this._handleCloseBound = this.close.bind(this);

        if (this.options.hoverEnabled && !this.options.toolbarEnabled) {
          this.el.addEventListener('mouseenter', this._handleOpenBound);
          this.el.addEventListener('mouseleave', this._handleCloseBound);
        } else {
          this.el.addEventListener('click', this._handleFABClickBound);
        }
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        if (this.options.hoverEnabled && !this.options.toolbarEnabled) {
          this.el.removeEventListener('mouseenter', this._handleOpenBound);
          this.el.removeEventListener('mouseleave', this._handleCloseBound);
        } else {
          this.el.removeEventListener('click', this._handleFABClickBound);
        }
      }

      /**
       * Handle FAB Click
       */
      _handleFABClick () {
        if (this.isOpen) {
          this.close();
        } else {
          this.open();
        }
      }

      /**
       * Handle Document Click
       * @param {Event} e
       */
      _handleDocumentClick (e) {
        if (!$(e.target).closest(this.$menu).length) {
          this.close();
        }
      }

      /**
       * Open FAB
       */
      open () {
        if (this.isOpen) {
          return;
        }

        if (this.options.toolbarEnabled) {
          this._animateInToolbar();
        } else {
          this._animateInFAB();
        }
        this.isOpen = true;
      }

      /**
       * Close FAB
       */
      close () {
        if (!this.isOpen) {
          return;
        }

        if (this.options.toolbarEnabled) {
          window.removeEventListener('scroll', this._handleCloseBound, true);
          document.body.removeEventListener('click', this._handleDocumentClickBound, true);
          this._animateOutToolbar();
        } else {
          this._animateOutFAB();
        }
        this.isOpen = false;
      }

      /**
       * Classic FAB Menu open
       */
      _animateInFAB () {
        this.$el.addClass('active');

        let time = 0;
        this.$floatingBtnsReverse.each((el) => {
          anim({
            targets: el,
            opacity: 1,
            scale: [0.4, 1],
            translateY: [this.offsetY, 0],
            translateX: [this.offsetX, 0],
            duration: 275,
            delay: time,
            easing: 'easeInOutQuad'
          });
          time += 40;
        });
      }

      /**
       * Classic FAB Menu close
       */
      _animateOutFAB () {
        this.$floatingBtnsReverse.each((el) => {
          anim.remove(el);
          anim({
            targets: el,
            opacity: 0,
            scale: 0.4,
            translateY: this.offsetY,
            translateX: this.offsetX,
            duration: 175,
            easing: 'easeOutQuad',
            complete: () => {
              this.$el.removeClass('active');
            }
          });
        });
      }

      /**
       * Toolbar transition Menu open
       */
      _animateInToolbar () {
        let scaleFactor;
        let windowWidth = window.innerWidth;
        let windowHeight = window.innerHeight;
        let btnRect = this.el.getBoundingClientRect();
        let backdrop = $('<div class="fab-backdrop"></div>');
        let fabColor = this.$anchor.css('background-color');
        this.$anchor.append(backdrop);

        this.offsetX = btnRect.left - windowWidth / 2 + btnRect.width / 2;
        this.offsetY = windowHeight - btnRect.bottom;
        scaleFactor = windowWidth / backdrop[0].clientWidth;
        this.btnBottom = btnRect.bottom;
        this.btnLeft = btnRect.left;
        this.btnWidth = btnRect.width;

        // Set initial state
        this.$el.addClass('active');
        this.$el.css({
          'text-align': 'center',
          width: '100%',
          bottom: 0,
          left: 0,
          transform: 'translateX(' + this.offsetX + 'px)',
          transition: 'none'
        });
        this.$anchor.css({
          transform: 'translateY(' + -this.offsetY + 'px)',
          transition: 'none'
        });
        backdrop.css({
          'background-color': fabColor
        });

        setTimeout(() => {
          this.$el.css({
            transform: '',
            transition:
              'transform .2s cubic-bezier(0.550, 0.085, 0.680, 0.530), background-color 0s linear .2s'
          });
          this.$anchor.css({
            overflow: 'visible',
            transform: '',
            transition: 'transform .2s'
          });

          setTimeout(() => {
            this.$el.css({
              overflow: 'hidden',
              'background-color': fabColor
            });
            backdrop.css({
              transform: 'scale(' + scaleFactor + ')',
              transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
            });
            this.$menu
              .children('li')
              .children('a')
              .css({
                opacity: 1
              });

            // Scroll to close.
            this._handleDocumentClickBound = this._handleDocumentClick.bind(this);
            window.addEventListener('scroll', this._handleCloseBound, true);
            document.body.addEventListener('click', this._handleDocumentClickBound, true);
          }, 100);
        }, 0);
      }

      /**
       * Toolbar transition Menu close
       */
      _animateOutToolbar () {
        let windowWidth = window.innerWidth;
        let windowHeight = window.innerHeight;
        let backdrop = this.$el.find('.fab-backdrop');
        let fabColor = this.$anchor.css('background-color');

        this.offsetX = this.btnLeft - windowWidth / 2 + this.btnWidth / 2;
        this.offsetY = windowHeight - this.btnBottom;

        // Hide backdrop
        this.$el.removeClass('active');
        this.$el.css({
          'background-color': 'transparent',
          transition: 'none'
        });
        this.$anchor.css({
          transition: 'none'
        });
        backdrop.css({
          transform: 'scale(0)',
          'background-color': fabColor
        });
        this.$menu
          .children('li')
          .children('a')
          .css({
            opacity: ''
          });

        setTimeout(() => {
          backdrop.remove();

          // Set initial state.
          this.$el.css({
            'text-align': '',
            width: '',
            bottom: '',
            left: '',
            overflow: '',
            'background-color': '',
            transform: 'translate3d(' + -this.offsetX + 'px,0,0)'
          });
          this.$anchor.css({
            overflow: '',
            transform: 'translate3d(0,' + this.offsetY + 'px,0)'
          });

          setTimeout(() => {
            this.$el.css({
              transform: 'translate3d(0,0,0)',
              transition: 'transform .2s'
            });
            this.$anchor.css({
              transform: 'translate3d(0,0,0)',
              transition: 'transform .2s cubic-bezier(0.550, 0.055, 0.675, 0.190)'
            });
          }, 20);
        }, 200);
      }
    }

    M.FloatingActionButton = FloatingActionButton;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(
        FloatingActionButton,
        'floatingActionButton',
        'M_FloatingActionButton'
      );
    }
  })(cash, M.anime);

  (function ($) {
    'use strict';

    let _defaults = {
      onOpen: undefined,
      onClose: undefined
    };

    /**
     * @class
     *
     */
    class TapTarget extends Component {
      /**
       * Construct TapTarget instance
       * @constructor
       * @param {Element} el
       * @param {Object} options
       */
      constructor (el, options) {
        super(TapTarget, el, options);

        this.el.M_TapTarget = this;

        /**
         * Options for the select
         * @member TapTarget#options
         * @prop {Function} onOpen - Callback function called when feature discovery is opened
         * @prop {Function} onClose - Callback function called when feature discovery is closed
         */
        this.options = $.extend({}, TapTarget.defaults, options);

        this.isOpen = false;

        // setup
        this.$origin = $('#' + this.$el.attr('data-target'));
        this._setup();

        this._calculatePositioning();
        this._setupEventHandlers();
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_TapTarget;
      }

      /**
       * Teardown component
       */
      destroy () {
        this._removeEventHandlers();
        this.el.TapTarget = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        this._handleDocumentClickBound = this._handleDocumentClick.bind(this);
        this._handleTargetClickBound = this._handleTargetClick.bind(this);
        this._handleOriginClickBound = this._handleOriginClick.bind(this);

        this.el.addEventListener('click', this._handleTargetClickBound);
        this.originEl.addEventListener('click', this._handleOriginClickBound);

        // Resize
        let throttledResize = M.throttle(this._handleResize, 200);
        this._handleThrottledResizeBound = throttledResize.bind(this);

        window.addEventListener('resize', this._handleThrottledResizeBound);
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        this.el.removeEventListener('click', this._handleTargetClickBound);
        this.originEl.removeEventListener('click', this._handleOriginClickBound);
        window.removeEventListener('resize', this._handleThrottledResizeBound);
      }

      /**
       * Handle Target Click
       * @param {Event} e
       */
      _handleTargetClick (e) {
        this.open();
      }

      /**
       * Handle Origin Click
       * @param {Event} e
       */
      _handleOriginClick (e) {
        this.close();
      }

      /**
       * Handle Resize
       * @param {Event} e
       */
      _handleResize (e) {
        this._calculatePositioning();
      }

      /**
       * Handle Resize
       * @param {Event} e
       */
      _handleDocumentClick (e) {
        if (!$(e.target).closest('.tap-target-wrapper').length) {
          this.close();
          e.preventDefault();
          e.stopPropagation();
        }
      }

      /**
       * Setup Tap Target
       */
      _setup () {
        // Creating tap target
        this.wrapper = this.$el.parent()[0];
        this.waveEl = $(this.wrapper).find('.tap-target-wave')[0];
        this.originEl = $(this.wrapper).find('.tap-target-origin')[0];
        this.contentEl = this.$el.find('.tap-target-content')[0];

        // Creating wrapper
        if (!$(this.wrapper).hasClass('.tap-target-wrapper')) {
          this.wrapper = document.createElement('div');
          this.wrapper.classList.add('tap-target-wrapper');
          this.$el.before($(this.wrapper));
          this.wrapper.append(this.el);
        }

        // Creating content
        if (!this.contentEl) {
          this.contentEl = document.createElement('div');
          this.contentEl.classList.add('tap-target-content');
          this.$el.append(this.contentEl);
        }

        // Creating foreground wave
        if (!this.waveEl) {
          this.waveEl = document.createElement('div');
          this.waveEl.classList.add('tap-target-wave');

          // Creating origin
          if (!this.originEl) {
            this.originEl = this.$origin.clone(true, true);
            this.originEl.addClass('tap-target-origin');
            this.originEl.removeAttr('id');
            this.originEl.removeAttr('style');
            this.originEl = this.originEl[0];
            this.waveEl.append(this.originEl);
          }

          this.wrapper.append(this.waveEl);
        }
      }

      /**
       * Calculate positioning
       */
      _calculatePositioning () {
        // Element or parent is fixed position?
        let isFixed = this.$origin.css('position') === 'fixed';
        if (!isFixed) {
          let parents = this.$origin.parents();
          for (let i = 0; i < parents.length; i++) {
            isFixed = $(parents[i]).css('position') == 'fixed';
            if (isFixed) {
              break;
            }
          }
        }

        // Calculating origin
        let originWidth = this.$origin.outerWidth();
        let originHeight = this.$origin.outerHeight();
        let originTop = isFixed
          ? this.$origin.offset().top - M.getDocumentScrollTop()
          : this.$origin.offset().top;
        let originLeft = isFixed
          ? this.$origin.offset().left - M.getDocumentScrollLeft()
          : this.$origin.offset().left;

        // Calculating screen
        let windowWidth = window.innerWidth;
        let windowHeight = window.innerHeight;
        let centerX = windowWidth / 2;
        let centerY = windowHeight / 2;
        let isLeft = originLeft <= centerX;
        let isRight = originLeft > centerX;
        let isTop = originTop <= centerY;
        let isBottom = originTop > centerY;
        let isCenterX = originLeft >= windowWidth * 0.25 && originLeft <= windowWidth * 0.75;

        // Calculating tap target
        let tapTargetWidth = this.$el.outerWidth();
        let tapTargetHeight = this.$el.outerHeight();
        let tapTargetTop = originTop + originHeight / 2 - tapTargetHeight / 2;
        let tapTargetLeft = originLeft + originWidth / 2 - tapTargetWidth / 2;
        let tapTargetPosition = isFixed ? 'fixed' : 'absolute';

        // Calculating content
        let tapTargetTextWidth = isCenterX ? tapTargetWidth : tapTargetWidth / 2 + originWidth;
        let tapTargetTextHeight = tapTargetHeight / 2;
        let tapTargetTextTop = isTop ? tapTargetHeight / 2 : 0;
        let tapTargetTextBottom = 0;
        let tapTargetTextLeft = isLeft && !isCenterX ? tapTargetWidth / 2 - originWidth : 0;
        let tapTargetTextRight = 0;
        let tapTargetTextPadding = originWidth;
        let tapTargetTextAlign = isBottom ? 'bottom' : 'top';

        // Calculating wave
        let tapTargetWaveWidth = originWidth > originHeight ? originWidth * 2 : originWidth * 2;
        let tapTargetWaveHeight = tapTargetWaveWidth;
        let tapTargetWaveTop = tapTargetHeight / 2 - tapTargetWaveHeight / 2;
        let tapTargetWaveLeft = tapTargetWidth / 2 - tapTargetWaveWidth / 2;

        // Setting tap target
        let tapTargetWrapperCssObj = {};
        tapTargetWrapperCssObj.top = isTop ? tapTargetTop + 'px' : '';
        tapTargetWrapperCssObj.right = isRight
          ? windowWidth - tapTargetLeft - tapTargetWidth + 'px'
          : '';
        tapTargetWrapperCssObj.bottom = isBottom
          ? windowHeight - tapTargetTop - tapTargetHeight + 'px'
          : '';
        tapTargetWrapperCssObj.left = isLeft ? tapTargetLeft + 'px' : '';
        tapTargetWrapperCssObj.position = tapTargetPosition;
        $(this.wrapper).css(tapTargetWrapperCssObj);

        // Setting content
        $(this.contentEl).css({
          width: tapTargetTextWidth + 'px',
          height: tapTargetTextHeight + 'px',
          top: tapTargetTextTop + 'px',
          right: tapTargetTextRight + 'px',
          bottom: tapTargetTextBottom + 'px',
          left: tapTargetTextLeft + 'px',
          padding: tapTargetTextPadding + 'px',
          verticalAlign: tapTargetTextAlign
        });

        // Setting wave
        $(this.waveEl).css({
          top: tapTargetWaveTop + 'px',
          left: tapTargetWaveLeft + 'px',
          width: tapTargetWaveWidth + 'px',
          height: tapTargetWaveHeight + 'px'
        });
      }

      /**
       * Open TapTarget
       */
      open () {
        if (this.isOpen) {
          return;
        }

        // onOpen callback
        if (typeof this.options.onOpen === 'function') {
          this.options.onOpen.call(this, this.$origin[0]);
        }

        this.isOpen = true;
        this.wrapper.classList.add('open');

        document.body.addEventListener('click', this._handleDocumentClickBound, true);
        document.body.addEventListener('touchend', this._handleDocumentClickBound);
      }

      /**
       * Close Tap Target
       */
      close () {
        if (!this.isOpen) {
          return;
        }

        // onClose callback
        if (typeof this.options.onClose === 'function') {
          this.options.onClose.call(this, this.$origin[0]);
        }

        this.isOpen = false;
        this.wrapper.classList.remove('open');

        document.body.removeEventListener('click', this._handleDocumentClickBound, true);
        document.body.removeEventListener('touchend', this._handleDocumentClickBound);
      }
    }

    M.TapTarget = TapTarget;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(TapTarget, 'tapTarget', 'M_TapTarget');
    }
  })(cash);

  (function ($) {
    'use strict';

    let _defaults = {
      classes: '',
      dropdownOptions: {}
    };

    /**
     * @class
     *
     */
    class FormSelect extends Component {
      /**
       * Construct FormSelect instance
       * @constructor
       * @param {Element} el
       * @param {Object} options
       */
      constructor (el, options) {
        super(FormSelect, el, options);

        // Don't init if browser default version
        if (this.$el.hasClass('browser-default')) {
          return;
        }

        this.el.M_FormSelect = this;

        /**
         * Options for the select
         * @member FormSelect#options
         */
        this.options = $.extend({}, FormSelect.defaults, options);

        this.isMultiple = this.$el.prop('multiple');

        // Setup
        this.el.tabIndex = -1;
        this._keysSelected = {};
        this._valueDict = {}; // Maps key to original and generated option element.
        this._setupDropdown();

        this._setupEventHandlers();
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_FormSelect;
      }

      /**
       * Teardown component
       */
      destroy () {
        this._removeEventHandlers();
        this._removeDropdown();
        this.el.M_FormSelect = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        this._handleSelectChangeBound = this._handleSelectChange.bind(this);
        this._handleOptionClickBound = this._handleOptionClick.bind(this);
        this._handleInputClickBound = this._handleInputClick.bind(this);

        $(this.dropdownOptions)
          .find('li:not(.optgroup)')
          .each((el) => {
            el.addEventListener('click', this._handleOptionClickBound);
          });
        this.el.addEventListener('change', this._handleSelectChangeBound);
        this.input.addEventListener('click', this._handleInputClickBound);
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        $(this.dropdownOptions)
          .find('li:not(.optgroup)')
          .each((el) => {
            el.removeEventListener('click', this._handleOptionClickBound);
          });
        this.el.removeEventListener('change', this._handleSelectChangeBound);
        this.input.removeEventListener('click', this._handleInputClickBound);
      }

      /**
       * Handle Select Change
       * @param {Event} e
       */
      _handleSelectChange (e) {
        this._setValueToInput();
      }

      /**
       * Handle Option Click
       * @param {Event} e
       */
      _handleOptionClick (e) {
        e.preventDefault();
        let option = $(e.target).closest('li')[0];
        let key = option.id;
        if (!$(option).hasClass('disabled') && !$(option).hasClass('optgroup') && key.length) {
          let selected = true;

          if (this.isMultiple) {
            // Deselect placeholder option if still selected.
            let placeholderOption = $(this.dropdownOptions).find('li.disabled.selected');
            if (placeholderOption.length) {
              placeholderOption.removeClass('selected');
              placeholderOption.find('input[type="checkbox"]').prop('checked', false);
              this._toggleEntryFromArray(placeholderOption[0].id);
            }
            selected = this._toggleEntryFromArray(key);
          } else {
            $(this.dropdownOptions)
              .find('li')
              .removeClass('selected');
            $(option).toggleClass('selected', selected);
            this._keysSelected = {};
            this._keysSelected[option.id] = true;
          }

          // Set selected on original select option
          // Only trigger if selected state changed
          let prevSelected = $(this._valueDict[key].el).prop('selected');
          if (prevSelected !== selected) {
            $(this._valueDict[key].el).prop('selected', selected);
            this.$el.trigger('change');
          }
        }

        e.stopPropagation();
      }

      /**
       * Handle Input Click
       */
      _handleInputClick () {
        if (this.dropdown && this.dropdown.isOpen) {
          this._setValueToInput();
          this._setSelectedStates();
        }
      }

      /**
       * Setup dropdown
       */
      _setupDropdown () {
        this.wrapper = document.createElement('div');
        $(this.wrapper).addClass('select-wrapper ' + this.options.classes);
        this.$el.before($(this.wrapper));
        this.wrapper.appendChild(this.el);

        if (this.el.disabled) {
          this.wrapper.classList.add('disabled');
        }

        // Create dropdown
        this.$selectOptions = this.$el.children('option, optgroup');
        this.dropdownOptions = document.createElement('ul');
        this.dropdownOptions.id = `select-options-${M.guid()}`;
        $(this.dropdownOptions).addClass(
          'dropdown-content select-dropdown ' + (this.isMultiple ? 'multiple-select-dropdown' : '')
        );

        // Create dropdown structure.
        if (this.$selectOptions.length) {
          this.$selectOptions.each((el) => {
            if ($(el).is('option')) {
              // Direct descendant option.
              let optionEl;
              if (this.isMultiple) {
                optionEl = this._appendOptionWithIcon(this.$el, el, 'multiple');
              } else {
                optionEl = this._appendOptionWithIcon(this.$el, el);
              }

              this._addOptionToValueDict(el, optionEl);
            } else if ($(el).is('optgroup')) {
              // Optgroup.
              let selectOptions = $(el).children('option');
              $(this.dropdownOptions).append(
                $('<li class="optgroup"><span>' + el.getAttribute('label') + '</span></li>')[0]
              );

              selectOptions.each((el) => {
                let optionEl = this._appendOptionWithIcon(this.$el, el, 'optgroup-option');
                this._addOptionToValueDict(el, optionEl);
              });
            }
          });
        }

        this.$el.after(this.dropdownOptions);

        // Add input dropdown
        this.input = document.createElement('input');
        $(this.input).addClass('select-dropdown dropdown-trigger');
        this.input.setAttribute('type', 'text');
        this.input.setAttribute('readonly', 'true');
        this.input.setAttribute('data-target', this.dropdownOptions.id);
        if (this.el.disabled) {
          $(this.input).prop('disabled', 'true');
        }

        this.$el.before(this.input);
        this._setValueToInput();

        // Add caret
        let dropdownIcon = $(
          '<svg class="caret" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg"><path d="M7 10l5 5 5-5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>'
        );
        this.$el.before(dropdownIcon[0]);

        // Initialize dropdown
        if (!this.el.disabled) {
          let dropdownOptions = $.extend({}, this.options.dropdownOptions);

          // Add callback for centering selected option when dropdown content is scrollable
          dropdownOptions.onOpenEnd = (el) => {
            let selectedOption = $(this.dropdownOptions)
              .find('.selected')
              .first();

            if (selectedOption.length) {
              // Focus selected option in dropdown
              M.keyDown = true;
              this.dropdown.focusedIndex = selectedOption.index();
              this.dropdown._focusFocusedItem();
              M.keyDown = false;

              // Handle scrolling to selected option
              if (this.dropdown.isScrollable) {
                let scrollOffset =
                  selectedOption[0].getBoundingClientRect().top -
                  this.dropdownOptions.getBoundingClientRect().top; // scroll to selected option
                scrollOffset -= this.dropdownOptions.clientHeight / 2; // center in dropdown
                this.dropdownOptions.scrollTop = scrollOffset;
              }
            }
          };

          if (this.isMultiple) {
            dropdownOptions.closeOnClick = false;
          }
          this.dropdown = M.Dropdown.init(this.input, dropdownOptions);
        }

        // Add initial selections
        this._setSelectedStates();
      }

      /**
       * Add option to value dict
       * @param {Element} el  original option element
       * @param {Element} optionEl  generated option element
       */
      _addOptionToValueDict (el, optionEl) {
        let index = Object.keys(this._valueDict).length;
        let key = this.dropdownOptions.id + index;
        let obj = {};
        optionEl.id = key;

        obj.el = el;
        obj.optionEl = optionEl;
        this._valueDict[key] = obj;
      }

      /**
       * Remove dropdown
       */
      _removeDropdown () {
        $(this.wrapper)
          .find('.caret')
          .remove();
        $(this.input).remove();
        $(this.dropdownOptions).remove();
        $(this.wrapper).before(this.$el);
        $(this.wrapper).remove();
      }

      /**
       * Setup dropdown
       * @param {Element} select  select element
       * @param {Element} option  option element from select
       * @param {String} type
       * @return {Element}  option element added
       */
      _appendOptionWithIcon (select, option, type) {
        // Add disabled attr if disabled
        let disabledClass = option.disabled ? 'disabled ' : '';
        let optgroupClass = type === 'optgroup-option' ? 'optgroup-option ' : '';
        let multipleCheckbox = this.isMultiple
          ? `<label><input type="checkbox"${disabledClass}"/><span>${option.innerHTML}</span></label>`
          : option.innerHTML;
        let liEl = $('<li></li>');
        let spanEl = $('<span></span>');
        spanEl.html(multipleCheckbox);
        liEl.addClass(`${disabledClass} ${optgroupClass}`);
        liEl.append(spanEl);

        // add icons
        let iconUrl = option.getAttribute('data-icon');
        if (!!iconUrl) {
          let imgEl = $(`<img alt="" src="${iconUrl}">`);
          liEl.prepend(imgEl);
        }

        // Check for multiple type.
        $(this.dropdownOptions).append(liEl[0]);
        return liEl[0];
      }

      /**
       * Toggle entry from option
       * @param {String} key  Option key
       * @return {Boolean}  if entry was added or removed
       */
      _toggleEntryFromArray (key) {
        let notAdded = !this._keysSelected.hasOwnProperty(key);
        let $optionLi = $(this._valueDict[key].optionEl);

        if (notAdded) {
          this._keysSelected[key] = true;
        } else {
          delete this._keysSelected[key];
        }

        $optionLi.toggleClass('selected', notAdded);

        // Set checkbox checked value
        $optionLi.find('input[type="checkbox"]').prop('checked', notAdded);

        // use notAdded instead of true (to detect if the option is selected or not)
        $optionLi.prop('selected', notAdded);

        return notAdded;
      }

      /**
       * Set text value to input
       */
      _setValueToInput () {
        let values = [];
        let options = this.$el.find('option');

        options.each((el) => {
          if ($(el).prop('selected')) {
            let text = $(el).text();
            values.push(text);
          }
        });

        if (!values.length) {
          let firstDisabled = this.$el.find('option:disabled').eq(0);
          if (firstDisabled.length && firstDisabled[0].value === '') {
            values.push(firstDisabled.text());
          }
        }

        this.input.value = values.join(', ');
      }

      /**
       * Set selected state of dropdown to match actual select element
       */
      _setSelectedStates () {
        this._keysSelected = {};

        for (let key in this._valueDict) {
          let option = this._valueDict[key];
          let optionIsSelected = $(option.el).prop('selected');
          $(option.optionEl)
            .find('input[type="checkbox"]')
            .prop('checked', optionIsSelected);
          if (optionIsSelected) {
            this._activateOption($(this.dropdownOptions), $(option.optionEl));
            this._keysSelected[key] = true;
          } else {
            $(option.optionEl).removeClass('selected');
          }
        }
      }

      /**
       * Make option as selected and scroll to selected position
       * @param {jQuery} collection  Select options jQuery element
       * @param {Element} newOption  element of the new option
       */
      _activateOption (collection, newOption) {
        if (newOption) {
          if (!this.isMultiple) {
            collection.find('li.selected').removeClass('selected');
          }
          let option = $(newOption);
          option.addClass('selected');
        }
      }

      /**
       * Get Selected Values
       * @return {Array}  Array of selected values
       */
      getSelectedValues () {
        let selectedValues = [];
        for (let key in this._keysSelected) {
          selectedValues.push(this._valueDict[key].el.value);
        }
        return selectedValues;
      }
    }

    M.FormSelect = FormSelect;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(FormSelect, 'formSelect', 'M_FormSelect');
    }
  })(cash);

  (function ($, anim) {
    'use strict';

    let _defaults = {};

    /**
     * @class
     *
     */
    class Range extends Component {
      /**
       * Construct Range instance
       * @constructor
       * @param {Element} el
       * @param {Object} options
       */
      constructor (el, options) {
        super(Range, el, options);

        this.el.M_Range = this;

        /**
         * Options for the range
         * @member Range#options
         */
        this.options = $.extend({}, Range.defaults, options);

        this._mousedown = false;

        // Setup
        this._setupThumb();

        this._setupEventHandlers();
      }

      static get defaults () {
        return _defaults;
      }

      static init (els, options) {
        return super.init(this, els, options);
      }

      /**
       * Get Instance
       */
      static getInstance (el) {
        let domElem = !!el.jquery ? el[0] : el;
        return domElem.M_Range;
      }

      /**
       * Teardown component
       */
      destroy () {
        this._removeEventHandlers();
        this._removeThumb();
        this.el.M_Range = undefined;
      }

      /**
       * Setup Event Handlers
       */
      _setupEventHandlers () {
        this._handleRangeChangeBound = this._handleRangeChange.bind(this);
        this._handleRangeMousedownTouchstartBound = this._handleRangeMousedownTouchstart.bind(this);
        this._handleRangeInputMousemoveTouchmoveBound = this._handleRangeInputMousemoveTouchmove.bind(
          this
        );
        this._handleRangeMouseupTouchendBound = this._handleRangeMouseupTouchend.bind(this);
        this._handleRangeBlurMouseoutTouchleaveBound = this._handleRangeBlurMouseoutTouchleave.bind(
          this
        );

        this.el.addEventListener('change', this._handleRangeChangeBound);

        this.el.addEventListener('mousedown', this._handleRangeMousedownTouchstartBound);
        this.el.addEventListener('touchstart', this._handleRangeMousedownTouchstartBound);

        this.el.addEventListener('input', this._handleRangeInputMousemoveTouchmoveBound);
        this.el.addEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound);
        this.el.addEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound);

        this.el.addEventListener('mouseup', this._handleRangeMouseupTouchendBound);
        this.el.addEventListener('touchend', this._handleRangeMouseupTouchendBound);

        this.el.addEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound);
        this.el.addEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound);
        this.el.addEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound);
      }

      /**
       * Remove Event Handlers
       */
      _removeEventHandlers () {
        this.el.removeEventListener('change', this._handleRangeChangeBound);

        this.el.removeEventListener('mousedown', this._handleRangeMousedownTouchstartBound);
        this.el.removeEventListener('touchstart', this._handleRangeMousedownTouchstartBound);

        this.el.removeEventListener('input', this._handleRangeInputMousemoveTouchmoveBound);
        this.el.removeEventListener('mousemove', this._handleRangeInputMousemoveTouchmoveBound);
        this.el.removeEventListener('touchmove', this._handleRangeInputMousemoveTouchmoveBound);

        this.el.removeEventListener('mouseup', this._handleRangeMouseupTouchendBound);
        this.el.removeEventListener('touchend', this._handleRangeMouseupTouchendBound);

        this.el.removeEventListener('blur', this._handleRangeBlurMouseoutTouchleaveBound);
        this.el.removeEventListener('mouseout', this._handleRangeBlurMouseoutTouchleaveBound);
        this.el.removeEventListener('touchleave', this._handleRangeBlurMouseoutTouchleaveBound);
      }

      /**
       * Handle Range Change
       * @param {Event} e
       */
      _handleRangeChange () {
        $(this.value).html(this.$el.val());

        if (!$(this.thumb).hasClass('active')) {
          this._showRangeBubble();
        }

        let offsetLeft = this._calcRangeOffset();
        $(this.thumb)
          .addClass('active')
          .css('left', offsetLeft + 'px');
      }

      /**
       * Handle Range Mousedown and Touchstart
       * @param {Event} e
       */
      _handleRangeMousedownTouchstart (e) {
        // Set indicator value
        $(this.value).html(this.$el.val());

        this._mousedown = true;
        this.$el.addClass('active');

        if (!$(this.thumb).hasClass('active')) {
          this._showRangeBubble();
        }

        if (e.type !== 'input') {
          let offsetLeft = this._calcRangeOffset();
          $(this.thumb)
            .addClass('active')
            .css('left', offsetLeft + 'px');
        }
      }

      /**
       * Handle Range Input, Mousemove and Touchmove
       */
      _handleRangeInputMousemoveTouchmove () {
        if (this._mousedown) {
          if (!$(this.thumb).hasClass('active')) {
            this._showRangeBubble();
          }

          let offsetLeft = this._calcRangeOffset();
          $(this.thumb)
            .addClass('active')
            .css('left', offsetLeft + 'px');
          $(this.value).html(this.$el.val());
        }
      }

      /**
       * Handle Range Mouseup and Touchend
       */
      _handleRangeMouseupTouchend () {
        this._mousedown = false;
        this.$el.removeClass('active');
      }

      /**
       * Handle Range Blur, Mouseout and Touchleave
       */
      _handleRangeBlurMouseoutTouchleave () {
        if (!this._mousedown) {
          let paddingLeft = parseInt(this.$el.css('padding-left'));
          let marginLeft = 7 + paddingLeft + 'px';

          if ($(this.thumb).hasClass('active')) {
            anim.remove(this.thumb);
            anim({
              targets: this.thumb,
              height: 0,
              width: 0,
              top: 10,
              easing: 'easeOutQuad',
              marginLeft: marginLeft,
              duration: 100
            });
          }
          $(this.thumb).removeClass('active');
        }
      }

      /**
       * Setup dropdown
       */
      _setupThumb () {
        this.thumb = document.createElement('span');
        this.value = document.createElement('span');
        $(this.thumb).addClass('thumb');
        $(this.value).addClass('value');
        $(this.thumb).append(this.value);
        this.$el.after(this.thumb);
      }

      /**
       * Remove dropdown
       */
      _removeThumb () {
        $(this.thumb).remove();
      }

      /**
       * morph thumb into bubble
       */
      _showRangeBubble () {
        let paddingLeft = parseInt(
          $(this.thumb)
            .parent()
            .css('padding-left')
        );
        let marginLeft = -7 + paddingLeft + 'px'; // TODO: fix magic number?
        anim.remove(this.thumb);
        anim({
          targets: this.thumb,
          height: 30,
          width: 30,
          top: -30,
          marginLeft: marginLeft,
          duration: 300,
          easing: 'easeOutQuint'
        });
      }

      /**
       * Calculate the offset of the thumb
       * @return {Number}  offset in pixels
       */
      _calcRangeOffset () {
        let width = this.$el.width() - 15;
        let max = parseFloat(this.$el.attr('max')) || 100; // Range default max
        let min = parseFloat(this.$el.attr('min')) || 0; // Range default min
        let percent = (parseFloat(this.$el.val()) - min) / (max - min);
        return percent * width;
      }
    }

    M.Range = Range;

    if (M.jQueryLoaded) {
      M.initializeJqueryWrapper(Range, 'range', 'M_Range');
    }

    Range.init($('input[type=range]'));
  })(cash, M.anime);
}
