
!function(t){var e={};function n(i){if(e[i])return e[i].exports;var s=e[i]={i:i,l:!1,exports:{}};return t[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}n.m=t,n.c=e,n.d=function(t,e,i){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:i})},n.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"==typeof t&&t&&t.__esModule)return t;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var s in t)n.d(i,s,function(e){return t[e]}.bind(null,s));return i},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=0)}({"./JavaScript/Frontend/components/filter.js":
/*!**************************************************!*\
  !*** ./JavaScript/Frontend/components/filter.js ***!
  \**************************************************/
/*! exports provided: Filter */function(module,__webpack_exports__,__webpack_require__){"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Filter\", function() { return Filter; });\n/* harmony import */ var _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utility/urlUtility */ \"./JavaScript/Frontend/utility/urlUtility.js\");\n/* harmony import */ var _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../utility/loaderUtility */ \"./JavaScript/Frontend/utility/loaderUtility.js\");\n/* harmony import */ var _utility_arrayUtility__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utility/arrayUtility */ \"./JavaScript/Frontend/utility/arrayUtility.js\");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\n\n\nvar Filter = /*#__PURE__*/function () {\n  function Filter(pluginContainer) {\n    _classCallCheck(this, Filter);\n    this.identifier = {\n      container: '.in2studyfinder',\n      filterContainer: '.js-in2studyfinder-filter',\n      showFilterButton: '.js-in2studyfinder-filter-button-show',\n      hideFilterButton: '.js-in2studyfinder-filter-button-reset',\n      filterSectionContainer: '.js-in2studyfinder-filter-section-container',\n      filterOptionContainer: '.js-in2studyfinder-filter-options',\n      filterSection: '.js-in2studyfinder-filter-section',\n      filterCheckbox: '.js-in2studyfinder-checkbox',\n      filterShowAllCheckbox: '.js-in2studyfinder-checkbox-all',\n      filterRadio: '.js-in2studyfinder-radio',\n      filterLegend: '.js-in2studyfinder-filter-legend',\n      hideElement: '.u-in2studyfinder-hide'\n    };\n    this.filter = [];\n    this.studyfinderElement = pluginContainer;\n    this.filterElement = pluginContainer.querySelector(this.identifier.filterContainer);\n    this.openFilterOnLoad = true;\n  }\n  _createClass(Filter, [{\n    key: \"init\",\n    value: function init() {\n      this.setEventListener();\n      this.prepareFilter();\n      var hashArguments = _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__[\"UrlUtility\"].getHashArgumentsFromUrl();\n      if (hashArguments.length > 0) {\n        this.updateFilterByHashArguments(hashArguments);\n      }\n    }\n  }, {\n    key: \"update\",\n    value: function update(studyfinderElement) {\n      this.filterElement = studyfinderElement.querySelector(this.identifier.filterContainer);\n      this.setEventListener();\n      this.prepareFilter();\n    }\n  }, {\n    key: \"setEventListener\",\n    value: function setEventListener() {\n      // hide filter button\n      this.filterElement.querySelector(this.identifier.hideFilterButton).addEventListener('click', function (event) {\n        if (this.filter.length === 0) {\n          this.toggleFilterVisibility();\n        } else {\n          this.resetAllFilter(event);\n          this.call();\n        }\n      }.bind(this));\n\n      // show filter button\n      this.filterElement.querySelector(this.identifier.showFilterButton).addEventListener('click', function (event) {\n        this.toggleFilterVisibility(event);\n      }.bind(this));\n      this.filterElement.querySelectorAll(this.identifier.filterSection).forEach(function (fieldSet) {\n        // visibility toggle of filter sections\n        fieldSet.querySelector(this.identifier.filterLegend).addEventListener('click', function (event) {\n          event.target.nextElementSibling.classList.toggle(this.identifier.hideElement.substring(1));\n        }.bind(this));\n\n        // tab navigation for filter\n        fieldSet.addEventListener('keypress', function (event) {\n          if (event.which === 13) {\n            event.target.querySelector(this.identifier.filterLegend).click();\n          }\n        }.bind(this));\n      }.bind(this));\n\n      // set eventListener for filter checkboxes\n      this.setFilterCheckboxEventListener();\n    }\n  }, {\n    key: \"prepareFilter\",\n    value: function prepareFilter() {\n      this.prepareCheckboxes();\n\n      // open selected filter sections\n      if (this.filter.length > 0 && this.openFilterOnLoad) {\n        this.toggleFilterVisibility();\n        this.filter.forEach(function (filterName) {\n          var filterFieldset = this.filterElement.querySelector('[data-filtergroup=\"' + filterName + '\"]');\n          var filter = filterFieldset.querySelector(this.identifier.filterOptionContainer);\n          filter.classList.toggle(this.identifier.hideElement.substring(1));\n        }.bind(this));\n      }\n    }\n  }, {\n    key: \"prepareCheckboxes\",\n    value: function prepareCheckboxes() {\n      this.filterElement.querySelectorAll(this.identifier.filterOptionContainer).forEach(function (filterOptionContainer) {\n        var filterStatus = this.isFilterSet(filterOptionContainer);\n        if (filterStatus) {\n          if (this.filter.indexOf(filterOptionContainer.closest('[data-filtergroup]').getAttribute('data-filtergroup')) === -1) {\n            this.filter.push(filterOptionContainer.closest('[data-filtergroup]').getAttribute('data-filtergroup'));\n          }\n          var showAllCheckbox = filterOptionContainer.querySelector(this.identifier.filterShowAllCheckbox);\n          showAllCheckbox.checked = false;\n          showAllCheckbox.disabled = false;\n        } else {\n          var index = this.filter.indexOf(filterOptionContainer.closest('[data-filtergroup]').getAttribute('data-filtergroup'));\n          if (index !== -1) {\n            this.filter.splice(index, 1);\n          }\n        }\n      }.bind(this));\n    }\n  }, {\n    key: \"call\",\n    value: function call(paginationPage) {\n      var _this = this;\n      var pid = this.filterElement.querySelector('input[name=\"tx_in2studyfinder_pi1[pluginInformation][pid]\"]').value;\n      var language = this.filterElement.querySelector('input[name=\"tx_in2studyfinder_pi1[pluginInformation][languageUid]\"]').value;\n      var paginationArgument = '';\n      var instanceId = this.studyfinderElement.getAttribute('data-in2studyfinder-instance-id');\n      if (typeof paginationPage === 'undefined') {\n        paginationPage = 1;\n      }\n      if (typeof paginationPage !== 'undefined') {\n        paginationArgument = '&tx_in2studyfinder_pi1[studyCoursesForPage][currentPage]=' + paginationPage;\n      }\n      _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__[\"LoaderUtility\"].enableLoader();\n      fetch('/index.php?id=' + pid + '&L=' + language + '&type=1308171055' + paginationArgument, {\n        method: 'POST',\n        headers: {\n          'Content-Type': 'application/x-www-form-urlencoded'\n        },\n        body: _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__[\"UrlUtility\"].serialize(this.filterElement)\n      }).then(function (response) {\n        return response.text();\n      }).then(function (html) {\n        _this.setSelectedFilterToUrl(paginationPage);\n        var tempElement = document.createElement('div');\n        tempElement.innerHTML = html;\n        _this.studyfinderElement.innerHTML = tempElement.querySelector(_this.identifier.container).innerHTML;\n        _utility_loaderUtility__WEBPACK_IMPORTED_MODULE_1__[\"LoaderUtility\"].disableLoader();\n        window.in2studyfinder.getInstance(instanceId).update(_this.studyfinderElement);\n      });\n    }\n  }, {\n    key: \"setSelectedFilterToUrl\",\n    value: function setSelectedFilterToUrl(paginationPage) {\n      var selectionString = '';\n      var filterFieldSets = this.filterElement.querySelectorAll(this.identifier.filterSection);\n      filterFieldSets.forEach(function (filterFieldSet) {\n        var selectedOptions = filterFieldSet.querySelectorAll(this.identifier.filterCheckbox + ':checked, ' + this.identifier.filterRadio + ':checked');\n        if (selectedOptions.length > 0) {\n          selectionString += filterFieldSet.getAttribute('data-filtergroup') + '=';\n          for (var j = 0; j < selectedOptions.length; j++) {\n            selectionString += selectedOptions[j].value + '+';\n          }\n          if (selectedOptions.length >= 1) {\n            selectionString = selectionString.substring(0, selectionString.length - 1);\n          }\n          selectionString += '&';\n        }\n      }.bind(this));\n      selectionString = selectionString.slice(0, -1);\n      if (paginationPage && parseInt(paginationPage) > 1) {\n        selectionString += 'page=' + paginationPage;\n      }\n      if (selectionString !== '') {\n        selectionString = '#' + selectionString;\n      }\n      window.location = location.protocol + '//' + location.host + location.pathname + (location.search ? location.search : '') + selectionString;\n    }\n  }, {\n    key: \"updateFilterByHashArguments\",\n    value: function updateFilterByHashArguments(hashArguments) {\n      var page = 1;\n      hashArguments.forEach(function (hashArgument) {\n        // if argument page is set\n        if (hashArgument.name === 'page') {\n          page = hashArgument.values[0];\n        } else {\n          if (this.filterElement.querySelector('[data-filtergroup=\"' + hashArgument.name + '\"]') !== null) {\n            // set the selected filters\n            var filterFieldset = this.filterElement.querySelector('[data-filtergroup=\"' + hashArgument.name + '\"]');\n            var checkboxes = filterFieldset.querySelectorAll('input[type=checkbox],input[type=radio]');\n            var status = false;\n            for (var j = 0; j < checkboxes.length; j++) {\n              if (_utility_arrayUtility__WEBPACK_IMPORTED_MODULE_2__[\"ArrayUtility\"].isInArray(checkboxes[j].value, hashArgument.values)) {\n                checkboxes[j].checked = true;\n                status = true;\n              }\n            }\n            if (status) {\n              filterFieldset.querySelector(this.identifier.filterShowAllCheckbox).checked = false;\n            }\n          }\n        }\n      }.bind(this));\n      this.call(page);\n    }\n  }, {\n    key: \"setFilterCheckboxEventListener\",\n    value: function setFilterCheckboxEventListener() {\n      this.filterElement.querySelector(this.identifier.filterSectionContainer).addEventListener('click', function (evt) {\n        var target = evt.target;\n        if (target.tagName === 'INPUT') {\n          // if a show all checkbox is clicked\n          if (target.classList.contains(this.identifier.filterShowAllCheckbox.substring(1))) {\n            var filterContainer = target.closest(this.identifier.filterOptionContainer);\n            this.resetFilter(filterContainer);\n          }\n\n          // if a specific filter checkbox is clicked\n          if (target.classList.contains(this.identifier.filterCheckbox.substring(1)) || target.classList.contains(this.identifier.filterRadio.substring(1))) {\n            var showAllCheckbox = target.closest(this.identifier.filterOptionContainer).querySelector(this.identifier.filterShowAllCheckbox);\n            showAllCheckbox.checked = false;\n            showAllCheckbox.disabled = false;\n          }\n          this.call();\n        }\n      }.bind(this));\n    }\n  }, {\n    key: \"toggleFilterVisibility\",\n    value: function toggleFilterVisibility() {\n      // toggle fieldset Visibility\n      var filterFieldSets = this.filterElement.querySelectorAll(this.identifier.filterSection);\n      for (var i = 0; i < filterFieldSets.length; i++) {\n        filterFieldSets[i].classList.toggle(this.identifier.hideElement.substring(1));\n      }\n\n      // toggle button Visibility\n      this.filterElement.querySelector(this.identifier.showFilterButton).classList.toggle(this.identifier.hideElement.substring(1));\n      this.filterElement.querySelector(this.identifier.hideFilterButton).classList.toggle(this.identifier.hideElement.substring(1));\n    }\n  }, {\n    key: \"resetAllFilter\",\n    value: function resetAllFilter() {\n      var filterSection = this.filterElement.querySelectorAll(this.identifier.filterSection);\n      for (var i = 0; i < filterSection.length; i++) {\n        this.resetFilter(filterSection[i]);\n      }\n    }\n  }, {\n    key: \"resetFilter\",\n    value: function resetFilter(filterSection) {\n      var showAllCheckbox = filterSection.querySelector(this.identifier.filterShowAllCheckbox);\n      var checkboxes = filterSection.querySelectorAll(this.identifier.filterCheckbox);\n      showAllCheckbox.checked = true;\n      showAllCheckbox.disabled = true;\n      for (var i = 0; i < checkboxes.length; i++) {\n        checkboxes[i].checked = false;\n      }\n      var index = this.filter.indexOf(filterSection.getAttribute('data-filtergroup'));\n      if (index !== -1) {\n        this.filter.splice(index, 1);\n      }\n    }\n\n    /**\n     * checks if a given filter element is set\n     *\n     * @param filterOptionContainer\n     * @returns {boolean}\n     */\n  }, {\n    key: \"isFilterSet\",\n    value: function isFilterSet(filterOptionContainer) {\n      var status = false;\n      var filterCheckboxes = filterOptionContainer.querySelectorAll(this.identifier.filterCheckbox + ', ' + this.identifier.filterRadio);\n      for (var i = 0; i < filterCheckboxes.length; i++) {\n        if (filterCheckboxes[i].checked) {\n          status = true;\n        }\n      }\n      return status;\n    }\n  }]);\n  return Filter;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/filter.js?")},"./JavaScript/Frontend/components/instance.js":
/*!****************************************************!*\
  !*** ./JavaScript/Frontend/components/instance.js ***!
  \****************************************************/
/*! exports provided: Instance */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Instance", function() { return Instance; });\n/* harmony import */ var _pagination__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./pagination */ "./JavaScript/Frontend/components/pagination.js");\n/* harmony import */ var _filter__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./filter */ "./JavaScript/Frontend/components/filter.js");\n/* harmony import */ var _quickselect__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./quickselect */ "./JavaScript/Frontend/components/quickselect.js");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\n\n\n\nvar Instance = /*#__PURE__*/function () {\n  function Instance(element) {\n    _classCallCheck(this, Instance);\n    this.identifier = {\n      paginationContainer: \'.js-in2studyfinder-pagebrowser\',\n      filterContainer: \'.js-in2studyfinder-filter\',\n      quickSelectContainer: \'.js-in2studyfinder-select\'\n    };\n    this.hasPagination = false;\n    this.pagination = null;\n    this.hasFilter = false;\n    this.filter = null;\n    this.hasQuickselect = false;\n    this.quickselect = null;\n    this.element = element;\n  }\n  _createClass(Instance, [{\n    key: "init",\n    value: function init() {\n      if (this.element.querySelector(this.identifier.paginationContainer) !== null) {\n        this.hasPagination = true;\n        this.pagination = new _pagination__WEBPACK_IMPORTED_MODULE_0__["Pagination"](this.element);\n        this.pagination.init();\n      }\n      if (this.element.querySelector(this.identifier.filterContainer) !== null) {\n        this.hasFilter = true;\n        this.filter = new _filter__WEBPACK_IMPORTED_MODULE_1__["Filter"](this.element);\n        this.filter.init();\n      }\n      if (this.element.querySelector(this.identifier.quickSelectContainer) !== null) {\n        this.hasQuickselect = true;\n        this.quickselect = new _quickselect__WEBPACK_IMPORTED_MODULE_2__["Quickselect"](this.element);\n        this.quickselect.init();\n      }\n    }\n  }, {\n    key: "update",\n    value: function update(studyfinderElement) {\n      this.element = studyfinderElement;\n      if (this.element.querySelector(this.identifier.paginationContainer) !== null) {\n        this.pagination.update(studyfinderElement);\n      }\n      if (this.element.querySelector(this.identifier.filterContainer) !== null) {\n        this.filter.update(studyfinderElement);\n      }\n      if (this.element.querySelector(this.identifier.quickSelectContainer) !== null) {\n        this.quickselect.update(studyfinderElement);\n      }\n    }\n  }]);\n  return Instance;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/instance.js?')},"./JavaScript/Frontend/components/pagination.js":
/*!******************************************************!*\
  !*** ./JavaScript/Frontend/components/pagination.js ***!
  \******************************************************/
/*! exports provided: Pagination */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "Pagination", function() { return Pagination; });\n/* harmony import */ var _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../utility/urlUtility */ "./JavaScript/Frontend/utility/urlUtility.js");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\n\nvar Pagination = /*#__PURE__*/function () {\n  function Pagination(studyfinderElement) {\n    _classCallCheck(this, Pagination);\n    this.identifier = {\n      container: \'.js-in2studyfinder-pagebrowser\',\n      paginationLink: \'.js-in2studyfinder-pagination-link\'\n    };\n    this.studyfinderElement = studyfinderElement;\n    this.paginationElement = studyfinderElement.querySelector(this.identifier.container);\n  }\n  _createClass(Pagination, [{\n    key: "init",\n    value: function init() {\n      this.paginationElement.querySelectorAll(this.identifier.paginationLink).forEach(function (item) {\n        item.addEventListener(\'click\', function (event) {\n          this.call(event);\n        }.bind(this));\n      }.bind(this));\n    }\n  }, {\n    key: "update",\n    value: function update(studyfinderElement) {\n      this.studyfinderElement = studyfinderElement;\n      this.paginationElement = studyfinderElement.querySelector(this.identifier.container);\n      this.paginationElement.querySelectorAll(this.identifier.paginationLink).forEach(function (item) {\n        item.addEventListener(\'click\', function (event) {\n          this.call(event);\n        }.bind(this));\n      }.bind(this));\n      this.onUpdate();\n    }\n  }, {\n    key: "call",\n    value: function call(event) {\n      var _this = this;\n      event.preventDefault();\n      this.afterClick(event);\n      var targetPage = 1;\n      var url = event.target.href;\n      var instanceId = this.studyfinderElement.getAttribute(\'data-in2studyfinder-instance-id\');\n      if (_utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__["UrlUtility"].getParameterFromUrl(url, \'tx_in2studyfinder_pi1[studyCoursesForPage][currentPage]\') !== \'\') {\n        targetPage = _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__["UrlUtility"].getParameterFromUrl(url, \'tx_in2studyfinder_pi1[studyCoursesForPage][currentPage]\');\n      }\n      _utility_urlUtility__WEBPACK_IMPORTED_MODULE_0__["UrlUtility"].addOrUpdateHash(\'page\', [targetPage]);\n      var ajaxCall = new Promise(function (resolve) {\n        window.in2studyfinder.getInstance(instanceId).filter.call(targetPage);\n        resolve(\'done\');\n      });\n      ajaxCall.then(function (message) {\n        _this.afterLoad(event);\n      });\n    }\n  }, {\n    key: "onUpdate",\n    value: function onUpdate() {}\n  }, {\n    key: "afterClick",\n    value: function afterClick() {}\n  }, {\n    key: "afterLoad",\n    value: function afterLoad() {}\n  }]);\n  return Pagination;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/pagination.js?')},"./JavaScript/Frontend/components/quickselect.js":
/*!*******************************************************!*\
  !*** ./JavaScript/Frontend/components/quickselect.js ***!
  \*******************************************************/
/*! exports provided: Quickselect */function(module,__webpack_exports__,__webpack_require__){"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"Quickselect\", function() { return Quickselect; });\n/* harmony import */ var tom_select__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! tom-select */ \"./node_modules/tom-select/dist/js/tom-select.complete.js\");\n/* harmony import */ var tom_select__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(tom_select__WEBPACK_IMPORTED_MODULE_0__);\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar Quickselect = /*#__PURE__*/function () {\n  function Quickselect(studyfinderContainer) {\n    _classCallCheck(this, Quickselect);\n    this.identifier = {\n      quicksearchContainer: '.js-in2studyfinder-quick-search',\n      select: '.js-in2studyfinder-select'\n    };\n    this.settings = {\n      maxOptions: null,\n      searchField: ['text', 'keywords'],\n      onDropdownOpen: function onDropdownOpen() {\n        this.clear(); // prevents the \"preselect\" bug of firefox 106\n      },\n\n      onItemAdd: function onItemAdd(value, item) {\n        var url = item.getAttribute('data-url');\n        if (url.length) {\n          window.location.href = url;\n        }\n      },\n      render: {\n        item: function item(data, escape) {\n          return '<div title=\"' + escape(data.text) + '\" data-url=\"' + data.url + '\">' + escape(data.text) + '</div>';\n        },\n        no_results: function no_results(data, escape) {\n          var lang = document.querySelector('html').getAttribute('lang');\n          var message = 'No results found';\n          if (lang === 'de' || 'de-DE') {\n            message = 'Keine Ergebnisse gefunden';\n          }\n          return '<div class=\"no-results\">' + message + '</div>';\n        }\n      }\n    };\n    this.tomSelect = null;\n    this.in2studyfinderContainer = studyfinderContainer;\n  }\n  _createClass(Quickselect, [{\n    key: \"init\",\n    value: function init() {\n      this.tomSelect = new tom_select__WEBPACK_IMPORTED_MODULE_0___default.a(this.in2studyfinderContainer.querySelector(this.identifier.select), this.settings);\n    }\n  }, {\n    key: \"update\",\n    value: function update(studyfinderContainer) {\n      this.in2studyfinderContainer = studyfinderContainer;\n      if (this.tomSelect !== null) {\n        this.tomSelect.destroy();\n      }\n      this.init();\n    }\n  }]);\n  return Quickselect;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/components/quickselect.js?")},"./JavaScript/Frontend/in2studyfinder/in2studyfinder.js":
/*!**************************************************************!*\
  !*** ./JavaScript/Frontend/in2studyfinder/in2studyfinder.js ***!
  \**************************************************************/
/*! exports provided: In2studyfinder */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "In2studyfinder", function() { return In2studyfinder; });\n/* harmony import */ var _components_instance__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../components/instance */ "./JavaScript/Frontend/components/instance.js");\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\n\nvar In2studyfinder = /*#__PURE__*/function () {\n  function In2studyfinder() {\n    _classCallCheck(this, In2studyfinder);\n    this.identifier = {\n      container: \'.in2studyfinder\'\n    };\n    this.instances = [];\n  }\n  _createClass(In2studyfinder, [{\n    key: "init",\n    value: function init() {\n      document.querySelectorAll(this.identifier.container).forEach(function (item, index) {\n        item.classList.replace(\'no-js\', \'js\');\n        item.setAttribute(\'data-in2studyfinder-instance-id\', index);\n        this.instances[index] = new _components_instance__WEBPACK_IMPORTED_MODULE_0__["Instance"](item);\n        this.instances[index].init();\n      }.bind(this));\n    }\n  }, {\n    key: "getInstance",\n    value: function getInstance(instanceId) {\n      if (this.instances[instanceId] !== undefined) {\n        return this.instances[instanceId];\n      }\n      return null;\n    }\n  }]);\n  return In2studyfinder;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/in2studyfinder/in2studyfinder.js?')},"./JavaScript/Frontend/main.js":
/*!*************************************!*\
  !*** ./JavaScript/Frontend/main.js ***!
  \*************************************/
/*! no exports provided */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _in2studyfinder_in2studyfinder__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./in2studyfinder/in2studyfinder */ "./JavaScript/Frontend/in2studyfinder/in2studyfinder.js");\n\nif (document.querySelector(\'.in2studyfinder\') !== null) {\n  var in2studyfinder = new _in2studyfinder_in2studyfinder__WEBPACK_IMPORTED_MODULE_0__["In2studyfinder"]();\n  in2studyfinder.init();\n  window.in2studyfinder = in2studyfinder;\n}\n\n//# sourceURL=webpack:///./JavaScript/Frontend/main.js?')},"./JavaScript/Frontend/utility/arrayUtility.js":
/*!*****************************************************!*\
  !*** ./JavaScript/Frontend/utility/arrayUtility.js ***!
  \*****************************************************/
/*! exports provided: ArrayUtility */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "ArrayUtility", function() { return ArrayUtility; });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\nvar ArrayUtility = /*#__PURE__*/function () {\n  function ArrayUtility() {\n    _classCallCheck(this, ArrayUtility);\n  }\n  _createClass(ArrayUtility, null, [{\n    key: "isInArray",\n    value:\n    /**\n     *\n     * @param value\n     * @param array\n     * @returns {boolean}\n     */\n    function isInArray(value, array) {\n      return array.indexOf(value) > -1;\n    }\n  }, {\n    key: "containsObjectWithKey",\n    value:\n    /**\n     *\n     * @param array\n     * @param key\n     * @param value\n     * @returns {int} the array key of the object. -1 if no match is found\n     */\n    function containsObjectWithKey(array, key, value) {\n      if (Array.isArray(array)) {\n        for (var i = 0; i <= array.length - 1; i++) {\n          if (array[i] instanceof Object) {\n            if (array[i].hasOwnProperty(key) && array[i][key] === value) {\n              return i;\n            }\n          }\n        }\n      }\n      return -1;\n    }\n  }]);\n  return ArrayUtility;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/utility/arrayUtility.js?')},"./JavaScript/Frontend/utility/loaderUtility.js":
/*!******************************************************!*\
  !*** ./JavaScript/Frontend/utility/loaderUtility.js ***!
  \******************************************************/
/*! exports provided: LoaderUtility */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "LoaderUtility", function() { return LoaderUtility; });\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, "prototype", { writable: false }); return Constructor; }\nvar LoaderUtility = /*#__PURE__*/function () {\n  function LoaderUtility() {\n    _classCallCheck(this, LoaderUtility);\n  }\n  _createClass(LoaderUtility, null, [{\n    key: "enableLoader",\n    value: function enableLoader() {\n      document.querySelector(this.identifier.loader).classList.add(this.identifier.loaderActive.substring(1));\n    }\n  }, {\n    key: "disableLoader",\n    value: function disableLoader() {\n      if (document.querySelector(this.identifier.loaderActive) !== null) {\n        document.querySelector(this.identifier.loaderActive).classList.remove(this.identifier.loaderActive.substring(1));\n      }\n    }\n  }]);\n  return LoaderUtility;\n}();\nLoaderUtility.identifier = {\n  loader: \'.in2studyfinder-loader\',\n  loaderActive: \'.in2studyfinder-loader--active\'\n};\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/utility/loaderUtility.js?')},"./JavaScript/Frontend/utility/urlUtility.js":
/*!***************************************************!*\
  !*** ./JavaScript/Frontend/utility/urlUtility.js ***!
  \***************************************************/
/*! exports provided: UrlUtility */function(module,__webpack_exports__,__webpack_require__){"use strict";eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"UrlUtility\", function() { return UrlUtility; });\n/* harmony import */ var _arrayUtility__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./arrayUtility */ \"./JavaScript/Frontend/utility/arrayUtility.js\");\nfunction _typeof(obj) { \"@babel/helpers - typeof\"; return _typeof = \"function\" == typeof Symbol && \"symbol\" == typeof Symbol.iterator ? function (obj) { return typeof obj; } : function (obj) { return obj && \"function\" == typeof Symbol && obj.constructor === Symbol && obj !== Symbol.prototype ? \"symbol\" : typeof obj; }, _typeof(obj); }\nfunction _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError(\"Cannot call a class as a function\"); } }\nfunction _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if (\"value\" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }\nfunction _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); Object.defineProperty(Constructor, \"prototype\", { writable: false }); return Constructor; }\n\nvar UrlUtility = /*#__PURE__*/function () {\n  function UrlUtility() {\n    _classCallCheck(this, UrlUtility);\n  }\n  _createClass(UrlUtility, null, [{\n    key: \"removeParameterFromUrl\",\n    value:\n    /**\n     * initialized all functions\n     *\n     * @return {void}\n     */\n    function removeParameterFromUrl(url, parameter) {\n      var urlParts = url.split('?');\n      if (urlParts.length >= 2) {\n        var prefix = encodeURIComponent(parameter) + '=';\n        var pars = urlParts[1].split(/[&;]/g);\n\n        //reverse iteration as may be destructive\n        for (var i = pars.length; i-- > 0;) {\n          //idiom for string.startsWith\n          if (pars[i].lastIndexOf(prefix, 0) !== -1) {\n            pars.splice(i, 1);\n          }\n        }\n        url = urlParts[0] + (pars.length > 0 ? '?' + pars.join('&') : \"\");\n        return url;\n      } else {\n        return url;\n      }\n    }\n  }, {\n    key: \"getParameterFromUrl\",\n    value: function getParameterFromUrl(url, parameter) {\n      var parts = url.split('?'),\n        value = '';\n      if (parts.length >= 2) {\n        var queryString = parts[1];\n        queryString = '&' + queryString;\n        var prefix = encodeURIComponent(parameter) + '=';\n        var parameters = queryString.split(/[&;]/g);\n        for (var i = parameters.length; i-- > 0;) {\n          if (parameters[i].lastIndexOf(prefix, 0) !== -1) {\n            value = parameters[i].split('=')[1];\n            break;\n          }\n        }\n      }\n      return value;\n    }\n  }, {\n    key: \"addOrUpdateHash\",\n    value:\n    /**\n     *\n     * @param {string} attribute\n     * @param {array} values\n     */\n    function addOrUpdateHash(attribute, values) {\n      var hashArguments = this.getHashArgumentsFromUrl();\n      if (hashArguments.length > 0) {\n        var key = _arrayUtility__WEBPACK_IMPORTED_MODULE_0__[\"ArrayUtility\"].containsObjectWithKey(hashArguments, 'name', attribute);\n        if (key >= 0) {\n          hashArguments[key]['values'] = values;\n        }\n      } else {\n        hashArguments[0] = {\n          name: attribute,\n          values: values\n        };\n      }\n      var hash = '#';\n      // write hash\n      for (var i = 0; i <= hashArguments.length - 1; i++) {\n        if (i === hashArguments.length - 1) {\n          hash += hashArguments[i].name + '=' + hashArguments[i].values.join();\n        } else {\n          hash += hashArguments[i].name + '=' + hashArguments[i].values.join() + '&';\n        }\n      }\n      window.location.hash = hash;\n    }\n  }, {\n    key: \"addAttributeToUrl\",\n    value:\n    /**\n     *\n     * @param url\n     * @param attribute\n     * @param value\n     * @returns {string|*}\n     */\n    function addAttributeToUrl(url, attribute, value) {\n      var divider = '?';\n      if (url.indexOf('?') !== -1) {\n        divider = '&';\n      }\n      url += divider + attribute + '=' + value;\n      return url;\n    }\n  }, {\n    key: \"serialize\",\n    value:\n    /**\n     * Serialize a given Form\n     *\n     * @param form\n     * @returns {string}\n     */\n    function serialize(form) {\n      var field,\n        s = [];\n      if (_typeof(form) === 'object' && form.nodeName === 'FORM') {\n        var len = form.elements.length;\n        for (var i = 0; i < len; i++) {\n          field = form.elements[i];\n          if (field.name && !field.disabled && field.type !== 'file' && field.type !== 'reset' && field.type !== 'submit' && field.type !== 'button') {\n            if (field.type === 'select-multiple') {\n              for (var j = form.elements[i].options.length - 1; j >= 0; j--) {\n                if (field.options[j].selected) {\n                  s[s.length] = encodeURIComponent(field.name) + '=' + encodeURIComponent(field.options[j].value);\n                }\n              }\n            } else if (field.type !== 'checkbox' && field.type !== 'radio' || field.checked) {\n              s[s.length] = encodeURIComponent(field.name) + '=' + encodeURIComponent(field.value);\n            }\n          }\n        }\n      }\n      return s.join('&').replace(/%20/g, '+');\n    }\n  }, {\n    key: \"getHashArgumentsFromUrl\",\n    value:\n    /**\n     * @return array\n     */\n    function getHashArgumentsFromUrl() {\n      if (window.location.hash) {\n        var hash = window.location.hash.split('#')[1];\n        var argumentArray = hash.split(/[&;]/g);\n        var hashArguments = [];\n        for (var i = 0; i < argumentArray.length; i++) {\n          var singleArgument = argumentArray[i].split(/[=;]/g);\n          if (singleArgument.length === 2) {\n            var values = singleArgument[1].split(/[+;]/g);\n            hashArguments[i] = {\n              name: singleArgument[0],\n              values: values\n            };\n          }\n        }\n        return hashArguments;\n      }\n      return [];\n    }\n  }]);\n  return UrlUtility;\n}();\n\n\n//# sourceURL=webpack:///./JavaScript/Frontend/utility/urlUtility.js?")},"./Sass/backend.scss":
/*!***************************!*\
  !*** ./Sass/backend.scss ***!
  \***************************/
/*! exports provided: default */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (__webpack_require__.p + "../Public/Css/backend.css");\n\n//# sourceURL=webpack:///./Sass/backend.scss?')},"./Sass/demo.scss":
/*!************************!*\
  !*** ./Sass/demo.scss ***!
  \************************/
/*! exports provided: default */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (__webpack_require__.p + "../Public/Css/demo.css");\n\n//# sourceURL=webpack:///./Sass/demo.scss?')},"./Sass/style.scss":
/*!*************************!*\
  !*** ./Sass/style.scss ***!
  \*************************/
/*! exports provided: default */function(module,__webpack_exports__,__webpack_require__){"use strict";eval('__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__["default"] = (__webpack_require__.p + "../Public/Css/style.css");\n\n//# sourceURL=webpack:///./Sass/style.scss?')},"./node_modules/tom-select/dist/js/tom-select.complete.js":
/*!****************************************************************!*\
  !*** ./node_modules/tom-select/dist/js/tom-select.complete.js ***!
  \****************************************************************/
/*! no static exports found */function(module,exports,__webpack_require__){eval("/**\n* Tom Select v2.2.2\n* Licensed under the Apache License, Version 2.0 (the \"License\");\n*/\n\n(function (global, factory) {\n\t true ? module.exports = factory() :\n\tundefined;\n})(this, (function () { 'use strict';\n\n\t/**\n\t * MicroEvent - to make any js object an event emitter\n\t *\n\t * - pure javascript - server compatible, browser compatible\n\t * - dont rely on the browser doms\n\t * - super simple - you get it immediatly, no mistery, no magic involved\n\t *\n\t * @author Jerome Etienne (https://github.com/jeromeetienne)\n\t */\n\n\t/**\n\t * Execute callback for each event in space separated list of event names\n\t *\n\t */\n\tfunction forEvents(events, callback) {\n\t  events.split(/\\s+/).forEach(event => {\n\t    callback(event);\n\t  });\n\t}\n\n\tclass MicroEvent {\n\t  constructor() {\n\t    this._events = void 0;\n\t    this._events = {};\n\t  }\n\n\t  on(events, fct) {\n\t    forEvents(events, event => {\n\t      const event_array = this._events[event] || [];\n\t      event_array.push(fct);\n\t      this._events[event] = event_array;\n\t    });\n\t  }\n\n\t  off(events, fct) {\n\t    var n = arguments.length;\n\n\t    if (n === 0) {\n\t      this._events = {};\n\t      return;\n\t    }\n\n\t    forEvents(events, event => {\n\t      if (n === 1) {\n\t        delete this._events[event];\n\t        return;\n\t      }\n\n\t      const event_array = this._events[event];\n\t      if (event_array === undefined) return;\n\t      event_array.splice(event_array.indexOf(fct), 1);\n\t      this._events[event] = event_array;\n\t    });\n\t  }\n\n\t  trigger(events, ...args) {\n\t    var self = this;\n\t    forEvents(events, event => {\n\t      const event_array = self._events[event];\n\t      if (event_array === undefined) return;\n\t      event_array.forEach(fct => {\n\t        fct.apply(self, args);\n\t      });\n\t    });\n\t  }\n\n\t}\n\n\t/**\n\t * microplugin.js\n\t * Copyright (c) 2013 Brian Reavis & contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t * @author Brian Reavis <brian@thirdroute.com>\n\t */\n\tfunction MicroPlugin(Interface) {\n\t  Interface.plugins = {};\n\t  return class extends Interface {\n\t    constructor(...args) {\n\t      super(...args);\n\t      this.plugins = {\n\t        names: [],\n\t        settings: {},\n\t        requested: {},\n\t        loaded: {}\n\t      };\n\t    }\n\n\t    /**\n\t     * Registers a plugin.\n\t     *\n\t     * @param {function} fn\n\t     */\n\t    static define(name, fn) {\n\t      Interface.plugins[name] = {\n\t        'name': name,\n\t        'fn': fn\n\t      };\n\t    }\n\t    /**\n\t     * Initializes the listed plugins (with options).\n\t     * Acceptable formats:\n\t     *\n\t     * List (without options):\n\t     *   ['a', 'b', 'c']\n\t     *\n\t     * List (with options):\n\t     *   [{'name': 'a', options: {}}, {'name': 'b', options: {}}]\n\t     *\n\t     * Hash (with options):\n\t     *   {'a': { ... }, 'b': { ... }, 'c': { ... }}\n\t     *\n\t     * @param {array|object} plugins\n\t     */\n\n\n\t    initializePlugins(plugins) {\n\t      var key, name;\n\t      const self = this;\n\t      const queue = [];\n\n\t      if (Array.isArray(plugins)) {\n\t        plugins.forEach(plugin => {\n\t          if (typeof plugin === 'string') {\n\t            queue.push(plugin);\n\t          } else {\n\t            self.plugins.settings[plugin.name] = plugin.options;\n\t            queue.push(plugin.name);\n\t          }\n\t        });\n\t      } else if (plugins) {\n\t        for (key in plugins) {\n\t          if (plugins.hasOwnProperty(key)) {\n\t            self.plugins.settings[key] = plugins[key];\n\t            queue.push(key);\n\t          }\n\t        }\n\t      }\n\n\t      while (name = queue.shift()) {\n\t        self.require(name);\n\t      }\n\t    }\n\n\t    loadPlugin(name) {\n\t      var self = this;\n\t      var plugins = self.plugins;\n\t      var plugin = Interface.plugins[name];\n\n\t      if (!Interface.plugins.hasOwnProperty(name)) {\n\t        throw new Error('Unable to find \"' + name + '\" plugin');\n\t      }\n\n\t      plugins.requested[name] = true;\n\t      plugins.loaded[name] = plugin.fn.apply(self, [self.plugins.settings[name] || {}]);\n\t      plugins.names.push(name);\n\t    }\n\t    /**\n\t     * Initializes a plugin.\n\t     *\n\t     */\n\n\n\t    require(name) {\n\t      var self = this;\n\t      var plugins = self.plugins;\n\n\t      if (!self.plugins.loaded.hasOwnProperty(name)) {\n\t        if (plugins.requested[name]) {\n\t          throw new Error('Plugin has circular dependency (\"' + name + '\")');\n\t        }\n\n\t        self.loadPlugin(name);\n\t      }\n\n\t      return plugins.loaded[name];\n\t    }\n\n\t  };\n\t}\n\n\t/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */\n\t/**\n\t * Convert array of strings to a regular expression\n\t *\tex ['ab','a'] => (?:ab|a)\n\t * \tex ['a','b'] => [ab]\n\t * @param {string[]} chars\n\t * @return {string}\n\t */\n\tconst arrayToPattern = chars => {\n\t  chars = chars.filter(Boolean);\n\n\t  if (chars.length < 2) {\n\t    return chars[0] || '';\n\t  }\n\n\t  return maxValueLength(chars) == 1 ? '[' + chars.join('') + ']' : '(?:' + chars.join('|') + ')';\n\t};\n\t/**\n\t * @param {string[]} array\n\t * @return {string}\n\t */\n\n\tconst sequencePattern = array => {\n\t  if (!hasDuplicates(array)) {\n\t    return array.join('');\n\t  }\n\n\t  let pattern = '';\n\t  let prev_char_count = 0;\n\n\t  const prev_pattern = () => {\n\t    if (prev_char_count > 1) {\n\t      pattern += '{' + prev_char_count + '}';\n\t    }\n\t  };\n\n\t  array.forEach((char, i) => {\n\t    if (char === array[i - 1]) {\n\t      prev_char_count++;\n\t      return;\n\t    }\n\n\t    prev_pattern();\n\t    pattern += char;\n\t    prev_char_count = 1;\n\t  });\n\t  prev_pattern();\n\t  return pattern;\n\t};\n\t/**\n\t * Convert array of strings to a regular expression\n\t *\tex ['ab','a'] => (?:ab|a)\n\t * \tex ['a','b'] => [ab]\n\t * @param {Set<string>} chars\n\t * @return {string}\n\t */\n\n\tconst setToPattern = chars => {\n\t  let array = toArray(chars);\n\t  return arrayToPattern(array);\n\t};\n\t/**\n\t *\n\t * https://stackoverflow.com/questions/7376598/in-javascript-how-do-i-check-if-an-array-has-duplicate-values\n\t * @param {any[]} array\n\t */\n\n\tconst hasDuplicates = array => {\n\t  return new Set(array).size !== array.length;\n\t};\n\t/**\n\t * https://stackoverflow.com/questions/63006601/why-does-u-throw-an-invalid-escape-error\n\t * @param {string} str\n\t * @return {string}\n\t */\n\n\tconst escape_regex = str => {\n\t  return (str + '').replace(/([\\$\\(\\)\\*\\+\\.\\?\\[\\]\\^\\{\\|\\}\\\\])/gu, '\\\\$1');\n\t};\n\t/**\n\t * Return the max length of array values\n\t * @param {string[]} array\n\t *\n\t */\n\n\tconst maxValueLength = array => {\n\t  return array.reduce((longest, value) => Math.max(longest, unicodeLength(value)), 0);\n\t};\n\t/**\n\t * @param {string} str\n\t */\n\n\tconst unicodeLength = str => {\n\t  return toArray(str).length;\n\t};\n\t/**\n\t * @param {any} p\n\t * @return {any[]}\n\t */\n\n\tconst toArray = p => Array.from(p);\n\n\t/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */\n\t/**\n\t * Get all possible combinations of substrings that add up to the given string\n\t * https://stackoverflow.com/questions/30169587/find-all-the-combination-of-substrings-that-add-up-to-the-given-string\n\t * @param {string} input\n\t * @return {string[][]}\n\t */\n\tconst allSubstrings = input => {\n\t  if (input.length === 1) return [[input]];\n\t  /** @type {string[][]} */\n\n\t  let result = [];\n\t  const start = input.substring(1);\n\t  const suba = allSubstrings(start);\n\t  suba.forEach(function (subresult) {\n\t    let tmp = subresult.slice(0);\n\t    tmp[0] = input.charAt(0) + tmp[0];\n\t    result.push(tmp);\n\t    tmp = subresult.slice(0);\n\t    tmp.unshift(input.charAt(0));\n\t    result.push(tmp);\n\t  });\n\t  return result;\n\t};\n\n\t/*! @orchidjs/unicode-variants | https://github.com/orchidjs/unicode-variants | Apache License (v2) */\n\n\t/**\n\t * @typedef {{[key:string]:string}} TUnicodeMap\n\t * @typedef {{[key:string]:Set<string>}} TUnicodeSets\n\t * @typedef {[[number,number]]} TCodePoints\n\t * @typedef {{folded:string,composed:string,code_point:number}} TCodePointObj\n\t * @typedef {{start:number,end:number,length:number,substr:string}} TSequencePart\n\t */\n\t/** @type {TCodePoints} */\n\n\tconst code_points = [[0, 65535]];\n\tconst accent_pat = '[\\u0300-\\u036F\\u{b7}\\u{2be}\\u{2bc}]';\n\t/** @type {TUnicodeMap} */\n\n\tlet unicode_map;\n\t/** @type {RegExp} */\n\n\tlet multi_char_reg;\n\tconst max_char_length = 3;\n\t/** @type {TUnicodeMap} */\n\n\tconst latin_convert = {};\n\t/** @type {TUnicodeMap} */\n\n\tconst latin_condensed = {\n\t  '/': '⁄∕',\n\t  '0': '߀',\n\t  \"a\": \"ⱥɐɑ\",\n\t  \"aa\": \"ꜳ\",\n\t  \"ae\": \"æǽǣ\",\n\t  \"ao\": \"ꜵ\",\n\t  \"au\": \"ꜷ\",\n\t  \"av\": \"ꜹꜻ\",\n\t  \"ay\": \"ꜽ\",\n\t  \"b\": \"ƀɓƃ\",\n\t  \"c\": \"ꜿƈȼↄ\",\n\t  \"d\": \"đɗɖᴅƌꮷԁɦ\",\n\t  \"e\": \"ɛǝᴇɇ\",\n\t  \"f\": \"ꝼƒ\",\n\t  \"g\": \"ǥɠꞡᵹꝿɢ\",\n\t  \"h\": \"ħⱨⱶɥ\",\n\t  \"i\": \"ɨı\",\n\t  \"j\": \"ɉȷ\",\n\t  \"k\": \"ƙⱪꝁꝃꝅꞣ\",\n\t  \"l\": \"łƚɫⱡꝉꝇꞁɭ\",\n\t  \"m\": \"ɱɯϻ\",\n\t  \"n\": \"ꞥƞɲꞑᴎлԉ\",\n\t  \"o\": \"øǿɔɵꝋꝍᴑ\",\n\t  \"oe\": \"œ\",\n\t  \"oi\": \"ƣ\",\n\t  \"oo\": \"ꝏ\",\n\t  \"ou\": \"ȣ\",\n\t  \"p\": \"ƥᵽꝑꝓꝕρ\",\n\t  \"q\": \"ꝗꝙɋ\",\n\t  \"r\": \"ɍɽꝛꞧꞃ\",\n\t  \"s\": \"ßȿꞩꞅʂ\",\n\t  \"t\": \"ŧƭʈⱦꞇ\",\n\t  \"th\": \"þ\",\n\t  \"tz\": \"ꜩ\",\n\t  \"u\": \"ʉ\",\n\t  \"v\": \"ʋꝟʌ\",\n\t  \"vy\": \"ꝡ\",\n\t  \"w\": \"ⱳ\",\n\t  \"y\": \"ƴɏỿ\",\n\t  \"z\": \"ƶȥɀⱬꝣ\",\n\t  \"hv\": \"ƕ\"\n\t};\n\n\tfor (let latin in latin_condensed) {\n\t  let unicode = latin_condensed[latin] || '';\n\n\t  for (let i = 0; i < unicode.length; i++) {\n\t    let char = unicode.substring(i, i + 1);\n\t    latin_convert[char] = latin;\n\t  }\n\t}\n\n\tconst convert_pat = new RegExp(Object.keys(latin_convert).join('|') + '|' + accent_pat, 'gu');\n\t/**\n\t * Initialize the unicode_map from the give code point ranges\n\t *\n\t * @param {TCodePoints=} _code_points\n\t */\n\n\tconst initialize = _code_points => {\n\t  if (unicode_map !== undefined) return;\n\t  unicode_map = generateMap(_code_points || code_points);\n\t};\n\t/**\n\t * Helper method for normalize a string\n\t * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/normalize\n\t * @param {string} str\n\t * @param {string} form\n\t */\n\n\tconst normalize = (str, form = 'NFKD') => str.normalize(form);\n\t/**\n\t * Remove accents without reordering string\n\t * calling str.normalize('NFKD') on \\u{594}\\u{595}\\u{596} becomes \\u{596}\\u{594}\\u{595}\n\t * via https://github.com/krisk/Fuse/issues/133#issuecomment-318692703\n\t * @param {string} str\n\t * @return {string}\n\t */\n\n\tconst asciifold = str => {\n\t  return toArray(str).reduce(\n\t  /**\n\t   * @param {string} result\n\t   * @param {string} char\n\t   */\n\t  (result, char) => {\n\t    return result + _asciifold(char);\n\t  }, '');\n\t};\n\t/**\n\t * @param {string} str\n\t * @return {string}\n\t */\n\n\tconst _asciifold = str => {\n\t  str = normalize(str).toLowerCase().replace(convert_pat, (\n\t  /** @type {string} */\n\t  char) => {\n\t    return latin_convert[char] || '';\n\t  }); //return str;\n\n\t  return normalize(str, 'NFC');\n\t};\n\t/**\n\t * Generate a list of unicode variants from the list of code points\n\t * @param {TCodePoints} code_points\n\t * @yield {TCodePointObj}\n\t */\n\n\tfunction* generator(code_points) {\n\t  for (const [code_point_min, code_point_max] of code_points) {\n\t    for (let i = code_point_min; i <= code_point_max; i++) {\n\t      let composed = String.fromCharCode(i);\n\t      let folded = asciifold(composed);\n\n\t      if (folded == composed.toLowerCase()) {\n\t        continue;\n\t      } // skip when folded is a string longer than 3 characters long\n\t      // bc the resulting regex patterns will be long\n\t      // eg:\n\t      // folded صلى الله عليه وسلم length 18 code point 65018\n\t      // folded جل جلاله length 8 code point 65019\n\n\n\t      if (folded.length > max_char_length) {\n\t        continue;\n\t      }\n\n\t      if (folded.length == 0) {\n\t        continue;\n\t      }\n\n\t      yield {\n\t        folded: folded,\n\t        composed: composed,\n\t        code_point: i\n\t      };\n\t    }\n\t  }\n\t}\n\t/**\n\t * Generate a unicode map from the list of code points\n\t * @param {TCodePoints} code_points\n\t * @return {TUnicodeSets}\n\t */\n\n\tconst generateSets = code_points => {\n\t  /** @type {{[key:string]:Set<string>}} */\n\t  const unicode_sets = {};\n\t  /**\n\t   * @param {string} folded\n\t   * @param {string} to_add\n\t   */\n\n\t  const addMatching = (folded, to_add) => {\n\t    /** @type {Set<string>} */\n\t    const folded_set = unicode_sets[folded] || new Set();\n\t    const patt = new RegExp('^' + setToPattern(folded_set) + '$', 'iu');\n\n\t    if (to_add.match(patt)) {\n\t      return;\n\t    }\n\n\t    folded_set.add(escape_regex(to_add));\n\t    unicode_sets[folded] = folded_set;\n\t  };\n\n\t  for (let value of generator(code_points)) {\n\t    addMatching(value.folded, value.folded);\n\t    addMatching(value.folded, value.composed);\n\t  }\n\n\t  return unicode_sets;\n\t};\n\t/**\n\t * Generate a unicode map from the list of code points\n\t * ae => (?:(?:ae|Æ|Ǽ|Ǣ)|(?:A|Ⓐ|Ａ...)(?:E|ɛ|Ⓔ...))\n\t *\n\t * @param {TCodePoints} code_points\n\t * @return {TUnicodeMap}\n\t */\n\n\tconst generateMap = code_points => {\n\t  /** @type {TUnicodeSets} */\n\t  const unicode_sets = generateSets(code_points);\n\t  /** @type {TUnicodeMap} */\n\n\t  const unicode_map = {};\n\t  /** @type {string[]} */\n\n\t  let multi_char = [];\n\n\t  for (let folded in unicode_sets) {\n\t    let set = unicode_sets[folded];\n\n\t    if (set) {\n\t      unicode_map[folded] = setToPattern(set);\n\t    }\n\n\t    if (folded.length > 1) {\n\t      multi_char.push(escape_regex(folded));\n\t    }\n\t  }\n\n\t  multi_char.sort((a, b) => b.length - a.length);\n\t  const multi_char_patt = arrayToPattern(multi_char);\n\t  multi_char_reg = new RegExp('^' + multi_char_patt, 'u');\n\t  return unicode_map;\n\t};\n\t/**\n\t * Map each element of an array from it's folded value to all possible unicode matches\n\t * @param {string[]} strings\n\t * @param {number} min_replacement\n\t * @return {string}\n\t */\n\n\tconst mapSequence = (strings, min_replacement = 1) => {\n\t  let chars_replaced = 0;\n\t  strings = strings.map(str => {\n\t    if (unicode_map[str]) {\n\t      chars_replaced += str.length;\n\t    }\n\n\t    return unicode_map[str] || str;\n\t  });\n\n\t  if (chars_replaced >= min_replacement) {\n\t    return sequencePattern(strings);\n\t  }\n\n\t  return '';\n\t};\n\t/**\n\t * Convert a short string and split it into all possible patterns\n\t * Keep a pattern only if min_replacement is met\n\t *\n\t * 'abc'\n\t * \t\t=> [['abc'],['ab','c'],['a','bc'],['a','b','c']]\n\t *\t\t=> ['abc-pattern','ab-c-pattern'...]\n\t *\n\t *\n\t * @param {string} str\n\t * @param {number} min_replacement\n\t * @return {string}\n\t */\n\n\tconst substringsToPattern = (str, min_replacement = 1) => {\n\t  min_replacement = Math.max(min_replacement, str.length - 1);\n\t  return arrayToPattern(allSubstrings(str).map(sub_pat => {\n\t    return mapSequence(sub_pat, min_replacement);\n\t  }));\n\t};\n\t/**\n\t * Convert an array of sequences into a pattern\n\t * [{start:0,end:3,length:3,substr:'iii'}...] => (?:iii...)\n\t *\n\t * @param {Sequence[]} sequences\n\t * @param {boolean} all\n\t */\n\n\tconst sequencesToPattern = (sequences, all = true) => {\n\t  let min_replacement = sequences.length > 1 ? 1 : 0;\n\t  return arrayToPattern(sequences.map(sequence => {\n\t    let seq = [];\n\t    const len = all ? sequence.length() : sequence.length() - 1;\n\n\t    for (let j = 0; j < len; j++) {\n\t      seq.push(substringsToPattern(sequence.substrs[j] || '', min_replacement));\n\t    }\n\n\t    return sequencePattern(seq);\n\t  }));\n\t};\n\t/**\n\t * Return true if the sequence is already in the sequences\n\t * @param {Sequence} needle_seq\n\t * @param {Sequence[]} sequences\n\t */\n\n\n\tconst inSequences = (needle_seq, sequences) => {\n\t  for (const seq of sequences) {\n\t    if (seq.start != needle_seq.start || seq.end != needle_seq.end) {\n\t      continue;\n\t    }\n\n\t    if (seq.substrs.join('') !== needle_seq.substrs.join('')) {\n\t      continue;\n\t    }\n\n\t    let needle_parts = needle_seq.parts;\n\t    /**\n\t     * @param {TSequencePart} part\n\t     */\n\n\t    const filter = part => {\n\t      for (const needle_part of needle_parts) {\n\t        if (needle_part.start === part.start && needle_part.substr === part.substr) {\n\t          return false;\n\t        }\n\n\t        if (part.length == 1 || needle_part.length == 1) {\n\t          continue;\n\t        } // check for overlapping parts\n\t        // a = ['::=','==']\n\t        // b = ['::','===']\n\t        // a = ['r','sm']\n\t        // b = ['rs','m']\n\n\n\t        if (part.start < needle_part.start && part.end > needle_part.start) {\n\t          return true;\n\t        }\n\n\t        if (needle_part.start < part.start && needle_part.end > part.start) {\n\t          return true;\n\t        }\n\t      }\n\n\t      return false;\n\t    };\n\n\t    let filtered = seq.parts.filter(filter);\n\n\t    if (filtered.length > 0) {\n\t      continue;\n\t    }\n\n\t    return true;\n\t  }\n\n\t  return false;\n\t};\n\n\tclass Sequence {\n\t  constructor() {\n\t    /** @type {TSequencePart[]} */\n\t    this.parts = [];\n\t    /** @type {string[]} */\n\n\t    this.substrs = [];\n\t    this.start = 0;\n\t    this.end = 0;\n\t  }\n\t  /**\n\t   * @param {TSequencePart|undefined} part\n\t   */\n\n\n\t  add(part) {\n\t    if (part) {\n\t      this.parts.push(part);\n\t      this.substrs.push(part.substr);\n\t      this.start = Math.min(part.start, this.start);\n\t      this.end = Math.max(part.end, this.end);\n\t    }\n\t  }\n\n\t  last() {\n\t    return this.parts[this.parts.length - 1];\n\t  }\n\n\t  length() {\n\t    return this.parts.length;\n\t  }\n\t  /**\n\t   * @param {number} position\n\t   * @param {TSequencePart} last_piece\n\t   */\n\n\n\t  clone(position, last_piece) {\n\t    let clone = new Sequence();\n\t    let parts = JSON.parse(JSON.stringify(this.parts));\n\t    let last_part = parts.pop();\n\n\t    for (const part of parts) {\n\t      clone.add(part);\n\t    }\n\n\t    let last_substr = last_piece.substr.substring(0, position - last_part.start);\n\t    let clone_last_len = last_substr.length;\n\t    clone.add({\n\t      start: last_part.start,\n\t      end: last_part.start + clone_last_len,\n\t      length: clone_last_len,\n\t      substr: last_substr\n\t    });\n\t    return clone;\n\t  }\n\n\t}\n\t/**\n\t * Expand a regular expression pattern to include unicode variants\n\t * \teg /a/ becomes /aⓐａẚàáâầấẫẩãāăằắẵẳȧǡäǟảåǻǎȁȃạậặḁąⱥɐɑAⒶＡÀÁÂẦẤẪẨÃĀĂẰẮẴẲȦǠÄǞẢÅǺǍȀȂẠẬẶḀĄȺⱯ/\n\t *\n\t * Issue:\n\t *  ﺊﺋ [ 'ﺊ = \\\\u{fe8a}', 'ﺋ = \\\\u{fe8b}' ]\n\t *\tbecomes:\tئئ [ 'ي = \\\\u{64a}', 'ٔ = \\\\u{654}', 'ي = \\\\u{64a}', 'ٔ = \\\\u{654}' ]\n\t *\n\t *\tİĲ = IIJ = ⅡJ\n\t *\n\t * \t1/2/4\n\t *\n\t * @param {string} str\n\t * @return {string|undefined}\n\t */\n\n\n\tconst getPattern = str => {\n\t  initialize();\n\t  str = asciifold(str);\n\t  let pattern = '';\n\t  let sequences = [new Sequence()];\n\n\t  for (let i = 0; i < str.length; i++) {\n\t    let substr = str.substring(i);\n\t    let match = substr.match(multi_char_reg);\n\t    const char = str.substring(i, i + 1);\n\t    const match_str = match ? match[0] : null; // loop through sequences\n\t    // add either the char or multi_match\n\n\t    let overlapping = [];\n\t    let added_types = new Set();\n\n\t    for (const sequence of sequences) {\n\t      const last_piece = sequence.last();\n\n\t      if (!last_piece || last_piece.length == 1 || last_piece.end <= i) {\n\t        // if we have a multi match\n\t        if (match_str) {\n\t          const len = match_str.length;\n\t          sequence.add({\n\t            start: i,\n\t            end: i + len,\n\t            length: len,\n\t            substr: match_str\n\t          });\n\t          added_types.add('1');\n\t        } else {\n\t          sequence.add({\n\t            start: i,\n\t            end: i + 1,\n\t            length: 1,\n\t            substr: char\n\t          });\n\t          added_types.add('2');\n\t        }\n\t      } else if (match_str) {\n\t        let clone = sequence.clone(i, last_piece);\n\t        const len = match_str.length;\n\t        clone.add({\n\t          start: i,\n\t          end: i + len,\n\t          length: len,\n\t          substr: match_str\n\t        });\n\t        overlapping.push(clone);\n\t      } else {\n\t        // don't add char\n\t        // adding would create invalid patterns: 234 => [2,34,4]\n\t        added_types.add('3');\n\t      }\n\t    } // if we have overlapping\n\n\n\t    if (overlapping.length > 0) {\n\t      // ['ii','iii'] before ['i','i','iii']\n\t      overlapping = overlapping.sort((a, b) => {\n\t        return a.length() - b.length();\n\t      });\n\n\t      for (let clone of overlapping) {\n\t        // don't add if we already have an equivalent sequence\n\t        if (inSequences(clone, sequences)) {\n\t          continue;\n\t        }\n\n\t        sequences.push(clone);\n\t      }\n\n\t      continue;\n\t    } // if we haven't done anything unique\n\t    // clean up the patterns\n\t    // helps keep patterns smaller\n\t    // if str = 'r₨㎧aarss', pattern will be 446 instead of 655\n\n\n\t    if (i > 0 && added_types.size == 1 && !added_types.has('3')) {\n\t      pattern += sequencesToPattern(sequences, false);\n\t      let new_seq = new Sequence();\n\t      const old_seq = sequences[0];\n\n\t      if (old_seq) {\n\t        new_seq.add(old_seq.last());\n\t      }\n\n\t      sequences = [new_seq];\n\t    }\n\t  }\n\n\t  pattern += sequencesToPattern(sequences, true);\n\t  return pattern;\n\t};\n\n\t/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */\n\n\t/**\n\t * A property getter resolving dot-notation\n\t * @param  {Object}  obj     The root object to fetch property on\n\t * @param  {String}  name    The optionally dotted property name to fetch\n\t * @return {Object}          The resolved property value\n\t */\n\tconst getAttr = (obj, name) => {\n\t  if (!obj) return;\n\t  return obj[name];\n\t};\n\t/**\n\t * A property getter resolving dot-notation\n\t * @param  {Object}  obj     The root object to fetch property on\n\t * @param  {String}  name    The optionally dotted property name to fetch\n\t * @return {Object}          The resolved property value\n\t */\n\n\tconst getAttrNesting = (obj, name) => {\n\t  if (!obj) return;\n\t  var part,\n\t      names = name.split(\".\");\n\n\t  while ((part = names.shift()) && (obj = obj[part]));\n\n\t  return obj;\n\t};\n\t/**\n\t * Calculates how close of a match the\n\t * given value is against a search token.\n\t *\n\t */\n\n\tconst scoreValue = (value, token, weight) => {\n\t  var score, pos;\n\t  if (!value) return 0;\n\t  value = value + '';\n\t  if (token.regex == null) return 0;\n\t  pos = value.search(token.regex);\n\t  if (pos === -1) return 0;\n\t  score = token.string.length / value.length;\n\t  if (pos === 0) score += 0.5;\n\t  return score * weight;\n\t};\n\t/**\n\t * Cast object property to an array if it exists and has a value\n\t *\n\t */\n\n\tconst propToArray = (obj, key) => {\n\t  var value = obj[key];\n\t  if (typeof value == 'function') return value;\n\n\t  if (value && !Array.isArray(value)) {\n\t    obj[key] = [value];\n\t  }\n\t};\n\t/**\n\t * Iterates over arrays and hashes.\n\t *\n\t * ```\n\t * iterate(this.items, function(item, id) {\n\t *    // invoked for each item\n\t * });\n\t * ```\n\t *\n\t */\n\n\tconst iterate$1 = (object, callback) => {\n\t  if (Array.isArray(object)) {\n\t    object.forEach(callback);\n\t  } else {\n\t    for (var key in object) {\n\t      if (object.hasOwnProperty(key)) {\n\t        callback(object[key], key);\n\t      }\n\t    }\n\t  }\n\t};\n\tconst cmp = (a, b) => {\n\t  if (typeof a === 'number' && typeof b === 'number') {\n\t    return a > b ? 1 : a < b ? -1 : 0;\n\t  }\n\n\t  a = asciifold(a + '').toLowerCase();\n\t  b = asciifold(b + '').toLowerCase();\n\t  if (a > b) return 1;\n\t  if (b > a) return -1;\n\t  return 0;\n\t};\n\n\t/*! sifter.js | https://github.com/orchidjs/sifter.js | Apache License (v2) */\n\n\t/**\n\t * sifter.js\n\t * Copyright (c) 2013–2020 Brian Reavis & contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t * @author Brian Reavis <brian@thirdroute.com>\n\t */\n\n\tclass Sifter {\n\t  // []|{};\n\n\t  /**\n\t   * Textually searches arrays and hashes of objects\n\t   * by property (or multiple properties). Designed\n\t   * specifically for autocomplete.\n\t   *\n\t   */\n\t  constructor(items, settings) {\n\t    this.items = void 0;\n\t    this.settings = void 0;\n\t    this.items = items;\n\t    this.settings = settings || {\n\t      diacritics: true\n\t    };\n\t  }\n\n\t  /**\n\t   * Splits a search string into an array of individual\n\t   * regexps to be used to match results.\n\t   *\n\t   */\n\t  tokenize(query, respect_word_boundaries, weights) {\n\t    if (!query || !query.length) return [];\n\t    const tokens = [];\n\t    const words = query.split(/\\s+/);\n\t    var field_regex;\n\n\t    if (weights) {\n\t      field_regex = new RegExp('^(' + Object.keys(weights).map(escape_regex).join('|') + ')\\:(.*)$');\n\t    }\n\n\t    words.forEach(word => {\n\t      let field_match;\n\t      let field = null;\n\t      let regex = null; // look for \"field:query\" tokens\n\n\t      if (field_regex && (field_match = word.match(field_regex))) {\n\t        field = field_match[1];\n\t        word = field_match[2];\n\t      }\n\n\t      if (word.length > 0) {\n\t        if (this.settings.diacritics) {\n\t          regex = getPattern(word) || null;\n\t        } else {\n\t          regex = escape_regex(word);\n\t        }\n\n\t        if (regex && respect_word_boundaries) regex = \"\\\\b\" + regex;\n\t      }\n\n\t      tokens.push({\n\t        string: word,\n\t        regex: regex ? new RegExp(regex, 'iu') : null,\n\t        field: field\n\t      });\n\t    });\n\t    return tokens;\n\t  }\n\n\t  /**\n\t   * Returns a function to be used to score individual results.\n\t   *\n\t   * Good matches will have a higher score than poor matches.\n\t   * If an item is not a match, 0 will be returned by the function.\n\t   *\n\t   * @returns {T.ScoreFn}\n\t   */\n\t  getScoreFunction(query, options) {\n\t    var search = this.prepareSearch(query, options);\n\t    return this._getScoreFunction(search);\n\t  }\n\t  /**\n\t   * @returns {T.ScoreFn}\n\t   *\n\t   */\n\n\n\t  _getScoreFunction(search) {\n\t    const tokens = search.tokens,\n\t          token_count = tokens.length;\n\n\t    if (!token_count) {\n\t      return function () {\n\t        return 0;\n\t      };\n\t    }\n\n\t    const fields = search.options.fields,\n\t          weights = search.weights,\n\t          field_count = fields.length,\n\t          getAttrFn = search.getAttrFn;\n\n\t    if (!field_count) {\n\t      return function () {\n\t        return 1;\n\t      };\n\t    }\n\t    /**\n\t     * Calculates the score of an object\n\t     * against the search query.\n\t     *\n\t     */\n\n\n\t    const scoreObject = function () {\n\t      if (field_count === 1) {\n\t        return function (token, data) {\n\t          const field = fields[0].field;\n\t          return scoreValue(getAttrFn(data, field), token, weights[field] || 1);\n\t        };\n\t      }\n\n\t      return function (token, data) {\n\t        var sum = 0; // is the token specific to a field?\n\n\t        if (token.field) {\n\t          const value = getAttrFn(data, token.field);\n\n\t          if (!token.regex && value) {\n\t            sum += 1 / field_count;\n\t          } else {\n\t            sum += scoreValue(value, token, 1);\n\t          }\n\t        } else {\n\t          iterate$1(weights, (weight, field) => {\n\t            sum += scoreValue(getAttrFn(data, field), token, weight);\n\t          });\n\t        }\n\n\t        return sum / field_count;\n\t      };\n\t    }();\n\n\t    if (token_count === 1) {\n\t      return function (data) {\n\t        return scoreObject(tokens[0], data);\n\t      };\n\t    }\n\n\t    if (search.options.conjunction === 'and') {\n\t      return function (data) {\n\t        var score,\n\t            sum = 0;\n\n\t        for (let token of tokens) {\n\t          score = scoreObject(token, data);\n\t          if (score <= 0) return 0;\n\t          sum += score;\n\t        }\n\n\t        return sum / token_count;\n\t      };\n\t    } else {\n\t      return function (data) {\n\t        var sum = 0;\n\t        iterate$1(tokens, token => {\n\t          sum += scoreObject(token, data);\n\t        });\n\t        return sum / token_count;\n\t      };\n\t    }\n\t  }\n\n\t  /**\n\t   * Returns a function that can be used to compare two\n\t   * results, for sorting purposes. If no sorting should\n\t   * be performed, `null` will be returned.\n\t   *\n\t   * @return function(a,b)\n\t   */\n\t  getSortFunction(query, options) {\n\t    var search = this.prepareSearch(query, options);\n\t    return this._getSortFunction(search);\n\t  }\n\n\t  _getSortFunction(search) {\n\t    var implicit_score,\n\t        sort_flds = [];\n\t    const self = this,\n\t          options = search.options,\n\t          sort = !search.query && options.sort_empty ? options.sort_empty : options.sort;\n\n\t    if (typeof sort == 'function') {\n\t      return sort.bind(this);\n\t    }\n\t    /**\n\t     * Fetches the specified sort field value\n\t     * from a search result item.\n\t     *\n\t     */\n\n\n\t    const get_field = function get_field(name, result) {\n\t      if (name === '$score') return result.score;\n\t      return search.getAttrFn(self.items[result.id], name);\n\t    }; // parse options\n\n\n\t    if (sort) {\n\t      for (let s of sort) {\n\t        if (search.query || s.field !== '$score') {\n\t          sort_flds.push(s);\n\t        }\n\t      }\n\t    } // the \"$score\" field is implied to be the primary\n\t    // sort field, unless it's manually specified\n\n\n\t    if (search.query) {\n\t      implicit_score = true;\n\n\t      for (let fld of sort_flds) {\n\t        if (fld.field === '$score') {\n\t          implicit_score = false;\n\t          break;\n\t        }\n\t      }\n\n\t      if (implicit_score) {\n\t        sort_flds.unshift({\n\t          field: '$score',\n\t          direction: 'desc'\n\t        });\n\t      } // without a search.query, all items will have the same score\n\n\t    } else {\n\t      sort_flds = sort_flds.filter(fld => fld.field !== '$score');\n\t    } // build function\n\n\n\t    const sort_flds_count = sort_flds.length;\n\n\t    if (!sort_flds_count) {\n\t      return null;\n\t    }\n\n\t    return function (a, b) {\n\t      var result, field;\n\n\t      for (let sort_fld of sort_flds) {\n\t        field = sort_fld.field;\n\t        let multiplier = sort_fld.direction === 'desc' ? -1 : 1;\n\t        result = multiplier * cmp(get_field(field, a), get_field(field, b));\n\t        if (result) return result;\n\t      }\n\n\t      return 0;\n\t    };\n\t  }\n\n\t  /**\n\t   * Parses a search query and returns an object\n\t   * with tokens and fields ready to be populated\n\t   * with results.\n\t   *\n\t   */\n\t  prepareSearch(query, optsUser) {\n\t    const weights = {};\n\t    var options = Object.assign({}, optsUser);\n\t    propToArray(options, 'sort');\n\t    propToArray(options, 'sort_empty'); // convert fields to new format\n\n\t    if (options.fields) {\n\t      propToArray(options, 'fields');\n\t      const fields = [];\n\t      options.fields.forEach(field => {\n\t        if (typeof field == 'string') {\n\t          field = {\n\t            field: field,\n\t            weight: 1\n\t          };\n\t        }\n\n\t        fields.push(field);\n\t        weights[field.field] = 'weight' in field ? field.weight : 1;\n\t      });\n\t      options.fields = fields;\n\t    }\n\n\t    return {\n\t      options: options,\n\t      query: query.toLowerCase().trim(),\n\t      tokens: this.tokenize(query, options.respect_word_boundaries, weights),\n\t      total: 0,\n\t      items: [],\n\t      weights: weights,\n\t      getAttrFn: options.nesting ? getAttrNesting : getAttr\n\t    };\n\t  }\n\n\t  /**\n\t   * Searches through all items and returns a sorted array of matches.\n\t   *\n\t   */\n\t  search(query, options) {\n\t    var self = this,\n\t        score,\n\t        search;\n\t    search = this.prepareSearch(query, options);\n\t    options = search.options;\n\t    query = search.query; // generate result scoring function\n\n\t    const fn_score = options.score || self._getScoreFunction(search); // perform search and sort\n\n\n\t    if (query.length) {\n\t      iterate$1(self.items, (item, id) => {\n\t        score = fn_score(item);\n\n\t        if (options.filter === false || score > 0) {\n\t          search.items.push({\n\t            'score': score,\n\t            'id': id\n\t          });\n\t        }\n\t      });\n\t    } else {\n\t      iterate$1(self.items, (_, id) => {\n\t        search.items.push({\n\t          'score': 1,\n\t          'id': id\n\t        });\n\t      });\n\t    }\n\n\t    const fn_sort = self._getSortFunction(search);\n\n\t    if (fn_sort) search.items.sort(fn_sort); // apply limits\n\n\t    search.total = search.items.length;\n\n\t    if (typeof options.limit === 'number') {\n\t      search.items = search.items.slice(0, options.limit);\n\t    }\n\n\t    return search;\n\t  }\n\n\t}\n\n\t/**\n\t * Iterates over arrays and hashes.\n\t *\n\t * ```\n\t * iterate(this.items, function(item, id) {\n\t *    // invoked for each item\n\t * });\n\t * ```\n\t *\n\t */\n\n\tconst iterate = (object, callback) => {\n\t  if (Array.isArray(object)) {\n\t    object.forEach(callback);\n\t  } else {\n\t    for (var key in object) {\n\t      if (object.hasOwnProperty(key)) {\n\t        callback(object[key], key);\n\t      }\n\t    }\n\t  }\n\t};\n\n\t/**\n\t * Return a dom element from either a dom query string, jQuery object, a dom element or html string\n\t * https://stackoverflow.com/questions/494143/creating-a-new-dom-element-from-an-html-string-using-built-in-dom-methods-or-pro/35385518#35385518\n\t *\n\t * param query should be {}\n\t */\n\n\tconst getDom = query => {\n\t  if (query.jquery) {\n\t    return query[0];\n\t  }\n\n\t  if (query instanceof HTMLElement) {\n\t    return query;\n\t  }\n\n\t  if (isHtmlString(query)) {\n\t    var tpl = document.createElement('template');\n\t    tpl.innerHTML = query.trim(); // Never return a text node of whitespace as the result\n\n\t    return tpl.content.firstChild;\n\t  }\n\n\t  return document.querySelector(query);\n\t};\n\tconst isHtmlString = arg => {\n\t  if (typeof arg === 'string' && arg.indexOf('<') > -1) {\n\t    return true;\n\t  }\n\n\t  return false;\n\t};\n\tconst escapeQuery = query => {\n\t  return query.replace(/['\"\\\\]/g, '\\\\$&');\n\t};\n\t/**\n\t * Dispatch an event\n\t *\n\t */\n\n\tconst triggerEvent = (dom_el, event_name) => {\n\t  var event = document.createEvent('HTMLEvents');\n\t  event.initEvent(event_name, true, false);\n\t  dom_el.dispatchEvent(event);\n\t};\n\t/**\n\t * Apply CSS rules to a dom element\n\t *\n\t */\n\n\tconst applyCSS = (dom_el, css) => {\n\t  Object.assign(dom_el.style, css);\n\t};\n\t/**\n\t * Add css classes\n\t *\n\t */\n\n\tconst addClasses = (elmts, ...classes) => {\n\t  var norm_classes = classesArray(classes);\n\t  elmts = castAsArray(elmts);\n\t  elmts.map(el => {\n\t    norm_classes.map(cls => {\n\t      el.classList.add(cls);\n\t    });\n\t  });\n\t};\n\t/**\n\t * Remove css classes\n\t *\n\t */\n\n\tconst removeClasses = (elmts, ...classes) => {\n\t  var norm_classes = classesArray(classes);\n\t  elmts = castAsArray(elmts);\n\t  elmts.map(el => {\n\t    norm_classes.map(cls => {\n\t      el.classList.remove(cls);\n\t    });\n\t  });\n\t};\n\t/**\n\t * Return arguments\n\t *\n\t */\n\n\tconst classesArray = args => {\n\t  var classes = [];\n\t  iterate(args, _classes => {\n\t    if (typeof _classes === 'string') {\n\t      _classes = _classes.trim().split(/[\\11\\12\\14\\15\\40]/);\n\t    }\n\n\t    if (Array.isArray(_classes)) {\n\t      classes = classes.concat(_classes);\n\t    }\n\t  });\n\t  return classes.filter(Boolean);\n\t};\n\t/**\n\t * Create an array from arg if it's not already an array\n\t *\n\t */\n\n\tconst castAsArray = arg => {\n\t  if (!Array.isArray(arg)) {\n\t    arg = [arg];\n\t  }\n\n\t  return arg;\n\t};\n\t/**\n\t * Get the closest node to the evt.target matching the selector\n\t * Stops at wrapper\n\t *\n\t */\n\n\tconst parentMatch = (target, selector, wrapper) => {\n\t  if (wrapper && !wrapper.contains(target)) {\n\t    return;\n\t  }\n\n\t  while (target && target.matches) {\n\t    if (target.matches(selector)) {\n\t      return target;\n\t    }\n\n\t    target = target.parentNode;\n\t  }\n\t};\n\t/**\n\t * Get the first or last item from an array\n\t *\n\t * > 0 - right (last)\n\t * <= 0 - left (first)\n\t *\n\t */\n\n\tconst getTail = (list, direction = 0) => {\n\t  if (direction > 0) {\n\t    return list[list.length - 1];\n\t  }\n\n\t  return list[0];\n\t};\n\t/**\n\t * Return true if an object is empty\n\t *\n\t */\n\n\tconst isEmptyObject = obj => {\n\t  return Object.keys(obj).length === 0;\n\t};\n\t/**\n\t * Get the index of an element amongst sibling nodes of the same type\n\t *\n\t */\n\n\tconst nodeIndex = (el, amongst) => {\n\t  if (!el) return -1;\n\t  amongst = amongst || el.nodeName;\n\t  var i = 0;\n\n\t  while (el = el.previousElementSibling) {\n\t    if (el.matches(amongst)) {\n\t      i++;\n\t    }\n\t  }\n\n\t  return i;\n\t};\n\t/**\n\t * Set attributes of an element\n\t *\n\t */\n\n\tconst setAttr = (el, attrs) => {\n\t  iterate(attrs, (val, attr) => {\n\t    if (val == null) {\n\t      el.removeAttribute(attr);\n\t    } else {\n\t      el.setAttribute(attr, '' + val);\n\t    }\n\t  });\n\t};\n\t/**\n\t * Replace a node\n\t */\n\n\tconst replaceNode = (existing, replacement) => {\n\t  if (existing.parentNode) existing.parentNode.replaceChild(replacement, existing);\n\t};\n\n\t/**\n\t * highlight v3 | MIT license | Johann Burkard <jb@eaio.com>\n\t * Highlights arbitrary terms in a node.\n\t *\n\t * - Modified by Marshal <beatgates@gmail.com> 2011-6-24 (added regex)\n\t * - Modified by Brian Reavis <brian@thirdroute.com> 2012-8-27 (cleanup)\n\t */\n\tconst highlight = (element, regex) => {\n\t  if (regex === null) return; // convet string to regex\n\n\t  if (typeof regex === 'string') {\n\t    if (!regex.length) return;\n\t    regex = new RegExp(regex, 'i');\n\t  } // Wrap matching part of text node with highlighting <span>, e.g.\n\t  // Soccer  ->  <span class=\"highlight\">Soc</span>cer  for regex = /soc/i\n\n\n\t  const highlightText = node => {\n\t    var match = node.data.match(regex);\n\n\t    if (match && node.data.length > 0) {\n\t      var spannode = document.createElement('span');\n\t      spannode.className = 'highlight';\n\t      var middlebit = node.splitText(match.index);\n\t      middlebit.splitText(match[0].length);\n\t      var middleclone = middlebit.cloneNode(true);\n\t      spannode.appendChild(middleclone);\n\t      replaceNode(middlebit, spannode);\n\t      return 1;\n\t    }\n\n\t    return 0;\n\t  }; // Recurse element node, looking for child text nodes to highlight, unless element\n\t  // is childless, <script>, <style>, or already highlighted: <span class=\"hightlight\">\n\n\n\t  const highlightChildren = node => {\n\t    if (node.nodeType === 1 && node.childNodes && !/(script|style)/i.test(node.tagName) && (node.className !== 'highlight' || node.tagName !== 'SPAN')) {\n\t      Array.from(node.childNodes).forEach(element => {\n\t        highlightRecursive(element);\n\t      });\n\t    }\n\t  };\n\n\t  const highlightRecursive = node => {\n\t    if (node.nodeType === 3) {\n\t      return highlightText(node);\n\t    }\n\n\t    highlightChildren(node);\n\t    return 0;\n\t  };\n\n\t  highlightRecursive(element);\n\t};\n\t/**\n\t * removeHighlight fn copied from highlight v5 and\n\t * edited to remove with(), pass js strict mode, and use without jquery\n\t */\n\n\tconst removeHighlight = el => {\n\t  var elements = el.querySelectorAll(\"span.highlight\");\n\t  Array.prototype.forEach.call(elements, function (el) {\n\t    var parent = el.parentNode;\n\t    parent.replaceChild(el.firstChild, el);\n\t    parent.normalize();\n\t  });\n\t};\n\n\tconst KEY_A = 65;\n\tconst KEY_RETURN = 13;\n\tconst KEY_ESC = 27;\n\tconst KEY_LEFT = 37;\n\tconst KEY_UP = 38;\n\tconst KEY_RIGHT = 39;\n\tconst KEY_DOWN = 40;\n\tconst KEY_BACKSPACE = 8;\n\tconst KEY_DELETE = 46;\n\tconst KEY_TAB = 9;\n\tconst IS_MAC = typeof navigator === 'undefined' ? false : /Mac/.test(navigator.userAgent);\n\tconst KEY_SHORTCUT = IS_MAC ? 'metaKey' : 'ctrlKey'; // ctrl key or apple key for ma\n\n\tvar defaults = {\n\t  options: [],\n\t  optgroups: [],\n\t  plugins: [],\n\t  delimiter: ',',\n\t  splitOn: null,\n\t  // regexp or string for splitting up values from a paste command\n\t  persist: true,\n\t  diacritics: true,\n\t  create: null,\n\t  createOnBlur: false,\n\t  createFilter: null,\n\t  highlight: true,\n\t  openOnFocus: true,\n\t  shouldOpen: null,\n\t  maxOptions: 50,\n\t  maxItems: null,\n\t  hideSelected: null,\n\t  duplicates: false,\n\t  addPrecedence: false,\n\t  selectOnTab: false,\n\t  preload: null,\n\t  allowEmptyOption: false,\n\t  //closeAfterSelect: false,\n\t  loadThrottle: 300,\n\t  loadingClass: 'loading',\n\t  dataAttr: null,\n\t  //'data-data',\n\t  optgroupField: 'optgroup',\n\t  valueField: 'value',\n\t  labelField: 'text',\n\t  disabledField: 'disabled',\n\t  optgroupLabelField: 'label',\n\t  optgroupValueField: 'value',\n\t  lockOptgroupOrder: false,\n\t  sortField: '$order',\n\t  searchField: ['text'],\n\t  searchConjunction: 'and',\n\t  mode: null,\n\t  wrapperClass: 'ts-wrapper',\n\t  controlClass: 'ts-control',\n\t  dropdownClass: 'ts-dropdown',\n\t  dropdownContentClass: 'ts-dropdown-content',\n\t  itemClass: 'item',\n\t  optionClass: 'option',\n\t  dropdownParent: null,\n\t  controlInput: '<input type=\"text\" autocomplete=\"off\" size=\"1\" />',\n\t  copyClassesToDropdown: false,\n\t  placeholder: null,\n\t  hidePlaceholder: null,\n\t  shouldLoad: function (query) {\n\t    return query.length > 0;\n\t  },\n\n\t  /*\n\t  load                 : null, // function(query, callback) { ... }\n\t  score                : null, // function(search) { ... }\n\t  onInitialize         : null, // function() { ... }\n\t  onChange             : null, // function(value) { ... }\n\t  onItemAdd            : null, // function(value, $item) { ... }\n\t  onItemRemove         : null, // function(value) { ... }\n\t  onClear              : null, // function() { ... }\n\t  onOptionAdd          : null, // function(value, data) { ... }\n\t  onOptionRemove       : null, // function(value) { ... }\n\t  onOptionClear        : null, // function() { ... }\n\t  onOptionGroupAdd     : null, // function(id, data) { ... }\n\t  onOptionGroupRemove  : null, // function(id) { ... }\n\t  onOptionGroupClear   : null, // function() { ... }\n\t  onDropdownOpen       : null, // function(dropdown) { ... }\n\t  onDropdownClose      : null, // function(dropdown) { ... }\n\t  onType               : null, // function(str) { ... }\n\t  onDelete             : null, // function(values) { ... }\n\t  */\n\t  render: {\n\t    /*\n\t    item: null,\n\t    optgroup: null,\n\t    optgroup_header: null,\n\t    option: null,\n\t    option_create: null\n\t    */\n\t  }\n\t};\n\n\t/**\n\t * Converts a scalar to its best string representation\n\t * for hash keys and HTML attribute values.\n\t *\n\t * Transformations:\n\t *   'str'     -> 'str'\n\t *   null      -> ''\n\t *   undefined -> ''\n\t *   true      -> '1'\n\t *   false     -> '0'\n\t *   0         -> '0'\n\t *   1         -> '1'\n\t *\n\t */\n\tconst hash_key = value => {\n\t  if (typeof value === 'undefined' || value === null) return null;\n\t  return get_hash(value);\n\t};\n\tconst get_hash = value => {\n\t  if (typeof value === 'boolean') return value ? '1' : '0';\n\t  return value + '';\n\t};\n\t/**\n\t * Escapes a string for use within HTML.\n\t *\n\t */\n\n\tconst escape_html = str => {\n\t  return (str + '').replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;');\n\t};\n\t/**\n\t * Debounce the user provided load function\n\t *\n\t */\n\n\tconst loadDebounce = (fn, delay) => {\n\t  var timeout;\n\t  return function (value, callback) {\n\t    var self = this;\n\n\t    if (timeout) {\n\t      self.loading = Math.max(self.loading - 1, 0);\n\t      clearTimeout(timeout);\n\t    }\n\n\t    timeout = setTimeout(function () {\n\t      timeout = null;\n\t      self.loadedSearches[value] = true;\n\t      fn.call(self, value, callback);\n\t    }, delay);\n\t  };\n\t};\n\t/**\n\t * Debounce all fired events types listed in `types`\n\t * while executing the provided `fn`.\n\t *\n\t */\n\n\tconst debounce_events = (self, types, fn) => {\n\t  var type;\n\t  var trigger = self.trigger;\n\t  var event_args = {}; // override trigger method\n\n\t  self.trigger = function () {\n\t    var type = arguments[0];\n\n\t    if (types.indexOf(type) !== -1) {\n\t      event_args[type] = arguments;\n\t    } else {\n\t      return trigger.apply(self, arguments);\n\t    }\n\t  }; // invoke provided function\n\n\n\t  fn.apply(self, []);\n\t  self.trigger = trigger; // trigger queued events\n\n\t  for (type of types) {\n\t    if (type in event_args) {\n\t      trigger.apply(self, event_args[type]);\n\t    }\n\t  }\n\t};\n\t/**\n\t * Determines the current selection within a text input control.\n\t * Returns an object containing:\n\t *   - start\n\t *   - length\n\t *\n\t */\n\n\tconst getSelection = input => {\n\t  return {\n\t    start: input.selectionStart || 0,\n\t    length: (input.selectionEnd || 0) - (input.selectionStart || 0)\n\t  };\n\t};\n\t/**\n\t * Prevent default\n\t *\n\t */\n\n\tconst preventDefault = (evt, stop = false) => {\n\t  if (evt) {\n\t    evt.preventDefault();\n\n\t    if (stop) {\n\t      evt.stopPropagation();\n\t    }\n\t  }\n\t};\n\t/**\n\t * Add event helper\n\t *\n\t */\n\n\tconst addEvent = (target, type, callback, options) => {\n\t  target.addEventListener(type, callback, options);\n\t};\n\t/**\n\t * Return true if the requested key is down\n\t * Will return false if more than one control character is pressed ( when [ctrl+shift+a] != [ctrl+a] )\n\t * The current evt may not always set ( eg calling advanceSelection() )\n\t *\n\t */\n\n\tconst isKeyDown = (key_name, evt) => {\n\t  if (!evt) {\n\t    return false;\n\t  }\n\n\t  if (!evt[key_name]) {\n\t    return false;\n\t  }\n\n\t  var count = (evt.altKey ? 1 : 0) + (evt.ctrlKey ? 1 : 0) + (evt.shiftKey ? 1 : 0) + (evt.metaKey ? 1 : 0);\n\n\t  if (count === 1) {\n\t    return true;\n\t  }\n\n\t  return false;\n\t};\n\t/**\n\t * Get the id of an element\n\t * If the id attribute is not set, set the attribute with the given id\n\t *\n\t */\n\n\tconst getId = (el, id) => {\n\t  const existing_id = el.getAttribute('id');\n\n\t  if (existing_id) {\n\t    return existing_id;\n\t  }\n\n\t  el.setAttribute('id', id);\n\t  return id;\n\t};\n\t/**\n\t * Returns a string with backslashes added before characters that need to be escaped.\n\t */\n\n\tconst addSlashes = str => {\n\t  return str.replace(/[\\\\\"']/g, '\\\\$&');\n\t};\n\t/**\n\t *\n\t */\n\n\tconst append = (parent, node) => {\n\t  if (node) parent.append(node);\n\t};\n\n\tfunction getSettings(input, settings_user) {\n\t  var settings = Object.assign({}, defaults, settings_user);\n\t  var attr_data = settings.dataAttr;\n\t  var field_label = settings.labelField;\n\t  var field_value = settings.valueField;\n\t  var field_disabled = settings.disabledField;\n\t  var field_optgroup = settings.optgroupField;\n\t  var field_optgroup_label = settings.optgroupLabelField;\n\t  var field_optgroup_value = settings.optgroupValueField;\n\t  var tag_name = input.tagName.toLowerCase();\n\t  var placeholder = input.getAttribute('placeholder') || input.getAttribute('data-placeholder');\n\n\t  if (!placeholder && !settings.allowEmptyOption) {\n\t    let option = input.querySelector('option[value=\"\"]');\n\n\t    if (option) {\n\t      placeholder = option.textContent;\n\t    }\n\t  }\n\n\t  var settings_element = {\n\t    placeholder: placeholder,\n\t    options: [],\n\t    optgroups: [],\n\t    items: [],\n\t    maxItems: null\n\t  };\n\t  /**\n\t   * Initialize from a <select> element.\n\t   *\n\t   */\n\n\t  var init_select = () => {\n\t    var tagName;\n\t    var options = settings_element.options;\n\t    var optionsMap = {};\n\t    var group_count = 1;\n\n\t    var readData = el => {\n\t      var data = Object.assign({}, el.dataset); // get plain object from DOMStringMap\n\n\t      var json = attr_data && data[attr_data];\n\n\t      if (typeof json === 'string' && json.length) {\n\t        data = Object.assign(data, JSON.parse(json));\n\t      }\n\n\t      return data;\n\t    };\n\n\t    var addOption = (option, group) => {\n\t      var value = hash_key(option.value);\n\t      if (value == null) return;\n\t      if (!value && !settings.allowEmptyOption) return; // if the option already exists, it's probably been\n\t      // duplicated in another optgroup. in this case, push\n\t      // the current group to the \"optgroup\" property on the\n\t      // existing option so that it's rendered in both places.\n\n\t      if (optionsMap.hasOwnProperty(value)) {\n\t        if (group) {\n\t          var arr = optionsMap[value][field_optgroup];\n\n\t          if (!arr) {\n\t            optionsMap[value][field_optgroup] = group;\n\t          } else if (!Array.isArray(arr)) {\n\t            optionsMap[value][field_optgroup] = [arr, group];\n\t          } else {\n\t            arr.push(group);\n\t          }\n\t        }\n\t      } else {\n\t        var option_data = readData(option);\n\t        option_data[field_label] = option_data[field_label] || option.textContent;\n\t        option_data[field_value] = option_data[field_value] || value;\n\t        option_data[field_disabled] = option_data[field_disabled] || option.disabled;\n\t        option_data[field_optgroup] = option_data[field_optgroup] || group;\n\t        option_data.$option = option;\n\t        optionsMap[value] = option_data;\n\t        options.push(option_data);\n\t      }\n\n\t      if (option.selected) {\n\t        settings_element.items.push(value);\n\t      }\n\t    };\n\n\t    var addGroup = optgroup => {\n\t      var id, optgroup_data;\n\t      optgroup_data = readData(optgroup);\n\t      optgroup_data[field_optgroup_label] = optgroup_data[field_optgroup_label] || optgroup.getAttribute('label') || '';\n\t      optgroup_data[field_optgroup_value] = optgroup_data[field_optgroup_value] || group_count++;\n\t      optgroup_data[field_disabled] = optgroup_data[field_disabled] || optgroup.disabled;\n\t      settings_element.optgroups.push(optgroup_data);\n\t      id = optgroup_data[field_optgroup_value];\n\t      iterate(optgroup.children, option => {\n\t        addOption(option, id);\n\t      });\n\t    };\n\n\t    settings_element.maxItems = input.hasAttribute('multiple') ? null : 1;\n\t    iterate(input.children, child => {\n\t      tagName = child.tagName.toLowerCase();\n\n\t      if (tagName === 'optgroup') {\n\t        addGroup(child);\n\t      } else if (tagName === 'option') {\n\t        addOption(child);\n\t      }\n\t    });\n\t  };\n\t  /**\n\t   * Initialize from a <input type=\"text\"> element.\n\t   *\n\t   */\n\n\n\t  var init_textbox = () => {\n\t    const data_raw = input.getAttribute(attr_data);\n\n\t    if (!data_raw) {\n\t      var value = input.value.trim() || '';\n\t      if (!settings.allowEmptyOption && !value.length) return;\n\t      const values = value.split(settings.delimiter);\n\t      iterate(values, value => {\n\t        const option = {};\n\t        option[field_label] = value;\n\t        option[field_value] = value;\n\t        settings_element.options.push(option);\n\t      });\n\t      settings_element.items = values;\n\t    } else {\n\t      settings_element.options = JSON.parse(data_raw);\n\t      iterate(settings_element.options, opt => {\n\t        settings_element.items.push(opt[field_value]);\n\t      });\n\t    }\n\t  };\n\n\t  if (tag_name === 'select') {\n\t    init_select();\n\t  } else {\n\t    init_textbox();\n\t  }\n\n\t  return Object.assign({}, defaults, settings_element, settings_user);\n\t}\n\n\tvar instance_i = 0;\n\tclass TomSelect extends MicroPlugin(MicroEvent) {\n\t  // @deprecated 1.8\n\t  constructor(input_arg, user_settings) {\n\t    super();\n\t    this.control_input = void 0;\n\t    this.wrapper = void 0;\n\t    this.dropdown = void 0;\n\t    this.control = void 0;\n\t    this.dropdown_content = void 0;\n\t    this.focus_node = void 0;\n\t    this.order = 0;\n\t    this.settings = void 0;\n\t    this.input = void 0;\n\t    this.tabIndex = void 0;\n\t    this.is_select_tag = void 0;\n\t    this.rtl = void 0;\n\t    this.inputId = void 0;\n\t    this._destroy = void 0;\n\t    this.sifter = void 0;\n\t    this.isOpen = false;\n\t    this.isDisabled = false;\n\t    this.isRequired = void 0;\n\t    this.isInvalid = false;\n\t    this.isValid = true;\n\t    this.isLocked = false;\n\t    this.isFocused = false;\n\t    this.isInputHidden = false;\n\t    this.isSetup = false;\n\t    this.ignoreFocus = false;\n\t    this.ignoreHover = false;\n\t    this.hasOptions = false;\n\t    this.currentResults = void 0;\n\t    this.lastValue = '';\n\t    this.caretPos = 0;\n\t    this.loading = 0;\n\t    this.loadedSearches = {};\n\t    this.activeOption = null;\n\t    this.activeItems = [];\n\t    this.optgroups = {};\n\t    this.options = {};\n\t    this.userOptions = {};\n\t    this.items = [];\n\t    instance_i++;\n\t    var dir;\n\t    var input = getDom(input_arg);\n\n\t    if (input.tomselect) {\n\t      throw new Error('Tom Select already initialized on this element');\n\t    }\n\n\t    input.tomselect = this; // detect rtl environment\n\n\t    var computedStyle = window.getComputedStyle && window.getComputedStyle(input, null);\n\t    dir = computedStyle.getPropertyValue('direction'); // setup default state\n\n\t    const settings = getSettings(input, user_settings);\n\t    this.settings = settings;\n\t    this.input = input;\n\t    this.tabIndex = input.tabIndex || 0;\n\t    this.is_select_tag = input.tagName.toLowerCase() === 'select';\n\t    this.rtl = /rtl/i.test(dir);\n\t    this.inputId = getId(input, 'tomselect-' + instance_i);\n\t    this.isRequired = input.required; // search system\n\n\t    this.sifter = new Sifter(this.options, {\n\t      diacritics: settings.diacritics\n\t    }); // option-dependent defaults\n\n\t    settings.mode = settings.mode || (settings.maxItems === 1 ? 'single' : 'multi');\n\n\t    if (typeof settings.hideSelected !== 'boolean') {\n\t      settings.hideSelected = settings.mode === 'multi';\n\t    }\n\n\t    if (typeof settings.hidePlaceholder !== 'boolean') {\n\t      settings.hidePlaceholder = settings.mode !== 'multi';\n\t    } // set up createFilter callback\n\n\n\t    var filter = settings.createFilter;\n\n\t    if (typeof filter !== 'function') {\n\t      if (typeof filter === 'string') {\n\t        filter = new RegExp(filter);\n\t      }\n\n\t      if (filter instanceof RegExp) {\n\t        settings.createFilter = input => filter.test(input);\n\t      } else {\n\t        settings.createFilter = value => {\n\t          return this.settings.duplicates || !this.options[value];\n\t        };\n\t      }\n\t    }\n\n\t    this.initializePlugins(settings.plugins);\n\t    this.setupCallbacks();\n\t    this.setupTemplates(); // Create all elements\n\n\t    const wrapper = getDom('<div>');\n\t    const control = getDom('<div>');\n\n\t    const dropdown = this._render('dropdown');\n\n\t    const dropdown_content = getDom(`<div role=\"listbox\" tabindex=\"-1\">`);\n\t    const classes = this.input.getAttribute('class') || '';\n\t    const inputMode = settings.mode;\n\t    var control_input;\n\t    addClasses(wrapper, settings.wrapperClass, classes, inputMode);\n\t    addClasses(control, settings.controlClass);\n\t    append(wrapper, control);\n\t    addClasses(dropdown, settings.dropdownClass, inputMode);\n\n\t    if (settings.copyClassesToDropdown) {\n\t      addClasses(dropdown, classes);\n\t    }\n\n\t    addClasses(dropdown_content, settings.dropdownContentClass);\n\t    append(dropdown, dropdown_content);\n\t    getDom(settings.dropdownParent || wrapper).appendChild(dropdown); // default controlInput\n\n\t    if (isHtmlString(settings.controlInput)) {\n\t      control_input = getDom(settings.controlInput); // set attributes\n\n\t      var attrs = ['autocorrect', 'autocapitalize', 'autocomplete'];\n\t      iterate$1(attrs, attr => {\n\t        if (input.getAttribute(attr)) {\n\t          setAttr(control_input, {\n\t            [attr]: input.getAttribute(attr)\n\t          });\n\t        }\n\t      });\n\t      control_input.tabIndex = -1;\n\t      control.appendChild(control_input);\n\t      this.focus_node = control_input; // dom element\n\t    } else if (settings.controlInput) {\n\t      control_input = getDom(settings.controlInput);\n\t      this.focus_node = control_input;\n\t    } else {\n\t      control_input = getDom('<input/>');\n\t      this.focus_node = control;\n\t    }\n\n\t    this.wrapper = wrapper;\n\t    this.dropdown = dropdown;\n\t    this.dropdown_content = dropdown_content;\n\t    this.control = control;\n\t    this.control_input = control_input;\n\t    this.setup();\n\t  }\n\t  /**\n\t   * set up event bindings.\n\t   *\n\t   */\n\n\n\t  setup() {\n\t    const self = this;\n\t    const settings = self.settings;\n\t    const control_input = self.control_input;\n\t    const dropdown = self.dropdown;\n\t    const dropdown_content = self.dropdown_content;\n\t    const wrapper = self.wrapper;\n\t    const control = self.control;\n\t    const input = self.input;\n\t    const focus_node = self.focus_node;\n\t    const passive_event = {\n\t      passive: true\n\t    };\n\t    const listboxId = self.inputId + '-ts-dropdown';\n\t    setAttr(dropdown_content, {\n\t      id: listboxId\n\t    });\n\t    setAttr(focus_node, {\n\t      role: 'combobox',\n\t      'aria-haspopup': 'listbox',\n\t      'aria-expanded': 'false',\n\t      'aria-controls': listboxId\n\t    });\n\t    const control_id = getId(focus_node, self.inputId + '-ts-control');\n\t    const query = \"label[for='\" + escapeQuery(self.inputId) + \"']\";\n\t    const label = document.querySelector(query);\n\t    const label_click = self.focus.bind(self);\n\n\t    if (label) {\n\t      addEvent(label, 'click', label_click);\n\t      setAttr(label, {\n\t        for: control_id\n\t      });\n\t      const label_id = getId(label, self.inputId + '-ts-label');\n\t      setAttr(focus_node, {\n\t        'aria-labelledby': label_id\n\t      });\n\t      setAttr(dropdown_content, {\n\t        'aria-labelledby': label_id\n\t      });\n\t    }\n\n\t    wrapper.style.width = input.style.width;\n\n\t    if (self.plugins.names.length) {\n\t      const classes_plugins = 'plugin-' + self.plugins.names.join(' plugin-');\n\t      addClasses([wrapper, dropdown], classes_plugins);\n\t    }\n\n\t    if ((settings.maxItems === null || settings.maxItems > 1) && self.is_select_tag) {\n\t      setAttr(input, {\n\t        multiple: 'multiple'\n\t      });\n\t    }\n\n\t    if (settings.placeholder) {\n\t      setAttr(control_input, {\n\t        placeholder: settings.placeholder\n\t      });\n\t    } // if splitOn was not passed in, construct it from the delimiter to allow pasting universally\n\n\n\t    if (!settings.splitOn && settings.delimiter) {\n\t      settings.splitOn = new RegExp('\\\\s*' + escape_regex(settings.delimiter) + '+\\\\s*');\n\t    } // debounce user defined load() if loadThrottle > 0\n\t    // after initializePlugins() so plugins can create/modify user defined loaders\n\n\n\t    if (settings.load && settings.loadThrottle) {\n\t      settings.load = loadDebounce(settings.load, settings.loadThrottle);\n\t    }\n\n\t    self.control_input.type = input.type;\n\t    addEvent(dropdown, 'mousemove', () => {\n\t      self.ignoreHover = false;\n\t    });\n\t    addEvent(dropdown, 'mouseenter', e => {\n\t      var target_match = parentMatch(e.target, '[data-selectable]', dropdown);\n\t      if (target_match) self.onOptionHover(e, target_match);\n\t    }, {\n\t      capture: true\n\t    }); // clicking on an option should select it\n\n\t    addEvent(dropdown, 'click', evt => {\n\t      const option = parentMatch(evt.target, '[data-selectable]');\n\n\t      if (option) {\n\t        self.onOptionSelect(evt, option);\n\t        preventDefault(evt, true);\n\t      }\n\t    });\n\t    addEvent(control, 'click', evt => {\n\t      var target_match = parentMatch(evt.target, '[data-ts-item]', control);\n\n\t      if (target_match && self.onItemSelect(evt, target_match)) {\n\t        preventDefault(evt, true);\n\t        return;\n\t      } // retain focus (see control_input mousedown)\n\n\n\t      if (control_input.value != '') {\n\t        return;\n\t      }\n\n\t      self.onClick();\n\t      preventDefault(evt, true);\n\t    }); // keydown on focus_node for arrow_down/arrow_up\n\n\t    addEvent(focus_node, 'keydown', e => self.onKeyDown(e)); // keypress and input/keyup\n\n\t    addEvent(control_input, 'keypress', e => self.onKeyPress(e));\n\t    addEvent(control_input, 'input', e => self.onInput(e));\n\t    addEvent(focus_node, 'blur', e => self.onBlur(e));\n\t    addEvent(focus_node, 'focus', e => self.onFocus(e));\n\t    addEvent(control_input, 'paste', e => self.onPaste(e));\n\n\t    const doc_mousedown = evt => {\n\t      // blur if target is outside of this instance\n\t      // dropdown is not always inside wrapper\n\t      const target = evt.composedPath()[0];\n\n\t      if (!wrapper.contains(target) && !dropdown.contains(target)) {\n\t        if (self.isFocused) {\n\t          self.blur();\n\t        }\n\n\t        self.inputState();\n\t        return;\n\t      } // retain focus by preventing native handling. if the\n\t      // event target is the input it should not be modified.\n\t      // otherwise, text selection within the input won't work.\n\t      // Fixes bug #212 which is no covered by tests\n\n\n\t      if (target == control_input && self.isOpen) {\n\t        evt.stopPropagation(); // clicking anywhere in the control should not blur the control_input (which would close the dropdown)\n\t      } else {\n\t        preventDefault(evt, true);\n\t      }\n\t    };\n\n\t    const win_scroll = () => {\n\t      if (self.isOpen) {\n\t        self.positionDropdown();\n\t      }\n\t    };\n\n\t    addEvent(document, 'mousedown', doc_mousedown);\n\t    addEvent(window, 'scroll', win_scroll, passive_event);\n\t    addEvent(window, 'resize', win_scroll, passive_event);\n\n\t    this._destroy = () => {\n\t      document.removeEventListener('mousedown', doc_mousedown);\n\t      window.removeEventListener('scroll', win_scroll);\n\t      window.removeEventListener('resize', win_scroll);\n\t      if (label) label.removeEventListener('click', label_click);\n\t    }; // store original html and tab index so that they can be\n\t    // restored when the destroy() method is called.\n\n\n\t    this.revertSettings = {\n\t      innerHTML: input.innerHTML,\n\t      tabIndex: input.tabIndex\n\t    };\n\t    input.tabIndex = -1;\n\t    input.insertAdjacentElement('afterend', self.wrapper);\n\t    self.sync(false);\n\t    settings.items = [];\n\t    delete settings.optgroups;\n\t    delete settings.options;\n\t    addEvent(input, 'invalid', () => {\n\t      if (self.isValid) {\n\t        self.isValid = false;\n\t        self.isInvalid = true;\n\t        self.refreshState();\n\t      }\n\t    });\n\t    self.updateOriginalInput();\n\t    self.refreshItems();\n\t    self.close(false);\n\t    self.inputState();\n\t    self.isSetup = true;\n\n\t    if (input.disabled) {\n\t      self.disable();\n\t    } else {\n\t      self.enable(); //sets tabIndex\n\t    }\n\n\t    self.on('change', this.onChange);\n\t    addClasses(input, 'tomselected', 'ts-hidden-accessible');\n\t    self.trigger('initialize'); // preload options\n\n\t    if (settings.preload === true) {\n\t      self.preload();\n\t    }\n\t  }\n\t  /**\n\t   * Register options and optgroups\n\t   *\n\t   */\n\n\n\t  setupOptions(options = [], optgroups = []) {\n\t    // build options table\n\t    this.addOptions(options); // build optgroup table\n\n\t    iterate$1(optgroups, optgroup => {\n\t      this.registerOptionGroup(optgroup);\n\t    });\n\t  }\n\t  /**\n\t   * Sets up default rendering functions.\n\t   */\n\n\n\t  setupTemplates() {\n\t    var self = this;\n\t    var field_label = self.settings.labelField;\n\t    var field_optgroup = self.settings.optgroupLabelField;\n\t    var templates = {\n\t      'optgroup': data => {\n\t        let optgroup = document.createElement('div');\n\t        optgroup.className = 'optgroup';\n\t        optgroup.appendChild(data.options);\n\t        return optgroup;\n\t      },\n\t      'optgroup_header': (data, escape) => {\n\t        return '<div class=\"optgroup-header\">' + escape(data[field_optgroup]) + '</div>';\n\t      },\n\t      'option': (data, escape) => {\n\t        return '<div>' + escape(data[field_label]) + '</div>';\n\t      },\n\t      'item': (data, escape) => {\n\t        return '<div>' + escape(data[field_label]) + '</div>';\n\t      },\n\t      'option_create': (data, escape) => {\n\t        return '<div class=\"create\">Add <strong>' + escape(data.input) + '</strong>&hellip;</div>';\n\t      },\n\t      'no_results': () => {\n\t        return '<div class=\"no-results\">No results found</div>';\n\t      },\n\t      'loading': () => {\n\t        return '<div class=\"spinner\"></div>';\n\t      },\n\t      'not_loading': () => {},\n\t      'dropdown': () => {\n\t        return '<div></div>';\n\t      }\n\t    };\n\t    self.settings.render = Object.assign({}, templates, self.settings.render);\n\t  }\n\t  /**\n\t   * Maps fired events to callbacks provided\n\t   * in the settings used when creating the control.\n\t   */\n\n\n\t  setupCallbacks() {\n\t    var key, fn;\n\t    var callbacks = {\n\t      'initialize': 'onInitialize',\n\t      'change': 'onChange',\n\t      'item_add': 'onItemAdd',\n\t      'item_remove': 'onItemRemove',\n\t      'item_select': 'onItemSelect',\n\t      'clear': 'onClear',\n\t      'option_add': 'onOptionAdd',\n\t      'option_remove': 'onOptionRemove',\n\t      'option_clear': 'onOptionClear',\n\t      'optgroup_add': 'onOptionGroupAdd',\n\t      'optgroup_remove': 'onOptionGroupRemove',\n\t      'optgroup_clear': 'onOptionGroupClear',\n\t      'dropdown_open': 'onDropdownOpen',\n\t      'dropdown_close': 'onDropdownClose',\n\t      'type': 'onType',\n\t      'load': 'onLoad',\n\t      'focus': 'onFocus',\n\t      'blur': 'onBlur'\n\t    };\n\n\t    for (key in callbacks) {\n\t      fn = this.settings[callbacks[key]];\n\t      if (fn) this.on(key, fn);\n\t    }\n\t  }\n\t  /**\n\t   * Sync the Tom Select instance with the original input or select\n\t   *\n\t   */\n\n\n\t  sync(get_settings = true) {\n\t    const self = this;\n\t    const settings = get_settings ? getSettings(self.input, {\n\t      delimiter: self.settings.delimiter\n\t    }) : self.settings;\n\t    self.setupOptions(settings.options, settings.optgroups);\n\t    self.setValue(settings.items || [], true); // silent prevents recursion\n\n\t    self.lastQuery = null; // so updated options will be displayed in dropdown\n\t  }\n\t  /**\n\t   * Triggered when the main control element\n\t   * has a click event.\n\t   *\n\t   */\n\n\n\t  onClick() {\n\t    var self = this;\n\n\t    if (self.activeItems.length > 0) {\n\t      self.clearActiveItems();\n\t      self.focus();\n\t      return;\n\t    }\n\n\t    if (self.isFocused && self.isOpen) {\n\t      self.blur();\n\t    } else {\n\t      self.focus();\n\t    }\n\t  }\n\t  /**\n\t   * @deprecated v1.7\n\t   *\n\t   */\n\n\n\t  onMouseDown() {}\n\t  /**\n\t   * Triggered when the value of the control has been changed.\n\t   * This should propagate the event to the original DOM\n\t   * input / select element.\n\t   */\n\n\n\t  onChange() {\n\t    triggerEvent(this.input, 'input');\n\t    triggerEvent(this.input, 'change');\n\t  }\n\t  /**\n\t   * Triggered on <input> paste.\n\t   *\n\t   */\n\n\n\t  onPaste(e) {\n\t    var self = this;\n\n\t    if (self.isInputHidden || self.isLocked) {\n\t      preventDefault(e);\n\t      return;\n\t    } // If a regex or string is included, this will split the pasted\n\t    // input and create Items for each separate value\n\n\n\t    if (!self.settings.splitOn) {\n\t      return;\n\t    } // Wait for pasted text to be recognized in value\n\n\n\t    setTimeout(() => {\n\t      var pastedText = self.inputValue();\n\n\t      if (!pastedText.match(self.settings.splitOn)) {\n\t        return;\n\t      }\n\n\t      var splitInput = pastedText.trim().split(self.settings.splitOn);\n\t      iterate$1(splitInput, piece => {\n\t        const hash = hash_key(piece);\n\n\t        if (hash) {\n\t          if (this.options[piece]) {\n\t            self.addItem(piece);\n\t          } else {\n\t            self.createItem(piece);\n\t          }\n\t        }\n\t      });\n\t    }, 0);\n\t  }\n\t  /**\n\t   * Triggered on <input> keypress.\n\t   *\n\t   */\n\n\n\t  onKeyPress(e) {\n\t    var self = this;\n\n\t    if (self.isLocked) {\n\t      preventDefault(e);\n\t      return;\n\t    }\n\n\t    var character = String.fromCharCode(e.keyCode || e.which);\n\n\t    if (self.settings.create && self.settings.mode === 'multi' && character === self.settings.delimiter) {\n\t      self.createItem();\n\t      preventDefault(e);\n\t      return;\n\t    }\n\t  }\n\t  /**\n\t   * Triggered on <input> keydown.\n\t   *\n\t   */\n\n\n\t  onKeyDown(e) {\n\t    var self = this;\n\t    self.ignoreHover = true;\n\n\t    if (self.isLocked) {\n\t      if (e.keyCode !== KEY_TAB) {\n\t        preventDefault(e);\n\t      }\n\n\t      return;\n\t    }\n\n\t    switch (e.keyCode) {\n\t      // ctrl+A: select all\n\t      case KEY_A:\n\t        if (isKeyDown(KEY_SHORTCUT, e)) {\n\t          if (self.control_input.value == '') {\n\t            preventDefault(e);\n\t            self.selectAll();\n\t            return;\n\t          }\n\t        }\n\n\t        break;\n\t      // esc: close dropdown\n\n\t      case KEY_ESC:\n\t        if (self.isOpen) {\n\t          preventDefault(e, true);\n\t          self.close();\n\t        }\n\n\t        self.clearActiveItems();\n\t        return;\n\t      // down: open dropdown or move selection down\n\n\t      case KEY_DOWN:\n\t        if (!self.isOpen && self.hasOptions) {\n\t          self.open();\n\t        } else if (self.activeOption) {\n\t          let next = self.getAdjacent(self.activeOption, 1);\n\t          if (next) self.setActiveOption(next);\n\t        }\n\n\t        preventDefault(e);\n\t        return;\n\t      // up: move selection up\n\n\t      case KEY_UP:\n\t        if (self.activeOption) {\n\t          let prev = self.getAdjacent(self.activeOption, -1);\n\t          if (prev) self.setActiveOption(prev);\n\t        }\n\n\t        preventDefault(e);\n\t        return;\n\t      // return: select active option\n\n\t      case KEY_RETURN:\n\t        if (self.canSelect(self.activeOption)) {\n\t          self.onOptionSelect(e, self.activeOption);\n\t          preventDefault(e); // if the option_create=null, the dropdown might be closed\n\t        } else if (self.settings.create && self.createItem()) {\n\t          preventDefault(e); // don't submit form when searching for a value\n\t        } else if (document.activeElement == self.control_input && self.isOpen) {\n\t          preventDefault(e);\n\t        }\n\n\t        return;\n\t      // left: modifiy item selection to the left\n\n\t      case KEY_LEFT:\n\t        self.advanceSelection(-1, e);\n\t        return;\n\t      // right: modifiy item selection to the right\n\n\t      case KEY_RIGHT:\n\t        self.advanceSelection(1, e);\n\t        return;\n\t      // tab: select active option and/or create item\n\n\t      case KEY_TAB:\n\t        if (self.settings.selectOnTab) {\n\t          if (self.canSelect(self.activeOption)) {\n\t            self.onOptionSelect(e, self.activeOption); // prevent default [tab] behaviour of jump to the next field\n\t            // if select isFull, then the dropdown won't be open and [tab] will work normally\n\n\t            preventDefault(e);\n\t          }\n\n\t          if (self.settings.create && self.createItem()) {\n\t            preventDefault(e);\n\t          }\n\t        }\n\n\t        return;\n\t      // delete|backspace: delete items\n\n\t      case KEY_BACKSPACE:\n\t      case KEY_DELETE:\n\t        self.deleteSelection(e);\n\t        return;\n\t    } // don't enter text in the control_input when active items are selected\n\n\n\t    if (self.isInputHidden && !isKeyDown(KEY_SHORTCUT, e)) {\n\t      preventDefault(e);\n\t    }\n\t  }\n\t  /**\n\t   * Triggered on <input> keyup.\n\t   *\n\t   */\n\n\n\t  onInput(e) {\n\t    var self = this;\n\n\t    if (self.isLocked) {\n\t      return;\n\t    }\n\n\t    var value = self.inputValue();\n\n\t    if (self.lastValue !== value) {\n\t      self.lastValue = value;\n\n\t      if (self.settings.shouldLoad.call(self, value)) {\n\t        self.load(value);\n\t      }\n\n\t      self.refreshOptions();\n\t      self.trigger('type', value);\n\t    }\n\t  }\n\t  /**\n\t   * Triggered when the user rolls over\n\t   * an option in the autocomplete dropdown menu.\n\t   *\n\t   */\n\n\n\t  onOptionHover(evt, option) {\n\t    if (this.ignoreHover) return;\n\t    this.setActiveOption(option, false);\n\t  }\n\t  /**\n\t   * Triggered on <input> focus.\n\t   *\n\t   */\n\n\n\t  onFocus(e) {\n\t    var self = this;\n\t    var wasFocused = self.isFocused;\n\n\t    if (self.isDisabled) {\n\t      self.blur();\n\t      preventDefault(e);\n\t      return;\n\t    }\n\n\t    if (self.ignoreFocus) return;\n\t    self.isFocused = true;\n\t    if (self.settings.preload === 'focus') self.preload();\n\t    if (!wasFocused) self.trigger('focus');\n\n\t    if (!self.activeItems.length) {\n\t      self.showInput();\n\t      self.refreshOptions(!!self.settings.openOnFocus);\n\t    }\n\n\t    self.refreshState();\n\t  }\n\t  /**\n\t   * Triggered on <input> blur.\n\t   *\n\t   */\n\n\n\t  onBlur(e) {\n\t    if (document.hasFocus() === false) return;\n\t    var self = this;\n\t    if (!self.isFocused) return;\n\t    self.isFocused = false;\n\t    self.ignoreFocus = false;\n\n\t    var deactivate = () => {\n\t      self.close();\n\t      self.setActiveItem();\n\t      self.setCaret(self.items.length);\n\t      self.trigger('blur');\n\t    };\n\n\t    if (self.settings.create && self.settings.createOnBlur) {\n\t      self.createItem(null, deactivate);\n\t    } else {\n\t      deactivate();\n\t    }\n\t  }\n\t  /**\n\t   * Triggered when the user clicks on an option\n\t   * in the autocomplete dropdown menu.\n\t   *\n\t   */\n\n\n\t  onOptionSelect(evt, option) {\n\t    var value,\n\t        self = this; // should not be possible to trigger a option under a disabled optgroup\n\n\t    if (option.parentElement && option.parentElement.matches('[data-disabled]')) {\n\t      return;\n\t    }\n\n\t    if (option.classList.contains('create')) {\n\t      self.createItem(null, () => {\n\t        if (self.settings.closeAfterSelect) {\n\t          self.close();\n\t        }\n\t      });\n\t    } else {\n\t      value = option.dataset.value;\n\n\t      if (typeof value !== 'undefined') {\n\t        self.lastQuery = null;\n\t        self.addItem(value);\n\n\t        if (self.settings.closeAfterSelect) {\n\t          self.close();\n\t        }\n\n\t        if (!self.settings.hideSelected && evt.type && /click/.test(evt.type)) {\n\t          self.setActiveOption(option);\n\t        }\n\t      }\n\t    }\n\t  }\n\t  /**\n\t   * Return true if the given option can be selected\n\t   *\n\t   */\n\n\n\t  canSelect(option) {\n\t    if (this.isOpen && option && this.dropdown_content.contains(option)) {\n\t      return true;\n\t    }\n\n\t    return false;\n\t  }\n\t  /**\n\t   * Triggered when the user clicks on an item\n\t   * that has been selected.\n\t   *\n\t   */\n\n\n\t  onItemSelect(evt, item) {\n\t    var self = this;\n\n\t    if (!self.isLocked && self.settings.mode === 'multi') {\n\t      preventDefault(evt);\n\t      self.setActiveItem(item, evt);\n\t      return true;\n\t    }\n\n\t    return false;\n\t  }\n\t  /**\n\t   * Determines whether or not to invoke\n\t   * the user-provided option provider / loader\n\t   *\n\t   * Note, there is a subtle difference between\n\t   * this.canLoad() and this.settings.shouldLoad();\n\t   *\n\t   *\t- settings.shouldLoad() is a user-input validator.\n\t   *\tWhen false is returned, the not_loading template\n\t   *\twill be added to the dropdown\n\t   *\n\t   *\t- canLoad() is lower level validator that checks\n\t   * \tthe Tom Select instance. There is no inherent user\n\t   *\tfeedback when canLoad returns false\n\t   *\n\t   */\n\n\n\t  canLoad(value) {\n\t    if (!this.settings.load) return false;\n\t    if (this.loadedSearches.hasOwnProperty(value)) return false;\n\t    return true;\n\t  }\n\t  /**\n\t   * Invokes the user-provided option provider / loader.\n\t   *\n\t   */\n\n\n\t  load(value) {\n\t    const self = this;\n\t    if (!self.canLoad(value)) return;\n\t    addClasses(self.wrapper, self.settings.loadingClass);\n\t    self.loading++;\n\t    const callback = self.loadCallback.bind(self);\n\t    self.settings.load.call(self, value, callback);\n\t  }\n\t  /**\n\t   * Invoked by the user-provided option provider\n\t   *\n\t   */\n\n\n\t  loadCallback(options, optgroups) {\n\t    const self = this;\n\t    self.loading = Math.max(self.loading - 1, 0);\n\t    self.lastQuery = null;\n\t    self.clearActiveOption(); // when new results load, focus should be on first option\n\n\t    self.setupOptions(options, optgroups);\n\t    self.refreshOptions(self.isFocused && !self.isInputHidden);\n\n\t    if (!self.loading) {\n\t      removeClasses(self.wrapper, self.settings.loadingClass);\n\t    }\n\n\t    self.trigger('load', options, optgroups);\n\t  }\n\n\t  preload() {\n\t    var classList = this.wrapper.classList;\n\t    if (classList.contains('preloaded')) return;\n\t    classList.add('preloaded');\n\t    this.load('');\n\t  }\n\t  /**\n\t   * Sets the input field of the control to the specified value.\n\t   *\n\t   */\n\n\n\t  setTextboxValue(value = '') {\n\t    var input = this.control_input;\n\t    var changed = input.value !== value;\n\n\t    if (changed) {\n\t      input.value = value;\n\t      triggerEvent(input, 'update');\n\t      this.lastValue = value;\n\t    }\n\t  }\n\t  /**\n\t   * Returns the value of the control. If multiple items\n\t   * can be selected (e.g. <select multiple>), this returns\n\t   * an array. If only one item can be selected, this\n\t   * returns a string.\n\t   *\n\t   */\n\n\n\t  getValue() {\n\t    if (this.is_select_tag && this.input.hasAttribute('multiple')) {\n\t      return this.items;\n\t    }\n\n\t    return this.items.join(this.settings.delimiter);\n\t  }\n\t  /**\n\t   * Resets the selected items to the given value.\n\t   *\n\t   */\n\n\n\t  setValue(value, silent) {\n\t    var events = silent ? [] : ['change'];\n\t    debounce_events(this, events, () => {\n\t      this.clear(silent);\n\t      this.addItems(value, silent);\n\t    });\n\t  }\n\t  /**\n\t   * Resets the number of max items to the given value\n\t   *\n\t   */\n\n\n\t  setMaxItems(value) {\n\t    if (value === 0) value = null; //reset to unlimited items.\n\n\t    this.settings.maxItems = value;\n\t    this.refreshState();\n\t  }\n\t  /**\n\t   * Sets the selected item.\n\t   *\n\t   */\n\n\n\t  setActiveItem(item, e) {\n\t    var self = this;\n\t    var eventName;\n\t    var i, begin, end, swap;\n\t    var last;\n\t    if (self.settings.mode === 'single') return; // clear the active selection\n\n\t    if (!item) {\n\t      self.clearActiveItems();\n\n\t      if (self.isFocused) {\n\t        self.showInput();\n\t      }\n\n\t      return;\n\t    } // modify selection\n\n\n\t    eventName = e && e.type.toLowerCase();\n\n\t    if (eventName === 'click' && isKeyDown('shiftKey', e) && self.activeItems.length) {\n\t      last = self.getLastActive();\n\t      begin = Array.prototype.indexOf.call(self.control.children, last);\n\t      end = Array.prototype.indexOf.call(self.control.children, item);\n\n\t      if (begin > end) {\n\t        swap = begin;\n\t        begin = end;\n\t        end = swap;\n\t      }\n\n\t      for (i = begin; i <= end; i++) {\n\t        item = self.control.children[i];\n\n\t        if (self.activeItems.indexOf(item) === -1) {\n\t          self.setActiveItemClass(item);\n\t        }\n\t      }\n\n\t      preventDefault(e);\n\t    } else if (eventName === 'click' && isKeyDown(KEY_SHORTCUT, e) || eventName === 'keydown' && isKeyDown('shiftKey', e)) {\n\t      if (item.classList.contains('active')) {\n\t        self.removeActiveItem(item);\n\t      } else {\n\t        self.setActiveItemClass(item);\n\t      }\n\t    } else {\n\t      self.clearActiveItems();\n\t      self.setActiveItemClass(item);\n\t    } // ensure control has focus\n\n\n\t    self.hideInput();\n\n\t    if (!self.isFocused) {\n\t      self.focus();\n\t    }\n\t  }\n\t  /**\n\t   * Set the active and last-active classes\n\t   *\n\t   */\n\n\n\t  setActiveItemClass(item) {\n\t    const self = this;\n\t    const last_active = self.control.querySelector('.last-active');\n\t    if (last_active) removeClasses(last_active, 'last-active');\n\t    addClasses(item, 'active last-active');\n\t    self.trigger('item_select', item);\n\n\t    if (self.activeItems.indexOf(item) == -1) {\n\t      self.activeItems.push(item);\n\t    }\n\t  }\n\t  /**\n\t   * Remove active item\n\t   *\n\t   */\n\n\n\t  removeActiveItem(item) {\n\t    var idx = this.activeItems.indexOf(item);\n\t    this.activeItems.splice(idx, 1);\n\t    removeClasses(item, 'active');\n\t  }\n\t  /**\n\t   * Clears all the active items\n\t   *\n\t   */\n\n\n\t  clearActiveItems() {\n\t    removeClasses(this.activeItems, 'active');\n\t    this.activeItems = [];\n\t  }\n\t  /**\n\t   * Sets the selected item in the dropdown menu\n\t   * of available options.\n\t   *\n\t   */\n\n\n\t  setActiveOption(option, scroll = true) {\n\t    if (option === this.activeOption) {\n\t      return;\n\t    }\n\n\t    this.clearActiveOption();\n\t    if (!option) return;\n\t    this.activeOption = option;\n\t    setAttr(this.focus_node, {\n\t      'aria-activedescendant': option.getAttribute('id')\n\t    });\n\t    setAttr(option, {\n\t      'aria-selected': 'true'\n\t    });\n\t    addClasses(option, 'active');\n\t    if (scroll) this.scrollToOption(option);\n\t  }\n\t  /**\n\t   * Sets the dropdown_content scrollTop to display the option\n\t   *\n\t   */\n\n\n\t  scrollToOption(option, behavior) {\n\t    if (!option) return;\n\t    const content = this.dropdown_content;\n\t    const height_menu = content.clientHeight;\n\t    const scrollTop = content.scrollTop || 0;\n\t    const height_item = option.offsetHeight;\n\t    const y = option.getBoundingClientRect().top - content.getBoundingClientRect().top + scrollTop;\n\n\t    if (y + height_item > height_menu + scrollTop) {\n\t      this.scroll(y - height_menu + height_item, behavior);\n\t    } else if (y < scrollTop) {\n\t      this.scroll(y, behavior);\n\t    }\n\t  }\n\t  /**\n\t   * Scroll the dropdown to the given position\n\t   *\n\t   */\n\n\n\t  scroll(scrollTop, behavior) {\n\t    const content = this.dropdown_content;\n\n\t    if (behavior) {\n\t      content.style.scrollBehavior = behavior;\n\t    }\n\n\t    content.scrollTop = scrollTop;\n\t    content.style.scrollBehavior = '';\n\t  }\n\t  /**\n\t   * Clears the active option\n\t   *\n\t   */\n\n\n\t  clearActiveOption() {\n\t    if (this.activeOption) {\n\t      removeClasses(this.activeOption, 'active');\n\t      setAttr(this.activeOption, {\n\t        'aria-selected': null\n\t      });\n\t    }\n\n\t    this.activeOption = null;\n\t    setAttr(this.focus_node, {\n\t      'aria-activedescendant': null\n\t    });\n\t  }\n\t  /**\n\t   * Selects all items (CTRL + A).\n\t   */\n\n\n\t  selectAll() {\n\t    const self = this;\n\t    if (self.settings.mode === 'single') return;\n\t    const activeItems = self.controlChildren();\n\t    if (!activeItems.length) return;\n\t    self.hideInput();\n\t    self.close();\n\t    self.activeItems = activeItems;\n\t    iterate$1(activeItems, item => {\n\t      self.setActiveItemClass(item);\n\t    });\n\t  }\n\t  /**\n\t   * Determines if the control_input should be in a hidden or visible state\n\t   *\n\t   */\n\n\n\t  inputState() {\n\t    var self = this;\n\t    if (!self.control.contains(self.control_input)) return;\n\t    setAttr(self.control_input, {\n\t      placeholder: self.settings.placeholder\n\t    });\n\n\t    if (self.activeItems.length > 0 || !self.isFocused && self.settings.hidePlaceholder && self.items.length > 0) {\n\t      self.setTextboxValue();\n\t      self.isInputHidden = true;\n\t    } else {\n\t      if (self.settings.hidePlaceholder && self.items.length > 0) {\n\t        setAttr(self.control_input, {\n\t          placeholder: ''\n\t        });\n\t      }\n\n\t      self.isInputHidden = false;\n\t    }\n\n\t    self.wrapper.classList.toggle('input-hidden', self.isInputHidden);\n\t  }\n\t  /**\n\t   * Hides the input element out of view, while\n\t   * retaining its focus.\n\t   * @deprecated 1.3\n\t   */\n\n\n\t  hideInput() {\n\t    this.inputState();\n\t  }\n\t  /**\n\t   * Restores input visibility.\n\t   * @deprecated 1.3\n\t   */\n\n\n\t  showInput() {\n\t    this.inputState();\n\t  }\n\t  /**\n\t   * Get the input value\n\t   */\n\n\n\t  inputValue() {\n\t    return this.control_input.value.trim();\n\t  }\n\t  /**\n\t   * Gives the control focus.\n\t   */\n\n\n\t  focus() {\n\t    var self = this;\n\t    if (self.isDisabled) return;\n\t    self.ignoreFocus = true;\n\n\t    if (self.control_input.offsetWidth) {\n\t      self.control_input.focus();\n\t    } else {\n\t      self.focus_node.focus();\n\t    }\n\n\t    setTimeout(() => {\n\t      self.ignoreFocus = false;\n\t      self.onFocus();\n\t    }, 0);\n\t  }\n\t  /**\n\t   * Forces the control out of focus.\n\t   *\n\t   */\n\n\n\t  blur() {\n\t    this.focus_node.blur();\n\t    this.onBlur();\n\t  }\n\t  /**\n\t   * Returns a function that scores an object\n\t   * to show how good of a match it is to the\n\t   * provided query.\n\t   *\n\t   * @return {function}\n\t   */\n\n\n\t  getScoreFunction(query) {\n\t    return this.sifter.getScoreFunction(query, this.getSearchOptions());\n\t  }\n\t  /**\n\t   * Returns search options for sifter (the system\n\t   * for scoring and sorting results).\n\t   *\n\t   * @see https://github.com/orchidjs/sifter.js\n\t   * @return {object}\n\t   */\n\n\n\t  getSearchOptions() {\n\t    var settings = this.settings;\n\t    var sort = settings.sortField;\n\n\t    if (typeof settings.sortField === 'string') {\n\t      sort = [{\n\t        field: settings.sortField\n\t      }];\n\t    }\n\n\t    return {\n\t      fields: settings.searchField,\n\t      conjunction: settings.searchConjunction,\n\t      sort: sort,\n\t      nesting: settings.nesting\n\t    };\n\t  }\n\t  /**\n\t   * Searches through available options and returns\n\t   * a sorted array of matches.\n\t   *\n\t   */\n\n\n\t  search(query) {\n\t    var result, calculateScore;\n\t    var self = this;\n\t    var options = this.getSearchOptions(); // validate user-provided result scoring function\n\n\t    if (self.settings.score) {\n\t      calculateScore = self.settings.score.call(self, query);\n\n\t      if (typeof calculateScore !== 'function') {\n\t        throw new Error('Tom Select \"score\" setting must be a function that returns a function');\n\t      }\n\t    } // perform search\n\n\n\t    if (query !== self.lastQuery) {\n\t      self.lastQuery = query;\n\t      result = self.sifter.search(query, Object.assign(options, {\n\t        score: calculateScore\n\t      }));\n\t      self.currentResults = result;\n\t    } else {\n\t      result = Object.assign({}, self.currentResults);\n\t    } // filter out selected items\n\n\n\t    if (self.settings.hideSelected) {\n\t      result.items = result.items.filter(item => {\n\t        let hashed = hash_key(item.id);\n\t        return !(hashed && self.items.indexOf(hashed) !== -1);\n\t      });\n\t    }\n\n\t    return result;\n\t  }\n\t  /**\n\t   * Refreshes the list of available options shown\n\t   * in the autocomplete dropdown menu.\n\t   *\n\t   */\n\n\n\t  refreshOptions(triggerDropdown = true) {\n\t    var i, j, k, n, optgroup, optgroups, html, has_create_option, active_group;\n\t    var create;\n\t    const groups = {};\n\t    const groups_order = [];\n\t    var self = this;\n\t    var query = self.inputValue();\n\t    const same_query = query === self.lastQuery || query == '' && self.lastQuery == null;\n\t    var results = self.search(query);\n\t    var active_option = null;\n\t    var show_dropdown = self.settings.shouldOpen || false;\n\t    var dropdown_content = self.dropdown_content;\n\n\t    if (same_query) {\n\t      active_option = self.activeOption;\n\n\t      if (active_option) {\n\t        active_group = active_option.closest('[data-group]');\n\t      }\n\t    } // build markup\n\n\n\t    n = results.items.length;\n\n\t    if (typeof self.settings.maxOptions === 'number') {\n\t      n = Math.min(n, self.settings.maxOptions);\n\t    }\n\n\t    if (n > 0) {\n\t      show_dropdown = true;\n\t    } // render and group available options individually\n\n\n\t    for (i = 0; i < n; i++) {\n\t      // get option dom element\n\t      let item = results.items[i];\n\t      if (!item) continue;\n\t      let opt_value = item.id;\n\t      let option = self.options[opt_value];\n\t      if (option === undefined) continue;\n\t      let opt_hash = get_hash(opt_value);\n\t      let option_el = self.getOption(opt_hash, true); // toggle 'selected' class\n\n\t      if (!self.settings.hideSelected) {\n\t        option_el.classList.toggle('selected', self.items.includes(opt_hash));\n\t      }\n\n\t      optgroup = option[self.settings.optgroupField] || '';\n\t      optgroups = Array.isArray(optgroup) ? optgroup : [optgroup];\n\n\t      for (j = 0, k = optgroups && optgroups.length; j < k; j++) {\n\t        optgroup = optgroups[j];\n\n\t        if (!self.optgroups.hasOwnProperty(optgroup)) {\n\t          optgroup = '';\n\t        }\n\n\t        let group_fragment = groups[optgroup];\n\n\t        if (group_fragment === undefined) {\n\t          group_fragment = document.createDocumentFragment();\n\t          groups_order.push(optgroup);\n\t        } // nodes can only have one parent, so if the option is in mutple groups, we need a clone\n\n\n\t        if (j > 0) {\n\t          option_el = option_el.cloneNode(true);\n\t          setAttr(option_el, {\n\t            id: option.$id + '-clone-' + j,\n\t            'aria-selected': null\n\t          });\n\t          option_el.classList.add('ts-cloned');\n\t          removeClasses(option_el, 'active'); // make sure we keep the activeOption in the same group\n\n\t          if (self.activeOption && self.activeOption.dataset.value == opt_value) {\n\t            if (active_group && active_group.dataset.group === optgroup.toString()) {\n\t              active_option = option_el;\n\t            }\n\t          }\n\t        }\n\n\t        group_fragment.appendChild(option_el);\n\t        groups[optgroup] = group_fragment;\n\t      }\n\t    } // sort optgroups\n\n\n\t    if (self.settings.lockOptgroupOrder) {\n\t      groups_order.sort((a, b) => {\n\t        const grp_a = self.optgroups[a];\n\t        const grp_b = self.optgroups[b];\n\t        const a_order = grp_a && grp_a.$order || 0;\n\t        const b_order = grp_b && grp_b.$order || 0;\n\t        return a_order - b_order;\n\t      });\n\t    } // render optgroup headers & join groups\n\n\n\t    html = document.createDocumentFragment();\n\t    iterate$1(groups_order, optgroup => {\n\t      let group_fragment = groups[optgroup];\n\t      if (!group_fragment || !group_fragment.children.length) return;\n\t      let group_heading = self.optgroups[optgroup];\n\n\t      if (group_heading !== undefined) {\n\t        let group_options = document.createDocumentFragment();\n\t        let header = self.render('optgroup_header', group_heading);\n\t        append(group_options, header);\n\t        append(group_options, group_fragment);\n\t        let group_html = self.render('optgroup', {\n\t          group: group_heading,\n\t          options: group_options\n\t        });\n\t        append(html, group_html);\n\t      } else {\n\t        append(html, group_fragment);\n\t      }\n\t    });\n\t    dropdown_content.innerHTML = '';\n\t    append(dropdown_content, html); // highlight matching terms inline\n\n\t    if (self.settings.highlight) {\n\t      removeHighlight(dropdown_content);\n\n\t      if (results.query.length && results.tokens.length) {\n\t        iterate$1(results.tokens, tok => {\n\t          highlight(dropdown_content, tok.regex);\n\t        });\n\t      }\n\t    } // helper method for adding templates to dropdown\n\n\n\t    var add_template = template => {\n\t      let content = self.render(template, {\n\t        input: query\n\t      });\n\n\t      if (content) {\n\t        show_dropdown = true;\n\t        dropdown_content.insertBefore(content, dropdown_content.firstChild);\n\t      }\n\n\t      return content;\n\t    }; // add loading message\n\n\n\t    if (self.loading) {\n\t      add_template('loading'); // invalid query\n\t    } else if (!self.settings.shouldLoad.call(self, query)) {\n\t      add_template('not_loading'); // add no_results message\n\t    } else if (results.items.length === 0) {\n\t      add_template('no_results');\n\t    } // add create option\n\n\n\t    has_create_option = self.canCreate(query);\n\n\t    if (has_create_option) {\n\t      create = add_template('option_create');\n\t    } // activate\n\n\n\t    self.hasOptions = results.items.length > 0 || has_create_option;\n\n\t    if (show_dropdown) {\n\t      if (results.items.length > 0) {\n\t        if (!active_option && self.settings.mode === 'single' && self.items[0] != undefined) {\n\t          active_option = self.getOption(self.items[0]);\n\t        }\n\n\t        if (!dropdown_content.contains(active_option)) {\n\t          let active_index = 0;\n\n\t          if (create && !self.settings.addPrecedence) {\n\t            active_index = 1;\n\t          }\n\n\t          active_option = self.selectable()[active_index];\n\t        }\n\t      } else if (create) {\n\t        active_option = create;\n\t      }\n\n\t      if (triggerDropdown && !self.isOpen) {\n\t        self.open();\n\t        self.scrollToOption(active_option, 'auto');\n\t      }\n\n\t      self.setActiveOption(active_option);\n\t    } else {\n\t      self.clearActiveOption();\n\n\t      if (triggerDropdown && self.isOpen) {\n\t        self.close(false); // if create_option=null, we want the dropdown to close but not reset the textbox value\n\t      }\n\t    }\n\t  }\n\t  /**\n\t   * Return list of selectable options\n\t   *\n\t   */\n\n\n\t  selectable() {\n\t    return this.dropdown_content.querySelectorAll('[data-selectable]');\n\t  }\n\t  /**\n\t   * Adds an available option. If it already exists,\n\t   * nothing will happen. Note: this does not refresh\n\t   * the options list dropdown (use `refreshOptions`\n\t   * for that).\n\t   *\n\t   * Usage:\n\t   *\n\t   *   this.addOption(data)\n\t   *\n\t   */\n\n\n\t  addOption(data, user_created = false) {\n\t    const self = this; // @deprecated 1.7.7\n\t    // use addOptions( array, user_created ) for adding multiple options\n\n\t    if (Array.isArray(data)) {\n\t      self.addOptions(data, user_created);\n\t      return false;\n\t    }\n\n\t    const key = hash_key(data[self.settings.valueField]);\n\n\t    if (key === null || self.options.hasOwnProperty(key)) {\n\t      return false;\n\t    }\n\n\t    data.$order = data.$order || ++self.order;\n\t    data.$id = self.inputId + '-opt-' + data.$order;\n\t    self.options[key] = data;\n\t    self.lastQuery = null;\n\n\t    if (user_created) {\n\t      self.userOptions[key] = user_created;\n\t      self.trigger('option_add', key, data);\n\t    }\n\n\t    return key;\n\t  }\n\t  /**\n\t   * Add multiple options\n\t   *\n\t   */\n\n\n\t  addOptions(data, user_created = false) {\n\t    iterate$1(data, dat => {\n\t      this.addOption(dat, user_created);\n\t    });\n\t  }\n\t  /**\n\t   * @deprecated 1.7.7\n\t   */\n\n\n\t  registerOption(data) {\n\t    return this.addOption(data);\n\t  }\n\t  /**\n\t   * Registers an option group to the pool of option groups.\n\t   *\n\t   * @return {boolean|string}\n\t   */\n\n\n\t  registerOptionGroup(data) {\n\t    var key = hash_key(data[this.settings.optgroupValueField]);\n\t    if (key === null) return false;\n\t    data.$order = data.$order || ++this.order;\n\t    this.optgroups[key] = data;\n\t    return key;\n\t  }\n\t  /**\n\t   * Registers a new optgroup for options\n\t   * to be bucketed into.\n\t   *\n\t   */\n\n\n\t  addOptionGroup(id, data) {\n\t    var hashed_id;\n\t    data[this.settings.optgroupValueField] = id;\n\n\t    if (hashed_id = this.registerOptionGroup(data)) {\n\t      this.trigger('optgroup_add', hashed_id, data);\n\t    }\n\t  }\n\t  /**\n\t   * Removes an existing option group.\n\t   *\n\t   */\n\n\n\t  removeOptionGroup(id) {\n\t    if (this.optgroups.hasOwnProperty(id)) {\n\t      delete this.optgroups[id];\n\t      this.clearCache();\n\t      this.trigger('optgroup_remove', id);\n\t    }\n\t  }\n\t  /**\n\t   * Clears all existing option groups.\n\t   */\n\n\n\t  clearOptionGroups() {\n\t    this.optgroups = {};\n\t    this.clearCache();\n\t    this.trigger('optgroup_clear');\n\t  }\n\t  /**\n\t   * Updates an option available for selection. If\n\t   * it is visible in the selected items or options\n\t   * dropdown, it will be re-rendered automatically.\n\t   *\n\t   */\n\n\n\t  updateOption(value, data) {\n\t    const self = this;\n\t    var item_new;\n\t    var index_item;\n\t    const value_old = hash_key(value);\n\t    const value_new = hash_key(data[self.settings.valueField]); // sanity checks\n\n\t    if (value_old === null) return;\n\t    const data_old = self.options[value_old];\n\t    if (data_old == undefined) return;\n\t    if (typeof value_new !== 'string') throw new Error('Value must be set in option data');\n\t    const option = self.getOption(value_old);\n\t    const item = self.getItem(value_old);\n\t    data.$order = data.$order || data_old.$order;\n\t    delete self.options[value_old]; // invalidate render cache\n\t    // don't remove existing node yet, we'll remove it after replacing it\n\n\t    self.uncacheValue(value_new);\n\t    self.options[value_new] = data; // update the option if it's in the dropdown\n\n\t    if (option) {\n\t      if (self.dropdown_content.contains(option)) {\n\t        const option_new = self._render('option', data);\n\n\t        replaceNode(option, option_new);\n\n\t        if (self.activeOption === option) {\n\t          self.setActiveOption(option_new);\n\t        }\n\t      }\n\n\t      option.remove();\n\t    } // update the item if we have one\n\n\n\t    if (item) {\n\t      index_item = self.items.indexOf(value_old);\n\n\t      if (index_item !== -1) {\n\t        self.items.splice(index_item, 1, value_new);\n\t      }\n\n\t      item_new = self._render('item', data);\n\t      if (item.classList.contains('active')) addClasses(item_new, 'active');\n\t      replaceNode(item, item_new);\n\t    } // invalidate last query because we might have updated the sortField\n\n\n\t    self.lastQuery = null;\n\t  }\n\t  /**\n\t   * Removes a single option.\n\t   *\n\t   */\n\n\n\t  removeOption(value, silent) {\n\t    const self = this;\n\t    value = get_hash(value);\n\t    self.uncacheValue(value);\n\t    delete self.userOptions[value];\n\t    delete self.options[value];\n\t    self.lastQuery = null;\n\t    self.trigger('option_remove', value);\n\t    self.removeItem(value, silent);\n\t  }\n\t  /**\n\t   * Clears all options.\n\t   */\n\n\n\t  clearOptions(filter) {\n\t    const boundFilter = (filter || this.clearFilter).bind(this);\n\t    this.loadedSearches = {};\n\t    this.userOptions = {};\n\t    this.clearCache();\n\t    const selected = {};\n\t    iterate$1(this.options, (option, key) => {\n\t      if (boundFilter(option, key)) {\n\t        selected[key] = option;\n\t      }\n\t    });\n\t    this.options = this.sifter.items = selected;\n\t    this.lastQuery = null;\n\t    this.trigger('option_clear');\n\t  }\n\t  /**\n\t   * Used by clearOptions() to decide whether or not an option should be removed\n\t   * Return true to keep an option, false to remove\n\t   *\n\t   */\n\n\n\t  clearFilter(option, value) {\n\t    if (this.items.indexOf(value) >= 0) {\n\t      return true;\n\t    }\n\n\t    return false;\n\t  }\n\t  /**\n\t   * Returns the dom element of the option\n\t   * matching the given value.\n\t   *\n\t   */\n\n\n\t  getOption(value, create = false) {\n\t    const hashed = hash_key(value);\n\t    if (hashed === null) return null;\n\t    const option = this.options[hashed];\n\n\t    if (option != undefined) {\n\t      if (option.$div) {\n\t        return option.$div;\n\t      }\n\n\t      if (create) {\n\t        return this._render('option', option);\n\t      }\n\t    }\n\n\t    return null;\n\t  }\n\t  /**\n\t   * Returns the dom element of the next or previous dom element of the same type\n\t   * Note: adjacent options may not be adjacent DOM elements (optgroups)\n\t   *\n\t   */\n\n\n\t  getAdjacent(option, direction, type = 'option') {\n\t    var self = this,\n\t        all;\n\n\t    if (!option) {\n\t      return null;\n\t    }\n\n\t    if (type == 'item') {\n\t      all = self.controlChildren();\n\t    } else {\n\t      all = self.dropdown_content.querySelectorAll('[data-selectable]');\n\t    }\n\n\t    for (let i = 0; i < all.length; i++) {\n\t      if (all[i] != option) {\n\t        continue;\n\t      }\n\n\t      if (direction > 0) {\n\t        return all[i + 1];\n\t      }\n\n\t      return all[i - 1];\n\t    }\n\n\t    return null;\n\t  }\n\t  /**\n\t   * Returns the dom element of the item\n\t   * matching the given value.\n\t   *\n\t   */\n\n\n\t  getItem(item) {\n\t    if (typeof item == 'object') {\n\t      return item;\n\t    }\n\n\t    var value = hash_key(item);\n\t    return value !== null ? this.control.querySelector(`[data-value=\"${addSlashes(value)}\"]`) : null;\n\t  }\n\t  /**\n\t   * \"Selects\" multiple items at once. Adds them to the list\n\t   * at the current caret position.\n\t   *\n\t   */\n\n\n\t  addItems(values, silent) {\n\t    var self = this;\n\t    var items = Array.isArray(values) ? values : [values];\n\t    items = items.filter(x => self.items.indexOf(x) === -1);\n\t    const last_item = items[items.length - 1];\n\t    items.forEach(item => {\n\t      self.isPending = item !== last_item;\n\t      self.addItem(item, silent);\n\t    });\n\t  }\n\t  /**\n\t   * \"Selects\" an item. Adds it to the list\n\t   * at the current caret position.\n\t   *\n\t   */\n\n\n\t  addItem(value, silent) {\n\t    var events = silent ? [] : ['change', 'dropdown_close'];\n\t    debounce_events(this, events, () => {\n\t      var item, wasFull;\n\t      const self = this;\n\t      const inputMode = self.settings.mode;\n\t      const hashed = hash_key(value);\n\n\t      if (hashed && self.items.indexOf(hashed) !== -1) {\n\t        if (inputMode === 'single') {\n\t          self.close();\n\t        }\n\n\t        if (inputMode === 'single' || !self.settings.duplicates) {\n\t          return;\n\t        }\n\t      }\n\n\t      if (hashed === null || !self.options.hasOwnProperty(hashed)) return;\n\t      if (inputMode === 'single') self.clear(silent);\n\t      if (inputMode === 'multi' && self.isFull()) return;\n\t      item = self._render('item', self.options[hashed]);\n\n\t      if (self.control.contains(item)) {\n\t        // duplicates\n\t        item = item.cloneNode(true);\n\t      }\n\n\t      wasFull = self.isFull();\n\t      self.items.splice(self.caretPos, 0, hashed);\n\t      self.insertAtCaret(item);\n\n\t      if (self.isSetup) {\n\t        // update menu / remove the option (if this is not one item being added as part of series)\n\t        if (!self.isPending && self.settings.hideSelected) {\n\t          let option = self.getOption(hashed);\n\t          let next = self.getAdjacent(option, 1);\n\n\t          if (next) {\n\t            self.setActiveOption(next);\n\t          }\n\t        } // refreshOptions after setActiveOption(),\n\t        // otherwise setActiveOption() will be called by refreshOptions() with the wrong value\n\n\n\t        if (!self.isPending && !self.settings.closeAfterSelect) {\n\t          self.refreshOptions(self.isFocused && inputMode !== 'single');\n\t        } // hide the menu if the maximum number of items have been selected or no options are left\n\n\n\t        if (self.settings.closeAfterSelect != false && self.isFull()) {\n\t          self.close();\n\t        } else if (!self.isPending) {\n\t          self.positionDropdown();\n\t        }\n\n\t        self.trigger('item_add', hashed, item);\n\n\t        if (!self.isPending) {\n\t          self.updateOriginalInput({\n\t            silent: silent\n\t          });\n\t        }\n\t      }\n\n\t      if (!self.isPending || !wasFull && self.isFull()) {\n\t        self.inputState();\n\t        self.refreshState();\n\t      }\n\t    });\n\t  }\n\t  /**\n\t   * Removes the selected item matching\n\t   * the provided value.\n\t   *\n\t   */\n\n\n\t  removeItem(item = null, silent) {\n\t    const self = this;\n\t    item = self.getItem(item);\n\t    if (!item) return;\n\t    var i, idx;\n\t    const value = item.dataset.value;\n\t    i = nodeIndex(item);\n\t    item.remove();\n\n\t    if (item.classList.contains('active')) {\n\t      idx = self.activeItems.indexOf(item);\n\t      self.activeItems.splice(idx, 1);\n\t      removeClasses(item, 'active');\n\t    }\n\n\t    self.items.splice(i, 1);\n\t    self.lastQuery = null;\n\n\t    if (!self.settings.persist && self.userOptions.hasOwnProperty(value)) {\n\t      self.removeOption(value, silent);\n\t    }\n\n\t    if (i < self.caretPos) {\n\t      self.setCaret(self.caretPos - 1);\n\t    }\n\n\t    self.updateOriginalInput({\n\t      silent: silent\n\t    });\n\t    self.refreshState();\n\t    self.positionDropdown();\n\t    self.trigger('item_remove', value, item);\n\t  }\n\t  /**\n\t   * Invokes the `create` method provided in the\n\t   * TomSelect options that should provide the data\n\t   * for the new item, given the user input.\n\t   *\n\t   * Once this completes, it will be added\n\t   * to the item list.\n\t   *\n\t   */\n\n\n\t  createItem(input = null, callback = () => {}) {\n\t    // triggerDropdown parameter @deprecated 2.1.1\n\t    if (arguments.length === 3) {\n\t      callback = arguments[2];\n\t    }\n\n\t    if (typeof callback != 'function') {\n\t      callback = () => {};\n\t    }\n\n\t    var self = this;\n\t    var caret = self.caretPos;\n\t    var output;\n\t    input = input || self.inputValue();\n\n\t    if (!self.canCreate(input)) {\n\t      callback();\n\t      return false;\n\t    }\n\n\t    self.lock();\n\t    var created = false;\n\n\t    var create = data => {\n\t      self.unlock();\n\t      if (!data || typeof data !== 'object') return callback();\n\t      var value = hash_key(data[self.settings.valueField]);\n\n\t      if (typeof value !== 'string') {\n\t        return callback();\n\t      }\n\n\t      self.setTextboxValue();\n\t      self.addOption(data, true);\n\t      self.setCaret(caret);\n\t      self.addItem(value);\n\t      callback(data);\n\t      created = true;\n\t    };\n\n\t    if (typeof self.settings.create === 'function') {\n\t      output = self.settings.create.call(this, input, create);\n\t    } else {\n\t      output = {\n\t        [self.settings.labelField]: input,\n\t        [self.settings.valueField]: input\n\t      };\n\t    }\n\n\t    if (!created) {\n\t      create(output);\n\t    }\n\n\t    return true;\n\t  }\n\t  /**\n\t   * Re-renders the selected item lists.\n\t   */\n\n\n\t  refreshItems() {\n\t    var self = this;\n\t    self.lastQuery = null;\n\n\t    if (self.isSetup) {\n\t      self.addItems(self.items);\n\t    }\n\n\t    self.updateOriginalInput();\n\t    self.refreshState();\n\t  }\n\t  /**\n\t   * Updates all state-dependent attributes\n\t   * and CSS classes.\n\t   */\n\n\n\t  refreshState() {\n\t    const self = this;\n\t    self.refreshValidityState();\n\t    const isFull = self.isFull();\n\t    const isLocked = self.isLocked;\n\t    self.wrapper.classList.toggle('rtl', self.rtl);\n\t    const wrap_classList = self.wrapper.classList;\n\t    wrap_classList.toggle('focus', self.isFocused);\n\t    wrap_classList.toggle('disabled', self.isDisabled);\n\t    wrap_classList.toggle('required', self.isRequired);\n\t    wrap_classList.toggle('invalid', !self.isValid);\n\t    wrap_classList.toggle('locked', isLocked);\n\t    wrap_classList.toggle('full', isFull);\n\t    wrap_classList.toggle('input-active', self.isFocused && !self.isInputHidden);\n\t    wrap_classList.toggle('dropdown-active', self.isOpen);\n\t    wrap_classList.toggle('has-options', isEmptyObject(self.options));\n\t    wrap_classList.toggle('has-items', self.items.length > 0);\n\t  }\n\t  /**\n\t   * Update the `required` attribute of both input and control input.\n\t   *\n\t   * The `required` property needs to be activated on the control input\n\t   * for the error to be displayed at the right place. `required` also\n\t   * needs to be temporarily deactivated on the input since the input is\n\t   * hidden and can't show errors.\n\t   */\n\n\n\t  refreshValidityState() {\n\t    var self = this;\n\n\t    if (!self.input.validity) {\n\t      return;\n\t    }\n\n\t    self.isValid = self.input.validity.valid;\n\t    self.isInvalid = !self.isValid;\n\t  }\n\t  /**\n\t   * Determines whether or not more items can be added\n\t   * to the control without exceeding the user-defined maximum.\n\t   *\n\t   * @returns {boolean}\n\t   */\n\n\n\t  isFull() {\n\t    return this.settings.maxItems !== null && this.items.length >= this.settings.maxItems;\n\t  }\n\t  /**\n\t   * Refreshes the original <select> or <input>\n\t   * element to reflect the current state.\n\t   *\n\t   */\n\n\n\t  updateOriginalInput(opts = {}) {\n\t    const self = this;\n\t    var option, label;\n\t    const empty_option = self.input.querySelector('option[value=\"\"]');\n\n\t    if (self.is_select_tag) {\n\t      const selected = [];\n\t      const has_selected = self.input.querySelectorAll('option:checked').length;\n\n\t      function AddSelected(option_el, value, label) {\n\t        if (!option_el) {\n\t          option_el = getDom('<option value=\"' + escape_html(value) + '\">' + escape_html(label) + '</option>');\n\t        } // don't move empty option from top of list\n\t        // fixes bug in firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1725293\n\n\n\t        if (option_el != empty_option) {\n\t          self.input.append(option_el);\n\t        }\n\n\t        selected.push(option_el); // marking empty option as selected can break validation\n\t        // fixes https://github.com/orchidjs/tom-select/issues/303\n\n\t        if (option_el != empty_option || has_selected > 0) {\n\t          option_el.selected = true;\n\t        }\n\n\t        return option_el;\n\t      } // unselect all selected options\n\n\n\t      self.input.querySelectorAll('option:checked').forEach(option_el => {\n\t        option_el.selected = false;\n\t      }); // nothing selected?\n\n\t      if (self.items.length == 0 && self.settings.mode == 'single') {\n\t        AddSelected(empty_option, \"\", \"\"); // order selected <option> tags for values in self.items\n\t      } else {\n\t        self.items.forEach(value => {\n\t          option = self.options[value];\n\t          label = option[self.settings.labelField] || '';\n\n\t          if (selected.includes(option.$option)) {\n\t            const reuse_opt = self.input.querySelector(`option[value=\"${addSlashes(value)}\"]:not(:checked)`);\n\t            AddSelected(reuse_opt, value, label);\n\t          } else {\n\t            option.$option = AddSelected(option.$option, value, label);\n\t          }\n\t        });\n\t      }\n\t    } else {\n\t      self.input.value = self.getValue();\n\t    }\n\n\t    if (self.isSetup) {\n\t      if (!opts.silent) {\n\t        self.trigger('change', self.getValue());\n\t      }\n\t    }\n\t  }\n\t  /**\n\t   * Shows the autocomplete dropdown containing\n\t   * the available options.\n\t   */\n\n\n\t  open() {\n\t    var self = this;\n\t    if (self.isLocked || self.isOpen || self.settings.mode === 'multi' && self.isFull()) return;\n\t    self.isOpen = true;\n\t    setAttr(self.focus_node, {\n\t      'aria-expanded': 'true'\n\t    });\n\t    self.refreshState();\n\t    applyCSS(self.dropdown, {\n\t      visibility: 'hidden',\n\t      display: 'block'\n\t    });\n\t    self.positionDropdown();\n\t    applyCSS(self.dropdown, {\n\t      visibility: 'visible',\n\t      display: 'block'\n\t    });\n\t    self.focus();\n\t    self.trigger('dropdown_open', self.dropdown);\n\t  }\n\t  /**\n\t   * Closes the autocomplete dropdown menu.\n\t   */\n\n\n\t  close(setTextboxValue = true) {\n\t    var self = this;\n\t    var trigger = self.isOpen;\n\n\t    if (setTextboxValue) {\n\t      // before blur() to prevent form onchange event\n\t      self.setTextboxValue();\n\n\t      if (self.settings.mode === 'single' && self.items.length) {\n\t        self.hideInput();\n\t      }\n\t    }\n\n\t    self.isOpen = false;\n\t    setAttr(self.focus_node, {\n\t      'aria-expanded': 'false'\n\t    });\n\t    applyCSS(self.dropdown, {\n\t      display: 'none'\n\t    });\n\n\t    if (self.settings.hideSelected) {\n\t      self.clearActiveOption();\n\t    }\n\n\t    self.refreshState();\n\t    if (trigger) self.trigger('dropdown_close', self.dropdown);\n\t  }\n\t  /**\n\t   * Calculates and applies the appropriate\n\t   * position of the dropdown if dropdownParent = 'body'.\n\t   * Otherwise, position is determined by css\n\t   */\n\n\n\t  positionDropdown() {\n\t    if (this.settings.dropdownParent !== 'body') {\n\t      return;\n\t    }\n\n\t    var context = this.control;\n\t    var rect = context.getBoundingClientRect();\n\t    var top = context.offsetHeight + rect.top + window.scrollY;\n\t    var left = rect.left + window.scrollX;\n\t    applyCSS(this.dropdown, {\n\t      width: rect.width + 'px',\n\t      top: top + 'px',\n\t      left: left + 'px'\n\t    });\n\t  }\n\t  /**\n\t   * Resets / clears all selected items\n\t   * from the control.\n\t   *\n\t   */\n\n\n\t  clear(silent) {\n\t    var self = this;\n\t    if (!self.items.length) return;\n\t    var items = self.controlChildren();\n\t    iterate$1(items, item => {\n\t      self.removeItem(item, true);\n\t    });\n\t    self.showInput();\n\t    if (!silent) self.updateOriginalInput();\n\t    self.trigger('clear');\n\t  }\n\t  /**\n\t   * A helper method for inserting an element\n\t   * at the current caret position.\n\t   *\n\t   */\n\n\n\t  insertAtCaret(el) {\n\t    const self = this;\n\t    const caret = self.caretPos;\n\t    const target = self.control;\n\t    target.insertBefore(el, target.children[caret] || null);\n\t    self.setCaret(caret + 1);\n\t  }\n\t  /**\n\t   * Removes the current selected item(s).\n\t   *\n\t   */\n\n\n\t  deleteSelection(e) {\n\t    var direction, selection, caret, tail;\n\t    var self = this;\n\t    direction = e && e.keyCode === KEY_BACKSPACE ? -1 : 1;\n\t    selection = getSelection(self.control_input); // determine items that will be removed\n\n\t    const rm_items = [];\n\n\t    if (self.activeItems.length) {\n\t      tail = getTail(self.activeItems, direction);\n\t      caret = nodeIndex(tail);\n\n\t      if (direction > 0) {\n\t        caret++;\n\t      }\n\n\t      iterate$1(self.activeItems, item => rm_items.push(item));\n\t    } else if ((self.isFocused || self.settings.mode === 'single') && self.items.length) {\n\t      const items = self.controlChildren();\n\t      let rm_item;\n\n\t      if (direction < 0 && selection.start === 0 && selection.length === 0) {\n\t        rm_item = items[self.caretPos - 1];\n\t      } else if (direction > 0 && selection.start === self.inputValue().length) {\n\t        rm_item = items[self.caretPos];\n\t      }\n\n\t      if (rm_item !== undefined) {\n\t        rm_items.push(rm_item);\n\t      }\n\t    }\n\n\t    if (!self.shouldDelete(rm_items, e)) {\n\t      return false;\n\t    }\n\n\t    preventDefault(e, true); // perform removal\n\n\t    if (typeof caret !== 'undefined') {\n\t      self.setCaret(caret);\n\t    }\n\n\t    while (rm_items.length) {\n\t      self.removeItem(rm_items.pop());\n\t    }\n\n\t    self.showInput();\n\t    self.positionDropdown();\n\t    self.refreshOptions(false);\n\t    return true;\n\t  }\n\t  /**\n\t   * Return true if the items should be deleted\n\t   */\n\n\n\t  shouldDelete(items, evt) {\n\t    const values = items.map(item => item.dataset.value); // allow the callback to abort\n\n\t    if (!values.length || typeof this.settings.onDelete === 'function' && this.settings.onDelete(values, evt) === false) {\n\t      return false;\n\t    }\n\n\t    return true;\n\t  }\n\t  /**\n\t   * Selects the previous / next item (depending on the `direction` argument).\n\t   *\n\t   * > 0 - right\n\t   * < 0 - left\n\t   *\n\t   */\n\n\n\t  advanceSelection(direction, e) {\n\t    var last_active,\n\t        adjacent,\n\t        self = this;\n\t    if (self.rtl) direction *= -1;\n\t    if (self.inputValue().length) return; // add or remove to active items\n\n\t    if (isKeyDown(KEY_SHORTCUT, e) || isKeyDown('shiftKey', e)) {\n\t      last_active = self.getLastActive(direction);\n\n\t      if (last_active) {\n\t        if (!last_active.classList.contains('active')) {\n\t          adjacent = last_active;\n\t        } else {\n\t          adjacent = self.getAdjacent(last_active, direction, 'item');\n\t        } // if no active item, get items adjacent to the control input\n\n\t      } else if (direction > 0) {\n\t        adjacent = self.control_input.nextElementSibling;\n\t      } else {\n\t        adjacent = self.control_input.previousElementSibling;\n\t      }\n\n\t      if (adjacent) {\n\t        if (adjacent.classList.contains('active')) {\n\t          self.removeActiveItem(last_active);\n\t        }\n\n\t        self.setActiveItemClass(adjacent); // mark as last_active !! after removeActiveItem() on last_active\n\t      } // move caret to the left or right\n\n\t    } else {\n\t      self.moveCaret(direction);\n\t    }\n\t  }\n\n\t  moveCaret(direction) {}\n\t  /**\n\t   * Get the last active item\n\t   *\n\t   */\n\n\n\t  getLastActive(direction) {\n\t    let last_active = this.control.querySelector('.last-active');\n\n\t    if (last_active) {\n\t      return last_active;\n\t    }\n\n\t    var result = this.control.querySelectorAll('.active');\n\n\t    if (result) {\n\t      return getTail(result, direction);\n\t    }\n\t  }\n\t  /**\n\t   * Moves the caret to the specified index.\n\t   *\n\t   * The input must be moved by leaving it in place and moving the\n\t   * siblings, due to the fact that focus cannot be restored once lost\n\t   * on mobile webkit devices\n\t   *\n\t   */\n\n\n\t  setCaret(new_pos) {\n\t    this.caretPos = this.items.length;\n\t  }\n\t  /**\n\t   * Return list of item dom elements\n\t   *\n\t   */\n\n\n\t  controlChildren() {\n\t    return Array.from(this.control.querySelectorAll('[data-ts-item]'));\n\t  }\n\t  /**\n\t   * Disables user input on the control. Used while\n\t   * items are being asynchronously created.\n\t   */\n\n\n\t  lock() {\n\t    this.isLocked = true;\n\t    this.refreshState();\n\t  }\n\t  /**\n\t   * Re-enables user input on the control.\n\t   */\n\n\n\t  unlock() {\n\t    this.isLocked = false;\n\t    this.refreshState();\n\t  }\n\t  /**\n\t   * Disables user input on the control completely.\n\t   * While disabled, it cannot receive focus.\n\t   */\n\n\n\t  disable() {\n\t    var self = this;\n\t    self.input.disabled = true;\n\t    self.control_input.disabled = true;\n\t    self.focus_node.tabIndex = -1;\n\t    self.isDisabled = true;\n\t    this.close();\n\t    self.lock();\n\t  }\n\t  /**\n\t   * Enables the control so that it can respond\n\t   * to focus and user input.\n\t   */\n\n\n\t  enable() {\n\t    var self = this;\n\t    self.input.disabled = false;\n\t    self.control_input.disabled = false;\n\t    self.focus_node.tabIndex = self.tabIndex;\n\t    self.isDisabled = false;\n\t    self.unlock();\n\t  }\n\t  /**\n\t   * Completely destroys the control and\n\t   * unbinds all event listeners so that it can\n\t   * be garbage collected.\n\t   */\n\n\n\t  destroy() {\n\t    var self = this;\n\t    var revertSettings = self.revertSettings;\n\t    self.trigger('destroy');\n\t    self.off();\n\t    self.wrapper.remove();\n\t    self.dropdown.remove();\n\t    self.input.innerHTML = revertSettings.innerHTML;\n\t    self.input.tabIndex = revertSettings.tabIndex;\n\t    removeClasses(self.input, 'tomselected', 'ts-hidden-accessible');\n\n\t    self._destroy();\n\n\t    delete self.input.tomselect;\n\t  }\n\t  /**\n\t   * A helper method for rendering \"item\" and\n\t   * \"option\" templates, given the data.\n\t   *\n\t   */\n\n\n\t  render(templateName, data) {\n\t    var id, html;\n\t    const self = this;\n\n\t    if (typeof this.settings.render[templateName] !== 'function') {\n\t      return null;\n\t    } // render markup\n\n\n\t    html = self.settings.render[templateName].call(this, data, escape_html);\n\n\t    if (!html) {\n\t      return null;\n\t    }\n\n\t    html = getDom(html); // add mandatory attributes\n\n\t    if (templateName === 'option' || templateName === 'option_create') {\n\t      if (data[self.settings.disabledField]) {\n\t        setAttr(html, {\n\t          'aria-disabled': 'true'\n\t        });\n\t      } else {\n\t        setAttr(html, {\n\t          'data-selectable': ''\n\t        });\n\t      }\n\t    } else if (templateName === 'optgroup') {\n\t      id = data.group[self.settings.optgroupValueField];\n\t      setAttr(html, {\n\t        'data-group': id\n\t      });\n\n\t      if (data.group[self.settings.disabledField]) {\n\t        setAttr(html, {\n\t          'data-disabled': ''\n\t        });\n\t      }\n\t    }\n\n\t    if (templateName === 'option' || templateName === 'item') {\n\t      const value = get_hash(data[self.settings.valueField]);\n\t      setAttr(html, {\n\t        'data-value': value\n\t      }); // make sure we have some classes if a template is overwritten\n\n\t      if (templateName === 'item') {\n\t        addClasses(html, self.settings.itemClass);\n\t        setAttr(html, {\n\t          'data-ts-item': ''\n\t        });\n\t      } else {\n\t        addClasses(html, self.settings.optionClass);\n\t        setAttr(html, {\n\t          role: 'option',\n\t          id: data.$id\n\t        }); // update cache\n\n\t        data.$div = html;\n\t        self.options[value] = data;\n\t      }\n\t    }\n\n\t    return html;\n\t  }\n\t  /**\n\t   * Type guarded rendering\n\t   *\n\t   */\n\n\n\t  _render(templateName, data) {\n\t    const html = this.render(templateName, data);\n\n\t    if (html == null) {\n\t      throw 'HTMLElement expected';\n\t    }\n\n\t    return html;\n\t  }\n\t  /**\n\t   * Clears the render cache for a template. If\n\t   * no template is given, clears all render\n\t   * caches.\n\t   *\n\t   */\n\n\n\t  clearCache() {\n\t    iterate$1(this.options, option => {\n\t      if (option.$div) {\n\t        option.$div.remove();\n\t        delete option.$div;\n\t      }\n\t    });\n\t  }\n\t  /**\n\t   * Removes a value from item and option caches\n\t   *\n\t   */\n\n\n\t  uncacheValue(value) {\n\t    const option_el = this.getOption(value);\n\t    if (option_el) option_el.remove();\n\t  }\n\t  /**\n\t   * Determines whether or not to display the\n\t   * create item prompt, given a user input.\n\t   *\n\t   */\n\n\n\t  canCreate(input) {\n\t    return this.settings.create && input.length > 0 && this.settings.createFilter.call(this, input);\n\t  }\n\t  /**\n\t   * Wraps this.`method` so that `new_fn` can be invoked 'before', 'after', or 'instead' of the original method\n\t   *\n\t   * this.hook('instead','onKeyDown',function( arg1, arg2 ...){\n\t   *\n\t   * });\n\t   */\n\n\n\t  hook(when, method, new_fn) {\n\t    var self = this;\n\t    var orig_method = self[method];\n\n\t    self[method] = function () {\n\t      var result, result_new;\n\n\t      if (when === 'after') {\n\t        result = orig_method.apply(self, arguments);\n\t      }\n\n\t      result_new = new_fn.apply(self, arguments);\n\n\t      if (when === 'instead') {\n\t        return result_new;\n\t      }\n\n\t      if (when === 'before') {\n\t        result = orig_method.apply(self, arguments);\n\t      }\n\n\t      return result;\n\t    };\n\t  }\n\n\t}\n\n\t/**\n\t * Plugin: \"change_listener\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction change_listener () {\n\t  addEvent(this.input, 'change', () => {\n\t    this.sync();\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"restore_on_backspace\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction checkbox_options () {\n\t  var self = this;\n\t  var orig_onOptionSelect = self.onOptionSelect;\n\t  self.settings.hideSelected = false; // update the checkbox for an option\n\n\t  var UpdateCheckbox = function UpdateCheckbox(option) {\n\t    setTimeout(() => {\n\t      var checkbox = option.querySelector('input');\n\n\t      if (checkbox instanceof HTMLInputElement) {\n\t        if (option.classList.contains('selected')) {\n\t          checkbox.checked = true;\n\t        } else {\n\t          checkbox.checked = false;\n\t        }\n\t      }\n\t    }, 1);\n\t  }; // add checkbox to option template\n\n\n\t  self.hook('after', 'setupTemplates', () => {\n\t    var orig_render_option = self.settings.render.option;\n\n\t    self.settings.render.option = (data, escape_html) => {\n\t      var rendered = getDom(orig_render_option.call(self, data, escape_html));\n\t      var checkbox = document.createElement('input');\n\t      checkbox.addEventListener('click', function (evt) {\n\t        preventDefault(evt);\n\t      });\n\t      checkbox.type = 'checkbox';\n\t      const hashed = hash_key(data[self.settings.valueField]);\n\n\t      if (hashed && self.items.indexOf(hashed) > -1) {\n\t        checkbox.checked = true;\n\t      }\n\n\t      rendered.prepend(checkbox);\n\t      return rendered;\n\t    };\n\t  }); // uncheck when item removed\n\n\t  self.on('item_remove', value => {\n\t    var option = self.getOption(value);\n\n\t    if (option) {\n\t      // if dropdown hasn't been opened yet, the option won't exist\n\t      option.classList.remove('selected'); // selected class won't be removed yet\n\n\t      UpdateCheckbox(option);\n\t    }\n\t  }); // check when item added\n\n\t  self.on('item_add', value => {\n\t    var option = self.getOption(value);\n\n\t    if (option) {\n\t      // if dropdown hasn't been opened yet, the option won't exist\n\t      UpdateCheckbox(option);\n\t    }\n\t  }); // remove items when selected option is clicked\n\n\t  self.hook('instead', 'onOptionSelect', (evt, option) => {\n\t    if (option.classList.contains('selected')) {\n\t      option.classList.remove('selected');\n\t      self.removeItem(option.dataset.value);\n\t      self.refreshOptions();\n\t      preventDefault(evt, true);\n\t      return;\n\t    }\n\n\t    orig_onOptionSelect.call(self, evt, option);\n\t    UpdateCheckbox(option);\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_header\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction clear_button (userOptions) {\n\t  const self = this;\n\t  const options = Object.assign({\n\t    className: 'clear-button',\n\t    title: 'Clear All',\n\t    html: data => {\n\t      return `<div class=\"${data.className}\" title=\"${data.title}\">&#10799;</div>`;\n\t    }\n\t  }, userOptions);\n\t  self.on('initialize', () => {\n\t    var button = getDom(options.html(options));\n\t    button.addEventListener('click', evt => {\n\t      if (self.isDisabled) {\n\t        return;\n\t      }\n\n\t      self.clear();\n\n\t      if (self.settings.mode === 'single' && self.settings.allowEmptyOption) {\n\t        self.addItem('');\n\t      }\n\n\t      evt.preventDefault();\n\t      evt.stopPropagation();\n\t    });\n\t    self.control.appendChild(button);\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"drag_drop\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction drag_drop () {\n\t  var self = this;\n\t  if (!$.fn.sortable) throw new Error('The \"drag_drop\" plugin requires jQuery UI \"sortable\".');\n\t  if (self.settings.mode !== 'multi') return;\n\t  var orig_lock = self.lock;\n\t  var orig_unlock = self.unlock;\n\t  self.hook('instead', 'lock', () => {\n\t    var sortable = $(self.control).data('sortable');\n\t    if (sortable) sortable.disable();\n\t    return orig_lock.call(self);\n\t  });\n\t  self.hook('instead', 'unlock', () => {\n\t    var sortable = $(self.control).data('sortable');\n\t    if (sortable) sortable.enable();\n\t    return orig_unlock.call(self);\n\t  });\n\t  self.on('initialize', () => {\n\t    var $control = $(self.control).sortable({\n\t      items: '[data-value]',\n\t      forcePlaceholderSize: true,\n\t      disabled: self.isLocked,\n\t      start: (e, ui) => {\n\t        ui.placeholder.css('width', ui.helper.css('width'));\n\t        $control.css({\n\t          overflow: 'visible'\n\t        });\n\t      },\n\t      stop: () => {\n\t        $control.css({\n\t          overflow: 'hidden'\n\t        });\n\t        var values = [];\n\t        $control.children('[data-value]').each(function () {\n\t          if (this.dataset.value) values.push(this.dataset.value);\n\t        });\n\t        self.setValue(values);\n\t      }\n\t    });\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_header\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction dropdown_header (userOptions) {\n\t  const self = this;\n\t  const options = Object.assign({\n\t    title: 'Untitled',\n\t    headerClass: 'dropdown-header',\n\t    titleRowClass: 'dropdown-header-title',\n\t    labelClass: 'dropdown-header-label',\n\t    closeClass: 'dropdown-header-close',\n\t    html: data => {\n\t      return '<div class=\"' + data.headerClass + '\">' + '<div class=\"' + data.titleRowClass + '\">' + '<span class=\"' + data.labelClass + '\">' + data.title + '</span>' + '<a class=\"' + data.closeClass + '\">&times;</a>' + '</div>' + '</div>';\n\t    }\n\t  }, userOptions);\n\t  self.on('initialize', () => {\n\t    var header = getDom(options.html(options));\n\t    var close_link = header.querySelector('.' + options.closeClass);\n\n\t    if (close_link) {\n\t      close_link.addEventListener('click', evt => {\n\t        preventDefault(evt, true);\n\t        self.close();\n\t      });\n\t    }\n\n\t    self.dropdown.insertBefore(header, self.dropdown.firstChild);\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_input\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction caret_position () {\n\t  var self = this;\n\t  /**\n\t   * Moves the caret to the specified index.\n\t   *\n\t   * The input must be moved by leaving it in place and moving the\n\t   * siblings, due to the fact that focus cannot be restored once lost\n\t   * on mobile webkit devices\n\t   *\n\t   */\n\n\t  self.hook('instead', 'setCaret', new_pos => {\n\t    if (self.settings.mode === 'single' || !self.control.contains(self.control_input)) {\n\t      new_pos = self.items.length;\n\t    } else {\n\t      new_pos = Math.max(0, Math.min(self.items.length, new_pos));\n\n\t      if (new_pos != self.caretPos && !self.isPending) {\n\t        self.controlChildren().forEach((child, j) => {\n\t          if (j < new_pos) {\n\t            self.control_input.insertAdjacentElement('beforebegin', child);\n\t          } else {\n\t            self.control.appendChild(child);\n\t          }\n\t        });\n\t      }\n\t    }\n\n\t    self.caretPos = new_pos;\n\t  });\n\t  self.hook('instead', 'moveCaret', direction => {\n\t    if (!self.isFocused) return; // move caret before or after selected items\n\n\t    const last_active = self.getLastActive(direction);\n\n\t    if (last_active) {\n\t      const idx = nodeIndex(last_active);\n\t      self.setCaret(direction > 0 ? idx + 1 : idx);\n\t      self.setActiveItem();\n\t      removeClasses(last_active, 'last-active'); // move caret left or right of current position\n\t    } else {\n\t      self.setCaret(self.caretPos + direction);\n\t    }\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"dropdown_input\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction dropdown_input () {\n\t  const self = this;\n\t  self.settings.shouldOpen = true; // make sure the input is shown even if there are no options to display in the dropdown\n\n\t  self.hook('before', 'setup', () => {\n\t    self.focus_node = self.control;\n\t    addClasses(self.control_input, 'dropdown-input');\n\t    const div = getDom('<div class=\"dropdown-input-wrap\">');\n\t    div.append(self.control_input);\n\t    self.dropdown.insertBefore(div, self.dropdown.firstChild); // set a placeholder in the select control\n\n\t    const placeholder = getDom('<input class=\"items-placeholder\" tabindex=\"-1\" />');\n\t    placeholder.placeholder = self.settings.placeholder || '';\n\t    self.control.append(placeholder);\n\t  });\n\t  self.on('initialize', () => {\n\t    // set tabIndex on control to -1, otherwise [shift+tab] will put focus right back on control_input\n\t    self.control_input.addEventListener('keydown', evt => {\n\t      //addEvent(self.control_input,'keydown' as const,(evt:KeyboardEvent) =>{\n\t      switch (evt.keyCode) {\n\t        case KEY_ESC:\n\t          if (self.isOpen) {\n\t            preventDefault(evt, true);\n\t            self.close();\n\t          }\n\n\t          self.clearActiveItems();\n\t          return;\n\n\t        case KEY_TAB:\n\t          self.focus_node.tabIndex = -1;\n\t          break;\n\t      }\n\n\t      return self.onKeyDown.call(self, evt);\n\t    });\n\t    self.on('blur', () => {\n\t      self.focus_node.tabIndex = self.isDisabled ? -1 : self.tabIndex;\n\t    }); // give the control_input focus when the dropdown is open\n\n\t    self.on('dropdown_open', () => {\n\t      self.control_input.focus();\n\t    }); // prevent onBlur from closing when focus is on the control_input\n\n\t    const orig_onBlur = self.onBlur;\n\t    self.hook('instead', 'onBlur', evt => {\n\t      if (evt && evt.relatedTarget == self.control_input) return;\n\t      return orig_onBlur.call(self);\n\t    });\n\t    addEvent(self.control_input, 'blur', () => self.onBlur()); // return focus to control to allow further keyboard input\n\n\t    self.hook('before', 'close', () => {\n\t      if (!self.isOpen) return;\n\t      self.focus_node.focus({\n\t        preventScroll: true\n\t      });\n\t    });\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"input_autogrow\" (Tom Select)\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction input_autogrow () {\n\t  var self = this;\n\t  self.on('initialize', () => {\n\t    var test_input = document.createElement('span');\n\t    var control = self.control_input;\n\t    test_input.style.cssText = 'position:absolute; top:-99999px; left:-99999px; width:auto; padding:0; white-space:pre; ';\n\t    self.wrapper.appendChild(test_input);\n\t    var transfer_styles = ['letterSpacing', 'fontSize', 'fontFamily', 'fontWeight', 'textTransform'];\n\n\t    for (const style_name of transfer_styles) {\n\t      // @ts-ignore TS7015 https://stackoverflow.com/a/50506154/697576\n\t      test_input.style[style_name] = control.style[style_name];\n\t    }\n\t    /**\n\t     * Set the control width\n\t     *\n\t     */\n\n\n\t    var resize = () => {\n\t      test_input.textContent = control.value;\n\t      control.style.width = test_input.clientWidth + 'px';\n\t    };\n\n\t    resize();\n\t    self.on('update item_add item_remove', resize);\n\t    addEvent(control, 'input', resize);\n\t    addEvent(control, 'keyup', resize);\n\t    addEvent(control, 'blur', resize);\n\t    addEvent(control, 'update', resize);\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"input_autogrow\" (Tom Select)\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction no_backspace_delete () {\n\t  var self = this;\n\t  var orig_deleteSelection = self.deleteSelection;\n\t  this.hook('instead', 'deleteSelection', evt => {\n\t    if (self.activeItems.length) {\n\t      return orig_deleteSelection.call(self, evt);\n\t    }\n\n\t    return false;\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"no_active_items\" (Tom Select)\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction no_active_items () {\n\t  this.hook('instead', 'setActiveItem', () => {});\n\t  this.hook('instead', 'selectAll', () => {});\n\t}\n\n\t/**\n\t * Plugin: \"optgroup_columns\" (Tom Select.js)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction optgroup_columns () {\n\t  var self = this;\n\t  var orig_keydown = self.onKeyDown;\n\t  self.hook('instead', 'onKeyDown', evt => {\n\t    var index, option, options, optgroup;\n\n\t    if (!self.isOpen || !(evt.keyCode === KEY_LEFT || evt.keyCode === KEY_RIGHT)) {\n\t      return orig_keydown.call(self, evt);\n\t    }\n\n\t    self.ignoreHover = true;\n\t    optgroup = parentMatch(self.activeOption, '[data-group]');\n\t    index = nodeIndex(self.activeOption, '[data-selectable]');\n\n\t    if (!optgroup) {\n\t      return;\n\t    }\n\n\t    if (evt.keyCode === KEY_LEFT) {\n\t      optgroup = optgroup.previousSibling;\n\t    } else {\n\t      optgroup = optgroup.nextSibling;\n\t    }\n\n\t    if (!optgroup) {\n\t      return;\n\t    }\n\n\t    options = optgroup.querySelectorAll('[data-selectable]');\n\t    option = options[Math.min(options.length - 1, index)];\n\n\t    if (option) {\n\t      self.setActiveOption(option);\n\t    }\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"remove_button\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction remove_button (userOptions) {\n\t  const options = Object.assign({\n\t    label: '&times;',\n\t    title: 'Remove',\n\t    className: 'remove',\n\t    append: true\n\t  }, userOptions); //options.className = 'remove-single';\n\n\t  var self = this; // override the render method to add remove button to each item\n\n\t  if (!options.append) {\n\t    return;\n\t  }\n\n\t  var html = '<a href=\"javascript:void(0)\" class=\"' + options.className + '\" tabindex=\"-1\" title=\"' + escape_html(options.title) + '\">' + options.label + '</a>';\n\t  self.hook('after', 'setupTemplates', () => {\n\t    var orig_render_item = self.settings.render.item;\n\n\t    self.settings.render.item = (data, escape) => {\n\t      var item = getDom(orig_render_item.call(self, data, escape));\n\t      var close_button = getDom(html);\n\t      item.appendChild(close_button);\n\t      addEvent(close_button, 'mousedown', evt => {\n\t        preventDefault(evt, true);\n\t      });\n\t      addEvent(close_button, 'click', evt => {\n\t        // propagating will trigger the dropdown to show for single mode\n\t        preventDefault(evt, true);\n\t        if (self.isLocked) return;\n\t        if (!self.shouldDelete([item], evt)) return;\n\t        self.removeItem(item);\n\t        self.refreshOptions(false);\n\t        self.inputState();\n\t      });\n\t      return item;\n\t    };\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"restore_on_backspace\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction restore_on_backspace (userOptions) {\n\t  const self = this;\n\t  const options = Object.assign({\n\t    text: option => {\n\t      return option[self.settings.labelField];\n\t    }\n\t  }, userOptions);\n\t  self.on('item_remove', function (value) {\n\t    if (!self.isFocused) {\n\t      return;\n\t    }\n\n\t    if (self.control_input.value.trim() === '') {\n\t      var option = self.options[value];\n\n\t      if (option) {\n\t        self.setTextboxValue(options.text.call(self, option));\n\t      }\n\t    }\n\t  });\n\t}\n\n\t/**\n\t * Plugin: \"restore_on_backspace\" (Tom Select)\n\t * Copyright (c) contributors\n\t *\n\t * Licensed under the Apache License, Version 2.0 (the \"License\"); you may not use this\n\t * file except in compliance with the License. You may obtain a copy of the License at:\n\t * http://www.apache.org/licenses/LICENSE-2.0\n\t *\n\t * Unless required by applicable law or agreed to in writing, software distributed under\n\t * the License is distributed on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF\n\t * ANY KIND, either express or implied. See the License for the specific language\n\t * governing permissions and limitations under the License.\n\t *\n\t */\n\tfunction virtual_scroll () {\n\t  const self = this;\n\t  const orig_canLoad = self.canLoad;\n\t  const orig_clearActiveOption = self.clearActiveOption;\n\t  const orig_loadCallback = self.loadCallback;\n\t  var pagination = {};\n\t  var dropdown_content;\n\t  var loading_more = false;\n\t  var load_more_opt;\n\t  var default_values = [];\n\n\t  if (!self.settings.shouldLoadMore) {\n\t    // return true if additional results should be loaded\n\t    self.settings.shouldLoadMore = () => {\n\t      const scroll_percent = dropdown_content.clientHeight / (dropdown_content.scrollHeight - dropdown_content.scrollTop);\n\n\t      if (scroll_percent > 0.9) {\n\t        return true;\n\t      }\n\n\t      if (self.activeOption) {\n\t        var selectable = self.selectable();\n\t        var index = Array.from(selectable).indexOf(self.activeOption);\n\n\t        if (index >= selectable.length - 2) {\n\t          return true;\n\t        }\n\t      }\n\n\t      return false;\n\t    };\n\t  }\n\n\t  if (!self.settings.firstUrl) {\n\t    throw 'virtual_scroll plugin requires a firstUrl() method';\n\t  } // in order for virtual scrolling to work,\n\t  // options need to be ordered the same way they're returned from the remote data source\n\n\n\t  self.settings.sortField = [{\n\t    field: '$order'\n\t  }, {\n\t    field: '$score'\n\t  }]; // can we load more results for given query?\n\n\t  const canLoadMore = query => {\n\t    if (typeof self.settings.maxOptions === 'number' && dropdown_content.children.length >= self.settings.maxOptions) {\n\t      return false;\n\t    }\n\n\t    if (query in pagination && pagination[query]) {\n\t      return true;\n\t    }\n\n\t    return false;\n\t  };\n\n\t  const clearFilter = (option, value) => {\n\t    if (self.items.indexOf(value) >= 0 || default_values.indexOf(value) >= 0) {\n\t      return true;\n\t    }\n\n\t    return false;\n\t  }; // set the next url that will be\n\n\n\t  self.setNextUrl = (value, next_url) => {\n\t    pagination[value] = next_url;\n\t  }; // getUrl() to be used in settings.load()\n\n\n\t  self.getUrl = query => {\n\t    if (query in pagination) {\n\t      const next_url = pagination[query];\n\t      pagination[query] = false;\n\t      return next_url;\n\t    } // if the user goes back to a previous query\n\t    // we need to load the first page again\n\n\n\t    pagination = {};\n\t    return self.settings.firstUrl.call(self, query);\n\t  }; // don't clear the active option (and cause unwanted dropdown scroll)\n\t  // while loading more results\n\n\n\t  self.hook('instead', 'clearActiveOption', () => {\n\t    if (loading_more) {\n\t      return;\n\t    }\n\n\t    return orig_clearActiveOption.call(self);\n\t  }); // override the canLoad method\n\n\t  self.hook('instead', 'canLoad', query => {\n\t    // first time the query has been seen\n\t    if (!(query in pagination)) {\n\t      return orig_canLoad.call(self, query);\n\t    }\n\n\t    return canLoadMore(query);\n\t  }); // wrap the load\n\n\t  self.hook('instead', 'loadCallback', (options, optgroups) => {\n\t    if (!loading_more) {\n\t      self.clearOptions(clearFilter);\n\t    } else if (load_more_opt) {\n\t      const first_option = options[0];\n\n\t      if (first_option !== undefined) {\n\t        load_more_opt.dataset.value = first_option[self.settings.valueField];\n\t      }\n\t    }\n\n\t    orig_loadCallback.call(self, options, optgroups);\n\t    loading_more = false;\n\t  }); // add templates to dropdown\n\t  //\tloading_more if we have another url in the queue\n\t  //\tno_more_results if we don't have another url in the queue\n\n\t  self.hook('after', 'refreshOptions', () => {\n\t    const query = self.lastValue;\n\t    var option;\n\n\t    if (canLoadMore(query)) {\n\t      option = self.render('loading_more', {\n\t        query: query\n\t      });\n\n\t      if (option) {\n\t        option.setAttribute('data-selectable', ''); // so that navigating dropdown with [down] keypresses can navigate to this node\n\n\t        load_more_opt = option;\n\t      }\n\t    } else if (query in pagination && !dropdown_content.querySelector('.no-results')) {\n\t      option = self.render('no_more_results', {\n\t        query: query\n\t      });\n\t    }\n\n\t    if (option) {\n\t      addClasses(option, self.settings.optionClass);\n\t      dropdown_content.append(option);\n\t    }\n\t  }); // add scroll listener and default templates\n\n\t  self.on('initialize', () => {\n\t    default_values = Object.keys(self.options);\n\t    dropdown_content = self.dropdown_content; // default templates\n\n\t    self.settings.render = Object.assign({}, {\n\t      loading_more: () => {\n\t        return `<div class=\"loading-more-results\">Loading more results ... </div>`;\n\t      },\n\t      no_more_results: () => {\n\t        return `<div class=\"no-more-results\">No more results</div>`;\n\t      }\n\t    }, self.settings.render); // watch dropdown content scroll position\n\n\t    dropdown_content.addEventListener('scroll', () => {\n\t      if (!self.settings.shouldLoadMore.call(self)) {\n\t        return;\n\t      } // !important: this will get checked again in load() but we still need to check here otherwise loading_more will be set to true\n\n\n\t      if (!canLoadMore(self.lastValue)) {\n\t        return;\n\t      } // don't call load() too much\n\n\n\t      if (loading_more) return;\n\t      loading_more = true;\n\t      self.load.call(self, self.lastValue);\n\t    });\n\t  });\n\t}\n\n\tTomSelect.define('change_listener', change_listener);\n\tTomSelect.define('checkbox_options', checkbox_options);\n\tTomSelect.define('clear_button', clear_button);\n\tTomSelect.define('drag_drop', drag_drop);\n\tTomSelect.define('dropdown_header', dropdown_header);\n\tTomSelect.define('caret_position', caret_position);\n\tTomSelect.define('dropdown_input', dropdown_input);\n\tTomSelect.define('input_autogrow', input_autogrow);\n\tTomSelect.define('no_backspace_delete', no_backspace_delete);\n\tTomSelect.define('no_active_items', no_active_items);\n\tTomSelect.define('optgroup_columns', optgroup_columns);\n\tTomSelect.define('remove_button', remove_button);\n\tTomSelect.define('restore_on_backspace', restore_on_backspace);\n\tTomSelect.define('virtual_scroll', virtual_scroll);\n\n\treturn TomSelect;\n\n}));\nvar tomSelect=function(el,opts){return new TomSelect(el,opts);} \n//# sourceMappingURL=tom-select.complete.js.map\n\n\n//# sourceURL=webpack:///./node_modules/tom-select/dist/js/tom-select.complete.js?")},0:
/*!**************************************************************************************************!*\
  !*** multi ./JavaScript/Frontend/main.js ./Sass/backend.scss ./Sass/demo.scss ./Sass/style.scss ***!
  \**************************************************************************************************/
/*! no static exports found */function(module,exports,__webpack_require__){eval('__webpack_require__(/*! ./JavaScript/Frontend/main.js */"./JavaScript/Frontend/main.js");\n__webpack_require__(/*! ./Sass/backend.scss */"./Sass/backend.scss");\n__webpack_require__(/*! ./Sass/demo.scss */"./Sass/demo.scss");\nmodule.exports = __webpack_require__(/*! ./Sass/style.scss */"./Sass/style.scss");\n\n\n//# sourceURL=webpack:///multi_./JavaScript/Frontend/main.js_./Sass/backend.scss_./Sass/demo.scss_./Sass/style.scss?')}});