{"version":3,"sources":["mod::utwente_base/web/pub/ws2016/searsia.js","mod::utwente_base/web/pub/ws2016/searsiaconfig.ts","node_modules/events/events.js","mod::system/js/net/requester.ts","mod::system/js/net/jsonrpc.ts","mod::utwente_base/node_modules/@webhare/dompack-carrousel/src/iscroll.modified.js","mod::utwente_base/node_modules/@webhare/dompack-carrousel/src/index.es","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/photoalbum/fullscreen-slideshow.ts","mod::utwente_base/node_modules/ev-emitter/ev-emitter.js","mod::utwente_base/node_modules/get-size/get-size.js","mod::utwente_base/node_modules/desandro-matches-selector/matches-selector.js","mod::utwente_base/node_modules/fizzy-ui-utils/utils.js","mod::utwente_base/node_modules/outlayer/item.js","mod::utwente_base/node_modules/outlayer/outlayer.js","mod::utwente_base/node_modules/masonry-layout/masonry.js","mod::system/js/wh/rpc.ts","@webhare/frontend/src/init.ts","@webhare/env/src/init-browser.ts","mod::publisher/js/internal/polyfills/all.ts","mod::publisher/js/internal/polyfills/iterator-helpers.ts","mod::publisher/js/internal/polyfills/publisher-integration.ts","mod::utwente_base/webdesigns/ws2026/ws2026-site.tsx","@webhare/frontend/src/gtm.ts","mod::publisher/js/analytics/gtm.ts","mod::publisher/js/analytics/consenthandler.ts","mod::utwente_base/webdesigns/ws2016/src/shared/searchsheet/index.tsx","mod::utwente_base/node_modules/@webhare/dompack-justifiedcontentgrid/src/index.es","mod::consilio/js/pxl.ts","mod::utwente_design/vendor/perfect-scrollbar-wh/src/lib/css.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/lib/dom.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/lib/class-names.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/lib/event-manager.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/process-scroll-diff.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/lib/util.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/update-geometry.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/handlers/click-rail.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/handlers/drag-thumb.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/handlers/keyboard.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/handlers/mouse-wheel.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/handlers/touch.js","mod::utwente_design/vendor/perfect-scrollbar-wh/src/index.js","mod::utwente_base/webdesigns/ws2016/src/shared/crm/managedctas.ts","mod::publisher/js/analytics/geoip.ts","mod::system/js/dompack/extra/storage.ts","mod::system/js/dompack/extra/cookie.ts","mod::utwente_design/js/cookiebar/index.tsx","@webhare/frontend/src/frontend.ts","@webhare/frontend/src/auth.ts","@webhare/rpc/src/rpc.ts","@webhare/auth/src/shared.ts","mod::platform/js/concepts/frontend.ts","@webhare/frontend/src/authormode.ts","@webhare/frontend/src/pxl.ts","@webhare/frontend/src/analytics.ts","mod::utwente_base/webdesigns/ws2016/src/cobrowserchat/index.ts","mod::utwente_base/webdesigns/ws2016/src/shared/crm/index.ts","mod::utwente_design/js/crm/consenthandler.ts","mod::utwente_base/webdesigns/ws2016/src/shared/crm/usersettings.ts","mod::utwente_base/webdesigns/ws2016/src/shared/crm/referralinfo.ts","mod::utwente_design/js/crm/auth.ts","mod::wrd/js/auth.ts","mod::system/js/wh/integration.ts","mod::utwente_design/js/crm/networks.ts","mod::utwente_base/webdesigns/ws2016/src/shared/showalllinks.ts","mod::utwente_base/webdesigns/ws2016/src/shared/searchsheet/searsiasuggest.tsx","mod::utwente_base/webdesigns/ws2016/src/shared/searchsheet/searsiatypes.tsx","mod::utwente_base/webdesigns/ws2016/src/shared/searchsheet/searsiawidgets.tsx","mod::utwente_design/theme/theme.tsx","mod::utwente_design/theme/theme-ws2016.tsx","mod::utwente_base/webdesigns/ws2016/src/site.lang.json","mod::utwente_base/webdesigns/ws2016/src/shared/addthisevent/index.ts","mod::utwente_base/src/nextpager/nextpager.ts","mod::utwente_design/webfeatures/videoproviders/index.ts","mod::utwente_design/webfeatures/videoproviders/video.ts","mod::tollium/js/gettid.ts","mod::publisher/js/internal/rtd.lang.json","mod::utwente_base/webdesigns/ws2026/shared/rtd/rtd.ts","mod::utwente_design/web/utdesign/fonts/univers-next-async.ts","mod::utwente_base/webdesigns/ws2026/testcode/testcode.tsx","mod::utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters.tsx","mod::utwente_base/node_modules/autocompleter/autocomplete.ts","mod::utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter.ts","mod::utwente_base/webdesigns/ws2026/shared/pagefilters/searchindex.tsx","mod::utwente_base/webdesigns/ws2026/ws2026.ts","mod::utwente_base/webdesigns/ws2026/frontend.lang.json","mod::utwente_design/js/ut-menu.ts","mod::utwente_design/utilitymenu/utilitymenu.tsx","mod::utwente_design/utilitymenu/utilitymenu.lang.json","mod::utwente_base/webdesigns/ws2026/header/header.tsx","mod::utwente_base/webdesigns/ws2026/header/breadcrumbs.tsx","mod::utwente_base/webdesigns/ws2026/header/menu.tsx","mod::utwente_base/webdesigns/ws2026/shared/layout-tools.tsx","mod::utwente_base/webdesigns/ws2026/shared/skiplinks.ts","mod::utwente_base/webdesigns/ws2026/footer/footer.tsx","mod::utwente_base/webdesigns/ws2026/shared/psa-chatbot.tsx","mod::utwente_base/webdesigns/ws2026/shared/overflow-placeholder.tsx","mod::publisher/js/forms/rpc.ts","mod::system/js/dompack/browserfix/focus.ts","mod::system/js/dompack/extra/merge.ts","mod::publisher/js/forms/formbase.ts","mod::publisher/js/forms/internal/webharefields.tsx","mod::system/js/dompack/types/datetime.ts","mod::publisher/js/forms/fields/addressfield.ts","@webhare/forms/src/address.ts","mod::publisher/js/forms/internal/customvalidation.ts","@webhare/forms/src/domsupport.ts","@webhare/forms/src/jsformelement.ts","mod::publisher/js/forms/internal/datehelpers.ts","@webhare/forms/src/registeredfield.ts","mod::publisher/js/forms/fields/arrayfield.ts","@webhare/forms/src/fieldmap.ts","mod::publisher/js/forms/internal/emailvalidation.tsx","mod::system/js/dompack/api/dialog.ts","mod::publisher/js/forms/fields/captchafield.ts","mod::publisher/js/captcha/api.ts","mod::publisher/js/captcha/__captcha.lang.json","@webhare/forms/src/registration.ts","mod::publisher/js/forms/fields/upload.tsx","mod::publisher/js/forms/fields/fileeditbase.ts","mod::publisher/js/forms/internal/form.lang.json","mod::publisher/js/forms/fields/imgedit.ts","@webhare/forms/src/forms.ts","mod::publisher/js/forms/fields/datetime.tsx","mod::publisher/js/forms/internal/datepicker.tsx","mod::publisher/js/captcha/google-recaptcha.tsx","@webhare/forms/src/friendly-captcha.ts","mod::utwente_base/webdesigns/ws2026/shared/forms/forms.tsx","mod::utwente_design/node_modules/slim-select/src/slim-select/classes.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/animations.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/settings.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/helpers.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/events.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/lifecycle.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/store.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/render.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/mutations.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/select.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/sync.ts","mod::utwente_design/node_modules/slim-select/src/slim-select/index.ts","mod::utwente_design/js/utils/trigram.ts","mod::utwente_base/webdesigns/ws2026/shared/forms/phone.tsx","mod::publisher/js/forms/index.ts","mod::publisher/js/forms/fields/rtd/index.ts","mod::publisher/js/forms/fields/rtd/embedvideo.ts","mod::utwente_base/webdesigns/ws2026/shared/forms/dialogs.tsx","mod::utwente_base/webdesigns/ws2026/shared/forms/dialogs.lang.json","mod::system/js/dompack/components/dialog/index.ts","mod::utwente_base/webdesigns/ws2016/src/shared/utforms/linkhandling.ts","mod::utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts","mod::utwente_base/webdesigns/ws2026/contentheader/ctabuttonsbar.tsx","mod::utwente_base/webdesigns/ws2026/contentheader/contentheader.tsx","mod::utwente_base/webdesigns/ws2016/src/components/video.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/managed-cta/index.tsx","mod::utwente_base/webdesigns/ws2016/src/components/scrolllistener.ts","mod::utwente_base/webfeatures/utcomponents/countdown/countdown2026.tsx","mod::utwente_base/webdesigns/ws2026/shared/slidesanimation.tsx","mod::utwente_base/webdesigns/ws2026/notificationbar/notificationbar.tsx","mod::utwente_base/webdesigns/ws2026/shared/deeplinks.tsx","mod::utwente_base/webdesigns/ws2026/shared/smoothscroll.ts","mod::utwente_base/webdesigns/ws2026/shared/scrolllistener.ts","mod::utwente_base/webdesigns/ws2026/shared/osiris/osiris.tsx","mod::utwente_base/js/service.ts","mod::utwente_base/webdesigns/ws2026/widgets/widgets.tsx","mod::utwente_base/webdesigns/ws2016/src/components/resizeobserver.ts","mod::utwente_base/webdesigns/ws2016/src/shared/slideshow.ts","mod::utwente_base/webdesigns/ws2016/src/components/swipedetect.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/widgetsholder/widgetsholder.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/widgetsholder/dompack-masonry.ts","mod::utwente_base/webdesigns/ws2016/src/shared/layout-tools.ts","mod::utwente_base/webfeatures/utwidgets/layout.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/consentcheck.tsx","mod::utwente_base/webdesigns/ws2016/src/widgets/homepage/index.ts","mod::utwente_base/webdesigns/ws2016/src/components/carrouselcontent/index.ts","mod::utwente_base/webfeatures/utwidgets/imagewithcaption/index.tsx","mod::utwente_base/webfeatures/utcomponents/countdown/index.ts","mod::utwente_base/webfeatures/utwidgets/countdown/index.ts","mod::utwente_base/webfeatures/utwidgets/events/index.tsx","mod::utwente_base/webfeatures/utwidgets/faq/index.ts","mod::utwente_base/webfeatures/utwidgets/imagevideowithtext/index.tsx","mod::utwente_base/webdesigns/ws2016/src/shared/dialog/index.tsx","mod::utwente_base/webdesigns/ws2016/src/shared/dialog/dialog.lang.json","mod::utwente_base/webfeatures/utwidgets/news/index.tsx","mod::utwente_base/webfeatures/utwidgets/quote/index.tsx","mod::utwente_design/js/ut-formatting.tsx","mod::utwente_base/webfeatures/utwidgets/soundcloud/soundcloud.tsx","mod::utwente_base/webfeatures/utwidgets/tablewithtabs/index.ts","mod::utwente_design/js/foldablecontent/index.tsx","mod::utwente_base/webfeatures/utwidgets/video/index.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/carrousel/index.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/photoalbum/index.ts","mod::utwente_base/webdesigns/ws2016/src/shared/hoversupport.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/slideshow/index.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/slideshow/dompack-carrousel-slideshow.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/progress/index.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/timeline/index.ts","mod::utwente_base/webdesigns/ws2016/src/filteredoverview/index.tsx","mod::utwente_base/webdesigns/ws2016/src/filteredoverview/searchindex/index.tsx","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/timeline/dompack-masonry-update.ts","mod::utwente_base/webdesigns/ws2016/src/components/smoothscroll.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/banner/index.ts","mod::utwente_base/webdesigns/ws2016/src/widgets/figures/index.ts","mod::utwente_base/webdesigns/ws2026/widgets/linkspercategory_tabs/linkspercategory_tabs.tsx","mod::utwente_base/webdesigns/ws2026/widgets/newsandevents/newsandevents.tsx","mod::utwente_base/webfeatures/utwidgets/sam-chat/sam-chat.ts","mod::utwente_base/webdesigns/ws2026/widgets/photoalbum/photoalbum.tsx","mod::utwente_base/webdesigns/ws2026/shared/photosoverlay/photosoverlay.tsx","mod::utwente_base/webdesigns/ws2026/shared/swipedetect.tsx","mod::utwente_base/webdesigns/ws2026/widgets/embeddedobjects.tsx","mod::utwente_base/webfeatures/ws2021/main/index.ts","mod::utwente_base/webdesigns/ws2016/src/pages/medical/index.ts","mod::utwente_base/webdesigns/ws2016/src/pages/login/index.ts","mod::utwente_base/webdesigns/ws2016/src/pages/meetings/index.ts","mod::system/js/dompack/types/text.ts","mod::utwente_base/webdesigns/ws2016/src/pages/neoform/index.tsx","mod::utwente_base/webdesigns/ws2026/pages/filteredfolder/filteredfolder.tsx","mod::utwente_base/webdesigns/ws2026/pages/newsevents/newsevents.tsx","mod::utwente_base/webdesigns/ws2026/pages/people/people.tsx","mod::utwente_base/webdesigns/ws2026/pages/tablewithfilter/tablewithfilter.tsx","mod::utwente_base/webdesigns/ws2026/pages/timeline/timeline.tsx","mod::utwente_base/webdesigns/ws2026/pages/ufonds-donaties/index.ts","mod::utwente_base/js/frontendauth.ts","mod::datacloud/webfeatures/datacloud-loader.ts","mod::utwente_courses/webfeatures/courses/pages/course/index.tsx","mod::utwente_courses/webfeatures/courses/pages/mycourses/index.ts","mod::utwente_courses/webfeatures/courses/components/dialogs/index.tsx","mod::utwente_courses/js/site-service.ts","mod::utwente_courses/webfeatures/courses/components/detail/index.tsx","mod::utwente_courses/webfeatures/courses/components/calendar/calendar.tsx","mod::utwente_courses/webfeatures/courses/coursefinder.lang.json","mod::utwente_courses/webfeatures/courses/coursefinder.tsx","mod::utwente_education/webfeatures/studyfinder/studyfinder2026.tsx","mod::utwente_education/webfeatures/studyfinder/studyfinder.lang.json","mod::utwente_education/webfeatures/scholarshipfinder/scholarshipfinder.tsx","mod::utwente_education/webfeatures/widgets/transfer/index.tsx","mod::utwente_education/webfeatures/shared/services.rpc.json","mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/index.ts","mod::utwente_education/webfeatures/widgets/transfer/transfer.lang.json","mod::utwente_base/webdesigns/ws2016/src/shared/peopleimages/index.ts","mod::utwente_base/webdesigns/ws2016/src/shared/peopleimages/pirservice.rpc.json","mod::utwente_education/webfeatures/widgets/programmedetails/index.ts","mod::utwente_education/webfeatures/widgets/programmeheader/programmeheader.ts","mod::utwente_education/webfeatures/widgets/relatedmasterprogrammes/index.ts","mod::utwente_education/webfeatures/widgets/studyinnumbers/index.ts","mod::utwente_education/webfeatures/widgets/cssstudies/index.ts","mod::utwente_education/webfeatures/widgets/specializations/index.ts","mod::utwente_jobs/webfeatures/vacanciespage/vacancywidget/index.tsx","mod::utwente_jobs/webfeatures/vacanciespage/vacancywidget/vacancies.rpc.json","mod::utwente_jobs/webfeatures/vacanciespage/index.ts","mod::utwente_ppp/webdesigns/shared/widgets/projectslist/index.ts","mod::utwente_voorlichting/js/shared/orgselect.tsx","mod::utwente_voorlichting/js/shared/internal/leads.rpc.json","mod::utwente_voorlichting/js/shared/shared_search.ts","mod::utwente_voorlichting/js/shared/institutes.ts","mod::utwente_voorlichting/webfeatures/cashpoint/index.tsx","mod::utwente_voorlichting/webfeatures/cashpoint/cashpointpage.lang.json","mod::utwente_base/webdesigns/ws2016/src/shared/crm/prefill.ts","mod::utwente_voorlichting/js/shared/forms.ts","mod::utwente_voorlichting/webfeatures/echeck/widget.ts","mod::utwente_voorlichting/webfeatures/echeck/index.tsx","mod::utwente_voorlichting/webfeatures/opendagen/index.tsx","mod::utwente_voorlichting/webfeatures/opendagen/opendagen.lang.json","@webhare/dompack/src/html.ts","mod::utwente_voorlichting/webfeatures/opendays_v2/index.tsx","mod::utwente_voorlichting/webfeatures/opendays_v2/opendays_v2.lang.json","mod::utwente_voorlichting/webfeatures/leadswidgets/brochurerequest/brochurerequest.ts","mod::utwente_voorlichting/webfeatures/leadswidgets/leadswidgets.rpc.json","mod::utwente_voorlichting/webfeatures/leadswidgets/stayuptodate/stayuptodate.ts","mod::utwente_voorlichting/webfeatures/leadswidgets/index.ts","mod::utwente_voorlichting/webfeatures/scopemastercontact/index.ts","mod::utwente_voorlichting/webfeatures/tasterdays/index.tsx","mod::utwente_voorlichting/webfeatures/tasterdays/tasterdays.lang.json","mod::utwente_voorlichting/webfeatures/lifelonglearning/registercourse/registercourse.tsx","mod::utwente_voorlichting/webfeatures/sirform/sirform.ts","mod::publisher/js/pwa/index.ts","mod::publisher/js/pwa/internal/debugmenu.tsx","mod::publisher/js/pwa/internal/settings.ts","node_modules/idb/build/index.js","mod::publisher/js/pwa/internal/maintenance.ts","mod::utwente_voorlichting/webfeatures/sirform/sirform.lang.json","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/activities/blockspage.ts","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/activities/activities.ts","mod::utwente_base/webdesigns/ws2016/src/shared/deeplinks.tsx","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/activities/activitieslist.tsx","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/components/toggle.ts","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/activities/activitiespagefilter.tsx","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/widgets/ctalinks/ctalinks.ts","mod::utwente_voorlichting/webfeatures/ws2016_voorlichting/ws2026_voorlichting.ts","/entrypoint.js"],"sourcesContent":["//this file MUST keep its .js extension!\n\n/*\n * Copyright 2017 Searsia\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *   http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n * Searsia Library v1.2.0:\n *\n *   The web page should first call searsia.initClient(template) and then\n *   searsia.searchFederated(params, callback), see: exampleclient.js\n *   Syntax checked with: standard (https://standardjs.com)\n */\n\n/*\n * Modifications by WebHare:\n * - Prepare for usage as module by exporting the searsia object\n * - Support relative urls, interpret relative to Searsia\n * - Use fetch instead of XMLHttpRequest for better redirection control\n * - Encode amp _before_ encoding lt and gt in noHTMLelement\n *\n * Usage:\n *\n *   import searsia from \"searsia\";\n *   searsia.initClient(template);\n *   searsia.searchFederated(params, callback);\n */\n\n'use strict'\n\nvar searsia = (function () {\n  var SEARSIAVERSION = 'v1.2.0'\n  var globalId = null\n  var globalApiTemplate = null\n  var globalMother = null\n\n  /* replace JQuery $.ajax() */\n\n  async function searsiaAjax (ajaxObject) {\n    let url = ajaxObject.url;\n    const success = ajaxObject.success;\n    const error = ajaxObject.error;\n    //ADDME: timeout support (using AbortController?)\n    //const timeout = ajaxObject.timeout;\n    const dataType = ajaxObject.dataType;\n\n    const options = {\n      credentials: 'same-origin',\n      redirect: 'follow'\n    };\n\n    let response;\n    for (let tries = 0; tries < 3; ++tries) {\n      // For testing purposes only, replace www.webhare-test.utsp.utwente.nl with serviceportal.webhare-test.utsp.utwente.nl\n      // (the actual service portal will run at www, but the test... version runs at serviceportal...)\n      url = url.replace(\"//www.webhare-test.utsp.utwente.nl/\", \"//serviceportal.webhare-test.utsp.utwente.nl/\");\n\n      try {\n        response = await fetch(url, options);\n        if (response.status === 200) {\n          if (response.redirected)\n          {\n            url = response.url;\n            continue;\n          }\n          try {\n            const data = dataType === 'json' ? await response.json() : null;\n            success(data);\n            return;\n          } catch(decodeError) {\n            error(response, null, decodeError.message);\n            return;\n          }\n        } else {\n          let message = response.statusText;\n          if (!message) {\n            message = 'Not available';\n          }\n          error(response, null, message);\n          return;\n        }\n      } catch (connectError) {\n        error(response, null, 'Connection error');\n        return;\n      }\n    }\n    error(response, null, 'Max tries exceeded');\n  }\n\n  /* Basic local storage functions */\n\n  function clearLocalStorage () {\n    try {\n      Object.keys(localStorage).filter(function(key){return key.substr(0,8)=='searsia-'}).forEach(function(key){localStorage.removeItem(key)});\n    } catch (ignore) { }\n  }\n\n  function setLocalStorage (field, value) {\n    if (value != null) {\n      try {\n        window.localStorage['searsia-' + field] = value\n      } catch (ignore) { }\n    }\n  }\n\n  function deleteLocalStorage (field) {\n    try {\n      window.localStorage['searsia-' + field] = null\n    } catch (ignore) { }\n  }\n\n  function getLocalStorage (field) {\n    var value = null\n    try {\n      value = window.localStorage['searsia-' + field]\n    } catch (ignore) { }\n    return value\n  }\n\n  function existsLocalStorage (field) {\n    var value = false\n    try {\n      value = window.localStorage.hasOwnProperty('searsia-' + field)\n    } catch (ignore) { }\n    return value\n  }\n\n  /* Special storage functions -- fallback to local variables */\n\n  function setMother (motherObject) {\n    globalMother = motherObject // global\n    setLocalStorage('mother', JSON.stringify(motherObject))\n    if (motherObject.id != null) {\n      globalId = motherObject.id // global\n    } else {\n      globalId = 'searsia'\n    }\n    setLocalStorage('id', globalId)\n  }\n\n  function getMother () {\n    var motherJson\n    if (globalMother != null) { // global\n      return globalMother\n    }\n    motherJson = getLocalStorage('mother')\n    if (motherJson) {\n      return JSON.parse(motherJson)\n    }\n    return null\n  }\n\n  function setApiTemplate (template) {\n    globalApiTemplate = template // global\n    setLocalStorage('apitemplate', template)\n  }\n\n  function getApiTemplate () {\n    if (globalApiTemplate != null) { // global\n      return globalApiTemplate\n    }\n    return getLocalStorage('apitemplate')\n  }\n\n  /* there is no setId(), instead: see setMother() */\n  function getId () {\n    if (globalId != null) {\n      return globalId\n    } else {\n      return getLocalStorage('id')\n    }\n  }\n\n  function setLocalResource (resource) {\n    var id = getId()\n    if (id != null) {\n      setLocalStorage(id + '/' + resource.id, JSON.stringify(resource))\n    }\n  }\n\n  function getLocalResource (rid) {\n    var json\n    var id = getId()\n    if (id == null) {\n      return null\n    }\n    json = getLocalStorage(id + '/' + rid)\n    if (json) {\n      return JSON.parse(json)\n    }\n    return null\n  }\n\n  function existsLocalResource (rid) {\n    var id = getId()\n    if (id == null) {\n      return false\n    }\n    return existsLocalStorage(id + '/' + rid)\n  }\n\n  function deleteLocalResource (rid) {\n    var id = getId()\n    if (id != null) {\n      deleteLocalStorage(id + '/' + rid)\n    }\n  }\n\n  /* Template: only works on Searsia Server templates */\n  function fillUrlTemplate (template, query, page, resourceId, resulttype) {\n    if(template[0]=='/') //it's origin-relative, so copy origin from the api template.\n      template = getApiTemplate().split(\"/\").slice(0,3).join('/') + template;\n\n    var start, end, ext\n    var json = '.json'\n    if (resourceId) {\n      start = template.lastIndexOf('/')\n      end = template.indexOf('?')\n      if (start > 4 && end > start) {\n        if (template.substring(start + 1, end).indexOf(json) !== -1) {\n          ext = json\n        } else {\n          ext = ''\n        }\n        template = template.substring(0, start + 1) + resourceId + ext + template.substring(end, template.length)\n      }\n    }\n    if (page == null) {\n      page = 1\n    }\n    if (resulttype == null) {\n      resulttype = ''\n    }\n    template = template.replace(/\\{q\\??\\}/g, query)\n    template = template.replace(/\\{searchTerms\\??\\}/g, query)\n    template = template.replace(/\\{startPage\\??\\}/, page)\n    template = template.replace(/\\{resultType\\??\\}/, resulttype)\n    return template.replace(/\\{[A-Za-z]+\\?\\}/g, '') // remove all optional\n  }\n\n  function addToHits (hits, hit) {\n    var i\n    var newIndex = hits.length\n    var TOP = 100\n    if (newIndex < TOP || hit.score > hits[TOP - 1].score) {\n      if (newIndex < TOP) { newIndex += 1 }\n      i = newIndex - 1\n      while (i > 0 && hits[i - 1].score < hit.score) {\n        hits[i] = hits[i - 1]\n        i -= 1\n      }\n      hits[i] = hit\n    }\n  }\n\n  function normalizeText (text) {\n    return text.toLowerCase().replace(new RegExp('[^a-z0-9]+', 'g'), ' ').replace(new RegExp('^ +| +$', 'g'), '')\n  }\n\n  function noHTMLattribute (text) {\n    text = text.replace(/&/g, '&amp;')\n    text = text.replace(/\"/g, '&#34;')\n    return text\n  }\n\n  function noHTMLelement (text) {\n    text = text.replace(/&/g, '&amp;')\n    text = text.replace(/</g, '&lt;')\n    text = text.replace(/>/g, '&gt;')\n    return text\n  }\n\n  function scoreText (text, queryTerms) {\n    var i, j, len\n    var textTerms\n    var score = 0.0\n    textTerms = normalizeText(text).split(/ +/)\n    for (i = 0; i < queryTerms.length; i += 1) { // TODO: Really? Nested loop??\n      len = textTerms.length\n      if (len > 1000) { len = 1000 } // Only check first 1000 words\n      j = 0\n      while (j < len) {\n        if (queryTerms[i] === textTerms[j]) {\n          score += 1.0\n          j = len // one occurrence per query term\n        }\n        j += 1\n      }\n    }\n    return score\n  }\n\n  function restrictStart (someText, start, size) { // size must be > 3\n    var i, j\n    var prefix = ''\n    var postfix = ''\n    if (someText != null && someText.length > size) {\n      if (start < 0) { start = 0 }\n      if (start > 2) {\n        i = someText.indexOf(' ', start - 1)\n        if (i === -1) { i = start } else { i += 1 }\n        prefix = '... '\n      } else {\n        i = 0\n      }\n      if (start + size < someText.length) {\n        j = someText.lastIndexOf(' ', start + size)\n        if (j === -1) { j = start + size - 3 }\n        postfix = ' ...'\n      } else {\n        j = start + size\n      }\n      someText = prefix + someText.substr(i, j - i) + postfix\n    }\n    return someText\n  }\n\n  function matchingSnippets (hits, queryTerms) { // TODO for queries length > 2\n    var i, j, k, description, first, second\n    for (i = 0; i < hits.length; i += 1) {\n      first = -1\n      second = -1\n      if (queryTerms.length < 2) { first = 0 } // Take first part of description for query length 1\n      if (hits[i].description != null) {\n        description = hits[i].description.toLowerCase()\n        j = 0\n        while (j < queryTerms.length) {\n          if (first === -1) {\n            first = description.indexOf(queryTerms[j])\n          } else if (second === -1) {\n            k = first - 120\n            if (k < 0) { k = 0 }\n            second = description.indexOf(queryTerms[j], k)\n            if (second === -1) {\n              second = description.indexOf(queryTerms[j])\n            }\n          }\n          j += 1\n        }\n        if (first === -1) { first = 0 }\n        if (second === -1) { second = 0 }\n        if (first > second) {\n          k = first\n          first = second\n          second = k\n        }\n        if (second - first < 120) {\n          description = restrictStart(hits[i].description, first - 40, 192)\n        } else {\n          description = restrictStart(hits[i].description, first - 40, 92)\n          description += restrictStart(hits[i].description, second - 40, 92)\n        }\n        hits[i].description = description\n      }\n    }\n  }\n\n  /**\n   *  Computes maxscore of hits\n   *  If rerank === true: rerank and select those that match the query\n   *  Used if mother has \"rerank\"\n   */\n  function scoreAllHits (data, query, rerank) {\n    var queryTerms, queryLen, hit, score, maxscore, tscore\n    var newHits = []\n    var nrOfTopHits = 0\n    var i = 0\n    query = normalizeText(printableQuery(query))\n    queryTerms = query.split(/ +/).sort(function (a, b) { return b.length - a.length }) // TODO: Split might not work for all character encodings\n    queryLen = queryTerms.length\n    newHits = []\n    maxscore = 0\n    while (i < data.hits.length) {\n      hit = data.hits[i]\n      score = 0\n      tscore = 0\n      if (hit.title != null) {\n        tscore = scoreText(hit.title, queryTerms)\n      }\n      if (tscore === 0 && hit.url != null) {\n        tscore = scoreText(hit.url, queryTerms) / 1.1\n      }\n      if (tscore < queryLen && hit.description != null) {\n        score = scoreText(hit.description, queryTerms)\n      }\n      if (tscore * 1.1 > score) { // title boost\n        score = tscore * 1.1\n      } else {\n        score += tscore / 10\n      }\n      if (score > 0) {\n        if (score >= queryLen) { nrOfTopHits += 1 }\n        hit.score = score\n        addToHits(newHits, hit) // TODO: only if rerank?\n        if (score > maxscore) { maxscore = score }\n      }\n      if (nrOfTopHits >= 100) { break }\n      i += 1\n    }\n    if (rerank) {\n      matchingSnippets(newHits, queryTerms)\n      data.hits = newHits\n    }\n    return maxscore\n  }\n\n  function correctUrl (absUrl, relUrl) {\n    if (relUrl.match(/^https?:\\/\\//) || relUrl.match(/^\\/\\//)) {\n      return relUrl\n    }\n    if (absUrl == null) {\n      return null\n    }\n    if (relUrl.match(/^\\//)) {\n      return absUrl.replace(/([a-z])\\/.*$/, '$1') + relUrl\n    }\n    return absUrl.replace(/\\/[^/]+$/, '/') + relUrl\n  }\n\n  function getHost (url) {\n    if (!url) {\n      return null\n    }\n    var match = url.match(/:\\/\\/(www\\.)?(.[^/:]+)/)\n    if (match == null) {\n      return null\n    }\n    return match[2]\n  }\n\n  function urlParameters () {\n    var i, values\n    var params = { q: '', r: '', p: '', t: '' }\n    var paramString = window.location.search.substring(1)\n    var parts = paramString.split('&')\n    for (i = 0; i < parts.length; i += 1) {\n      values = parts[i].split('=')\n      if (values[0] === 'q') {\n        params.q = values[1]\n        params.q = params.q.replace(/%3C.*?%3E/g, '') // no HTML\n        params.q = params.q.replace(/%3C|%3E/g, '')\n        params.q = params.q.replace(/^\\++|\\++$/g, '') // no leading and trailing spaces\n      } else if (values[0] === 'r') {\n        params.r = values[1]\n      } else if (values[0] === 'p') {\n        params.p = values[1]\n      } else if (values[0] === 't') {\n        params.t = values[1]\n      }\n    }\n    return params\n  }\n\n  /* takes a url parameter query and returns a human readable query */\n  function printableQuery (query) {\n    query = query.replace(/\\+/g, ' ')\n    query = decodeURIComponent(query)\n    return noHTMLelement(query)\n  }\n\n  /* takes a url parameter query and returns a query for an HTML form */\n  function formQuery (query) {\n    query = printableQuery(query)\n    query = query.replace(/&amp;/g, '&')\n    return query\n  }\n\n  /* takes a human readable query and turns it into an urlencoded query */\n  function encodedQuery (text) {\n    text = encodeURIComponent(text)\n    text = text.replace(/%20/g, '+')\n    return text\n  }\n\n  /*\n   * This function is a mutable data type brain cracker:\n   * That is, we purposely change the values of data and\n   * resource here...\n   */\n  function inferMissingData (data, query, resulttype, rank) {\n    var i, hit, resource, rhost\n    var typeImages = true\n    var typeSmall = true\n    var typeFull = false\n    var typeTitleOnly = true\n    var count = data.hits.length - 1\n    var prior = null\n    var maxScore = 10\n\n    if (count >= maxScore) {\n      maxScore = count + 1\n    }\n    resource = data.resource\n    prior = Number(resource.prior)\n    if (isNaN(prior) || prior == null) { prior = 0.0 }\n\n    if (resource.urltemplate != null) {\n      rhost = getHost(resource.urltemplate)\n    }\n    for (i = count; i >= 0; i -= 1) {\n      hit = data.hits[i]\n      if (hit.title == null) { // everything *must* have a title\n        hit.title = 'Title'\n        console.log('WARNING: result without title')\n      } else {\n        hit.title = noHTMLelement(hit.title)\n      }\n      hit.score = 1 / Math.sqrt(rank) - i / maxScore\n      if (hit.score < 0.001) {\n        hit.score = 0.001\n      }\n      if (hit.url == null) {\n        if (resource.urltemplate != null) {\n          hit.url = fillUrlTemplate(resource.urltemplate, encodedQuery(hit.title), 1, '', resulttype)\n        } else {\n          hit.url = fillUrlTemplate('?q={searchTerms}&t={resultType?}', encodedQuery(hit.title), null, null, resulttype)\n        }\n      } else {\n        if (resource.urltemplate) {\n          hit.url = correctUrl(resource.urltemplate, hit.url)\n        } else {\n          hit.url = correctUrl(resource.apitemplate, hit.url)\n        }\n        if (rhost == null || rhost !== getHost(hit.url)) {\n          typeFull = true\n        }\n        hit.url = noHTMLelement(hit.url)\n      }\n      if (hit.description != null) {\n        hit.description = noHTMLelement(hit.description)\n        typeTitleOnly = false\n      }\n      if (hit.image != null) {\n        hit.image = noHTMLattribute(correctUrl(resource.urltemplate, hit.image))\n        typeTitleOnly = false\n      }\n      if (hit.favicon == null && resource.favicon != null) {\n        hit.favicon = resource.favicon\n      }\n      if (hit.favicon != null) {\n        hit.favicon = noHTMLattribute(hit.favicon)\n      }\n      if (hit.tags == null || hit.tags.indexOf('small') === -1) {\n        typeSmall = false\n      }\n      if (hit.tags == null || hit.tags.indexOf('image') === -1) {\n        typeImages = false\n      }\n    }\n    if (typeImages) {\n      resource.type = 'images'\n    } else if (typeSmall || typeTitleOnly) {\n      resource.type = 'small'\n    } else if (typeFull) {\n      resource.type = 'full'\n    } else {\n      resource.type = 'web'\n    }\n  }\n\n  function returnResults (query, resulttype, sessionid, data, rank, olddata, callbackSearch) {\n    var newscore, oldscore\n    var liveResults = true\n    var count = 0\n    if (data.resource && data.resource.apitemplate) { // TODO: why apitemplate necessary?\n      setLocalResource(data.resource)\n    }\n    if (data.hits && data.hits.length) {\n      count = data.hits.length // TODO: also includes 'rid'-only results from searsia engines\n      newscore = scoreAllHits(data, query, false)\n      oldscore = scoreAllHits(olddata, query, true)\n    }\n    if (count === 0 || oldscore - 0.5 > newscore) { // use old data if olddata is clearly better\n      data = olddata\n      liveResults = false\n      count = data.hits.length\n    }\n    if (count > 0) {\n      inferMissingData(data, query, resulttype, rank)\n      callbackSearch({\n        'searsia': SEARSIAVERSION,\n        'status': 'hits',\n        'sessionid': sessionid,\n        'resource': data.resource,\n        'hits': data.hits,\n        'rank': rank,\n        'query': query,\n        'live': liveResults })\n    }\n  }\n\n  function queryResources (query, resulttype, sessionid, data, callbackSearch) {\n    var pending = 0 // will be used by checkEmpty() and getResults()\n\n    function checkEmpty (sessionid, callbackSearch) {\n      if (pending === 0) {\n        callbackSearch({ 'searsia': SEARSIAVERSION, 'sessionid': sessionid, 'status': 'done' })\n      }\n    }\n\n    function getResults (query, resulttype, sessionid, rid, rank, olddata, callbackSearch) {\n      var template = getApiTemplate()\n      if (template == null) {\n        callbackSearch({\n          'searsia': SEARSIAVERSION,\n          'status': 'error',\n          'sessionid': sessionid,\n          'resource': { 'id': rid },\n          'message': 'No API template found.' })\n      } else {\n        pending += 1\n        searsiaAjax({\n          url: fillUrlTemplate(template, query, 1, rid, resulttype),\n          success: function (data) {\n            returnResults(query, resulttype, sessionid, data, rank, olddata, callbackSearch)\n            pending -= 1\n            checkEmpty(sessionid, callbackSearch)\n          },\n          error: function (xhr, options, err) {\n            if (xhr && xhr.status === 410) {\n              deleteLocalResource(rid)\n            } else {\n              returnResults(query, resulttype, sessionid, olddata, rank, olddata, callbackSearch)\n            }\n            console.log('WARNING: ' + rid + ' unavailable.')\n            pending -= 1\n            checkEmpty(sessionid, callbackSearch)\n          },\n          timeout: 12000,\n          dataType: 'json'\n        })\n      }\n    }\n\n    var rid, hits, olddata\n    var i = 0\n    var rank = 1\n    var done = []\n    var resource = data.resource\n    if (resource != null) {\n      setMother(resource)\n      if (resource.rerank != null) {\n        scoreAllHits(data, query, true)\n      }\n    } else {\n      resource = getMother()\n    }\n    callbackSearch({ 'searsia': SEARSIAVERSION, 'status': 'start', 'sessionid': sessionid, 'resource': resource })\n    hits = data.hits\n    if (hits == null || hits.length === 0) {\n      callbackSearch({ 'searsia': SEARSIAVERSION, 'status': 'done', 'sessionid': sessionid })\n      return\n    }\n    while (i < hits.length) {\n      rid = hits[i].rid\n      if (rid == null) { // a result that is not from another resource\n        if (data.resource != null && data.resource.urltemplate != null) {\n          hits[i].url = correctUrl(data.resource.urltemplate, hits[i].url)\n        }\n        callbackSearch({\n          'searsia': SEARSIAVERSION,\n          'hits': [ hits[i] ],\n          'query': query,\n          'status': 'hits',\n          'sessionid': sessionid,\n          'rank': rank })\n        rank += 1\n      } else if (done[rid] !== 1) {\n        olddata = { hits: [] }\n        if (existsLocalResource(rid)) {\n          olddata.resource = getLocalResource(rid)\n          while (i < hits.length && hits[i].rid === rid) {\n            if (hits[i].title != null && hits[i].title !== '' && // too many exceptions?\n                            (hits[i].url != null || olddata.resource.urltemplate != null) &&\n                            (hits[i].foundBefore == null || Date.now() - new Date(hits[i].foundBefore).getTime() < 1209600000)) { // 1209600000 is 2 weeks in ms\n              olddata.hits.push(hits[i])\n            }\n            i += 1\n          }\n          i -= 1 // otherwise we miss one\n        } else {\n          olddata.resource = { id: rid } // TODO: get it?\n        }\n        getResults(query, resulttype, sessionid, rid, rank, olddata, callbackSearch)\n        done[rid] = 1\n        rank += 1\n      }\n      i += 1\n    }\n  }\n\n  /**\n   * Generates a random identifier compliant with the uuid(v4) spec.\n   * The randomness of this number is based on Math.random(), which might not\n   * be a guaranteed RNG.\n   * @returns {string} the uuid string\n   */\n  function generateUUID () {\n    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,\n      function (c) {\n        var r = Math.random() * 16 | 0; var v = c === 'x' ? r : (r & 0x3 | 0x8)\n        return v.toString(16)\n      })\n  }\n\n  function searchFederated (params, callbackSearch) {\n    var url, query, page\n    var resulttype = null\n    var template = getApiTemplate()\n    var sessionid = generateUUID()\n    if (template == null) {\n      callbackSearch({ 'status': 'error', 'error': 'First initialize with searsia.initClient(apiTemplate)' })\n      return\n    }\n    if (params.q == null || params.q === '') {\n      callbackSearch({ 'status': 'error', 'sessionid': sessionid, 'error': 'No query.' })\n      return\n    }\n    if (params.q.length > 150) {\n      callbackSearch({ 'status': 'error', 'sessionid': sessionid, 'error': 'Query too long.' })\n      return\n    }\n    query = encodedQuery(params.q)\n    if (params.p == null) {\n      page = 1\n    } else {\n      page = params.p\n    }\n    if (params.t) {\n      resulttype = params.t\n    }\n    url = fillUrlTemplate(template, query, page, null, resulttype)\n    searsiaAjax({\n      url: url,\n      success: function (data) { queryResources(query, resulttype, sessionid, data, callbackSearch) },\n      error: function (xhr, options, error) {\n        console.log('ERROR: ' + error)\n        callbackSearch({ 'status': 'error', 'sessionid': sessionid, 'error': 'Temporarily out of order. Please try again later.' })\n      },\n      timeout: 10000,\n      dataType: 'json'\n    })\n    return sessionid\n  }\n\n  /* connect to mother and return definition */\n  function connectToServer (callbackConnect) {\n    var template = getApiTemplate()\n    if (template == null) {\n      callbackConnect({ 'status': 'error', 'error': 'If you see this then searsiaclient needs to be initialized with searsia.initClient(apiTemplate)' })\n    } else {\n      searsiaAjax({\n        url: fillUrlTemplate(template, '', '', null, null),\n        success: function (data) {\n          if (data.resource != null) {\n            data.status = 'connect'\n            setMother(data.resource)\n          }\n          callbackConnect(data)\n        },\n        error: function (xhr, options, error) {\n          console.log('ERROR: ' + error)\n          callbackConnect({ 'status': 'error', 'error': error })\n        },\n        timeout: 10000,\n        dataType: 'json'\n      })\n    }\n  }\n\n  /* sets the apiTemplate. If not new, return mother from storage */\n  function initClient (template) {\n    var originalTemplate = getApiTemplate()\n    var motherObject = null\n    if (template !== originalTemplate) {\n      clearLocalStorage()\n      setApiTemplate(template)\n    } else {\n      motherObject = getMother()\n    }\n    if (motherObject) {\n      return { 'resource': motherObject }\n    } else {\n      return null\n    }\n  }\n\n  return {\n    urlParameters: function () {\n      return urlParameters()\n    },\n    printableQuery: function (query) {\n      return printableQuery(query)\n    },\n    formQuery: function (query) {\n      return formQuery(query)\n    },\n    encodedQuery: function (query) {\n      return encodedQuery(query)\n    },\n    correctUrl: function (absUrl, relUrl) {\n      return correctUrl(absUrl, relUrl)\n    },\n    fillUrlTemplate: function (template, query, page, resourceId, resultType) {\n      return fillUrlTemplate(template, query, page, resourceId, resultType)\n    },\n    initClient: function (template) {\n      return initClient(template)\n    },\n    connectToServer: function (callbackConnect) {\n      connectToServer(callbackConnect)\n    },\n    searchFederated: function (params, callbackSearch) {\n      return searchFederated(params, callbackSearch)\n    }\n  }\n})()\n\nif (typeof module != \"undefined\")\n  module.exports = searsia;\n","const MIN_SUGGEST_LENGTH = 3; // Min number of characters for suggestions\nconst NUM_SUGGESTIONS = 5; // Max number of suggestions to show\nconst NUM_RELATED = 5; // Max number of related searches to show\n\n// Sources that aren't mapped here (e.g. 'googlecustom') are shown as 'plain' results\nconst SEARSIA_SOURCES =\n{\n  \"alsosearched\": { type: \"related\" },\n  \"alumni\": { type: \"news\" },\n  \"beeldbank\": { type: \"image\" },\n  \"bussen\": { type: \"pubtrans\", group: \"bus\" },\n  \"courses\": { type: \"courses\" },\n  \"cultuur\": { type: \"event\" },\n  \"didyoumean\": { type: \"didyoumean\" },\n  \"essays\": { type: \"publication\" },\n  \"evenementen\": { type: \"event\" },\n  \"facebook\": { type: \"news\" },\n  \"flickr\": { type: \"image\" },\n  \"forecast\": { type: \"weather\", group: \"weather\" },\n  \"instagram\": { type: \"image\" },\n  \"maps\": { type: \"location\" },\n  \"nieuws\": { type: \"news\" },\n  \"people\": { type: \"people\" },\n  \"publications\": { type: \"publication\" },\n  \"serviceportal\": { type: \"serviceportal\" },\n  \"treinen\": { type: \"pubtrans\", group: \"train\" },\n  \"utoday\": { type: \"news\" },\n  \"vimeo\": { type: \"video\" },\n  \"youtube\": { type: \"video\" }\n};\n\n// Duplicate URL's from these sources are deduplicated in the order they are listed here (e.g. if a URL is returned by both\n// the 'people' and 'googlecustom' sources, only the 'people' result is kept)\nconst SEARSIA_DUPLICATE_RESOURCES =\n  [\"courses\", \"evenementen\", \"bravesearch\", \"nieuws\", \"people\", \"serviceportal\"];\n\n// These words are filtered out of the user's query\nconst QUERY_STOPWORDS =\n{\n  \"nl\": [\n    \"de\", \"een\", \"en\", \"het\", \"of\",\n    \"a\", \"an\", \"and\", \"or\", \"the\"\n  ],\n  \"en\": [\"a\", \"an\", \"and\", \"or\", \"the\"]\n};\n\nif (typeof module !== \"undefined\") {\n  module.exports.MIN_SUGGEST_LENGTH = MIN_SUGGEST_LENGTH;\n  module.exports.NUM_SUGGESTIONS = NUM_SUGGESTIONS;\n  module.exports.NUM_RELATED = NUM_RELATED;\n  module.exports.SEARSIA_SOURCES = SEARSIA_SOURCES;\n  module.exports.SEARSIA_DUPLICATE_RESOURCES = SEARSIA_DUPLICATE_RESOURCES;\n  module.exports.QUERY_STOPWORDS = QUERY_STOPWORDS;\n}\n","// Copyright Joyent, Inc. and other Node contributors.\n//\n// Permission is hereby granted, free of charge, to any person obtaining a\n// copy of this software and associated documentation files (the\n// \"Software\"), to deal in the Software without restriction, including\n// without limitation the rights to use, copy, modify, merge, publish,\n// distribute, sublicense, and/or sell copies of the Software, and to permit\n// persons to whom the Software is furnished to do so, subject to the\n// following conditions:\n//\n// The above copyright notice and this permission notice shall be included\n// in all copies or substantial portions of the Software.\n//\n// THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS\n// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN\n// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,\n// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR\n// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE\n// USE OR OTHER DEALINGS IN THE SOFTWARE.\n\n'use strict';\n\nvar R = typeof Reflect === 'object' ? Reflect : null\nvar ReflectApply = R && typeof R.apply === 'function'\n  ? R.apply\n  : function ReflectApply(target, receiver, args) {\n    return Function.prototype.apply.call(target, receiver, args);\n  }\n\nvar ReflectOwnKeys\nif (R && typeof R.ownKeys === 'function') {\n  ReflectOwnKeys = R.ownKeys\n} else if (Object.getOwnPropertySymbols) {\n  ReflectOwnKeys = function ReflectOwnKeys(target) {\n    return Object.getOwnPropertyNames(target)\n      .concat(Object.getOwnPropertySymbols(target));\n  };\n} else {\n  ReflectOwnKeys = function ReflectOwnKeys(target) {\n    return Object.getOwnPropertyNames(target);\n  };\n}\n\nfunction ProcessEmitWarning(warning) {\n  if (console && console.warn) console.warn(warning);\n}\n\nvar NumberIsNaN = Number.isNaN || function NumberIsNaN(value) {\n  return value !== value;\n}\n\nfunction EventEmitter() {\n  EventEmitter.init.call(this);\n}\nmodule.exports = EventEmitter;\nmodule.exports.once = once;\n\n// Backwards-compat with node 0.10.x\nEventEmitter.EventEmitter = EventEmitter;\n\nEventEmitter.prototype._events = undefined;\nEventEmitter.prototype._eventsCount = 0;\nEventEmitter.prototype._maxListeners = undefined;\n\n// By default EventEmitters will print a warning if more than 10 listeners are\n// added to it. This is a useful default which helps finding memory leaks.\nvar defaultMaxListeners = 10;\n\nfunction checkListener(listener) {\n  if (typeof listener !== 'function') {\n    throw new TypeError('The \"listener\" argument must be of type Function. Received type ' + typeof listener);\n  }\n}\n\nObject.defineProperty(EventEmitter, 'defaultMaxListeners', {\n  enumerable: true,\n  get: function() {\n    return defaultMaxListeners;\n  },\n  set: function(arg) {\n    if (typeof arg !== 'number' || arg < 0 || NumberIsNaN(arg)) {\n      throw new RangeError('The value of \"defaultMaxListeners\" is out of range. It must be a non-negative number. Received ' + arg + '.');\n    }\n    defaultMaxListeners = arg;\n  }\n});\n\nEventEmitter.init = function() {\n\n  if (this._events === undefined ||\n      this._events === Object.getPrototypeOf(this)._events) {\n    this._events = Object.create(null);\n    this._eventsCount = 0;\n  }\n\n  this._maxListeners = this._maxListeners || undefined;\n};\n\n// Obviously not all Emitters should be limited to 10. This function allows\n// that to be increased. Set to zero for unlimited.\nEventEmitter.prototype.setMaxListeners = function setMaxListeners(n) {\n  if (typeof n !== 'number' || n < 0 || NumberIsNaN(n)) {\n    throw new RangeError('The value of \"n\" is out of range. It must be a non-negative number. Received ' + n + '.');\n  }\n  this._maxListeners = n;\n  return this;\n};\n\nfunction _getMaxListeners(that) {\n  if (that._maxListeners === undefined)\n    return EventEmitter.defaultMaxListeners;\n  return that._maxListeners;\n}\n\nEventEmitter.prototype.getMaxListeners = function getMaxListeners() {\n  return _getMaxListeners(this);\n};\n\nEventEmitter.prototype.emit = function emit(type) {\n  var args = [];\n  for (var i = 1; i < arguments.length; i++) args.push(arguments[i]);\n  var doError = (type === 'error');\n\n  var events = this._events;\n  if (events !== undefined)\n    doError = (doError && events.error === undefined);\n  else if (!doError)\n    return false;\n\n  // If there is no 'error' event listener then throw.\n  if (doError) {\n    var er;\n    if (args.length > 0)\n      er = args[0];\n    if (er instanceof Error) {\n      // Note: The comments on the `throw` lines are intentional, they show\n      // up in Node's output if this results in an unhandled exception.\n      throw er; // Unhandled 'error' event\n    }\n    // At least give some kind of context to the user\n    var err = new Error('Unhandled error.' + (er ? ' (' + er.message + ')' : ''));\n    err.context = er;\n    throw err; // Unhandled 'error' event\n  }\n\n  var handler = events[type];\n\n  if (handler === undefined)\n    return false;\n\n  if (typeof handler === 'function') {\n    ReflectApply(handler, this, args);\n  } else {\n    var len = handler.length;\n    var listeners = arrayClone(handler, len);\n    for (var i = 0; i < len; ++i)\n      ReflectApply(listeners[i], this, args);\n  }\n\n  return true;\n};\n\nfunction _addListener(target, type, listener, prepend) {\n  var m;\n  var events;\n  var existing;\n\n  checkListener(listener);\n\n  events = target._events;\n  if (events === undefined) {\n    events = target._events = Object.create(null);\n    target._eventsCount = 0;\n  } else {\n    // To avoid recursion in the case that type === \"newListener\"! Before\n    // adding it to the listeners, first emit \"newListener\".\n    if (events.newListener !== undefined) {\n      target.emit('newListener', type,\n                  listener.listener ? listener.listener : listener);\n\n      // Re-assign `events` because a newListener handler could have caused the\n      // this._events to be assigned to a new object\n      events = target._events;\n    }\n    existing = events[type];\n  }\n\n  if (existing === undefined) {\n    // Optimize the case of one listener. Don't need the extra array object.\n    existing = events[type] = listener;\n    ++target._eventsCount;\n  } else {\n    if (typeof existing === 'function') {\n      // Adding the second element, need to change to array.\n      existing = events[type] =\n        prepend ? [listener, existing] : [existing, listener];\n      // If we've already got an array, just append.\n    } else if (prepend) {\n      existing.unshift(listener);\n    } else {\n      existing.push(listener);\n    }\n\n    // Check for listener leak\n    m = _getMaxListeners(target);\n    if (m > 0 && existing.length > m && !existing.warned) {\n      existing.warned = true;\n      // No error code for this since it is a Warning\n      // eslint-disable-next-line no-restricted-syntax\n      var w = new Error('Possible EventEmitter memory leak detected. ' +\n                          existing.length + ' ' + String(type) + ' listeners ' +\n                          'added. Use emitter.setMaxListeners() to ' +\n                          'increase limit');\n      w.name = 'MaxListenersExceededWarning';\n      w.emitter = target;\n      w.type = type;\n      w.count = existing.length;\n      ProcessEmitWarning(w);\n    }\n  }\n\n  return target;\n}\n\nEventEmitter.prototype.addListener = function addListener(type, listener) {\n  return _addListener(this, type, listener, false);\n};\n\nEventEmitter.prototype.on = EventEmitter.prototype.addListener;\n\nEventEmitter.prototype.prependListener =\n    function prependListener(type, listener) {\n      return _addListener(this, type, listener, true);\n    };\n\nfunction onceWrapper() {\n  if (!this.fired) {\n    this.target.removeListener(this.type, this.wrapFn);\n    this.fired = true;\n    if (arguments.length === 0)\n      return this.listener.call(this.target);\n    return this.listener.apply(this.target, arguments);\n  }\n}\n\nfunction _onceWrap(target, type, listener) {\n  var state = { fired: false, wrapFn: undefined, target: target, type: type, listener: listener };\n  var wrapped = onceWrapper.bind(state);\n  wrapped.listener = listener;\n  state.wrapFn = wrapped;\n  return wrapped;\n}\n\nEventEmitter.prototype.once = function once(type, listener) {\n  checkListener(listener);\n  this.on(type, _onceWrap(this, type, listener));\n  return this;\n};\n\nEventEmitter.prototype.prependOnceListener =\n    function prependOnceListener(type, listener) {\n      checkListener(listener);\n      this.prependListener(type, _onceWrap(this, type, listener));\n      return this;\n    };\n\n// Emits a 'removeListener' event if and only if the listener was removed.\nEventEmitter.prototype.removeListener =\n    function removeListener(type, listener) {\n      var list, events, position, i, originalListener;\n\n      checkListener(listener);\n\n      events = this._events;\n      if (events === undefined)\n        return this;\n\n      list = events[type];\n      if (list === undefined)\n        return this;\n\n      if (list === listener || list.listener === listener) {\n        if (--this._eventsCount === 0)\n          this._events = Object.create(null);\n        else {\n          delete events[type];\n          if (events.removeListener)\n            this.emit('removeListener', type, list.listener || listener);\n        }\n      } else if (typeof list !== 'function') {\n        position = -1;\n\n        for (i = list.length - 1; i >= 0; i--) {\n          if (list[i] === listener || list[i].listener === listener) {\n            originalListener = list[i].listener;\n            position = i;\n            break;\n          }\n        }\n\n        if (position < 0)\n          return this;\n\n        if (position === 0)\n          list.shift();\n        else {\n          spliceOne(list, position);\n        }\n\n        if (list.length === 1)\n          events[type] = list[0];\n\n        if (events.removeListener !== undefined)\n          this.emit('removeListener', type, originalListener || listener);\n      }\n\n      return this;\n    };\n\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\n\nEventEmitter.prototype.removeAllListeners =\n    function removeAllListeners(type) {\n      var listeners, events, i;\n\n      events = this._events;\n      if (events === undefined)\n        return this;\n\n      // not listening for removeListener, no need to emit\n      if (events.removeListener === undefined) {\n        if (arguments.length === 0) {\n          this._events = Object.create(null);\n          this._eventsCount = 0;\n        } else if (events[type] !== undefined) {\n          if (--this._eventsCount === 0)\n            this._events = Object.create(null);\n          else\n            delete events[type];\n        }\n        return this;\n      }\n\n      // emit removeListener for all listeners on all events\n      if (arguments.length === 0) {\n        var keys = Object.keys(events);\n        var key;\n        for (i = 0; i < keys.length; ++i) {\n          key = keys[i];\n          if (key === 'removeListener') continue;\n          this.removeAllListeners(key);\n        }\n        this.removeAllListeners('removeListener');\n        this._events = Object.create(null);\n        this._eventsCount = 0;\n        return this;\n      }\n\n      listeners = events[type];\n\n      if (typeof listeners === 'function') {\n        this.removeListener(type, listeners);\n      } else if (listeners !== undefined) {\n        // LIFO order\n        for (i = listeners.length - 1; i >= 0; i--) {\n          this.removeListener(type, listeners[i]);\n        }\n      }\n\n      return this;\n    };\n\nfunction _listeners(target, type, unwrap) {\n  var events = target._events;\n\n  if (events === undefined)\n    return [];\n\n  var evlistener = events[type];\n  if (evlistener === undefined)\n    return [];\n\n  if (typeof evlistener === 'function')\n    return unwrap ? [evlistener.listener || evlistener] : [evlistener];\n\n  return unwrap ?\n    unwrapListeners(evlistener) : arrayClone(evlistener, evlistener.length);\n}\n\nEventEmitter.prototype.listeners = function listeners(type) {\n  return _listeners(this, type, true);\n};\n\nEventEmitter.prototype.rawListeners = function rawListeners(type) {\n  return _listeners(this, type, false);\n};\n\nEventEmitter.listenerCount = function(emitter, type) {\n  if (typeof emitter.listenerCount === 'function') {\n    return emitter.listenerCount(type);\n  } else {\n    return listenerCount.call(emitter, type);\n  }\n};\n\nEventEmitter.prototype.listenerCount = listenerCount;\nfunction listenerCount(type) {\n  var events = this._events;\n\n  if (events !== undefined) {\n    var evlistener = events[type];\n\n    if (typeof evlistener === 'function') {\n      return 1;\n    } else if (evlistener !== undefined) {\n      return evlistener.length;\n    }\n  }\n\n  return 0;\n}\n\nEventEmitter.prototype.eventNames = function eventNames() {\n  return this._eventsCount > 0 ? ReflectOwnKeys(this._events) : [];\n};\n\nfunction arrayClone(arr, n) {\n  var copy = new Array(n);\n  for (var i = 0; i < n; ++i)\n    copy[i] = arr[i];\n  return copy;\n}\n\nfunction spliceOne(list, index) {\n  for (; index + 1 < list.length; index++)\n    list[index] = list[index + 1];\n  list.pop();\n}\n\nfunction unwrapListeners(arr) {\n  var ret = new Array(arr.length);\n  for (var i = 0; i < ret.length; ++i) {\n    ret[i] = arr[i].listener || arr[i];\n  }\n  return ret;\n}\n\nfunction once(emitter, name) {\n  return new Promise(function (resolve, reject) {\n    function errorListener(err) {\n      emitter.removeListener(name, resolver);\n      reject(err);\n    }\n\n    function resolver() {\n      if (typeof emitter.removeListener === 'function') {\n        emitter.removeListener('error', errorListener);\n      }\n      resolve([].slice.call(arguments));\n    };\n\n    eventTargetAgnosticAddListener(emitter, name, resolver, { once: true });\n    if (name !== 'error') {\n      addErrorHandlerIfEventEmitter(emitter, errorListener, { once: true });\n    }\n  });\n}\n\nfunction addErrorHandlerIfEventEmitter(emitter, handler, flags) {\n  if (typeof emitter.on === 'function') {\n    eventTargetAgnosticAddListener(emitter, 'error', handler, flags);\n  }\n}\n\nfunction eventTargetAgnosticAddListener(emitter, name, listener, flags) {\n  if (typeof emitter.on === 'function') {\n    if (flags.once) {\n      emitter.once(name, listener);\n    } else {\n      emitter.on(name, listener);\n    }\n  } else if (typeof emitter.addEventListener === 'function') {\n    // EventTarget does not have `error` event semantics like Node\n    // EventEmitters, we do not listen for `error` events here.\n    emitter.addEventListener(name, function wrapListener(arg) {\n      // IE does not have builtin `{ once: true }` support so we\n      // have to do it manually.\n      if (flags.once) {\n        emitter.removeEventListener(name, wrapListener);\n      }\n      listener(arg);\n    });\n  } else {\n    throw new TypeError('The \"emitter\" argument must be of type EventEmitter. Received type ' + typeof emitter);\n  }\n}\n","/* eslint-disable */\n/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\nimport * as dompack from 'dompack';\nconst EventEmitter = require('events');\n\nclass InternetRequester extends EventEmitter {\n  constructor(options) {\n    super();\n    if (!options)\n      options = {};\n    //Host url of event server\n    this.options = {\n      url: options.url || '',\n      log: Boolean(options.log || dompack.debugflags.rpc),\n      withcredentials: 'withCredentials' in options && options.withcredentials\n    };\n\n    // XMLHttpRequest\n    this.conn = null;\n\n    // used for estimating the server date\n    this.__date_server = null;\n    this.__date_client = null;\n    this.__date_diff = null;\n  }\n\n  destroy() {\n    this.stopCurrentRequest();\n    this.conn = null;\n  }\n\n  stopCurrentRequest() {\n    if (this.conn) {\n      this.conn.onreadystatechange = null;\n      this.conn.onloadend = null;\n\n      this.conn.abort();\n    }\n    if (this.jsoncheckinterval) {\n      clearTimeout(this.jsoncheckinterval);\n      this.jsoncheckinterval = null;\n    }\n  }\n\n  ensureConnection() {\n    if (!this.conn)\n      this.conn = new XMLHttpRequest();\n  }\n\n  startXMLHTTPRequest(method, url, body, options) {\n    this.ensureConnection();\n\n    const async = !options || !options.synchronous;\n\n    // Because aborting the connection may result in a readystatechange event (yes, we're looking at you, Titanium's\n    // TiNetworkHTTPClient...), we have to reset the have_response flag _after_ aborting the connection, so the response for\n    // the previous request isn't used for the new request\n\n    this.laststateevent = null; //make sure we don't accidentally cancel the previous request\n    this.conn.abort();\n    this.have_response = false;\n\n    this.conn.open(method.toUpperCase(), url, async);\n    if (options && options.headers)\n      Object.keys(options.headers).forEach(key => { this.conn.setRequestHeader(key, options.headers[key]); });\n\n    if (this.options.withcredentials)\n      this.conn.withCredentials = true;\n\n    this.conn.onreadystatechange = this.onStateChange.bind(this);\n    // Required for Firefox 12 (+firebug?), without it statechange to 4 doesn't seem to be fired sometimes\n    this.conn.onloadend = this.onStateChange.bind(this);\n    this.conn.onabort = this.onAbort.bind(this);\n\n    this.emit(\"requeststart\", { target: this });\n    this.conn.send(body);\n\n    if (!async)\n      this.onStateChange();\n  }\n\n  onAbort(event) {\n    if (this.laststateevent)\n      this.laststateevent.isaborted = true;\n  }\n\n  onStateChange(event) {\n    if (this.conn.readyState !== 4 || this.have_response)\n      return;\n\n    this.have_response = true;\n\n    const datestr = this.conn.getResponseHeader(\"date\");\n    if (datestr !== \"\") {\n      const parseddate = Date.parse(datestr);\n      this.__date_server = parseddate;\n      this.__date_client = new Date();\n      this.__date_diff = this.__date_server - this.__date_client;\n    }\n\n    const evt = {\n      target: this,\n      success: this.conn.status === 200,\n      internalerror: this.conn.status === 500,\n      message: this.conn.status,\n\n      responsetext: this.conn.responseText,\n      responsejson: null\n    };\n\n    //FIXME only decode JSON data if the mimetype specified it was JSON, and then log any errors\n    try {\n      evt.responsejson = JSON.parse(evt.responsetext);\n    } catch (e) {\n    }\n\n    this.laststateevent = evt;\n    this.emit(\"requestend\", evt);\n  }\n}\n\nmodule.exports = InternetRequester;\n","/* eslint-disable */\n/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\n/** @require: var JSONRPC = require('@mod-system/js/net/jsonrpc')\n*/\nconst InternetRequester = require('./requester');\nimport { isLive } from \"@webhare/env\";\nimport * as dompack from 'dompack';\n\nconst rpcscriptid = Math.floor(Math.random() * 1000);\n\nclass JSONRPC extends InternetRequester {\n  /** @short RPC status codes (defined as getter-only properties as long as we don't have static const properties) */\n  static get HTTP_ERROR() { return -1; } // Error connecting to the RPC server\n  static get JSON_ERROR() { return -2; } // The returned value could not be decoded into a JSON object\n  static get PROTOCOL_ERROR() { return -3; } // The return object did not contain an id, or the id did not match the request id\n  static get RPC_ERROR() { return -4; } // The RPC returned an error\n  static get OFFLINE_ERROR() { return -5; } // The application is not online (only returned if the onlineonly option was set)\n  static get TIMEOUT_ERROR() { return -6; } // The request could not be sent or was not answered before within the timeout set in the options\n  static get SERVER_ERROR() { return -7; } // The server encountered an internal error\n\n  constructor(options) {\n    super(options);\n    if (!options)\n      options = {};\n\n    this.lastid = 0;\n    this.requestqueue = [];\n    this.cachecounter = 0;\n    this.activerequest = null;\n    this.haveresponse = false;\n    //timeout after which we trigger a 'wait' action, eg a spinner\n    this.options.waittimeout = 'waittimeout' in options ? options.waittimeout : 500;\n    this.options.appendfunctionname = 'appendfunctionname' in options ? options.appendfunctionname : false;\n    this.waitcallback = null;\n    this.waittimeoutid = null;\n    this.waitingnow = false;\n\n    this.on(\"requestend\", this.onResponse.bind(this));\n  }\n\n  destroy() {\n    super.destroy();\n    this.requestqueue = [];\n    this.activerequest = null;\n\n    if (this.waittimeoutid) {\n      clearTimeout(this.waittimeoutid);\n      this.waittimeoutid = null;\n    }\n  }\n\n  promiseRequest(method, params, options) {\n    const deferred = Promise.withResolvers();\n    const req = this.request(method, params, deferred.resolve, (errorcode, errormsg, rpcid) => { deferred.reject(new Error(errormsg)); }, options);\n    deferred.promise.__jsonrpcinfo = { deferred, req };\n    return deferred.promise;\n  }\n  async(method, ...params) {\n    return this.promiseRequest(method, params);\n  }\n\n  _doAsyncAbort(promise, result, rejection) {\n    if (!promise.__jsonrpcinfo)\n      throw new Error(\"The promise is not an async JSONRPC request\");\n    if (!rejection)\n      promise.__jsonrpcinfo.deferred.resolve(result);\n    else\n      promise.__jsonrpcinfo.deferred.reject(rejection);\n    promise.__jsonrpcinfo.req.cancel();\n  }\n\n  rpcResolve(promise, result) {\n    this._doAsyncAbort(promise, result);\n  }\n  rpcReject(promise, rejection) {\n    this._doAsyncAbort(promise, null, rejection);\n  }\n\n\n  /**\n   * @short Queue an RPC request\n   * @param method The RPC method to call\n   * @param params Params for the RPC method\n   * @param callback The callback which is called, with:\n   *                 param status A JSONRPC. value\n   *                 param result The result object as sent by the RPC, or an error message string sent by the RPC, or an error\n   *                              message\n   *                 param id The request id\n   * @param options Options\n   * @param options.url The URL to connect to\n   * @param options.timeout Timeout in ms after which the request will fail (callback is called with ERROR_TIMEOUT error)\n   * @param options.waittimeout Timeout in ms after which the request will set waiting status to TRUE (via the waitCallback)\n   *                Set negative to not trigger waiting status.\n   * @return The request id\n   */\n  request(method, params, onsuccess, onfailure, options) {\n    if (!params || typeof params !== \"object\" || params.length === undefined)\n      throw new Error(\"The parameters passed to request must be an Array\");\n\n    const id = ++this.lastid;\n\n    let url;\n    if (options && options.url)\n      url = options.url + (options.appendfunctionname ? (options.url.match(/\\/$/) ? '' : '/') + method : '');\n    else if (this.options.url)\n      url = this.options.url + (this.options.appendfunctionname ? (this.options.url.match(/\\/$/) ? '' : '/') + method : '');\n    else\n      url = location.href; //we do not support appendfunctionname for self-posts\n\n    const timeout = Math.max((options && typeof options.timeout === \"number\") ? options.timeout : 0, 0);\n    const waittimeout = (options && typeof options.waittimeout === \"number\") ? options.waittimeout : this.options.waittimeout;\n    const synchronous = options && options.synchronous || false;\n    const errortrace = options && options.errortrace || null;\n\n    if (this.options.log)\n      console.log(\"JSONRPC request\", method, params, options, 'timeout:', timeout, 'waitTimeout:', waittimeout);\n\n    const request = new Request(this, id, method, params, url, timeout, waittimeout, onsuccess, onfailure, synchronous, errortrace);\n    if (this.options.log || !isLive)\n      request.stack = new Error().stack;\n\n    this.requestqueue.push(request);\n    if (this.options.log)\n      console.log(\"JSONRPC request is on queue\");\n    this.processNextRequest();\n    return request;\n  }\n\n  handleError(onfailure, errorcode, errormsg, rpcid) {\n    if (onfailure)\n      setTimeout(() => onfailure(errorcode, errormsg, rpcid), 0);\n\n    setTimeout(() => this.emit([\"error\", { target: this, errorcode: errorcode, errormessage: errormsg, rpcid: rpcid }]), 0);\n  }\n\n  //is a json request pending?\n  isRequestPending() {\n    return this.activerequest !== null || this.requestqueue.length;\n  }\n\n  //ADDME is it possible for the 'next' response to already be .delay/setTimeout() scheduled, racing against our cancel ?\n  __cancelRequest(id) {\n    if (typeof id !== 'number')\n      return;\n\n    if (this.activerequest === id) {\n      this.stopCurrentRequest();\n      this.activerequest = null;\n\n      const request = this.requestqueue.shift();\n      if (request.timeout && typeof request.timeout !== \"boolean\")\n        clearTimeout(request.timeout);\n\n      this.processNextRequest();\n    } else {\n      for (let i = 0; i < this.requestqueue.length; ++i)\n        if (this.requestqueue[i].id === id) {\n          this.requestqueue.splice(i, 1);\n          break;\n        }\n    }\n  }\n\n  processNextRequest() {\n    if (this.activerequest) {\n      if (this.options.log)\n        console.log(\"JSONRPC request #\" + this.activerequest + \" pending, not scheduling a new one yet\");\n      this.handleWaitTimeouts();\n      return;\n    }\n\n    let request = null;\n    while (!request) {\n      request = this.requestqueue[0];\n      if (!request) {\n        if (this.options.log)\n          console.log(\"JSONRPC request - processNextRequest, queue is empty\");\n        return;\n      }\n      if (request.timeout && typeof request.timeout === \"boolean\") {\n        this.requestqueue = this.requestqueue.filter(el => el !== request);\n        request = this.requestqueue[0];\n      }\n    }\n\n    this.activerequest = request.id;\n\n    if (request.timeout)\n      request.timeout = setTimeout(() => this.onTimeout(request), request.timeout);\n\n    if (this.options.log)\n      console.log(\"JSONRPC request #\" + request.id + \" offering for XMLHTTP\");\n    this.startXMLHTTPRequest(\n      \"post\",\n      request.url,\n      JSON.stringify(request.request),\n      {\n        headers: { \"Content-Type\": \"application/json; charset=utf-8\" },\n        synchronous: request.synchronous\n      });\n    this.handleWaitTimeouts();\n  }\n\n  onResponse(event) {\n    this.activerequest = null;\n\n    const request = this.requestqueue[0];\n    if (!request)\n      return;\n\n    this.requestqueue = this.requestqueue.slice(1);\n\n    if (request.timeout) {\n      if (typeof request.timeout === \"boolean\") {\n        this.processNextRequest();\n        return;\n      }\n      clearTimeout(request.timeout);\n    }\n\n    let status = -1;\n    let result = null;\n\n    if (!event.success) {\n      status = JSONRPC.HTTP_ERROR;\n      result = \"HTTP Error: \" + event.message;\n\n      if (event.internalerror) {\n        let json = null;\n        try {\n          json = event.responsejson;\n          let trace;\n          if (json && json.error && json.error.data) {\n            trace = json.error.data.trace || json.error.data.errors || json.error.data.list || [];\n\n            console.group();\n            const line = \"RPC #\" + rpcscriptid + \":\" + request.id + \" failed: \" + json.error.message;\n            console.warn(line);\n            if (request.errortrace)\n              request.errortrace.push(line);\n            trace.forEach(rec => {\n              if (rec.filename || rec.line) {\n                const line = rec.filename + '#' + rec.line + '#' + rec.col + (rec.func ? ' (' + rec.func + ')' : '');\n                console.warn(line);\n                if (request.errortrace)\n                  request.errortrace.push(line);\n              }\n            });\n            console.groupEnd();\n          }\n          status = JSONRPC.SERVER_ERROR;\n          result = json.error && `${json.error.message} from ${request.url}` || \"Unknown error\";\n        } catch (e) {\n        }\n      }\n    } else {\n      const json = event.responsejson;\n\n      if (!json) {\n        status = JSONRPC.JSON_ERROR;\n        result = \"Invalid JSON response\";\n      } else if (json.id === null || json.id !== request.id) {\n        status = JSONRPC.PROTOCOL_ERROR;\n        result = \"Protocol error: invalid id\";\n      } else if (json.error !== null) {\n        status = JSONRPC.RPC_ERROR;\n        result = json.error;\n        if (this.options.log)\n          console.log('RPC error:', result.message ? result.message : '*no message*');\n      } else if (\"result\" in json) {\n        status = 0;\n        result = json.result;\n      } else {\n        status = JSONRPC.PROTOCOL_ERROR;\n        result = \"Could not interpret response\";\n      }\n    }\n\n    this.processNextRequest();\n\n    if (this.options.log) {\n      console.log(\"JSONRPC request\", request.request.method, 'status:', status, 'time:', (new Date).getTime() - request.scheduled, 'ms, result:');\n      console.log(result);\n    }\n\n    /*\n    console.log({ serverdate: this.__date_server\n                , clientdate: this.__date_client\n                , diff: this.__date_diff\n                });\n    */\n    setTimeout(() => request.__completedCall(status, result, event), 0);\n  }\n\n  onTimeout(request) {\n    request.timeout = true;\n    if (this.activerequest === request.id) {\n      this.activerequest = null;\n      this.stopCurrentRequest();\n      this.processNextRequest();\n    }\n    this.handleError(request.onfailure, JSONRPC.TIMEOUT_ERROR, \"Timeout while waiting for response\", request.id);\n  }\n\n  onWaitTimeout() {\n    this.waittimeoutid = null;\n    this.handleWaitTimeouts();\n  }\n\n  handleWaitTimeouts() {\n    if (this.waittimeoutid) {\n      clearTimeout(this.waittimeoutid);\n      this.waittimeoutid = null;\n    }\n\n    if (!this.waitCallback)\n      return;\n\n    let waiting = false;\n    let nextTimeout = -1;\n\n    const now = (new Date).getTime();\n    for (let i = 0; i < this.requestqueue.length; ++i) {\n      const req = this.requestqueue[i];\n      if (req.waitTimeout >= 0) {\n        const waitLength = now - req.scheduled;\n\n        if (waitLength >= req.waitTimeout)\n          waiting = true;\n        else {\n          const toGo = req.waitTimeout - waitLength;\n          if (nextTimeout < 0 || nextTimeout > toGo)\n            nextTimeout = toGo;\n        }\n      }\n    }\n\n    if (this.waitingNow !== waiting) {\n      this.waitingNow = waiting;\n      setTimeout(() => this.waitCallback(waiting), 0);\n    }\n\n    if (nextTimeout >= 0)\n      this.waittimeoutid = setTimeout(() => this.onWaitTimeout(), nextTimeout);\n  }\n\n  getEstimatedServerTime() {\n    return new Date().getTime() + this.__date_diff;\n  }\n\n  /** @short estimate the server's datetime based on the known descrepancy between the date of an reponse from the server and the time on the client\n  */\n  getEstimatedServerDate() {\n    return new Date(this.getEstimatedServerTime());\n  }\n}\n\nclass Request //extends PreloadableAsset\n{\n  constructor(parent, id, method, params, url, timeout, waittimeout, onsuccess, onfailure, synchronous, errortrace) {\n    //    super();\n\n    this.cancelled = false;\n    this.stack = null;\n\n    if (parent.options.log)\n      console.log('req', this);\n    this.parent = parent;\n    this.id = id;\n    this.request = {\n      id: id,\n      method: method,\n      params: params || []\n    };\n    this.url = url;\n    this.onsuccess = onsuccess;\n    this.onfailure = onfailure;\n    this.timeout = timeout;\n    this.scheduled = new Date - 0;\n    this.waittimeout = waittimeout;\n    this.synchronous = synchronous;\n    this.errortrace = errortrace;\n\n    //this.startPreload();\n  }\n  onStartPreload() {\n\n  }\n  cancel() {\n    //we need to prevent a race when our parent invokes cancel(), but we actually had our __completedCall already queued up. if we still fire onsuccess/onfailure, our parent might think we completed the _next_ request our parent submitted\n    this.cancelled = true;\n    this.parent.__cancelRequest(this.id);\n  }\n\n  __completedCall(status, result, event) {\n    if (event.isaborted)\n      this.cancelled = true;\n\n    if (status === 0) {\n      if (this.onsuccess && !this.cancelled)\n        this.onsuccess(result);\n      //this.donePreload(true);\n    } else {\n      if (!this.cancelled) {\n        if (this.stack) {\n          console.log(\"Stack at calling point:\");\n          console.log(this.stack);\n        }\n        this.parent.handleError(this.onfailure, status, result, this.id);\n      }\n      //this.donePreload(false);\n    }\n  }\n}\n\nmodule.exports = JSONRPC;\n","/*! iScroll v5.2.0 ~ (c) 2008-2016 Matteo Spinelli ~ http://cubiq.org/license */\n\n/*\n\n!!!!! For Chrome 55 (on Touch devices/Android) iScroll will use pointer events instead of touch events.\n      However this ONLY WORKS if the element has touch-action: none;\n\n\nModifications made:\n- options and code to allow for an endless scroll without iScroll performing any DOM/style interactions\n- tap event will pass the source (mouse or touch) of the event\n- patch from RByers from https://github.com/cubiq/iscroll/issues/1100 to fix scrolling on Android breaking\n\n*/\n\n(function (window, document, Math) {\nvar rAF = window.requestAnimationFrame  ||\n  window.webkitRequestAnimationFrame  ||\n  window.mozRequestAnimationFrame   ||\n  window.oRequestAnimationFrame   ||\n  window.msRequestAnimationFrame    ||\n  function (callback) { window.setTimeout(callback, 1000 / 60); };\n\nvar utils = (function () {\n  var me = {};\n\n  var _elementStyle = document.createElement('div').style;\n  var _vendor = (function () {\n    var vendors = ['t', 'webkitT', 'MozT', 'msT', 'OT'],\n      transform,\n      i = 0,\n      l = vendors.length;\n\n    for ( ; i < l; i++ ) {\n      transform = vendors[i] + 'ransform';\n      if ( transform in _elementStyle ) return vendors[i].substr(0, vendors[i].length-1);\n    }\n\n    return false;\n  })();\n\n  function _prefixStyle (style) {\n    if ( _vendor === false ) return false;\n    if ( _vendor === '' ) return style;\n    return _vendor + style.charAt(0).toUpperCase() + style.substr(1);\n  }\n\n  me.getTime = Date.now || function getTime () { return new Date().getTime(); };\n\n  me.extend = function (target, obj) {\n    for ( var i in obj ) {\n      target[i] = obj[i];\n    }\n  };\n\n  me.addEvent = function (el, type, fn, capture) {\n    el.addEventListener(type, fn, !!capture);\n  };\n\n  me.removeEvent = function (el, type, fn, capture) {\n    el.removeEventListener(type, fn, !!capture);\n  };\n\n  me.prefixPointerEvent = function (pointerEvent) {\n    return window.MSPointerEvent ?\n      'MSPointer' + pointerEvent.charAt(7).toUpperCase() + pointerEvent.substr(8):\n      pointerEvent;\n  };\n\n  //(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration)\n  me.momentum = function (current, start, time, lowerMargin, wrapperSize, deceleration) {\n    var distance = current - start,\n      speed = Math.abs(distance) / time,\n      destination,\n      duration;\n\n    deceleration = deceleration === undefined ? 0.0006 : deceleration;\n\n    destination = current + ( speed * speed ) / ( 2 * deceleration ) * ( distance < 0 ? -1 : 1 );\n    duration = speed / deceleration;\n\n    if ( destination < lowerMargin ) {\n      destination = wrapperSize ? lowerMargin - ( wrapperSize / 2.5 * ( speed / 8 ) ) : lowerMargin;\n      distance = Math.abs(destination - current);\n      duration = distance / speed;\n    } else if ( destination > 0 ) {\n      destination = wrapperSize ? wrapperSize / 2.5 * ( speed / 8 ) : 0;\n      distance = Math.abs(current) + destination;\n      duration = distance / speed;\n    }\n\n    return {\n      destination: Math.round(destination),\n      duration: duration\n    };\n  };\n\n  var _transform = _prefixStyle('transform');\n\n  me.extend(me, {\n    hasTransform: _transform !== false,\n    hasPerspective: _prefixStyle('perspective') in _elementStyle,\n    hasTouch: 'ontouchstart' in window,\n    hasPointer: !!(window.PointerEvent || window.MSPointerEvent), // IE10 is prefixed\n    hasTransition: _prefixStyle('transition') in _elementStyle\n  });\n\n  /*\n  This should find all Android browsers lower than build 535.19 (both stock browser and webview)\n  - galaxy S2 is ok\n    - 2.3.6 : `AppleWebKit/533.1 (KHTML, like Gecko) Version/4.0 Mobile Safari/533.1`\n    - 4.0.4 : `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`\n   - galaxy S3 is badAndroid (stock brower, webview)\n     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`\n   - galaxy S4 is badAndroid (stock brower, webview)\n     `AppleWebKit/534.30 (KHTML, like Gecko) Version/4.0 Mobile Safari/534.30`\n   - galaxy S5 is OK\n     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`\n   - galaxy S6 is OK\n     `AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Mobile Safari/537.36 (Chrome/)`\n  */\n  me.isBadAndroid = (function() {\n    var appVersion = window.navigator.appVersion;\n    // Android browser is not a chrome browser.\n    if (/Android/.test(appVersion) && !(/Chrome\\/\\d/.test(appVersion))) {\n      var safariVersion = appVersion.match(/Safari\\/(\\d+.\\d)/);\n      if(safariVersion && typeof safariVersion === \"object\" && safariVersion.length >= 2) {\n        return parseFloat(safariVersion[1]) < 535.19;\n      } else {\n        return true;\n      }\n    } else {\n      return false;\n    }\n  })();\n\n  me.extend(me.style = {}, {\n    transform: _transform,\n    transitionTimingFunction: _prefixStyle('transitionTimingFunction'),\n    transitionDuration: _prefixStyle('transitionDuration'),\n    transitionDelay: _prefixStyle('transitionDelay'),\n    transformOrigin: _prefixStyle('transformOrigin')\n  });\n\n  me.hasClass = function (e, c) {\n    var re = new RegExp(\"(^|\\\\s)\" + c + \"(\\\\s|$)\");\n    return re.test(e.className);\n  };\n\n  me.addClass = function (e, c) {\n    if ( me.hasClass(e, c) ) {\n      return;\n    }\n\n    var newclass = e.className.split(' ');\n    newclass.push(c);\n    e.className = newclass.join(' ');\n  };\n\n  me.removeClass = function (e, c) {\n    if ( !me.hasClass(e, c) ) {\n      return;\n    }\n\n    var re = new RegExp(\"(^|\\\\s)\" + c + \"(\\\\s|$)\", 'g');\n    e.className = e.className.replace(re, ' ');\n  };\n\n  me.offset = function (el) {\n    var left = -el.offsetLeft,\n      top = -el.offsetTop;\n\n    // jshint -W084\n    while (el = el.offsetParent) {\n      left -= el.offsetLeft;\n      top -= el.offsetTop;\n    }\n    // jshint +W084\n\n    return {\n      left: left,\n      top: top\n    };\n  };\n\n  me.preventDefaultException = function (el, exceptions) {\n    for ( var i in exceptions ) {\n      if ( exceptions[i].test(el[i]) ) {\n        return true;\n      }\n    }\n\n    return false;\n  };\n\n  me.extend(me.eventType = {}, {\n    touchstart: 1,\n    touchmove: 1,\n    touchend: 1,\n\n    mousedown: 2,\n    mousemove: 2,\n    mouseup: 2,\n\n    pointerdown: 3,\n    pointermove: 3,\n    pointerup: 3,\n\n    MSPointerDown: 3,\n    MSPointerMove: 3,\n    MSPointerUp: 3\n  });\n\n  me.extend(me.ease = {}, {\n    quadratic: {\n      style: 'cubic-bezier(0.25, 0.46, 0.45, 0.94)',\n      fn: function (k) {\n        return k * ( 2 - k );\n      }\n    },\n    circular: {\n      style: 'cubic-bezier(0.1, 0.57, 0.1, 1)', // Not properly \"circular\" but this looks better, it should be (0.075, 0.82, 0.165, 1)\n      fn: function (k) {\n        return Math.sqrt( 1 - ( --k * k ) );\n      }\n    },\n    back: {\n      style: 'cubic-bezier(0.175, 0.885, 0.32, 1.275)',\n      fn: function (k) {\n        var b = 4;\n        return ( k = k - 1 ) * k * ( ( b + 1 ) * k + b ) + 1;\n      }\n    },\n    bounce: {\n      style: '',\n      fn: function (k) {\n        if ( ( k /= 1 ) < ( 1 / 2.75 ) ) {\n          return 7.5625 * k * k;\n        } else if ( k < ( 2 / 2.75 ) ) {\n          return 7.5625 * ( k -= ( 1.5 / 2.75 ) ) * k + 0.75;\n        } else if ( k < ( 2.5 / 2.75 ) ) {\n          return 7.5625 * ( k -= ( 2.25 / 2.75 ) ) * k + 0.9375;\n        } else {\n          return 7.5625 * ( k -= ( 2.625 / 2.75 ) ) * k + 0.984375;\n        }\n      }\n    },\n    elastic: {\n      style: '',\n      fn: function (k) {\n        var f = 0.22,\n          e = 0.4;\n\n        if ( k === 0 ) { return 0; }\n        if ( k == 1 ) { return 1; }\n\n        return ( e * Math.pow( 2, - 10 * k ) * Math.sin( ( k - f / 4 ) * ( 2 * Math.PI ) / f ) + 1 );\n      }\n    }\n  });\n//touch: e.type == \"touchend\"\n  me.tap = function (e, eventName) {\n    var ev = document.createEvent('Event');\n    ev.initEvent(eventName, true, true);\n//    ev.initCustomEvent(eventName, true, true, { touch: e.type == \"touchend\", mouse: e.type == \"mouseup\" });\n    ev.pageX = e.pageX;\n    ev.pageY = e.pageY;\n\n    ev.tapbytouch = e.type == \"touchend\"; // NOTE: should use initCustomEvent instead and pass details??(does this work in every target browser?)\n    ev.tapbymouse = e.type == \"mouseup\";\n\n    e.target.dispatchEvent(ev);\n  };\n\n  me.click = function (e) {\n    var target = e.target,\n      ev;\n\n    if ( !(/(SELECT|INPUT|TEXTAREA)/i).test(target.tagName) ) {\n      // https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/initMouseEvent\n      // initMouseEvent is deprecated.\n      ev = document.createEvent(window.MouseEvent ? 'MouseEvents' : 'Event');\n      ev.initEvent('click', true, true);\n      ev.view = e.view || window;\n      ev.detail = 1;\n      ev.screenX = target.screenX || 0;\n      ev.screenY = target.screenY || 0;\n      ev.clientX = target.clientX || 0;\n      ev.clientY = target.clientY || 0;\n      ev.ctrlKey = !!e.ctrlKey;\n      ev.altKey = !!e.altKey;\n      ev.shiftKey = !!e.shiftKey;\n      ev.metaKey = !!e.metaKey;\n      ev.button = 0;\n      ev.relatedTarget = null;\n      ev._constructed = true;\n      target.dispatchEvent(ev);\n    }\n  };\n\n  return me;\n})();\nfunction IScroll (el, options) {\n  this.wrapper = typeof el == 'string' ? document.querySelector(el) : el;\n  this.scroller = this.wrapper.children[0];\n  this.scrollerStyle = this.scroller.style;   // cache style for better performance\n\n  this.options = {\n\n    resizeScrollbars: true,\n\n    mouseWheelSpeed: 20,\n\n    snapThreshold: 0.334,\n\n// INSERT POINT: OPTIONS\n    disablePointer : !utils.hasPointer,\n    disableTouch : utils.hasPointer || !utils.hasTouch,\n    disableMouse : utils.hasPointer || utils.hasTouch,\n    startX: 0,\n    startY: 0,\n    scrollY: true,\n    directionLockThreshold: 5,\n    momentum: true,\n\n    bounce: true,\n    bounceTime: 600,\n    bounceEasing: '',\n\n    preventDefault: true,\n    preventDefaultException: { tagName: /^(INPUT|TEXTAREA|BUTTON|SELECT)$/ },\n\n    HWCompositing: true,\n    useTransition: true,\n    useTransform: true,\n    bindToWrapper: typeof window.onmousedown === \"undefined\",\n\n    autoUpdatePosition: true, // ADDED by Mark\n    overrideMeasurements: false // ADDED by Mark\n  };\n\n  for ( var i in options ) {\n    this.options[i] = options[i];\n  }\n\n  // Normalize options\n  this.translateZ = this.options.HWCompositing && utils.hasPerspective ? ' translateZ(0)' : '';\n\n  this.options.useTransition = utils.hasTransition && this.options.useTransition;\n  this.options.useTransform = utils.hasTransform && this.options.useTransform;\n\n  this.options.eventPassthrough = this.options.eventPassthrough === true ? 'vertical' : this.options.eventPassthrough;\n  this.options.preventDefault = !this.options.eventPassthrough && this.options.preventDefault;\n\n  // If you want eventPassthrough I have to lock one of the axes\n  this.options.scrollY = this.options.eventPassthrough == 'vertical' ? false : this.options.scrollY;\n  this.options.scrollX = this.options.eventPassthrough == 'horizontal' ? false : this.options.scrollX;\n\n  // With eventPassthrough we also need lockDirection mechanism\n  this.options.freeScroll = this.options.freeScroll && !this.options.eventPassthrough;\n  this.options.directionLockThreshold = this.options.eventPassthrough ? 0 : this.options.directionLockThreshold;\n\n  this.options.bounceEasing = typeof this.options.bounceEasing == 'string' ? utils.ease[this.options.bounceEasing] || utils.ease.circular : this.options.bounceEasing;\n\n  this.options.resizePolling = this.options.resizePolling === undefined ? 60 : this.options.resizePolling;\n\n  if ( this.options.tap === true ) {\n    this.options.tap = 'tap';\n  }\n\n  // https://github.com/cubiq/iscroll/issues/1029\n  if (!this.options.useTransition && !this.options.useTransform) {\n    if(!(/relative|absolute/i).test(this.scrollerStyle.position)) {\n      this.scrollerStyle.position = \"relative\";\n    }\n  }\n\n  if ( this.options.shrinkScrollbars == 'scale' ) {\n    this.options.useTransition = false;\n  }\n\n  this.options.invertWheelDirection = this.options.invertWheelDirection ? -1 : 1;\n\n// INSERT POINT: NORMALIZATION\n\n\n  // ADDED by Mark de Jong\n  if (options.overrideMeasurements)\n  {\n    this.wrapperWidth = options.wrapperWidth;\n    this.scrollerWidth = options.scrollerWidth;\n    this.maxScrollX = -options.maxScrollX;\n\n    this.hasHorizontalScroll  = options.scrollX && this.maxScrollX < 0;\n    this.hasVerticalScroll    = options.scrollY && this.maxScrollY < 0;\n\n    //console.log(\"overrideMeasurements\", this.hasHorizontalScroll, this.hasVerticalScroll);\n  }\n\n\n  // Some defaults\n  this.x = 0;\n  this.y = 0;\n  this.directionX = 0;\n  this.directionY = 0;\n  this._events = {};\n\n// INSERT POINT: DEFAULTS\n\n  this._init();\n  this.refresh();\n\n  this.scrollTo(this.options.startX, this.options.startY);\n  this.enable();\n}\n\nIScroll.prototype = {\n  version: '5.2.0',\n\n  _init: function () {\n    this._initEvents();\n\n    if ( this.options.scrollbars || this.options.indicators ) {\n      this._initIndicators();\n    }\n\n    if ( this.options.mouseWheel ) {\n      this._initWheel();\n    }\n\n    if ( this.options.snap ) {\n      this._initSnap();\n    }\n\n    if ( this.options.keyBindings ) {\n      this._initKeys();\n    }\n\n// INSERT POINT: _init\n\n  },\n\n  destroy: function () {\n    this._initEvents(true);\n    clearTimeout(this.resizeTimeout);\n    this.resizeTimeout = null;\n    this._execEvent('destroy');\n  },\n\n  _transitionEnd: function (e) {\n    if ( e.target != this.scroller || !this.isInTransition ) {\n      return;\n    }\n\n    this._transitionTime();\n    if ( !this.resetPosition(this.options.bounceTime) ) {\n      this.isInTransition = false;\n      this._execEvent('scrollEnd');\n    }\n  },\n\n  _start: function (e) {\n    // React to left mouse button only\n    if ( utils.eventType[e.type] != 1 ) {\n      // for button property\n      // http://unixpapa.com/js/mouse.html\n      var button;\n      if (!e.which) {\n        /* IE case */\n        button = (e.button < 2) ? 0 :\n                 ((e.button == 4) ? 1 : 2);\n      } else {\n        /* All others */\n        button = e.button;\n      }\n      if ( button !== 0 ) {\n        return;\n      }\n    }\n\n    if ( !this.enabled || (this.initiated && utils.eventType[e.type] !== this.initiated) ) {\n      return;\n    }\n\n    if ( this.options.preventDefault && !utils.isBadAndroid && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {\n      e.preventDefault();\n    }\n\n    var point = e.touches ? e.touches[0] : e,\n      pos;\n\n    this.initiated  = utils.eventType[e.type];\n    this.moved    = false;\n    this.distX    = 0;\n    this.distY    = 0;\n    this.directionX = 0;\n    this.directionY = 0;\n    this.directionLocked = 0;\n\n    this.startTime = utils.getTime();\n\n    if ( this.options.useTransition && this.isInTransition ) {\n      this._transitionTime();\n      this.isInTransition = false;\n      pos = this.getComputedPosition();\n      this._translate(Math.round(pos.x), Math.round(pos.y));\n      this._execEvent('scrollEnd');\n    } else if ( !this.options.useTransition && this.isAnimating ) {\n      this.isAnimating = false;\n      this._execEvent('scrollEnd');\n    }\n\n    this.startX    = this.x;\n    this.startY    = this.y;\n    this.absStartX = this.x;\n    this.absStartY = this.y;\n    this.pointX    = point.pageX;\n    this.pointY    = point.pageY;\n\n    this._execEvent('beforeScrollStart');\n  },\n\n  _move: function (e) {\n    if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {\n      return;\n    }\n\n    if ( this.options.preventDefault ) {  // increases performance on Android? TODO: check!\n      e.preventDefault();\n    }\n\n    var point   = e.touches ? e.touches[0] : e,\n      deltaX    = point.pageX - this.pointX,\n      deltaY    = point.pageY - this.pointY,\n      timestamp = utils.getTime(),\n      newX, newY,\n      absDistX, absDistY;\n\n    this.pointX   = point.pageX;\n    this.pointY   = point.pageY;\n\n    this.distX    += deltaX;\n    this.distY    += deltaY;\n    absDistX    = Math.abs(this.distX);\n    absDistY    = Math.abs(this.distY);\n\n    // We need to move at least 10 pixels for the scrolling to initiate\n    if ( timestamp - this.endTime > 300 && (absDistX < 10 && absDistY < 10) ) {\n      return;\n    }\n\n    // If you are scrolling in one direction lock the other\n    if ( !this.directionLocked && !this.options.freeScroll ) {\n      if ( absDistX > absDistY + this.options.directionLockThreshold ) {\n        this.directionLocked = 'h';   // lock horizontally\n      } else if ( absDistY >= absDistX + this.options.directionLockThreshold ) {\n        this.directionLocked = 'v';   // lock vertically\n      } else {\n        this.directionLocked = 'n';   // no lock\n      }\n    }\n\n    if ( this.directionLocked == 'h' ) {\n      if ( this.options.eventPassthrough == 'vertical' ) {\n        e.preventDefault();\n      } else if ( this.options.eventPassthrough == 'horizontal' ) {\n        this.initiated = false;\n        return;\n      }\n\n      deltaY = 0;\n    } else if ( this.directionLocked == 'v' ) {\n      if ( this.options.eventPassthrough == 'horizontal' ) {\n        e.preventDefault();\n      } else if ( this.options.eventPassthrough == 'vertical' ) {\n        this.initiated = false;\n        return;\n      }\n\n      deltaX = 0;\n    }\n\n    deltaX = this.hasHorizontalScroll ? deltaX : 0;\n    deltaY = this.hasVerticalScroll ? deltaY : 0;\n\n    newX = this.x + deltaX;\n    newY = this.y + deltaY;\n\n    // Slow down if outside of the boundaries\n    if ( newX > 0 || newX < this.maxScrollX ) {\n      newX = this.options.bounce ? this.x + deltaX / 3 : newX > 0 ? 0 : this.maxScrollX;\n    }\n    if ( newY > 0 || newY < this.maxScrollY ) {\n      newY = this.options.bounce ? this.y + deltaY / 3 : newY > 0 ? 0 : this.maxScrollY;\n    }\n\n    this.directionX = deltaX > 0 ? -1 : deltaX < 0 ? 1 : 0;\n    this.directionY = deltaY > 0 ? -1 : deltaY < 0 ? 1 : 0;\n\n    if ( !this.moved ) {\n      this._execEvent('scrollStart');\n    }\n\n    this.moved = true;\n\n    this._translate(newX, newY);\n\n/* REPLACE START: _move */\n\n    if ( timestamp - this.startTime > 300 ) {\n      this.startTime = timestamp;\n      this.startX = this.x;\n      this.startY = this.y;\n    }\n\n/* REPLACE END: _move */\n\n  },\n\n  _end: function (e) {\n    if ( !this.enabled || utils.eventType[e.type] !== this.initiated ) {\n      return;\n    }\n\n    if ( this.options.preventDefault && !utils.preventDefaultException(e.target, this.options.preventDefaultException) ) {\n      e.preventDefault();\n    }\n\n    var point = e.changedTouches ? e.changedTouches[0] : e,\n      momentumX,\n      momentumY,\n      duration = utils.getTime() - this.startTime,\n      newX = Math.round(this.x),\n      newY = Math.round(this.y),\n      distanceX = Math.abs(newX - this.startX),\n      distanceY = Math.abs(newY - this.startY),\n      time = 0,\n      easing = '';\n\n    this.isInTransition = 0;\n    this.initiated = 0;\n    this.endTime = utils.getTime();\n\n    // reset if we are outside of the boundaries\n    if ( this.resetPosition(this.options.bounceTime) ) {\n      return;\n    }\n\n    this.scrollTo(newX, newY);  // ensures that the last position is rounded\n\n    // we scrolled less than 10 pixels\n    if ( !this.moved ) {\n      if ( this.options.tap ) {\n        utils.tap(e, this.options.tap);\n      }\n\n      if ( this.options.click ) {\n        utils.click(e);\n      }\n\n      this._execEvent('scrollCancel');\n      return;\n    }\n\n/*\nFIXME: FLICK GIVES US PROBLEMS --- MARK\n    if ( this._events.flick && duration < 200 && distanceX < 100 && distanceY < 100 ) {\n      this._execEvent('flick');\n      return;\n    }\n*/\n    // start momentum animation if needed\n    if ( this.options.momentum && duration < 300 ) {\n      momentumX = this.hasHorizontalScroll ? utils.momentum(this.x, this.startX, duration, this.maxScrollX, this.options.bounce ? this.wrapperWidth : 0, this.options.deceleration) : { destination: newX, duration: 0 };\n      momentumY = this.hasVerticalScroll ? utils.momentum(this.y, this.startY, duration, this.maxScrollY, this.options.bounce ? this.wrapperHeight : 0, this.options.deceleration) : { destination: newY, duration: 0 };\n      newX = momentumX.destination;\n      newY = momentumY.destination;\n      time = Math.max(momentumX.duration, momentumY.duration);\n      this.isInTransition = 1;\n    }\n\n\n    if ( this.options.snap ) {\n      var snap = this._nearestSnap(newX, newY);\n      this.currentPage = snap;\n      time = this.options.snapSpeed || Math.max(\n          Math.max(\n            Math.min(Math.abs(newX - snap.x), 1000),\n            Math.min(Math.abs(newY - snap.y), 1000)\n          ), 300);\n      newX = snap.x;\n      newY = snap.y;\n\n      this.directionX = 0;\n      this.directionY = 0;\n      easing = this.options.bounceEasing;\n\n      //console.log(\"_end will snap to \", newX, newY);\n    }\n\n// INSERT POINT: _end\n\n    if ( newX != this.x || newY != this.y ) {\n      // change easing function when scroller goes out of the boundaries\n      if ( newX > 0 || newX < this.maxScrollX || newY > 0 || newY < this.maxScrollY ) {\n        easing = utils.ease.quadratic;\n      }\n\n      this.scrollTo(newX, newY, time, easing);\n      return;\n    }\n\n    this._execEvent('scrollEnd');\n  },\n\n  _resize: function () {\n    var that = this;\n\n    clearTimeout(this.resizeTimeout);\n\n    this.resizeTimeout = setTimeout(function () {\n      that.refresh();\n    }, this.options.resizePolling);\n  },\n\n  resetPosition: function (time) {\n    var x = this.x,\n      y = this.y;\n\n    time = time || 0;\n\n    if ( !this.hasHorizontalScroll || this.x > 0 ) {\n      x = 0;\n    } else if ( this.x < this.maxScrollX ) {\n      x = this.maxScrollX;\n    }\n\n    if ( !this.hasVerticalScroll || this.y > 0 ) {\n      y = 0;\n    } else if ( this.y < this.maxScrollY ) {\n      y = this.maxScrollY;\n    }\n\n    if ( x == this.x && y == this.y ) {\n      return false;\n    }\n\n    this.scrollTo(x, y, time, this.options.bounceEasing);\n\n    return true;\n  },\n\n  disable: function () {\n    /** Patch by RByers (21 dec 2016) **************************/\n    this.wrapper.style.touchAction='';\n\n    this.enabled = false;\n  },\n\n  enable: function () {\n\n    this.enabled = true;\n\n    /** Patch by RByers (21 dec 2016) **************************/\n    // https://github.com/cubiq/iscroll/issues/1100\n\n    var touchAction = 'none'\n    if ( this.options.eventPassthrough == 'vertical' ) {\n      touchAction = 'pan-y';\n    } else if ( this.options.eventPassthrough == 'horizontal' ) {\n      touchAction = 'pan-x';\n    }\n    this.wrapper.style.touchAction = touchAction;\n    if (touchAction != 'none') {\n      // add pinch-zoom support if the browser supports it, but if not (eg. Chrome <55) do nothing\n      this.wrapper.style.touchAction += ' pinch-zoom';\n    }\n    /***********************************************************/\n  },\n\n  refresh: function () {\n    var rf = this.wrapper.offsetHeight;   // Force reflow\n\n    this.wrapperWidth = this.wrapper.clientWidth;\n    this.wrapperHeight  = this.wrapper.clientHeight;\n\n/* REPLACE START: refresh */\n\n    if (!this.options.overrideMeasurements) // MARK\n    { // MARK\n      this.scrollerWidth  = this.scroller.offsetWidth;\n      this.scrollerHeight = this.scroller.offsetHeight;\n\n      this.maxScrollX   = this.wrapperWidth - this.scrollerWidth;\n      this.maxScrollY   = this.wrapperHeight - this.scrollerHeight;\n    } // MARK\n\n/* REPLACE END: refresh */\n\n    this.hasHorizontalScroll  = this.options.scrollX && this.maxScrollX < 0;\n    this.hasVerticalScroll    = this.options.scrollY && this.maxScrollY < 0;\n\n    if ( !this.hasHorizontalScroll ) {\n      this.maxScrollX = 0;\n      this.scrollerWidth = this.wrapperWidth;\n    }\n\n    if ( !this.hasVerticalScroll ) {\n      this.maxScrollY = 0;\n      this.scrollerHeight = this.wrapperHeight;\n    }\n\n    this.endTime = 0;\n    this.directionX = 0;\n    this.directionY = 0;\n\n    this.wrapperOffset = utils.offset(this.wrapper);\n\n    this._execEvent('refresh');\n\n    this.resetPosition();\n\n// INSERT POINT: _refresh\n\n  },\n\n  on: function (type, fn) {\n    if ( !this._events[type] ) {\n      this._events[type] = [];\n    }\n\n    this._events[type].push(fn);\n  },\n\n  off: function (type, fn) {\n    if ( !this._events[type] ) {\n      return;\n    }\n\n    var index = this._events[type].indexOf(fn);\n\n    if ( index > -1 ) {\n      this._events[type].splice(index, 1);\n    }\n  },\n\n  _execEvent: function (type) {\n    if ( !this._events[type] ) {\n      return;\n    }\n\n    var i = 0,\n      l = this._events[type].length;\n\n    if ( !l ) {\n      return;\n    }\n\n    for ( ; i < l; i++ ) {\n      this._events[type][i].apply(this, [].slice.call(arguments, 1));\n    }\n  },\n\n  scrollBy: function (x, y, time, easing) {\n    x = this.x + x;\n    y = this.y + y;\n    time = time || 0;\n\n    this.scrollTo(x, y, time, easing);\n  },\n\n  scrollTo: function (x, y, time, easing) {\n    this._execEvent('scrollStart'); // MARK\n\n\n// EXPERIMENTAL: a scrollTo (with no animation) while an animation is still running should override that animation..??\n    if (this.animframe) // MARK\n      cancelAnimationFrame(this.animframe); // MARK - Fixed multiple animate/scrollTo's fighting\n\n\n    easing = easing || utils.ease.circular;\n\n    this.isInTransition = this.options.useTransition && time > 0;\n    var transitionType = this.options.useTransition && easing.style;\n    if ( !time || transitionType ) {\n        if(transitionType) {\n          this._transitionTimingFunction(easing.style);\n          this._transitionTime(time);\n        }\n      this._translate(x, y);\n    } else {\n      this._animate(x, y, time, easing.fn);\n    }\n  },\n\n  scrollToElement: function (el, time, offsetX, offsetY, easing) {\n    el = el.nodeType ? el : this.scroller.querySelector(el);\n\n    if ( !el ) {\n      return;\n    }\n\n    var pos = utils.offset(el);\n\n    pos.left -= this.wrapperOffset.left;\n    pos.top  -= this.wrapperOffset.top;\n\n    // if offsetX/Y are true we center the element to the screen\n    if ( offsetX === true ) {\n      offsetX = Math.round(el.offsetWidth / 2 - this.wrapper.offsetWidth / 2);\n    }\n    if ( offsetY === true ) {\n      offsetY = Math.round(el.offsetHeight / 2 - this.wrapper.offsetHeight / 2);\n    }\n\n    pos.left -= offsetX || 0;\n    pos.top  -= offsetY || 0;\n\n    pos.left = pos.left > 0 ? 0 : pos.left < this.maxScrollX ? this.maxScrollX : pos.left;\n    pos.top  = pos.top  > 0 ? 0 : pos.top  < this.maxScrollY ? this.maxScrollY : pos.top;\n\n    time = time === undefined || time === null || time === 'auto' ? Math.max(Math.abs(this.x-pos.left), Math.abs(this.y-pos.top)) : time;\n\n    this.scrollTo(pos.left, pos.top, time, easing);\n  },\n\n  _transitionTime: function (time) {\n    if (this.options.autoUpdatePosition) // MARK\n      return; // MARK\n\n    if (!this.options.useTransition) {\n      return;\n    }\n    time = time || 0;\n    var durationProp = utils.style.transitionDuration;\n    if(!durationProp) {\n      return;\n    }\n\n    this.scrollerStyle[durationProp] = time + 'ms';\n\n    if ( !time && utils.isBadAndroid ) {\n      this.scrollerStyle[durationProp] = '0.0001ms';\n      // remove 0.0001ms\n      var self = this;\n      rAF(function() {\n        if(self.scrollerStyle[durationProp] === '0.0001ms') {\n          self.scrollerStyle[durationProp] = '0s';\n        }\n      });\n    }\n\n\n    if ( this.indicators ) {\n      for ( var i = this.indicators.length; i--; ) {\n        this.indicators[i].transitionTime(time);\n      }\n    }\n\n\n// INSERT POINT: _transitionTime\n\n  },\n\n  _transitionTimingFunction: function (easing) {\n    if (this.options.autoUpdatePosition) // MARK\n      return; // MARK\n\n    this.scrollerStyle[utils.style.transitionTimingFunction] = easing;\n\n\n    if ( this.indicators ) {\n      for ( var i = this.indicators.length; i--; ) {\n        this.indicators[i].transitionTimingFunction(easing);\n      }\n    }\n\n\n// INSERT POINT: _transitionTimingFunction\n\n  },\n\n  _translate: function (x, y) {\n\n    if (this.options.autoUpdatePosition) // MARK\n    { // MARK\n\n      if ( this.options.useTransform ) {\n\n  /* REPLACE START: _translate */\n\n        this.scrollerStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.translateZ;\n\n  /* REPLACE END: _translate */\n\n      } else {\n        x = Math.round(x);\n        y = Math.round(y);\n        this.scrollerStyle.left = x + 'px';\n        this.scrollerStyle.top = y + 'px';\n      }\n\n    } // MARK\n\n    this.x = x;\n    this.y = y;\n\n  if ( this.indicators ) {\n    for ( var i = this.indicators.length; i--; ) {\n      this.indicators[i].updatePosition();\n    }\n  }\n\n\n// INSERT POINT: _translate\n\n  },\n\n  _initEvents: function (remove) {\n    var eventType = remove ? utils.removeEvent : utils.addEvent,\n      target = this.options.bindToWrapper ? this.wrapper : window;\n\nif (!this.options.overrideMeasurements) // MARK\n{\n    eventType(window, 'orientationchange', this);\n    eventType(window, 'resize', this);\n}\n\n    if ( this.options.click ) {\n      eventType(this.wrapper, 'click', this, true);\n    }\n\n    if ( !this.options.disableMouse ) {\n      eventType(this.wrapper, 'mousedown', this);\n      eventType(target, 'mousemove', this);\n      eventType(target, 'mousecancel', this);\n      eventType(target, 'mouseup', this);\n    }\n\n    if ( utils.hasPointer && !this.options.disablePointer ) {\n      eventType(this.wrapper, utils.prefixPointerEvent('pointerdown'), this);\n      eventType(target, utils.prefixPointerEvent('pointermove'), this);\n      eventType(target, utils.prefixPointerEvent('pointercancel'), this);\n      eventType(target, utils.prefixPointerEvent('pointerup'), this);\n    }\n\n    if ( utils.hasTouch && !this.options.disableTouch ) {\n      eventType(this.wrapper, 'touchstart', this);\n      eventType(target, 'touchmove', this);\n      eventType(target, 'touchcancel', this);\n      eventType(target, 'touchend', this);\n    }\n\n    eventType(this.scroller, 'transitionend', this);\n    eventType(this.scroller, 'webkitTransitionEnd', this);\n    //eventType(this.scroller, 'oTransitionEnd', this); // MARK: only used for Opera < 12.10\n    eventType(this.scroller, 'MSTransitionEnd', this);\n  },\n\n  getComputedPosition: function () {\n    var matrix = window.getComputedStyle(this.scroller, null),\n      x, y;\n\n    if ( this.options.useTransform ) {\n      matrix = matrix[utils.style.transform].split(')')[0].split(', ');\n      x = +(matrix[12] || matrix[4]);\n      y = +(matrix[13] || matrix[5]);\n    } else {\n      x = +matrix.left.replace(/[^-\\d.]/g, '');\n      y = +matrix.top.replace(/[^-\\d.]/g, '');\n    }\n\n    return { x: x, y: y };\n  },\n  _initIndicators: function () {\n    var interactive = this.options.interactiveScrollbars,\n      customStyle = typeof this.options.scrollbars != 'string',\n      indicators = [],\n      indicator;\n\n    var that = this;\n\n    this.indicators = [];\n\n    if ( this.options.scrollbars ) {\n      // Vertical scrollbar\n      if ( this.options.scrollY ) {\n        indicator = {\n          el: createDefaultScrollbar('v', interactive, this.options.scrollbars),\n          interactive: interactive,\n          defaultScrollbars: true,\n          customStyle: customStyle,\n          resize: this.options.resizeScrollbars,\n          shrink: this.options.shrinkScrollbars,\n          fade: this.options.fadeScrollbars,\n          listenX: false\n        };\n\n        this.wrapper.appendChild(indicator.el);\n        indicators.push(indicator);\n      }\n\n      // Horizontal scrollbar\n      if ( this.options.scrollX ) {\n        indicator = {\n          el: createDefaultScrollbar('h', interactive, this.options.scrollbars),\n          interactive: interactive,\n          defaultScrollbars: true,\n          customStyle: customStyle,\n          resize: this.options.resizeScrollbars,\n          shrink: this.options.shrinkScrollbars,\n          fade: this.options.fadeScrollbars,\n          listenY: false\n        };\n\n        this.wrapper.appendChild(indicator.el);\n        indicators.push(indicator);\n      }\n    }\n\n    if ( this.options.indicators ) {\n      // TODO: check concat compatibility\n      indicators = indicators.concat(this.options.indicators);\n    }\n\n    for ( var i = indicators.length; i--; ) {\n      this.indicators.push( new Indicator(this, indicators[i]) );\n    }\n\n    // TODO: check if we can use array.map (wide compatibility and performance issues)\n    function _indicatorsMap (fn) {\n      if (that.indicators) {\n        for ( var i = that.indicators.length; i--; ) {\n          fn.call(that.indicators[i]);\n        }\n      }\n    }\n\n    if ( this.options.fadeScrollbars ) {\n      this.on('scrollEnd', function () {\n        _indicatorsMap(function () {\n          this.fade();\n        });\n      });\n\n      this.on('scrollCancel', function () {\n        _indicatorsMap(function () {\n          this.fade();\n        });\n      });\n\n      this.on('scrollStart', function () {\n        _indicatorsMap(function () {\n          this.fade(1);\n        });\n      });\n\n      this.on('beforeScrollStart', function () {\n        _indicatorsMap(function () {\n          this.fade(1, true);\n        });\n      });\n    }\n\n\n    this.on('refresh', function () {\n      _indicatorsMap(function () {\n        this.refresh();\n      });\n    });\n\n    this.on('destroy', function () {\n      _indicatorsMap(function () {\n        this.destroy();\n      });\n\n      delete this.indicators;\n    });\n  },\n\n  _initWheel: function () {\n    utils.addEvent(this.wrapper, 'wheel', this); // Firefox 17+\n    utils.addEvent(this.wrapper, 'mousewheel', this); // Chrome, IE, Safari, Opera\n    utils.addEvent(this.wrapper, 'DOMMouseScroll', this); // FF1.0\n\n    this.on('destroy', function () {\n      clearTimeout(this.wheelTimeout);\n      this.wheelTimeout = null;\n      utils.removeEvent(this.wrapper, 'wheel', this);\n      utils.removeEvent(this.wrapper, 'mousewheel', this);\n      utils.removeEvent(this.wrapper, 'DOMMouseScroll', this);\n    });\n  },\n\n  _wheel: function (e) {\n    if ( !this.enabled ) {\n      return;\n    }\n\n    e.preventDefault();\n\n    var wheelDeltaX, wheelDeltaY,\n      newX, newY,\n      that = this;\n\n    if ( this.wheelTimeout === undefined ) {\n      that._execEvent('scrollStart');\n    }\n\n    // Execute the scrollEnd event after 400ms the wheel stopped scrolling\n    clearTimeout(this.wheelTimeout);\n    this.wheelTimeout = setTimeout(function () {\n      if(!that.options.snap) {\n        that._execEvent('scrollEnd');\n      }\n      that.wheelTimeout = undefined;\n    }, 400);\n\n    if ( 'deltaX' in e ) {\n      if (e.deltaMode === 1) {\n        wheelDeltaX = -e.deltaX * this.options.mouseWheelSpeed;\n        wheelDeltaY = -e.deltaY * this.options.mouseWheelSpeed;\n      } else {\n// FIXME MARK: not using the mouseWheelSpeed here is a bug??\n        wheelDeltaX = -e.deltaX;\n        wheelDeltaY = -e.deltaY;\n      }\n    } else if ( 'wheelDeltaX' in e ) {\n      wheelDeltaX = e.wheelDeltaX / 120 * this.options.mouseWheelSpeed;\n      wheelDeltaY = e.wheelDeltaY / 120 * this.options.mouseWheelSpeed;\n    } else if ( 'wheelDelta' in e ) {\n      wheelDeltaX = wheelDeltaY = e.wheelDelta / 120 * this.options.mouseWheelSpeed;\n    } else if ( 'detail' in e ) {\n      wheelDeltaX = wheelDeltaY = -e.detail / 3 * this.options.mouseWheelSpeed;\n    } else {\n      return;\n    }\n\n    wheelDeltaX *= this.options.invertWheelDirection;\n    wheelDeltaY *= this.options.invertWheelDirection;\n\n    if ( !this.hasVerticalScroll ) {\n      wheelDeltaX = wheelDeltaY;\n      wheelDeltaY = 0;\n    }\n\n    if ( this.options.snap ) {\n      newX = this.currentPage.pageX;\n      newY = this.currentPage.pageY;\n\n      if ( wheelDeltaX > 0 ) {\n        newX--;\n      } else if ( wheelDeltaX < 0 ) {\n        newX++;\n      }\n\n      if ( wheelDeltaY > 0 ) {\n        newY--;\n      } else if ( wheelDeltaY < 0 ) {\n        newY++;\n      }\n\n      this.goToPage(newX, newY);\n\n      return;\n    }\n\n    newX = this.x + Math.round(this.hasHorizontalScroll ? wheelDeltaX : 0);\n    newY = this.y + Math.round(this.hasVerticalScroll ? wheelDeltaY : 0);\n\n    this.directionX = wheelDeltaX > 0 ? -1 : wheelDeltaX < 0 ? 1 : 0;\n    this.directionY = wheelDeltaY > 0 ? -1 : wheelDeltaY < 0 ? 1 : 0;\n\n    if ( newX > 0 ) {\n      newX = 0;\n    } else if ( newX < this.maxScrollX ) {\n      newX = this.maxScrollX;\n    }\n\n    if ( newY > 0 ) {\n      newY = 0;\n    } else if ( newY < this.maxScrollY ) {\n      newY = this.maxScrollY;\n    }\n\n    this.scrollTo(newX, newY, 0);\n\n// INSERT POINT: _wheel\n  },\n\n  _initSnap: function () {\n    this.currentPage = {};\n\n    if ( typeof this.options.snap == 'string' ) {\n      this.options.snap = this.scroller.querySelectorAll(this.options.snap);\n    }\n\n    this.on('refresh', function () {\n      var i = 0, l,\n        m = 0, n,\n        cx, cy,\n        x = 0, y,\n        stepX = this.options.snapStepX || this.wrapperWidth,\n        stepY = this.options.snapStepY || this.wrapperHeight,\n        el;\n\n      this.pages = [];\n\n      if ( !this.wrapperWidth || !this.wrapperHeight || !this.scrollerWidth || !this.scrollerHeight ) {\n        return;\n      }\n\n      if ( this.options.snap === true ) {\n        cx = Math.round( stepX / 2 );\n        cy = Math.round( stepY / 2 );\n\n        while ( x > -this.scrollerWidth ) {\n          this.pages[i] = [];\n          l = 0;\n          y = 0;\n\n          while ( y > -this.scrollerHeight ) {\n            this.pages[i][l] = {\n              x: Math.max(x, this.maxScrollX),\n              y: Math.max(y, this.maxScrollY),\n              width: stepX,\n              height: stepY,\n              cx: x - cx,\n              cy: y - cy\n            };\n\n            y -= stepY;\n            l++;\n          }\n\n          x -= stepX;\n          i++;\n        }\n      } else {\n        el = this.options.snap;\n        l = el.length;\n        n = -1;\n\n        for ( ; i < l; i++ ) {\n          if ( i === 0 || el[i].offsetLeft <= el[i-1].offsetLeft ) {\n            m = 0;\n            n++;\n          }\n\n          if ( !this.pages[m] ) {\n            this.pages[m] = [];\n          }\n\n          x = Math.max(-el[i].offsetLeft, this.maxScrollX);\n          y = Math.max(-el[i].offsetTop, this.maxScrollY);\n          cx = x - Math.round(el[i].offsetWidth / 2);\n          cy = y - Math.round(el[i].offsetHeight / 2);\n\n          this.pages[m][n] = {\n            x: x,\n            y: y,\n            width: el[i].offsetWidth,\n            height: el[i].offsetHeight,\n            cx: cx,\n            cy: cy\n          };\n\n          if ( x > this.maxScrollX ) {\n            m++;\n          }\n        }\n      }\n\n      this.goToPage(this.currentPage.pageX || 0, this.currentPage.pageY || 0, 0);\n\n      // Update snap threshold if needed\n      if ( this.options.snapThreshold % 1 === 0 ) {\n        this.snapThresholdX = this.options.snapThreshold;\n        this.snapThresholdY = this.options.snapThreshold;\n      } else {\n        this.snapThresholdX = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].width * this.options.snapThreshold);\n        this.snapThresholdY = Math.round(this.pages[this.currentPage.pageX][this.currentPage.pageY].height * this.options.snapThreshold);\n      }\n    });\n\n    this.on('flick', function () {\n      console.info(\"FLICK\");\n\n      var time = this.options.snapSpeed || Math.max(\n          Math.max(\n            Math.min(Math.abs(this.x - this.startX), 1000),\n            Math.min(Math.abs(this.y - this.startY), 1000)\n          ), 300);\n\n      this.goToPage(\n        this.currentPage.pageX + this.directionX,\n        this.currentPage.pageY + this.directionY,\n        time\n      );\n    });\n  },\n\n  _nearestSnap: function (x, y) {\n    // MARK ---\n    if (this.options.getNearestSnap)\n    {\n      var snap = this.options.getNearestSnap(x, y, this);\n      return snap;\n    }\n    // --------\n\n    if ( !this.pages.length ) {\n      return { x: 0, y: 0, pageX: 0, pageY: 0 };\n    }\n\n    var i = 0,\n      l = this.pages.length,\n      m = 0;\n\n    // Check if we exceeded the snap threshold\n    if ( Math.abs(x - this.absStartX) < this.snapThresholdX &&\n      Math.abs(y - this.absStartY) < this.snapThresholdY ) {\n      return this.currentPage;\n    }\n\n    if ( x > 0 ) {\n      x = 0;\n    } else if ( x < this.maxScrollX ) {\n      x = this.maxScrollX;\n    }\n\n    if ( y > 0 ) {\n      y = 0;\n    } else if ( y < this.maxScrollY ) {\n      y = this.maxScrollY;\n    }\n\n    for ( ; i < l; i++ ) {\n      if ( x >= this.pages[i][0].cx ) {\n        x = this.pages[i][0].x;\n        break;\n      }\n    }\n\n    l = this.pages[i].length;\n\n    for ( ; m < l; m++ ) {\n      if ( y >= this.pages[0][m].cy ) {\n        y = this.pages[0][m].y;\n        break;\n      }\n    }\n\n    if ( i == this.currentPage.pageX ) {\n      i += this.directionX;\n\n      if ( i < 0 ) {\n        i = 0;\n      } else if ( i >= this.pages.length ) {\n        i = this.pages.length - 1;\n      }\n\n      x = this.pages[i][0].x;\n    }\n\n    if ( m == this.currentPage.pageY ) {\n      m += this.directionY;\n\n      if ( m < 0 ) {\n        m = 0;\n      } else if ( m >= this.pages[0].length ) {\n        m = this.pages[0].length - 1;\n      }\n\n      y = this.pages[0][m].y;\n    }\n\n    return {\n      x: x,\n      y: y,\n      pageX: i,\n      pageY: m\n    };\n  },\n\n  goToPage: function (x, y, time, easing) {\n    easing = easing || this.options.bounceEasing;\n\n    // MARK ---\n    if (this.options.getPage)\n    {\n      var page = this.options.getPage(x, y);\n      var posX = page.x;\n      var posY = page.y;\n\n      time = time === undefined ? this.options.snapSpeed || Math.max(\n        Math.max(\n          Math.min(Math.abs(posX - this.x), 1000),\n          Math.min(Math.abs(posY - this.y), 1000)\n        ), 300) : time;\n\n      this.currentPage = {\n        x: page.x,\n        y: page.y,\n        pageX: page.x,\n        pageY: page.y\n      };\n\n      this.scrollTo(posX, posY, time, easing);\n\n      return;\n    }\n    // --------\n\n\n    if ( x >= this.pages.length ) {\n      x = this.pages.length - 1;\n    } else if ( x < 0 ) {\n      x = 0;\n    }\n\n    if ( y >= this.pages[x].length ) {\n      y = this.pages[x].length - 1;\n    } else if ( y < 0 ) {\n      y = 0;\n    }\n\n    var posX = this.pages[x][y].x,\n      posY = this.pages[x][y].y;\n\n    time = time === undefined ? this.options.snapSpeed || Math.max(\n      Math.max(\n        Math.min(Math.abs(posX - this.x), 1000),\n        Math.min(Math.abs(posY - this.y), 1000)\n      ), 300) : time;\n\n    this.currentPage = {\n      x: posX,\n      y: posY,\n      pageX: x,\n      pageY: y\n    };\n\n    this.scrollTo(posX, posY, time, easing);\n  },\n\n  next: function (time, easing) {\n    var x = this.currentPage.pageX,\n      y = this.currentPage.pageY;\n\n    x++;\n\n    if ( x >= this.pages.length && this.hasVerticalScroll ) {\n      x = 0;\n      y++;\n    }\n\n    this.goToPage(x, y, time, easing);\n  },\n\n  prev: function (time, easing) {\n    var x = this.currentPage.pageX,\n      y = this.currentPage.pageY;\n\n    x--;\n\n    if ( x < 0 && this.hasVerticalScroll ) {\n      x = 0;\n      y--;\n    }\n\n    this.goToPage(x, y, time, easing);\n  },\n\n  _initKeys: function (e) {\n    // default key bindings\n    var keys = {\n      pageUp: 33,\n      pageDown: 34,\n      end: 35,\n      home: 36,\n      left: 37,\n      up: 38,\n      right: 39,\n      down: 40\n    };\n    var i;\n\n    // if you give me characters I give you keycode\n    if ( typeof this.options.keyBindings == 'object' ) {\n      for ( i in this.options.keyBindings ) {\n        if ( typeof this.options.keyBindings[i] == 'string' ) {\n          this.options.keyBindings[i] = this.options.keyBindings[i].toUpperCase().charCodeAt(0);\n        }\n      }\n    } else {\n      this.options.keyBindings = {};\n    }\n\n    for ( i in keys ) {\n      this.options.keyBindings[i] = this.options.keyBindings[i] || keys[i];\n    }\n\n    utils.addEvent(window, 'keydown', this);\n\n    this.on('destroy', function () {\n      utils.removeEvent(window, 'keydown', this);\n    });\n  },\n\n  _key: function (e) {\n    if ( !this.enabled ) {\n      return;\n    }\n\nconsole.log(this.tempid);\n\n    var snap = this.options.snap, // we are using this alot, better to cache it\n      newX = snap ? this.currentPage.pageX : this.x,\n      newY = snap ? this.currentPage.pageY : this.y,\n      now = utils.getTime(),\n      prevTime = this.keyTime || 0,\n      acceleration = 0.250,\n      pos;\n\n    if ( this.options.useTransition && this.isInTransition ) {\n      pos = this.getComputedPosition();\n\n      this._translate(Math.round(pos.x), Math.round(pos.y));\n      this.isInTransition = false;\n    }\n\n    this.keyAcceleration = now - prevTime < 200 ? Math.min(this.keyAcceleration + acceleration, 50) : 0;\n\n    switch ( e.keyCode ) {\n      case this.options.keyBindings.pageUp:\n        if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {\n          newX += snap ? 1 : this.wrapperWidth;\n        } else {\n          newY += snap ? 1 : this.wrapperHeight;\n        }\n        break;\n      case this.options.keyBindings.pageDown:\n        if ( this.hasHorizontalScroll && !this.hasVerticalScroll ) {\n          newX -= snap ? 1 : this.wrapperWidth;\n        } else {\n          newY -= snap ? 1 : this.wrapperHeight;\n        }\n        break;\n      case this.options.keyBindings.end:\n        newX = snap ? this.pages.length-1 : this.maxScrollX;\n        newY = snap ? this.pages[0].length-1 : this.maxScrollY;\n        break;\n      case this.options.keyBindings.home:\n        newX = 0;\n        newY = 0;\n        break;\n      case this.options.keyBindings.left:\n        newX += snap ? -1 : 5 + this.keyAcceleration>>0;\n        break;\n      case this.options.keyBindings.up:\n        newY += snap ? 1 : 5 + this.keyAcceleration>>0;\n        break;\n      case this.options.keyBindings.right:\n        newX -= snap ? -1 : 5 + this.keyAcceleration>>0;\n        break;\n      case this.options.keyBindings.down:\n        newY -= snap ? 1 : 5 + this.keyAcceleration>>0;\n        break;\n      default:\n        return;\n    }\n\n    if ( snap ) {\n      this.goToPage(newX, newY);\n      return;\n    }\n\n    if ( newX > 0 ) {\n      newX = 0;\n      this.keyAcceleration = 0;\n    } else if ( newX < this.maxScrollX ) {\n      newX = this.maxScrollX;\n      this.keyAcceleration = 0;\n    }\n\n    if ( newY > 0 ) {\n      newY = 0;\n      this.keyAcceleration = 0;\n    } else if ( newY < this.maxScrollY ) {\n      newY = this.maxScrollY;\n      this.keyAcceleration = 0;\n    }\n\n    this.scrollTo(newX, newY, 0);\n\n    this.keyTime = now;\n  },\n\n  _animate: function (destX, destY, duration, easingFn) {\n    var that = this,\n      startX = this.x,\n      startY = this.y,\n      startTime = utils.getTime(),\n      destTime = startTime + duration;\n\n//console.log(this.tempid, \"_animate\");\n\n    if (this.animframe) // MARK\n      cancelAnimationFrame(this.animframe); // MARK - Fixed multiple animate/scrollTo's fighting\n\n    function step () {\n//console.log(that.tempid, \"_animate / step\");\n\n      var now = utils.getTime(),\n        newX, newY,\n        easing;\n\n      if ( now >= destTime ) {\n\n//console.log(that.tempid, \"DESTTIME reached\");\n        that.isAnimating = false;\n        that._translate(destX, destY);\n\n        if ( !that.resetPosition(that.options.bounceTime) ) {\n          that._execEvent('scrollEnd');\n        }\n\n        return;\n      }\n\n      now = ( now - startTime ) / duration;\n      easing = easingFn(now);\n      newX = ( destX - startX ) * easing + startX;\n      newY = ( destY - startY ) * easing + startY;\n      that._translate(newX, newY);\n\n      if ( that.isAnimating ) {\n        //rAF(step);\n        that.animframe = rAF(step); // FIXME: Mark fixing multiple scrollTo's, last one ends at timing of first one\n      }\n    }\n\n    this.isAnimating = true;\n    step();\n  },\n  handleEvent: function (e) {\n    switch ( e.type ) {\n      case 'touchstart':\n      case 'pointerdown':\n      case 'MSPointerDown':\n      case 'mousedown':\n        this._start(e);\n        break;\n      case 'touchmove':\n      case 'pointermove':\n      case 'MSPointerMove':\n      case 'mousemove':\n        this._move(e);\n        break;\n      case 'touchend':\n      case 'pointerup':\n      case 'MSPointerUp':\n      case 'mouseup':\n      case 'touchcancel':\n      case 'pointercancel':\n      case 'MSPointerCancel':\n      case 'mousecancel':\n        this._end(e);\n        break;\n      case 'orientationchange':\n      case 'resize':\n        this._resize();\n        break;\n      case 'transitionend':\n      case 'webkitTransitionEnd':\n      //case 'oTransitionEnd': // MARK: only for Opera < 12.10\n      case 'MSTransitionEnd':\n        this._transitionEnd(e);\n        break;\n      case 'wheel':\n      case 'DOMMouseScroll':\n      case 'mousewheel':\n        this._wheel(e);\n        break;\n      case 'keydown':\n        this._key(e);\n        break;\n      case 'click':\n        if ( this.enabled && !e._constructed ) {\n          e.preventDefault();\n          e.stopPropagation();\n        }\n        break;\n    }\n  }\n};\nfunction createDefaultScrollbar (direction, interactive, type) {\n  var scrollbar = document.createElement('div'),\n    indicator = document.createElement('div');\n\n  if ( type === true ) {\n    scrollbar.style.cssText = 'position:absolute;z-index:9999';\n    indicator.style.cssText = '-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;position:absolute;background:rgba(0,0,0,0.5);border:1px solid rgba(255,255,255,0.9);border-radius:3px';\n  }\n\n  indicator.className = 'iScrollIndicator';\n\n  if ( direction == 'h' ) {\n    if ( type === true ) {\n      scrollbar.style.cssText += ';height:7px;left:2px;right:2px;bottom:0';\n      indicator.style.height = '100%';\n    }\n    scrollbar.className = 'iScrollHorizontalScrollbar';\n  } else {\n    if ( type === true ) {\n      scrollbar.style.cssText += ';width:7px;bottom:2px;top:2px;right:1px';\n      indicator.style.width = '100%';\n    }\n    scrollbar.className = 'iScrollVerticalScrollbar';\n  }\n\n  scrollbar.style.cssText += ';overflow:hidden';\n\n  if ( !interactive ) {\n    scrollbar.style.pointerEvents = 'none';\n  }\n\n  scrollbar.appendChild(indicator);\n\n  return scrollbar;\n}\n\nfunction Indicator (scroller, options) {\n  this.wrapper = typeof options.el == 'string' ? document.querySelector(options.el) : options.el;\n  this.wrapperStyle = this.wrapper.style;\n  this.indicator = this.wrapper.children[0];\n  this.indicatorStyle = this.indicator.style;\n  this.scroller = scroller;\n\n  this.options = {\n    listenX: true,\n    listenY: true,\n    interactive: false,\n    resize: true,\n    defaultScrollbars: false,\n    shrink: false,\n    fade: false,\n    speedRatioX: 0,\n    speedRatioY: 0\n  };\n\n  for ( var i in options ) {\n    this.options[i] = options[i];\n  }\n\n  this.sizeRatioX = 1;\n  this.sizeRatioY = 1;\n  this.maxPosX = 0;\n  this.maxPosY = 0;\n\n  if ( this.options.interactive ) {\n    if ( !this.options.disableTouch ) {\n      utils.addEvent(this.indicator, 'touchstart', this);\n      utils.addEvent(window, 'touchend', this);\n    }\n    if ( !this.options.disablePointer ) {\n      utils.addEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);\n      utils.addEvent(window, utils.prefixPointerEvent('pointerup'), this);\n    }\n    if ( !this.options.disableMouse ) {\n      utils.addEvent(this.indicator, 'mousedown', this);\n      utils.addEvent(window, 'mouseup', this);\n    }\n  }\n\n  if ( this.options.fade ) {\n    this.wrapperStyle[utils.style.transform] = this.scroller.translateZ;\n    var durationProp = utils.style.transitionDuration;\n    if(!durationProp) {\n      return;\n    }\n    this.wrapperStyle[durationProp] = utils.isBadAndroid ? '0.0001ms' : '0ms';\n    // remove 0.0001ms\n    var self = this;\n    if(utils.isBadAndroid) {\n      rAF(function() {\n        if(self.wrapperStyle[durationProp] === '0.0001ms') {\n          self.wrapperStyle[durationProp] = '0s';\n        }\n      });\n    }\n    this.wrapperStyle.opacity = '0';\n  }\n}\n\nIndicator.prototype = {\n  handleEvent: function (e) {\n    switch ( e.type ) {\n      case 'touchstart':\n      case 'pointerdown':\n      case 'MSPointerDown':\n      case 'mousedown':\n        this._start(e);\n        break;\n      case 'touchmove':\n      case 'pointermove':\n      case 'MSPointerMove':\n      case 'mousemove':\n        this._move(e);\n        break;\n      case 'touchend':\n      case 'pointerup':\n      case 'MSPointerUp':\n      case 'mouseup':\n      case 'touchcancel':\n      case 'pointercancel':\n      case 'MSPointerCancel':\n      case 'mousecancel':\n        this._end(e);\n        break;\n    }\n  },\n\n  destroy: function () {\n    if ( this.options.fadeScrollbars ) {\n      clearTimeout(this.fadeTimeout);\n      this.fadeTimeout = null;\n    }\n    if ( this.options.interactive ) {\n      utils.removeEvent(this.indicator, 'touchstart', this);\n      utils.removeEvent(this.indicator, utils.prefixPointerEvent('pointerdown'), this);\n      utils.removeEvent(this.indicator, 'mousedown', this);\n\n      utils.removeEvent(window, 'touchmove', this);\n      utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);\n      utils.removeEvent(window, 'mousemove', this);\n\n      utils.removeEvent(window, 'touchend', this);\n      utils.removeEvent(window, utils.prefixPointerEvent('pointerup'), this);\n      utils.removeEvent(window, 'mouseup', this);\n    }\n\n    if ( this.options.defaultScrollbars ) {\n      this.wrapper.parentNode.removeChild(this.wrapper);\n    }\n  },\n\n  _start: function (e) {\n    var point = e.touches ? e.touches[0] : e;\n\n    e.preventDefault();\n    e.stopPropagation();\n\n    this.transitionTime();\n\n    this.initiated = true;\n    this.moved = false;\n    this.lastPointX = point.pageX;\n    this.lastPointY = point.pageY;\n\n    this.startTime  = utils.getTime();\n\n    if ( !this.options.disableTouch ) {\n      utils.addEvent(window, 'touchmove', this);\n    }\n    if ( !this.options.disablePointer ) {\n      utils.addEvent(window, utils.prefixPointerEvent('pointermove'), this);\n    }\n    if ( !this.options.disableMouse ) {\n      utils.addEvent(window, 'mousemove', this);\n    }\n\n    this.scroller._execEvent('beforeScrollStart');\n  },\n\n  _move: function (e) {\n    var point = e.touches ? e.touches[0] : e,\n      deltaX, deltaY,\n      newX, newY,\n      timestamp = utils.getTime();\n\n    if ( !this.moved ) {\n      this.scroller._execEvent('scrollStart');\n    }\n\n    this.moved = true;\n\n    deltaX = point.pageX - this.lastPointX;\n    this.lastPointX = point.pageX;\n\n    deltaY = point.pageY - this.lastPointY;\n    this.lastPointY = point.pageY;\n\n    newX = this.x + deltaX;\n    newY = this.y + deltaY;\n\n    this._pos(newX, newY);\n\n// INSERT POINT: indicator._move\n\n    e.preventDefault();\n    e.stopPropagation();\n  },\n\n  _end: function (e) {\n    if ( !this.initiated ) {\n      return;\n    }\n\n    this.initiated = false;\n\n    e.preventDefault();\n    e.stopPropagation();\n\n    utils.removeEvent(window, 'touchmove', this);\n    utils.removeEvent(window, utils.prefixPointerEvent('pointermove'), this);\n    utils.removeEvent(window, 'mousemove', this);\n\n    if ( this.scroller.options.snap ) {\n      var snap = this.scroller._nearestSnap(this.scroller.x, this.scroller.y); // MARK\n\n      var time = this.options.snapSpeed || Math.max(\n          Math.max(\n            Math.min(Math.abs(this.scroller.x - snap.x), 1000),\n            Math.min(Math.abs(this.scroller.y - snap.y), 1000)\n          ), 300);\n\n      if ( this.scroller.x != snap.x || this.scroller.y != snap.y ) {\n        this.scroller.directionX = 0;\n        this.scroller.directionY = 0;\n        this.scroller.currentPage = snap;\n        this.scroller.scrollTo(snap.x, snap.y, time, this.scroller.options.bounceEasing);\n      }\n    }\n\n    if ( this.moved ) {\n      this.scroller._execEvent('scrollEnd');\n    }\n  },\n\n  transitionTime: function (time) {\n    time = time || 0;\n    var durationProp = utils.style.transitionDuration;\n    if(!durationProp) {\n      return;\n    }\n\n    this.indicatorStyle[durationProp] = time + 'ms';\n\n    if ( !time && utils.isBadAndroid ) {\n      this.indicatorStyle[durationProp] = '0.0001ms';\n      // remove 0.0001ms\n      var self = this;\n      rAF(function() {\n        if(self.indicatorStyle[durationProp] === '0.0001ms') {\n          self.indicatorStyle[durationProp] = '0s';\n        }\n      });\n    }\n  },\n\n  transitionTimingFunction: function (easing) {\n    this.indicatorStyle[utils.style.transitionTimingFunction] = easing;\n  },\n\n  refresh: function () {\n    if (this.options.overrideMeasurements) // SPC\n      return; // SPC\n\n    this.transitionTime();\n\n    if ( this.options.listenX && !this.options.listenY ) {\n      this.indicatorStyle.display = this.scroller.hasHorizontalScroll ? 'block' : 'none';\n    } else if ( this.options.listenY && !this.options.listenX ) {\n      this.indicatorStyle.display = this.scroller.hasVerticalScroll ? 'block' : 'none';\n    } else {\n      this.indicatorStyle.display = this.scroller.hasHorizontalScroll || this.scroller.hasVerticalScroll ? 'block' : 'none';\n    }\n\n    if ( this.scroller.hasHorizontalScroll && this.scroller.hasVerticalScroll ) {\n      utils.addClass(this.wrapper, 'iScrollBothScrollbars');\n      utils.removeClass(this.wrapper, 'iScrollLoneScrollbar');\n\n      if ( this.options.defaultScrollbars && this.options.customStyle ) {\n        if ( this.options.listenX ) {\n          this.wrapper.style.right = '8px';\n        } else {\n          this.wrapper.style.bottom = '8px';\n        }\n      }\n    } else {\n      utils.removeClass(this.wrapper, 'iScrollBothScrollbars');\n      utils.addClass(this.wrapper, 'iScrollLoneScrollbar');\n\n      if ( this.options.defaultScrollbars && this.options.customStyle ) {\n        if ( this.options.listenX ) {\n          this.wrapper.style.right = '2px';\n        } else {\n          this.wrapper.style.bottom = '2px';\n        }\n      }\n    }\n\n    var r = this.wrapper.offsetHeight;  // force refresh\n\n    if ( this.options.listenX ) {\n      this.wrapperWidth = this.wrapper.clientWidth;\n      if ( this.options.resize ) {\n        this.indicatorWidth = Math.max(Math.round(this.wrapperWidth * this.wrapperWidth / (this.scroller.scrollerWidth || this.wrapperWidth || 1)), 8);\n        this.indicatorStyle.width = this.indicatorWidth + 'px';\n      } else {\n        this.indicatorWidth = this.indicator.clientWidth;\n      }\n\n      this.maxPosX = this.wrapperWidth - this.indicatorWidth;\n\n      if ( this.options.shrink == 'clip' ) {\n        this.minBoundaryX = -this.indicatorWidth + 8;\n        this.maxBoundaryX = this.wrapperWidth - 8;\n      } else {\n        this.minBoundaryX = 0;\n        this.maxBoundaryX = this.maxPosX;\n      }\n\n      this.sizeRatioX = this.options.speedRatioX || (this.scroller.maxScrollX && (this.maxPosX / this.scroller.maxScrollX));\n    }\n\n    if ( this.options.listenY ) {\n      this.wrapperHeight = this.wrapper.clientHeight;\n      if ( this.options.resize ) {\n        this.indicatorHeight = Math.max(Math.round(this.wrapperHeight * this.wrapperHeight / (this.scroller.scrollerHeight || this.wrapperHeight || 1)), 8);\n        this.indicatorStyle.height = this.indicatorHeight + 'px';\n      } else {\n        this.indicatorHeight = this.indicator.clientHeight;\n      }\n\n      this.maxPosY = this.wrapperHeight - this.indicatorHeight;\n\n      if ( this.options.shrink == 'clip' ) {\n        this.minBoundaryY = -this.indicatorHeight + 8;\n        this.maxBoundaryY = this.wrapperHeight - 8;\n      } else {\n        this.minBoundaryY = 0;\n        this.maxBoundaryY = this.maxPosY;\n      }\n\n      this.maxPosY = this.wrapperHeight - this.indicatorHeight;\n      this.sizeRatioY = this.options.speedRatioY || (this.scroller.maxScrollY && (this.maxPosY / this.scroller.maxScrollY));\n    }\n\n    this.updatePosition();\n  },\n\n  updatePosition: function () {\n    var x = this.options.listenX && Math.round(this.sizeRatioX * this.scroller.x) || 0,\n      y = this.options.listenY && Math.round(this.sizeRatioY * this.scroller.y) || 0;\n\n    if ( !this.options.ignoreBoundaries ) {\n      if ( x < this.minBoundaryX ) {\n        if ( this.options.shrink == 'scale' ) {\n          this.width = Math.max(this.indicatorWidth + x, 8);\n          this.indicatorStyle.width = this.width + 'px';\n        }\n        x = this.minBoundaryX;\n      } else if ( x > this.maxBoundaryX ) {\n        if ( this.options.shrink == 'scale' ) {\n          this.width = Math.max(this.indicatorWidth - (x - this.maxPosX), 8);\n          this.indicatorStyle.width = this.width + 'px';\n          x = this.maxPosX + this.indicatorWidth - this.width;\n        } else {\n          x = this.maxBoundaryX;\n        }\n      } else if ( this.options.shrink == 'scale' && this.width != this.indicatorWidth ) {\n        this.width = this.indicatorWidth;\n        this.indicatorStyle.width = this.width + 'px';\n      }\n\n      if ( y < this.minBoundaryY ) {\n        if ( this.options.shrink == 'scale' ) {\n          this.height = Math.max(this.indicatorHeight + y * 3, 8);\n          this.indicatorStyle.height = this.height + 'px';\n        }\n        y = this.minBoundaryY;\n      } else if ( y > this.maxBoundaryY ) {\n        if ( this.options.shrink == 'scale' ) {\n          this.height = Math.max(this.indicatorHeight - (y - this.maxPosY) * 3, 8);\n          this.indicatorStyle.height = this.height + 'px';\n          y = this.maxPosY + this.indicatorHeight - this.height;\n        } else {\n          y = this.maxBoundaryY;\n        }\n      } else if ( this.options.shrink == 'scale' && this.height != this.indicatorHeight ) {\n        this.height = this.indicatorHeight;\n        this.indicatorStyle.height = this.height + 'px';\n      }\n    }\n\n    this.x = x;\n    this.y = y;\n\n    if ( this.scroller.options.useTransform ) {\n      this.indicatorStyle[utils.style.transform] = 'translate(' + x + 'px,' + y + 'px)' + this.scroller.translateZ;\n    } else {\n      this.indicatorStyle.left = x + 'px';\n      this.indicatorStyle.top = y + 'px';\n    }\n  },\n\n  _pos: function (x, y) {\n    if ( x < 0 ) {\n      x = 0;\n    } else if ( x > this.maxPosX ) {\n      x = this.maxPosX;\n    }\n\n    if ( y < 0 ) {\n      y = 0;\n    } else if ( y > this.maxPosY ) {\n      y = this.maxPosY;\n    }\n\n    x = this.options.listenX ? Math.round(x / this.sizeRatioX) : this.scroller.x;\n    y = this.options.listenY ? Math.round(y / this.sizeRatioY) : this.scroller.y;\n\n    this.scroller.scrollTo(x, y);\n  },\n\n  fade: function (val, hold) {\n    if ( hold && !this.visible ) {\n      return;\n    }\n\n    clearTimeout(this.fadeTimeout);\n    this.fadeTimeout = null;\n\n    var time = val ? 250 : 500,\n      delay = val ? 0 : 300;\n\n    val = val ? '1' : '0';\n\n    this.wrapperStyle[utils.style.transitionDuration] = time + 'ms';\n\n    this.fadeTimeout = setTimeout((function (val) {\n      this.wrapperStyle.opacity = val;\n      this.visible = +val;\n    }).bind(this, val), delay);\n  }\n};\n\nIScroll.utils = utils;\n\nif ( typeof module != 'undefined' && module.exports ) {\n  module.exports = IScroll;\n} else if ( typeof define == 'function' && define.amd ) {\n        define( function () { return IScroll; } );\n} else {\n  window.IScroll = IScroll;\n}\n\n})(window, document, Math);\n","import * as dompack from \"dompack\";\nimport IScroll from \"./iscroll.modified\";\n\nlet tempid = 0;\n\n\nif (!window.__spc_carrousels)\n  window.__spc_carrousels = [];\n\nexport default class SpellcoderCarrousel\n{\n  /*\n  Variables used internally:\n      options\n      node\n      nodes.viewport\n      nodes.content\n      nodes.btn_prev\n      nodes.btn_next\n      items\n      items[].node\n      items[].width\n      items[].height\n      items[].left\n      items[].right\n      items[].usecount - at every animation frame the count is started at 0. It's used to deteremine which index to use in nodecopies.\n      items[].nodecopies - the original carrousel__cell and it's clones. when more clones are needed to fill up the carrousel's viewport, a clone is added on-the-fly.\n\n      items_onscreen - list of nodes in use. used to match after drawing all caroussel-cell's which nodes from the previous animation frame aren't used anymore and must be moved offscreen.\n\n      visiblenodes - rendering information that can be used outside the class for special effects\n\n      scrollleft - the virtual scroll left we internally work with\n      width_content - the size of the content (which will be repeated)\n      width_viewport\n      largestslideheight\n\n      slide_virtualstartidx\n      slide_offset\n\n      activeslideidx\n      activeslidenode\n      alignedslideidx\n      alignedslidenode - the (copy of the) slide which is active\n      alignedslidevirtualidx\n\n      paused // not implemented yet\n  */\n  constructor(node, options)\n  {\n    // DEBUG\n    window.__spc_carrousels.push(this);\n\n    tempid++;\n    this.tempid = tempid;\n\n    // for debugging\n    this.logprefix = \"name\" in options ? \"[SPC/CARROUSEL/\"+options.name+\"]\"\n                                       : \"[SPC/CARROUSEL #\" + this.tempid + \"]\";\n\n    if (!node)\n    {\n      console.error(\"SpellcoderCarrousel got null as node.\");\n      return;\n    }\n\n    var domoptions = dompack.getJSONAttribute(node, \"data-carrousel-options\");\n\n    this.options = Object.assign(\n            { // layout  -----------------------------------------------------------------------\n              gap:                20\n            , slidewidth:         0 // if set, the fixed width (in px) will be used instead of the measures width\n            , height:             0 // to override the automatic height based on slide height\n                                    // (auto slide height doesn't take things like box-shadow's into account and so the overflow: hidden; meant to prevent page overflow will cut off the box-shadows)\n            , updateviewportheight: true // Update the height of our viewport based on the specified height option or height of the slides.\n                                        // Set to TRUE of we want to resize to the slides or our parent have no fixed height\n                                        // Set to FALSE in case our parent has a fixed height which we want to fill (often in an inline/in-the-page slideshow)\n\n            // padding around the content space in which the active slide is positioned\n            , paddingLeft:        0\n            , paddingRight:       0\n\n            /*\n            \"viewport_left\"   - active slide will be at the far left, regardless of paddingLeft\n            \"viewport_middle\" - center the cell in the full space used by the carrousel\n            \"viewport_right\"  - !! not implemented yet\n\n            \"left\" - left\n            \"middle\" - center the cell in the content space (between the paddingLeft and paddingRight)\n            \"right\" - !! not implemented yet\n            */\n            , activeslidealignment:  \"left\"\n            , vertical_align:        \"top\" // \"top\", \"middle\", \"bottom\"\n\n\n            // scroll behaviour -----------------------------------------------------------------\n            , interactable:        true // allow drag, keyboard interaction etc... (if you use multiple carrousels and one is the main)\n            , useiscroll:          true // if false, no scroll animation is performed and no dragging is possible\n            , draggable:           true\n            , snap:                true\n            , blockscrolloncontentleft: false\n            , scroll_deceleration: 0.004 // default of iScroll is 0.0006\n\n\n            // content --------------------------------------------------------------------------\n            , items:                 \"\" // nodeList or string(selectors)\n            , renderinfo:            null\n            , masonry_renderinfo:    [] // renderinfo from Spellcoder Masonry, to turn a Masonry into an Carrousel\n            , contentnode:           null // node in which to place newly clones nodes. for easy grouping (destroying/fade effects)\n\n            , buttonprevious:        null\n            , buttonnext:            null\n            , slideskip:             1\n\n\n            // layout overrides ---------------------------------------------------------------\n            // (use at own risk)\n\n            , contentwidth:          null // amount of pixels after which the content will be repeated\n\n\n            // behaviour ----------------------------------------------------------------------\n\n            , nextSlideDelay:     5000  // ADDME\n            , transitionDuration: 750\n\n            /** allow mouse/touch events to pass, so vertical scrolling keeps working\n               downside is that dragging may cause selections. */\n            , eventPassthrough:   true\n\n            , initialslide:        0       // set to \"none\" to start a left 0 of the original content\n            , activateslidewithclick: true // when clicking on a cell, make it the active slide\n\n            , keyboardnavigation:  true\n\n            , randomizeslides:    false // set to true to randomize the slides on initialization\n\n            /** In case cases you might want to first setup stuff.. or prevent getting a callback before getting the returnvalue of new Carrousel..\n                If this is the case set autodraw_firstframe to false and call drawFrame();\n            */\n            , autodraw_firstframe: true\n\n            , debugoptions:       false // show computer carrousel and iScroll options\n            , debugslides:        false // show debug info in slides\n            , debugdimensions:    false // show debug information on the calculated slides and carrousel dimensions\n            , debugdraw:          false // show debug information on drawing/animation\n\n            , delayfirstframe:    false\n\n            // hooks & internal ---------------------------------------------------------------\n            , ondrawframe:        null // hook to call when a frame is drawn (this is done in an animationframe, usually when the scroll position has changed or an update has been forced)\n            // optimalizations\n            , items_positions_ordered: true // when using as a slideshow, simple horizontal carrousel all images can be placed after eachother and drawing can end upon the first item which is outside the viewport\n                                            // Set this to false if using the carrousel for arbitrary positioned content (for example an masonry)\n            }, domoptions, options);\n\n    this.node = node;\n\n    this.nodes =\n            { dragarea:   this.getSelfOrChild(node, \"carrousel__dragarea\")\n            , viewport:   this.getSelfOrChild(node, \"carrousel__viewport\") // positioning container for items + focus element for keyboard navigation\n            , content:    this.options.contentnode    ? this.options.contentnode : this.getSelfOrChild(node, \"carrousel__content\") // for easy grouping of all items (easy deletion/replacing), falls back to viewport if not existant.. all copies of content will be thrown into this container.\n            , btn_prev:   this.options.buttonprevious ? this.options.buttonprevious : this.getSelfOrChild(node, \"carrousel__previous\")\n            , btn_next:   this.options.buttonnext     ? this.options.buttonnext     : this.getSelfOrChild(node, \"carrousel__next\")\n            };\n\n    //this._addToLog(\"Initialized while document readyState is \" + document.readyState);\n\n    if (this.options.debugoptions)\n    {\n      console.groupCollapsed(this.logprefix);\n      console.log(\"Computed options\", this.options);\n      console.groupEnd();\n    }\n\n    if (!this.nodes.dragarea)\n      this.nodes.dragarea = this.node;\n\n    if (!this.nodes.viewport)\n      this.nodes.viewport = this.node;\n\n    if (!this.nodes.content)\n      this.nodes.content = this.nodes.viewport;\n\n    this.nodes.viewport.tabIndex = -1;\n    this.nodes.viewport.addEventListener(\"keydown\", this.onKeyPress.bind(this));\n\n    this.items = []; // the original slides/carousel-cells\n    this.items_onscreen = [];\n    this.visiblenodes = []; // ADDME: rendering information\n\n    this.scrollleft = 0;\n    this.width_viewport = 0;\n    this.width_content = 0;\n    this.largestslideheight = 0;\n\n    // variables to allow navigation to work during an active scroll\n    // (otherwise we have to freeze the navigation buttons until each previous/next action has completed)\n    this.slide_virtualstartidx = -1; // from which slide we started to slide. used to determine the direction of the scroll.\n    this.slide_offset = 0; // how many items to slide during the current scroll action\n\n    this.activeslideidx = this.options.initialslide;\n    this.activeslidenode = null;\n\n    this.alignedslide = null;\n    this.alignedslideidx = this.options.initialslide;\n    //this.alignedslidevirtualidx = 0;\n    this.alignedslidenode = null;\n\n    this.animationframe = null;\n\n    this.finishedinit = false; // if our content width is 0 we have to delay until this changes\n\n    //this.paused = false;\n\n    if (\"renderinfo\" in options)\n    {\n      this.importRenderInfo(options.renderinfo);\n    }\n    else if (\"masonry_renderinfo\" in options)\n    {\n      this.importSlidesFromMasonry(options.masonry_renderinfo);\n    }\n    else if (\"items\" in options)\n    {\n      if (typeof(options.items) == \"string\") // assume a selector string\n      {\n        console.log(\"items is a selector string\"); // debug\n        let nodes = node.querySelectorAll(options.items);\n        if (nodes.length == 0)\n        {\n          console.warn(\"No slides specified for the carrousel.\");\n          return;\n        }\n\n        this.setSlides(nodes);\n      }\n      else if(options.items instanceof NodeList || options.items instanceof Array)\n      {\n        console.log(\"items is a NodeList\"); // debug\n        this.setSlides(options.items);\n      }\n    }\n    else\n    {\n      let nodes = node.querySelectorAll(\".carrousel__cell\");\n      if (nodes.length == 0)\n      {\n        console.warn(\"No slides specified for the carrousel.\");\n        return;\n      }\n\n      this.setSlides(nodes);\n    }\n\n    if (this.options.contentwidth) // override any calculated (or imported from renderinfo) content width\n      this.width_content = this.options.contentwidth;\n\n    this.__determineContainerWidth();\n\n    this.virtualwidth = 2147483645;\n\n    if (this.options.blockscrolloncontentleft)\n      this.scrollleft = 0; // endless scroll to the right\n    else\n      this.scrollleft = Math.round(this.virtualwidth / 2); // endless scroll to all sides\n\n    this.attemptFinishInit();\n  }\n\n  attemptFinishInit()\n  {\n    if (this.width_content == 0)\n    {\n      console.info(\"Carrousel\", this.options.name, \"cancelled init (content width is 0)\");\n      return;\n    }\n    else\n      console.info(\"Carrousel\", this.options.name, \"is finishing init\");\n\n    let initialx = this.scrollleft;\n\n    if (this.options.initialslide != \"none\")\n    {\n      initialx = this.__getLeftForSlide(this.options.initialslide);\n      if (isNaN(initialx))\n        console.error(\"Cannot determine initial X position. (internal slides info corrupt?)\");\n    }\n    else\n    {\n      //initialx = this.__getContentScrollToVirtualScroll(this.scrollleft);\n      initialx = this.scrollleft - this.scrollleft % this.width_content; // round down to the nearest 0 in content position\n    }\n\n    if (this.options.useiscroll)\n    {\n      let iscrollsettings =\n          { useTransition: false // this would request computed style\n          , tap: true\n          , eventPassthrough: this.options.eventPassthrough\n\n          , deceleration: this.options.scroll_deceleration\n\n          , autoUpdatePosition: false // OVERRIDE\n          , overrideMeasurements: true // OVERRIDE\n\n          , wrapperWidth:  this.width_viewport // don't care // FIXME: care because this influences the momentum\n          , scrollerWidth: 0 // don't care\n\n          , maxScrollX:    this.virtualwidth\n          , startX:        -initialx\n\n          , scrollX: true\n          , scrollY: false\n\n          , snap:           this.options.snap\n          //, snapStepX: this.options.slidewidth\n          , getNearestSnap: this.getNearestSnap.bind(this)\n          , getPage:        this.getPage.bind(this)\n\n          , mouseWheel:     false\n          // mouseWheel disabled, because with mouse as input it's usually very jerky\n          //, mouseWheel:     this.options.interactable && this.options.mouseWheel\n          //mouseWheelSpeed: 20\n/*\n          , disableMouse:   !this.options.interactable\n          , disablePointer: !this.options.interactable\n          , disableTouch:   !this.options.interactable\n*/\n          , name:           \"\" // for debugging purposes\n          };\n\n      if (this.options.debugoptions)\n        console.log(iscrollsettings);\n\n      this.iscroll = new IScroll(this.nodes.dragarea, iscrollsettings);\n      this.iscroll.tempid = this.options.name + \"-iscroll\"; // debug\n\n      this.iscroll.on(\"scrollEnd\", this.onScrollEnd.bind(this));\n\n      if (!this.options.interactable || !this.options.draggable)\n        this.iscroll.disable();\n\n      this.prevtime = -1;\n\n      if (this.nodes.btn_prev)\n      {\n        // FIXME: if within viewport AND using iscroll ??\n//        if (dompack.closest(this.nodes.btn_prev, \".carrousel__viewport\")) // FIXME: look for this.nodes.viewport instead\n//          this.nodes.btn_prev.addEventListener(\"tap\", this.__onPreviousSlideClick.bind(this));\n//        else\n          this.nodes.btn_prev.addEventListener(\"click\", this.__onPreviousSlideClick.bind(this));\n      }\n\n      if (this.nodes.btn_next)\n      {\n//        if (dompack.closest(this.nodes.btn_next, \".carrousel__viewport\")) // FIXME: look for this.nodes.viewport instead\n//          this.nodes.btn_next.addEventListener(\"tap\", this.__onNextSlideClick.bind(this));\n//        else\n          this.nodes.btn_next.addEventListener(\"click\", this.__onNextSlideClick.bind(this));\n      }\n\n      this.nodes.viewport.addEventListener(\"tap\", this.__detectCellTap.bind(this));\n    }\n    else\n    {\n      this.scrollleft = 0;\n      this.scrollleft_next = initialx;\n    }\n\n    this.finishedinit = true;\n\n    if (!this.options.delayfirstframe)\n      this.onAnimFrame(0, true);    \n  }\n\n  destroy()\n  {\n    // prevent eventlisteners keeping iscroll and us alive\n    // (and triggering our onanimframe)\n    this.iscroll.destroy();\n    cancelAnimationFrame(this.animationframe);\n\n    let idx = window.__spc_carrousels.indexOf(this);\n    window.__spc_carrousels.splice(idx, 1);\n\n    /*\n    destroy references\n\n    for(let item of this.items)\n    {\n      for (let node of item.nodecopies)\n        delete node.__iteminfo // remove reference from node to it's rendering/item info object within our carrousel\n\n      item.nodecopies = null;\n    }\n    */\n\n    //this.dead = true;\n  }\n\n  getSelfOrChild(node, classname)\n  {\n    if (node.classList.contains(classname))\n      return node;\n    else\n      return node.querySelector(\".\"+classname);\n  }\n\n  setOptions(options)\n  {\n    //var need_slides_refresh = false;\n    //need_slides_refresh = (\"gap\" in options && gap != this.options.gap);\n\n    Object.assign(this.options, options);\n\n    //if (need_slides_refresh)\n    //  this.__refreshSlidesLayout();\n  }\n\n  onAnimFrame(timestamp, force)\n  {\n//console.log(\"onAnimFrame\", timestamp, force, this.iscroll.x);\n\n    window.cancelAnimationFrame(this.animationframe);\n    this.animationframe = null;\n\n    var dpr = window.devicePixelRatio;\n    if (!dpr)\n      dpr = 1; // fallback for IE10\n\n    var currentpos;\n    if (this.options.useiscroll)\n    {\n      if (isNaN(this.iscroll.x)) // FIXME: find the cause and remove\n      {\n        //console.error(\"ISCROLL's x position is not a number!\");\n        //currentpos = 0;\n        return;\n      }\n      currentpos = -Math.round(this.iscroll.x * dpr) / dpr;\n    }\n    else\n      currentpos = Math.round(this.scrollleft_next * dpr) / dpr;\n\n    if (force || this.scrollleft != currentpos)\n    {\n//       console.log(\"Scrolling:\", this.iscroll.x, dpr, currentpos);\n\n      //console.log(force, this.scrollleft, currentpos);\n\n      this.scrollleft = currentpos;\n      this.__redraw_slides(true);\n    }\n    else\n    {\n      if (this.options.ondrawframe)\n      {\n        var scrollleft = this.scrollleft % this.width_content;\n        //var visible_left = scrollleft;\n        //var visible_right = visible_left + this.width_viewport;\n        this.options.ondrawframe.bind(this)(\n                { scrollleft:   this.scrollleft // scrollposition in the virtual (almost endless) space\n                , contentleft:  scrollleft // scrollposition in the content (xpos in the content where we start in our container)\n                , contentwidth: this.width_content\n                , draw:         false // not drawing\n                });\n      }\n    }\n\n    // schedule the next frame\n    // (!! don't move this to the start of the function, this might create a race condition)\n    if (!this.animationframe)\n      this.animationframe = requestAnimationFrame(this.onAnimFrame.bind(this));\n  }\n\n  /** @short scroll to the x position in the virtual space\n  */\n  scrollTo(newx, animate)\n  {\n    //console.log(this.options.name+\".scrollTo\", newx, animate);\n\n    if (this.options.useiscroll)\n      this.iscroll.scrollTo(-newx, 0, animate ? this.options.transitionDuration : 0);\n    else\n    {\n      console.info(this.options.name + \" no iscroll\");\n      this.scrollleft_next = newx;\n      this.__redraw_slides(true);\n    }\n  }\n\n  scrollBy(offsetx, animate)\n  {\n    //console.log(this.options.name+\".scrollBy\", offsetx, animate);\n\n    if (this.options.useiscroll)\n    {\n      //this.iscroll.scrollTo(-(this.scrollleft + offsetx), 0, animate ? this.options.transitionDuration : 0);\n\n      // We apply the offset to iScroll's internal X since that one hasn't been rounded,\n      // allowing us to scroll with subpixel position (even though we position at whole pixels)\n      this.iscroll.scrollTo(this.iscroll.x - offsetx, 0, animate ? this.options.transitionDuration : 0);\n    }\n    else\n    {\n      console.info(this.options.name + \" no iscroll\");\n      this.scrollleft_next += newx;\n      this.__redraw_slides(true);\n    }\n  }\n\n  /** @short scroll to the (nearest copy of the) content x position\n  */\n  scrollToContent(newx, forward, animate)\n  {\n    let xfloor = Math.floor(this.scrollleft / this.width_content) * this.width_content;\n    let xceil = xfloor + this.width_content;\n\n    if (forward)\n      this.scrollTo(xceil, animate);\n    else\n      this.scrollTo(xfloor, animate);\n  }\n\n  /** @short slide to (a copy of the) specified slide\n  */\n  jumpToSlide(idx, animate, forward)\n  {\n    if (idx >= this.items.length)\n    {\n      console.error(\"Slide #\"+idx+\" doesn't exist.\");\n      return;\n    }\n\n    this.activeslideidx = idx; // FIXME: should we do this here?\n\n    var newx = this.__getLeftForSlide(idx, forward);\n    this.iscroll.scrollTo(-newx, 0, animate ? this.options.transitionDuration : 0);\n  }\n\n  /** @short slide to the virtual slide\n  */\n  jumpToVirtualSlide(virtualidx)\n  {\n    if (virtualidx < 0)\n    {\n      console.error(\"Negative virtual slide idx not supported.\")\n      return;\n    }\n    // ADDME: should we set this.activeslideidx ?\n\n    var newx = this.__getVirtualLeftForSlide(virtualidx);\n    this.iscroll.scrollTo(-newx, 0, this.options.transitionDuration);\n  }\n\n  previousSlide()\n  {\n    if (this.slide_virtualstartidx == -1)\n    {\n      //console.info(\"Restart slide_virtualstartidx\");\n      this.slide_virtualstartidx = this.alignedslidevirtualidx;\n    }\n\n    this.slide_offset -= this.options.slideskip;\n\n    //console.log(\"previousSlide to \", this.slide_virtualstartidx, \"+\", this.slide_offset, \"=\", this.slide_virtualstartidx + this.slide_offset);\n\n    this.jumpToVirtualSlide(this.slide_virtualstartidx + this.slide_offset, true);\n  }\n\n  nextSlide()\n  {\n    if (this.slide_virtualstartidx == -1)\n    {\n      //console.info(\"Restart slide_virtualstartidx\");\n      this.slide_virtualstartidx = this.alignedslidevirtualidx;\n    }\n\n    this.slide_offset += this.options.slideskip;\n\n    if (this.options.name == \"videos\")\n      console.log(\"nextSlide to \", this.slide_virtualstartidx, \"+\", this.slide_offset, \"=\", this.slide_virtualstartidx + this.slide_offset);\n\n    this.jumpToVirtualSlide(this.slide_virtualstartidx + this.slide_offset, true);\n  }\n\n  onScrollEnd()\n  {\n    //console.info(\"onScrollEnd\");\n    this.slide_virtualstartidx = -1;\n    this.slide_offset = 0;\n  }\n\n\n  __determineContainerWidth()\n  {\n    this.width_viewport = this.nodes.viewport.clientWidth;\n\n    if (this.options.debugdimensions)\n      console.log(this.logprefix, \"New carrousel width_viewport is \", this.width_viewport)\n\n    if (this.width_viewport == 0)\n      console.warn(\"clientWidth of carrousel viewport is 0.\");\n  }\n\n  refresh()\n  {\n    this.__determineContainerWidth();\n//    if (this.width_viewport == 0)\n//      return; // nothing to draw\n\n    this.jumpToSlide(this.alignedslideidx, false) // heractiveer deze regel\n\n    this.__redraw_slides(true);\n\n    // reset keyboard navigation information\n    this.slide_virtualstartidx = -1;\n    this.slide_offset = 0;\n  }\n\n  drawFrame()\n  {\n    this.__redraw_slides(true);\n  }\n\n  // PRIVATE //////////////////////////////////////////////////////////////////////////////////\n\n\n\n  importRenderInfo(renderinfo)\n  {\n    this.width_content = renderinfo.width;\n    this.largestslideheight = renderinfo.height; // renderinfo.height; ... TEMP workaround FIXME\n\n//console.info(\"importLayoutArray\", items.length);\n\n    for (let item of renderinfo.items)\n    {\n      // enrich with some internal data\n      item.usecount = 0;\n      item.nodecopies = [item.node];\n\n      this.items_onscreen.push(item.node); // push so refresh() will move these out of view if needed\n\n      item.node.__iteminfo = item;\n    }\n\n    this.items = renderinfo.items;\n\n    this.__relayoutViewport();\n  }\n\n  // @short import items from a Spellcoder Masonry\n  //        Items imported this way aren't placed side by side, but their left position is copied.\n  //        The top style property will be left untouched.\n  importSlidesFromMasonry(renderinfo)\n  {\n    //console.log(renderinfo);\n    if (renderinfo.width == 0)\n    {\n      console.error(\"Cannot import data from masonry, it's width is reported to be 0.\")\n      return;\n    }\n\n    this.width_content = renderinfo.width;\n    this.largestslideheight = renderinfo.height; // renderinfo.height; ... TEMP workaround FIXME\n\n    /*\n    renderinfo.items[] =\n        col: 0\n        cols: 1\n        height: 100\n        left:0\n        node:div.projectview__project\n        top:0\n        width:469\n    */\n\n    for (let item of renderinfo.items)\n    {\n      var iteminfo =\n        { node:       item.node\n        , width:      item.width\n        , width_real: item.width\n        , height:     item.height\n        , left:       item.left\n        , right:      item.left + item.width\n        , usecount:   0\n        , nodecopies: [item.node]\n        };\n      this.items.push(iteminfo);\n      this.items_onscreen.push(item.node); // push so refresh() will move these out of view if needed\n\nitem.node.style.left = \"0\";\n      item.node.__iteminfo = iteminfo;\n    }\n\n    if (this.options.randomizeslides)\n      this._randomizeSlides();\n\n    this.__relayoutViewport();\n  }\n\n//TEST\n  // FIXME: if used again remove all old slides from the DOM ?\n  setSlides(nodes)\n  {\n    if (this.options.debugdimensions)\n      console.info(this.logprefix, \"setSlides\")\n\n    let posx = 0;\n    let largestheight = 0;\n    this.width_content = 0;\n\n    var fixedslidewidth = Math.round(this.options.slidewidth);\n\n    for (let node of nodes)\n    {\n      var width = node.offsetWidth;\n      var height = node.offsetHeight;\n\n      if (height > largestheight)\n        largestheight = height;\n\n      var positionwidth = fixedslidewidth > 0 ? fixedslidewidth : width;\n\n      var iteminfo =\n        { node:       node\n        , width:      positionwidth\n        , width_real: width\n        , height:     height\n\n        , left:       posx\n        , right:      posx + positionwidth\n\n        , usecount:   0      // how many times this slide is shown in the current drawn frame\n        , nodecopies: [node] // cache of all copies of the slide (including the original node)\n        };\n\n      if (fixedslidewidth > 0)\n        iteminfo.left += (positionwidth - width) / 2;\n\n      this.items.push(iteminfo);\n\n      this.items_onscreen.push(node); // push so refresh() will move these out of view if needed\n\n      posx += positionwidth + this.options.gap;\n\n      this.width_content += positionwidth + this.options.gap;\n\n      node.__iteminfo = iteminfo;\n    }\n\n    if (this.options.randomizeslides)\n      this._randomizeSlides();\n\n    this.largestslideheight = largestheight;\n\n    if (this.options.debugdimensions)\n      this._logSlides();\n\n    this.__relayoutViewport();\n  }\n\n  _randomizeSlides()\n  {\n    for (let i = this.items.length - 1; i > 0; --i)\n    {\n      let j = Math.floor(Math.random() * (i + 1));\n\n      let tmp = this.items[i];\n      this.items[i] = this.items[j];\n      this.items[j] = tmp;\n\n      tmp = this.items_onscreen[i];\n      this.items_onscreen[i] = this.items_onscreen[j];\n      this.items_onscreen[j] = tmp;\n    }\n  }\n\n  _addToLog(msg)\n  {\n    console.info(this.logprefix + \" \" + msg);\n  }\n\n  _logSlides()\n  {\n    if (this.options.debugdimensions)\n    {\n      this._addToLog(\"largest slide height is \" + this.largestslideheight);\n      for (let item of this.items)\n        this._addToLog(\"slide is \"+item.width+\"x\"+item.height);\n    }\n  }\n\n  /** @short call when dimension of slides have changes\n  */\n  relayoutSlides()\n  {\n    if (this.options.debugdimensions)\n      console.info(this.logprefix, \"relayoutSlides\")\n\n    let posx = 0;\n    let largestheight = 0;\n    let width_content = 0;\n\n    var fixedslidewidth = Math.round(this.options.slidewidth);\n\n    for (var idx = 0; idx < this.items.length; idx++)\n    {\n      var iteminfo = this.items[idx];\n      //console.log(\"Before\", iteminfo);\n\n      var width = iteminfo.node.offsetWidth;\n      var height = iteminfo.node.offsetHeight;\n\n      if (height > largestheight)\n        largestheight = height;\n\n      var positionwidth = fixedslidewidth > 0 ? fixedslidewidth : width;\n\n      iteminfo.width = positionwidth;\n      iteminfo.width_real = width\n      iteminfo.height = height;\n      iteminfo.left = posx;\n      iteminfo.right = posx + positionwidth;\n      //console.log(\"After\", iteminfo);\n\n      if (fixedslidewidth > 0)\n        iteminfo.left += (positionwidth - width) / 2;\n\n      posx += positionwidth + this.options.gap;\n\n      width_content += positionwidth + this.options.gap;\n    }\n\n    // FIXME: for now everything will get messed up if this.width_content is 0\n    //        so bail here and pages in which a carrousel temporary gets hidden\n    //        will stay working correctly\n    if (width_content == 0)\n    {\n      console.error(\"Content width is 0\");\n      return;\n    }\n\n    this.width_content = width_content;\n    this.largestslideheight = largestheight;\n\n    if (this.options.debugdimensions)\n      this._logSlides();\n\n    this.__relayoutViewport();\n\n    if (!this.finishedinit)\n      this.attemptFinishInit();\n  }\n\n  __relayoutViewport()\n  {\n    this.width_viewport = this.nodes.viewport.clientWidth;\n\n    let newheight = 0;\n    if (this.options.height)\n    {\n      newheight = this.options.height;\n    }\n    else\n    {\n      if (this.options.debugdimensions)\n        console.info(\"No options.height set, using the largestslideheight\");\n\n      newheight = this.largestslideheight;\n    }\n\n    if (this.options.debugdimensions)\n      console.log(\"__relayoutViewport reads width (\", this.width_viewport, \") and sets viewport height to\", newheight);\n\n    if (this.options.updateviewportheight)\n      this.nodes.viewport.style.height = newheight + \"px\";\n  }\n\n  // PRIVATE - UI interaction //////////////////////////////////////////////////////////////////\n\n  onKeyPress(evt)\n  {\n    //if (this.options.debug)\n    //  console.log(evt.keyCode, this.options.interactable, this.options.keyboardnavigation);\n\n    if (!this.options.interactable || !this.options.keyboardnavigation)\n      return;\n\n    switch (evt.keyCode)\n    {\n      case 37: // left arrow\n      {\n        evt.preventDefault();\n        evt.stopPropagation();\n        this.previousSlide();\n        break;\n      }\n\n      case 39: // right arrow\n      {\n        evt.preventDefault();\n        evt.stopPropagation();\n        this.nextSlide();\n        break;\n      }\n\n      case 27: // escape\n      {\n        evt.preventDefault();\n        evt.stopPropagation();\n        dompack.dispatchCustomEvent( this.node\n                                   , \"wh:closeslideshow\"\n                                   , { bubbles:    false // FIXME: or would we ever want this to be true?\n                                     , cancelable: false\n                                     , detail:     { carrousel:          this // for access if no reference was kept or if our event gets dispatched for 'new Carrousel' has returned \"this\".\n                                                   }\n                                     });\n        break;\n      }\n    }\n  }\n\n  __onPreviousSlideClick(evt)\n  {\n    evt.preventDefault();\n    evt.stopPropagation();\n    this.previousSlide(evt);\n  }\n\n  __onNextSlideClick(evt)\n  {\n    evt.preventDefault();\n    evt.stopPropagation();\n\n/*\nSometimes if eventPassThrough is set to true we get double events? (but only in fullscreen slideshow mode?)\n\n    var time = new Date().getTime();\n\n    console.info(\"__onNextSlideClick\", time - this.prevtime);\n\n    if (time - this.prevtime < 200)\n    {\n      console.log(\"again??\");\n      return;\n    }\n    if (time == this.prevtime)\n    {\n      console.warn(\"OI\");\n      return;\n    }\n    this.prevtime = time;\n*/\n//console.trace();\n    this.nextSlide(evt);\n  }\n\n  __detectCellTap(evt)\n  {\n    if (!this.options.activateslidewithclick)\n      return;\n\n    // lookup this node\n    var carrouselcell = dompack.closest(evt.target, \".carrousel__cell\");\n    if (!carrouselcell)\n      return;\n\n    var idx = this.items.indexOf(carrouselcell.__iteminfo);\n\n    if (idx == this.activeslideidx)\n      return; // whe're already in view\n\n    console.info(this.items[idx]); // DEBUG\n\n    var viewport_rect = this.nodes.viewport.getBoundingClientRect();\n    var clickpos = evt.pageX - viewport_rect.left;\n\n    // Whether the content is left or right of the position where the active slide appears\n    // determines whether we scroll forward or backward.\n    var forward = false;\n    switch(this.options.activeslidealignment)\n    {\n      case \"\":\n      case \"viewport_left\":\n          forward = true;\n          break;\n\n      case \"viewport_middle\":\n          forward = clickpos > this.width_viewport / 2;\n          break;\n\n      case \"left\":\n          forward = clickpos > this.options.paddingLeft;\n          break;\n\n      case \"middle\":\n          var contentareawidth = this.width_viewport - this.options.paddingLeft - this.options.paddingRight;\n          var middlex = contentareawidth / 2 + this.options.paddingLeft;\n          forward = clickpos > middlex;\n          break;\n    }\n\n    //console.log(\"Tapped at x position \" + clickpos + \", will now scroll \" + (forward ? \"forward\" : \"backward\"));\n\n    //console.log(evt);\n\n    this.jumpToSlide(idx, true, forward);\n  }\n\n\n  __getVirtualLeftForSlide(virtualidx)\n  {\n    var items = this.items.length;\n    var idx = virtualidx % items;\n    var pages = Math.floor(virtualidx / items);\n    //console.warn(virtualidx, pages, idx);\n\n    var left = (pages * this.width_content) + this.__getActivationCenterForSlide(idx);\n    //console.log(\"__getVirtualLeftForSlide\", pages, \"*\", this.width_content, \"+\", this.__getActivationCenterForSlide(idx));\n\n    return left;\n  }\n\n\n  __getActivationCenterForSlide(idx)\n  {\n    var wanted_left_within_content = this.items[idx].left;\n    switch(this.options.activeslidealignment)\n    {\n      case \"\":\n      case \"viewport_left\":\n          break;\n\n      case \"viewport_middle\":\n          wanted_left_within_content -= (this.width_viewport - this.items[idx].width_real) / 2;\n          break;\n\n      case \"left\":\n          wanted_left_within_content -= this.options.paddingLeft;\n          break;\n\n      case \"middle\":\n          var contentareawidth = this.width_viewport - this.options.paddingLeft - this.options.paddingRight;\n          //console.log(\"middle contentareawidth\", contentareawidth, this.options.paddingLeft, this.options.paddingRight);\n          wanted_left_within_content -= (contentareawidth - this.items[idx].width_real) / 2 + this.options.paddingLeft;\n          break;\n    }\n    return wanted_left_within_content;\n  }\n\n  __getLeftForSlide(idx, forward)\n  {\n    //var orig_idx = idx; // DEBUG\n\n    // get the real item index\n    var idx_neg = idx < 0;\n    var pages;\n    if (idx < 0)\n    {\n      idx++;\n      idx = (this.items.length-1) - (-idx % this.items.length);\n      pages = -Math.floor(-idx % this.items.length);\n    }\n    else\n    {\n      idx = idx % this.items.length;\n      pages = Math.floor(idx / this.items.length);\n    }\n\n    var wanted_left_within_content = this.__getActivationCenterForSlide(idx);\n    console.info(\"wanted_left_within_content\", wanted_left_within_content);\n\n    var left = this.scrollleft + wanted_left_within_content - (this.scrollleft % this.width_content);\n\n    if (forward && left < this.scrollleft)\n      left += this.width_content;\n    else if (!forward && left > this.scrollleft)\n      left -= this.width_content;\n\n    return left;\n  }\n\n  // NOTE: not finished\n  __getContentScrollToVirtualScroll(wanted_left_within_content, forward)\n  {\n// ADDME: forward\n    return this.scrollleft - this.scrollleft % this.width_content + wanted_left_within_content;\n  }\n\n\n  /** @short\n      @param x the page number\n\n      TEST:\n      ctest.iscroll.goToPage(12, 0)\n  */\n  getPage(pageX, pageY)\n  {\n    console.info(\"getPage\");\n\n    if (pageX < 0)\n    {\n      console.error(\"pageX should not be negative.\");\n      pageX = -pageX;\n    }\n\n    var repeatedcontent = Math.floor(pageX / this.items.length);\n    var itemidx = pageX % this.items.length;\n\n    console.log(\"iScroll pageX\", pageX, \"is actually contentrepetition\", repeatedcontent, \" slide #\"+itemidx);\n\n    var val =\n        { x:     - ((repeatedcontent * this.width_content) + this.items[itemidx].left)\n        , y:     0\n        , pageX: pageX //-Math.floor(x / this.width_content)\n        , pageY: pageY\n        };\n\n    console.info(\"getPage\", pageX, \" returns \", val);\n\n    return val;\n  }\n\n// iScroll.currentPage = nearest snap\n\n  getNearestSnap(x, y, iScroll)\n  {\n/*\n    if (this.options.snapto == \"contentstart\")\n    {\n      // (same calculation as in scrollToContent)\n      let xfloor = Math.floor(this.scrollleft / this.width_content) * this.width_content;\n      let xceil = xfloor + this.width_content;\n\n      let distance_to_previous_contentstart = xceil - this.scrollleft;\n      let distance_to_next_contentstart = this.scrollleft - xfloor;\n      let closest = distance_to_next_contentstart < distance_to_previous_contentstart ? xceil : xfloor;\n\n      console.log(this.scrollleft, xfloor, xceil);\n      console.log(distance_to_previous_contentstart, distance_to_next_contentstart, closest);\n\n      var val =\n          { x:     -closest\n          , y:     0\n          , pageX: 1\n          , pageY: 0\n          }\n      return val;\n    }\n*/\n    console.info(\"getNearestSnap\");\n\n    x = -x;\n    this.__redraw_slides(false, x);\n    var renderinfo = this.renderinfo; // renderinfo for this __redraw_slides or the previous one (if render failed due to viewport being 0 wide)\n/*    \n\n    // if we aren't visible (width is 0) we don't ret renderinfo\n    return { x: -this.scrollleft\n           , y: 0\n           , pageX: \n           }\n*/\n\n    //console.log(renderinfo);\n    var val =\n         {// x:     -this.__getLeftForSlide(renderinfo.newactiveslidevirtualidx)\n           x:     -this.__getVirtualLeftForSlide(renderinfo.newactiveslidevirtualidx)\n         , y:     0\n         , pageX: renderinfo.newactiveslidevirtualidx\n         , pageY: 0\n\n         //, _carr_contentrepeat: Math.floor(x / this.width_content)\n         //, _carr_slideidx:      nearestslideidx\n         };\n\n    //console.log(\"getNearestSnap\", val);\n\n    return val;\n  }\n\n  __getActivationX()\n  {\n    var activation_x = 0;//\n    switch(this.options.activeslidealignment)\n    {\n      case \"\":\n      case \"viewport_left\":\n          break;\n\n      case \"viewport_middle\":\n          activation_x = this.width_viewport / 2;\n          break;\n\n      case \"left\":\n          activation_x = this.options.paddingLeft;\n          break;\n\n      case \"middle\":\n          var contentareawidth = this.width_viewport - this.options.paddingLeft - this.options.paddingRight;\n          //console.log(\"middle contentareawidth\", contentareawidth, this.options.paddingLeft, this.options.paddingRight);\n          activation_x = contentareawidth / 2 + this.options.paddingLeft;\n          break;\n    }\n    return activation_x;\n  }\n\n\n  __redraw_slides(draw, override_scrollleft)\n  {\n    if (this.width_viewport == 0 || this.width_content == 0)\n    {\n      //console.error(\"cannot draw, width is 0\");\n      return;\n    }\n\n    if (isNaN(this.scrollleft)) // this should not happen anymore?\n    {\n      console.error(\"scrolleft is NaN\");\n      return;\n    }\n\n    // virtual positions\n    // Our scrolleft must be a round number to prevent blurring\n    // (which will be especially visible when scrolling has ended)\n    var absolute_scrollleft = (override_scrollleft ? override_scrollleft : this.scrollleft);\n    var scrollleft = absolute_scrollleft % this.width_content;\n    var visible_left = scrollleft;\n    var visible_right = visible_left + this.width_viewport;\n\n    if (this.options.ondrawframe && draw)\n      this.options.ondrawframe.bind(this)({ scrollleft:   absolute_scrollleft // scrollposition in the virtual (almost endless) space\n                               , contentleft:  scrollleft // scrollposition in the content (xpos in the content where we start in our container)\n                               , contentwidth: this.width_content\n                               , draw:         true // not drawing\n                               });\n\n\n    if (this.items.length == 0)\n    {\n      //console.warn(\"No slides to draw.\");\n      return;\n    }\n\n\n    var activation_x = this.__getActivationX();\n\n    //console.log(scrollleft, this.options.activeslidealignment, this.width_content, activation_x);\n\n\n    var new_items_onscreen = [];\n    this.visiblenodes = [];\n\n    var items_visible = 0;\n    var itemcount = this.items.length;\n    var draw_itemidx = 0; //first_idx;\n\n    if (this.options.debugdraw)\n    {\n      console.log( \"__redraw_slides()\"\n                 , { scrollleft:     scrollleft\n                   , content_offset: scrollleft\n\n                   , width_content:  this.width_content\n\n                   , visible_left: visible_left\n                   , visible_right: visible_right\n                   });\n    }\n\n\n    // reset the usage counter for each item\n    for (var idx = 0; idx < this.items.length; idx++)\n      this.items[idx].usecount = 0;\n\n    var offsetleft = 0;\n\n    var newactiveslideidx = -1;\n    var newactivenode = null;\n    var newactiveslidevirtualidx = null;\n    var newactiveslide_dist = -1;\n\n    var virtualslideidx = Math.floor( absolute_scrollleft / this.width_content) * this.items.length;\n\n    while(items_visible < 1000) // FIXME: arbitrary workaround to prevent a loop when all items have width 0\n    {\n\nif (items_visible == 999)\n{\n      console.log( \"__redraw_slides() overflow\"\n                 , { absolute_scrollleft: absolute_scrollleft\n                   , scrollleft:     scrollleft\n                   , width_content:  this.width_content\n\n                   , visible_left: visible_left\n                   , visible_right: visible_right\n\n                   , activation_x: activation_x\n\n                   , virtualslideidx: virtualslideidx\n                   });\n}\n\n\n      var item = this.items[draw_itemidx];\n\n//      console.log((item.left + offsetleft) + \" to \" + (item.right + offsetleft));\n\n      if (item.right + offsetleft < visible_left)\n      {\n        // Prepare for the next potential item to draw\n        draw_itemidx++;\n        virtualslideidx++;\n        if (draw_itemidx == itemcount)\n        {\n          draw_itemidx = 0;\n          offsetleft += this.width_content;\n        }\n        continue;\n      }\n\n      // for simple side-by-side scrollers (like a slideshow) we can assume all items after the first out-of-view item is also out-of-view\n      let outofview = item.left + offsetleft > visible_right;\n      if (outofview && this.options.items_positions_ordered)\n        break; // whe are done. whe've gone beyond the visible edge of the viewport.\n      // else !!! FIXME: implement detecting all items in the content being out of view.... or we only stop at our 1000 items cutoff point.\n\n      if (!outofview)\n      {\n        var left_in_viewport = item.left + offsetleft - scrollleft;\n\n        // idx in the \"infinite\" space - calculated to return for debug/render inspection\n        //var virtualslideidx = Math.floor(scrollleft + offsetleft + left_in_viewport) / this.width_content * this.items.length + draw_itemidx); // virtual world idx\n\n        // DRAW ---------------------------------------------------------------------\n        if (draw)\n        {\n          var use_node;\n          if (item.usecount < item.nodecopies.length)\n          {\n            // we can reuse a node\n            use_node = item.nodecopies[item.usecount];\n          }\n          else\n          {\n            // create a new copy of the slide to use\n            use_node = item.node.cloneNode(true);\n            use_node.__iteminfo = item;\n            item.nodecopies.push(use_node);\n            this.nodes.content.appendChild(use_node);\n          }\n\n          // store data which might be usefull when handling events (clicks) in content within a slide\n          use_node._wh_carrouseldata = { slideidx:        draw_itemidx\n                                       , virtualslideidx: virtualslideidx\n                                       };\n  /*\n          if (this.options.debugslides)\n          {\n            var titlenode = item.node.querySelector(\".carrousel__cell-title\");\n            if (titlenode)\n            {\n              // show the virtual slide idx and the idx of the real slide being drawn\n              titlenode.innerText = virtualslideidx + \" / \" + draw_itemidx;\n            }\n          }\n  */\n\n          var centerwithinheight = this.options.height ? this.options.height : this.largestslideheight;\n\n          var offsety = 0;\n          if (this.options.vertical_align == \"middle\")\n            offsety = Math.round(centerwithinheight - item.height) / 2; // FIXME: retina positioning\n          else if (this.options.vertical_align == \"bottom\")\n            offsety = Math.round(centerwithinheight - item.height);\n\n          let transform = \"translate3D(\"+left_in_viewport+\"px,\"+offsety+\"px,0)\";\n\n          if (item.scale)\n            transform += \" scale(\"+item.scale+\")\";\n\n          //use_node.style.webkitTransform = transform; // FIXME: reenable for iOS 8\n          use_node.style.transform = transform;\n\n          // FIXME: This should NOT be done here, implement a callback or event which passes the node which are or will become visible\n          //        and let the fsslideshow code handle this.\n          var imagecontainer = use_node.querySelector(\".carrousel__cell-image\");\n          if (imagecontainer)\n            imagecontainer.style.backgroundImage = \"\"; // FIXME: too specific to use here?? used to allow loading the bgimage from a class/id\n\n    //      console.log(\"Drawing item #\" + draw_itemidx + \" using copy #\" + item.usecount + \" at left: \" + left_in_viewport + \"px\");\n    //      console.log(use_node);\n\n          new_items_onscreen.push(use_node);\n          item.usecount++;\n        }\n        // --------------------------------------------------------------------------\n\n\n        // The slide closest to the activation area will be picked as the alignemnt slide\n        var leftdist = Math.abs(activation_x - left_in_viewport);\n       // var rightdist = Math.abs(activation_x - (left_in_viewport + item.width + this.options.gap/2))\n        var dist = leftdist;// > rightdist ? rightdist : leftdist;\n\n        // ADDME: work-in-progress to collect rendering information to do extra effects in code outside this library\n        this.visiblenodes.push(\n              { x: left_in_viewport\n              , y: offsety\n              , width: item.width\n              , height: item.height\n              });\n\n        if (newactiveslide_dist == -1 || dist < newactiveslide_dist)\n        {\n          //console.log(\"actsl\", virtualslideidx);\n          newactiveslideidx = draw_itemidx;\n          newactivenode = use_node;\n          newactiveslidevirtualidx = virtualslideidx;\n          newactiveslide_dist = dist;\n        }\n      } // if not out of view\n\n\n      // Prepare for the next potential item to draw\n      draw_itemidx++;\n      virtualslideidx++;\n      if (draw_itemidx == itemcount)\n      {\n        draw_itemidx = 0;\n        offsetleft += this.width_content;\n      }\n\n      items_visible++;\n    } // while\n\n    //console.log(items_visible, \"slides visible.\");\n\n    if (items_visible == 0)\n    {\n      //console.error(\"No items to draw??\");\n      return;\n    }\n\n//console.log(\"Old onscreen assets\", this.items_onscreen);\n//console.log(\"New onscreen assets\", new_items_onscreen);\n\n    if (draw)\n    {\n      // remove previously used, but now unused sprites from the view\n      // NOTE: we cannot use visibility or display for this, on iOS this will flush caches and making\n      //       a sprite reappear would cause flicker and stuttering.\n      for (var idx = 0; idx < this.items_onscreen.length; idx++)\n      {\n        var asset = this.items_onscreen[idx];\n        if (new_items_onscreen.indexOf(asset) == -1)\n        {\n          asset.style.webkitTransform = \"translate3D(-50000px,0,0)\";\n          asset.style.transform = \"translate3D(-50000px,0,0)\";\n        }\n      }\n\n      this.items_onscreen = new_items_onscreen;\n\n/*\nif (this.options.name == \"videos\")\n  console.log( \"This frame:\\n\"\n             , \"newactiveslideidx\",        newactiveslideidx, \"\\n\"\n             , \"newactiveslidevirtualidx\", newactiveslidevirtualidx, \"\\n\"\n             , \"slide_virtualstartidx\",    this.slide_virtualstartidx\n             );\n*/\n\n/*\nconsole.log(\"ACTIVE SLIDE\", { current:   this.alignedslidevirtualidx\n                            , new:       newactiveslideidx\n                            , carrousel: this.options.name\n\n                            , node_aligned: this.alignedslidenode\n                            , node_alignnew: newactivenode\n                            });\n*/\n      if (newactiveslideidx > -1)\n      {\n        if (this.alignedslidenode != newactivenode) //newactiveslidevirtualidx != this.alignedslidevirtualidx)\n        {\n          //console.log(\"Distance of active slide to activity-center: \", newactiveslide_dist, newactiveslidevirtualidx);\n          //console.log(\"Activate slide set to \", newactiveslideidx);\n          this.__setActiveSlide(item, newactiveslideidx, newactivenode, newactiveslidevirtualidx);\n        }\n\n        //console.info(\"virtualslideidx-active\", virtualslideidx);\n        this.alignedslideidx = newactiveslideidx;\n        this.alignedslidevirtualidx = newactiveslidevirtualidx;\n      }\n    }\n\n    this.renderinfo =\n           { newactiveslideidx: newactiveslideidx\n           , newactivenode:     newactivenode\n           , newactiveslidevirtualidx: newactiveslidevirtualidx\n           , newactiveslide_dist:      newactiveslide_dist\n           , width_viewport:           this.width_viewport\n           , width_content:            this.width_content\n           };\n\n    return this.renderinfo;\n  } // end of refresh()\n\n\n  __setActiveSlide(item, newactiveslideidx, newactivenode, virtualslideidx)\n  {\n    //console.log(\"Firing wh:activeslidechange\");\n\n    if (this.options.name == \"videos\")\n      console.log(\"New active slide\", newactiveslideidx, newactivenode, \"prev\", this.alignedslidenode);\n\n    if (this.alignedslidenode != newactivenode)\n    {\n      if (this.alignedslidenode)\n        this.alignedslidenode.classList.remove(\"carrousel__cell--aligned\");\n\n      newactivenode.classList.add(\"carrousel__cell--aligned\");\n    }\n\n    // FIXME: although the node getting the class has changed, the actual (original) slide may still be the same\n    dompack.dispatchCustomEvent( this.node\n                               , \"wh:activeslidechange\"\n                               , { bubbles:    false // FIXME: or would we ever want this to be true?\n                                 , cancelable: false\n                                 , detail:     { carrousel:          this // for access if no reference was kept or if our event gets dispatched for 'new Carrousel' has returned \"this\".\n                                               , previousactive:     this.alignedslide\n                                               , previousactiveidx:  this.alignedslideidx\n                                               , previousactivenode: this.alignedslidenode\n                                               , nextactive:         item\n                                               , nextactiveidx:      newactiveslideidx\n                                               , nextactivenode:     newactivenode\n                                               }\n                                 });\n\n    this.activeslide = item;\n    this.alignedslidenode = newactivenode;\n  }\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n///////////////////////////////////////////////////////////////////////////////////\n//\n//  Fullscreen slideshow\n//\n\nimport * as dompack from \"dompack\";\nimport Carrousel from \"@webhare/dompack-carrousel\";\n\n\nlet __active_photoviewer = null;\nlet __active_fsslideshow_container = null;\nlet __old_scrolly = 0;\nlet __initialized = false;\n\nfunction refreshFullScreenSlideshow(viewer) {\n  if (viewer.node.clientHeight == 0)\n    return;\n\n  resizeImagesToFitInViewport(viewer.node);\n\n  const options = getDefaultSlideshowOptions();\n  //console.log(\"Slideshow options\", options);\n\n  viewer.setOptions(options);\n  viewer.relayoutSlides();\n  viewer.refresh();\n}\n\n\nfunction resizeActivePhotoviewer() {\n  if (!__active_fsslideshow_container)\n    return;\n\n  if (__active_photoviewer) {\n    console.log(\"update active photoviewer\");\n    refreshFullScreenSlideshow(__active_photoviewer);\n  } else {\n    resizeImagesToFitInViewport(__active_fsslideshow_container);\n  }\n}\n\nfunction doActivateSlideshowByHash(hash) {\n  // we only use the ID part, since we assume the title may change more often than the (whfs/whfssetting)id of an image\n  // (people add titles after first publication of the page, they correct spelling errors)\n  const parts = hash.split(\"-\");\n  const imageid = parts[0]; // assume ID-title\n\n  console.info(\"doActivateSlideshowByHash\", hash);\n\n  // for items with <id>-title make sure to have - at the end so for example 1337 won't be a match when imageid is 133\n  let cell = document.querySelector('.carrousel__cell[data-hash^=\"' + imageid + '-\"]');\n\n  // for items with no title we only have <id>\n  if (!cell)\n    cell = document.querySelector('.carrousel__cell[data-hash=\"' + imageid + '\"]');\n\n  console.info('.carrousel__cell[data-hash=\"' + imageid + ']');\n\n  if (!cell)\n    return;\n\n  // find the first slideshow which has this hash\n  const slideshow = cell.closest(\".photoalbumwidget__slideshow\");\n\n  // lookup the index of the image we have to show\n  const all_items = slideshow.querySelectorAll(\".carrousel__cell\");\n  const itemidx = Array.from(all_items).indexOf(cell);\n\n  ___doActivateSlideshow(slideshow, itemidx);\n}\n\nfunction doActivateSlideshow(instanceid, itemidx) {\n  const containerid = instanceid + \"-slideshow\";\n  const slideshowcontainer = document.getElementById(containerid);\n  if (!slideshowcontainer) {\n    console.error(\"Cannot find slideshow container \", containerid);\n    return;\n  }\n\n  ___doActivateSlideshow(slideshowcontainer, itemidx);\n}\n\nfunction ___doActivateSlideshow(slideshowcontainer, itemidx) {\n  const use_carrousel = slideshowcontainer.hasAttribute(\"data-carrousel-options\");\n\n  if (!__initialized) {\n    window.addEventListener(\"resize\", resizeActivePhotoviewer);\n    __initialized = true;\n  }\n\n  __old_scrolly = document.body.scrollTop || document.documentElement.scrollTop;\n\n\n  document.body.appendChild(slideshowcontainer);\n\n  const carrouselcontainer = slideshowcontainer; //.querySelector(\".carrousel\");\n  carrouselcontainer.addEventListener(\"wh:activeslidechange\", onActiveSlideChange);\n  carrouselcontainer.addEventListener(\"wh:closeslideshow\", doCloseFullscreenSlideshow);\n\n  // FULLSCREEN\n  slideshowcontainer.classList.add(\"html__fullscreenelement\");\n  document.documentElement.classList.add(\"html--onlyfullscreenelement\");\n  slideshowcontainer.classList.add(\"prepare\"); // measure + pre-animation phase\n\n  //console.info(\"Fullscreen carrousel\", options);\n\n  const options = getDefaultSlideshowOptions();\n  resizeImagesToFitInViewport(carrouselcontainer); //carr.node);\n\n  //console.log(\"Slideshow options\", options);\n\n  let carr = carrouselcontainer.__carrousel;\n\n  //if (carr.node.clientHeight == 0)\n  if (carrouselcontainer.clientHeight == 0)\n    console.error(\"Failed to resize fullscreen slideshow.\");\n\n\n\n  if (use_carrousel) {\n    if (!carr) {\n      options.initialslide = itemidx;\n\n      carr = new Carrousel(carrouselcontainer, options);\n\n      // The carrousel must handle the click/taps!!\n      carr.node.addEventListener(\"tap\", detectButtonTaps);\n\n      carrouselcontainer.__carrousel = carr;\n    } else {\n      carr.setOptions(options);\n      carr.relayoutSlides();\n      carr.jumpToSlide(itemidx);\n    }\n\n    carr.drawFrame(); // be sure to have the first frame ready before settings 'visible'\n  } else {\n    slideshowcontainer.addEventListener(\"click\", detectButtonTaps);\n\n    // allow loading of the image\n    const slidenodes = slideshowcontainer.querySelectorAll(\".carrousel__cell-image\");\n    for (const node of slidenodes)\n      node.style.backgroundImage = \"\";\n  }\n\n  document.clientWidth; // Force reflow so the .visible will trigger an transition\n\n  slideshowcontainer.classList.add(\"visible\");\n\n  if (use_carrousel) {\n    // Set focus for keyboard navigation\n    carr.nodes.viewport.focus(); // FIXME: private node info\n  }\n\n  document.body.scrollTop = 0;\n  document.documentElement.scrollTop = 0;\n\n  if (use_carrousel)\n    __active_photoviewer = carrouselcontainer.__carrousel;\n\n  __active_fsslideshow_container = slideshowcontainer;\n}\n\nfunction doCloseFullscreenSlideshow() {\n  const fsscontainer = __active_fsslideshow_container;\n  fsscontainer.classList.remove(\"prepare\");\n  fsscontainer.classList.remove(\"active\");\n\n  // Exit FULLSCREEN\n  fsscontainer.classList.remove(\"html__fullscreenelement\");\n  document.documentElement.classList.remove(\"html--onlyfullscreenelement\");\n\n  // WS2016 specific\n  const headeranim = document.querySelector(\".header__universe\");\n  if (headeranim)\n    headeranim.style.display = \"block\";\n\n  window.scrollTo(0, __old_scrolly);\n\n  __active_photoviewer = null;\n  __active_fsslideshow_container = null;\n\n  history.replaceState(undefined, undefined, \".\");\n}\n\nfunction detectButtonTaps(evt) {\n  const buttonnode = evt.target.closest(\".fsslideshow__button\");\n  if (!buttonnode)\n    return;\n\n  if (buttonnode.classList.contains(\"fsslideshow__close\"))\n    doCloseFullscreenSlideshow();\n}\n\nfunction onActiveSlideChange(evt) {\n  //console.info(evt.detail);\n\n  const slideshowcontainer = evt.target.closest(\".fsslideshow\");\n  const titlenode = slideshowcontainer.querySelector(\".fsslideshow__title\");\n  const downloadbutton = slideshowcontainer.querySelector(\".fsslideshow__download\");\n\n  const carrousel = slideshowcontainer.querySelector(\".carrousel\").__carrousel;\n  const slidenode = evt.detail.nextactivenode;\n\n  // FIXME: carrousel.items.length ... is this evil or allowed?\n  titlenode.textContent = (evt.detail.nextactiveidx + 1) + \"/\" + evt.detail.carrousel.items.length + \" \" + evt.detail.nextactivenode.getAttribute(\"data-title\");\n  downloadbutton.href = slidenode.getAttribute(\"data-download\");\n  downloadbutton.setAttribute(\"download\", slidenode.getAttribute(\"data-filename\"));\n\n  const urlhash = slidenode.getAttribute(\"data-hash\");\n  history.replaceState(undefined, undefined, \"#fsviewer-\" + urlhash);\n}\n\nfunction getDefaultSlideshowOptions() {\n  const viewport_width = window.innerWidth;\n  const viewport_height = window.innerHeight;\n  return {\n    activeslidealignment: \"middle\",\n    vertical_align: \"middle\",\n    gap: viewport_width / 20,\n    slidewidth: viewport_width, //* 0.75\n\n    height: viewport_height, // center within the full height (if we use auto height the box-shadow get's cut off by overflow: hidden;)\n\n    autodraw_firstframe: false,\n\n    // because we are fullscreen we don't need to worry about blocking vertical dragging\n    // of the page on touch devices. We rather prevent dragging causing selections(with mouse)\n    // or unintentionally scrolling the background.\n    eventPassthrough: false\n  };\n}\n\nfunction resizeImagesToFitInViewport(carrouselcontainer) {\n  let viewport_width;\n  let viewport_height;\n\n  getComputedStyle(carrouselcontainer); // Force size calculation\n  const rect = carrouselcontainer.getBoundingClientRect();\n  viewport_width = rect.width;\n  viewport_height = rect.height;\n\n  const maximagewidth = viewport_width * 0.75;\n  const maximageheight = viewport_height - 130;\n\n  let dpr = window.devicePixelRatio;\n  if (!dpr)\n    dpr = 1; // fallback for IE10\n\n  const images = carrouselcontainer.querySelectorAll(\".carrousel__cell-image\");\n  //for (var idx = 0; idx < carrouselcontainer.__carrousel.items.length; idx++)\n  for (let idx = 0; idx < images.length; idx++) {\n    const image = images[idx];\n\n    const orig_w = parseInt(image.getAttribute(\"data-width\"));\n    const orig_h = parseInt(image.getAttribute(\"data-height\"));\n\n    const max_w_stretch = maximagewidth / orig_w;\n    const max_h_stretch = maximageheight / orig_h;\n    const stretch = max_w_stretch < max_h_stretch ? max_w_stretch : max_h_stretch;\n\n    const img_w = Math.round(orig_w * stretch * dpr) / dpr;\n    const img_h = Math.round(orig_h * stretch * dpr) / dpr;\n\n    //console.log(image, orig_w+\"x\"+orig_h, img_w+\"x\"+img_h);\n\n    image.style.width = img_w + \"px\";\n    image.style.height = img_h + \"px\";\n  }\n}\n\n\n\ndompack.register(\".fsslideshow\", (node, idx) => {\n  if (idx != 0)\n    return;\n\n  let hash = window.location.hash;\n\n  if (hash != \"\")\n    hash = hash.substr(1);\n\n  if (hash.substr(0, 9) == \"fsviewer-\") {\n    doActivateSlideshowByHash(hash.substr(9));\n  }\n});\n\n\nmodule.exports = { doActivateSlideshow: doActivateSlideshow };\n","/**\n * EvEmitter v1.1.0\n * Lil' event emitter\n * MIT License\n */\n\n/* jshint unused: true, undef: true, strict: true */\n\n( function( global, factory ) {\n  // universal module definition\n  /* jshint strict: false */ /* globals define, module, window */\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD - RequireJS\n    define( factory );\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS - Browserify, Webpack\n    module.exports = factory();\n  } else {\n    // Browser globals\n    global.EvEmitter = factory();\n  }\n\n}( typeof window != 'undefined' ? window : this, function() {\n\n\"use strict\";\n\nfunction EvEmitter() {}\n\nvar proto = EvEmitter.prototype;\n\nproto.on = function( eventName, listener ) {\n  if ( !eventName || !listener ) {\n    return;\n  }\n  // set events hash\n  var events = this._events = this._events || {};\n  // set listeners array\n  var listeners = events[ eventName ] = events[ eventName ] || [];\n  // only add once\n  if ( listeners.indexOf( listener ) == -1 ) {\n    listeners.push( listener );\n  }\n\n  return this;\n};\n\nproto.once = function( eventName, listener ) {\n  if ( !eventName || !listener ) {\n    return;\n  }\n  // add event\n  this.on( eventName, listener );\n  // set once flag\n  // set onceEvents hash\n  var onceEvents = this._onceEvents = this._onceEvents || {};\n  // set onceListeners object\n  var onceListeners = onceEvents[ eventName ] = onceEvents[ eventName ] || {};\n  // set flag\n  onceListeners[ listener ] = true;\n\n  return this;\n};\n\nproto.off = function( eventName, listener ) {\n  var listeners = this._events && this._events[ eventName ];\n  if ( !listeners || !listeners.length ) {\n    return;\n  }\n  var index = listeners.indexOf( listener );\n  if ( index != -1 ) {\n    listeners.splice( index, 1 );\n  }\n\n  return this;\n};\n\nproto.emitEvent = function( eventName, args ) {\n  var listeners = this._events && this._events[ eventName ];\n  if ( !listeners || !listeners.length ) {\n    return;\n  }\n  // copy over to avoid interference if .off() in listener\n  listeners = listeners.slice(0);\n  args = args || [];\n  // once stuff\n  var onceListeners = this._onceEvents && this._onceEvents[ eventName ];\n\n  for ( var i=0; i < listeners.length; i++ ) {\n    var listener = listeners[i]\n    var isOnce = onceListeners && onceListeners[ listener ];\n    if ( isOnce ) {\n      // remove listener\n      // remove before trigger to prevent recursion\n      this.off( eventName, listener );\n      // unset once flag\n      delete onceListeners[ listener ];\n    }\n    // trigger listener\n    listener.apply( this, args );\n  }\n\n  return this;\n};\n\nproto.allOff = function() {\n  delete this._events;\n  delete this._onceEvents;\n};\n\nreturn EvEmitter;\n\n}));\n","/*!\n * getSize v2.0.3\n * measure size of elements\n * MIT license\n */\n\n/* jshint browser: true, strict: true, undef: true, unused: true */\n/* globals console: false */\n\n( function( window, factory ) {\n  /* jshint strict: false */ /* globals define, module */\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD\n    define( factory );\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory();\n  } else {\n    // browser global\n    window.getSize = factory();\n  }\n\n})( window, function factory() {\n'use strict';\n\n// -------------------------- helpers -------------------------- //\n\n// get a number from a string, not a percentage\nfunction getStyleSize( value ) {\n  var num = parseFloat( value );\n  // not a percent like '100%', and a number\n  var isValid = value.indexOf('%') == -1 && !isNaN( num );\n  return isValid && num;\n}\n\nfunction noop() {}\n\nvar logError = typeof console == 'undefined' ? noop :\n  function( message ) {\n    console.error( message );\n  };\n\n// -------------------------- measurements -------------------------- //\n\nvar measurements = [\n  'paddingLeft',\n  'paddingRight',\n  'paddingTop',\n  'paddingBottom',\n  'marginLeft',\n  'marginRight',\n  'marginTop',\n  'marginBottom',\n  'borderLeftWidth',\n  'borderRightWidth',\n  'borderTopWidth',\n  'borderBottomWidth'\n];\n\nvar measurementsLength = measurements.length;\n\nfunction getZeroSize() {\n  var size = {\n    width: 0,\n    height: 0,\n    innerWidth: 0,\n    innerHeight: 0,\n    outerWidth: 0,\n    outerHeight: 0\n  };\n  for ( var i=0; i < measurementsLength; i++ ) {\n    var measurement = measurements[i];\n    size[ measurement ] = 0;\n  }\n  return size;\n}\n\n// -------------------------- getStyle -------------------------- //\n\n/**\n * getStyle, get style of element, check for Firefox bug\n * https://bugzilla.mozilla.org/show_bug.cgi?id=548397\n */\nfunction getStyle( elem ) {\n  var style = getComputedStyle( elem );\n  if ( !style ) {\n    logError( 'Style returned ' + style +\n      '. Are you running this code in a hidden iframe on Firefox? ' +\n      'See https://bit.ly/getsizebug1' );\n  }\n  return style;\n}\n\n// -------------------------- setup -------------------------- //\n\nvar isSetup = false;\n\nvar isBoxSizeOuter;\n\n/**\n * setup\n * check isBoxSizerOuter\n * do on first getSize() rather than on page load for Firefox bug\n */\nfunction setup() {\n  // setup once\n  if ( isSetup ) {\n    return;\n  }\n  isSetup = true;\n\n  // -------------------------- box sizing -------------------------- //\n\n  /**\n   * Chrome & Safari measure the outer-width on style.width on border-box elems\n   * IE11 & Firefox<29 measures the inner-width\n   */\n  var div = document.createElement('div');\n  div.style.width = '200px';\n  div.style.padding = '1px 2px 3px 4px';\n  div.style.borderStyle = 'solid';\n  div.style.borderWidth = '1px 2px 3px 4px';\n  div.style.boxSizing = 'border-box';\n\n  var body = document.body || document.documentElement;\n  body.appendChild( div );\n  var style = getStyle( div );\n  // round value for browser zoom. desandro/masonry#928\n  isBoxSizeOuter = Math.round( getStyleSize( style.width ) ) == 200;\n  getSize.isBoxSizeOuter = isBoxSizeOuter;\n\n  body.removeChild( div );\n}\n\n// -------------------------- getSize -------------------------- //\n\nfunction getSize( elem ) {\n  setup();\n\n  // use querySeletor if elem is string\n  if ( typeof elem == 'string' ) {\n    elem = document.querySelector( elem );\n  }\n\n  // do not proceed on non-objects\n  if ( !elem || typeof elem != 'object' || !elem.nodeType ) {\n    return;\n  }\n\n  var style = getStyle( elem );\n\n  // if hidden, everything is 0\n  if ( style.display == 'none' ) {\n    return getZeroSize();\n  }\n\n  var size = {};\n  size.width = elem.offsetWidth;\n  size.height = elem.offsetHeight;\n\n  var isBorderBox = size.isBorderBox = style.boxSizing == 'border-box';\n\n  // get all measurements\n  for ( var i=0; i < measurementsLength; i++ ) {\n    var measurement = measurements[i];\n    var value = style[ measurement ];\n    var num = parseFloat( value );\n    // any 'auto', 'medium' value will be 0\n    size[ measurement ] = !isNaN( num ) ? num : 0;\n  }\n\n  var paddingWidth = size.paddingLeft + size.paddingRight;\n  var paddingHeight = size.paddingTop + size.paddingBottom;\n  var marginWidth = size.marginLeft + size.marginRight;\n  var marginHeight = size.marginTop + size.marginBottom;\n  var borderWidth = size.borderLeftWidth + size.borderRightWidth;\n  var borderHeight = size.borderTopWidth + size.borderBottomWidth;\n\n  var isBorderBoxSizeOuter = isBorderBox && isBoxSizeOuter;\n\n  // overwrite width and height if we can get it from style\n  var styleWidth = getStyleSize( style.width );\n  if ( styleWidth !== false ) {\n    size.width = styleWidth +\n      // add padding and border unless it's already including it\n      ( isBorderBoxSizeOuter ? 0 : paddingWidth + borderWidth );\n  }\n\n  var styleHeight = getStyleSize( style.height );\n  if ( styleHeight !== false ) {\n    size.height = styleHeight +\n      // add padding and border unless it's already including it\n      ( isBorderBoxSizeOuter ? 0 : paddingHeight + borderHeight );\n  }\n\n  size.innerWidth = size.width - ( paddingWidth + borderWidth );\n  size.innerHeight = size.height - ( paddingHeight + borderHeight );\n\n  size.outerWidth = size.width + marginWidth;\n  size.outerHeight = size.height + marginHeight;\n\n  return size;\n}\n\nreturn getSize;\n\n});\n","/**\n * matchesSelector v2.0.2\n * matchesSelector( element, '.selector' )\n * MIT license\n */\n\n/*jshint browser: true, strict: true, undef: true, unused: true */\n\n( function( window, factory ) {\n  /*global define: false, module: false */\n  'use strict';\n  // universal module definition\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD\n    define( factory );\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory();\n  } else {\n    // browser global\n    window.matchesSelector = factory();\n  }\n\n}( window, function factory() {\n  'use strict';\n\n  var matchesMethod = ( function() {\n    var ElemProto = window.Element.prototype;\n    // check for the standard method name first\n    if ( ElemProto.matches ) {\n      return 'matches';\n    }\n    // check un-prefixed\n    if ( ElemProto.matchesSelector ) {\n      return 'matchesSelector';\n    }\n    // check vendor prefixes\n    var prefixes = [ 'webkit', 'moz', 'ms', 'o' ];\n\n    for ( var i=0; i < prefixes.length; i++ ) {\n      var prefix = prefixes[i];\n      var method = prefix + 'MatchesSelector';\n      if ( ElemProto[ method ] ) {\n        return method;\n      }\n    }\n  })();\n\n  return function matchesSelector( elem, selector ) {\n    return elem[ matchesMethod ]( selector );\n  };\n\n}));\n","/**\n * Fizzy UI utils v2.0.7\n * MIT license\n */\n\n/*jshint browser: true, undef: true, unused: true, strict: true */\n\n( function( window, factory ) {\n  // universal module definition\n  /*jshint strict: false */ /*globals define, module, require */\n\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD\n    define( [\n      'desandro-matches-selector/matches-selector'\n    ], function( matchesSelector ) {\n      return factory( window, matchesSelector );\n    });\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n      window,\n      require('desandro-matches-selector')\n    );\n  } else {\n    // browser global\n    window.fizzyUIUtils = factory(\n      window,\n      window.matchesSelector\n    );\n  }\n\n}( window, function factory( window, matchesSelector ) {\n\n'use strict';\n\nvar utils = {};\n\n// ----- extend ----- //\n\n// extends objects\nutils.extend = function( a, b ) {\n  for ( var prop in b ) {\n    a[ prop ] = b[ prop ];\n  }\n  return a;\n};\n\n// ----- modulo ----- //\n\nutils.modulo = function( num, div ) {\n  return ( ( num % div ) + div ) % div;\n};\n\n// ----- makeArray ----- //\n\nvar arraySlice = Array.prototype.slice;\n\n// turn element or nodeList into an array\nutils.makeArray = function( obj ) {\n  if ( Array.isArray( obj ) ) {\n    // use object if already an array\n    return obj;\n  }\n  // return empty array if undefined or null. #6\n  if ( obj === null || obj === undefined ) {\n    return [];\n  }\n\n  var isArrayLike = typeof obj == 'object' && typeof obj.length == 'number';\n  if ( isArrayLike ) {\n    // convert nodeList to array\n    return arraySlice.call( obj );\n  }\n\n  // array of single index\n  return [ obj ];\n};\n\n// ----- removeFrom ----- //\n\nutils.removeFrom = function( ary, obj ) {\n  var index = ary.indexOf( obj );\n  if ( index != -1 ) {\n    ary.splice( index, 1 );\n  }\n};\n\n// ----- getParent ----- //\n\nutils.getParent = function( elem, selector ) {\n  while ( elem.parentNode && elem != document.body ) {\n    elem = elem.parentNode;\n    if ( matchesSelector( elem, selector ) ) {\n      return elem;\n    }\n  }\n};\n\n// ----- getQueryElement ----- //\n\n// use element as selector string\nutils.getQueryElement = function( elem ) {\n  if ( typeof elem == 'string' ) {\n    return document.querySelector( elem );\n  }\n  return elem;\n};\n\n// ----- handleEvent ----- //\n\n// enable .ontype to trigger from .addEventListener( elem, 'type' )\nutils.handleEvent = function( event ) {\n  var method = 'on' + event.type;\n  if ( this[ method ] ) {\n    this[ method ]( event );\n  }\n};\n\n// ----- filterFindElements ----- //\n\nutils.filterFindElements = function( elems, selector ) {\n  // make array of elems\n  elems = utils.makeArray( elems );\n  var ffElems = [];\n\n  elems.forEach( function( elem ) {\n    // check that elem is an actual element\n    if ( !( elem instanceof HTMLElement ) ) {\n      return;\n    }\n    // add elem if no selector\n    if ( !selector ) {\n      ffElems.push( elem );\n      return;\n    }\n    // filter & find items if we have a selector\n    // filter\n    if ( matchesSelector( elem, selector ) ) {\n      ffElems.push( elem );\n    }\n    // find children\n    var childElems = elem.querySelectorAll( selector );\n    // concat childElems to filterFound array\n    for ( var i=0; i < childElems.length; i++ ) {\n      ffElems.push( childElems[i] );\n    }\n  });\n\n  return ffElems;\n};\n\n// ----- debounceMethod ----- //\n\nutils.debounceMethod = function( _class, methodName, threshold ) {\n  threshold = threshold || 100;\n  // original method\n  var method = _class.prototype[ methodName ];\n  var timeoutName = methodName + 'Timeout';\n\n  _class.prototype[ methodName ] = function() {\n    var timeout = this[ timeoutName ];\n    clearTimeout( timeout );\n\n    var args = arguments;\n    var _this = this;\n    this[ timeoutName ] = setTimeout( function() {\n      method.apply( _this, args );\n      delete _this[ timeoutName ];\n    }, threshold );\n  };\n};\n\n// ----- docReady ----- //\n\nutils.docReady = function( callback ) {\n  var readyState = document.readyState;\n  if ( readyState == 'complete' || readyState == 'interactive' ) {\n    // do async to allow for other scripts to run. metafizzy/flickity#441\n    setTimeout( callback );\n  } else {\n    document.addEventListener( 'DOMContentLoaded', callback );\n  }\n};\n\n// ----- htmlInit ----- //\n\n// http://jamesroberts.name/blog/2010/02/22/string-functions-for-javascript-trim-to-camel-case-to-dashed-and-to-underscore/\nutils.toDashed = function( str ) {\n  return str.replace( /(.)([A-Z])/g, function( match, $1, $2 ) {\n    return $1 + '-' + $2;\n  }).toLowerCase();\n};\n\nvar console = window.console;\n/**\n * allow user to initialize classes via [data-namespace] or .js-namespace class\n * htmlInit( Widget, 'widgetName' )\n * options are parsed from data-namespace-options\n */\nutils.htmlInit = function( WidgetClass, namespace ) {\n  utils.docReady( function() {\n    var dashedNamespace = utils.toDashed( namespace );\n    var dataAttr = 'data-' + dashedNamespace;\n    var dataAttrElems = document.querySelectorAll( '[' + dataAttr + ']' );\n    var jsDashElems = document.querySelectorAll( '.js-' + dashedNamespace );\n    var elems = utils.makeArray( dataAttrElems )\n      .concat( utils.makeArray( jsDashElems ) );\n    var dataOptionsAttr = dataAttr + '-options';\n    var jQuery = window.jQuery;\n\n    elems.forEach( function( elem ) {\n      var attr = elem.getAttribute( dataAttr ) ||\n        elem.getAttribute( dataOptionsAttr );\n      var options;\n      try {\n        options = attr && JSON.parse( attr );\n      } catch ( error ) {\n        // log error, do not initialize\n        if ( console ) {\n          console.error( 'Error parsing ' + dataAttr + ' on ' + elem.className +\n          ': ' + error );\n        }\n        return;\n      }\n      // initialize\n      var instance = new WidgetClass( elem, options );\n      // make available via $().data('namespace')\n      if ( jQuery ) {\n        jQuery.data( elem, namespace, instance );\n      }\n    });\n\n  });\n};\n\n// -----  ----- //\n\nreturn utils;\n\n}));\n","/**\n * Outlayer Item\n */\n\n( function( window, factory ) {\n  // universal module definition\n  /* jshint strict: false */ /* globals define, module, require */\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD - RequireJS\n    define( [\n        'ev-emitter/ev-emitter',\n        'get-size/get-size'\n      ],\n      factory\n    );\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS - Browserify, Webpack\n    module.exports = factory(\n      require('ev-emitter'),\n      require('get-size')\n    );\n  } else {\n    // browser global\n    window.Outlayer = {};\n    window.Outlayer.Item = factory(\n      window.EvEmitter,\n      window.getSize\n    );\n  }\n\n}( window, function factory( EvEmitter, getSize ) {\n'use strict';\n\n// ----- helpers ----- //\n\nfunction isEmptyObj( obj ) {\n  for ( var prop in obj ) {\n    return false;\n  }\n  prop = null;\n  return true;\n}\n\n// -------------------------- CSS3 support -------------------------- //\n\n\nvar docElemStyle = document.documentElement.style;\n\nvar transitionProperty = typeof docElemStyle.transition == 'string' ?\n  'transition' : 'WebkitTransition';\nvar transformProperty = typeof docElemStyle.transform == 'string' ?\n  'transform' : 'WebkitTransform';\n\nvar transitionEndEvent = {\n  WebkitTransition: 'webkitTransitionEnd',\n  transition: 'transitionend'\n}[ transitionProperty ];\n\n// cache all vendor properties that could have vendor prefix\nvar vendorProperties = {\n  transform: transformProperty,\n  transition: transitionProperty,\n  transitionDuration: transitionProperty + 'Duration',\n  transitionProperty: transitionProperty + 'Property',\n  transitionDelay: transitionProperty + 'Delay'\n};\n\n// -------------------------- Item -------------------------- //\n\nfunction Item( element, layout ) {\n  if ( !element ) {\n    return;\n  }\n\n  this.element = element;\n  // parent layout class, i.e. Masonry, Isotope, or Packery\n  this.layout = layout;\n  this.position = {\n    x: 0,\n    y: 0\n  };\n\n  this._create();\n}\n\n// inherit EvEmitter\nvar proto = Item.prototype = Object.create( EvEmitter.prototype );\nproto.constructor = Item;\n\nproto._create = function() {\n  // transition objects\n  this._transn = {\n    ingProperties: {},\n    clean: {},\n    onEnd: {}\n  };\n\n  this.css({\n    position: 'absolute'\n  });\n};\n\n// trigger specified handler for event type\nproto.handleEvent = function( event ) {\n  var method = 'on' + event.type;\n  if ( this[ method ] ) {\n    this[ method ]( event );\n  }\n};\n\nproto.getSize = function() {\n  this.size = getSize( this.element );\n};\n\n/**\n * apply CSS styles to element\n * @param {Object} style\n */\nproto.css = function( style ) {\n  var elemStyle = this.element.style;\n\n  for ( var prop in style ) {\n    // use vendor property if available\n    var supportedProp = vendorProperties[ prop ] || prop;\n    elemStyle[ supportedProp ] = style[ prop ];\n  }\n};\n\n // measure position, and sets it\nproto.getPosition = function() {\n  var style = getComputedStyle( this.element );\n  var isOriginLeft = this.layout._getOption('originLeft');\n  var isOriginTop = this.layout._getOption('originTop');\n  var xValue = style[ isOriginLeft ? 'left' : 'right' ];\n  var yValue = style[ isOriginTop ? 'top' : 'bottom' ];\n  var x = parseFloat( xValue );\n  var y = parseFloat( yValue );\n  // convert percent to pixels\n  var layoutSize = this.layout.size;\n  if ( xValue.indexOf('%') != -1 ) {\n    x = ( x / 100 ) * layoutSize.width;\n  }\n  if ( yValue.indexOf('%') != -1 ) {\n    y = ( y / 100 ) * layoutSize.height;\n  }\n  // clean up 'auto' or other non-integer values\n  x = isNaN( x ) ? 0 : x;\n  y = isNaN( y ) ? 0 : y;\n  // remove padding from measurement\n  x -= isOriginLeft ? layoutSize.paddingLeft : layoutSize.paddingRight;\n  y -= isOriginTop ? layoutSize.paddingTop : layoutSize.paddingBottom;\n\n  this.position.x = x;\n  this.position.y = y;\n};\n\n// set settled position, apply padding\nproto.layoutPosition = function() {\n  var layoutSize = this.layout.size;\n  var style = {};\n  var isOriginLeft = this.layout._getOption('originLeft');\n  var isOriginTop = this.layout._getOption('originTop');\n\n  // x\n  var xPadding = isOriginLeft ? 'paddingLeft' : 'paddingRight';\n  var xProperty = isOriginLeft ? 'left' : 'right';\n  var xResetProperty = isOriginLeft ? 'right' : 'left';\n\n  var x = this.position.x + layoutSize[ xPadding ];\n  // set in percentage or pixels\n  style[ xProperty ] = this.getXValue( x );\n  // reset other property\n  style[ xResetProperty ] = '';\n\n  // y\n  var yPadding = isOriginTop ? 'paddingTop' : 'paddingBottom';\n  var yProperty = isOriginTop ? 'top' : 'bottom';\n  var yResetProperty = isOriginTop ? 'bottom' : 'top';\n\n  var y = this.position.y + layoutSize[ yPadding ];\n  // set in percentage or pixels\n  style[ yProperty ] = this.getYValue( y );\n  // reset other property\n  style[ yResetProperty ] = '';\n\n  this.css( style );\n  this.emitEvent( 'layout', [ this ] );\n};\n\nproto.getXValue = function( x ) {\n  var isHorizontal = this.layout._getOption('horizontal');\n  return this.layout.options.percentPosition && !isHorizontal ?\n    ( ( x / this.layout.size.width ) * 100 ) + '%' : x + 'px';\n};\n\nproto.getYValue = function( y ) {\n  var isHorizontal = this.layout._getOption('horizontal');\n  return this.layout.options.percentPosition && isHorizontal ?\n    ( ( y / this.layout.size.height ) * 100 ) + '%' : y + 'px';\n};\n\nproto._transitionTo = function( x, y ) {\n  this.getPosition();\n  // get current x & y from top/left\n  var curX = this.position.x;\n  var curY = this.position.y;\n\n  var didNotMove = x == this.position.x && y == this.position.y;\n\n  // save end position\n  this.setPosition( x, y );\n\n  // if did not move and not transitioning, just go to layout\n  if ( didNotMove && !this.isTransitioning ) {\n    this.layoutPosition();\n    return;\n  }\n\n  var transX = x - curX;\n  var transY = y - curY;\n  var transitionStyle = {};\n  transitionStyle.transform = this.getTranslate( transX, transY );\n\n  this.transition({\n    to: transitionStyle,\n    onTransitionEnd: {\n      transform: this.layoutPosition\n    },\n    isCleaning: true\n  });\n};\n\nproto.getTranslate = function( x, y ) {\n  // flip cooridinates if origin on right or bottom\n  var isOriginLeft = this.layout._getOption('originLeft');\n  var isOriginTop = this.layout._getOption('originTop');\n  x = isOriginLeft ? x : -x;\n  y = isOriginTop ? y : -y;\n  return 'translate3d(' + x + 'px, ' + y + 'px, 0)';\n};\n\n// non transition + transform support\nproto.goTo = function( x, y ) {\n  this.setPosition( x, y );\n  this.layoutPosition();\n};\n\nproto.moveTo = proto._transitionTo;\n\nproto.setPosition = function( x, y ) {\n  this.position.x = parseFloat( x );\n  this.position.y = parseFloat( y );\n};\n\n// ----- transition ----- //\n\n/**\n * @param {Object} style - CSS\n * @param {Function} onTransitionEnd\n */\n\n// non transition, just trigger callback\nproto._nonTransition = function( args ) {\n  this.css( args.to );\n  if ( args.isCleaning ) {\n    this._removeStyles( args.to );\n  }\n  for ( var prop in args.onTransitionEnd ) {\n    args.onTransitionEnd[ prop ].call( this );\n  }\n};\n\n/**\n * proper transition\n * @param {Object} args - arguments\n *   @param {Object} to - style to transition to\n *   @param {Object} from - style to start transition from\n *   @param {Boolean} isCleaning - removes transition styles after transition\n *   @param {Function} onTransitionEnd - callback\n */\nproto.transition = function( args ) {\n  // redirect to nonTransition if no transition duration\n  if ( !parseFloat( this.layout.options.transitionDuration ) ) {\n    this._nonTransition( args );\n    return;\n  }\n\n  var _transition = this._transn;\n  // keep track of onTransitionEnd callback by css property\n  for ( var prop in args.onTransitionEnd ) {\n    _transition.onEnd[ prop ] = args.onTransitionEnd[ prop ];\n  }\n  // keep track of properties that are transitioning\n  for ( prop in args.to ) {\n    _transition.ingProperties[ prop ] = true;\n    // keep track of properties to clean up when transition is done\n    if ( args.isCleaning ) {\n      _transition.clean[ prop ] = true;\n    }\n  }\n\n  // set from styles\n  if ( args.from ) {\n    this.css( args.from );\n    // force redraw. http://blog.alexmaccaw.com/css-transitions\n    var h = this.element.offsetHeight;\n    // hack for JSHint to hush about unused var\n    h = null;\n  }\n  // enable transition\n  this.enableTransition( args.to );\n  // set styles that are transitioning\n  this.css( args.to );\n\n  this.isTransitioning = true;\n\n};\n\n// dash before all cap letters, including first for\n// WebkitTransform => -webkit-transform\nfunction toDashedAll( str ) {\n  return str.replace( /([A-Z])/g, function( $1 ) {\n    return '-' + $1.toLowerCase();\n  });\n}\n\nvar transitionProps = 'opacity,' + toDashedAll( transformProperty );\n\nproto.enableTransition = function(/* style */) {\n  // HACK changing transitionProperty during a transition\n  // will cause transition to jump\n  if ( this.isTransitioning ) {\n    return;\n  }\n\n  // make `transition: foo, bar, baz` from style object\n  // HACK un-comment this when enableTransition can work\n  // while a transition is happening\n  // var transitionValues = [];\n  // for ( var prop in style ) {\n  //   // dash-ify camelCased properties like WebkitTransition\n  //   prop = vendorProperties[ prop ] || prop;\n  //   transitionValues.push( toDashedAll( prop ) );\n  // }\n  // munge number to millisecond, to match stagger\n  var duration = this.layout.options.transitionDuration;\n  duration = typeof duration == 'number' ? duration + 'ms' : duration;\n  // enable transition styles\n  this.css({\n    transitionProperty: transitionProps,\n    transitionDuration: duration,\n    transitionDelay: this.staggerDelay || 0\n  });\n  // listen for transition end event\n  this.element.addEventListener( transitionEndEvent, this, false );\n};\n\n// ----- events ----- //\n\nproto.onwebkitTransitionEnd = function( event ) {\n  this.ontransitionend( event );\n};\n\nproto.onotransitionend = function( event ) {\n  this.ontransitionend( event );\n};\n\n// properties that I munge to make my life easier\nvar dashedVendorProperties = {\n  '-webkit-transform': 'transform'\n};\n\nproto.ontransitionend = function( event ) {\n  // disregard bubbled events from children\n  if ( event.target !== this.element ) {\n    return;\n  }\n  var _transition = this._transn;\n  // get property name of transitioned property, convert to prefix-free\n  var propertyName = dashedVendorProperties[ event.propertyName ] || event.propertyName;\n\n  // remove property that has completed transitioning\n  delete _transition.ingProperties[ propertyName ];\n  // check if any properties are still transitioning\n  if ( isEmptyObj( _transition.ingProperties ) ) {\n    // all properties have completed transitioning\n    this.disableTransition();\n  }\n  // clean style\n  if ( propertyName in _transition.clean ) {\n    // clean up style\n    this.element.style[ event.propertyName ] = '';\n    delete _transition.clean[ propertyName ];\n  }\n  // trigger onTransitionEnd callback\n  if ( propertyName in _transition.onEnd ) {\n    var onTransitionEnd = _transition.onEnd[ propertyName ];\n    onTransitionEnd.call( this );\n    delete _transition.onEnd[ propertyName ];\n  }\n\n  this.emitEvent( 'transitionEnd', [ this ] );\n};\n\nproto.disableTransition = function() {\n  this.removeTransitionStyles();\n  this.element.removeEventListener( transitionEndEvent, this, false );\n  this.isTransitioning = false;\n};\n\n/**\n * removes style property from element\n * @param {Object} style\n**/\nproto._removeStyles = function( style ) {\n  // clean up transition styles\n  var cleanStyle = {};\n  for ( var prop in style ) {\n    cleanStyle[ prop ] = '';\n  }\n  this.css( cleanStyle );\n};\n\nvar cleanTransitionStyle = {\n  transitionProperty: '',\n  transitionDuration: '',\n  transitionDelay: ''\n};\n\nproto.removeTransitionStyles = function() {\n  // remove transition\n  this.css( cleanTransitionStyle );\n};\n\n// ----- stagger ----- //\n\nproto.stagger = function( delay ) {\n  delay = isNaN( delay ) ? 0 : delay;\n  this.staggerDelay = delay + 'ms';\n};\n\n// ----- show/hide/remove ----- //\n\n// remove element from DOM\nproto.removeElem = function() {\n  this.element.parentNode.removeChild( this.element );\n  // remove display: none\n  this.css({ display: '' });\n  this.emitEvent( 'remove', [ this ] );\n};\n\nproto.remove = function() {\n  // just remove element if no transition support or no transition\n  if ( !transitionProperty || !parseFloat( this.layout.options.transitionDuration ) ) {\n    this.removeElem();\n    return;\n  }\n\n  // start transition\n  this.once( 'transitionEnd', function() {\n    this.removeElem();\n  });\n  this.hide();\n};\n\nproto.reveal = function() {\n  delete this.isHidden;\n  // remove display: none\n  this.css({ display: '' });\n\n  var options = this.layout.options;\n\n  var onTransitionEnd = {};\n  var transitionEndProperty = this.getHideRevealTransitionEndProperty('visibleStyle');\n  onTransitionEnd[ transitionEndProperty ] = this.onRevealTransitionEnd;\n\n  this.transition({\n    from: options.hiddenStyle,\n    to: options.visibleStyle,\n    isCleaning: true,\n    onTransitionEnd: onTransitionEnd\n  });\n};\n\nproto.onRevealTransitionEnd = function() {\n  // check if still visible\n  // during transition, item may have been hidden\n  if ( !this.isHidden ) {\n    this.emitEvent('reveal');\n  }\n};\n\n/**\n * get style property use for hide/reveal transition end\n * @param {String} styleProperty - hiddenStyle/visibleStyle\n * @returns {String}\n */\nproto.getHideRevealTransitionEndProperty = function( styleProperty ) {\n  var optionStyle = this.layout.options[ styleProperty ];\n  // use opacity\n  if ( optionStyle.opacity ) {\n    return 'opacity';\n  }\n  // get first property\n  for ( var prop in optionStyle ) {\n    return prop;\n  }\n};\n\nproto.hide = function() {\n  // set flag\n  this.isHidden = true;\n  // remove display: none\n  this.css({ display: '' });\n\n  var options = this.layout.options;\n\n  var onTransitionEnd = {};\n  var transitionEndProperty = this.getHideRevealTransitionEndProperty('hiddenStyle');\n  onTransitionEnd[ transitionEndProperty ] = this.onHideTransitionEnd;\n\n  this.transition({\n    from: options.visibleStyle,\n    to: options.hiddenStyle,\n    // keep hidden stuff hidden\n    isCleaning: true,\n    onTransitionEnd: onTransitionEnd\n  });\n};\n\nproto.onHideTransitionEnd = function() {\n  // check if still hidden\n  // during transition, item may have been un-hidden\n  if ( this.isHidden ) {\n    this.css({ display: 'none' });\n    this.emitEvent('hide');\n  }\n};\n\nproto.destroy = function() {\n  this.css({\n    position: '',\n    left: '',\n    right: '',\n    top: '',\n    bottom: '',\n    transition: '',\n    transform: ''\n  });\n};\n\nreturn Item;\n\n}));\n","/*!\n * Outlayer v2.1.1\n * the brains and guts of a layout library\n * MIT license\n */\n\n( function( window, factory ) {\n  'use strict';\n  // universal module definition\n  /* jshint strict: false */ /* globals define, module, require */\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD - RequireJS\n    define( [\n        'ev-emitter/ev-emitter',\n        'get-size/get-size',\n        'fizzy-ui-utils/utils',\n        './item'\n      ],\n      function( EvEmitter, getSize, utils, Item ) {\n        return factory( window, EvEmitter, getSize, utils, Item);\n      }\n    );\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS - Browserify, Webpack\n    module.exports = factory(\n      window,\n      require('ev-emitter'),\n      require('get-size'),\n      require('fizzy-ui-utils'),\n      require('./item')\n    );\n  } else {\n    // browser global\n    window.Outlayer = factory(\n      window,\n      window.EvEmitter,\n      window.getSize,\n      window.fizzyUIUtils,\n      window.Outlayer.Item\n    );\n  }\n\n}( window, function factory( window, EvEmitter, getSize, utils, Item ) {\n'use strict';\n\n// ----- vars ----- //\n\nvar console = window.console;\nvar jQuery = window.jQuery;\nvar noop = function() {};\n\n// -------------------------- Outlayer -------------------------- //\n\n// globally unique identifiers\nvar GUID = 0;\n// internal store of all Outlayer intances\nvar instances = {};\n\n\n/**\n * @param {Element, String} element\n * @param {Object} options\n * @constructor\n */\nfunction Outlayer( element, options ) {\n  var queryElement = utils.getQueryElement( element );\n  if ( !queryElement ) {\n    if ( console ) {\n      console.error( 'Bad element for ' + this.constructor.namespace +\n        ': ' + ( queryElement || element ) );\n    }\n    return;\n  }\n  this.element = queryElement;\n  // add jQuery\n  if ( jQuery ) {\n    this.$element = jQuery( this.element );\n  }\n\n  // options\n  this.options = utils.extend( {}, this.constructor.defaults );\n  this.option( options );\n\n  // add id for Outlayer.getFromElement\n  var id = ++GUID;\n  this.element.outlayerGUID = id; // expando\n  instances[ id ] = this; // associate via id\n\n  // kick it off\n  this._create();\n\n  var isInitLayout = this._getOption('initLayout');\n  if ( isInitLayout ) {\n    this.layout();\n  }\n}\n\n// settings are for internal use only\nOutlayer.namespace = 'outlayer';\nOutlayer.Item = Item;\n\n// default options\nOutlayer.defaults = {\n  containerStyle: {\n    position: 'relative'\n  },\n  initLayout: true,\n  originLeft: true,\n  originTop: true,\n  resize: true,\n  resizeContainer: true,\n  // item options\n  transitionDuration: '0.4s',\n  hiddenStyle: {\n    opacity: 0,\n    transform: 'scale(0.001)'\n  },\n  visibleStyle: {\n    opacity: 1,\n    transform: 'scale(1)'\n  }\n};\n\nvar proto = Outlayer.prototype;\n// inherit EvEmitter\nutils.extend( proto, EvEmitter.prototype );\n\n/**\n * set options\n * @param {Object} opts\n */\nproto.option = function( opts ) {\n  utils.extend( this.options, opts );\n};\n\n/**\n * get backwards compatible option value, check old name\n */\nproto._getOption = function( option ) {\n  var oldOption = this.constructor.compatOptions[ option ];\n  return oldOption && this.options[ oldOption ] !== undefined ?\n    this.options[ oldOption ] : this.options[ option ];\n};\n\nOutlayer.compatOptions = {\n  // currentName: oldName\n  initLayout: 'isInitLayout',\n  horizontal: 'isHorizontal',\n  layoutInstant: 'isLayoutInstant',\n  originLeft: 'isOriginLeft',\n  originTop: 'isOriginTop',\n  resize: 'isResizeBound',\n  resizeContainer: 'isResizingContainer'\n};\n\nproto._create = function() {\n  // get items from children\n  this.reloadItems();\n  // elements that affect layout, but are not laid out\n  this.stamps = [];\n  this.stamp( this.options.stamp );\n  // set container style\n  utils.extend( this.element.style, this.options.containerStyle );\n\n  // bind resize method\n  var canBindResize = this._getOption('resize');\n  if ( canBindResize ) {\n    this.bindResize();\n  }\n};\n\n// goes through all children again and gets bricks in proper order\nproto.reloadItems = function() {\n  // collection of item elements\n  this.items = this._itemize( this.element.children );\n};\n\n\n/**\n * turn elements into Outlayer.Items to be used in layout\n * @param {Array or NodeList or HTMLElement} elems\n * @returns {Array} items - collection of new Outlayer Items\n */\nproto._itemize = function( elems ) {\n\n  var itemElems = this._filterFindItemElements( elems );\n  var Item = this.constructor.Item;\n\n  // create new Outlayer Items for collection\n  var items = [];\n  for ( var i=0; i < itemElems.length; i++ ) {\n    var elem = itemElems[i];\n    var item = new Item( elem, this );\n    items.push( item );\n  }\n\n  return items;\n};\n\n/**\n * get item elements to be used in layout\n * @param {Array or NodeList or HTMLElement} elems\n * @returns {Array} items - item elements\n */\nproto._filterFindItemElements = function( elems ) {\n  return utils.filterFindElements( elems, this.options.itemSelector );\n};\n\n/**\n * getter method for getting item elements\n * @returns {Array} elems - collection of item elements\n */\nproto.getItemElements = function() {\n  return this.items.map( function( item ) {\n    return item.element;\n  });\n};\n\n// ----- init & layout ----- //\n\n/**\n * lays out all items\n */\nproto.layout = function() {\n  this._resetLayout();\n  this._manageStamps();\n\n  // don't animate first layout\n  var layoutInstant = this._getOption('layoutInstant');\n  var isInstant = layoutInstant !== undefined ?\n    layoutInstant : !this._isLayoutInited;\n  this.layoutItems( this.items, isInstant );\n\n  // flag for initalized\n  this._isLayoutInited = true;\n};\n\n// _init is alias for layout\nproto._init = proto.layout;\n\n/**\n * logic before any new layout\n */\nproto._resetLayout = function() {\n  this.getSize();\n};\n\n\nproto.getSize = function() {\n  this.size = getSize( this.element );\n};\n\n/**\n * get measurement from option, for columnWidth, rowHeight, gutter\n * if option is String -> get element from selector string, & get size of element\n * if option is Element -> get size of element\n * else use option as a number\n *\n * @param {String} measurement\n * @param {String} size - width or height\n * @private\n */\nproto._getMeasurement = function( measurement, size ) {\n  var option = this.options[ measurement ];\n  var elem;\n  if ( !option ) {\n    // default to 0\n    this[ measurement ] = 0;\n  } else {\n    // use option as an element\n    if ( typeof option == 'string' ) {\n      elem = this.element.querySelector( option );\n    } else if ( option instanceof HTMLElement ) {\n      elem = option;\n    }\n    // use size of element, if element\n    this[ measurement ] = elem ? getSize( elem )[ size ] : option;\n  }\n};\n\n/**\n * layout a collection of item elements\n * @api public\n */\nproto.layoutItems = function( items, isInstant ) {\n  items = this._getItemsForLayout( items );\n\n  this._layoutItems( items, isInstant );\n\n  this._postLayout();\n};\n\n/**\n * get the items to be laid out\n * you may want to skip over some items\n * @param {Array} items\n * @returns {Array} items\n */\nproto._getItemsForLayout = function( items ) {\n  return items.filter( function( item ) {\n    return !item.isIgnored;\n  });\n};\n\n/**\n * layout items\n * @param {Array} items\n * @param {Boolean} isInstant\n */\nproto._layoutItems = function( items, isInstant ) {\n  this._emitCompleteOnItems( 'layout', items );\n\n  if ( !items || !items.length ) {\n    // no items, emit event with empty array\n    return;\n  }\n\n  var queue = [];\n\n  items.forEach( function( item ) {\n    // get x/y object from method\n    var position = this._getItemLayoutPosition( item );\n    // enqueue\n    position.item = item;\n    position.isInstant = isInstant || item.isLayoutInstant;\n    queue.push( position );\n  }, this );\n\n  this._processLayoutQueue( queue );\n};\n\n/**\n * get item layout position\n * @param {Outlayer.Item} item\n * @returns {Object} x and y position\n */\nproto._getItemLayoutPosition = function( /* item */ ) {\n  return {\n    x: 0,\n    y: 0\n  };\n};\n\n/**\n * iterate over array and position each item\n * Reason being - separating this logic prevents 'layout invalidation'\n * thx @paul_irish\n * @param {Array} queue\n */\nproto._processLayoutQueue = function( queue ) {\n  this.updateStagger();\n  queue.forEach( function( obj, i ) {\n    this._positionItem( obj.item, obj.x, obj.y, obj.isInstant, i );\n  }, this );\n};\n\n// set stagger from option in milliseconds number\nproto.updateStagger = function() {\n  var stagger = this.options.stagger;\n  if ( stagger === null || stagger === undefined ) {\n    this.stagger = 0;\n    return;\n  }\n  this.stagger = getMilliseconds( stagger );\n  return this.stagger;\n};\n\n/**\n * Sets position of item in DOM\n * @param {Outlayer.Item} item\n * @param {Number} x - horizontal position\n * @param {Number} y - vertical position\n * @param {Boolean} isInstant - disables transitions\n */\nproto._positionItem = function( item, x, y, isInstant, i ) {\n  if ( isInstant ) {\n    // if not transition, just set CSS\n    item.goTo( x, y );\n  } else {\n    item.stagger( i * this.stagger );\n    item.moveTo( x, y );\n  }\n};\n\n/**\n * Any logic you want to do after each layout,\n * i.e. size the container\n */\nproto._postLayout = function() {\n  this.resizeContainer();\n};\n\nproto.resizeContainer = function() {\n  var isResizingContainer = this._getOption('resizeContainer');\n  if ( !isResizingContainer ) {\n    return;\n  }\n  var size = this._getContainerSize();\n  if ( size ) {\n    this._setContainerMeasure( size.width, true );\n    this._setContainerMeasure( size.height, false );\n  }\n};\n\n/**\n * Sets width or height of container if returned\n * @returns {Object} size\n *   @param {Number} width\n *   @param {Number} height\n */\nproto._getContainerSize = noop;\n\n/**\n * @param {Number} measure - size of width or height\n * @param {Boolean} isWidth\n */\nproto._setContainerMeasure = function( measure, isWidth ) {\n  if ( measure === undefined ) {\n    return;\n  }\n\n  var elemSize = this.size;\n  // add padding and border width if border box\n  if ( elemSize.isBorderBox ) {\n    measure += isWidth ? elemSize.paddingLeft + elemSize.paddingRight +\n      elemSize.borderLeftWidth + elemSize.borderRightWidth :\n      elemSize.paddingBottom + elemSize.paddingTop +\n      elemSize.borderTopWidth + elemSize.borderBottomWidth;\n  }\n\n  measure = Math.max( measure, 0 );\n  this.element.style[ isWidth ? 'width' : 'height' ] = measure + 'px';\n};\n\n/**\n * emit eventComplete on a collection of items events\n * @param {String} eventName\n * @param {Array} items - Outlayer.Items\n */\nproto._emitCompleteOnItems = function( eventName, items ) {\n  var _this = this;\n  function onComplete() {\n    _this.dispatchEvent( eventName + 'Complete', null, [ items ] );\n  }\n\n  var count = items.length;\n  if ( !items || !count ) {\n    onComplete();\n    return;\n  }\n\n  var doneCount = 0;\n  function tick() {\n    doneCount++;\n    if ( doneCount == count ) {\n      onComplete();\n    }\n  }\n\n  // bind callback\n  items.forEach( function( item ) {\n    item.once( eventName, tick );\n  });\n};\n\n/**\n * emits events via EvEmitter and jQuery events\n * @param {String} type - name of event\n * @param {Event} event - original event\n * @param {Array} args - extra arguments\n */\nproto.dispatchEvent = function( type, event, args ) {\n  // add original event to arguments\n  var emitArgs = event ? [ event ].concat( args ) : args;\n  this.emitEvent( type, emitArgs );\n\n  if ( jQuery ) {\n    // set this.$element\n    this.$element = this.$element || jQuery( this.element );\n    if ( event ) {\n      // create jQuery event\n      var $event = jQuery.Event( event );\n      $event.type = type;\n      this.$element.trigger( $event, args );\n    } else {\n      // just trigger with type if no event available\n      this.$element.trigger( type, args );\n    }\n  }\n};\n\n// -------------------------- ignore & stamps -------------------------- //\n\n\n/**\n * keep item in collection, but do not lay it out\n * ignored items do not get skipped in layout\n * @param {Element} elem\n */\nproto.ignore = function( elem ) {\n  var item = this.getItem( elem );\n  if ( item ) {\n    item.isIgnored = true;\n  }\n};\n\n/**\n * return item to layout collection\n * @param {Element} elem\n */\nproto.unignore = function( elem ) {\n  var item = this.getItem( elem );\n  if ( item ) {\n    delete item.isIgnored;\n  }\n};\n\n/**\n * adds elements to stamps\n * @param {NodeList, Array, Element, or String} elems\n */\nproto.stamp = function( elems ) {\n  elems = this._find( elems );\n  if ( !elems ) {\n    return;\n  }\n\n  this.stamps = this.stamps.concat( elems );\n  // ignore\n  elems.forEach( this.ignore, this );\n};\n\n/**\n * removes elements to stamps\n * @param {NodeList, Array, or Element} elems\n */\nproto.unstamp = function( elems ) {\n  elems = this._find( elems );\n  if ( !elems ){\n    return;\n  }\n\n  elems.forEach( function( elem ) {\n    // filter out removed stamp elements\n    utils.removeFrom( this.stamps, elem );\n    this.unignore( elem );\n  }, this );\n};\n\n/**\n * finds child elements\n * @param {NodeList, Array, Element, or String} elems\n * @returns {Array} elems\n */\nproto._find = function( elems ) {\n  if ( !elems ) {\n    return;\n  }\n  // if string, use argument as selector string\n  if ( typeof elems == 'string' ) {\n    elems = this.element.querySelectorAll( elems );\n  }\n  elems = utils.makeArray( elems );\n  return elems;\n};\n\nproto._manageStamps = function() {\n  if ( !this.stamps || !this.stamps.length ) {\n    return;\n  }\n\n  this._getBoundingRect();\n\n  this.stamps.forEach( this._manageStamp, this );\n};\n\n// update boundingLeft / Top\nproto._getBoundingRect = function() {\n  // get bounding rect for container element\n  var boundingRect = this.element.getBoundingClientRect();\n  var size = this.size;\n  this._boundingRect = {\n    left: boundingRect.left + size.paddingLeft + size.borderLeftWidth,\n    top: boundingRect.top + size.paddingTop + size.borderTopWidth,\n    right: boundingRect.right - ( size.paddingRight + size.borderRightWidth ),\n    bottom: boundingRect.bottom - ( size.paddingBottom + size.borderBottomWidth )\n  };\n};\n\n/**\n * @param {Element} stamp\n**/\nproto._manageStamp = noop;\n\n/**\n * get x/y position of element relative to container element\n * @param {Element} elem\n * @returns {Object} offset - has left, top, right, bottom\n */\nproto._getElementOffset = function( elem ) {\n  var boundingRect = elem.getBoundingClientRect();\n  var thisRect = this._boundingRect;\n  var size = getSize( elem );\n  var offset = {\n    left: boundingRect.left - thisRect.left - size.marginLeft,\n    top: boundingRect.top - thisRect.top - size.marginTop,\n    right: thisRect.right - boundingRect.right - size.marginRight,\n    bottom: thisRect.bottom - boundingRect.bottom - size.marginBottom\n  };\n  return offset;\n};\n\n// -------------------------- resize -------------------------- //\n\n// enable event handlers for listeners\n// i.e. resize -> onresize\nproto.handleEvent = utils.handleEvent;\n\n/**\n * Bind layout to window resizing\n */\nproto.bindResize = function() {\n  window.addEventListener( 'resize', this );\n  this.isResizeBound = true;\n};\n\n/**\n * Unbind layout to window resizing\n */\nproto.unbindResize = function() {\n  window.removeEventListener( 'resize', this );\n  this.isResizeBound = false;\n};\n\nproto.onresize = function() {\n  this.resize();\n};\n\nutils.debounceMethod( Outlayer, 'onresize', 100 );\n\nproto.resize = function() {\n  // don't trigger if size did not change\n  // or if resize was unbound. See #9\n  if ( !this.isResizeBound || !this.needsResizeLayout() ) {\n    return;\n  }\n\n  this.layout();\n};\n\n/**\n * check if layout is needed post layout\n * @returns Boolean\n */\nproto.needsResizeLayout = function() {\n  var size = getSize( this.element );\n  // check that this.size and size are there\n  // IE8 triggers resize on body size change, so they might not be\n  var hasSizes = this.size && size;\n  return hasSizes && size.innerWidth !== this.size.innerWidth;\n};\n\n// -------------------------- methods -------------------------- //\n\n/**\n * add items to Outlayer instance\n * @param {Array or NodeList or Element} elems\n * @returns {Array} items - Outlayer.Items\n**/\nproto.addItems = function( elems ) {\n  var items = this._itemize( elems );\n  // add items to collection\n  if ( items.length ) {\n    this.items = this.items.concat( items );\n  }\n  return items;\n};\n\n/**\n * Layout newly-appended item elements\n * @param {Array or NodeList or Element} elems\n */\nproto.appended = function( elems ) {\n  var items = this.addItems( elems );\n  if ( !items.length ) {\n    return;\n  }\n  // layout and reveal just the new items\n  this.layoutItems( items, true );\n  this.reveal( items );\n};\n\n/**\n * Layout prepended elements\n * @param {Array or NodeList or Element} elems\n */\nproto.prepended = function( elems ) {\n  var items = this._itemize( elems );\n  if ( !items.length ) {\n    return;\n  }\n  // add items to beginning of collection\n  var previousItems = this.items.slice(0);\n  this.items = items.concat( previousItems );\n  // start new layout\n  this._resetLayout();\n  this._manageStamps();\n  // layout new stuff without transition\n  this.layoutItems( items, true );\n  this.reveal( items );\n  // layout previous items\n  this.layoutItems( previousItems );\n};\n\n/**\n * reveal a collection of items\n * @param {Array of Outlayer.Items} items\n */\nproto.reveal = function( items ) {\n  this._emitCompleteOnItems( 'reveal', items );\n  if ( !items || !items.length ) {\n    return;\n  }\n  var stagger = this.updateStagger();\n  items.forEach( function( item, i ) {\n    item.stagger( i * stagger );\n    item.reveal();\n  });\n};\n\n/**\n * hide a collection of items\n * @param {Array of Outlayer.Items} items\n */\nproto.hide = function( items ) {\n  this._emitCompleteOnItems( 'hide', items );\n  if ( !items || !items.length ) {\n    return;\n  }\n  var stagger = this.updateStagger();\n  items.forEach( function( item, i ) {\n    item.stagger( i * stagger );\n    item.hide();\n  });\n};\n\n/**\n * reveal item elements\n * @param {Array}, {Element}, {NodeList} items\n */\nproto.revealItemElements = function( elems ) {\n  var items = this.getItems( elems );\n  this.reveal( items );\n};\n\n/**\n * hide item elements\n * @param {Array}, {Element}, {NodeList} items\n */\nproto.hideItemElements = function( elems ) {\n  var items = this.getItems( elems );\n  this.hide( items );\n};\n\n/**\n * get Outlayer.Item, given an Element\n * @param {Element} elem\n * @param {Function} callback\n * @returns {Outlayer.Item} item\n */\nproto.getItem = function( elem ) {\n  // loop through items to get the one that matches\n  for ( var i=0; i < this.items.length; i++ ) {\n    var item = this.items[i];\n    if ( item.element == elem ) {\n      // return item\n      return item;\n    }\n  }\n};\n\n/**\n * get collection of Outlayer.Items, given Elements\n * @param {Array} elems\n * @returns {Array} items - Outlayer.Items\n */\nproto.getItems = function( elems ) {\n  elems = utils.makeArray( elems );\n  var items = [];\n  elems.forEach( function( elem ) {\n    var item = this.getItem( elem );\n    if ( item ) {\n      items.push( item );\n    }\n  }, this );\n\n  return items;\n};\n\n/**\n * remove element(s) from instance and DOM\n * @param {Array or NodeList or Element} elems\n */\nproto.remove = function( elems ) {\n  var removeItems = this.getItems( elems );\n\n  this._emitCompleteOnItems( 'remove', removeItems );\n\n  // bail if no items to remove\n  if ( !removeItems || !removeItems.length ) {\n    return;\n  }\n\n  removeItems.forEach( function( item ) {\n    item.remove();\n    // remove item from collection\n    utils.removeFrom( this.items, item );\n  }, this );\n};\n\n// ----- destroy ----- //\n\n// remove and disable Outlayer instance\nproto.destroy = function() {\n  // clean up dynamic styles\n  var style = this.element.style;\n  style.height = '';\n  style.position = '';\n  style.width = '';\n  // destroy items\n  this.items.forEach( function( item ) {\n    item.destroy();\n  });\n\n  this.unbindResize();\n\n  var id = this.element.outlayerGUID;\n  delete instances[ id ]; // remove reference to instance by id\n  delete this.element.outlayerGUID;\n  // remove data for jQuery\n  if ( jQuery ) {\n    jQuery.removeData( this.element, this.constructor.namespace );\n  }\n\n};\n\n// -------------------------- data -------------------------- //\n\n/**\n * get Outlayer instance from element\n * @param {Element} elem\n * @returns {Outlayer}\n */\nOutlayer.data = function( elem ) {\n  elem = utils.getQueryElement( elem );\n  var id = elem && elem.outlayerGUID;\n  return id && instances[ id ];\n};\n\n\n// -------------------------- create Outlayer class -------------------------- //\n\n/**\n * create a layout class\n * @param {String} namespace\n */\nOutlayer.create = function( namespace, options ) {\n  // sub-class Outlayer\n  var Layout = subclass( Outlayer );\n  // apply new options and compatOptions\n  Layout.defaults = utils.extend( {}, Outlayer.defaults );\n  utils.extend( Layout.defaults, options );\n  Layout.compatOptions = utils.extend( {}, Outlayer.compatOptions  );\n\n  Layout.namespace = namespace;\n\n  Layout.data = Outlayer.data;\n\n  // sub-class Item\n  Layout.Item = subclass( Item );\n\n  // -------------------------- declarative -------------------------- //\n\n  utils.htmlInit( Layout, namespace );\n\n  // -------------------------- jQuery bridge -------------------------- //\n\n  // make into jQuery plugin\n  if ( jQuery && jQuery.bridget ) {\n    jQuery.bridget( namespace, Layout );\n  }\n\n  return Layout;\n};\n\nfunction subclass( Parent ) {\n  function SubClass() {\n    Parent.apply( this, arguments );\n  }\n\n  SubClass.prototype = Object.create( Parent.prototype );\n  SubClass.prototype.constructor = SubClass;\n\n  return SubClass;\n}\n\n// ----- helpers ----- //\n\n// how many milliseconds are in each unit\nvar msUnits = {\n  ms: 1,\n  s: 1000\n};\n\n// munge time-like parameter into millisecond number\n// '0.4s' -> 40\nfunction getMilliseconds( time ) {\n  if ( typeof time == 'number' ) {\n    return time;\n  }\n  var matches = time.match( /(^\\d*\\.?\\d*)(\\w*)/ );\n  var num = matches && matches[1];\n  var unit = matches && matches[2];\n  if ( !num.length ) {\n    return 0;\n  }\n  num = parseFloat( num );\n  var mult = msUnits[ unit ] || 1;\n  return num * mult;\n}\n\n// ----- fin ----- //\n\n// back in global\nOutlayer.Item = Item;\n\nreturn Outlayer;\n\n}));\n","/*!\n * Masonry v4.2.1\n * Cascading grid layout library\n * https://masonry.desandro.com\n * MIT License\n * by David DeSandro\n */\n\n( function( window, factory ) {\n  // universal module definition\n  /* jshint strict: false */ /*globals define, module, require */\n  if ( typeof define == 'function' && define.amd ) {\n    // AMD\n    define( [\n        'outlayer/outlayer',\n        'get-size/get-size'\n      ],\n      factory );\n  } else if ( typeof module == 'object' && module.exports ) {\n    // CommonJS\n    module.exports = factory(\n      require('outlayer'),\n      require('get-size')\n    );\n  } else {\n    // browser global\n    window.Masonry = factory(\n      window.Outlayer,\n      window.getSize\n    );\n  }\n\n}( window, function factory( Outlayer, getSize ) {\n\n'use strict';\n\n// -------------------------- masonryDefinition -------------------------- //\n\n  // create an Outlayer layout class\n  var Masonry = Outlayer.create('masonry');\n  // isFitWidth -> fitWidth\n  Masonry.compatOptions.fitWidth = 'isFitWidth';\n\n  var proto = Masonry.prototype;\n\n  proto._resetLayout = function() {\n    this.getSize();\n    this._getMeasurement( 'columnWidth', 'outerWidth' );\n    this._getMeasurement( 'gutter', 'outerWidth' );\n    this.measureColumns();\n\n    // reset column Y\n    this.colYs = [];\n    for ( var i=0; i < this.cols; i++ ) {\n      this.colYs.push( 0 );\n    }\n\n    this.maxY = 0;\n    this.horizontalColIndex = 0;\n  };\n\n  proto.measureColumns = function() {\n    this.getContainerWidth();\n    // if columnWidth is 0, default to outerWidth of first item\n    if ( !this.columnWidth ) {\n      var firstItem = this.items[0];\n      var firstItemElem = firstItem && firstItem.element;\n      // columnWidth fall back to item of first element\n      this.columnWidth = firstItemElem && getSize( firstItemElem ).outerWidth ||\n        // if first elem has no width, default to size of container\n        this.containerWidth;\n    }\n\n    var columnWidth = this.columnWidth += this.gutter;\n\n    // calculate columns\n    var containerWidth = this.containerWidth + this.gutter;\n    var cols = containerWidth / columnWidth;\n    // fix rounding errors, typically with gutters\n    var excess = columnWidth - containerWidth % columnWidth;\n    // if overshoot is less than a pixel, round up, otherwise floor it\n    var mathMethod = excess && excess < 1 ? 'round' : 'floor';\n    cols = Math[ mathMethod ]( cols );\n    this.cols = Math.max( cols, 1 );\n  };\n\n  proto.getContainerWidth = function() {\n    // container is parent if fit width\n    var isFitWidth = this._getOption('fitWidth');\n    var container = isFitWidth ? this.element.parentNode : this.element;\n    // check that this.size and size are there\n    // IE8 triggers resize on body size change, so they might not be\n    var size = getSize( container );\n    this.containerWidth = size && size.innerWidth;\n  };\n\n  proto._getItemLayoutPosition = function( item ) {\n    item.getSize();\n    // how many columns does this brick span\n    var remainder = item.size.outerWidth % this.columnWidth;\n    var mathMethod = remainder && remainder < 1 ? 'round' : 'ceil';\n    // round if off by 1 pixel, otherwise use ceil\n    var colSpan = Math[ mathMethod ]( item.size.outerWidth / this.columnWidth );\n    colSpan = Math.min( colSpan, this.cols );\n    // use horizontal or top column position\n    var colPosMethod = this.options.horizontalOrder ?\n      '_getHorizontalColPosition' : '_getTopColPosition';\n    var colPosition = this[ colPosMethod ]( colSpan, item );\n    // position the brick\n    var position = {\n      x: this.columnWidth * colPosition.col,\n      y: colPosition.y\n    };\n    // apply setHeight to necessary columns\n    var setHeight = colPosition.y + item.size.outerHeight;\n    var setMax = colSpan + colPosition.col;\n    for ( var i = colPosition.col; i < setMax; i++ ) {\n      this.colYs[i] = setHeight;\n    }\n\n    return position;\n  };\n\n  proto._getTopColPosition = function( colSpan ) {\n    var colGroup = this._getTopColGroup( colSpan );\n    // get the minimum Y value from the columns\n    var minimumY = Math.min.apply( Math, colGroup );\n\n    return {\n      col: colGroup.indexOf( minimumY ),\n      y: minimumY,\n    };\n  };\n\n  /**\n   * @param {Number} colSpan - number of columns the element spans\n   * @returns {Array} colGroup\n   */\n  proto._getTopColGroup = function( colSpan ) {\n    if ( colSpan < 2 ) {\n      // if brick spans only one column, use all the column Ys\n      return this.colYs;\n    }\n\n    var colGroup = [];\n    // how many different places could this brick fit horizontally\n    var groupCount = this.cols + 1 - colSpan;\n    // for each group potential horizontal position\n    for ( var i = 0; i < groupCount; i++ ) {\n      colGroup[i] = this._getColGroupY( i, colSpan );\n    }\n    return colGroup;\n  };\n\n  proto._getColGroupY = function( col, colSpan ) {\n    if ( colSpan < 2 ) {\n      return this.colYs[ col ];\n    }\n    // make an array of colY values for that one group\n    var groupColYs = this.colYs.slice( col, col + colSpan );\n    // and get the max value of the array\n    return Math.max.apply( Math, groupColYs );\n  };\n\n  // get column position based on horizontal index. #873\n  proto._getHorizontalColPosition = function( colSpan, item ) {\n    var col = this.horizontalColIndex % this.cols;\n    var isOver = colSpan > 1 && col + colSpan > this.cols;\n    // shift to next row if item can't fit on current row\n    col = isOver ? 0 : col;\n    // don't let zero-size items take up space\n    var hasSize = item.size.outerWidth && item.size.outerHeight;\n    this.horizontalColIndex = hasSize ? col + colSpan : this.horizontalColIndex;\n\n    return {\n      col: col,\n      y: this._getColGroupY( col, colSpan ),\n    };\n  };\n\n  proto._manageStamp = function( stamp ) {\n    var stampSize = getSize( stamp );\n    var offset = this._getElementOffset( stamp );\n    // get the columns that this stamp affects\n    var isOriginLeft = this._getOption('originLeft');\n    var firstX = isOriginLeft ? offset.left : offset.right;\n    var lastX = firstX + stampSize.outerWidth;\n    var firstCol = Math.floor( firstX / this.columnWidth );\n    firstCol = Math.max( 0, firstCol );\n    var lastCol = Math.floor( lastX / this.columnWidth );\n    // lastCol should not go over if multiple of columnWidth #425\n    lastCol -= lastX % this.columnWidth ? 0 : 1;\n    lastCol = Math.min( this.cols - 1, lastCol );\n    // set colYs to bottom of the stamp\n\n    var isOriginTop = this._getOption('originTop');\n    var stampMaxY = ( isOriginTop ? offset.top : offset.bottom ) +\n      stampSize.outerHeight;\n    for ( var i = firstCol; i <= lastCol; i++ ) {\n      this.colYs[i] = Math.max( stampMaxY, this.colYs[i] );\n    }\n  };\n\n  proto._getContainerSize = function() {\n    this.maxY = Math.max.apply( Math, this.colYs );\n    var size = {\n      height: this.maxY\n    };\n\n    if ( this._getOption('fitWidth') ) {\n      size.width = this._getContainerFitWidth();\n    }\n\n    return size;\n  };\n\n  proto._getContainerFitWidth = function() {\n    var unusedCols = 0;\n    // count unused columns\n    var i = this.cols;\n    while ( --i ) {\n      if ( this.colYs[i] !== 0 ) {\n        break;\n      }\n      unusedCols++;\n    }\n    // fit container to columns that have been used\n    return ( this.cols - unusedCols ) * this.columnWidth - this.gutter;\n  };\n\n  proto.needsResizeLayout = function() {\n    var previousWidth = this.containerWidth;\n    this.getContainerWidth();\n    return previousWidth != this.containerWidth;\n  };\n\n  return Masonry;\n\n}));\n","/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\nimport * as dompack from 'dompack';\n\n//just number RPCs globally instead of per server, makes debug ouput more useful\nlet globalseqnr = 1;\n\nfunction getDebugAppend() {\n  const urldebugvar = window.location.href.match(new RegExp('[?&#]wh-debug=([^&#?]*)'));\n  return urldebugvar ? '?wh-debug=' + urldebugvar[1] : '';\n}\n\n/* this is the followup for net/jsonrpc.es - we can hopefully clear net/ someday\n   and move net/eventserver to wh/eventserver.es then */\n\nclass ControlledCall {\n  abortcontroller = new AbortController;\n  timeout;\n  _callurl;\n  _fetchoptions;\n  promise: Promise<unknown>;\n  timedout = false;\n  aborted = false;\n  legacyresolve;\n  client;\n  options;\n\n  constructor(client, method, stack, id, options, callurl, fetchoptions) {\n    this.client = client;\n    this.options = options;\n    // if(options.timeout || options.signal) //as long as rpcResolve exists, we'll ALWAYS need to setup a controller\n    {\n      fetchoptions.signal = this.abortcontroller.signal;\n\n      if (options.timeout > 0) {\n        this.timeout = options.timeout;\n        setTimeout(() => this._handleTimeout(), options.timeout);\n      }\n      if (options.signal) {\n        options.signal.addEventListener(\"abort\", () => this._abort());\n      }\n    }\n\n    this._callurl = callurl;\n    this._fetchoptions = fetchoptions;\n\n    const fetchpromise = fetch(this._callurl, this._fetchoptions);\n    this.promise = this._completeCall(method, stack, id, fetchpromise);\n    this.promise.__jsonrpcinfo = this;\n  }\n  _handleTimeout() {\n    this.timedout = true;\n    this.abortcontroller.abort();\n  }\n  _abort() {\n    this.aborted = true;\n    this.abortcontroller.abort();\n  }\n  _legacyResolve(resolution) {\n    this.legacyresolve = resolution;\n    this.abortcontroller.abort();\n  }\n  async _completeCall(method, stack, id, fetchpromise) {\n    let response;\n    try {\n      while (true) { //loop for 429\n        response = await fetchpromise;\n        if (response.status === 429 && !(\"retry429\" in this.options && !this.options.retry429) && response.headers.get(\"Retry-After\")) {\n          const retryafter = parseInt(response.headers.get(\"Retry-After\"));\n          if (this.options.debug)\n            console.warn(`[rpc] We are being throttled (429 Too Many Requests) - retrying after ${retryafter} seconds`);\n\n          await new Promise(resolve => setTimeout(resolve, retryafter * 1000));\n          fetchpromise = fetch(this._callurl, this._fetchoptions);\n          continue;\n        }\n        break;\n      }\n    } catch (exception) {\n      if (this.options.debug)\n        console.log(`[rpc] #${id} Exception invoking '${method}'`, exception);\n\n      if (this.aborted)\n        throw new Error(`RPC Aborted`);\n      else if (this.timedout)\n        throw new Error(`RPC Timeout: timeout was set to ${this.timeout} milliseconds`);\n      else if (this.legacyresolve && this.legacyresolve.resolve)\n        return this.legacyresolve.resolve;\n      else\n        throw new Error(`RPC Failed: exception: ` + exception);\n    }\n\n    let jsonresponse;\n    try {\n      jsonresponse = await response.json();\n      if (this.options.debug)\n        console.log(`[rpc] #${id} Received response to '${method}'`, jsonresponse);\n    } catch (exception) {\n      if (this.options.debug)\n        console.warn(`[rpc] #${id} Response was not valid JSON`, exception);\n    }\n\n    if (!jsonresponse)\n      throw new Error(\"RPC Failed: Invalid JSON/RPC response received\");\n\n    if (jsonresponse && jsonresponse.error) {\n      this.client._tryLogError(stack, jsonresponse.error);\n      throw new Error(\"RPC Error: \" + (jsonresponse.error.message || \"Unknown error\"));\n    }\n\n    if (response.status === 200 && jsonresponse && jsonresponse.id !== id)\n      throw new Error(\"RPC Failed: Invalid JSON/RPC response received\");\n\n    if (this.options.wrapresult) {\n      return {\n        status: response.status,\n        result: jsonresponse.result || null,\n        error: jsonresponse.error || null,\n        retryafter: response.headers.get(\"Retry-After\") ? parseInt(response.headers.get(\"Retry-After\")) : null\n      };\n    }\n\n    return jsonresponse.result;\n  }\n}\n\n/** Invokes (WebHare) JSON/RPC\n    @param url - URL to invoke (leave empty or pass no parameters at all to callback to the current page)\n    options.timeout Default timeout for all calls\n    options.debug Debug (Follows 'rpc' debugflag if not explicity specified)\n    @deprecated Switch to \\@webhare/jsonrpc */\nexport default class RPCClient {\n  options;\n  url: string;\n  addfunctionname;\n  urlappend;\n  constructor(url: string, options?) {\n    this.options = {\n      timeout: 0,\n      debug: dompack.debugflags.rpc,\n      ...options\n    };\n\n    let whservicematch;\n    if (url) {\n      whservicematch = url.match(/^([a-z0-9_]+):([a-z0-9_]+)$/);\n      if (whservicematch)\n        this.url = `${location.origin}/wh_services/${whservicematch[1]}/${whservicematch[2]}`;\n      else\n        this.url = url;\n    } else {\n      this.url = location.href;  //invoke ourselves directly if no path specified\n    }\n\n    //if shorthand syntax is used, we know we're talking to our local webhare. add function names and the profiling flag if needed\n    this.addfunctionname = this.options.addfunctionname !== undefined ? this.options.addfunctionname : Boolean(whservicematch);\n    this.urlappend = this.options.urlappend !== undefined ? this.options.urlappend : whservicematch ? getDebugAppend() : \"\";\n  }\n\n  setOptions(options) {\n    this.options = { ...this.options, ...options };\n  }\n\n  _handleLegacyRPCResolve(promise, result) {\n    if (!promise.__jsonrpcinfo)\n      throw new Error(\"The promise is not an async JSONRPC request\");\n    promise.__jsonrpcinfo._legacyResolve({ resolve: result });\n  }\n\n  _tryLogError(stack, error) {\n    const trace = error.data ? (error.data.trace || error.data.list || []) : [];\n\n    console.group();\n    console.warn(\"RPC failed:\", error.message);\n    trace.forEach(rec => {\n      if (rec.filename || rec.line) {\n        const line = rec.filename + '#' + rec.line + '#' + rec.col + (rec.func ? ' (' + rec.func + ')' : '');\n        console.log(line);\n      }\n    });\n    if (stack) {\n      console.warn(\"Stack at calling point\");\n      console.log(stack);\n    }\n    console.groupEnd();\n  }\n\n  invoke(...params: unknown[]) {\n    let options;\n    if (typeof params[0] === \"object\")\n      options = { ...this.options, ...params.shift() };\n    else\n      options = this.options;\n\n    const method = params.shift();\n\n    //build the URL, add profiling and function parameters where needed\n    let callurl = this.url;\n    if (this.addfunctionname) //simplifies log analysis, ignored by the server\n      callurl += `/${method}`;\n    callurl += this.urlappend;\n\n    const id = ++globalseqnr;\n    let stack;\n\n    if (options.debug) {\n      stack = new Error().stack;\n      console.log(`[rpc] #${id} Invoking '${method}'`, params, callurl);\n    }\n\n    const fetchoptions = {\n      method: \"POST\",\n      credentials: 'same-origin', //this is the default since 2017-08-25, but Edge pre-18 is still around and will fail here\n      headers: {\n        \"Accept\": \"application/json\",\n        \"Content-Type\": \"application/json; charset=utf-8\"\n      },\n      body: JSON.stringify(\n        {\n          id: id,\n          method: method,\n          params: params || []\n        }),\n      keepalive: Boolean(options.keepalive)\n    };\n\n    return new ControlledCall(this, method, stack, id, options, callurl, fetchoptions).promise;\n  }\n}\n\nclass JSONRPCService { //originally generated inline by the rpcloader.ts\n  rpcclient;\n\n  static get HTTP_ERROR() { return -1; } // Error connecting to the RPC server\n  static get JSON_ERROR() { return -2; } // The returned value could not be decoded into a JSON object\n  static get PROTOCOL_ERROR() { return -3; } // The return object did not contain an id, or the id did not match the request id\n  static get RPC_ERROR() { return -4; } // The RPC returned an error\n  static get OFFLINE_ERROR() { return -5; } // The application is not online (only returned if the onlineonly option was set)\n  static get TIMEOUT_ERROR() { return -6; } // The request could not be sent or was not answered before within the timeout set in the options\n  static get SERVER_ERROR() { return -7; } // The server encountered an internal error\n\n  constructor(service: string) {\n    this.rpcclient = new RPCClient(service);\n  }\n\n  rpcResolve(promise: Promise<unknown>, result: unknown) {\n    this.rpcclient._handleLegacyRPCResolve(promise, result);\n  }\n  invoke(...args: unknown[]) {\n    return this.rpcclient.invoke(...args);\n  }\n}\n\nclass JSONRPCServiceProxy {\n  get(target: JSONRPCService, prop: string, receiver: unknown) {\n    if (prop in target)\n      return Reflect.get(target, prop, receiver);\n    //it's a call, turn into an invoke\n    return (...args: unknown[]) => target.invoke(prop, ...args);\n  }\n}\n\nexport function createService(name: string) {\n  const service = new JSONRPCService(name);\n  return new Proxy(service, new JSONRPCServiceProxy);\n}\n","/* frontend-config parses the wh-config object in the browser and mocks any missing data. @webhare/env does not actually expose this config, @webhare/frontend does\n   The frontend configuration is built in PageBuildRequest's 'frontendConfig' member */\n\nimport type { DTAPStage } from \"@webhare/env/src/concepts\";\nimport { debugFlags, initEnv } from \"@webhare/env/src/envbackend\";\nimport { getBrowserDebugFlags } from \"@webhare/env/src/init-browser\";\nimport { getLang } from \"@webhare/dompack/src/tree\";\nimport type { FrontendDataTypes } from \"@webhare/frontend\";\nimport { omit, throwError } from \"@webhare/std\";\n\n\n/** The format of the <script id=\"wh-config\"> object  */\nexport type WHConfigScriptData = {\n  //NOTE: existing frontend code doesn't expect site/obj to ever be null. not sure if 'object' provides the best interface or whether we need some sort of 'unknown but an existing object'\n  /** Page (targetobject) specific settings\n   *  @deprecated Use setFrontendData for type-safe settings\n  */\n  obj: { [key: string]: unknown };\n  /** Site specific settings\n   *  @deprecated Use setFrontendData for type-safe settings\n   */\n  site: { [key: string]: unknown };\n\n  /** Root URL of this site */\n  siteRoot: string;\n};\n\nexport type WHConfigScriptData_FromServer = WHConfigScriptData & { dtapStage: DTAPStage };\n\n//names fields can still have when not yet republished\ninterface WHConfigScriptData_OldPublishFields {\n  islive: boolean;\n  dtapstage: DTAPStage;\n  siteroot: string;\n}\n\n//fallback names with deprecation warnings\ninterface WHConfigScriptData_LegacyFields {\n  /** @deprecated Use dtapStage in WH5.4+ */\n  islive: boolean;\n  /** @deprecated Use `dtapStage` from \"\\@webhare/env\"; in WH5.4+ */\n  dtapstage: DTAPStage;\n  /** @deprecated Use `getSiteRoot` from \"\\@webhare/frontend\"; in WH5.7+ */\n  siteroot: string;\n}\n\nlet config: WHConfigScriptData_FromServer | undefined;\nlet siteroot: string | undefined;\nlet dtapStage: DTAPStage = \"production\";\n\n//if document is undefined, we're serverside or in a worker\nconst whconfigel = typeof document !== \"undefined\" ? document.querySelector('script#wh-config') : null;\nif (whconfigel?.textContent) {\n  const parsedConfig: WHConfigScriptData_FromServer & WHConfigScriptData_OldPublishFields = JSON.parse(whconfigel.textContent);\n  config = omit(parsedConfig, [\"siteroot\", \"dtapstage\", \"islive\"]);\n\n  //Fallbacks for pages last published with WH5.3 *and* pages published from HareScript which still emit lowercase props\n  siteroot = parsedConfig.siteRoot ?? parsedConfig.siteroot!;\n  dtapStage = parsedConfig.dtapStage ?? parsedConfig.dtapstage;\n}\n\ninitEnv(dtapStage, '/');\n\nif (typeof location !== \"undefined\")\n  for (const flag of getBrowserDebugFlags('wh-debug'))\n    debugFlags[flag] = true;\n\n\n/** @deprecated frontendConfig has been deprecated. Switch to the getFrontendData system */\n// Make sure we have obj/site as some sort of object, to prevent crashes on naive 'if ($wh.config.obj.x)' tests'\nexport const frontendConfig: WHConfigScriptData & {\n  /** @deprecated Use `getLang().tag` in WH6.0+ & WH5.9.7 */\n  locale?: string;\n} = {\n  ...config,\n  obj: config?.obj || {},\n  site: config?.site || {},\n  siteRoot: siteroot || \"\",\n  dtapstage: dtapStage,\n  islive: dtapStage === \"production\" || dtapStage === \"acceptance\",\n  siteroot: siteroot || \"\",\n  ...typeof document !== \"undefined\" ? { locale: getLang().tag } : {},\n} as WHConfigScriptData & WHConfigScriptData_LegacyFields;\n\n// this is what we actually store in the config object but is type-unsafe to access. Plugins still store data in the config object\nexport type WHConfigSerializedData = WHConfigScriptData & WHConfigScriptData_LegacyFields & { [key in keyof FrontendDataTypes]?: FrontendDataTypes[key] };\n\nif (dtapStage === \"development\") { //WH6.0: it's time to hard phase-out the old fields\n  Object.defineProperties(frontendConfig, {\n    islive: { get() { throw new Error(\"frontendConfig.islive will be removed - replace with testing 'dtapStage' for production | acceptance (WH5.4+)\"); } },\n    dtapstage: { get() { throw new Error(\"frontendConfig.dtapstage will be removed - replace with 'dtapStage' (WH5.4+)\"); } },\n    siteroot: { get() { throw new Error(\"frontendConfig.siteroot will be removed - replace with 'getSiteRoot()' (WH5.7+)\"); } },\n    //TODO but only WH6 addded this property AND getLang so there's no phasing out yet.\n    //locale: { get() { throw new Error(\"frontendConfig.locale will be removed - replace with getLang().tag in WH6.0+ & WH5.9.7\"); } },\n  });\n}\n\n//NOTE: These APIs need to live in init.ts so eg gtm.ts can access us without triggering a CSS reset through frontend.ts. When frontend.ts stops auto-resetting we might move it back\n\nexport function getFrontendData<Type extends keyof FrontendDataTypes>(type: Type, options: { allowMissing: true }): FrontendDataTypes[Type] | null;\nexport function getFrontendData<Type extends keyof FrontendDataTypes>(type: Type, options?: { allowMissing: boolean }): FrontendDataTypes[Type];\n\n/** Get data exported by the response\n * @typeParam Type - The type of data to get\n * @param dataObject - The data object of data to get\n * @param allowMissing - If true, return null if the data object is missing. Otherwise throw an error\n * @example\n```\n  declare module \"@webhare/frontend\" {\n    interface FrontendDataTypes {\n      \"mymodule:type\": {\n        test: number;\n      };\n    }\n  }\n\n  const data = getFrontendData(\"mymodule:type\");\n```\n*/\nexport function getFrontendData<Type extends keyof FrontendDataTypes>(dataObject: Type, { allowMissing = false } = {}): FrontendDataTypes[Type] | null {\n  const retval = (config as undefined | WHConfigSerializedData)?.[dataObject] as FrontendDataTypes[Type];\n  if (!retval)\n    if (allowMissing)\n      return null;\n    else\n      throw new Error(`Missing frontend data object: ${dataObject}`);\n\n  return retval;\n}\n\n/** Get the current site root\n *\n * @returns The site root URL (ending with a slash)\n*/\nexport function getSiteRoot(): string { //now an API to improve treeshaking\n  return siteroot ?? throwError(\"Site root is undefined. HTML code may be broken\");\n}\n","\n//Note that @webhare/env does not invoke this API itself. In WebHare @webhare/frontend/src/init uses this to initialize\nexport function getBrowserDebugFlags(varname: string): string[] {\n  const flags = [];\n  const urldebugvar = new URL(location.href).searchParams.get(varname);\n  if (urldebugvar)\n    flags.push(...urldebugvar.split(','));\n\n  //not importing getCookie to solve some import ordering issues\n  if (typeof document !== \"undefined\") { //'document' is undefined in a worker but assetpacks compiled for a ServiceWorker will also load us\n    const debugcookie = document.cookie.match(`(?:^|;)\\\\s*${varname}=([^;]*)`); //TODO escape varname\n    if (debugcookie) {\n      const debugcookievalue = decodeURIComponent(debugcookie[1]);\n      if (debugcookievalue)\n        flags.push(... (debugcookievalue.split('.').filter(flag => !flag.startsWith('sig='))));\n    }\n  }\n\n  if (typeof sessionStorage !== \"undefined\") {\n    const sessionDebug = sessionStorage.getItem(varname);\n    if (sessionDebug)\n      flags.push(...sessionDebug.split(','));\n  }\n\n  return flags;\n}\n","import \"@webhare/tsrun/src/polyfills\";\nimport \"./iterator-helpers\";\nimport \"./publisher-integration\";\n","/* eslint-disable @typescript-eslint/no-loop-func */\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/* eslint-disable @typescript-eslint/no-this-alias */\n\n/* Iterator polyfills (https://caniuse.com/?search=iterator) - stage 4 ES but not in all browsers yet\n   Based on https://github.com/alkihis/iterator-polyfill/tree/master but we removed all the AsyncIterator\n   stuff as that's still stage 2 AND not implemented in TypeScript (as of 5.6)\n\n   We're ignoring a few linting/any issues as we really don't care to maintain this much\n   Fixed an issue with .some - reported as https://github.com/alkihis/iterator-polyfill/issues/6\n*/\n\n(function () {\n  // polyfill already applied / proposal implemented\n  if ('Iterator' in globalThis) {\n    return;\n  }\n\n  // Polyfill for Iterator\n  const IteratorPrototype = {};\n\n  const ArrayIteratorPrototype = Object.getPrototypeOf([][Symbol.iterator]());\n  const OriginalIteratorPrototype = Object.getPrototypeOf(ArrayIteratorPrototype);\n\n  Object.setPrototypeOf(OriginalIteratorPrototype, IteratorPrototype);\n\n  Object.defineProperties(IteratorPrototype, {\n    [Symbol.iterator]: {\n      value() {\n        return this;\n      }\n    },\n    map: {\n      *value<T, R>(callback: (value: T) => R): Generator<any, any, any> {\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = callback(value.value);\n          const next_value = yield real_value;\n          value = it.next(next_value);\n        }\n\n        return value.value;\n      },\n    },\n    filter: {\n      *value<T>(callback: (value: T) => boolean): Generator<any, any, any> {\n        const it = this;\n        let value = it.next();\n        let next_value;\n\n        while (!value.done) {\n          const real_value = value.value;\n          if (callback(real_value)) {\n            next_value = yield real_value;\n            value = it.next(next_value);\n          } else {\n            value = it.next(next_value);\n          }\n        }\n\n        return value.value;\n      },\n    },\n    find: {\n      value<T>(callback: (value: boolean) => T) {\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (callback(real_value))\n            return real_value;\n\n          value = it.next();\n        }\n      }\n    },\n    every: {\n      value<T>(callback: (value: T) => boolean) {\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (!callback(real_value))\n            return false;\n\n          value = it.next();\n        }\n\n        return true;\n      }\n    },\n    some: {\n      value<T>(callback: (value: T) => boolean) {\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (callback(real_value)) {\n            it.return();\n            return true;\n          }\n\n          value = it.next();\n        }\n\n        return false;\n      }\n    },\n    toArray: {\n      value(max_count = Infinity) {\n        const values = [];\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (max_count <= 0)\n            return values;\n\n          values.push(real_value);\n\n          if (max_count !== Infinity)\n            max_count--;\n\n          value = it.next();\n        }\n\n        return values;\n      }\n    },\n    take: {\n      *value(limit: number): Generator<any, any, any> {\n        limit = Number(limit);\n        if (limit < 0)\n          throw new RangeError('Invalid limit.');\n\n        const it = this;\n        let value = it.next();\n        let remaining = limit;\n        let next_value;\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (remaining <= 0)\n            return;\n\n          next_value = yield real_value;\n          value = it.next(next_value);\n          remaining--;\n        }\n\n        return value.value;\n      },\n    },\n    drop: {\n      *value(limit: number): Generator<any, any, any> {\n        limit = Number(limit);\n        if (limit < 0)\n          throw new RangeError('Invalid limit.');\n\n        const it = this;\n        let value = it.next();\n        let remaining = limit;\n        let next_value;\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (remaining > 0) {\n            value = it.next(next_value);\n            remaining--;\n            continue;\n          }\n\n          next_value = yield real_value;\n          value = it.next(next_value);\n        }\n\n        return value.value;\n      },\n    },\n    asIndexedPairs: {\n      *value(): Generator<any, any, any> {\n        const it = this;\n        let value = it.next();\n        let index = 0;\n\n        while (!value.done) {\n          const real_value = value.value;\n          const next_value = yield [index, real_value];\n          value = it.next(next_value);\n          index++;\n        }\n\n        return value.value;\n      }\n    },\n    flatMap: {\n      *value<T, R extends object>(mapper: (value: T) => IterableIterator<R> | R): Generator<any, any, any> {\n        if (typeof mapper !== 'function') {\n          throw new TypeError('Mapper must be a function.');\n        }\n\n        const it = this;\n        let value = it.next();\n        let next_value;\n\n        while (!value.done) {\n          const real_value = value.value;\n          const mapped = mapper(real_value);\n\n          if (Symbol.iterator in mapped) {\n            next_value = yield* mapped[Symbol.iterator]();\n          } else {\n            next_value = yield mapped;\n          }\n\n          value = it.next(next_value);\n        }\n\n        return value.value;\n      },\n    },\n    reduce: {\n      value<T, V>(reducer: (acc: V, value: T) => V, initial_value?: V) {\n        let acc = initial_value;\n\n        const it = this;\n        if (acc === undefined) {\n          acc = it.next().value;\n        }\n\n        let value = it.next();\n        while (!value.done) {\n          const real_value = value.value;\n\n          acc = reducer(acc!, real_value);\n\n          value = it.next();\n        }\n\n        return acc;\n      }\n    },\n    forEach: {\n      value<T>(callback: (value: T) => any) {\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          callback(real_value);\n\n          value = it.next();\n        }\n      }\n    },\n    [Symbol.toStringTag]: {\n      value: 'IteratorPrototype'\n    },\n\n    /* OUTSIDE PROPOSAL */\n    count: {\n      value() {\n        let count = 0;\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          count++;\n          value = it.next();\n        }\n\n        return count;\n      },\n    },\n    join: {\n      value(string: string) {\n        let final = '';\n        let first = true;\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (first) {\n            first = false;\n            final += real_value;\n          } else {\n            final += string + real_value;\n          }\n\n          value = it.next();\n        }\n\n        return final;\n      }\n    },\n    chain: {\n      *value<I>(...iterables: IterableIterator<I>[]) {\n        yield* this;\n\n        for (const it of iterables) {\n          yield* it;\n        }\n      }\n    },\n    zip: {\n      *value<T, O>(...others: IterableIterator<O>[]): Iterator<(T | O)[]> {\n        const it_array = [this, ...others].map((e: any) => Symbol.iterator in e ? e[Symbol.iterator]() : e as Iterator<T | O>);\n        let values = it_array.map(e => e.next());\n        let next_value: any;\n\n        while (values.every(e => !e.done)) {\n          next_value = yield values.map(e => e.value);\n          values = it_array.map(e => e.next(next_value));\n        }\n      },\n    },\n    takeWhile: {\n      *value<T>(callback: (value: T) => boolean): Generator<any, any, any> {\n        const it = this;\n        let value = it.next();\n        let next_value;\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (callback(real_value))\n            next_value = yield real_value;\n          else\n            return;\n\n          value = it.next(next_value);\n        }\n\n        return value.value;\n      }\n    },\n    dropWhile: {\n      *value<T>(callback: (value: T) => boolean): Generator<any, any, any> {\n        const it = this;\n        let value = it.next();\n        let next_value;\n        let finished = false;\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (!finished && callback(real_value)) {\n            value = it.next(next_value);\n            continue;\n          }\n\n          finished = true;\n          next_value = yield real_value;\n\n          value = it.next(next_value);\n        }\n\n        return value.value;\n      }\n    },\n    fuse: {\n      *value(): Generator<any, any, any> {\n        const it = this;\n        let value = it.next();\n        let next_value;\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (real_value !== undefined && real_value !== null)\n            next_value = yield real_value;\n          else\n            return;\n\n          value = it.next(next_value);\n        }\n\n        return value.value;\n      }\n    },\n    partition: {\n      value<T>(callback: (value: T) => boolean) {\n        const partition1 = [], partition2 = [];\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (callback(real_value))\n            partition1.push(real_value);\n          else\n            partition2.push(real_value);\n\n          value = it.next();\n        }\n\n        return [partition1, partition2];\n      },\n    },\n    findIndex: {\n      value<T>(callback: (value: T) => boolean) {\n        const it = this;\n        let i = 0;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (callback(real_value))\n            return i;\n\n          value = it.next();\n          i++;\n        }\n\n        return -1;\n      }\n    },\n    max: {\n      value() {\n        let max = -Infinity;\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (max < real_value)\n            max = real_value;\n\n          value = it.next();\n        }\n\n        return max;\n      },\n    },\n    min: {\n      value() {\n        let min = Infinity;\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n\n          if (min > real_value)\n            min = real_value;\n\n          value = it.next();\n        }\n\n        return min;\n      },\n    },\n    cycle: {\n      *value(): Generator<any, any, any> {\n        const values = [];\n\n        const it = this;\n        let value = it.next();\n\n        while (!value.done) {\n          const real_value = value.value;\n          values.push(real_value);\n\n          const next_value = yield real_value;\n          value = it.next(next_value);\n        }\n\n        while (true) {\n          yield* values;\n        }\n      },\n    },\n  });\n\n  //iterator.from from https://github.com/rauschma/iterator-helpers-polyfill/\n\n  function isObject(value: unknown) {\n    if (value === null) return false;\n    const t = typeof value;\n    return t === 'object' || t === 'function';\n  }\n\n  function GetIteratorFlattenable<T>(obj: Record<symbol, any>): T {\n    if (!isObject(obj)) {\n      throw new TypeError();\n    }\n    const method = obj[Symbol.iterator];\n    let iterator = undefined;\n    if (typeof method !== 'function') {\n      iterator = obj;\n    } else {\n      iterator = method.call(obj);\n    }\n    if (!isObject(iterator)) {\n      throw new TypeError();\n    }\n    return iterator;\n  }\n\n  if (!('Iterator' in globalThis)) {\n    const Iterator = function Iterator() { };\n\n    Iterator.prototype = IteratorPrototype;\n\n    // @ts-expect-error We're still missing From in this poyfill\n    (globalThis).Iterator = Iterator;\n  }\n\n\n  //----- Static method -----\n  // Must be done after Iterator.prototype was set up,\n  // so that `extends Iterator` works below\n\n  class WrappedIterator<T, TReturn = any, TNext = undefined> extends Iterator<T, TReturn, TNext> {\n    #iterator;\n    constructor(iterator: Iterator<T, TReturn, TNext>) {\n      super();\n      this.#iterator = iterator;\n    }\n    override next(...args: [] | [TNext]): any {\n      return this.#iterator.next(...args);\n    }\n    // `async` helps with line (*)\n    override return(value?: TReturn | PromiseLike<TReturn>): any {\n      const returnMethod = this.#iterator.return;\n      if (returnMethod === undefined) {\n        return { done: true, value: value as any }; // (*)\n      }\n      return returnMethod.call(this.#iterator);\n    }\n  }\n\n  function Iterator_from<T>(value: any) {\n    const iterator = GetIteratorFlattenable<Iterator<T>>(value);\n    if (iterator instanceof Iterator) {\n      return iterator;\n    }\n    // `iterator´ does not support the new API – wrap it so that it does\n    return new WrappedIterator(iterator);\n  }\n\n  Object.defineProperty(\n    Iterator, 'from',\n    {\n      writable: true,\n      enumerable: false,\n      configurable: true,\n      value: Iterator_from,\n    }\n  );\n})();\n","import { isHTMLElement } from \"@webhare/dompack\";\nimport type { CMSConfig } from \"@mod-system/js/internal/generation/gen_misc_ts\";\n\nlet config: CMSConfig | undefined;\n\nfunction forwardPublisherNavigation(event: Event) {\n  /* we watch for clicks.. as we only want to update the Publisher's selection for user triggered actions (otherwise we'd\n     start navigation in response to JS or internal link autoredirects) */\n  if (!isHTMLElement(event.target) || !config?.interfaceServers)\n    return;\n\n  const navaction = event.target.closest<HTMLAnchorElement>('a[href]');\n  if (!navaction)\n    return;\n\n  const desturl = navaction.href;\n  if (desturl.split('#')[0] !== location.href.split('#')[0]) { //it's actual navigation...\n    for (const origin of config.interfaceServers)\n      if (origin.startsWith(document.referrer || ''))\n        try {\n          window.top?.postMessage({ type: \"webhare-navigation\", location: desturl }, origin);\n        } catch (ignore) {\n          //ignore crossdomain errors\n        }\n  }\n}\n\nasync function configureForCMS() {\n  try {\n    const res = await fetch(\"/.wh/ea/config/cms.json\");\n    config = await res.json();\n  } catch (e) {\n    console.log(\"Failed to get CMS configuration\", e);\n    return;\n  }\n  window.addEventListener(\"click\", forwardPublisherNavigation);\n}\n\nif (typeof window !== \"undefined\" && window !== window.top) { //if we're in an iframe, we may be running in WebHare and need to forward navigation events\n  //we have no way to detect whether we're in a WebHare iframe or a 3rd party iframe. assume it's webhare and grab the interface servers\n  void configureForCMS();\n}\n","/*\nwebdesigns/ws2026/ws2026-site (this file) is the entrypoint for\n- the \"WS2026\" (UT / Webdesign2026)\n\n- Stuff here is NOT shared with the \"apdesign\" (UT AlumniPortal) webdesign.\n*/\n\nimport * as dompack from \"@webhare/dompack\";\nimport \"@webhare/dompack/reset.css\";\nimport \"@mod-publisher/js/analytics/gtm\"; // Load as early as possible\n\nimport * as searchSheet from \"@mod-utwente_base/webdesigns/ws2016/src/shared/searchsheet\";\n\nimport \"@mod-utwente_design/scss/config-colors.css\";\nimport { initTheme } from \"@mod-utwente_design/theme/theme.tsx\";\nimport \"@mod-utwente_design/web/utdesign/fonts/ut-iconfont.css\";\nimport \"@mod-utwente_design/web/utdesign/fonts/ut-iconfont-48px.css\";\nimport \"@mod-utwente_design/vendor/perfect-scrollbar-wh/css/perfect-scrollbar.css\"; // Basic styling for the custom scrollbar\n\nimport \"@mod-utwente_base/webdesigns/ws2016/src/site.lang.json\";\n\nimport \"@mod-utwente_base/webdesigns/ws2016/src/shared/summary.scss\"; // lists with lines (such as contentlistings, news summaries)\nimport \"@mod-utwente_base/webdesigns/ws2016/src/shared/summary-overrides.scss\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/shared/addthisevent/\";\n\nimport \"./ws2026.ts\";\nimport \"./ws2026.css\";\nimport \"./frontend.lang.json\";\nimport \"./header/header.tsx\";\nimport \"./footer/footer.tsx\";\nimport \"./shared/psa-chatbot.tsx\";\nimport \"./shared/buttons.css\";\nimport \"./shared/overflow-placeholder.tsx\";\nimport \"./shared/forms/forms.tsx\";\nimport \"./contentheader/contentheader.tsx\";\nimport \"./notificationbar/notificationbar.tsx\";\nimport { initDeeplinksNav } from \"./shared/deeplinks\";\nimport { combineFloatParagraphs } from \"./shared/layout-tools\";\n\nimport \"@mod-utwente_base/webdesigns/ws2026/shared/osiris/osiris\";\n\n//Widgets\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/widgets\";\n\n// ws2021 foldable content blocks (accordeons) fixes (not yet ported)\nimport '@mod-utwente_base/webfeatures/ws2021/main/';\n\n//pages\nimport \"@mod-utwente_base/webdesigns/ws2016/src/pages/medical/index.ts\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/pages/login/index.ts\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/pages/meetings\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/pages/neoform\";\nimport \"@mod-utwente_base/webdesigns/ws2026/pages/filteredfolder/filteredfolder\";\nimport \"@mod-utwente_base/webdesigns/ws2026/pages/newsevents/newsevents\";\nimport \"@mod-utwente_base/webdesigns/ws2026/pages/people/people\";\nimport \"@mod-utwente_base/webdesigns/ws2026/pages/tablewithfilter/tablewithfilter\";\nimport \"@mod-utwente_base/webdesigns/ws2026/pages/timeline/timeline\";\nimport \"@mod-utwente_base/webdesigns/ws2026/pages/ufonds-donaties/index.ts\";\n\n//Components\nimport { setupAutoPageFilter } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters.tsx\";\n\nimport { dtapStage } from \"@webhare/env\";\nimport { setupAuthorMode } from \"@webhare/frontend\";\nimport { catchServicePortalLoginLink, handleUTGLobalLogin, utSilentLogin } from \"@mod-utwente_base/js/frontendauth.ts\";\nimport { getLocal } from \"@webhare/dompack\";\n\n//FIXME: move/port to ws2026?\nimport { requestGeoIP } from \"@mod-utwente_base/webdesigns/ws2016/src/shared/crm\";\nimport { setupCoBrowserChat } from \"../ws2016/src/cobrowserchat/index.ts\";\n\n/** Are we the TOP level homepage? ie the toplevel equivalent of 'www.utwente.nl' eg 'www.utwente.nl/en/'\n * @param lang - If set, only return true if the page is in the specified language\n*/\n\nfunction isTopLevelHomepage(lang?: \"nl\" | \"en\") {\n  if (!document.documentElement.classList.contains(\"page--toplevelhome\"))\n    return false;\n  return !lang || document.documentElement.lang.startsWith(lang);\n}\n\ndompack.onDomReady(() => {\n  // To ensure allowing multiple paragraphs to flow around an floating image we\n  // need to combine these paragraphs. Otherwise a new paragraph won't wrap around the float\n  // due to our richtext nodes being part of a grid.\n  combineFloatParagraphs();\n\n  if (!document.documentElement.dataset.nodeeplinks)\n    initDeeplinksNav();\n});\n\nif (!handleUTGLobalLogin()) {\n  //not redirecting. check if its a hit for utwente.nl/, NL was not explicitly selected and this is a not a NL/BE user - then we direct to utwente.nl/en/\n  if (getLocal<string>(\"utwente-lastselectedlanguage\") !== \"nl\" && isTopLevelHomepage(\"nl\")) {\n    requestGeoIP().then(country => {\n      if (country !== \"NL\" && country !== \"BE\")\n        location.href = location.pathname + \"en/\";\n    }).catch(() => { });\n  }\n}\n\n//Setup filters if use on this page\nsetupAutoPageFilter();\n\ninitTheme();\n\nif (dtapStage === \"development\")\n  setupAuthorMode({ allowFeedback: false, orientation: \"left\" });\n\ndocument.addEventListener(\"ws2026:togglesearch\", (event) => {\n  searchSheet.toggle();\n  if (event.detail.q)\n    searchSheet.doSearch(event.detail.q, undefined);\n});\n\ndompack.register(\".scroll-indicator\", node => {\n  let showIndicator = true;\n  // Show the indicator after 5 seconds, if not yet scrolled\n  setTimeout(() => node.classList.toggle(\"show\", showIndicator), 5000);\n  // Hide the scroll indicator when scrolling/swiping down\n  const scrollHandler = () => {\n    if (window.scrollY > 0) {\n      showIndicator = false;\n      node.classList.remove(\"show\");\n      window.removeEventListener(\"wheel\", scrollHandler);\n      window.removeEventListener(\"touchmove\", scrollHandler);\n    }\n  };\n  window.addEventListener(\"wheel\", scrollHandler);\n  window.addEventListener(\"touchmove\", scrollHandler);\n});\n\ncatchServicePortalLoginLink();\n\n// UT Debug API\nObject.assign(window, {\n  utSilentLogin\n});\n\nsetupCoBrowserChat();\n","import { qSA } from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport type { FormAnalyticsEvent } from \"@webhare/forms\";\nimport type { DataLayerEntry } from \"./gtm-types\";\nimport { omit } from \"@webhare/std\";\n\ndeclare global {\n  interface Window {\n    /** The google tag manager (GTM) datalayer */\n    dataLayer: DataLayerEntry[]; //technically window.dataLayer may not exist and should be optional, but we already used to declare it as existing from gtm.ts\n  }\n  //It's safer to access dataLayer through globalThis, which will always be available in all environments unlike 'window'\n  var dataLayer: DataLayerEntry[] | undefined;\n}\n\n//ADDME if we ever figure out a bundler trick to flush this command to the top of all imports/loads, that would be great (we could consider *ALWAYS* putting this in the generated startup code, or we'd need to do a tree pre-walk to see if gtm.es is loaded anywhere)\n(globalThis as unknown as Window).dataLayer ||= [];\nlet lastSeen: DataLayerEntry | undefined;\n\nfunction showDataLayerUpdates() {\n  if (!globalThis.dataLayer)\n    return; //not set up (yet?)\n\n  if (debugFlags.anl)\n    globalThis.dataLayer.slice(globalThis.dataLayer.indexOf(lastSeen!) + 1).forEach(entry => console.log(\"[anl] dataLayer.push:\", entry));\n\n  lastSeen = globalThis.dataLayer[globalThis.dataLayer.length - 1];\n}\n\n/** Push to the dataLayer\n * @param vars - The variables to push\n * @param options - Options for the push\n *   timeout Time before any eventCallback is forcibly called (default 200ms)\n*/\nexport function pushToDataLayer(vars: DataLayerEntry, options?: { timeout?: number }) {\n  if (vars.eventCallback) { //we'll wrap the callback into a promise to ensure it's only invoked once\n    const savecallback = vars.eventCallback;\n    let newcallback: () => void;\n    void (new Promise<void>(resolve => newcallback = resolve)).then(() => savecallback());\n    setTimeout(() => newcallback, options?.timeout || 200);\n  }\n\n  globalThis.dataLayer?.push(vars);\n  showDataLayerUpdates();\n}\n\nfunction collectFormValues(formnode: HTMLFormElement): Record<string, unknown> {\n  const donefields: Record<string, boolean> = {};\n  const outdata: Record<string, unknown> = {};\n\n  const multifields = qSA<HTMLInputElement>(formnode, 'input[type=radio], input[type=checkbox]');\n  for (const multifield of multifields) {\n    if (!multifield.name || donefields[multifield.name])\n      continue; //we did this one\n\n    donefields[multifield.name] = true;\n\n    let idx = 0;\n    const values = [];\n    const labels = [];\n    const checkboxes = multifields.filter(node => node.name === multifield.name);\n\n    for (const node of checkboxes.filter(cbox => cbox.checked)) {\n      const keyname = 'form_' + multifield.name + (idx ? '_' + idx : '');\n      let labelsfornode = node.dataset.gtmTag || qSA(`label[for=\"${CSS.escape(node.id)}\"]`).map(labelnode => labelnode.textContent).filter(labelnode => Boolean(labelnode)).join(' ');\n      labelsfornode = labelsfornode.trim(); //TODO normalize whitespace\n      outdata[keyname] = node.value;\n      outdata[keyname + '_label'] = labelsfornode;\n\n      ++idx;\n      values.push(node.value);\n      labels.push(labelsfornode);\n    }\n\n    if (values.length) {\n      const allkeyname = 'form_' + multifield.name + '_all';\n      outdata[allkeyname] = values.join(';');\n      outdata[allkeyname + '_label'] = labels.join(';');\n    }\n  }\n\n  for (const field of formnode.querySelectorAll<HTMLSelectElement | HTMLInputElement>('input:not([type=radio]):not([type=checkbox]),select,textarea')) {\n    if (!field.name || donefields[field.name])\n      continue;\n\n    donefields[field.name] = true;\n\n    const val = field.value;\n    outdata['form_' + field.name] = val;\n    if (field.matches('select')) {\n      const opt = (field as HTMLSelectElement).options[(field as HTMLSelectElement).selectedIndex];\n      if (opt)\n        outdata['form_' + field.name + '_label'] = opt.dataset.gtmTag || opt.textContent;\n    }\n  }\n  return outdata;\n}\n\n/** Setup the dataLayer */\nlet didinit: boolean | undefined;\nexport function setupGTM() {\n  if (!didinit) {\n    didinit = true;\n    if (debugFlags.anl)\n      setInterval(showDataLayerUpdates, 100);\n  }\n}\n\n/** Setup dataLayer events for form analytics events\n * @param options - Options for the form analytics setup\n     - `eventPrefix`. Prefix to use. Default is `wh-platform:form_` but existing integrations may (also) require `publisher:form`\n*/\nexport function setupFormAnalyticsForGTM(options?: { eventPrefix: string }): void {\n  setupGTM(); //ensurse the GTM basics are installed\n\n  addEventListener(\"wh:form-analytics\", (e: FormAnalyticsEvent) => {\n    //we use the same prefixing as pxl events would\n    const entry: DataLayerEntry = {\n      event: `${options?.eventPrefix || \"platform:form_\"}${e.detail.event}`\n    };\n\n    for (const [key, val] of Object.entries(e.detail))\n      if (key !== \"event\" && [\"string\", \"number\", \"boolean\"].includes(typeof val))\n        entry[`formmeta_${key}`] = val;\n\n    const form = e.target as HTMLFormElement | undefined;\n    if (form?.dataset.gtmSubmit) {\n      //When set, we push both the form: variable in gtmSubmit and the current form field avlues\n      Object.assign(entry, JSON.parse(form.dataset.gtmSubmit));\n      Object.assign(entry, collectFormValues(form));\n    }\n\n    pushToDataLayer(entry);\n  });\n}\n\nfunction processClickDataLayerTags(event: MouseEvent) {\n  const entry: Record<string, unknown> = {};\n\n  for (let node = event.target as HTMLElement | undefined | null; node; node = node?.parentElement)\n    for (const attr of node.attributes)\n      if (attr.nodeName.startsWith(\"data-wh-datalayer-onclick-\")) {\n        const key = attr.nodeName.substring(26);\n        if (key !== \"__proto__\" && !(key in entry)) //as we're working upwards, don't overwrite already set keys\n          entry[key] = attr.nodeValue || \"\";\n      } else if (attr.nodeName === \"data-wh-datalayer-onclick\") { //JSON setter\n        const data = JSON.parse(attr.nodeValue!);\n        for (const [key, value] of Object.entries(data))\n          if (key !== \"__proto__\" && !(key in entry)) //as we're working upwards, don't overwrite already set keys\n            entry[key] = value;\n      }\n\n  if (Object.keys(entry).length)\n    pushToDataLayer(entry as DataLayerEntry);\n}\n\n/** Setup support for data-wh-datalayer-onclick-xxx=\"yyy\" attributes. When clicking an element with these attributes the JSON from the attribute and all parents are merged together and pushed to the dataLayer  */\nexport function setupDataLayerTags() {\n  //we capture so we can also simply set variables for any existing GTM handlers\n  window.addEventListener(\"click\", processClickDataLayerTags, { capture: true });\n}\n\n/** Get the current variables in the GTM datalayer\n * @param win - The window to get the dataLayer from (default: current window)\n * @return The current variables in the GTM datalayer, merged together from all entries. Note that this is a snapshot and won't update as the dataLayer changes\n*/\nexport function getCurrentDataLayerVariables<DataLayerFormat extends object = Record<string, unknown>>(win: Window = window): DataLayerFormat {\n  const state: DataLayerFormat = {} as DataLayerFormat;\n  if (win.dataLayer)\n    win.dataLayer.forEach(entry =>\n      Object.assign(state, structuredClone(omit(entry, [\"event\", \"eventCallback\", \"gtm.uniqueEventId\"]))));\n  return state;\n}\n","/* import '@mod-publisher/js/analytics/gtm';\n   enables ?wh-debug=anl support for GTM calls and implements non-script integration methods */\nimport { pushToDataLayer, setupGTM } from \"@webhare/frontend/src/gtm\";\nimport type { DataLayerEntry } from \"@webhare/frontend/src/gtm-types\";\nimport * as dompack from '@webhare/dompack';\nimport { loadScript } from '@webhare/dompack';\nimport { onConsentChange, type ConsentSettings } from \"./consenthandler\";\n\n//NOTE: Do *NOT* load @webhare/frontend or we enforce the new CSS reset!\nimport { getFrontendData } from '@webhare/frontend/src/init';\n\ndeclare global {\n  interface Window {\n    __gtmformsubmit: undefined | 1; //used by dev module for a sanity check\n  }\n}\n\nconst gtmsettings = getFrontendData(\"socialite:gtm\", { allowMissing: true });\nlet didinit: undefined | true;\n\n/* Send variables to the data layer */\nexport function setVariables(vars: DataLayerEntry & { event?: never }) {\n  if (vars.event)\n    throw new Error(\"An 'event' is not a a variable. use sendEvent for events\");\n  pushToDataLayer(vars);\n}\n\n/** Send an event to the data layer. Returns a promise that will resolve when the event is sent, or after a timeout of 200ms\n * @param event - The event name to send. If null, doesn't actually set an event but just sets the variables\n * @param vars - The variables to send with the event\n * @returns A promise that resolves when the event is sent or after a timeout of 200ms\n*/\nexport function sendEvent(event: string | null, vars: DataLayerEntry & { event?: never } = {}) {\n  const defer = Promise.withResolvers();\n  try {\n    if (event)\n      pushToDataLayer({ event: event, eventCallback: () => defer.resolve(false), ...vars });\n    else\n      pushToDataLayer(vars);\n  } catch (e) {\n  }\n  window.setTimeout(() => defer.resolve(true), event ? 200 : 0);\n  return defer.promise;\n}\n\nfunction processGTMPluginInstruction(node: HTMLElement) {\n  const topush = node.getAttribute(\"push\");\n  if (topush)\n    window.dataLayer.push(...JSON.parse(topush));\n}\n\nexport async function init() {\n  if (didinit || !gtmsettings) //even though we check for gtmsettings being available before init(), we may be invoked externally by manual launchers\n    return false;\n\n  didinit = true;\n  window.dataLayer.push({ 'gtm.start': Date.now() });\n\n  //give other event handlers a chance to run and add their events - many GTM users expect all variables to be available when their script starts\n  await new Promise(resolve => window.setTimeout(resolve, 1));\n  window.dataLayer.push({ event: 'gtm.js' });\n\n  await loadScript(\"https://www.googletagmanager.com/gtm.js?id=\" + encodeURIComponent(gtmsettings.a));\n}\n\nexport function initOnConsent() {\n  if (!(gtmsettings && gtmsettings.a && gtmsettings.m))\n    console.error(\"<gtm/> tag must be configured with launch=manual to support initOnConsent\");\n\n  onConsentChange((consentsettings: ConsentSettings) => {\n    const consentsetting = consentsettings.consent?.length ? consentsettings.consent.join(' ') : \"denied\";\n    window.dataLayer.push({ \"wh.consent\": consentsetting, \"event\": \"wh-consentchange\" });\n    void init();\n  });\n}\n\nexport function configureGTMFormSubmit(opts: { eventname: string }) {\n  //STUB to remove sometime after WH5.7 - this used to setup the wh-formevents behavior\n}\n\ndompack.register(\"wh-socialite-gtm\", processGTMPluginInstruction);\n\nif (gtmsettings?.a && !gtmsettings?.m) //account is set, manual is not set\n  void init();\n\nwindow.__gtmformsubmit = 1; //allow us to validate we're installed - ADDME compile only in dev mode\n\n//unconditionally invoked if you use the 'old' import\nsetupGTM();\n","import * as dompack from '@webhare/dompack';\nimport { navigateTo } from '@webhare/env';\nimport { debugFlags } from '@webhare/env/src/envbackend';\n\ndeclare global {\n  interface Window {\n    whResetConsent: () => void;\n  }\n  interface GlobalEventHandlersEventMap {\n    \"wh:consent-changed\": CustomEvent<ConsentSettings>;\n  }\n}\n\nexport interface SetupConsentOptions {\n  /** Domain to which to bind the cookie, can be at most one level higher (eg '.example.net' for 'www.example.net') */\n  cookiedomain?: string;\n  /** Duration to store or extend the consent, in days. Defaults to 365 */\n  cookieduration?: number;\n  /** The consent tags which are active by default (only use this for anonymous tracking and functional cookies) */\n  defaultconsent?: string[];\n}\n\ninterface ConsentStatus {\n  /** Version (2) */\n  v: 2;\n  //** Consent options */\n  c?: string[];\n  /** Last consent change (ISO8601 date) */\n  lc?: string;\n}\n\nlet consentstatus: ConsentStatus | null;\nlet cookiename: string | undefined;\nlet consentoptions: SetupConsentOptions | undefined;\n\nexport type ConsentSettings = {\n  isdefault: true;\n  consent: string[];\n} | {\n  isdefault: false;\n  consent: string[] | undefined; //we've explicitly defined no consent-yet-given as 'undefined' (TODO was this a good idea?)\n};\n\n/** Setup the consent handler\n    @param usecookiename - Name of the cookie. Should be identical for all sites sharing this consent, set to empty string if you store consent externally\n    @param consentrequester - Function to invoke if consent is unknown to eg trigger a cookie bar. This function will be immediately registered for invocation through dompack.onDomReady\n*/\nexport function setup(usecookiename: string, consentrequester?: () => void, options?: SetupConsentOptions) {\n  if (typeof usecookiename !== 'string')\n    throw new Error(\"Cookiename must be of type 'string'\");\n  if (debugFlags.cst)\n    console.log(`[cst] consenthandler initialized. cookiename: '${usecookiename}'`);\n\n  cookiename = usecookiename;\n  consentoptions = {\n    cookieduration: 365,\n    defaultconsent: [],\n    ...options\n  };\n\n  if (consentrequester)\n    try {\n      consentstatus = JSON.parse(dompack.getCookie(cookiename)!);\n      if (debugFlags.cst)\n        console.log(`[cst] initial consent state:`, consentstatus);\n    } catch (ignore) {\n    }\n\n  if (!consentstatus || typeof consentstatus !== \"object\" || consentstatus.v !== 2 || typeof consentstatus.c !== \"object\")\n    consentstatus = { v: 2 };\n\n  if (!(\"c\" in consentstatus)) { //simple consent flag\n    if (consentrequester)\n      dompack.onDomReady(consentrequester); //run the request function, but only on domready! it's a safe assumption it should be delayed...\n  } else {\n    storeConsent(); //renew the status\n  }\n  updateConsent();\n}\n\n//Test for consent\nexport function hasConsent(consentsetting: string) {\n  if (consentsetting === undefined) //generic consent check\n    throw new Error(\"hasConsent required a string argument\");\n\n  const details = getConsentDetail();\n  if (!details // setup() not called yet?\n    || !details.consent) // no consent has been given and no defaults are available consent will be undefined?\n    return undefined;\n\n  return details.consent.includes(consentsetting);\n}\n\n//Set simple consent\nexport function setConsent(newsetting: string[]) {\n  if (cookiename === undefined)\n    throw new Error(\"Invoke consenthandler.setup before modifying consent state!\");\n  if (typeof newsetting !== \"object\" || !Array.isArray(newsetting))\n    throw new Error(\"Expecting an array in call to setConsent\");\n\n  // Check if there are some consents being revoked\n  const details = getConsentDetail(); // get current list of consent tags, including implicit (default) consent\n  let consent_revoked = false;\n  if (details?.consent) { // if no explicit or default consent, the consent field is undefined\n    for (const tag of details.consent) {\n      if (!newsetting.includes(tag))\n        consent_revoked = true;\n    }\n  }\n\n  if (!consentstatus)\n    throw new Error(`Attempting to change consent status before invoking consenthandler.setup`);\n\n  consentstatus.c = newsetting.sort();//ensure stable order\n  consentstatus.lc = (new Date()).toISOString();\n\n  storeConsent();\n\n  // Revoked consent may need a reload to take effect.\n  // This is because it's not worth the effort for most websites to implement on-the-fly disabling\n  // of functionality. It might even be impossible if 3rd party scripts are already loaded.\n  if (consent_revoked) {\n    console.log(\"[cst] Reloading to handle revoked consent\");\n    navigateTo({ type: \"reload\" });\n  }\n\n  updateConsent();\n}\n\n/** Get a list of consents and whether they are defaults (or explicitly set)\n    @returns consent: list all consents\n            isdefault: if true then the consents are implicit/defaults (not consent explicitly given by the user)\n*/\nfunction getConsentDetail(): ConsentSettings | null {\n  if (!consentstatus) // setup() did not run yet\n    return null;\n\n  if (!(\"c\" in consentstatus)) { // consent not set yet\n    if (consentoptions?.defaultconsent && consentoptions?.defaultconsent.length > 0)\n      return { consent: consentoptions!.defaultconsent!, isdefault: true }; // use fallback consent\n    else\n      return { consent: undefined, isdefault: false }; // no consent given yet (expected to return undefined for consent)\n  }\n\n  return {\n    consent: consentstatus.c,\n    isdefault: false\n  };\n}\n\nexport function onConsent(type: string, callback: (cs: ConsentSettings) => void) {\n  window.addEventListener(\"wh:consent-changed\", evt => {\n    if (evt.detail.consent?.includes(type))\n      callback(evt.detail);\n  });\n\n  const details = getConsentDetail();\n\n  if (details && details.consent && details.consent.includes(type)) {//already missed it, so invoke\n    if (debugFlags.cst)\n      console.log(\"[anl] Invoking callback\", details);\n    callback(details);\n  }\n}\n\n//Register callback for content changes\nexport function onConsentChange(callback: (cs: ConsentSettings) => void): void {\n  window.addEventListener(\"wh:consent-changed\", evt => callback(evt.detail));\n\n  const details = getConsentDetail();\n\n  if (details) { //already missed it, so invoke\n    if (debugFlags.cst)\n      console.log(\"[cst] Invoking callback\", details);\n    callback(details);\n  }\n}\n\nfunction updateConsentOverlays() {\n  const overlays = dompack.qSA(\".wh-requireconsent__overlay\");\n  const consent = getConsentDetail()!.consent; //we are only scheduled when details are set (but we reread them as they may change)\n\n  if (debugFlags.cst)\n    console.log(`[cst] update ${overlays.length} consent overlay(s). ${consent ? `consent: ${consent.length ? consent.join(', ') : \"<none>\"}` : \"<undefined>\"}`);\n\n  overlays.forEach(overlay => {\n    const parent = overlay.closest<HTMLElement>(\".wh-requireconsent\");\n    if (parent && parent.dataset.whConsentRequired)\n      overlay.hidden = consent?.includes(parent.dataset.whConsentRequired) || false;\n  });\n}\n\nfunction updateConsent() { //update in DOM, GTM, etc\n  const details = getConsentDetail();\n\n  if (!details // setup() not called yet?\n    || !details.consent) { // no consent has been given and no defaults are available consent will be undefined?\n    document.documentElement.dataset.whConsent = \"unknown\"; // unknown - no explicit or explicit (options.defaultconsent) consent\n    return;\n  }\n\n  document.documentElement.dataset.whConsent = details.consent.length ? details.consent.join(\" \") : \"denied\";\n\n  if (debugFlags.cst)\n    console.log(\"[cst] Firing wh:consent-changed with\", details);\n\n  dompack.dispatchCustomEvent(window, \"wh:consent-changed\", { bubbles: false, cancelable: false, detail: details });\n  dompack.onDomReady(updateConsentOverlays);\n}\n\nfunction storeConsent() {\n  if (cookiename)\n    dompack.setCookie(cookiename, JSON.stringify(consentstatus), { duration: consentoptions!.cookieduration, domain: consentoptions!.cookiedomain });\n}\n\nwindow.whResetConsent = function () {\n  if (cookiename === undefined)\n    throw new Error(\"Consent handler not setup\");\n  else if (!cookiename)\n    throw new Error(\"Consent handler is not handling storage\");\n\n  dompack.deleteCookie(cookiename);\n  console.log(\"Reloading for whResetConsent\");\n  navigateTo({ type: \"reload\" });\n};\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport { JustifiedImageGrid } from \"@webhare/dompack-justifiedcontentgrid\";\nimport { getTid, getHTMLTid } from \"@webhare/gettid\";\nimport * as pxl from \"@mod-consilio/js/pxl\";\nimport PerfectScrollbar from \"@mod-utwente_design/vendor/perfect-scrollbar-wh\";\nimport searsia from \"@mod-utwente_base/web/pub/ws2016/searsia\";\nimport {\n  MIN_SUGGEST_LENGTH,\n  NUM_SUGGESTIONS,\n  NUM_RELATED,\n  SEARSIA_SOURCES,\n  SEARSIA_DUPLICATE_RESOURCES,\n  QUERY_STOPWORDS\n} from \"@mod-utwente_base/web/pub/ws2016/searsiaconfig\";\nimport * as managedctas from \"@mod-utwente_base/webdesigns/ws2016/src/shared/crm/managedctas\";\n\nimport * as crm from \"../crm\";\nimport setupShowAllLinks from \"../showalllinks\";\nimport SearsiaAutoSuggest from \"./searsiasuggest\";\nimport * as searsiaTypes from \"./searsiatypes\";\nimport { showSearsiaWidgets } from \"./searsiawidgets\";\n\nimport \"./searchsheet.scss\";\nimport '../fonts/ut-search-iconfont.css';\n\n\nconst resultScoreProp = Symbol(\"result-score\");\nconst resultLangProp = Symbol(\"result-lang\");\nconst resultSourceProp = Symbol(\"result-source\");\n\nlet searsiaClient: SearsiaClient | undefined;\nexport let defaultSearchType = \"all\";\n\n//ADDME: Certainly not the most optimized implementation...\nfunction isSubArray(master, sub) {\n  for (let i = 0; i < master.length; ++i) {\n    if (master[i] === sub[0]) {\n      let j;\n      for (j = 0; j < sub.length; ++j)\n        if (master[i + j] !== sub[j])\n          break;\n      if (j === sub.length) {\n        return true;\n      }\n    }\n  }\n  return false;\n}\n\nclass SearsiaClient {\n  inputNode: HTMLInputElement;\n  client: {\n    status: string;\n    resource: {\n      suggesttemplate: string;\n    };\n  };\n\n  constructor(public node: HTMLElement) {\n    this.inputNode = dompack.qR(node, \".searchsheet__searchfield\");\n    this.headerNode = node.querySelector(\".searchsheet__searchform\");\n    this.statusNode = node.querySelector(\".searchsheet__status\");\n    this.resultsNode = node.querySelector(\".searsia__results\");\n    this.suggestNode = node.querySelector(\".searchsheet__suggestions\");\n    this.ctaslots = [];\n\n    this.haveResults = false;\n    this.searsiaSession = \"\";\n\n    this.headerNode.addEventListener(\"transitionend\", event => this.onTransitioned(event));\n    this.inputNode.addEventListener(\"focus\", event => this.onInputFocus(event));\n    this.inputNode.addEventListener(\"blur\", event => this.onInputFocus(event));\n    this.inputNode.addEventListener(\"searsia:showsuggestions\", event => this.onShowSuggestions(event));\n    this.inputNode.addEventListener(\"searsia:hidesuggestions\", event => this.onHideSuggestions(event));\n    this.inputNode.addEventListener(\"searsia:searchsuggestion\", event => this.onStartSearch(event));\n    this.inputNode.form.addEventListener(\"submit\", event => this.onStartSearch(event));\n    this.statusNode.addEventListener(\"click\", event => this.onClickStatus(event));\n    this.resultsNode.addEventListener(\"click\", event => this.onClickResult(event));\n    node.addEventListener(\"keydown\", event => this.onKeyDown(event));\n\n    this.lang = (document.documentElement.lang || \"\").split(\"-\")[0];\n    this.stopwordfilters = (QUERY_STOPWORDS[this.lang] || []).map(_ => new RegExp(`((^|\\\\s+)${_}(\\\\s+|$))`, \"i\"));\n\n    // Collect user data for search CTA matching\n    this.userCountry = crm.getUserCountry();\n    if (!this.userCountry) {\n      if (debugFlags.umc)\n        console.log(`[umc] Requesting user country`);\n      void crm.requestGeoIP().then(country => {\n        this.userCountry = country;\n        console.log(`[umc] User country '${this.userCountry}'`);\n      });\n    } else if (debugFlags.umc)\n      console.log(`[umc] User country '${this.userCountry}'`);\n    this.userBeacons = crm.getUserBeacons();\n    if (debugFlags.umc)\n      console.log(`[umc] User beacons`, this.userBeacons);\n\n    this.url = new URL(location.href);\n\n    this.searchType = this.url.searchParams.get(\"t\");\n    this.tabWidgets = false;\n    this.tabNodes = [];\n    this.tabs = new Map();\n    const tabsNode = this.node.querySelector(\".searchsheet__tabs\");\n    new PerfectScrollbar(tabsNode, {\n      swipePropagation: true,\n      wheelPropagation: true,\n      suppressScrollY: true\n    });\n\n    //ADDME: Tab nodes are added dynamically throught the search configuration. Statically published files can contain tab\n    //       nodes if they haven't been published yet since the change to dynamically added tabs, so we'll just remove the\n    //       static tabs. This code can be removed after all files have been published once after this change.\n    for (const tabNode of this.node.querySelectorAll(\".searchsheet__tab\"))\n      tabNode.remove();\n\n    const q = this.url.searchParams.get(\"q\");\n    if (q && !document.documentElement.classList.contains(\"utwente--ws2026\")) {\n      this.doSearchFor(q);\n    } else if (document.documentElement.classList.contains(\"searchsheet--fixed\")) {\n      this.toggle(true);\n      this.reset();\n    }\n\n    //unload is deprecated and breaks B-F cache. I'm not sure the utwente_base:searsia_unload event actually matters though\n    window.addEventListener(\"pagehide\", event => this.onUnload(event));\n  }\n\n  async initSearsiaClient(t) {\n    if (t) {\n      defaultSearchType = t;\n      if (!this.searchType)\n        this.searchType = t;\n    }\n    if (!this.configPromise)\n      this.configPromise = this.fetchSearchConfig();\n    await this.configPromise;\n  }\n\n  async fetchSearchConfig() {\n    if (debugFlags.searsia)\n      console.log(\"[searsia] Fetching search configuration\");\n\n    const configlang = document.documentElement.lang.substring(0, 2);\n    const searchconfigurl = `/.st/utwente_base/searchsettings.${configlang}.json?` + Math.random(); //TODO if we want to CDN this, make more specific\n    const response = await fetch(searchconfigurl, { credentials: 'same-origin' });\n    if (response.status !== 200) {\n      if (debugFlags.searsia)\n        console.warn(\"[searsia] Did not receive search configuration\");\n      return;\n    }\n    const searchconfig = await response.json();\n\n    const apitemplate = localStorage.searsiaApiTemplate || searchconfig.settings.apitemplate;\n    this.client = searsia.initClient(apitemplate);\n    if (!this.client) {\n      // If initClient didn't return an object, there is not 'mother' stored yet (i.e. there hasn't been a search yet), so we\n      // can just run a search to have it filled\n      if (debugFlags.searsia)\n        console.warn(\"[searsia] Searsia not yet connected, retrieving client\");\n      this.client = await new Promise(resolve => searsia.connectToServer(resolve));\n      if (debugFlags.searsia)\n        console.warn(\"[searsia] We have a client now!\");\n    }\n    if (this.client && this.client.status !== \"error\") {\n      this.suggest = new SearsiaAutoSuggest(this.inputNode, this.suggestNode,\n        {\n          template: this.client.resource.suggesttemplate,\n          minlength: MIN_SUGGEST_LENGTH,\n          numsuggestions: NUM_SUGGESTIONS\n        });\n    }\n\n    // Read the CTA configuration\n    if (searchconfig.searchcta_highlight)\n      this.ctaslots.push({ type: \"highlight\", cta: searchconfig.searchcta_highlight });\n    if (searchconfig.searchcta_widget)\n      this.ctaslots.push({ type: \"widget\", cta: searchconfig.searchcta_widget });\n    // Rewrite CTA configurations\n    for (const ctaslot of this.ctaslots) {\n      for (const cta of ctaslot.cta.ctas) {\n        try {\n          cta.ctaconfig = managedctas.parseManagedCTAConfig(cta.ctaconfig);\n        } catch {\n          cta.ctaconfig = null;\n        }\n      }\n    }\n\n    // Get the 'all events' link\n    this.eventsurl = searchconfig.events_url;\n\n    // Get the manipulated queries\n    this.manipulatedqueries = searchconfig.queries.filter(_ => _.lang === this.lang).map(_ => {\n      return { ..._, terms: this.getQueryTerms(_.query) };\n    });\n\n    // Get the tabs to show\n    const tabsNode = this.node.querySelector(\".searchsheet__tabscontainer\");\n    for (const tab of searchconfig.tabs) {\n      const tabNode = <a href=\"#\" class=\"searchsheet__tab\" data-tab={tab.name}>{tab.title}</a>;\n      if (tab.showwidgets)\n        tabNode.dataset.widgets = \"\";\n      this.tabNodes.push(tabNode);\n      this.tabs.set(tabNode.dataset.tab, { node: tabNode });\n      tabNode.addEventListener(\"click\", event => this.onShowTab(event));\n      if (tabNode.dataset.tab === this.searchType || (!this.searchType && tabNode.dataset.tab === defaultSearchType)) {\n        tabNode.classList.add(\"searchsheet__tab--current\");\n        this.tabWidgets = \"widgets\" in tabNode.dataset;\n      } else\n        tabNode.classList.remove(\"searchsheet__tab--current\");\n      tabsNode.append(tabNode);\n    }\n\n    if (debugFlags.searsia)\n      console.info(\"[searsia] Search configuration\", this.ctaslots, this.eventsurl);\n  }\n\n  getQueryTerms(query) {\n    const words = query.match(/(\\+|\")?\\b\\w+\\b\"?/g);\n    const terms = [];\n    let phrase = null;\n    for (let word of words) {\n      let phrasestart = false;\n      if (word.startsWith(`\"`)) {\n        word = word.substr(1);\n        // start phrase, if not within a phrase yet (otherwise ignore the opening quote)\n        if (!phrase)\n          phrasestart = true;\n      }\n      if (word.endsWith(`\"`)) {\n        word = word.substr(0, word.length - 1);\n        if (phrasestart) {\n          // just a single word\n          phrasestart = false;\n          word = \"+\" + word;\n        } else {\n          // end of phrase?\n          if (phrase) {\n            phrase.push(word);\n            terms.push(phrase);\n            phrase = null;\n            continue;\n          }\n          // just a single word\n        }\n      }\n      // if this is the start of a new phrase, initialize a phrase\n      if (phrasestart)\n        phrase = [];\n      // if parsing a phrase, add the word to the phrase\n      if (phrase)\n        phrase.push(word);\n      else if (word.startsWith(\"+\")) {\n        // add the required word as a term\n        terms.push(word);\n      } else\n        // just add the word term\n        terms.push(word);\n    }\n    // the phrase we're parsing wasn't closed\n    if (phrase) {\n      // if this is a one-word phrase, add the word as a required word\n      if (phrase.length === 1)\n        terms.push(\"+\" + phrase[0]);\n      // add the phrase\n      else\n        terms.push(phrase);\n    }\n    return terms.map(_ => typeof _ === \"string\" ? _.toLowerCase() : _.map(__ => __.toLowerCase()));\n  }\n\n  toggle(show, searchType) {\n    const doshow = !document.documentElement.classList.contains(\"searchsheet--open\");\n    if (doshow) {\n      this.initSearsiaClient(searchType);\n\n      dompack.dispatchCustomEvent(this.node, \"searsia:showsearchsheet\", { bubbles: true, cancelable: false });\n      pxl.sendPxlEvent(\"utwente_base:searsia_open\");\n\n      document.documentElement.classList.remove(\"searchsheet--closing\");\n      document.documentElement.classList.add(\"searchsheet--opening\");\n      this.node._wsTmpTransition = getComputedStyle(this.node).transition;\n      document.documentElement.classList.add(\"searchsheet--open\");\n      this.node._wsTmpTransition = getComputedStyle(this.node).transition;\n    } else if (!show) {\n      pxl.sendPxlEvent(\"utwente_base:searsia_close\");\n      this.node.classList.remove(\"searchsheet--show\");\n\n      document.documentElement.classList.remove(\"searchsheet--opening\");\n      document.documentElement.classList.add(\"searchsheet--closing\");\n      this.node._wsTmpTransition = getComputedStyle(this.node).transition;\n      document.documentElement.classList.add(\"searchsheet--close\");\n      document.documentElement.classList.remove(\"searchsheet--open\");\n      this.node._wsTmpTransition = getComputedStyle(this.node).transition;\n\n      this.updateUrl(true);\n    }\n    return doshow;\n  }\n\n  showSheet(toshow) {\n    for (const sheet of [\"quicklinks\", \"quickresults\", \"results\"])\n      if (sheet === toshow)\n        this.node.classList.add(\"searchsheet--show\" + sheet);\n      else\n        this.node.classList.remove(\"searchsheet--show\" + sheet);\n  }\n\n  showTab(toshow, nosearch) {\n    if (this.tabs.has(toshow)) {\n      const tab = this.tabs.get(toshow);\n      this.tabWidgets = false;\n      for (const tabNode of this.tabNodes) {\n        if (tabNode === tab.node) {\n          tabNode.classList.add(\"searchsheet__tab--current\");\n          this.tabWidgets = \"widgets\" in tabNode.dataset;\n        } else\n          tabNode.classList.remove(\"searchsheet__tab--current\");\n      }\n      pxl.sendPxlEvent(\"utwente_base:searsia_showtab\", { ds_tab: toshow });\n      this.searchType = toshow !== \"all\" ? toshow : \"\";\n      if (!nosearch) {\n        this.doSearch();\n        this.updateUrl();\n      }\n    }\n  }\n\n  setStyles(style) {\n    for (const prop of Object.keys(style))\n      this.node.style[prop] = style[prop];\n  }\n\n  reset() {\n    if (this.suggest)\n      this.suggest.cancel();\n    this.inputNode.form.reset();\n    this.inputNode.focus();\n    this.haveResults = false;\n    this.showSheet(\"quicklinks\");\n    this.showTab(defaultSearchType, true);\n    this.updateUrl(true);\n  }\n\n  updateUrl(reset) {\n    if (reset) {\n      this.url.searchParams.delete(\"q\");\n      this.url.searchParams.delete(\"t\");\n    } else {\n      const params = { q: this.inputNode.value, t: this.searchType };\n      this.url.searchParams.set(\"q\", params.q);\n      if (params.t)\n        this.url.searchParams.set(\"t\", params.t);\n      else\n        this.url.searchParams.delete(\"t\");\n    }\n    window.history.replaceState(null, \"\", this.url.toString());\n  }\n\n  onShowTab(event) {\n    event.preventDefault();\n    const tabNode = event.target.closest(\".searchsheet__tab\");\n    if (tabNode)\n      this.showTab(tabNode.dataset.tab);\n  }\n\n  onTransitioned(event) {\n    // When the closing transition ends for the haader node, remove the close class (which resets the transform)\n    if (event.propertyName === \"transform\" && event.target === this.headerNode && document.documentElement.classList.contains(\"searchsheet--close\")) {\n      dompack.dispatchCustomEvent(this.node, \"searsia:hidesearchsheet\", { bubbles: true, cancelable: false });\n      document.documentElement.classList.remove(\"searchsheet--close\");\n      this.showSheet(\"quicklinks\");\n    }\n  }\n\n  onInputFocus(event) {\n    if (event.type === \"focus\")\n      this.node.classList.add(\"searchsheet--inputfocus\");\n    else\n      this.node.classList.remove(\"searchsheet--inputfocus\");\n  }\n\n  onShowSuggestions() {\n    this.showSheet(\"quickresults\");\n  }\n\n  onHideSuggestions() {\n    if (this.haveResults)\n      this.showSheet(\"results\");\n    else\n      this.showSheet(\"quicklinks\");\n  }\n\n  onStartSearch(event) {\n    event.preventDefault();\n    if (this.inputNode.value) {\n      this.inputNode.blur();\n      this.doSearch();\n      this.updateUrl();\n    }\n  }\n\n  doSearchFor(q, t) {\n    this.toggle(true, t); // toggle calls initSearsiaClient, so call it before calling doSearch\n    this.inputNode.value = q;\n    if (t)\n      this.showTab(t, true);\n    this.doSearch();\n    this.updateUrl();\n  }\n\n  async doSearch() {\n    await this.configPromise; //ensure we have the client initialized\n\n    if (this.suggest)\n      this.suggest.cancel();\n    this.orgQuery = this.getFilteredUserQuery();\n    const params = { q: this.orgQuery, t: this.searchType };\n    this.query = this.inputNode.value;\n    this.queryWords = this.getUserQueryWords(params.q);\n    this.queryFilter = null;\n    this.filteredResults = 0;\n    this.numResults = 0;\n    this.didYouMean = \"\";\n    this.relatedNode = null;\n    this.searsiaSession = searsia.searchFederated(params, result => this.onResults(result));\n    if (debugFlags.searsia)\n      console.info(\"[searsia] searchFederated\", params, this.searsiaSession);\n    pxl.sendPxlEvent(\"utwente_base:searsia_search\", { ds_session: this.searsiaSession, ds_query: params.q, ds_type: params.t });\n  }\n\n  getFilteredUserQuery() {\n    let query = this.inputNode.value;\n    for (const filter of this.stopwordfilters)\n      query = query.replace(filter, \" \");\n    return query.trim();\n  }\n\n  getUserQueryWords(query) {\n    return query ? new RegExp(`\\\\b${query.match(/\\b\\w+\\b/g).join(\"\\\\b|\\\\b\")}\\\\b`, \"i\") : null;\n  }\n\n  getQueryFilter() {\n    if (!this.queryFilter) {\n      this.queryFilter = null;\n      const words = this.orgQuery.match(/\\b\\w+\\b/g).map(_ => _.toLowerCase());\n      for (const filter of this.manipulatedqueries) {\n        if (filter.terms.every(term => {\n          if (typeof term === \"string\") {\n            if (term.startsWith(\"+\"))\n              return words.includes(term.substring(1));\n            else\n              return words.includes(term); //ADDME: Also search misspellings etc\n          } else\n            return isSubArray(words, term);\n        })) {\n          this.queryFilter = filter;\n          break;\n        }\n      }\n\n      if (!this.queryFilter)\n        this.queryFilter = [];\n      else {\n        this.queryFilter = this.queryFilter.urls.map(_ => ({ ..._, seen: false }));\n        if (debugFlags.searsia && this.queryFilter.length)\n          console.info(\"[searsia] Using queryFilter\", this.queryFilter);\n      }\n    }\n    return this.queryFilter;\n  }\n\n  async onResults(result) {\n    // Wait for CTA config before showing results, so we can show CTA's based on the user query and determine query filters\n    await this.configPromise;\n\n    this.queryFilter = this.getQueryFilter();\n\n    if (debugFlags.searsia)\n      console.info(\"[searsia]\", result);\n    if (result.sessionid !== this.searsiaSession) {\n      if (debugFlags.searsia)\n        console.warn(`[searsia] Ignoring search results for old session '${result.sessionid}'`);\n      return;\n    }\n    switch (result.status) {\n      case \"start\":\n        {\n          pxl.sendPxlEvent(\"utwente_base:searsia_start\", { ds_session: this.searsiaSession });\n          this.allhits = [];\n          this.haveResults = true;\n          this.showSheet(\"results\");\n          this.resultsNode.replaceChildren();\n          this.grid = null;\n          this.statusNode.innerHTML = getHTMLTid(\"utwente_base:frontend.ws2016.js.searchsheet.searching\", this.query);\n          if (this.searchType === \"images\")\n            this.resultsNode.appendChild(<div class=\"searsia__imagegrid\"></div>);\n\n          if (this.tabWidgets)\n            this.showWidgets();\n          dompack.registerMissed();\n        } break;\n      case \"hits\":\n        {\n          const source = { ...SEARSIA_SOURCES[result.resource.id], resource: result.resource.id, rank: result.rank };\n          pxl.sendPxlEvent(\"utwente_base:searsia_hits\", { ds_session: this.searsiaSession, ds_resource: result.resource.id, dn_hits: result.hits.length, db_hidden: source.display === false });\n          if (source.display === false)\n            break;\n\n          if (source.type === \"didyoumean\") {\n            if (!this.didYouMean && result.hits.length) {\n              this.didYouMean = result.hits[0].title;\n              this.updateStatusNode();\n              pxl.sendPxlEvent(\"utwente_base:searsia_didyoumean\", { ds_session: this.searsiaSession, ds_suggestion: this.didYouMean });\n            }\n            break;\n          }\n          if (source.type === \"related\") {\n            const relatedHits = result.hits.slice(0, NUM_RELATED);\n            if (debugFlags.searsia)\n              console.info(\"[searsia] Show related searches\", relatedHits);\n            this.relatedNode = searsiaTypes.createRelatedResults(relatedHits, source, this.queryWords);\n            break;\n          }\n\n          // Get the resource score for url deduplication\n          const resourceDuplicateScore = SEARSIA_DUPLICATE_RESOURCES.indexOf(source.resource);\n\n          const hits = [];\n          for (const hit of result.hits) {\n            const manipulated = this.queryFilter.find(_ => _.url === hit.url);\n            if (manipulated) {\n              manipulated.seen = true;\n              if (manipulated.pos < 0) {\n                if (debugFlags.searsia)\n                  console.info(\"[searsia] Skipping filtered hit\", hit);\n                ++this.filteredResults;\n                continue;\n              }\n            }\n\n            // Check if this is a duplicate url\n            if (resourceDuplicateScore >= 0) {\n              const dupIdx = this.allhits.findIndex(_ => _.hit.url === hit.url);\n              if (dupIdx >= 0) {\n                if (this.allhits[dupIdx].score >= resourceDuplicateScore) {\n                  // Remove the existing url, adding the new url\n                  if (debugFlags.searsia)\n                    console.info(\"[searsia] Removing duplicate hit\", this.allhits[dupIdx].hit);\n                  this.allhits[dupIdx].node.remove();\n                  this.allhits.splice(dupIdx, 1);\n                } else {\n                  // Skip the new url, keeping the existing url\n                  if (debugFlags.searsia)\n                    console.info(\"[searsia] Skipping duplicate hit\", hit);\n                  continue;\n                }\n              }\n            }\n\n            hit.rankscore = hit.score;// * Math.max(10 - result.rank, 1);\n            hit.urllang = this.getResultLanguage(hit, source);\n            if (manipulated) {\n              if (debugFlags.searsia)\n                console.info(\"[searsia] Promoting hit\", hit, manipulated.pos);\n              hit.rankscore = 5 - manipulated.pos; // pos has range [ 1, 3 ], rankscore has range [ 0, 1 ]\n              hit.urllang = this.lang;\n            }\n            hits.push({ hit, source });\n            ++this.numResults;\n\n            let resultContainer = this.resultsNode;\n            if (this.searchType === \"images\") {\n              // Add image results to the justified image grid\n              resultContainer = this.resultsNode.querySelector(\".searsia__imagegrid\");\n            } else if (source.group) {\n              // Add a container for the grouped results\n              resultContainer = this.resultsNode.querySelector(`.searsia__resultgroup--${source.group}`);\n              if (!resultContainer) {\n                resultContainer = <div class={\"searsia__resultgroup searsia__resultgroup--\" + source.group}></div>;\n                resultContainer[resultScoreProp] = Infinity;\n                const refNode = Array.from(this.resultsNode.childNodes).find(_ => _[resultScoreProp] < resultContainer[resultScoreProp]);\n                this.resultsNode.insertBefore(resultContainer, refNode);\n              }\n            }\n\n            let resultNode;\n            switch (source.type) {\n              case \"news\":\n                {\n                  resultNode = searsiaTypes.createNewsResult(hit, source, this.searchType === \"news\", this.queryWords);\n                } break;\n              case \"event\":\n                {\n                  resultNode = searsiaTypes.createEventResult(hit, source, this.searchType === \"news\", this.queryWords);\n                } break;\n              case \"people\":\n                {\n                  resultNode = searsiaTypes.createPeopleResult(hit, source, this.searchType === \"people\", this.queryWords);\n                } break;\n              case \"video\":\n                {\n                  resultNode = searsiaTypes.createVideoResult(hit, source, this.searchType === \"videos\", this.queryWords);\n                } break;\n              case \"image\":\n                {\n                  resultNode = searsiaTypes.createImageResult(hit, source, this.searchType === \"images\", this.queryWords);\n                } break;\n              default:\n                {\n                  resultNode = searsiaTypes.createGeneralResult(hit, source, this.queryWords);\n                }\n            }\n\n            resultNode[resultScoreProp] = hit.rankscore;\n            resultNode[resultLangProp] = hit.urllang;\n            resultNode[resultSourceProp] = source.resource;\n            const refNode = Array.from(resultContainer.childNodes).find(_ => {\n              // Skip over widget nodes\n              if (_.classList.contains(\"searsia__widget\"))\n                return false;\n              // If this isn't the Dutch search page, we're sorting Dutch results after non-Dutch results\n              if (this.lang !== \"nl\" && resultNode[resultLangProp] !== _[resultLangProp])\n                return resultNode[resultLangProp] !== \"nl\"; // Non-Dutch before Dutch results\n              // Sort 'serviceportal' results before 'googlecustom' results\n              //Temporarily disabled for #2698\n              //if (resultNode[resultSourceProp] == \"serviceportal\" && _[resultSourceProp] == \"googlecustom\")\n              //  return true;\n              //if (resultNode[resultSourceProp] == \"googlecustom\" && _[resultSourceProp] == \"serviceportal\")\n              //  return false;\n              return _[resultScoreProp] < resultNode[resultScoreProp];\n            });\n            resultContainer.insertBefore(resultNode, refNode);\n            if (resourceDuplicateScore >= 0)\n              this.allhits.push({ hit, node: resultNode, score: resourceDuplicateScore });\n          }\n          this.updateStatusNode();\n          if (!this.searchType)\n            this.showWidgets(hits);\n          dompack.registerMissed();\n        } break;\n      case \"done\":\n        {\n          pxl.sendPxlEvent(\"utwente_base:searsia_done\", { ds_session: this.searsiaSession, dn_results: this.numResults });\n          if (this.searchType === \"images\") {\n            const gridNode = this.resultsNode.firstChild;\n\n            this.grid = new JustifiedImageGrid(gridNode, this.getDefaultGridOptions(this.resultsNode));\n\n            if (!this.imggridresizetimer) {\n              window.addEventListener(\"resize\", () => {\n                if (!this.grid || !this.grid.container.clientWidth) //must be active and visible\n                  return;\n                clearTimeout(this.imggridresizetimer);\n                this.imggridresizetimer = setTimeout(function() {\n                  const defaultoptions = this.getDefaultGridOptions(this.resultsNode);\n                  this.grid.setOptions(defaultoptions);\n                  this.grid.refresh();\n                }.bind(this), 100);\n              });\n            }\n\n            this.imggridresizetimer = setTimeout(function() {\n              this.grid.refresh();\n            }.bind(this), 100);\n          } else if (this.relatedNode) {\n            // Insert the related searches after the 10th result (i.e. before the 11th result)\n            const refNode = this.resultsNode.querySelector(\".searsia__result:nth-of-type(11)\");\n            // refNode == null => insertBefore(node, null) == appendChild(node)\n            this.resultsNode.insertBefore(this.relatedNode, refNode);\n          }\n          if (this.filteredResults > 0) {\n            const filteredNode = searsiaTypes.createFilteredResult();\n            this.resultsNode.appendChild(filteredNode);\n          }\n          this.updateStatusNode(true);\n          if (this.numResults)\n            this.resultsNode.appendChild(<div class=\"searsia__resultsdone\"><p>{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.searchdone\")}</p></div>);\n        } break;\n      case \"error\":\n        {\n          throw new Error(result.error);\n        }\n    }\n  }\n\n  getResultLanguage(hit, _source) {\n    // For utwente.nl URLs, non-Dutch URLs have a path starting with \"/de/\" or \"/en/\"\n    // Treat utwente.nl subdomains (like \"people.utwente.nl\") as non-Dutch\n    if (/:\\/\\/(www\\.)?utwente.nl\\/en\\//.test(hit.url))\n      return \"en\";\n    if (/:\\/\\/(www\\.)?utwente.nl\\/de\\//.test(hit.url))\n      return \"de\";\n    if (/:\\/\\/(www\\.)?utwente.nl\\//.test(hit.url))\n      return \"nl\";\n    return \"en\";\n  }\n\n  updateStatusNode(force) {\n    if (this.numResults || force) {\n      let html = getHTMLTid(\"utwente_base:frontend.ws2016.js.searchsheet.results\", this.numResults, this.query, this.didYouMean);\n      if (!this.numResults && !this.didYouMean && this.searchType)\n        html = html + getHTMLTid(\"utwente_base:frontend.ws2016.js.searchsheet.searchall\");\n      html = html.split(\"%S%\").join('<span class=\"searchsheet__didyoumean\">').split(\"%/S%\").join('</span>');\n      this.statusNode.innerHTML = html;\n\n      // See https://gitlab.webhare.com/utwente/utwente_base/-/issues/2266\n      const isstudent = Boolean(this.userBeacons && this.userBeacons[\"usertype-student\"]);\n      const isemployee = Boolean(this.userBeacons && this.userBeacons[\"usertype-employee\"]);\n      if (!document.documentElement.classList.contains(\"loggedin\") && (isstudent || isemployee) && [\"\", \"people\", \"serviceportal\"].includes(this.searchType)) {\n        const loginmsg = <div class=\"searchsheet__login-msgbox\">\n          <div class=\"searchsheet__login-msgbox__content\">\n            {this.lang === \"nl\" ? <p><a href=\"x-serviceportal:login\">Log in</a> om interne/afgeschermde pagina&apos;s van de Service Portal aan de zoekresultaten toe te voegen.</p> : this.lang === \"de\" ? <p>Bitte <a href=\"x-serviceportal:login\">logge dich ein</a> um abgeschirmte Seiten aus dem internen Service Portal in den Suchergebnissen zu sehen.</p> : <p>Please <a href=\"x-serviceportal:login\">log in</a> if you also want to see internal/protected pages from the Service Portal.</p>}\n          </div>\n        </div>;\n        this.statusNode.prepend(loginmsg);\n      }\n    }\n  }\n\n  showWidgets(hits) {\n    const node = showSearsiaWidgets(hits, this.ctaslots, { country: this.userCountry, beacons: this.userBeacons, url: location.href, query: this.query }, this.eventsurl);\n    if (node)\n      this.resultsNode.insertBefore(node, this.resultsNode.firstChild);\n  }\n\n  onClickStatus(event) {\n    const didyoumean = event.target.closest(\".searchsheet__didyoumean\");\n    if (didyoumean) {\n      pxl.sendPxlEvent(\"utwente_base:searsia_clickdidyoumean\", { ds_session: this.searsiaSession, ds_suggestion: this.didYouMean || \"\", ds_type: this.searchType });\n      if (this.didYouMean) {\n        this.inputNode.value = this.didYouMean;\n        this.doSearch();\n        this.updateUrl();\n      } else\n        this.showTab(\"all\");\n    }\n  }\n\n  onClickResult(event) {\n    const peopleResult = event.target.closest(\".searsia__result--people\");\n    if (peopleResult && !event.target.closest(\".searsia__peopledetails\")) {\n      event.preventDefault();\n      peopleResult.classList.toggle(\"searsia__result--open\");\n      return;\n    }\n\n    const relatedResult = event.target.closest(\".searsia__related__link\");\n    if (relatedResult) {\n      const suggestion = relatedResult.textContent;\n      pxl.sendPxlEvent(\"utwente_base:searsia_clickrelated\", { ds_session: this.searsiaSession, ds_suggestion: suggestion });\n      this.inputNode.value = suggestion;\n      this.doSearch();\n      this.updateUrl();\n      return;\n    }\n\n    const link = event.target.closest(\"a\");\n    if (link) {\n      const widget = event.target.closest(\".searsia__widget\");\n      this.linkClicked = true;\n      pxl.sendPxlEvent(\"utwente_base:searsia_clickresult\", { ds_session: this.searsiaSession, ds_url: link.href, ds_target: widget ? widget.dataset.widgetType : \"result\" }, { beacon: true });\n    }\n  }\n\n  onKeyDown(event) {\n    if (event.key === \"Escape\") {\n      if (this.inputNode.value)\n        this.reset();\n      else\n        this.toggle(false);\n    }\n  }\n\n  getDefaultGridOptions(node) {\n    const options =\n    {\n      width: Math.round(node.clientWidth * window.devicePixelRatio) / window.devicePixelRatio,\n      row_height: 215,\n      gutter_x: 20,\n      gutter_y: 20,\n      debug: true,\n      debug_layout: true\n    };\n    return options;\n  }\n\n  onUnload() {\n    if (document.documentElement.classList.contains(\"searchsheet--open\") && !this.linkClicked)\n      pxl.sendPxlEvent(\"utwente_base:searsia_unload\", { ds_session: this.searsiaSession }, { beacon: true });\n  }\n}\n\n\nfunction initSearchSheet(node) {\n  const searchSheetContentNode = node.querySelector(\".searchsheet__content\");\n\n  node._wsTmpTransition = getComputedStyle(node).transition;\n  searchSheetContentNode._wsTmpTransition = getComputedStyle(searchSheetContentNode).transition;\n\n  node.classList.remove(\"searchsheet--init\");\n  setTimeout(() => searchSheetContentNode.classList.remove(\"searchsheet__content--init\"), 250);\n\n  node.querySelector(\".searchsheet__searchfield-clear\").addEventListener(\"click\", resetSearch);\n\n  /*  for (let section of node.querySelectorAll(\".searchsheet__section\"))\n      setupSection(section);*/\n\n  for (const section of node.querySelectorAll(\".searchsheet__section-links\"))\n    setupShowAllLinks(section, \"searchsheet__section-alllinks\", \"searchsheet__section-link\");\n\n  searsiaClient = new SearsiaClient(node);\n\n  node.querySelector(\".searchsheet__close\").addEventListener(\"click\", event => {\n    dompack.stop(event);\n    toggle();\n  });\n}\n\n/*function setupSection(sectionNode)\n{\n  // Open/close link sections when in accordion mode\n  sectionNode.querySelector(\".searchsheet__section-title\").addEventListener(\"click\", event =>\n  {\n    // Check if the footer is actually in accordion mode\n    let target = event.target.closest(\".searchsheet__section-title\");\n    if (getComputedStyle(target).display != \"block\") // The sectiontitle is hidden, no accordion\n      return;\n\n    // Save section height so it can be animated using transition (which only animates explicitly set height)\n    let links = sectionNode.querySelector(\".searchsheet__section-links\");\n    if (links.classList.contains(\"searchsheet__section-links--init\"))\n    {\n      links.setAttribute(\"data-height\", links.clientHeight + \"px\");\n      links.classList.remove(\"searchsheet__section-links--init\");\n\n      // Force a style recompute after the links 'init' class is removed, so the transition will work properly\n      links._wsTmpHeight = getComputedStyle(links).height;\n    }\n\n    // Toggle section open/close, update height to trigger height transition\n    requestAnimationFrame(() =>\n    {\n      if (target.classList.contains(\"searchsheet__section-title--open\"))\n      {\n        target.classList.remove(\"searchsheet__section-title--open\");\n        links.classList.remove(\"searchsheet__section-links--open\");\n        links.style.height = \"\";\n      }\n      else\n      {\n        target.classList.add(\"searchsheet__section-title--open\");\n        links.classList.add(\"searchsheet__section-links--open\");\n        links.style.height = links.getAttribute(\"data-height\");\n      }\n    });\n  });\n}*/\n\nfunction resetSearch(event) {\n  if (event) {\n    event.preventDefault();\n    event.stopPropagation();\n  }\n  if (searsiaClient)\n    searsiaClient.reset();\n}\n\n\nexport function toggle() {\n  if (searsiaClient && searsiaClient.toggle())\n    searsiaClient.reset();\n}\n\nexport function doSearch(query, searchType) {\n  if (searsiaClient)\n    searsiaClient.doSearchFor(query, searchType);\n}\n\nexport function setStyles(style) {\n  if (searsiaClient)\n    searsiaClient.setStyles(style);\n}\n\nexport async function initSearsiaClient(searchType) {\n  if (searsiaClient) {\n    await searsiaClient.initSearsiaClient(searchType);\n    return searsiaClient.client;\n  }\n}\n\n\ndompack.register(\".searchsheet\", node => initSearchSheet(node));\ndompack.register(\"#searsiasearch\", node => node.parentNode.removeChild(node));\n","import * as dompack from \"dompack\";\n\n\nexport class JustifiedContentGrid\n{\n  constructor(container, options)\n  {\n    this.container = null;\n    this.gridcontainer = null;\n    this.items = [];\n\n    // vars for auto update in case image dimensions have to be determines and updated on the fly\n    this.newinforefreshtimer = null;\n    this.waitingforimagecount = 0;\n\n    this.options =\n      { width:              0\n      , height:             0\n\n      , row_height:         256 // used for direction: \"horizontal\"\n      , column_width:       256 // used for direction: \"vertical\"\n\n\n      // the amount of rows(if direction=\"horizontal\") or columns if direction=\"vertical\"\n      // if set and the track's size is fixed, any images which do not fit in the specified amount of tracks won't be shown\n      //, tracks:             4 // FIXME: not implemented\n\n      // \"keep\" - keep original ordering\n      // \"bestfit\" - order in such a way as to get equal sized tracks\n      //, ordering:           \"keep\" // FIXME: not implemented\n\n      , gutter_x:           2\n      , gutter_y:           2\n\n      , debug:              false\n      , debug_layout:       false\n\n      , fill_last_strip_threshold: 40\n      };\n\n    //this.setOptions(options);\n    this.options = {...this.options, ...options};\n\n    //this.gridcontainer = new Element(\"div\", { styles: { position: \"relative\" } });\n    this.gridcontainer = document.createElement(\"div\");\n    this.gridcontainer.style.position = \"relative\";\n\n    if (typeof this.container == \"string\")\n      this.container = document.querySelector(container);\n    else// if node\n      this.container = container;\n  }\n\n  setOptions(options)\n  {\n    Object.assign(this.options, options);\n  }\n\n  /** @short relayout\n  */\n  refresh()\n  {\n    this.refreshHorizontal();\n  }\n\n  refreshHorizontal()\n  {\n    var strip_width = this.options.width; // container width\n    var strip_height = this.options.row_height;\n\n    if (strip_width == 0)\n    {\n      strip_width = this.container.clientWidth;\n\n      if (strip_width == 0)\n      {\n        console.warn(\"Cannot draw, the clientWidth of the specified container is 0 (display: none; ?).\");\n        return;\n      }\n    }\n\n    var img_idx = 0;\n    var img_count = this.items.length;\n\n    var current_width = 0\n      , current_width_next = 0\n      , row = 0\n      , ypos = 0;\n\n    this.options.debug = this.options.debug || this.options.debug_layout;\n\n    if (this.options.debug)\n    {\n      if (console.groupCollapsed)\n        console.groupCollapsed(\"JustifiedContentGrid refresh\");\n      else\n        console.group(\"JustifiedContentGrid refresh\");\n\n      console.log(img_count, \"images\");\n\n      if (!this.options.debug_layout)\n        console.log(\"You can also use debug_layout for more information.\");\n    }\n\n    if (this.options.debug_layout)\n      console.log(\"strip_width:\", strip_width);\n\n    var maxiterations = 999;\n    var maxrows = 999;\n    while(img_idx < img_count && row < maxrows && maxiterations > 0)\n    {\n      maxiterations--;\n\n      var column = 0;\n      var current_width = 0;\n      var current_width_next = 0;\n\n      if (row > 0)\n        ypos += this.options.gutter_y;\n\n      // determine how many items can fit\n      var img_this_strip = [];\n      var item = null;\n      while(img_idx < img_count && current_width_next < strip_width)\n      {\n        item = this.items[img_idx];\n\n        // determine width we need to get the height to exactly fit\n        var resized_width = Math.ceil(item.width * (strip_height / item.height));\n        item.width_apply = resized_width;\n\n        /*\n        console.log({ width:   item.width\n                    , height:  item.height\n                    , width_r: item.width_apply\n                    });\n        */\n\n        current_width_next += item.width_apply + (column == 0 ? 0 : this.options.gutter_x);\n\n        if (current_width_next < strip_width)\n        {\n          current_width = current_width_next;\n          img_this_strip.push(item);\n          img_idx++;\n        }\n\n        column++;\n      }\n      column--;\n\n      //console.info(\"img_this_strip\", img_this_strip);\n\n      // the total amount of pixels to add or substract from images in this strip\n      var compensatex = 0;\n\n      // Determine what strategy would be the best for getting content\n      // nicely justified (with the less amount of stretching or shrinking)\n      // (unless we fit exactly)\n      if (current_width != strip_width)\n      {\n        var grow_if_no_extra_image = strip_width - current_width; // how many pixels do items have to grow to fit?\n        var shrink_if_extra_image = current_width_next - strip_width; // if we add one extra image (and overflow), how many pixels do items have to shrink to fit?\n\n        //console.log(img_idx, img_count);\n        //console.log(row);\n\n        if (img_this_strip.length == 0) // single wide (panoramic) image\n        {\n          img_this_strip.push(item);\n          column++; // (for debugging or if we want to store the column and row in the array)\n\n          // Scale the image to fill the width & height of this strip\n          var scale_to_fill_width  = strip_width  / item.width;\n          var scale_to_fill_height = strip_height / item.height;\n          var scale_to_fill_both   = scale_to_fill_width > scale_to_fill_height ? scale_to_fill_width : scale_to_fill_height;\n\n          // For blowing up the items a little we center on the middle and\n          var result_width = Math.ceil(item.width * scale_to_fill_both);\n          var result_height = Math.ceil(item.height * scale_to_fill_both);\n\n          item.width_apply = result_width;\n\n          /*\n          console.log({ scale_w: scale_to_fill_width\n                      , scale_h: scale_to_fill_height\n                      , scale_final: scale_to_fill_both\n                      , result_width: result_width\n                      , result_height: result_height\n                      });\n          */\n\n          item.node_applied = { left:   0\n                              , top:    ypos\n                              , width:  strip_width\n                              , height: strip_height\n                              };\n\n          // update the clipping node\n          item.node.style.left   = \"0\";\n          item.node.style.top    = ypos+\"px\";\n          item.node.style.width  = strip_width+\"px\";\n          item.node.style.height = strip_height+\"px\";\n\n          // FIXME: positioning can happen in non-rounded pixels...\n          //        prevent this by increasing the scale_to_fill_both a tiny bit so we can Math.floor ?\n\n          item.img_applied =  { left:  (strip_width - result_width) / 2\n                              , top:   (strip_height - result_height) / 2\n                              , width: item.width_apply\n                              };\n\n          // update the image\n          item.img.style.width = item.width_apply+\"px\";\n          item.img.style.left = item.img_applied.left + \"px\";\n          item.img.style.top = item.img_applied.top + \"px\";\n\n          column++; // (for debugging or if we want to store the column and row in the array)\n          img_idx++;\n\n          row++;\n          ypos += strip_height;\n\n          if (this.options.debug_layout)\n            console.log(img_idx, \"will fill it's own row (panoramic)\");\n\n          continue;\n        }\n        if (img_idx == img_count && this.options.fill_last_strip_threshold < grow_if_no_extra_image)\n        {\n          img_this_strip.push(item);\n          column++; // (for debugging or if we want to store the column and row in the array)\n\n          if (this.options.debug_layout)\n            console.log(img_idx, \"last image but no need to grow (fill_last_strip_threshold lower than empty space\");\n        }\n        else if (grow_if_no_extra_image < shrink_if_extra_image)\n        {\n          // 1. grow the items which fit to fill up all space\n          compensatex = grow_if_no_extra_image;\n\n          if (this.options.debug_layout)\n            console.log(img_idx, \"will distribute\", compensatex, \"to items in row\");\n        }\n        else // also get the current image into this column\n        {\n          // 2. shrink the items to fit\n          compensatex = -shrink_if_extra_image;\n          img_this_strip.push(item);\n\n          if (this.options.debug_layout)\n            console.log(img_idx, \"will shrink\", compensatex, \"to make a last image fit in the row\");\n\n          column++; // (for debugging or if we want to store the column and row in the array)\n          img_idx++;\n        }\n      }\n\n      if (this.options.debug_layout)\n        console.info(\"Row #\"+row+\" contains \", img_this_strip.length, \"images\");\n\n\n      // if (compensatex != 0)\n      var add_each_item = Math.floor(compensatex / column);\n      var add_last_item = compensatex - add_each_item * column;\n\n      if (this.options.debug_layout)\n      {\n        console.info(\"We need to grow\"); //, distributing\", compensatex, \" over\", column, \"columns.\");\n        console.info(\n            { compensatex:   compensatex\n            , columns:       column\n            , add_each_item: add_each_item\n            , add_last_item: add_last_item\n            });\n      }\n\n      var xpos = 0;\n      for (var col_idx = 0; col_idx < column; col_idx++)\n      {\n        //console.log(col_idx);\n        var item = img_this_strip[col_idx];\n\n        item.width_apply_orig = item.width_apply;\n\n        // apply extra pixels\n        if (compensatex != 0)\n        {\n          item.width_apply += add_each_item;\n          if (col_idx == column - 1)\n            item.width_apply += add_last_item;\n        }\n\n        // styles for the container/cropping node\n        item.node_applied = { left: xpos\n                            , top:  ypos\n                            , width: item.width_apply\n                            , height: strip_height\n                            };\n\n        if (compensatex > 0)\n        {\n          // For blowing up the items a little we center on the middle and\n          // cut off a little at the top and bottom\n          var expected_height = item.height * (item.width_apply / item.width);\n          /*\n          console.log({ img: item.img\n                      , width: item.width\n                      , width_scaled: item.width_apply_orig\n                      , width_scaled_justified: item.width_apply\n                      , expected_height: item.expected_height\n                      , left: 0\n                      , top:  (strip_height - expected_height) / 2\n                      });\n          */\n\n          item.img_applied =  { left: 0\n                              , top:  Math.round((strip_height - expected_height) / 2)\n                              , width: item.width_apply\n                              };\n        }\n        else if (compensatex < 0) // < 0, because == 0 is already handled\n        {\n          // Shrinking items has to be done by cutting off pixels at the sides\n          // (because we resize to exactly fit in the height, so if we zoom out whe'll have empty border)\n\n          item.img_applied =  { left: Math.round((item.width_apply - item.width_apply_orig) / 2)\n                              , top:  0\n                              , width: item.width_apply_orig\n                              };\n\n        }\n        else if (compensatex == 0)\n        {\n          item.img_applied =  { left:  0\n                              , top:   0\n                              , width: item.width_apply_orig\n                              };\n        }\n\n        // update the container/clipping node\n        item.node.style.left   = item.node_applied.left+\"px\";\n        item.node.style.top    = item.node_applied.top+\"px\";\n        item.node.style.width  = item.node_applied.width+\"px\";\n        item.node.style.height = item.node_applied.height+\"px\";\n\n        // update the image\n        item.img.style.left    = item.img_applied.left+\"px\";\n        item.img.style.top     = item.img_applied.top+\"px\";\n        item.img.style.width   = item.img_applied.width+\"px\";\n\n        xpos += item.width_apply + this.options.gutter_x;\n      }\n\n      /*\n      if (item.node_applied)\n        console.log(item.node_applied.width + \"x\" + item.node_applied.height + \" at \" + item.node_applied.left + \"x\" + item.node_applied.top);\n      else\n        console.log(\"no node_applied for item\");\n      */\n\n      row++;\n      ypos += strip_height;\n    }\n\n    this.gridcontainer.style.width = this.options.width+\"px\";\n    this.gridcontainer.style.height = ypos+\"px\";\n\n    if (this.options.debug)\n    {\n      console.log(\"The grid consists of\", row, \"rows\");\n      console.groupEnd();\n    }\n  }\n\n\n\n////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n//\n//  Private functions\n//\n\n  importItems(items)\n  {\n    var frag = document.createDocumentFragment();\n\n    for (var tel=0; tel < items.length; tel++)\n    {\n      var item = items[tel];\n\n      //var clip_node = new Element(\"div\", { styles: { position: \"absolute\", overflow: \"hidden\" } });\n      var clip_node = document.createElement(\"div\");\n      clip_node.style.cssText = \"position: absolute; overflow: hidden;\";\n      clip_node.appendChild(item.contentnode);\n\n      frag.appendChild(clip_node);\n\n      item.node = clip_node;\n    }\n\n    this.gridcontainer.appendChild(frag);\n  }\n};\n\n\nexport class JustifiedImageGrid extends JustifiedContentGrid\n{\n  /** @short import images from the specified node\n  */\n  constructor(container, options)\n  {\n    super(container, options);\n\n    //var images = container.getElements(\"IMG\");\n    var items = container.children;\n    var imgcount = items.length;\n\n    var new_items = [];\n\n    for(var img_idx = 0; img_idx < imgcount; img_idx++)\n    {\n      // 1. preferred method is when the HTML author specified the dimensions\n      var img = items[img_idx];\n      //console.log(\"Importing \", img);\n\n      var contentnode;\n      // assume these are anchors/containers with the image inside them\n      if (img.tagName != \"IMG\")\n      {\n        contentnode = img;\n        //img = $(contentnode).getElement(\"img\"); // $() needed for IE<9\n        img = img.querySelector(\"img\");\n        if (!img)\n        {\n          console.warn(\"missing image node\");\n          continue;\n        };\n      }\n      else\n      {\n        contentnode = img;\n      };\n\n      img.style.position = \"absolute\";\n\n      var imgwidth = img.getAttribute(\"data-width\");\n      var imgheight = img.getAttribute(\"data-height\");\n\n      // 2. otherwise check whether the browsers already has access to at least the size of the image\n      if (imgwidth === null)\n        imgwidth = img.naturalWidth;\n      else\n        imgwidth = parseInt(imgwidth);\n\n      if (imgheight === null)\n        imgheight = img.naturalHeight;\n      else\n        imgheight = parseInt(imgheight);\n\n      // remove width & height attributes so they won't interfere\n      // FIXME: or should we always set our height in the inline styles?\n      img.removeAttribute(\"width\");\n      img.removeAttribute(\"height\");\n\n      // store the known data on the image\n      var imgdesc =\n          { img:    img\n          , contentnode: contentnode // the node to be imported in the clipping node\n          , node:   null             // clipping node, to be set in the JustifiedContentGrid::importNode() function\n          , width:  imgwidth\n          , height: imgheight\n          };\n      new_items.push(imgdesc);\n\n      // if no image dimensions available yet (image not loaded) resort to updating this info later\n      if (imgwidth == 0 || imgheight == 0)\n      {\n        this.waitingforimagecount++;\n        img.addEventListener(\"load\", this.__onImageLoad.bind(this, imgdesc));\n      }\n    };\n\n    this.importItems(new_items);\n\n    //this.items.append(new_items);\n    this.items = this.items.concat(new_items);\n\n    this.container.appendChild(this.gridcontainer);\n  }\n\n  /** @short add images by passiging an array with image information\n      @param images\n      @cell images.url\n      @cell images.width\n      @cell images.height\n, addImages: function(images)\n  {\n    // ADDME: validate?\n\n    // now append in a single operation\n    this.items.append(images);\n  }\n  */\n\n  __onImageLoad(item_ref, evt)\n  {\n    if (this.options.debug)\n      console.log(\"Updating image size\");\n\n    var imgnode = evt.target;\n    item_ref.width = imgnode.naturalWidth;\n    item_ref.height = imgnode.naturalHeight;\n\n    imgnode.dataset.width = item_ref.width;\n    imgnode.dataset.height = item_ref.height;\n\n    this.waitingforimagecount--;\n    if (this.waitingforimagecount == 0)\n    {\n      // this was the last image we needed, we can cancel the timer and directly force an refresh\n      clearTimeout(this.newinforefreshtimer);\n      this.__forceRefresh();\n    }\n    else if (!this.newinforefreshtimer)\n    {\n      // update on a timer to make sure we don't update for every single image\n      this.newinforefreshtimer = setTimeout(() => this.__forceRefresh(), 250);\n    }\n  }\n\n  __forceRefresh()\n  {\n    this.newinforefreshtimer = null;\n    this.refresh();\n  }\n};\n","import { getBrowser } from \"@webhare/dompack\";\nimport { generateRandomId } from \"@webhare/std\";\nimport { debugFlags, isLive } from \"@webhare/env\";\n\ninterface PxlEventDetails {\n  event: string;\n  data: PxlEventData;\n  options: PxlOptions;\n  isAlt: boolean;\n}\n\nexport type PxlEvent = CustomEvent<PxlEventDetails>;\n\nexport type PxlEventData = {\n  [K in `ds_${string}` | `db_${string}` | `dn_${string}`]: (K extends `ds_${string}` ? string :\n    (K extends `db_${string}` ? boolean :\n      (K extends `dn_${string}` ? number : never)))\n};\n\nexport interface PxlOptions {\n  /** Override pi (pxlId) to control or anonymize user ids*/\n  pi?: string | undefined;\n  /**  Base url to which to send PXL events. Defaults to \"/.wh/ea/pxl/\". */\n  url: string;\n  /**  Sample rate for the alternative record url as a fraction of the number of events, for example, setting it to 1/100 sends 1 in 100 events to the alternative record url. Defaults to 0 (no sampling). */\n  altSampleRate: number;\n  /**  Alternative record url. Defaults to \"/.wh/ea/pxl/alt/\". */\n  altUrl: string;\n  /** The number of days the user id is valid. Defaults to 30. */\n  sessionExpiration: number; //TODO if we ever camel this, also add 'Days' to the name\n  /** Set to true to omit some browser context fields (\"bu\", \"bs\" and \"bp\"). This option can\n      be used to reduce the length of the pxl url. Defaults to false. */\n  noBrowser: boolean;\n  /** Node responsible for generating this event (if not set, 'window' is assumed). Used for the event handlers */\n  node?: HTMLElement;\n  /** Send pixels as beacons */\n  beacon: boolean;\n  /** Callback to execute once pixel is sent */\n  onComplete?: () => void;\n}\n\n//event names must match isValidModuleScopedName, but we won't do the module name checks here. also isValidModuleScopedName lives in @webhare/services so..\nconst eventname_regex = /^([a-z0-9][-a-z0-9_]*[a-z0-9]):([a-z0-9][-.a-z0-9_]*[a-z0-9])$/;\nconst datakey_regex = /^(ds_[0-9a-z_]+)|(dn_[0-9a-z_]+)|(db_[0-9a-z_]+)$/;\n/*TODO: Not sure yet what the new maximum URL length will be\nconst max_data_length = 600; // The maximum number of bytes stored for the request*/\nconst max_sessionid_age = 30;\n\nlet globalOptions: Partial<PxlOptions> | undefined;\n\nlet pagesession: string | undefined; //current page session id (used to track multiple events from single page)\nlet useAltRecordURL = false; //send events for this page to the altrecordurl\nlet seqnr = 0;\n\nlet pxlUserId: string | undefined, pxlSessionId: string | undefined;\n\nfunction buildOptions(options: Partial<PxlOptions> | undefined): PxlOptions {\n  return {\n    url: \"/.wh/ea/pxl/\",\n    altSampleRate: 0,\n    altUrl: \"/.wh/ea/pxl/alt/\",\n    sessionExpiration: max_sessionid_age,\n    noBrowser: false,\n    beacon: false,\n    ...globalOptions,\n    ...options\n  };\n}\n\n/** Set global pxl options\n    @param options - Option updates\n*/\nexport function setPxlOptions(options: Partial<PxlOptions> | null) {\n  globalOptions = { ...globalOptions, ...options };\n\n  if (globalOptions.altUrl && globalOptions.altSampleRate) {\n    useAltRecordURL = Math.random() < globalOptions.altSampleRate;\n    if (debugFlags.pxl)\n      console.log(`[pxl] using altrecordurl for ${100 * globalOptions.altSampleRate}% of pageloads, this session is sent to the ${useAltRecordURL ? \"alternative\" : \"normal\"} url`);\n  } else\n    useAltRecordURL = false;\n}\n\nfunction pxlFailed(errormessage: string, ...params: unknown[]) {\n  console.error('[pxl] ' + errormessage, ...params);\n  if (!isLive)\n    throw new Error(errormessage); //big errors on test servers\n  return null;\n}\n\nexport function makePxlURL(baseurl: string, eventname: string, data?: PxlEventData | null, options?: Partial<PxlOptions>) {\n  options = { ...globalOptions, ...options };\n\n  if (typeof eventname !== \"string\")\n    return pxlFailed(`Invalid eventname name '${eventname}', expected string, got ${typeof eventname}`);\n  if (!eventname_regex.test(eventname))\n    return pxlFailed(`Invalid eventname name '${eventname}', must be a valid module:event name`);\n  if (data && typeof data !== \"object\")\n    return pxlFailed(`Invalid data, expected object, got ${typeof data}`);\n\n  if (!pagesession)\n    pagesession = generateRandomId();\n\n  //not using URL object, simplifies support of relative URLs\n  const url = typeof document !== \"undefined\" ? new URL(baseurl, document.baseURI) : new URL(baseurl);\n  url.searchParams.set(\"pe\", eventname);\n  url.searchParams.set(\"pp\", pagesession);\n  url.searchParams.set(\"pc\", String(++seqnr));\n  url.searchParams.set(\"ps\", getPxlSessionId());\n  url.searchParams.set(\"pi\", options?.pi ?? getPxlId());\n\n  if (options.altSampleRate)\n    url.searchParams.set(\"pr\", String(options.altSampleRate));\n\n  const browser = getBrowser();\n  url.searchParams.set(\"bt\", browser.triplet);\n  if (browser.device)\n    url.searchParams.set(\"bd\", browser.device);\n\n  if (typeof document !== \"undefined\") {\n    if (document.documentElement.dataset.whOb)\n      url.searchParams.set(\"ob\", document.documentElement.dataset.whOb.substring(0, 20));\n    if (document.location)\n      url.searchParams.set(\"bl\", document.location.href.substring(0, 1000));\n    if (document.referrer)\n      url.searchParams.set(\"br\", document.referrer.substring(0, 1000));\n\n    if (!options.noBrowser) {\n      url.searchParams.set(\"bu\", window.navigator.userAgent.substring(0, 300));\n      if (window.screen.width && window.screen.height)\n        url.searchParams.set(\"bs\", `${window.screen.width}x${window.screen.height}`);\n      if (window.devicePixelRatio)\n        url.searchParams.set(\"bp\", String(window.devicePixelRatio));\n    }\n  }\n\n  if (data) {\n    for (const [name, value] of Object.entries(data)) {\n      const test = datakey_regex.exec(name);\n      if (!test)\n        return pxlFailed(`Invalid data field name '${name}', should be ds_XXX, dn_XXX or db_XXX with X consisting of characters in the range 0 - 9, a - z or an underscore`);\n\n      const type = typeof value;\n\n      if (test[1]) { // String\n        if (value && type !== \"string\")\n          return pxlFailed(`Invalid value type '${type}', expected 'string' for field '${name}'`);\n\n        url.searchParams.set(name, value as string || '');\n      } else if (test[2]) { // Number\n        if (value && type !== \"number\")\n          return pxlFailed(`Invalid value type '${type}', expected 'number' for field '${name}'`);\n\n        url.searchParams.set(name, String(value) || '0');\n      } else if (test[3]) { // Boolean\n        if (value && type !== \"boolean\")\n          return pxlFailed(`Invalid value type '${type}', expected 'boolean' for field '${name}'`);\n\n        url.searchParams.set(name, value ? \"true\" : \"false\");\n      }\n    }\n  }\n  return url;\n}\n\nexport function getPxlId(): string {\n  if (!pxlUserId) {\n    try {\n      const timestampvar = localStorage.getItem(\"_wh.ti\");\n      if (timestampvar && new Date(timestampvar) > new Date) { //not expired yet\n        pxlUserId = localStorage.getItem(\"_wh.pi\") || undefined;\n        if (pxlUserId && debugFlags.pxl)\n          console.log(`[pxl] Using id ${pxlUserId} from localStorage`);\n      }\n      pxlUserId ||= generateRandomId();\n      const sessionExpireDays = (globalOptions?.sessionExpiration ?? max_sessionid_age);\n      const expiration = new Date(Date.now() + sessionExpireDays * 24 * 60 * 60 * 1000);\n      localStorage.setItem(\"_wh.pi\", pxlUserId);\n      localStorage.setItem(\"_wh.ti\", expiration.toISOString());\n    } catch {\n      pxlUserId ||= generateRandomId();\n    }\n  }\n  return pxlUserId;\n}\n\nexport function getPxlSessionId() {\n  if (!pxlSessionId) {\n    try {\n      pxlSessionId = sessionStorage[\"_wh.ps\"];\n      pxlSessionId ||= generateRandomId();\n      sessionStorage[\"_wh.ps\"] = pxlSessionId;\n    } catch { //privacy mode? just (re)try to generate an id\n      pxlSessionId ||= generateRandomId();\n    }\n  }\n  return pxlSessionId;\n}\n\n/** Send a pxl event\n    @param event - Event type, preferably in the format 'module:event'\n    @param data - Event data. A map whose keys must start with either ds_ (string), db_ (boolean) or dn_ (number)\n*/\nexport function sendPxlEvent(event: string, data?: PxlEventData | null, options?: Partial<PxlOptions>) {\n  const finaloptions = buildOptions(options);\n  const baseurl = useAltRecordURL ? finaloptions.altUrl : finaloptions.url;\n\n  if (debugFlags.pxl)\n    console.log(`[pxl] Event '${event}'`, data);\n\n  // Add the pxl event to the url. We wrap it in async() for simpler code but we won't force our callers to await us, they rarely want to\n  (async () => {\n    const url = makePxlURL(baseurl, event, data, finaloptions);\n    if (!url)\n      return;\n\n    if (finaloptions.beacon && typeof navigator !== \"undefined\" && navigator.sendBeacon) {\n      navigator.sendBeacon(url);\n      return; //as beacons don't return anything per definition, we can stop here\n    }\n\n    if (debugFlags.pxl)\n      console.log(`[pxl] Pinging pxl '${url}'`);\n\n    // Load the pxl file using fetch\n    const fetchRes = await fetch(url, { mode: \"no-cors\", method: \"HEAD\", credentials: \"same-origin\", cache: \"no-store\", keepalive: true });\n    if (fetchRes.type === \"opaque\") { //we can't verify cross-server requests\n      if (debugFlags.pxl)\n        console.log(`[pxl] Assuming succesful pxl event '${event}'`);\n      return;\n    }\n    if (!fetchRes.ok) {\n      console.error(`[pxl] Failed to send pxl event '${event}'`, fetchRes);\n      return;\n    }\n\n    if (finaloptions.onComplete) //if we care about completion, we'll explicitly wait for the body to come in\n      await fetchRes.text(); //this will throw if the request failed, so we can skip the next check\n\n    if (debugFlags.pxl)\n      console.log(`[pxl] Successfully sent pxl event '${event}'`);\n  })().catch((error: Error) => {\n    console.error(`[pxl] Error while sending pxl event '${event}'`, error);\n  }).finally(() => {\n    finaloptions.onComplete?.(); //any exception here we'll keep uncaught\n  });\n}\n","export function get(element) {\n  return getComputedStyle(element);\n}\n\nexport function set(element, obj) {\n  for (const key in obj) {\n    let val = obj[key];\n    if (typeof val === 'number') {\n      val = `${val}px`;\n    }\n    element.style[key] = val;\n  }\n  return element;\n}\n","export function div(className) {\n  const div = document.createElement('div');\n  div.className = className;\n  return div;\n}\n\nconst elMatches =\n  typeof Element !== 'undefined' &&\n  (Element.prototype.matches ||\n    Element.prototype.webkitMatchesSelector ||\n    Element.prototype.mozMatchesSelector ||\n    Element.prototype.msMatchesSelector);\n\nexport function matches(element, query) {\n  if (!elMatches) {\n    throw new Error('No element matching method supported');\n  }\n\n  return elMatches.call(element, query);\n}\n\nexport function remove(element) {\n  if (element.remove) {\n    element.remove();\n  } else {\n    if (element.parentNode) {\n      element.parentNode.removeChild(element);\n    }\n  }\n}\n\nexport function queryChildren(element, selector) {\n  return Array.prototype.filter.call(element.children, child =>\n    matches(child, selector)\n  );\n}\n","const cls = {\n  main: 'ps',\n  rtl: 'ps__rtl',\n  element: {\n    thumb: x => `ps__thumb-${x}`,\n    rail: x => `ps__rail-${x}`,\n    consuming: 'ps__child--consume',\n  },\n  state: {\n    focus: 'ps--focus',\n    clicking: 'ps--clicking',\n    active: x => `ps--active-${x}`,\n    scrolling: x => `ps--scrolling-${x}`,\n  },\n};\n\nexport default cls;\n\n/*\n * Helper methods\n */\nconst scrollingClassTimeout = { x: null, y: null };\n\nexport function addScrollingClass(i, x) {\n  const classList = i.element.classList;\n  const className = cls.state.scrolling(x);\n\n  if (classList.contains(className)) {\n    clearTimeout(scrollingClassTimeout[x]);\n  } else {\n    classList.add(className);\n  }\n}\n\nexport function removeScrollingClass(i, x) {\n  scrollingClassTimeout[x] = setTimeout(\n    () => i.isAlive && i.element.classList.remove(cls.state.scrolling(x)),\n    i.settings.scrollingThreshold\n  );\n}\n\nexport function setScrollingClassInstantly(i, x) {\n  addScrollingClass(i, x);\n  removeScrollingClass(i, x);\n}\n","class EventElement {\n  constructor(element) {\n    this.element = element;\n    this.handlers = {};\n  }\n\n  bind(eventName, handler) {\n    if (typeof this.handlers[eventName] === 'undefined') {\n      this.handlers[eventName] = [];\n    }\n    this.handlers[eventName].push(handler);\n    this.element.addEventListener(eventName, handler, false);\n  }\n\n  unbind(eventName, target) {\n    this.handlers[eventName] = this.handlers[eventName].filter(handler => {\n      if (target && handler !== target) {\n        return true;\n      }\n      this.element.removeEventListener(eventName, handler, false);\n      return false;\n    });\n  }\n\n  unbindAll() {\n    for (const name in this.handlers) {\n      this.unbind(name);\n    }\n  }\n\n  get isEmpty() {\n    return Object.keys(this.handlers).every(\n      key => this.handlers[key].length === 0\n    );\n  }\n}\n\nexport default class EventManager {\n  constructor() {\n    this.eventElements = [];\n  }\n\n  eventElement(element) {\n    let ee = this.eventElements.filter(ee => ee.element === element)[0];\n    if (!ee) {\n      ee = new EventElement(element);\n      this.eventElements.push(ee);\n    }\n    return ee;\n  }\n\n  bind(element, eventName, handler) {\n    this.eventElement(element).bind(eventName, handler);\n  }\n\n  unbind(element, eventName, handler) {\n    const ee = this.eventElement(element);\n    ee.unbind(eventName, handler);\n\n    if (ee.isEmpty) {\n      // remove\n      this.eventElements.splice(this.eventElements.indexOf(ee), 1);\n    }\n  }\n\n  unbindAll() {\n    this.eventElements.forEach(e => e.unbindAll());\n    this.eventElements = [];\n  }\n\n  once(element, eventName, handler) {\n    const ee = this.eventElement(element);\n    const onceHandler = evt => {\n      ee.unbind(eventName, onceHandler);\n      handler(evt);\n    };\n    ee.bind(eventName, onceHandler);\n  }\n}\n","import { setScrollingClassInstantly } from './lib/class-names';\n\nfunction createEvent(name) {\n  if (typeof window.CustomEvent === 'function') {\n    return new CustomEvent(name);\n  } else {\n    const evt = document.createEvent('CustomEvent');\n    evt.initCustomEvent(name, false, false, undefined);\n    return evt;\n  }\n}\n\nexport default function(\n  i,\n  axis,\n  diff,\n  useScrollingClass = true,\n  forceFireReachEvent = false\n) {\n  let fields;\n  if (axis === 'top') {\n    fields = [\n      'contentHeight',\n      'containerHeight',\n      'scrollTop',\n      'y',\n      'up',\n      'down',\n    ];\n  } else if (axis === 'left') {\n    fields = [\n      'contentWidth',\n      'containerWidth',\n      'scrollLeft',\n      'x',\n      'left',\n      'right',\n    ];\n  } else {\n    throw new Error('A proper axis should be provided');\n  }\n\n  processScrollDiff(i, diff, fields, useScrollingClass, forceFireReachEvent);\n}\n\nfunction processScrollDiff(\n  i,\n  diff,\n  [contentHeight, containerHeight, scrollTop, y, up, down],\n  useScrollingClass = true,\n  forceFireReachEvent = false\n) {\n  const element = i.element;\n\n  // reset reach\n  i.reach[y] = null;\n\n  // 1 for subpixel rounding\n  if (element[scrollTop] < 1) {\n    i.reach[y] = 'start';\n  }\n\n  // 1 for subpixel rounding\n  if (element[scrollTop] > i[contentHeight] - i[containerHeight] - 1) {\n    i.reach[y] = 'end';\n  }\n\n  if (diff) {\n    element.dispatchEvent(createEvent(`ps-scroll-${y}`));\n\n    if (diff < 0) {\n      element.dispatchEvent(createEvent(`ps-scroll-${up}`));\n    } else if (diff > 0) {\n      element.dispatchEvent(createEvent(`ps-scroll-${down}`));\n    }\n\n    if (useScrollingClass) {\n      setScrollingClassInstantly(i, y);\n    }\n  }\n\n  if (i.reach[y] && (diff || forceFireReachEvent)) {\n    element.dispatchEvent(createEvent(`ps-${y}-reach-${i.reach[y]}`));\n  }\n}\n","import * as CSS from './css';\nimport * as DOM from './dom';\n\nexport function toInt(x) {\n  return parseInt(x, 10) || 0;\n}\n\nexport function isEditable(el) {\n  return (\n    DOM.matches(el, 'input,[contenteditable]') ||\n    DOM.matches(el, 'select,[contenteditable]') ||\n    DOM.matches(el, 'textarea,[contenteditable]') ||\n    DOM.matches(el, 'button,[contenteditable]')\n  );\n}\n\nexport function outerWidth(element) {\n  const styles = CSS.get(element);\n  return (\n    toInt(styles.width) +\n    toInt(styles.paddingLeft) +\n    toInt(styles.paddingRight) +\n    toInt(styles.borderLeftWidth) +\n    toInt(styles.borderRightWidth)\n  );\n}\n\nexport const env = {\n  isWebKit:\n    typeof document !== 'undefined' &&\n    'WebkitAppearance' in document.documentElement.style,\n  supportsTouch:\n    typeof window !== 'undefined' &&\n    ('ontouchstart' in window ||\n      ('maxTouchPoints' in window.navigator &&\n        window.navigator.maxTouchPoints > 0) ||\n      (window.DocumentTouch && document instanceof window.DocumentTouch)),\n  supportsIePointer:\n    typeof navigator !== 'undefined' && navigator.msMaxTouchPoints,\n  isChrome:\n    typeof navigator !== 'undefined' &&\n    /Chrome/i.test(navigator && navigator.userAgent),\n};\n","import * as CSS from './lib/css';\nimport * as DOM from './lib/dom';\nimport cls from './lib/class-names';\nimport { toInt } from './lib/util';\n\nexport default function(i) {\n  const element = i.element;\n  const roundedScrollTop = Math.floor(element.scrollTop);\n  const rect = element.getBoundingClientRect();\n\n  i.containerWidth = Math.round(rect.width);\n  i.containerHeight = Math.round(rect.height);\n\n  i.contentWidth = element.scrollWidth;\n  i.contentHeight = element.scrollHeight;\n\n  if (!element.contains(i.scrollbarXRail)) {\n    // clean up and append\n    DOM.queryChildren(element, cls.element.rail('x')).forEach(el =>\n      DOM.remove(el)\n    );\n    element.appendChild(i.scrollbarXRail);\n  }\n  if (!element.contains(i.scrollbarYRail)) {\n    // clean up and append\n    DOM.queryChildren(element, cls.element.rail('y')).forEach(el =>\n      DOM.remove(el)\n    );\n    element.appendChild(i.scrollbarYRail);\n  }\n\n  if (\n    !i.settings.suppressScrollX &&\n    i.containerWidth + i.settings.scrollXMarginOffset < i.contentWidth\n  ) {\n    i.scrollbarXActive = true;\n    i.railXWidth = i.containerWidth - i.railXMarginWidth;\n    i.railXRatio = i.containerWidth / i.railXWidth;\n    i.scrollbarXWidth = getThumbSize(\n      i,\n      toInt((i.railXWidth * i.containerWidth) / i.contentWidth)\n    );\n    i.scrollbarXLeft = toInt(\n      ((i.negativeScrollAdjustment + element.scrollLeft) *\n        (i.railXWidth - i.scrollbarXWidth)) /\n        (i.contentWidth - i.containerWidth)\n    );\n  } else {\n    i.scrollbarXActive = false;\n  }\n\n  if (\n    !i.settings.suppressScrollY &&\n    i.containerHeight + i.settings.scrollYMarginOffset < i.contentHeight\n  ) {\n    i.scrollbarYActive = true;\n    i.railYHeight = i.containerHeight - i.railYMarginHeight;\n    i.railYRatio = i.containerHeight / i.railYHeight;\n    i.scrollbarYHeight = getThumbSize(\n      i,\n      toInt((i.railYHeight * i.containerHeight) / i.contentHeight)\n    );\n    i.scrollbarYTop = toInt(\n      (roundedScrollTop * (i.railYHeight - i.scrollbarYHeight)) /\n        (i.contentHeight - i.containerHeight)\n    );\n  } else {\n    i.scrollbarYActive = false;\n  }\n\n  if (i.scrollbarXLeft >= i.railXWidth - i.scrollbarXWidth) {\n    i.scrollbarXLeft = i.railXWidth - i.scrollbarXWidth;\n  }\n  if (i.scrollbarYTop >= i.railYHeight - i.scrollbarYHeight) {\n    i.scrollbarYTop = i.railYHeight - i.scrollbarYHeight;\n  }\n\n  updateCss(element, i);\n\n  if (i.scrollbarXActive) {\n    element.classList.add(cls.state.active('x'));\n  } else {\n    element.classList.remove(cls.state.active('x'));\n    i.scrollbarXWidth = 0;\n    i.scrollbarXLeft = 0;\n    element.scrollLeft = i.isRtl === true ? i.contentWidth : 0;\n  }\n  if (i.scrollbarYActive) {\n    element.classList.add(cls.state.active('y'));\n  } else {\n    element.classList.remove(cls.state.active('y'));\n    i.scrollbarYHeight = 0;\n    i.scrollbarYTop = 0;\n    element.scrollTop = 0;\n  }\n}\n\nfunction getThumbSize(i, thumbSize) {\n  if (i.settings.minScrollbarLength) {\n    thumbSize = Math.max(thumbSize, i.settings.minScrollbarLength);\n  }\n  if (i.settings.maxScrollbarLength) {\n    thumbSize = Math.min(thumbSize, i.settings.maxScrollbarLength);\n  }\n  return thumbSize;\n}\n\nfunction updateCss(element, i) {\n  const xRailOffset = { width: i.railXWidth };\n  const roundedScrollTop = Math.floor(element.scrollTop);\n\n  if (i.isRtl) {\n    xRailOffset.left =\n      i.negativeScrollAdjustment +\n      element.scrollLeft +\n      i.containerWidth -\n      i.contentWidth;\n  } else {\n    xRailOffset.left = element.scrollLeft;\n  }\n  if (i.isScrollbarXUsingBottom) {\n    xRailOffset.bottom = i.scrollbarXBottom - roundedScrollTop;\n  } else {\n    xRailOffset.top = i.scrollbarXTop + roundedScrollTop;\n  }\n  CSS.set(i.scrollbarXRail, xRailOffset);\n\n  const yRailOffset = { top: roundedScrollTop, height: i.railYHeight };\n  if (i.isScrollbarYUsingRight) {\n    if (i.isRtl) {\n      yRailOffset.right =\n        i.contentWidth -\n        (i.negativeScrollAdjustment + element.scrollLeft) -\n        i.scrollbarYRight -\n        i.scrollbarYOuterWidth -\n        9;\n    } else {\n      yRailOffset.right = i.scrollbarYRight - element.scrollLeft;\n    }\n  } else {\n    if (i.isRtl) {\n      yRailOffset.left =\n        i.negativeScrollAdjustment +\n        element.scrollLeft +\n        i.containerWidth * 2 -\n        i.contentWidth -\n        i.scrollbarYLeft -\n        i.scrollbarYOuterWidth;\n    } else {\n      yRailOffset.left = i.scrollbarYLeft + element.scrollLeft;\n    }\n  }\n  CSS.set(i.scrollbarYRail, yRailOffset);\n\n  CSS.set(i.scrollbarX, {\n    left: i.scrollbarXLeft,\n    width: i.scrollbarXWidth - i.railBorderXWidth,\n  });\n  CSS.set(i.scrollbarY, {\n    top: i.scrollbarYTop,\n    height: i.scrollbarYHeight - i.railBorderYWidth,\n  });\n}\n","import updateGeometry from '../update-geometry';\n\nexport default function(i) {\n  const element = i.element;\n\n  i.event.bind(i.scrollbarY, 'mousedown', e => e.stopPropagation());\n  i.event.bind(i.scrollbarYRail, 'mousedown', e => {\n    const positionTop =\n      e.pageY -\n      window.pageYOffset -\n      i.scrollbarYRail.getBoundingClientRect().top;\n    const direction = positionTop > i.scrollbarYTop ? 1 : -1;\n\n    i.element.scrollTop += direction * i.containerHeight;\n    updateGeometry(i);\n\n    e.stopPropagation();\n  });\n\n  i.event.bind(i.scrollbarX, 'mousedown', e => e.stopPropagation());\n  i.event.bind(i.scrollbarXRail, 'mousedown', e => {\n    const positionLeft =\n      e.pageX -\n      window.pageXOffset -\n      i.scrollbarXRail.getBoundingClientRect().left;\n    const direction = positionLeft > i.scrollbarXLeft ? 1 : -1;\n\n    i.element.scrollLeft += direction * i.containerWidth;\n    updateGeometry(i);\n\n    e.stopPropagation();\n  });\n}\n","import * as CSS from '../lib/css';\nimport * as DOM from '../lib/dom';\nimport cls, {\n  addScrollingClass,\n  removeScrollingClass,\n} from '../lib/class-names';\nimport updateGeometry from '../update-geometry';\nimport { toInt } from '../lib/util';\n\nexport default function(i) {\n  bindMouseScrollHandler(i, [\n    'containerWidth',\n    'contentWidth',\n    'pageX',\n    'railXWidth',\n    'scrollbarX',\n    'scrollbarXWidth',\n    'scrollLeft',\n    'x',\n    'scrollbarXRail',\n  ]);\n  bindMouseScrollHandler(i, [\n    'containerHeight',\n    'contentHeight',\n    'pageY',\n    'railYHeight',\n    'scrollbarY',\n    'scrollbarYHeight',\n    'scrollTop',\n    'y',\n    'scrollbarYRail',\n  ]);\n}\n\nfunction bindMouseScrollHandler(\n  i,\n  [\n    containerHeight,\n    contentHeight,\n    pageY,\n    railYHeight,\n    scrollbarY,\n    scrollbarYHeight,\n    scrollTop,\n    y,\n    scrollbarYRail,\n  ]\n) {\n  const element = i.element;\n\n  let startingScrollTop = null;\n  let startingMousePageY = null;\n  let scrollBy = null;\n\n  function mouseMoveHandler(e) {\n    if (e.touches && e.touches[0]) {\n      e[pageY] = e.touches[0].pageY;\n    }\n    element[scrollTop] =\n      startingScrollTop + scrollBy * (e[pageY] - startingMousePageY);\n    addScrollingClass(i, y);\n    updateGeometry(i);\n\n    e.stopPropagation();\n    if (e.type.startsWith('touch') && e.changedTouches.length > 1) {\n      e.preventDefault();\n    }\n  }\n\n  function mouseUpHandler() {\n    removeScrollingClass(i, y);\n    i[scrollbarYRail].classList.remove(cls.state.clicking);\n    i.event.unbind(i.ownerDocument, 'mousemove', mouseMoveHandler);\n  }\n\n  function bindMoves(e, touchMode) {\n    startingScrollTop = element[scrollTop];\n    if (touchMode && e.touches) {\n      e[pageY] = e.touches[0].pageY;\n    }\n    startingMousePageY = e[pageY];\n    scrollBy =\n      (i[contentHeight] - i[containerHeight]) /\n      (i[railYHeight] - i[scrollbarYHeight]);\n    if (!touchMode) {\n      i.event.bind(i.ownerDocument, 'mousemove', mouseMoveHandler);\n      i.event.once(i.ownerDocument, 'mouseup', mouseUpHandler);\n      e.preventDefault();\n    } else {\n      i.event.bind(i.ownerDocument, 'touchmove', mouseMoveHandler);\n    }\n\n    i[scrollbarYRail].classList.add(cls.state.clicking);\n\n    e.stopPropagation();\n  }\n\n  i.event.bind(i[scrollbarY], 'mousedown', e => {\n    bindMoves(e);\n  });\n  i.event.bind(i[scrollbarY], 'touchstart', e => {\n    bindMoves(e, true);\n  });\n}\n","import * as DOM from '../lib/dom';\nimport updateGeometry from '../update-geometry';\nimport { isEditable } from '../lib/util';\n\nexport default function(i) {\n  const element = i.element;\n\n  const elementHovered = () => DOM.matches(element, ':hover');\n  const scrollbarFocused = () =>\n    DOM.matches(i.scrollbarX, ':focus') || DOM.matches(i.scrollbarY, ':focus');\n\n  function shouldPreventDefault(deltaX, deltaY) {\n    const scrollTop = Math.floor(element.scrollTop);\n    if (deltaX === 0) {\n      if (!i.scrollbarYActive) {\n        return false;\n      }\n      if (\n        (scrollTop === 0 && deltaY > 0) ||\n        (scrollTop >= i.contentHeight - i.containerHeight && deltaY < 0)\n      ) {\n        return !i.settings.wheelPropagation;\n      }\n    }\n\n    const scrollLeft = element.scrollLeft;\n    if (deltaY === 0) {\n      if (!i.scrollbarXActive) {\n        return false;\n      }\n      if (\n        (scrollLeft === 0 && deltaX < 0) ||\n        (scrollLeft >= i.contentWidth - i.containerWidth && deltaX > 0)\n      ) {\n        return !i.settings.wheelPropagation;\n      }\n    }\n    return true;\n  }\n\n  i.event.bind(i.ownerDocument, 'keydown', e => {\n    if (\n      (e.isDefaultPrevented && e.isDefaultPrevented()) ||\n      e.defaultPrevented\n    ) {\n      return;\n    }\n\n    if (!elementHovered() && !scrollbarFocused()) {\n      return;\n    }\n\n    let activeElement = document.activeElement\n      ? document.activeElement\n      : i.ownerDocument.activeElement;\n    if (activeElement) {\n      if (activeElement.tagName === 'IFRAME') {\n        activeElement = activeElement.contentDocument.activeElement;\n      } else {\n        // go deeper if element is a webcomponent\n        while (activeElement.shadowRoot) {\n          activeElement = activeElement.shadowRoot.activeElement;\n        }\n      }\n      if (isEditable(activeElement)) {\n        return;\n      }\n    }\n\n    let deltaX = 0;\n    let deltaY = 0;\n\n    switch (e.which) {\n      case 37: // left\n        if (e.metaKey) {\n          deltaX = -i.contentWidth;\n        } else if (e.altKey) {\n          deltaX = -i.containerWidth;\n        } else {\n          deltaX = -30;\n        }\n        break;\n      case 38: // up\n        if (e.metaKey) {\n          deltaY = i.contentHeight;\n        } else if (e.altKey) {\n          deltaY = i.containerHeight;\n        } else {\n          deltaY = 30;\n        }\n        break;\n      case 39: // right\n        if (e.metaKey) {\n          deltaX = i.contentWidth;\n        } else if (e.altKey) {\n          deltaX = i.containerWidth;\n        } else {\n          deltaX = 30;\n        }\n        break;\n      case 40: // down\n        if (e.metaKey) {\n          deltaY = -i.contentHeight;\n        } else if (e.altKey) {\n          deltaY = -i.containerHeight;\n        } else {\n          deltaY = -30;\n        }\n        break;\n      case 32: // space bar\n        if (e.shiftKey) {\n          deltaY = i.containerHeight;\n        } else {\n          deltaY = -i.containerHeight;\n        }\n        break;\n      case 33: // page up\n        deltaY = i.containerHeight;\n        break;\n      case 34: // page down\n        deltaY = -i.containerHeight;\n        break;\n      case 36: // home\n        deltaY = i.contentHeight;\n        break;\n      case 35: // end\n        deltaY = -i.contentHeight;\n        break;\n      default:\n        return;\n    }\n\n    if (i.settings.suppressScrollX && deltaX !== 0) {\n      return;\n    }\n    if (i.settings.suppressScrollY && deltaY !== 0) {\n      return;\n    }\n\n    element.scrollTop -= deltaY;\n    element.scrollLeft += deltaX;\n    updateGeometry(i);\n\n    if (shouldPreventDefault(deltaX, deltaY)) {\n      e.preventDefault();\n    }\n  });\n}\n","import * as CSS from '../lib/css';\nimport cls from '../lib/class-names';\nimport updateGeometry from '../update-geometry';\nimport { env } from '../lib/util';\n\nexport default function(i) {\n  const element = i.element;\n\n  let shouldPrevent = false;\n\n  function shouldPreventDefault(deltaX, deltaY) {\n    const roundedScrollTop = Math.floor(element.scrollTop);\n    const isTop = element.scrollTop === 0;\n    const isBottom =\n      roundedScrollTop + element.offsetHeight === element.scrollHeight;\n    const isLeft = element.scrollLeft === 0;\n    const isRight =\n      element.scrollLeft + element.offsetWidth === element.scrollWidth;\n\n    let hitsBound;\n\n    // pick axis with primary direction\n    if (Math.abs(deltaY) > Math.abs(deltaX)) {\n      hitsBound = isTop || isBottom;\n    } else {\n      hitsBound = isLeft || isRight;\n    }\n\n    return hitsBound ? !i.settings.wheelPropagation : true;\n  }\n\n  function getDeltaFromEvent(e) {\n    let deltaX = e.deltaX;\n    let deltaY = -1 * e.deltaY;\n\n    if (typeof deltaX === 'undefined' || typeof deltaY === 'undefined') {\n      // OS X Safari\n      deltaX = (-1 * e.wheelDeltaX) / 6;\n      deltaY = e.wheelDeltaY / 6;\n    }\n\n    if (e.deltaMode && e.deltaMode === 1) {\n      // Firefox in deltaMode 1: Line scrolling\n      deltaX *= 10;\n      deltaY *= 10;\n    }\n\n    if (deltaX !== deltaX && deltaY !== deltaY /* NaN checks */) {\n      // IE in some mouse drivers\n      deltaX = 0;\n      deltaY = e.wheelDelta;\n    }\n\n    if (e.shiftKey) {\n      // reverse axis with shift key\n      return [-deltaY, -deltaX];\n    }\n    return [deltaX, deltaY];\n  }\n\n  function shouldBeConsumedByChild(target, deltaX, deltaY) {\n    // FIXME: this is a workaround for <select> issue in FF and IE #571\n    if (!env.isWebKit && element.querySelector('select:focus')) {\n      return true;\n    }\n\n    if (!element.contains(target)) {\n      return false;\n    }\n\n    let cursor = target;\n\n    while (cursor && cursor !== element) {\n      if (cursor.classList.contains(cls.element.consuming)) {\n        return true;\n      }\n\n      const style = CSS.get(cursor);\n\n      // if deltaY && vertical scrollable\n      if (deltaY && style.overflowY.match(/(scroll|auto)/)) {\n        const maxScrollTop = cursor.scrollHeight - cursor.clientHeight;\n        if (maxScrollTop > 0) {\n          if (\n            (cursor.scrollTop > 0 && deltaY < 0) ||\n            (cursor.scrollTop < maxScrollTop && deltaY > 0)\n          ) {\n            return true;\n          }\n        }\n      }\n      // if deltaX && horizontal scrollable\n      if (deltaX && style.overflowX.match(/(scroll|auto)/)) {\n        const maxScrollLeft = cursor.scrollWidth - cursor.clientWidth;\n        if (maxScrollLeft > 0) {\n          if (\n            (cursor.scrollLeft > 0 && deltaX < 0) ||\n            (cursor.scrollLeft < maxScrollLeft && deltaX > 0)\n          ) {\n            return true;\n          }\n        }\n      }\n\n      cursor = cursor.parentNode;\n    }\n\n    return false;\n  }\n\n  function mousewheelHandler(e) {\n    const [deltaX, deltaY] = getDeltaFromEvent(e);\n\n    if (shouldBeConsumedByChild(e.target, deltaX, deltaY)) {\n      return;\n    }\n\n    let shouldPrevent = false;\n    if (!i.settings.useBothWheelAxes) {\n      // deltaX will only be used for horizontal scrolling and deltaY will\n      // only be used for vertical scrolling - this is the default\n      element.scrollTop -= deltaY * i.settings.wheelSpeed;\n      element.scrollLeft += deltaX * i.settings.wheelSpeed;\n    } else if (i.scrollbarYActive && !i.scrollbarXActive) {\n      // only vertical scrollbar is active and useBothWheelAxes option is\n      // active, so let's scroll vertical bar using both mouse wheel axes\n      if (deltaY) {\n        element.scrollTop -= deltaY * i.settings.wheelSpeed;\n      } else {\n        element.scrollTop += deltaX * i.settings.wheelSpeed;\n      }\n      shouldPrevent = true;\n    } else if (i.scrollbarXActive && !i.scrollbarYActive) {\n      // useBothWheelAxes and only horizontal bar is active, so use both\n      // wheel axes for horizontal bar\n      if (deltaX) {\n        element.scrollLeft += deltaX * i.settings.wheelSpeed;\n      } else {\n        element.scrollLeft -= deltaY * i.settings.wheelSpeed;\n      }\n      shouldPrevent = true;\n    }\n\n    updateGeometry(i);\n\n    shouldPrevent = shouldPrevent || shouldPreventDefault(deltaX, deltaY);\n    if (shouldPrevent && !e.ctrlKey) {\n      e.stopPropagation();\n      e.preventDefault();\n    }\n  }\n\n  if (typeof window.onwheel !== 'undefined') {\n    i.event.bind(element, 'wheel', mousewheelHandler);\n  } else if (typeof window.onmousewheel !== 'undefined') {\n    i.event.bind(element, 'mousewheel', mousewheelHandler);\n  }\n}\n","import updateGeometry from '../update-geometry';\nimport cls from '../lib/class-names';\nimport * as CSS from '../lib/css';\nimport { env } from '../lib/util';\n\nexport default function(i) {\n  if (!env.supportsTouch && !env.supportsIePointer) {\n    return;\n  }\n\n  const element = i.element;\n\n  function shouldPrevent(deltaX, deltaY) {\n    const scrollTop = Math.floor(element.scrollTop);\n    const scrollLeft = element.scrollLeft;\n    const magnitudeX = Math.abs(deltaX);\n    const magnitudeY = Math.abs(deltaY);\n\n    if (magnitudeY > magnitudeX) {\n      // user is perhaps trying to swipe up/down the page\n\n      if (\n        (deltaY < 0 && scrollTop === i.contentHeight - i.containerHeight) ||\n        (deltaY > 0 && scrollTop === 0)\n      ) {\n        // set prevent for mobile Chrome refresh\n        return window.scrollY === 0 && deltaY > 0 && env.isChrome;\n      }\n    } else if (magnitudeX > magnitudeY) {\n      // user is perhaps trying to swipe left/right across the page\n\n      if (\n        (deltaX < 0 && scrollLeft === i.contentWidth - i.containerWidth) ||\n        (deltaX > 0 && scrollLeft === 0)\n      ) {\n        return true;\n      }\n    }\n\n    return true;\n  }\n\n  function applyTouchMove(differenceX, differenceY) {\n    element.scrollTop -= differenceY;\n    element.scrollLeft -= differenceX;\n\n    updateGeometry(i);\n  }\n\n  let startOffset = {};\n  let startTime = 0;\n  let speed = {};\n  let easingLoop = null;\n\n  function getTouch(e) {\n    if (e.targetTouches) {\n      return e.targetTouches[0];\n    } else {\n      // Maybe IE pointer\n      return e;\n    }\n  }\n\n  function shouldHandle(e) {\n    if (e.pointerType && e.pointerType === 'pen' && e.buttons === 0) {\n      return false;\n    }\n    if (e.targetTouches && e.targetTouches.length === 1) {\n      return true;\n    }\n    if (\n      e.pointerType &&\n      e.pointerType !== 'mouse' &&\n      e.pointerType !== e.MSPOINTER_TYPE_MOUSE\n    ) {\n      return true;\n    }\n    return false;\n  }\n\n  function touchStart(e) {\n    if (!shouldHandle(e)) {\n      return;\n    }\n\n    const touch = getTouch(e);\n\n    startOffset.pageX = touch.pageX;\n    startOffset.pageY = touch.pageY;\n\n    startTime = new Date().getTime();\n\n    if (easingLoop !== null) {\n      clearInterval(easingLoop);\n    }\n  }\n\n  function shouldBeConsumedByChild(target, deltaX, deltaY) {\n    if (!element.contains(target)) {\n      return false;\n    }\n\n    let cursor = target;\n\n    while (cursor && cursor !== element) {\n      if (cursor.classList.contains(cls.element.consuming)) {\n        return true;\n      }\n\n      const style = CSS.get(cursor);\n\n      // if deltaY && vertical scrollable\n      if (deltaY && style.overflowY.match(/(scroll|auto)/)) {\n        const maxScrollTop = cursor.scrollHeight - cursor.clientHeight;\n        if (maxScrollTop > 0) {\n          if (\n            (cursor.scrollTop > 0 && deltaY < 0) ||\n            (cursor.scrollTop < maxScrollTop && deltaY > 0)\n          ) {\n            return true;\n          }\n        }\n      }\n      // if deltaX && horizontal scrollable\n      if (deltaX && style.overflowX.match(/(scroll|auto)/)) {\n        const maxScrollLeft = cursor.scrollWidth - cursor.clientWidth;\n        if (maxScrollLeft > 0) {\n          if (\n            (cursor.scrollLeft > 0 && deltaX < 0) ||\n            (cursor.scrollLeft < maxScrollLeft && deltaX > 0)\n          ) {\n            return true;\n          }\n        }\n      }\n\n      cursor = cursor.parentNode;\n    }\n\n    return false;\n  }\n\n  function touchMove(e) {\n    if (shouldHandle(e)) {\n      const touch = getTouch(e);\n\n      const currentOffset = { pageX: touch.pageX, pageY: touch.pageY };\n\n      const differenceX = currentOffset.pageX - startOffset.pageX;\n      const differenceY = currentOffset.pageY - startOffset.pageY;\n\n      if (shouldBeConsumedByChild(e.target, differenceX, differenceY)) {\n        return;\n      }\n\n      applyTouchMove(differenceX, differenceY);\n      startOffset = currentOffset;\n\n      const currentTime = new Date().getTime();\n\n      const timeGap = currentTime - startTime;\n      if (timeGap > 0) {\n        speed.x = differenceX / timeGap;\n        speed.y = differenceY / timeGap;\n        startTime = currentTime;\n      }\n\n      if (shouldPrevent(differenceX, differenceY)) {\n        e.preventDefault();\n      }\n    }\n  }\n  function touchEnd() {\n    if (i.settings.swipeEasing) {\n      clearInterval(easingLoop);\n      easingLoop = setInterval(function() {\n        if (i.isInitialized) {\n          clearInterval(easingLoop);\n          return;\n        }\n\n        if (!speed.x && !speed.y) {\n          clearInterval(easingLoop);\n          return;\n        }\n\n        if (Math.abs(speed.x) < 0.01 && Math.abs(speed.y) < 0.01) {\n          clearInterval(easingLoop);\n          return;\n        }\n\n        if (!i.element) {\n          clearInterval(easingLoop);\n          return;\n        }\n\n        applyTouchMove(speed.x * 30, speed.y * 30);\n\n        speed.x *= 0.8;\n        speed.y *= 0.8;\n      }, 10);\n    }\n  }\n\n  if (env.supportsTouch) {\n    i.event.bind(element, 'touchstart', touchStart);\n    i.event.bind(element, 'touchmove', touchMove);\n    i.event.bind(element, 'touchend', touchEnd);\n  } else if (env.supportsIePointer) {\n    if (window.PointerEvent) {\n      i.event.bind(element, 'pointerdown', touchStart);\n      i.event.bind(element, 'pointermove', touchMove);\n      i.event.bind(element, 'pointerup', touchEnd);\n    } else if (window.MSPointerEvent) {\n      i.event.bind(element, 'MSPointerDown', touchStart);\n      i.event.bind(element, 'MSPointerMove', touchMove);\n      i.event.bind(element, 'MSPointerUp', touchEnd);\n    }\n  }\n}\n","import * as CSS from './lib/css';\nimport * as DOM from './lib/dom';\nimport cls from './lib/class-names';\nimport EventManager from './lib/event-manager';\nimport processScrollDiff from './process-scroll-diff';\nimport updateGeometry from './update-geometry';\nimport { toInt, outerWidth } from './lib/util';\n\nimport clickRail from './handlers/click-rail';\nimport dragThumb from './handlers/drag-thumb';\nimport keyboard from './handlers/keyboard';\nimport wheel from './handlers/mouse-wheel';\nimport touch from './handlers/touch';\n\nconst defaultSettings = () => ({\n  handlers: ['click-rail', 'drag-thumb', 'keyboard', 'wheel', 'touch'],\n  maxScrollbarLength: null,\n  minScrollbarLength: null,\n  scrollingThreshold: 1000,\n  scrollXMarginOffset: 0,\n  scrollYMarginOffset: 0,\n  suppressScrollX: false,\n  suppressScrollY: false,\n  swipeEasing: true,\n  useBothWheelAxes: false,\n  wheelPropagation: true,\n  wheelSpeed: 1,\n});\n\nconst handlers = {\n  'click-rail': clickRail,\n  'drag-thumb': dragThumb,\n  keyboard,\n  wheel,\n  touch,\n};\n\nexport default class PerfectScrollbar {\n  constructor(element, userSettings = {}) {\n    if (typeof element === 'string') {\n      element = document.querySelector(element);\n    }\n\n    if (!element || !element.nodeName) {\n      throw new Error('no element is specified to initialize PerfectScrollbar');\n    }\n\n    this.element = element;\n\n    element.classList.add(cls.main);\n\n    this.settings = defaultSettings();\n    for (const key in userSettings) {\n      this.settings[key] = userSettings[key];\n    }\n\n    this.containerWidth = null;\n    this.containerHeight = null;\n    this.contentWidth = null;\n    this.contentHeight = null;\n\n    const focus = () => element.classList.add(cls.state.focus);\n    const blur = () => element.classList.remove(cls.state.focus);\n\n    this.isRtl = CSS.get(element).direction === 'rtl';\n    if (this.isRtl === true) {\n      element.classList.add(cls.rtl);\n    }\n    this.isNegativeScroll = (() => {\n      const originalScrollLeft = element.scrollLeft;\n      let result = null;\n      element.scrollLeft = -1;\n      result = element.scrollLeft < 0;\n      element.scrollLeft = originalScrollLeft;\n      return result;\n    })();\n    this.negativeScrollAdjustment = this.isNegativeScroll\n      ? element.scrollWidth - element.clientWidth\n      : 0;\n    this.event = new EventManager();\n    this.ownerDocument = element.ownerDocument || document;\n\n    this.scrollbarXRail = DOM.div(cls.element.rail('x'));\n    element.appendChild(this.scrollbarXRail);\n    this.scrollbarX = DOM.div(cls.element.thumb('x'));\n    this.scrollbarXRail.appendChild(this.scrollbarX);\n    this.scrollbarX.setAttribute('tabindex', 0);\n    this.event.bind(this.scrollbarX, 'focus', focus);\n    this.event.bind(this.scrollbarX, 'blur', blur);\n    this.scrollbarXActive = null;\n    this.scrollbarXWidth = null;\n    this.scrollbarXLeft = null;\n    const railXStyle = CSS.get(this.scrollbarXRail);\n    this.scrollbarXBottom = parseInt(railXStyle.bottom, 10);\n    if (isNaN(this.scrollbarXBottom)) {\n      this.isScrollbarXUsingBottom = false;\n      this.scrollbarXTop = toInt(railXStyle.top);\n    } else {\n      this.isScrollbarXUsingBottom = true;\n    }\n    this.railBorderXWidth =\n      toInt(railXStyle.borderLeftWidth) + toInt(railXStyle.borderRightWidth);\n    // Set rail to display:block to calculate margins\n    CSS.set(this.scrollbarXRail, { display: 'block' });\n    this.railXMarginWidth =\n      toInt(railXStyle.marginLeft) + toInt(railXStyle.marginRight);\n    CSS.set(this.scrollbarXRail, { display: '' });\n    this.railXWidth = null;\n    this.railXRatio = null;\n\n    this.scrollbarYRail = DOM.div(cls.element.rail('y'));\n    element.appendChild(this.scrollbarYRail);\n    this.scrollbarY = DOM.div(cls.element.thumb('y'));\n    this.scrollbarYRail.appendChild(this.scrollbarY);\n    this.scrollbarY.setAttribute('tabindex', 0);\n    this.event.bind(this.scrollbarY, 'focus', focus);\n    this.event.bind(this.scrollbarY, 'blur', blur);\n    this.scrollbarYActive = null;\n    this.scrollbarYHeight = null;\n    this.scrollbarYTop = null;\n    const railYStyle = CSS.get(this.scrollbarYRail);\n    this.scrollbarYRight = parseInt(railYStyle.right, 10);\n    if (isNaN(this.scrollbarYRight)) {\n      this.isScrollbarYUsingRight = false;\n      this.scrollbarYLeft = toInt(railYStyle.left);\n    } else {\n      this.isScrollbarYUsingRight = true;\n    }\n    this.scrollbarYOuterWidth = this.isRtl ? outerWidth(this.scrollbarY) : null;\n    this.railBorderYWidth =\n      toInt(railYStyle.borderTopWidth) + toInt(railYStyle.borderBottomWidth);\n    CSS.set(this.scrollbarYRail, { display: 'block' });\n    this.railYMarginHeight =\n      toInt(railYStyle.marginTop) + toInt(railYStyle.marginBottom);\n    CSS.set(this.scrollbarYRail, { display: '' });\n    this.railYHeight = null;\n    this.railYRatio = null;\n\n    this.reach = {\n      x:\n        element.scrollLeft <= 0\n          ? 'start'\n          : element.scrollLeft >= this.contentWidth - this.containerWidth\n          ? 'end'\n          : null,\n      y:\n        element.scrollTop <= 0\n          ? 'start'\n          : element.scrollTop >= this.contentHeight - this.containerHeight\n          ? 'end'\n          : null,\n    };\n\n    this.isAlive = true;\n\n    this.settings.handlers.forEach(handlerName => handlers[handlerName](this));\n\n    this.lastScrollTop = Math.floor(element.scrollTop); // for onScroll only\n    this.lastScrollLeft = element.scrollLeft; // for onScroll only\n    this.event.bind(this.element, 'scroll', e => this.onScroll(e));\n    updateGeometry(this);\n  }\n\n  update() {\n    if (!this.isAlive) {\n      return;\n    }\n\n    // Recalcuate negative scrollLeft adjustment\n    this.negativeScrollAdjustment = this.isNegativeScroll\n      ? this.element.scrollWidth - this.element.clientWidth\n      : 0;\n\n    // Recalculate rail margins\n    CSS.set(this.scrollbarXRail, { display: 'block' });\n    CSS.set(this.scrollbarYRail, { display: 'block' });\n    this.railXMarginWidth =\n      toInt(CSS.get(this.scrollbarXRail).marginLeft) +\n      toInt(CSS.get(this.scrollbarXRail).marginRight);\n    this.railYMarginHeight =\n      toInt(CSS.get(this.scrollbarYRail).marginTop) +\n      toInt(CSS.get(this.scrollbarYRail).marginBottom);\n\n    // Hide scrollbars not to affect scrollWidth and scrollHeight\n    CSS.set(this.scrollbarXRail, { display: 'none' });\n    CSS.set(this.scrollbarYRail, { display: 'none' });\n\n    updateGeometry(this);\n\n    processScrollDiff(this, 'top', 0, false, true);\n    processScrollDiff(this, 'left', 0, false, true);\n\n    CSS.set(this.scrollbarXRail, { display: '' });\n    CSS.set(this.scrollbarYRail, { display: '' });\n  }\n\n  onScroll(e) {\n    if (!this.isAlive) {\n      return;\n    }\n\n    updateGeometry(this);\n    processScrollDiff(this, 'top', this.element.scrollTop - this.lastScrollTop);\n    processScrollDiff(\n      this,\n      'left',\n      this.element.scrollLeft - this.lastScrollLeft\n    );\n\n    this.lastScrollTop = Math.floor(this.element.scrollTop);\n    this.lastScrollLeft = this.element.scrollLeft;\n  }\n\n  destroy() {\n    if (!this.isAlive) {\n      return;\n    }\n\n    this.event.unbindAll();\n    DOM.remove(this.scrollbarX);\n    DOM.remove(this.scrollbarY);\n    DOM.remove(this.scrollbarXRail);\n    DOM.remove(this.scrollbarYRail);\n    this.removePsClasses();\n\n    // unset elements\n    this.element = null;\n    this.scrollbarX = null;\n    this.scrollbarY = null;\n    this.scrollbarXRail = null;\n    this.scrollbarYRail = null;\n\n    this.isAlive = false;\n  }\n\n  removePsClasses() {\n    this.element.className = this.element.className\n      .split(' ')\n      .filter(name => !name.match(/^ps([-_].+|)$/))\n      .join(' ');\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from 'dompack';\n\n/** @short Parse the CTA configuration from a data-ctaconfig attribute */\nexport function parseManagedCTAConfig(ctaconfig) {\n  const config = JSON.parse(ctaconfig);\n  // Parse datetimes\n  config.publish_from = Date.parse(config.publish_from) || null;\n  config.publish_until = Date.parse(config.publish_until) || null;\n  // Convert regexes\n  if (config.regexes)\n    config.regexes.forEach(_ => _.regex = new RegExp(_.regex, \"i\"));\n  // Convert search queries\n  if (config.queries)\n    config.queries = config.queries.map((regex, idx) => {\n      const r = new RegExp(regex, \"i\");\n      r._term = config._queryterms[idx];\n      return r;\n    });\n  return config;\n}\n\n/** @short Thrown by tryMatchCTAConfig if the given properties don't match the CTA's configuration\n*/\nexport class CTAMatchError extends Error {\n  constructor(prop, values, ...params) {\n    super(...params);\n    this.name = \"CTAMatchError\";\n    this._prop = prop;\n    this._values = values;\n  }\n\n  /** @short The configuration property that failed\n      @long One of `publish_from`, `publish_until`, `countries`, `beacons`, `regexes` or `queries`\n  */\n  get prop() {\n    return this._prop;\n  }\n\n  /** @short The values that failed\n      @long This object holds the expected and received values, which may be different based on the property and context:\n\n          | prop | values |\n          | :--- | :----- |\n          | `publish_from` | `expected`: the date after which the CTA is shown<br>`got`: the 'now' date that was used for this check |\n          | `publish_until` | `expected`: the date before which the CTA is shown<br>`got`: the 'now' date that was used for this check |\n          | `countries` | `expected`: the list of country codes for which the CTA is shown<br>`got`: the country code that was used for this check |\n          | `beacons` | if neither `expected` nor `got` are present, there were no beacons triggered<br><br>`expected`: if only `expected` is present, the tag of the beacon that was not triggered<br><br>`expected`: if both `expected` and `got` are present, the date before which the beacon had to be triggered to show the CTA<br>`got`: the 'now' date that was used for this check<br>`tag`: the tag of the failing beacon |\n          | `regexes` | `expected`: if present, the regex that matched the url (causing the CTA _not_ to be shown) or that caused an error, if not present, no regex matched the url<br>`got`: if present, the url that was used for this check<br>`error`: if present, the this error was thrown while matching the regex |\n          | `queries` | `expected`: if not present, no query regex matched the query, if present, the query regex that caused an error<br>`got`: if present, the query that was used for this check<br>`error`: if present, the this error was thrown while matching the query regex |\n  */\n  get values() {\n    return this._values;\n  }\n}\n\n/*\n  @short Check if the given props match the given config\n  @long This function throws a CTAMatchError if the props don't match the config\n  @cell config.publish_from\n  @cell config.publish_until\n  @cell config.countries\n  @cell config.beacons\n  @cell config.regexes\n  @cell config.queries\n  @cell props.country\n  @cell props.beacons\n  @cell props.url\n  @cell props.query\n*/\nexport function tryMatchCTAConfig(config, props) {\n  const now = props.date || Date.now();\n  if (dompack.debugflags.umc)\n    console.info(`[umc] tryMatchCTAConfig`, config, props, now);\n\n  if (config.publish_from && now < config.publish_from)\n    throw new CTAMatchError(\"publish_from\", { expected: config.publish_from, got: now }, `Not yet published: ${now} < ${config.publish_from}`);\n  if (config.publish_until && now >= config.publish_until)\n    throw new CTAMatchError(\"publish_until\", { expected: config.publish_until, got: now }, `No longer published: ${now} >= ${config.publish_until}`);\n  if (config.countries && config.countries.length && (!props.country || !config.countries.includes(props.country)))\n    throw new CTAMatchError(\"countries\", { expected: config.countries, got: props.country }, `'${props.country}' not in [ '${config.countries.join(\"', '\")}' ]`);\n  if (config.beacons && config.beacons.length) {\n    if (!props.beacons)\n      throw new CTAMatchError(\"beacons\", {}, `No beacons triggered`);\n\n    let hitanybeacon;\n\n    for (const beacon of config.beacons) {\n      if (!props.beacons[beacon.tag]) {\n        if (config.anybeacon)\n          continue;\n        throw new CTAMatchError(\"beacons\", { expected: beacon.tag }, `Beacon ${beacon.tag} not triggered`);\n      }\n\n      const maxtime = beacon.maxdays * 24 * 60 * 60 * 1000;\n      const beacondate = parseInt(props.beacons[beacon.tag]);\n      if (maxtime > 0 && now > beacondate + maxtime) {\n        if (config.anybeacon)\n          continue;\n\n        throw new CTAMatchError(\"beacons\", { expected: beacondate + maxtime, got: now, tag: beacon.tag }, `Beacon ${beacon.tag} too old: ${now} > ${beacondate} + ${maxtime}`);\n      }\n\n      hitanybeacon = true;\n    }\n\n    if (!hitanybeacon)\n      throw new CTAMatchError(\"beacons\", { expected: config.beacons }, `No allowed beacon triggered`);\n  }\n  if (config.regexes && config.regexes.length) {\n    let matching_regex = null;\n    let only_excludes = true;\n    for (const cta_regex of config.regexes) {\n      only_excludes = only_excludes && cta_regex.exclude;\n      try {\n        if (cta_regex.regex.test(props.url)) {\n          matching_regex = cta_regex;\n          break;\n        }\n      } catch (e) {\n        throw new CTAMatchError(\"regexes\", { expected: cta_regex.regex.source, error: e }, `Error while trying to match regular expression '${cta_regex.regex.source}': ${e}`);\n      }\n    }\n    if (matching_regex) {\n      if (matching_regex.exclude)\n        throw new CTAMatchError(\"regexes\", { expected: matching_regex.regex.source, got: props.url }, `URL ${props.url} matches exclusion regular expression '${matching_regex.regex.source}'`);\n      if (dompack.debugflags.umc)\n        console.info(`[umc] URL ${props.url} matches inclusion regular expression '${matching_regex.regex.source}'`);\n    } else if (only_excludes) {\n      // If there are only 'exclude' regexes, and the url didn't match any, we can show the cta\n      if (dompack.debugflags.umc)\n        console.info(`[umc] URL ${props.url} not matching any regular expression`);\n    } else {\n      // The url matched none of the 'include' regexes, so don't show this\n      throw new CTAMatchError(\"regexes\", { got: props.url }, `URL ${props.url} not matching any regular expression`);\n    }\n  }\n  if (config.queries && config.queries.length) {\n    for (const regex of config.queries) {\n      try {\n        if (regex.test(props.query)) {\n          if (dompack.debugflags.umc)\n            console.info(`[umc] Query '${props.query}' matches search term '${regex.source}'`);\n          return;\n        }\n      } catch (e) {\n        throw new CTAMatchError(\"queries\", { expected: regex.source, error: e }, `Error while trying to match search term '${regex.source}': ${e}`);\n      }\n    }\n    throw new CTAMatchError(\"queries\", { got: props.query || \"\" }, `Query '${props.query || \"\"}' not matching any search term`);\n  }\n}\n","import { createClient } from '@webhare/jsonrpc-client';\n\nlet requestbarrier: Promise<void> | undefined; //TODO replace with serialize (or wait until we have it as a decorator)\n\ninterface GetIPInfoOptions {\n  /** Language code in which you want the country name */\n  countrylang?: string;\n  /** How long to trust the previously cached result in days (default: 7) */\n  cachedays?: number;\n}\n\ninterface PublisherRPCCLient {\n  getIPInfo(options: { countrylang?: string }): Promise<{ country: string; countryname?: string }>;\n}\n\nasync function getIPInfoIntoCache(options?: GetIPInfoOptions) {\n  const reqoptions = { countrylang: options?.countrylang };\n  const result = await createClient<PublisherRPCCLient>(\"publisher:rpc\").getIPInfo(reqoptions);\n  let geoinfo = {\n    countrycode: result ? result.country : \"\",\n    creationdate: Date.now(),\n  };\n  if (result && options?.countrylang)\n    geoinfo = { ...geoinfo, [\"countrylang_\" + options.countrylang]: result.countryname };\n\n  localStorage.setItem(\"_wh.geoinfo\", JSON.stringify(geoinfo));\n  return geoinfo;\n}\n\nexport async function getIPInfo(options?: { countrylang: string }): Promise<{ countrycode: string; countryname: string } | null>;\nexport async function getIPInfo(options?: GetIPInfoOptions): Promise<{ countrycode: string; countryname?: string } | null>;\n\n/** Get geoip fields\n    @returns Object with country code and possible name, null if unknown */\nexport async function getIPInfo(options?: GetIPInfoOptions): Promise<{ countrycode: string; countryname?: string } | null> {\n  //TODO return more than country name and code once we need it.\n\n  const finaloptions = {\n    cachedays: 7,\n    countrylang: \"\",\n    ...options\n  };\n\n  if (requestbarrier)\n    await requestbarrier; //first let parallel requests complete and set _wh.geoinfo\n\n  const barrier = Promise.withResolvers<void>();\n  requestbarrier = barrier.promise;\n\n  let geoinfo;\n  try {\n    let curgeoinfotext = localStorage.getItem(\"_wh.geoinfo\");\n\n    if (!curgeoinfotext) { //test local storage\n      localStorage.setItem(\"_wh.geoinfo\", JSON.stringify({ dummy: \"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx\" }));\n      curgeoinfotext = localStorage.getItem(\"_wh.geoinfo\") || '';\n    }\n    geoinfo = JSON.parse(curgeoinfotext);\n  } catch (e) {\n    console.error(e);\n    barrier.resolve();\n    return null; //localstorage is broken\n  }\n\n  let refetch = false;\n\n  if (!geoinfo.creationdate || (geoinfo.creationdate + finaloptions.cachedays * 86400 * 1000) <= Date.now()) //is answer still valid?\n    refetch = true;\n  else if (finaloptions.countrylang && geoinfo.countrycode && !((\"countrylang_\" + finaloptions.countrylang) in geoinfo))\n    refetch = true;   //If the countrylang isn't requested.. OR we have it... OR we don't have it because we didn't even have the country figured out in the cached call... we can continue\n\n  if (refetch)\n    geoinfo = await getIPInfoIntoCache(options);\n\n  barrier.resolve();\n\n  if (geoinfo && geoinfo.countrycode) {\n    const retval: { countrycode: string; countryname?: string } = { countrycode: geoinfo.countrycode };\n    if (finaloptions.countrylang)\n      retval.countryname = geoinfo[\"countrylang_\" + finaloptions.countrylang];\n\n    return retval;\n  }\n\n  return null;\n}\n\n/** Get the current country code\n    @returns Promise resolving to 2-letter countrycode, or null if unknown */\nexport async function getCountryCode(options?: GetIPInfoOptions) {\n  const data = await getIPInfo(options);\n  return data ? data.countrycode : null;\n}\n","import * as storage from \"@webhare/dompack/src/storage\";\n\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const getCookie = storage.getCookie;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const setCookie = storage.setCookie;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const deleteCookie = storage.deleteCookie;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const listCookies = storage.listCookies;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const getLocal = storage.getLocal;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const setLocal = storage.setLocal;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const getSession = storage.getSession;\n/** @deprecated Import \\@webhare/dompack for storage APIs */\nexport const setSession = storage.setSession;\n","import { getCookie, setCookie, listCookies, deleteCookie } from \"@webhare/dompack\";\n/** @deprecated Use \\@webhare/dompack listCookies */\nexport const list = listCookies;\n/** @deprecated Use \\@webhare/dompack getCookie */\nexport const read = getCookie;\n/** @deprecated Use \\@webhare/dompack setCookie */\nexport const write = setCookie;\n/** @deprecated Use \\@webhare/dompack deleteCookie */\nexport const remove = deleteCookie;\n","import * as dompack from \"@webhare/dompack\";\nimport \"./cookiebar.scss\";\nimport { throwError } from \"@webhare/std\";\nimport * as consenthandler from '@mod-publisher/js/analytics/consenthandler';\nimport { pushToDataLayer } from \"@webhare/frontend\";\n\n//cookiedomain should be toplevel domain to make sure utwente.nl doesn't overwrite lower cookies\nconst cookiedomain = '.' + (document.domain.split('.').slice(location.host.match(/webhare.(nl|dev)$/) ? 1 : -2).join('.'));\n\ninterface CookieSettings {\n  c: boolean;\n  v?: 1;\n  lc?: string;\n  isset?: boolean;\n}\n\nfunction getLangCode(): \"en\" | \"nl\" | \"de\" {\n  const lang = ((document.documentElement.lang || \"\").split('-')[0].toLowerCase());\n  return [\"nl\", \"de\"].includes(lang) ? lang as \"nl\" | \"de\" : \"en\";\n}\n\nclass UtwenteCookies {\n  _consent = false;\n  cookieName = \"utwente__avgconsent\";\n  /** @deprecated some old code still checks this to see if AVG rules are in effect yet */\n  readonly avg = true as const;\n\n  constructor() {\n  }\n\n  reset(): void {\n    dompack.deleteCookie(this.cookieName, { domain: cookiedomain });\n    dompack.setLocal(\"utwente-design:cookiebar-variant\", null);\n    location.reload();\n  }\n  info(): void {\n    console.log(\"[utwente-avg-api] Cookiedomain = \" + cookiedomain);\n    console.log(\"[utwente-avg-api] Prefs = \" + JSON.stringify(utwenteCookies._getPrefs()));\n    console.log(\"[utwente-avg-api] Settings = \" + JSON.stringify({ consent: utwenteCookies._consent }));\n  }\n\n  private getNewTexts(): {\n    privacylink: string;\n    cookielink: string;\n    accept: string;\n    reject: string;\n  } {\n    const link = \"https://\" + (location.host.match(/webhare.nl$/) ? 'utwente' : 'www') + cookiedomain;\n    switch (getLangCode()) {\n      case \"nl\":\n        return {\n          privacylink: 'https://www.utwente.nl/over-de-website/',\n          cookielink: link + '/nl/cookies/',\n          accept: \"Accepteren\",\n          reject: \"Weigeren\"\n        };\n      case \"de\":\n        return {\n          privacylink: 'https://www.utwente.nl/de/ueber-unsere-webseite/',\n          cookielink: link + '/de/cookies/',\n          accept: \"Zustimmen\",\n          reject: \"Ablehnen\"\n        };\n      default:\n        return {\n          privacylink: 'https://www.utwente.nl/en/about-our-website/',\n          cookielink: link + '/en/cookies/',\n          accept: \"Accept\",\n          reject: \"Reject\"\n        };\n    }\n  }\n\n  private getNewContent(cookielink: string, privacylink: string) {\n    switch (getLangCode()) {\n      case 'nl':\n        return [\n          <h2>Cookies</h2>,\n          <p>We gebruiken cookies en vergelijkbare technologieën en verwerken je persoonlijke gegevens (bijv. IP-adres) voor gepersonaliseerde content, advertenties en voor media integraties van externe aanbieders.\n            Voor het gebruiken en analyseren van de website plaatsen wij altijd functionele en strikt analytische cookies. De gegevensverwerking voor niet-functionele en niet-analytische cookies vereist jouw toestemming.\n            Voor meer informatie over het gebruik van je gegevens, bezoek onze <a href={privacylink}>privacyverklaring</a> of ons <a href={cookielink}>cookiebeleid</a>.</p>\n        ];\n      case 'de':\n        return [\n          <h2>Cookies</h2>,\n          <p>Wir verwenden Cookies und ähnliche Technologien und verarbeiten deine personenbezogenen Daten (z.B. IP-Adresse) für personalisierte Inhalte, Werbung und die Einbindung von Drittanbieter-Medien.\n            Funktionale und strikt analytische Cookies werden immer gesetzt. Für nicht notwendige und nicht analytische Cookies benötigen wir deine Einwilligung. Weitere Informationen findest du in\n            unserer <a href={privacylink}>Datenschutzerklärung</a> oder unseren <a href={cookielink}>Cookie-Richtlinien</a>.</p>\n        ];\n      case 'en':\n        return [\n          <h2>Cookies</h2>,\n          <p>We use cookies and similar technologies to process your personal data (e.g. IP address) for personalised content, ads and third-party media integrations. Functional and strictly analytical cookies are always set.\n            Non-essential and non-analytical cookies require your permission. For more details, see our <a href={privacylink}>privacy statement</a> or <a href={cookielink}>cookie policy</a>.</p>\n        ];\n    }\n  }\n\n  //NOTE cannot rename, this is a public API (at least for the cookie test page)\n  _showBar(): void {\n    const reject = () => {\n      utwenteCookies._setPrefs({ c: false });\n      d.close();\n    };\n    const accept = () => {\n      utwenteCookies._setPrefs({ c: true });\n      d.close();\n    };\n    const texts = this.getNewTexts();\n    const buttons = [\n      <button type=\"button\" class=\"wh-form__button\" onClick={reject}>{texts.reject}</button>,\n      <button type=\"button\" class=\"wh-form__button\" onClick={accept}>{texts.accept}</button>\n    ];\n\n    const d: HTMLDialogElement = <dialog data-nosnippet class=\"utwente-cookiedialog\">\n      {this.getNewContent(texts.cookielink, texts.privacylink)}\n      <div class=\"utwente-cookiedialog__buttons\">{buttons}</div>\n    </dialog>;\n\n    document.body.appendChild(d);\n    d.showModal();\n    if (getComputedStyle(d).display === \"none\")\n      d.close(); //user is hiding cookie bar, eg by browser plugin. close the dialog then\n    else\n      (document.activeElement as HTMLElement)?.blur?.(); //prevent focus ring, https://gitlab.webhare.com/utwente/utwente_base/-/issues/2414#note_211171\n  }\n\n  _getPrefs(): CookieSettings {\n    try {\n      let prefs = JSON.parse(dompack.getCookie(this.cookieName) || '{}') as CookieSettings;\n      //@ts-expect-error This type violation is how we detect Ghostery etc setting broken/blocked cookies. https://gitlab.webhare.com/utwente/utwente_base/-/issues/2414#note_211588\n      if (prefs?.v === \"1\") {\n        this.cookieName = \"utwente__cookieprefs\"; //new cookie name\n        prefs = JSON.parse(dompack.getCookie(this.cookieName) || '{}') as CookieSettings;\n      }\n      if (prefs.v === 1)\n        return { ...prefs, isset: true };\n    } catch (e) {\n      console.log(\"Error parsing cookie\", e);\n    }\n\n    return {\n      isset: false, //nothing recorded yet\n      c: false\n    };\n  }\n  _handlePrefs(prefs: CookieSettings, { ischange = false }) {\n    utwenteCookies._consent = Boolean(prefs.c);\n    try {\n      //we always fire this event as soon as we have cookie information, geoversity needs this trigger. https://gitlab.webhare.com/utwente/utwente_base/-/issues/2414#note_228507\n      const vars = { utwenteAnalytics: true, utwenteConsent: utwenteCookies._consent };\n      pushToDataLayer({ event: \"utwente.cookiesettings\", ...vars });\n      if (ischange)\n        pushToDataLayer({ event: \"utwente.cookieconsent\", ...vars });\n\n      document.documentElement.classList[utwenteCookies._consent ? \"add\" : \"remove\"](\"utwente--consent\");\n\n      const evt = document.createEvent(\"HTMLEvents\");\n      evt.initEvent(\"wh:consent-change\", true, false);\n      document.dispatchEvent(evt);\n    } catch (e) {\n      console.error(e);\n    }\n  }\n  _setCookie(newsettings: CookieSettings) {\n    const setting = JSON.stringify(newsettings);\n    const expires = new Date(Date.now() + 86400 * 365 * 1000);\n    dompack.setCookie(this.cookieName, setting, { domain: cookiedomain, expires, sameSite: \"None\", secure: true });\n  }\n  _setPrefs(newprefs: { c?: boolean }) {\n    const curprefs = this._getPrefs();\n    const newsettings: CookieSettings = {\n      c: newprefs.c ?? curprefs.c,\n      v: 1,\n      lc: (new Date).toUTCString(),\n    };\n\n    utwenteCookies._setCookie(newsettings);\n    newsettings.isset = true;\n    utwenteCookies._handlePrefs(newsettings, { ischange: true });\n  }\n\n  setup(): void {\n    //get the current cookie\n    const prefs = utwenteCookies._getPrefs();\n    utwenteCookies._handlePrefs(prefs, { ischange: false });\n\n    if (prefs.isset) {\n      utwenteCookies._setCookie(prefs); //prefs already set - refresh lifetime\n    } else {\n      if (document.documentElement.classList.contains(\"utwente--nocookiebar\")  //page opting out of cookiebar (eg. privacy statement)\n        || document.documentElement.classList.contains(\"wh-isstaticdownload\")\n        || document.documentElement.classList.contains(\"wh-widgetpreview\")\n        || document.querySelector(\"form.ut-cookiewidget, div.widget-cookiesettings\") //pages containing the cookie widget\n        || location.host.match(/utchallenge.nl$/)  //they're no longer compatible\n        || window.top !== window.self) //running in a frame - we normally don't permit this it must be a CI test or internal use, hide the cookiebar\n        return;\n\n      utwenteCookies._showBar();\n    }\n  }\n  _save(): void {\n    const c = document.querySelector<HTMLInputElement>(\"#utwenteCookiesConsent\")?.checked || false;\n    this._setPrefs({ c });\n  }\n  _accept(): void { //NOTE still used externally!\n    this.acceptMarketingCookies();\n  }\n  acceptMarketingCookies(): void { // invoked when activated by a consent layer\n    this._setPrefs({ c: true });\n  }\n  getConsent(): boolean {\n    return utwenteCookies._consent;\n  }\n  getAnalytics(): boolean {\n    return true;\n  }\n  getCookieSettingsLink() {\n    return this.getNewTexts().cookielink;\n  }\n  getExplicitAnalytics(): boolean {\n    return true;\n  }\n}\n\nconst utwenteCookies = new UtwenteCookies;\n\nexport function setupCookieWidget(form: HTMLFormElement): void {\n  const thirdparty = form.elements.namedItem(\"thirdparty\") as HTMLInputElement ?? throwError(\"Missing checkbox named 'thirdparty' in cookie settings form\");\n\n  thirdparty.checked = utwenteCookies.getConsent();\n\n  thirdparty.addEventListener(\"change\", ev => {\n    utwenteCookies._setPrefs({ c: thirdparty.checked });\n  });\n\n  form.inert = false; //activate!\n}\n\nexport function setupConsentHandlerForUtwente(): void {\n  //Link cookie api to consent handler\n  function syncConsent() {\n    const consent: string[] = [];\n    if (utwenteCookies.getConsent())\n      consent.push('marketing');\n    if (utwenteCookies.getAnalytics())\n      consent.push('analytics');\n    consenthandler.setConsent(consent);\n  }\n\n  consenthandler.setup(''); //setup consent handler in listening mode\n  window.addEventListener(\"wh:consent-change\", syncConsent);\n  syncConsent();\n\n  dompack.register<HTMLInputElement>(\".utwente__marketing__checkbox\", node => node.addEventListener(\"change\", function () {\n    //accepting marketing cookies\n    if (node.checked)\n      utwenteCookies._setPrefs({ c: true });\n  }));\n}\n\ndompack.onDomReady(() => utwenteCookies.setup());\n\nwindow.utwenteSetConsent = (__ignored: boolean, thirdparty: boolean) => utwenteCookies._setPrefs({ c: thirdparty });\nwindow.utwenteResetCookies = () => utwenteCookies.reset();\n\nexport default utwenteCookies;\n","/* To verify tree shaking viability, try:\n   whcd\n   cd whtree\n   echo 'import \"@webhare/frontend\"' | node_modules/.bin/esbuild --loader:.css=empty --tsconfig=tsconfig.json --bundle --minify\n*/\n\n// This gets TypeScript to refer to us by our @webhare/... name in auto imports:\ndeclare module \"@webhare/frontend\" {\n}\n\nimport { onDomReady } from \"@webhare/dompack\";\nexport { frontendConfig, getFrontendData, getSiteRoot } from \"./init\";\nexport { startSSOLogin, login, setupWRDAuth, isLoggedIn, logout, getUserInfo, setupWebHareSSOTrigger } from \"./auth\";\nexport { loadAssetPack, setupAuthorMode, type AuthorModeOptions } from \"./authormode\";\nexport { setPxlOptions, sendPxl, getPxlUserId, getPxlSessionId, setupFormAnalytics, type PxlData } from \"./pxl\";\nexport { getRemoteIPAddress, getGeoIPInfo, type GetIPInfoOptions, type GeoIPInfoResult } from \"./analytics\";\nexport { setupGTM, setupFormAnalyticsForGTM, pushToDataLayer, setupDataLayerTags, getCurrentDataLayerVariables } from \"./gtm\";\nexport { setupLinksInNewWindow, type LinkOpenOptions } from \"./linkhandler\";\n\nexport type * from \"./gtm-types\";\n\n// we shouldn't deprecate navigateTo exported from frontend. in fact it makes more sense to export it from frontend than env as it's browser-only\nexport { navigateTo } from \"@webhare/env\";\n\n/** Registry for data we receive from the backend */\nexport interface FrontendDataTypes {\n}\n\n/** Registry for expected PXL formats */\nexport interface PxlDataTypes {\n}\n\n/** Test whether the current page is being iframed in the WebHare test framework */\nexport function isInTestFramework(): boolean {\n  if (window.top !== window) { //in a frame\n    try {\n      if ((window.top as { __testframework?: unknown })?.__testframework)\n        return true;//we're inside a testframe, pretend to be the parent\n    } catch (ignore) {\n    }\n  }\n  return false;\n}\n\nfunction postRenderChecks() {\n  const log = document.getElementById(\"wh-console-log\");\n  if (log) {\n    const logtext = atob(log.textContent || \"\");\n    console.group(\"[etr] Server-side console output\");\n    console.log(logtext);\n    console.groupEnd();\n  }\n}\n\nonDomReady(postRenderChecks);\n","import { createClient } from \"@webhare/jsonrpc-client\";\nimport { type NavigateInstruction, navigateTo } from \"@webhare/env\";\nimport * as dompack from '@webhare/dompack';\nimport type { LoginOptions } from \"@webhare/auth/src/identity\";\nimport { rpc } from \"@webhare/rpc\";\n\n//NOTE: Do *NOT* load @webhare/frontend or we enforce the new CSS reset!\nimport { getFrontendData } from '@webhare/frontend/src/init';\nimport { PublicCookieSuffix, type LoginErrorCode, type LoginResult, type LoginTweaks } from \"@webhare/auth/src/shared\";\nimport { parseTyped, toSnakeCase, type ToSnakeCase } from \"@webhare/std\";\nimport type WRDAuthenticationProvider from \"@mod-wrd/js/auth\";\nimport type { OAuth2PromptFlag } from \"@webhare/auth/src/oauth2-client\";\n\n/** WRDAuth configuration */\nexport interface WRDAuthOptions {\n  /** Callback that is invoked after a succesful login. If not set the page will be reloaded. */\n  onLogin?: () => Promise<void> | void;\n}\n\nexport interface PublicAuthData {\n  expiresMs: number;\n  userInfo?: object | null;\n  persistent?: boolean;\n}\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"wrd:auth\": {\n      /** WRDAuth cookiename (used to store userinfo and expiry) */\n      cookiename: string;\n    };\n  }\n}\n\ndeclare global {\n  interface Window {\n    $wh$legacyAuthProvider: WRDAuthenticationProvider;\n    triggerWebHareSSO?: (tag: string, options?: SSOLoginOptions) => Promise<void>;\n  }\n}\n\n/** Current authoptions. undefined if setupWRDAuth hasn't been invoked yet */\nlet authOptions: WRDAuthOptions | undefined;\n\n/** Get current login cookie. If empty, wrdauth is not initialized here */\nfunction getCookieName(): string | null {\n  const settings = getFrontendData(\"wrd:auth\", { allowMissing: true });\n  return settings?.cookiename || null;\n}\n\nfunction getAuthLocalData(): PublicAuthData | null {\n  const c = getCookieName();\n  if (!c)\n    return null;\n\n  try {\n    return parseTyped(dompack.getCookie(c + PublicCookieSuffix)!) as PublicAuthData;\n  } catch {\n    return null;\n  }\n}\n\nasync function submitLoginForm(node: HTMLFormElement, event: SubmitEvent) {\n  if (node.propWhFormhandler)\n    return; //already handled by publisher forms so we'll defer to that\n  dompack.stop(event);\n\n  const username = (node.elements.namedItem(\"login\") as HTMLInputElement)?.value;\n  const password = (node.elements.namedItem(\"password\") as HTMLInputElement)?.value;\n  const site = (node.elements.namedItem(\"site\") as HTMLInputElement)?.value || undefined;\n  const returnto = (node.elements.namedItem(\"returnto\") as HTMLInputElement)?.value || undefined;\n  const persistentlogin = (node.elements.namedItem(\"persistent\") as HTMLInputElement)?.checked;\n  if (!login || !password)\n    throw new Error(`submitLoginForm: required elements login/password not set or missing`);\n\n  using lock = dompack.flagUIBusy({ modal: true });\n  void (lock);\n\n  const loginresult = await login(username, password, {\n    persistent: persistentlogin,\n    site,\n    returnTo: returnto ? new URL(returnto, location.href).toString() : location.href.split('#')[0]\n  });\n  if (loginresult.loggedIn) {\n    refreshLoginStatus();\n    if (loginresult.navigateTo.type === \"redirect\" && loginresult.navigateTo.url.split('#')[0] === location.href.split('#')[0]  //stay on same page\n      && authOptions?.onLogin) {\n\n      if (loginresult.navigateTo.url.includes('#')) //execute any #hash instruction\n        history.replaceState(null, \"\", loginresult.navigateTo.url.substring(loginresult.navigateTo.url.indexOf('#')));\n\n      await authOptions.onLogin();\n    } else {\n      //Reload the page to get the new login status - TODO put this behind a 'login state change' event and allow users to cancel it if they can deal with login/logout on-page\n      console.log(\"Post login redirect\", loginresult.navigateTo);\n      navigateTo(loginresult.navigateTo);\n    }\n  } else if (\"navigateTo\" in loginresult) {\n    console.log(\"Login incomplete, redirecting to\", loginresult.navigateTo);\n    navigateTo(loginresult.navigateTo);\n  } else\n    failLogin(loginresult.error ?? loginresult.code, { code: loginresult.code, data: \"\" }, node); //FIXME restore the code & data members from old wrdauth\n}\n\nfunction refreshLoginStatus() {\n  const loggedIn = isLoggedIn();\n  document.documentElement.classList.toggle(\"wh-wrdauth--isloggedin\", loggedIn);\n\n  window.$wh$legacyAuthProvider?.refresh();\n}\n\n/** Return whether a user's currently logged in */\nexport function isLoggedIn(): boolean {\n  return (getAuthLocalData()?.expiresMs || 0) > Date.now();\n}\n\n/** Setup WRDAuth frontend integration */\nexport function setupWRDAuth(options?: WRDAuthOptions) {\n  if (authOptions)\n    throw new Error(`Duplicate setupWRDAuth call`);\n\n  authOptions = { ...options };\n\n  dompack.register<HTMLFormElement>('form.wh-wrdauth__loginform,form.wh-wrdauth-login__form', node => {\n    node.setAttribute(\"data-wh-wrdauth-attached\", \"\");\n    dompack.addDocEventListener(node, \"submit\", evt => submitLoginForm(node, evt));\n  });\n  dompack.register('.wh-wrdauth__logout', node => {\n    function handleLogoutClick(event: Event) {\n      dompack.stop(event);\n\n      //letting rejections escape - our trigger is generally setup in HTML so there's nothing to catch but uncaught rejection handlers anyway\n      if (node instanceof HTMLAnchorElement && node.href && node.href.split('#')[0] !== location.href.split('#')[0]) { //logout link sending you elsewhere\n        void doLogout().then(() => {\n          console.log(\"Logout complete, redirecting to\", node.href);\n          navigateTo({ type: \"redirect\", url: node.href });\n        });\n      } else {\n        void logout(); //TODO what if the logout only changed the anchor? but what's the usecase for that?\n      }\n    }\n\n    dompack.addDocEventListener(node, \"click\", event => handleLogoutClick(event));\n  });\n\n  dompack.onDomReady(() => {\n    if (\"$wh$wrdauth\" in window) {\n      console.error(\"Both setupWRDAuth from @webhare/frontend and @mod-wrd/js/auth are present in this page. Mixing these is not supported!\");\n    }\n  });\n\n  refreshLoginStatus();\n}\n\nfunction failLogin(message: string, response: { code: LoginErrorCode; data: string }, form: HTMLFormElement) {\n  const evtdetail = {\n    message: message,\n    code: response.code,\n    data: response.data\n  };\n\n  const cancelled = !dompack.dispatchCustomEvent(form || document.documentElement, \"wh:wrdauth-loginfailed\", { bubbles: true, cancelable: true, detail: evtdetail });\n  if (!cancelled) {\n    //TODO depending on error we may need to change a different field?\n    const loginfield = dompack.qR<HTMLInputElement>(form, \"input[name=password]\");\n    loginfield.setCustomValidity(message);\n    // loginfield.reportValidity(); //this actually blocks wh-form error handling from showing the error in-page when so desired\n    loginfield.focus();\n  }\n}\n\n/** Retrieve userinfo if set by onFrontendUserInfo in your WRDAuth customizer */\nexport function getUserInfo<T extends object = object>(): T | null {\n  return isLoggedIn() ? getAuthLocalData()?.userInfo as T | null : null;\n}\n\nfunction getLoginTweaks(): LoginTweaks {\n  const tweaks: LoginTweaks = {\n    lang: dompack.getLang().tag\n  };\n\n  const urlvars = new URL(location.href);\n  if (urlvars.searchParams.has(\"wrdauth_limit_expiry\"))\n    tweaks.limitExpiry = parseInt(urlvars.searchParams.get(\"wrdauth_limit_expiry\") || '0') || undefined;\n\n  return tweaks;\n}\n\n/** Implements the common username/password flows */\nexport async function login(username: string, password: string, options: LoginOptions = {}): Promise<LoginResult> {\n  const cookieName = getCookieName();\n  if (!cookieName)\n    throw new Error(\"WRDAuth not initialized, please call setupWRDAuth first and ensure this page has a <wrdauth> rule\");\n\n  const result = await rpc(\"platform:authservice\").login(username, password, cookieName, dompack.getBrowser().triplet, { ...options, ...getLoginTweaks() });\n  if (result.loggedIn && !getAuthLocalData())\n    throw new Error(\"Login succeeded but no auth data was set in the cookie\");\n\n  return result;\n}\n\n/** Execute and verify cookie clearance to prepare for logging out */\nasync function doLogout() {\n  const cookieName = getCookieName();\n  if (!cookieName)\n    throw new Error(\"WRDAuth not initialized, please call setupWRDAuth first and ensure this page has a <wrdauth> rule\");\n\n  await rpc(\"platform:authservice\").logout(cookieName, dompack.getBrowser().triplet);\n\n  if (getAuthLocalData())\n    throw new Error(\"Logged out but we still have auth data in the cookie\");\n}\n\n/** Logout the current user */\nexport async function logout() {\n  await doLogout();\n  console.log(\"Reloading to process the new logged out status\");\n  navigateTo({ type: \"reload\" }); //TODO put this behind a 'login state change' event\n}\n\nexport interface MyService {\n  startLogin2(urlpath: string, tag: string, options: ToSnakeCase<SSOLoginOptions>): Promise<NavigateInstruction>;\n}\n\ninterface SSOLoginOptions {\n  /** @deprecated use prompt: \"none\" from WH6.0 up */\n  passive?: boolean;\n  /** Set the prompt flag for the authorize request */\n  prompt?: OAuth2PromptFlag;\n}\n\nexport function startSSOLogin(tag: string, options?: SSOLoginOptions): Promise<void> {\n  const client = createClient<MyService>(\"wrd:auth\");\n\n  if (options?.passive)\n    options = { prompt: \"none\", ...options, passive: undefined }; //force prompt to none in passive mode, and remove the passive flag since it doesn't mean anything to the server\n\n  const defer = Promise.withResolvers<void>();\n\n  //Launch SSO login for the current page.\n  //TODO also pass getLoginTweaks() at least to OIDC logins as soon as we've ported this to authservice\n  client.startLogin2(location.pathname + location.search + location.hash, tag, toSnakeCase(options) || {}).then(instr => {\n    //we leave the promise unresolved so any busy layers stay active during the actual redirect\n    //TODO can we have navigateTo detect failed navigations so we can throw ?\n    navigateTo(instr);\n  }).catch((e: Error) => {\n    defer.reject(e);\n  });\n\n  return defer.promise;\n}\n\n/** Configure WebHare external auth buttons (even hidden ones) to listen for bookmarklet login requests */\nexport function setupWebHareSSOTrigger(): void {\n  window.triggerWebHareSSO = startSSOLogin;\n}\n","// This gets TypeScript to refer to us by our @webhare/... name in auto imports:\ndeclare module \"@webhare/rpc\" {\n  export interface KnownRPCServices {\n    /* Filled by generated services.ts files */\n  }\n}\n\nimport { debugFlags, backendBase } from \"@webhare/env\";\nimport { type StackTrace, parseTrace, prependStackTrace, type PromisifyInterface } from \"@webhare/js-api-tools\";\nimport { omit, parseTyped, stringify } from \"@webhare/std\";\n\n//Preload interface definitions. To solve this cleaner we would have to do some sort of auto-inject but how to robustly do that accross IDEs/Tscs ?\n\n//@ts-ignore Ignore if it doesn't exist. this line *must* remain a @ts-ignore\nimport type { } from \"@mod-platform/generated/ts/services.ts\";\n//@ts-ignore Ignore if it doesn't exist. this line *must* remain a @ts-ignore\nimport type { } from \"wh:ts/services.ts\";\n\nfunction isAbsolute(url: string) {\n  return url.startsWith(\"http:\") || url.startsWith(\"https:\");\n}\n\nfunction getBaseURL() {\n  if (!backendBase)\n    throw new Error(`You must set the baseUrl option when using the RPC Client outside Webhare`);\n  return isAbsolute(backendBase) ? backendBase : new URL(backendBase, location.origin);\n}\n\nexport interface RPCClientOptions {\n  /** Custom request update. Use to eg. set keepalive or add debug variables to the URL */\n  onBeforeRequest?: (url: URL, requestInit: RequestInit & { headers: Headers }) => void;\n  /** Response callback. Use this if you need to capture details on the incoming respones. May be invoked multiple times per request, eg due to 429 errors! */\n  onResponse?: (response: Response) => void;\n  /** Call timeout */\n  timeout?: number;\n  /** Abort signal to cancel the RPC */\n  signal?: AbortSignal;\n  /** Retry on 429 */\n  retry429?: boolean;\n  /** Silent - do not log errors */\n  silent?: boolean;\n  /** Debug (Follows 'rpc' debugflag if not explicity specified) */\n  debug?: boolean;\n  /** Headers to submit (Eg Authorization) */\n  headers?: Record<string, string>;\n  /** Base URL for service paths */\n  baseUrl?: string;\n}\n\n/** RPC Response format */\nexport type RPCResponse = ({\n  /** Result. Not present if the function didn't return anything */\n  result?: unknown;\n} | {\n  /** Error message */\n  error: string;\n  /** Captured stack trace (if 'etr' debugFlag is set) */\n  trace?: StackTrace;\n}) & {\n  /** Captured console log entries (if 'etr' debugFlag is set) */\n  consoleLog?: Array<{\n    //TODO this is Serialized<ConsoleLogItem[]> - should probably rename it to SerializedToJSON and move to std or env ?\n    /** Date when console function was called */\n    when: string;\n    /** `console` method that was called (eg 'log') */\n    method: string;\n    /** Logged data */\n    data: string;\n    /** Location of caller */\n    location?: {\n      filename: string;\n      line: number;\n      col: number;\n      func: string;\n    };\n    /** Codecontext */\n    codeContextId?: string;\n  }>;\n};\n\nclass ControlledCall {\n  client: RPCClient;\n  options: RPCClientOptions;\n  abortcontroller?: AbortController;\n  timeout?: number;\n  _callurl: string;\n  _fetchoptions: RequestInit;\n  promise: Promise<unknown>;\n  timedout?: boolean;\n  aborted?: boolean;\n\n  constructor(client: RPCClient, method: string, stack: StackTrace | null, options: RPCClientOptions, callurl: URL, fetchoptions: RequestInit) {\n    this.client = client;\n    this.options = options;\n\n    if (options.timeout || options.signal) {\n      this.abortcontroller = new AbortController;\n      fetchoptions.signal = this.abortcontroller.signal;\n\n      if (options.timeout && options.timeout > 0) {\n        this.timeout = options.timeout;\n        setTimeout(() => this._handleTimeout(), options.timeout);\n      }\n      if (options.signal) {\n        options.signal.addEventListener(\"abort\", () => this._abort());\n      }\n    }\n\n    this._callurl = callurl.toString();\n    this._fetchoptions = fetchoptions;\n\n    const fetchpromise = fetch(this._callurl, this._fetchoptions);\n    this.promise = this._completeCall(method, stack, fetchpromise) as Promise<unknown>;\n  }\n  _handleTimeout() {\n    this.timedout = true;\n    this.abortcontroller?.abort();\n  }\n  _abort() {\n    this.aborted = true;\n    this.abortcontroller?.abort();\n  }\n\n  async _completeCall(method: string, requestStack: StackTrace | null, fetchpromise: Promise<Response>) {\n    let response;\n    for (; ;) { //loop to handle \"429 Conflict\"s\n      try { //we should only guard the fetch call and specifically *not* the onResponse callback\n        response = await fetchpromise;\n      } catch (exception) {\n        if (this.client.debug)\n          console.log(`[rpc] Exception invoking '${method}'`, exception);\n\n        if (this.aborted)\n          throw new Error(`RPC Aborted`);\n        else if (this.timedout)\n          throw new Error(`RPC Timeout: timeout was set to ${this.timeout} milliseconds`);\n        else\n          throw new Error(`RPC Failed: exception: ` + exception);\n      }\n\n      this.options.onResponse?.(response); //allow hooks to capture headers\n\n      if (response.status === 429 && !(\"retry429\" in this.options && !this.options.retry429) && response.headers.get(\"Retry-After\")) {\n        const retryafter = parseInt(response.headers.get(\"Retry-After\") || \"\");\n        if (this.client.debug)\n          console.warn(`[rpc] We are being throttled (429 Too Many Requests) - retrying after ${retryafter} seconds`);\n\n        await new Promise(resolve => setTimeout(resolve, retryafter * 1000));\n        fetchpromise = fetch(this._callurl, this._fetchoptions);\n        continue;\n      }\n      break;\n    }\n\n    let jsonresponse: RPCResponse;\n    try {\n      jsonresponse = parseTyped(await response.text());\n      if (jsonresponse.consoleLog) {\n        for (const logitem of jsonresponse.consoleLog) {\n          //should we log 'when'? it's getting more and more noisy then though....\n          //TODO should we match the remote's method (after validating) or just keep everything at 'log' ?\n          console.log(`[remote:${logitem.method}] ${logitem.location ? `${logitem.location.filename.split(\"/\").at(-1)}:${logitem.location.line}: ` : ''}${logitem.data}`);\n        }\n      }\n\n      if (this.client.debug)\n        console.log(`[rpc] Received response to '${method}'`, omit(jsonresponse, [\"consoleLog\", \"trace\"]));\n    } catch (exception) {\n      if (this.client.debug)\n        console.warn(`[rpc] Response was not valid JSON`, exception);\n      throw new Error(\"RPC Failed: Invalid response received\", { cause: exception });\n    }\n\n    if (\"error\" in jsonresponse) {\n      const err = new Error(`RPC Error: ${jsonresponse.error}`);\n      if (jsonresponse.trace) {\n        try {\n          prependStackTrace(err, jsonresponse.trace);\n        } catch (err2) {\n          //ignore stacktrace manipulation error\n        }\n      }\n\n      if (this.options.debug) {\n        console.group();\n        console.warn(\"RPC failed:\", err);\n        if (requestStack) {\n          console.warn(\"Stack at calling point\");\n          console.log(requestStack);\n        }\n        console.groupEnd();\n      }\n\n      throw err;\n    }\n\n    return jsonresponse.result;\n  }\n}\n\nclass RPCClient {\n  readonly url: string;\n  options: RPCClientOptions;\n\n  constructor(url: string, options?: RPCClientOptions) {\n    this.url = url;\n    this.options = {\n      timeout: 0,\n      debug: false,\n      ...options\n    };\n  }\n\n  get debug() {\n    return this.options.debug || debugFlags.rpc;\n  }\n\n  _tryLogError(requestStack: StackTrace | null, error: Error) {\n  }\n\n  invoke(method: string, params: unknown[]) {\n    //build the URL, add profiling and function parameters where needed\n    //We'll delay the baseurl calculation until the first call to allow for the backendBase to be set up\n    const callurl = isAbsolute(this.url) ? new URL(this.url + method) : new URL(this.url + method, this.options.baseUrl || getBaseURL());\n\n    let requestStack: StackTrace | null = null;\n\n    const fetchoptions: RequestInit & { headers: Headers } = {\n      method: \"POST\",\n      headers: new Headers({\n        \"Accept\": \"application/json\",\n        \"Content-Type\": \"application/json; charset=utf-8\",\n        ...this.options.headers\n      }),\n      body: stringify(params, { typed: true }),\n    };\n\n    const pathName = typeof location !== \"undefined\" ? location.pathname : new URL(this.options.baseUrl || getBaseURL()).pathname;\n    if (pathName !== '/')\n      callurl.searchParams.set(\"pathname\", pathName);\n\n    if (this.debug) {\n      requestStack = parseTrace(new Error);\n      console.log(`[rpc] Invoking '${method}'`, params);\n    }\n\n    this.options.onBeforeRequest?.(callurl, fetchoptions);\n    return new ControlledCall(this, method, requestStack, this.options, callurl, fetchoptions).promise;\n  }\n}\n\ntype ServiceBase<T> = {\n  withOptions(options: RPCClientOptions): T & ServiceBase<T>;\n};\n\nclass ServiceProxy<Service extends keyof KnownRPCServices | object> {\n  client: RPCClient;\n\n  constructor(client: RPCClient) {\n    this.client = client;\n  }\n\n  get(target: object, prop: string, receiver: unknown) {\n    if ([\"then\", \"catch\", \"finally\"].includes(prop)) //do not appear like our object is a promise\n      return undefined;\n\n    if (prop === 'withOptions') { //create a withOptions function\n      return (options: RPCClientOptions) => {\n        const newoptions = {\n          ...this.client.options,\n          ...options,\n          headers: { ...this.client.options.headers, ...options.headers }\n        };\n        return rpc(this.client.url as (Service extends keyof KnownRPCServices ? Service : string), newoptions);\n      };\n    }\n\n    return (...args: unknown[]) => this.client.invoke(prop, args);\n  }\n}\n\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- need any to not worry about the actual first arg\ntype OmitFirstArg<F> = F extends (x: any, ...args: infer P) => infer R ? (...args: P) => R : never;\n\nexport type OmitRPCContextArgs<ServiceType> = {\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- need any to not worry about the actual first arg\n  [K in keyof ServiceType as ServiceType[K] extends (...a: any) => any ? K : never]: ServiceType[K] extends (...a: any[]) => void ? OmitFirstArg<ServiceType[K]> : never;\n};\n\n\ntype ExtractInterface<Service extends object> = PromisifyInterface<Service> & ServiceBase<PromisifyInterface<Service>>;\n\n/** Get the client interface type as would be returned by createClient\n * @typeParam Service - either the `module:service` name or the interface to implement. If you want to pass the implementation's type you should wrap it into `OmitRPCContextArgs`.\n*/\nexport type GetRPCClientInterface<Service extends (keyof KnownRPCServices) | object> = Service extends keyof KnownRPCServices ? ExtractInterface<OmitRPCContextArgs<KnownRPCServices[Service]>> : Service extends object ? ExtractInterface<Service> : never;\n\n/** Create a WebHare RPC client\n  @param service - URL (https://<ORIGIN>/.wh/rpc/module/service/) or service name (module:service) to invoke\n*/\nexport function rpc<Service extends keyof KnownRPCServices>(service: Service, options?: RPCClientOptions): GetRPCClientInterface<Service>;\nexport function rpc<Service extends keyof KnownRPCServices>(service: string, options?: RPCClientOptions): GetRPCClientInterface<Service>;\nexport function rpc<Service extends object>(service: Service extends keyof KnownRPCServices ? Service : string, options?: RPCClientOptions): GetRPCClientInterface<Service>;\n\nexport function rpc<Service extends keyof KnownRPCServices | object>(service: Service extends keyof KnownRPCServices ? Service : string, options?: RPCClientOptions): GetRPCClientInterface<Service> {\n  //NOTE: needed the separate overloads to get Intellisense to list the known services for createRPClient's first argument\n\n  if (!service)\n    throw new Error(`You must specify either a WebHare rpcService name or a full URL`);\n\n  const servicematch = service.match(/^([a-z0-9_]+):([a-z0-9_]+)$/);\n  if (servicematch)\n    service = `/.wh/rpc/${servicematch[1]}/${servicematch[2]}/` as (Service extends keyof KnownRPCServices ? Service : string);\n  else if (!service.endsWith('/'))\n    throw new Error(`Service URL must end in a slash`);\n\n  const rpcclient = new RPCClient(service, options);\n  return new Proxy({}, new ServiceProxy<GetRPCClientInterface<Service>>(rpcclient)) as GetRPCClientInterface<Service>;\n}\n","import type { NavigateInstruction } from \"@webhare/env\";\n\n/** Login failure reasons that can also be used by custom isLoginDenied checks */\nexport type LoginErrorCode = \"internal-error\" | \"incorrect-login-password\" | \"incorrect-email-password\" | \"account-disabled\" | \"unknown-account\" | \"require-external-login\";\n\n/** Login reasons that require further client side work but are not errors per-se */\nexport type LoginIncompleteCode = \"totp\" | \"incomplete-account\";\n\nexport type LoginTweaks = {\n  /** Limit session duration (development servers only) */\n  limitExpiry?: number;\n  /** Language code */\n  lang?: string;\n};\n\nexport type LoginResult = {\n  loggedIn: boolean;\n  navigateTo: NavigateInstruction;\n} | {\n  loggedIn: false;\n  code: LoginErrorCode;\n  error?: string;\n};\n\nexport type LogoutResult = { success: true } | {\n  error: string;\n  code: LoginErrorCode | LoginIncompleteCode;\n};\n\nexport const PublicCookieSuffix = \"_publicauthdata\";\n\n/* APIs and types shared between the client and server */\nexport function getCompleteAccountNavigation(token: string, pathname: string): NavigateInstruction {\n  return {\n    type: \"redirect\", //TODO or use a \"form\" too? went for a session now as an excursion to followup GET pages is much more likely in this procedure than with totp\n    url: \"/.wh/common/authpages/?wrd_pwdaction=completeaccount&token=\" + encodeURIComponent(token || '') + \"&pathname=\" + encodeURIComponent(pathname)\n  };\n}\n","/* @mod-platform/js/concepts/ is for constants, concepts, simple support APIs, but heavily shared stuff\n   that we can't find a place for (yet) in the jssdk\n\n  this file holds stuff needed to run or build the frontend */\n\n/** Get base url for assetpacks\n * @param assetpack - assetpack name, like \"platform:frontend\"\n * @returns The base URL for the assetpack, starting with and ending in a slash\n*/\nexport function getAssetPackBase(assetpack: string) {\n  return `/.wh/ea/ap/${assetpack.replace(':', '.')}/`;\n}\n\n/** The path to devkit's debug package */\nexport const devkitDebugPath = `/.wh/mod/devkit/public/debug.mjs`;\n","import { getAssetPackBase } from \"@mod-platform/js/concepts/frontend\";\nimport type { AuthorModeOptions } from \"@mod-publisher/webdesigns/authormode/authormode\";\nimport { getLocal, loadCSS, loadScript } from \"@webhare/dompack\";\nexport type { AuthorModeOptions };\n\n/** Load an asset pack\n * @param apname - The asset pack name (eg platform:tollium)\n * @returns A promise resolving to an array containing the assetpack script and CSS nodes\n*/\nexport async function loadAssetPack(apname: string, options?: { doc?: Document }): Promise<void> {\n  const doc = options?.doc ?? document;\n  const basepath = `${getAssetPackBase(apname)}ap.`;\n  if (doc.querySelector(`script[src$=\"${CSS.escape(basepath + \"mjs\")}\"`))\n    return; //we have it already\n\n  await Promise.all([loadScript(basepath + \"mjs\", { module: true, doc }), loadCSS(basepath + 'css', { doc })]);\n}\n\n/** Setup author mode extensions */\nexport function setupAuthorMode(options?: AuthorModeOptions): void {\n  if (typeof window !== \"undefined\" && window.top === window && getLocal<string>(\"wh-feedback:accesstoken\")?.match(/^[^.]*\\.[^.]*\\.[^.]*$/)) { //in a browser\n    window.whAuthorModeOptions = options;\n    void loadAssetPack(\"platform:authormode\"); // load of assetpack is schedule, no need to wait for it\n  }\n}\n","/* TODO Move consilio pxl here eventually, but limit how much we actually want to export */\nimport { sendPxlEvent, type PxlEventData, type PxlOptions } from \"@mod-consilio/js/pxl\";\nimport { dtapStage } from \"@webhare/env\";\nimport type { FormAnalyticsEvent } from \"@webhare/forms\";\nimport type { PxlDataTypes } from \"@webhare/frontend\";\nexport { setPxlOptions, getPxlId as getPxlUserId, getPxlSessionId } from \"@mod-consilio/js/pxl\";\n\nexport type PxlData = Record<string, string | number | boolean>;\n\n// Track listener installation. Especially needed during the transition from @mod-publisher/js/forms to @webhare/frontend. After the transition we might not need stack traces anymore\nconst activeListenPrefixes = new Map<string, Error>;\n\n// Combine with `string & {}` to prevent TypeScript from eliminating `keyof PxlDataTypes`\ntype AllowedKeys = keyof PxlDataTypes | (string & {});\n\n// Filters out invalid types from the PXL data type\ntype FilterValidTypes<T extends object | void> = T extends object ? {\n  [K in keyof T]: T[K] extends undefined | string | number | boolean ?\n  T[K] :\n  { __error: \"Invalid property type used in PXL event declaration, allowed: boolean, number, string\"; __type: T[K] };\n} : T;\n\n/// Helper type to allow making the data parameter optional when the datatype is void\ntype ParamTuples<DataType, Key extends AllowedKeys> = Key extends keyof PxlDataTypes ?\n  [data: FilterValidTypes<PxlDataTypes[Key]>, options?: Partial<PxlOptions>] :\n  (DataType extends void ?\n    [data?: void, options?: Partial<PxlOptions>] :\n    [data: DataType, options?: Partial<PxlOptions>]);\n\n// Error type for when an event is not declared in PxlDataTypes and no data type override is provided\ntype NeedTypeParamError = { __error: \"Event not declared in PxlDataTypes and no data type override provided\" } & symbol;\n\nexport function sendPxl<DataType extends (Event extends keyof PxlDataTypes ? NeedTypeParamError : void | PxlData | NeedTypeParamError) = NeedTypeParamError, Event extends AllowedKeys = AllowedKeys>(eventKey: Event, ...params: ParamTuples<NoInfer<DataType>, Event>): void {\n  const [data, options] = params;\n  const pxldata: PxlEventData = {};\n  for (const [k, v] of Object.entries(data ?? {})) {\n    if (v === undefined)\n      continue;\n    if (typeof v === \"string\")\n      pxldata[`ds_${k}`] = v;\n    else if (typeof v === \"number\")\n      pxldata[`dn_${k}`] = v;\n    else if (typeof v === \"boolean\")\n      pxldata[`db_${k}`] = v;\n    else\n      throw new Error(`Invalid type '${typeof v}' for PXL data key '${k}'`);\n  }\n\n  sendPxlEvent(eventKey, pxldata, options);\n}\n\n/** Setup pxl events for form analytics events\n * @param options - Options for the form analytics setup\n     - `eventPrefix`. Prefix to use. Default is `platform:form_` but existing integrations may (also) require `publisher:form`\n*/\nexport function setupFormAnalytics(options?: { eventPrefix: string }): void {\n  const prefix = options?.eventPrefix || \"platform:form_\";\n  const registered = activeListenPrefixes.get(prefix);\n  if (registered)\n    if (dtapStage !== \"production\")\n      return console.error(`Duplicate setupFormAnalytics for prefix '${prefix}', earlier registration: `, registered);\n\n  activeListenPrefixes.set(prefix, new Error); //getStackTrace() would have been nicer, but doesn't get sourcemapped in the console\n\n  addEventListener(\"wh:form-analytics\", (e: FormAnalyticsEvent) => {\n    const formeventdata: { [K in `formmeta_${string}`]: string | number | boolean } = {};\n    for (const [key, val] of Object.entries(e.detail))\n      if (key !== \"event\" && [\"string\", \"number\", \"boolean\"].includes(typeof val))\n        formeventdata[`formmeta_${key}`] = val;\n\n    sendPxl<PxlData>(`${prefix}${e.detail.event}`, formeventdata, e.detail.event === \"abandoned\" ? { beacon: true } : undefined);\n  });\n}\n","import { getIPInfo } from \"@mod-publisher/js/analytics/geoip\";\n\nexport interface GetIPInfoOptions {\n  /** Language code in which you want the country name */\n  lang?: string;\n  /** How long to trust the previously cached result in days (default: 7) */\n  cacheDays?: number;\n}\n\nexport type GeoIPInfoResult = {\n  countryCode: string;\n  countryName?: string;\n};\n\nexport async function getGeoIPInfo(options?: GetIPInfoOptions): Promise<GeoIPInfoResult | null> {\n  const data = await getIPInfo({\n    countrylang: options?.lang,\n    cachedays: options?.cacheDays,\n  });\n\n  return data ? {\n    countryCode: data.countrycode,\n    countryName: data.countryname\n  } : null;\n}\n/** Get the remote client's IP address.\n *\n * Requires WebHare proxy 3.3.0+ and the `x-webhare-proxyoptions: addremoteip` header */\nexport function getRemoteIPAddress() {\n  return (performance.getEntries()[0] as PerformanceResourceTiming)?.serverTiming?.find(_ => _.name === 'remoteip')?.description ?? null;\n}\n","import utwenteCookies from \"@mod-utwente_design/js/cookiebar\";\nimport * as dompack from '@webhare/dompack';\nimport * as consenthandler from '@mod-publisher/js/analytics/consenthandler';\nimport './cobrowserchat.scss';\n\nlet startedload = false;\n\n/* API  and integration\n   https://cobrowser.zendesk.com/hc/en-us/categories/201390226-CoBrowser-Live-Chat\n*/\n\nwindow._cb = window._cb || [];\n// window._cb.push(['registerListener', function (event)\n// {\n//   //my_analytic_object.send(event);\n//   console.log('cobrowser event: ', event);\n// }]);\n\n\nfunction setupCobrowser(chtbtn: HTMLElement) {\n  if (!consenthandler.hasConsent(\"marketing\")) {\n    //show us as online as we can't actually check yet whether we're online\n    chtbtn.querySelector<HTMLElement>('.cb_online')!.style.display = \"\";\n    chtbtn.querySelector<HTMLElement>('.cb_offline')!.style.display = \"none\";\n  }\n\n  const onChatTouchBlur = function (event: TouchEvent) { //var, we need our function pointer inside the function\n    if (dompack.isHTMLElement(event.target) && event.target.closest('#my_cb_button')) //clink on our button, ignore\n      return;\n\n    chtbtn.classList.remove('cobrowserchatcontrol--opencontrol');\n    window.removeEventListener('touchstart', onChatTouchBlur);\n  };\n  chtbtn.querySelector('.cb_chatbutton')?.addEventListener(\"click\", function () {\n    chtbtn.classList.add(\"cobrowserchatcontrol--activated\");\n  });\n  chtbtn.querySelector('.cb_online .cb_chatbutton')?.addEventListener(\"click\", function () {\n    window.dataLayer.push({ event: 'chat-klik' });\n  });\n\n  chtbtn.addEventListener('touchstart', function (event) {\n    if (!chtbtn.classList.contains('cobrowserchatcontrol--opencontrol')) {\n      event.preventDefault();\n      chtbtn.classList.add('cobrowserchatcontrol--opencontrol');\n      window.addEventListener('touchstart', onChatTouchBlur);\n    }\n  });\n\n  const acceptnode = document.querySelector<HTMLInputElement>(\"input#cobrowserchatcontrol_accept_cookies\");\n  if (acceptnode)\n    acceptnode.addEventListener(\"change\", function () {\n      //accepting marketing cookies\n      if (acceptnode.checked) {\n        utwenteCookies._setPrefs({ c: true });\n        openCoBrowser();\n      }\n    });\n}\n\n//wait for cobrowser to appear and if so, open it!\nfunction openCoBrowser() {\n  const online = document.querySelector('#my_cb_button .cb_online');\n  if (online && startedload && getComputedStyle(online).display !== 'none') {\n    document.querySelector<HTMLElement>('#my_cb_button .cb_online .cb_click')?.click();\n  } else { //recheck in 200ms\n    setTimeout(openCoBrowser, 200);\n  }\n}\n\nfunction loadCobrowser() {\n  const chtbtn = dompack.qS(\"#my_cb_button\");\n  if (!chtbtn)\n    return;\n\n  //mark us as offline before loading\n  chtbtn.querySelector<HTMLElement>('.cb_online')!.style.display = \"none\";\n  chtbtn.querySelector<HTMLElement>('.cb_offline')!.style.display = \"\";\n  startedload = true; //now that we've disabled the button, it's safe for openCoBrowser to accept an enabled button\n\n  window._cb.push(['setSourceHash', '58886d0920b635.17133377']);\n  window._cb.push(['setPrivacyLevel', 'allowTracking']);\n  window._cb.push(['setEndpoint', 'https://app.cobrowser.com//sdk/']);\n  window._cb.push(['setDataEndpoint', 'https://app.cobrowser.com//']);\n  window._cb.push(['setVersion', '']);\n  window._cb.push(['forceTransport', 'jsonp']);\n  window._cb.push(['addPageview']);\n  window._cb.push(['setDefaultCss', true]);\n  window._cb.push(['setAutoLoad', true]);\n  window._cb.push(['setDebugMode', false]);\n  if (location.pathname.startsWith(\"/en/online-open-day/\") || location.pathname.startsWith(\"/en/online-open-day-int/\"))\n    window._cb.push(['pollAvailability', 5000]);\n  // window._cb.push(['setDebugMode', true]);\n\n  document.body.appendChild(dompack.create(\"script\", { id: \"cb_script\", src: \"https://app.cobrowser.com/sdk/loader.js\" }));\n}\n\nexport function setupCoBrowserChat() {\n  dompack.register('#my_cb_button', setupCobrowser);\n  consenthandler.onConsent(\"marketing\", () => loadCobrowser());\n  if (location.hash && location.hash.includes(\"#cobrowser\"))\n    openCoBrowser();\n}\n","import * as geoip from '@mod-publisher/js/analytics/geoip';\nimport * as storage from 'dompack/extra/storage';\n\nimport \"@mod-publisher/js/analytics/gtm\"; //?wh-debug=anl support\nimport * as cookie from 'dompack/extra/cookie';\nimport \"@mod-utwente_base/webdesigns/ws2016/src/cobrowserchat\";\nimport * as dompack from '@webhare/dompack';\nimport \"@mod-utwente_design/js/crm/consenthandler\";\n\nimport { getUserSettings, getUserGuid, setUserSettings, type UserSettings } from './usersettings';\nimport { getReferralInfo } from './referralinfo';\nimport { getUTUserInfo } from \"@mod-utwente_design/js/crm/auth\";\nimport { getNetworkForIP } from \"@mod-utwente_design/js/crm/networks\";\nexport { getUserSettings, getUserGuid, setUserSettings, getReferralInfo };\n\nimport { getRemoteIPAddress } from '@mod-publisher/js/analytics/clientinfo';\nimport { debugFlags } from '@webhare/env/src/envbackend';\nimport { pushToDataLayer, setupFormAnalyticsForGTM } from '@webhare/frontend';\n\nlet beacons: Record<string, number> = {};\nlet geoippromise: ReturnType<typeof geoip.getIPInfo> | null = null;\n\ndeclare global {\n  interface Window {\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    ga: any; //Ganalytics interface\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n    _cb?: any; //cobrowseri nterface\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n//  communicatiekanaal voor meeloopdag formulieren (werken via postmesage)\n//\nfunction onMeeloopdagMessage(event: MessageEvent) {\n  if (event.data && event.data.formdone) { //callbacks meeloopdag aanmeldingen\n    if (window.dataLayer)\n      window.dataLayer.push({\n        event: 'formulier-submit',\n        form: event.data.formdone + '-' + (event.data.country || ''),\n        form_programme: event.data.study || '',\n        url: location.href\n      });\n\n    if (!location.href.includes('ut-mld-no-redirect'))\n      switch (event.data.formdone) {\n        case 'meeloopdagen-ba-de':\n          setTimeout(() => document.location = \"/de/schnuppertag/bachelor/danke\", 100);\n          break;\n        case 'meeloopdagen-ba-nl':\n          setTimeout(() => document.location = \"/meeloopdag/bachelor/bedankt\", 100);\n          break;\n        case 'meeloopdagen-ba-int':\n          setTimeout(() => document.location = \"/en/student-for-a-day/bachelor/thanks\", 100);\n          break;\n        case 'meeloopdagen-ma-de':\n          setTimeout(() => document.location = \"/de/schnuppertag/master/danke\", 100);\n          break;\n        case 'meeloopdagen-ma-nl':\n          setTimeout(() => document.location = \"/meeloopdag/master/bedankt\", 100);\n          break;\n        case 'meeloopdagen-ma-int':\n          setTimeout(() => document.location = \"/en/student-for-a-day/master/thanks\", 100);\n          break;\n      }\n  }\n}\n\n///////////////////////////////////////////////////////////////////////////\n//\n//  track eerste client id\n//\n\nfunction getGTMTracker(analyticsid: string) {\n  if (window.ga && window.ga.getAll)\n    for (const tracker of window.ga.getAll())\n      if (tracker.get('trackingId') === analyticsid)\n        return tracker;\n  return null;\n}\n\nfunction trackClientId() {\n  //schedule the retry, if we crash for any reason we'll be rescheduled\n  const retry = window.setTimeout(trackClientId, 500);\n  const tracker = getGTMTracker('UA-9767236-1') || getGTMTracker('UA-9767236-16');\n  if (tracker) {\n    const clientid = tracker.get('clientId');\n    if (clientid) {\n      if (clientid !== getUserSettings().clientid)\n        setUserSettings({ clientid: clientid });\n\n      window.clearTimeout(retry);\n      storage.setSession(\"didclientidcheck\", true);\n    }\n  }\n}\n\n\n\n///////////////////////////////////////////////////////////////////////////\n//\n// set up GTM dataLayer - must be done outside domready, so we have it ready before <body> opens\n\n//FIXME remove - temp IP experiment\n//console.log(\"Your IP: \", performance.getEntries()[0]?.serverTiming?.find(_=>_.name == 'remoteip')?.description);\n\n\nfunction setupGTMDataLayer() {\n  const usersettings = getUserSettings();\n  const base = {\n    paginatitel: document.title,\n    fileid: document.documentElement.dataset.id || 0,\n    hoofdniveau: document.documentElement.dataset.hoofdniveau || '',\n    subniveau: document.documentElement.dataset.subniveau || '',\n    taal: (document.documentElement.lang || '').split('-')[0],\n    opleiding: document.documentElement.dataset.programme || '',\n    type: document.documentElement.dataset.targetinterest || '',\n    userid: getUserGuid() || '',\n    site: document.documentElement.dataset.site || '',\n    experimentId: document.documentElement.dataset.experimentId || '',\n    experimentVariant: document.documentElement.dataset.experimentVariant || '',\n    country: usersettings?.country || '',\n    countryname: usersettings?.countryname || '',\n    network: getNetworkForIP(getRemoteIPAddress())\n  };\n\n  window.dataLayer.push(base);\n}\n\nexport async function requestGeoIP() {\n  //schedule a RPC if needed, reuse the earlier RPC if possible\n  if (!geoippromise)\n    geoippromise = geoip.getIPInfo({ cachedays: 1, countrylang: 'en' });\n\n  const geoinfo = await geoippromise;\n  if (geoinfo) {\n    setUserSettings({ country: geoinfo.countrycode, countryname: geoinfo.countryname });\n    window.dataLayer.push({ country: geoinfo.countrycode, countryname: geoinfo.countryname });\n  }\n  return geoinfo?.countrycode || null;\n}\nexport function getUserCountry() {\n  const ccode = new URL(location.href).searchParams.get('ut-countrycode');\n  return ccode || getUserSettings().country || null;\n}\nexport function requestUserCountry() {\n  if (getUserCountry())\n    return Promise.resolve(getUserCountry());\n  return requestGeoIP();\n}\nexport function learnedAboutUser(newguid: string, firstname: string) {\n  const opts: UserSettings = {};\n  if (newguid)\n    opts.guid = newguid;\n  if (firstname)\n    opts.firstname = firstname;\n\n  setUserSettings(opts);\n  if (window.dataLayer)\n    window.dataLayer.push({ userid: getUserGuid() || '' });\n}\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nfunction addReferralInfoToForm(evt: any) { //TODO can't we remove this? utwente_voorlichting uses its own referralinfo handling and noone outside shouild need this?\n  if (!evt.detail.extrasubmit.referralinfo) {\n    evt.detail.extrasubmit.referralinfo = getReferralInfo();\n\n    const userbeacon = Object.keys(beacons).filter(name => name.startsWith('usertype-'))[0];\n    if (userbeacon)\n      evt.detail.extrasubmit.referralinfo.beaconusertype = userbeacon.substr(9);\n  }\n}\n\nexport function getUserBeacons() {\n  return beacons;\n}\n\nfunction storeBeacons() {\n  try {\n    localStorage[\"umc-beacons\"] = JSON.stringify(beacons);\n    window.setTimeout(function () { dompack.dispatchCustomEvent(window, \"ut-beaconchange\", { bubbles: true, cancelable: true }); }, 0);\n    return true;\n  } catch (e) {\n    console.log(e);\n    return false;\n  }\n}\n\nexport function triggerUserBeacon(tag: string, date?: number) {\n  if (!date)\n    date = Date.now();\n\n  if (window.dataLayer)\n    window.dataLayer.push({ event: 'trigger-user-beacon', beacon: tag });\n\n  if (debugFlags.umc)\n    console.log(`[umc] Added ${tag} with timestamp ${date}`);\n  beacons[tag] = date;\n  storeBeacons();\n}\n\nexport function setupRevisitBeacon(basetag: string, period: number) {\n  /* revisit beacons...\n     if <basetag>-firstvisit is not set or too old, set it AND set a <basetag>-firstvisit in sessionStorage\n     if <basetag>-firstvisit is set and <basetag>-firstvisit is in sessionStorage, ignore\n                                    else set <basetag>-secondvisit */\n\n  const firstvisit = beacons[basetag + \"-firstvisit\"];\n  const now = Date.now();\n\n  if (!firstvisit || firstvisit < (now - period * 86400 * 1000)) {\n    if (debugFlags.umc)\n      console.log(\"[umc] First visit \" + basetag);\n    beacons[basetag + \"-firstvisit\"] = now;\n    sessionStorage[basetag + \"-firstvisit\"] = \"y\";\n    storeBeacons();\n    return;\n  }\n  if (sessionStorage[basetag + \"-firstvisit\"] === \"y\") {\n    if (debugFlags.umc)\n      console.log(\"[umc] Still in first visit \" + basetag);\n    return;\n  }\n  if (debugFlags.umc)\n    console.log(\"[umc] Second visit \" + basetag);\n  beacons[basetag + \"-secondvisit\"] = now;\n  storeBeacons();\n}\n\nexport function clearUserBeacon(tag: string) {\n  if (!beacons[tag])\n    return;\n\n  if (window.dataLayer)\n    window.dataLayer.push({ event: 'clear-user-beacon', beacon: tag });\n\n  if (debugFlags.umc)\n    console.log(\"[umc] Clearing \" + tag);\n  delete beacons[tag];\n  storeBeacons();\n}\n\nfunction pickupGlobalBeacons() {\n  cookie.list().filter(ck => ck.name.match(/^ut-umc-setbeacon-/)).forEach(ck => {\n    triggerUserBeacon(ck.name.substr('ut-umc-setbeacon-'.length), parseInt(ck.value));\n    cookie.remove(ck.name, { domain: location.host.substr(location.host.indexOf('.')) });\n  });\n\n  //set user type (student/employee) based on logged in user\n  const userinfo = getUTUserInfo();\n  let usertype = '';\n  if (userinfo) {\n    if (userinfo.isemployee)\n      usertype = \"employee\";\n    else if (userinfo.isstudent)\n      usertype = \"student\";\n  }\n\n  const cookieusertype = cookie.read(\"ut-user-type\");\n  if (cookieusertype) {\n    //don't let the cookie overwrite 'student' or 'employee' if already set by logged in user\n    if (![\"student\", \"employee\"].includes(usertype))\n      usertype = cookieusertype;\n\n    if (location.host.endsWith('.utwente.nl'))\n      cookie.remove(\"ut-user-type\", { domain: 'utwente.nl' }); //to match the way the cookie is set\n    else\n      cookie.remove(\"ut-user-type\"); //assume it has no domain\n  }\n\n  if (usertype) {\n    //we used to only support 'student' and 'employee' but are generalizing for #1212\n    //clear 'other' beacons\n    const setbeacon = `usertype-${usertype}`;\n    Object.keys(beacons).filter(name => name !== setbeacon && name.startsWith('usertype-')).forEach(clearUserBeacon);\n    triggerUserBeacon(setbeacon);\n  }\n}\n\nfunction executeANLEvent(node: HTMLElement) { //generic analytics event\n  if (node.dataset.gtm)\n    window.dataLayer.push(JSON.parse(node.dataset.gtm));\n}\n\n//Read beacons from local storage\ntry {\n  beacons = JSON.parse(localStorage[\"umc-beacons\"]) || {};\n} catch (ignore) {\n}\n\ndompack.register(\".ut-beacon\", node => triggerUserBeacon(node.dataset.setbeacon!));\ndompack.register(\"ut-anl\", node => executeANLEvent(node));\n\nwindow.addEventListener(\"wh:form-preparesubmit\", addReferralInfoToForm);\npickupGlobalBeacons();\n\n//For WH5.7, send the custom event.\nsetupFormAnalyticsForGTM({ eventPrefix: \"publisher:form\" });\naddEventListener(\"wh:form-analytics\", evt => {\n  if (evt.detail.event === \"submitted\" && (evt.target as HTMLFormElement).dataset.gtmSubmit)\n    setTimeout(() => pushToDataLayer({ event: \"formulier-submit\" }), 1); //timeout to give setupFormAnalyticsForGTM a chance to add variables\n});\n\nsetupGTMDataLayer();\n\nwindow.addEventListener(\"message\", evt => onMeeloopdagMessage(evt));\n\nrequestGeoIP().then(() => { }, () => { });\nif (!storage.getSession(\"didclientidcheck\"))\n  window.addEventListener(\"load\", trackClientId);\n","//Once everyone directly invokes setupConsentHandlerForUtwente() this API can go away\n\nimport { setupConsentHandlerForUtwente } from \"@mod-utwente_design/js/cookiebar\";\n\nsetupConsentHandlerForUtwente();\n","//NOTE we are also included by SIR FORM so keep compact / keep dependencies limited\n\nimport * as dompack from 'dompack';\nimport * as cookie from 'dompack/extra/cookie';\n\nlet usersettings: {\n  guid?: string;\n  clientid?: string;\n  country?: string;\n  countryname?: string;\n  firstname?: string;\n  firstreferrer?: string;\n  firstrefertime?: number;\n  \"brochure-lastprogramme\"?: string;\n} = {};\n\nexport type UserSettings = typeof usersettings;\n\nexport function getUserSettings() {\n  return usersettings || {};\n}\n\nexport function getUserGuid(): string | null {\n  return usersettings.guid || null;\n}\n\nexport function setUserSettings(settings: typeof usersettings) {\n  const lastguid = getUserGuid();\n  usersettings = { ...usersettings, ...settings };\n  cookie.write(\"ut-settings\", JSON.stringify(usersettings), { duration: 365 });\n\n  if (lastguid !== getUserGuid())\n    dompack.dispatchCustomEvent(window, \"ut-settings-changed\", { bubbles: true, cancelable: false, detail: { userguid: getUserGuid() } });\n}\n\n//Read usersettings from cookie\ntry {\n  usersettings = JSON.parse(cookie.read(\"ut-settings\")!) || {};\n} catch (e) {\n}\n","//NOTE we are also included by SIR FORM so keep compact / keep dependencies limited\n\nimport { getUserSettings, setUserSettings } from './usersettings';\nimport { getUserBeacons } from './index';\nimport type { UTReferralInfo } from '@mod-utwente_base/js/types';\nimport { debugFlags } from '@webhare/env';\nimport { getBrowser, getCookie, setCookie } from '@webhare/dompack';\nimport utwenteCookies from '@mod-utwente_design/js/cookiebar';\n\ninterface SessionInfo {\n  referrer?: string;\n  start?: number;\n  gclid?: string;\n  wbraid?: string;\n  gbraid?: string;\n}\n\nfunction readSessionInfo(): SessionInfo {\n  try {\n    return JSON.parse(getCookie(\"ut-sess\")!) || {};\n  } catch (ignore) {\n    return {};\n  }\n}\n\nfunction writeSessionInfo(sessinfo: SessionInfo) {\n  setCookie(\"ut-sess\", JSON.stringify(sessinfo));\n}\n\n//returns getReferralInfo structure but with custom URL. used for eg SIR FORM PWA\nexport function getHardcodedURLReferralInfo(url: string): UTReferralInfo {\n  return {\n    device: getBrowser().triplet,\n    firstreferrer: url\n  };\n}\n\nexport function getReferralInfo(): UTReferralInfo {\n  const sessioninfo = readSessionInfo();\n  const usersettings = getUserSettings();\n  const referralinfo: UTReferralInfo = {\n    device: getBrowser().triplet,\n    firstreferrer: (usersettings ? usersettings.firstreferrer : '') || '',\n    firstrefertime: (usersettings ? usersettings.firstrefertime : 0) || 0,\n    sessionreferrer: (sessioninfo.referrer || \"\"),\n    sessionstart: (sessioninfo.start || 0),\n    clientid: (usersettings ? usersettings.clientid : '') || ''\n  };\n\n  if (utwenteCookies.getConsent()) {\n    for (const field of [\"gclid\", \"gbraid\", \"wbraid\"] as const)\n      if (sessioninfo[field])\n        referralinfo[field] = sessioninfo[field];\n  }\n\n  const userbeacon = Object.keys(getUserBeacons()).filter(name => name.startsWith('usertype-'))[0];\n  if (userbeacon)\n    return { ...referralinfo, beaconusertype: userbeacon.substring(9) };\n\n  return referralinfo;\n}\n\n\n///////////////////////////////////////////////////////////////////////////\n//\n//  track eerste referrer\n//\n\nfunction trackFirstReferrer() {\n  const usersettings = getUserSettings();\n  let referrer = (document.referrer || 'direct:').substr(0, 1000);\n\n  if (referrer) { //copy gclid & utm_ vars from the current URL to the referrer url\n    const referrerurl = new URL(referrer);\n    const urlparams = new URL(location.href).searchParams;\n    for (const varname of urlparams.keys()) {\n      if (varname.match(/^(gclid|utm_.*|fbclid|dyn_.*)$/))\n        referrerurl.searchParams.set(varname, urlparams.get(varname)!);\n    }\n\n    referrer = referrerurl.toString();\n  }\n\n  //Set sessionstorage referrer if not seen yet\n  const sessinfo = readSessionInfo();\n  let sessupdates: Record<string, string | number> | null = null;\n  if (!sessinfo.start) {\n    if (debugFlags.anl)\n      console.log(\"[anl] trackFirstReferrer: stored as session referrer: \" + referrer);\n    sessupdates = { referrer: referrer, start: Date.now() };\n  }\n\n  const urlinfo = new URL(location.href);\n  for (const grabVar of [\"gclid\", \"wbraid\", \"gbraid\"] as const)\n    if (urlinfo.searchParams.has(grabVar))\n      sessupdates = { ...sessupdates, [grabVar]: urlinfo.searchParams.get(grabVar) || '' };\n\n\n  if (sessupdates)\n    writeSessionInfo({ ...sessinfo, ...sessupdates });\n\n  if (usersettings.firstrefertime) {\n    const firstreferage = (Date.now() - usersettings.firstrefertime) / (86400 * 1000);\n    if (firstreferage < 90) {\n      if (debugFlags.anl)\n        console.log(\"[anl] trackFirstReferrer: ignoring referrer because currently stored referrer is \" + firstreferage + \" days old\");\n      return;\n    }\n  }\n\n  setUserSettings({ firstreferrer: referrer, firstrefertime: Date.now() });\n  if (debugFlags.anl)\n    console.log(\"[anl] trackFirstReferrer: stored as first referrer: \" + referrer);\n}\n\ntrackFirstReferrer();\n","// Auth is not really a 'crm' thing, but all related code is here too... so lets just put it here in @mod-utwente_design/js/crm/...\n\nimport * as dompack from 'dompack';\nimport * as wrdauth from '@mod-wrd/js/auth';\nimport { getNetworkForIP } from \"@mod-utwente_design/js/crm/networks\";\nimport { getRemoteIPAddress } from '@mod-publisher/js/analytics/clientinfo';\nimport \"@mod-publisher/js/analytics/gtm\"; //load as early as possible\nimport { dtapStage } from '@webhare/env';\n\nexport function getLoginLink({ prompt = false, silent = false, redirect = \"\" } = {}) {\n  const url = redirect ? redirect : location.href;\n  const gotourl = new URL('/.utdesign/auth/login.shtml', location.href);\n  gotourl.searchParams.set('goto', url.substr(location.origin.length + 1));\n  if (prompt)\n    gotourl.searchParams.set('prompt', '1');\n  if (silent)\n    gotourl.searchParams.set('silent', '1');\n  return gotourl.toString();\n}\n\nexport function getUTUserInfo() {\n  return wrdauth?.getDefaultAuth()?.getUserInfo();\n}\n\n\ndompack.register(\".ut-login--clicktologin,a[href^='x-ut-login:']\", node => node.addEventListener(\"click\", event => {\n  dompack.stop(event);\n  //TODO spinner while navigating?\n  location.href = getLoginLink({ redirect: node.dataset.redirect ? node.dataset.redirect : \"\" });\n}));\n\nif (dtapStage === \"development\" || dtapStage === \"test\")\n  console.log(\"To debug your login settings go to\", new URL(\"/.utdesign/auth/userinfo.shtml?path=\" + encodeURIComponent(location.pathname), location.href).toString());\n\nconst userinfo = getUTUserInfo();\nwindow.dataLayer?.push({\n  isloggedin: userinfo ? \"true\" : \"false\",\n  logintype: userinfo ? userinfo.isemployee ? \"Yes - employee\" : userinfo.isstudent ? \"Yes - student\" : \"Yes - other\" : \"No\",\n  company: getUTUserInfo()?.company ?? \"\",\n  network: getNetworkForIP(getRemoteIPAddress())\n});\n","/* eslint-disable */\n/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\n//ADDME move cookie state to sessionstorage, we don't need to transmit _c cookies on each request\n\nimport * as dompack from 'dompack';\nimport * as domcookie from 'dompack/extra/cookie';\nimport * as whintegration from '@mod-system/js/wh/integration';\nimport * as newauth from \"@webhare/frontend/src/auth\";\nimport Keyboard from 'dompack/extra/keyboard';\n\nimport JSONRPC from '@mod-system/js/net/jsonrpc';\nimport { navigateTo } from '@webhare/env';\nimport { isHTMLElement } from '@webhare/dompack';\n\nlet defaultauth: WRDAuthenticationProvider | null = null;\n\nfunction getBackVar(backurl) {\n  backurl = backurl.split('/').slice(3).join('/'); //strip origin, make relative to current server\n  return backurl ? '?b=' + encodeURIComponent(backurl) : '';\n}\n\nfunction getURLOrigin(url) {\n  return url.split('/').slice(0, 3).join('/');\n}\n\nexport class WRDAuthenticationProvider {\n  userinfo: object | null = null;\n  constructor(options) {\n    if (!options)\n      options = {};\n\n    this.cookiename = 'cookiename' in options ? options.cookiename : \"webharelogin\";\n\n    this.refresh();\n\n    window.$wh$legacyAuthProvider = this; //@webhare/frontend/src/auth needs this to keep us in sync\n  }\n\n  refresh() {\n    this.isloggedin = false;\n    this.userinfo = newauth.getUserInfo();\n    this.logouturl = \"\";\n    this.loginservice = new JSONRPC({ url: '/wh_services/wrd/auth' });\n\n    const jsstate = domcookie.read(this.cookiename + '_j');\n    const currentstate = domcookie.read(this.cookiename + '_c');\n\n    if (dompack.debugflags.aut) {\n      console.log(\"[aut] \" + this.cookiename + \"_j=\" + jsstate);\n      console.log(\"[aut] \" + this.cookiename + \"_c=\" + currentstate);\n    }\n    if (!jsstate)\n      return;\n\n    if (!currentstate || currentstate.substr(0, jsstate.length) !== jsstate) {\n      return;\n    } else {\n      if (dompack.debugflags.aut)\n        console.log(\"[aut] looks like we're still logged in\");\n\n      this.isloggedin = true;\n      if (currentstate.length > 1)\n        try {\n          this.userinfo = JSON.parse(currentstate.substr(jsstate.length));\n        } catch (e) {\n        }\n    }\n  }\n\n  //Get the current session id - use this if you need to discard settings\n  getCurrentSessionId() {\n    return domcookie.read(this.cookiename + '_j') || '';\n  }\n\n  logout() {\n    let backurl = location.href;\n    if (this.logouturl) {\n      const logouturl = new URL(this.logouturl, backurl).toString();\n      if (getURLOrigin(backurl) !== getURLOrigin(logouturl))\n        throw new Error(\"A logout URL is not allowed to change the origin\"); //we won't be an open redirect. and getBackVar will clear the origin anyway\n\n      backurl = logouturl;\n    }\n\n    const redirectto = '/.wrd/auth/logout.shtml' + getBackVar(backurl);\n    location.replace(redirectto);\n  }\n\n  setupLoginForm(form: HTMLFormElement) {\n    if (!form)\n      throw new Error(\"No such form\");\n\n    new Keyboard(form, { \"Enter\": evt => this._handleLoginForm(form, evt) });\n    form.addEventListener(\"submit\", evt => this._handleLoginForm(form, evt));\n    form.addEventListener(\"click\", evt => this._handleLoginClick(form, evt));\n  }\n  _handleLoginClick(form: HTMLFormElement, event: MouseEvent) {\n    if (form.hasAttribute(\"data-wh-wrdauth-attached\"))\n      return; //get out of the way - modern handlers are registered\n\n    if (isHTMLElement(event.target) && event.target.closest('.wh-wrdauth__loginbutton'))\n      return this._handleLoginForm(form, event); //will stop the event too\n  }\n  _handleLoginForm(form: HTMLFormElement, event: Event) {\n    if (form.hasAttribute(\"data-wh-wrdauth-attached\"))\n      return; //get out of the way - modern handlers are registered\n\n    dompack.stop(event);\n\n    const loginfield = form.querySelector('*[name=\"login\"]');\n    const passwordfield = form.querySelector('*[name=\"password\"]');\n    const persistentfield = form.querySelector('*[name=\"persistent\"]');\n\n    if (!loginfield)\n      throw new Error(\"No field named 'login' found\");\n    if (!passwordfield)\n      throw new Error(\"No field named 'password' found\");\n\n    const persistentlogin = persistentfield && persistentfield.checked;\n    this._tryLogin(form, loginfield.value, passwordfield.value, { persistent: persistentlogin });\n  }\n\n  login(login, password, options) {\n    options = { ...options };\n    return new Promise((resolve, reject) => {\n      const url = new URL(location.href);\n\n      const opts =\n      {\n        logincontrol: url.searchParams.get(\"wrdauth_logincontrol\") || \"\"\n      };\n\n      return this.loginservice.request('Login'\n        , [\n          location.href,\n          login,\n          password,\n          Boolean(options.persistent),\n          opts\n        ]\n        , function (response) { //success handler\n          resolve(response);\n        }\n        , function (error) {\n          reject(error);//FIXME translate to exception\n        }\n      );\n    });\n  }\n\n  /** Get the afterlogin submitinstruction from the wrdauth_logincontrol webvariable\n      @cell(string) opts.logincontrol Override wrdauth_logincontrol variable from the url\n      @return Submit instruction. The defult instruction is { \"type\": \"reload\" }.\n  */\n  getAfterLoginSubmitInstruction(opts = {}) {\n    const url = new URL(location.href);\n    const logincontrol = opts.logincontrol || url.searchParams.get(\"wrdauth_logincontrol\") || \"\";\n\n    return new Promise((resolve, reject) => {\n      this.loginservice.request('getAfterLoginSubmitInstruction',\n        [location.href, logincontrol],\n        function (response) { //success handler\n          resolve(response);\n        }\n        , function (error) {\n          reject(error);//FIXME translate to exception\n        }\n      );\n    });\n  }\n\n  //ADDME do we have direct callers or can we _tryLogin this?\n  //FIXME be more wh-form like, at least BEM the 'submitting' class\n  _tryLogin(form, login, password, options) {\n    const loginlock = dompack.flagUIBusy();\n    if (form)\n      form.classList.add(\"submitting\");\n\n    this.login(login, password, options).then(result => this.onLoginSuccess(loginlock, form, result))\n      .catch(error => this._onLoginFailure(loginlock, form, options, error));\n  }\n  onLoginSuccess(loginlock, form, response) {\n    if (form)\n      form.classList.remove(\"submitting\");\n\n    const completion = () => this._completeLoginSuccess(loginlock, response, form);\n    dompack.dispatchCustomEvent(form || document.documentElement, 'wh:wrdauth-onlogin',\n      {\n        bubbles: true,\n        cancelable: true,\n        detail: { callback: completion, userinfo: response.userinfo },\n        defaulthandler: completion\n      });\n  }\n  _completeLoginSuccess(loginlock, response, form) {\n    loginlock.release();\n    if (response.success) {\n      if (response.submitinstruction) {\n        navigateTo(response.submitinstruction);\n        return;\n      }\n\n      //The user has succesfully logged in\n      console.log(\"Reloading after succesfull login\");\n      navigateTo({ type: \"reload\" });\n      return;\n    }\n\n    this._failLogin(/* FIXME? Locale.get('wh-common.authentication.loginfail') || */'The specified login data is incorrect.', response, form);\n  }\n  _onLoginFailure(loginlock, form, options, code, msg) {\n    if (form)\n      form.classList.remove(\"submitting\");\n    loginlock.release();\n\n    this._failLogin(/* FIXME? Locale.get('wh-common.authentication.loginerror') || */'An error has occurred.', { code: code }, form);\n  }\n  _failLogin(message, response, form) {\n    if ([\"REQUIRESETUPSECONDFACTOR\", \"FAILEDVALIDATIONCHECKS\", \"REQUIRESECONDFACTOR\"].includes(response.code)) {\n      console.error(`Code \"${response.code}\" is NOT supported by @mod-wrd/js/auth - you will need to remove this library and fully switch to setupAuth in @webhare/frontend to support password requirements and/or MFA`);\n      message = \"An internal error has occured in the account management system. Please contact the webmaster.\";\n    }\n\n    const evtdetail = {\n      message: message,\n      code: response.code,\n      data: response.data\n    };\n\n    const cancelled = !dompack.dispatchCustomEvent(form || document.documentElement, \"wh:wrdauth-loginfailed\", { bubbles: true, cancelable: true, detail: evtdetail });\n    if (!cancelled) {\n      /*\n      if($wh.Popup && $wh.Popup.Dialog)\n        new $wh.Popup.Dialog( { text: failevent.message, buttons: [{ result: 'ok', title: \"Ok\" }] });\n      else*/\n      alert(message);\n    }\n  }\n  isLoggedIn() {\n    return newauth.isLoggedIn();\n  }\n  /** @deprecated Switch to frontend getUserInfo() */\n  getUserInfo(): any {\n    return newauth.getUserInfo();\n  }\n  setLogoutURL(url) {\n    this.logouturl = url;\n  }\n\n  startLogin(type, sp_tag, options) {\n    options = options || {};\n    const defer = Promise.withResolvers();\n\n    this.loginservice.request('StartLogin'\n      , [type, sp_tag, location.href, options]\n      , defer.resolve\n      , defer.reject //FIXME translate to exception\n    );\n\n    return defer.promise;\n  }\n  startSAMLLogin(sp_tag, options) {\n    return this.startLogin('saml', sp_tag, options);\n  }\n\n  //Setup the page with loginstate. automatically invoked on the default auth provider\n  setupPage() {\n    document.documentElement.classList.toggle(\"wh-wrdauth-loggedin\", this.isLoggedIn()); //legacy! will be removed\n    document.documentElement.classList.toggle(\"wh-wrdauth--isloggedin\", this.isLoggedIn());\n  }\n\n  static getDefaultAuth() {\n    return defaultauth;\n  }\n}\n\nexport function getDefaultAuth() {\n  return defaultauth;\n}\n\nif (window.$wh && window.$wh.WRDAuthenticationProvider) {\n  console.log(\"Both designfiles wrd.auth and @mod-wrd/js/auth are loaded. @mod-wrd/js/auth will not activate\");\n} else if (whintegration.config[\"wrd:auth\"]) {\n  defaultauth = new WRDAuthenticationProvider(whintegration.config[\"wrd:auth\"]);\n  defaultauth.setupPage();\n\n  dompack.register('.wh-wrdauth__logout, .whplugin-wrdauth-logout', node => {\n    node.whplugin_processed = true;\n    node.addEventListener(\"click\", event => {\n      event.stopPropagation();\n      event.preventDefault();\n      defaultauth.logout();\n    });\n  });\n  dompack.register('.wh-wrdauth__loginform, .whplugin-wrdauth-loginform', node => {\n    node.whplugin_processed = true;\n    defaultauth.setupLoginForm(node);\n  });\n\n  if (defaultauth.userinfo) {\n    dompack.register(\"*[data-wrdauth-text]\", node => {\n      const elname = node.dataset.wrdauthText;\n      if (elname in defaultauth.userinfo)\n        node.textContent = defaultauth.userinfo[elname];\n    });\n    dompack.register(\"*[data-wrdauth-value]\", node => {\n      const elname = node.dataset.wrdauthValue;\n      if (elname in defaultauth.userinfo)\n        node.value = defaultauth.userinfo[elname];\n    });\n  }\n}\n\nexport default WRDAuthenticationProvider;\n\nwindow.$wh$wrdauth = true; //flag our load - needed during transition to @webhare/wrdauth to prevent double loading\n","import * as dompack from '@webhare/dompack';\n\n//NOTE: Do *NOT* load @webhare/frontend or we enforce the new CSS reset!\nimport { navigateTo, type NavigateInstruction } from \"@webhare/env\";\nexport { frontendConfig as config } from '@webhare/frontend/src/init';\n\nexport function executeSubmitInstruction(instr: NavigateInstruction, options?: {\n  ismodal?: boolean;\n  iframe?: HTMLIFrameElement;\n}) {\n  if (!instr)\n    throw Error(\"Unknown instruction received\");\n\n  options = { ismodal: true, ...options };\n  //Are there any cirumstances where you would want to reelase this lock?\n  dompack.flagUIBusy({ modal: options.ismodal || false });\n  navigateTo(instr);\n}\n","export function getNetworkForIP(ip: string | null) {\n  /*\n  https://gitlab.webhare.com/utwente/utwente_base/-/issues/1768#note_140872\n  2001:67c:2564:*\n  2001:610:1908:*\n  130.89.*\n  145.126.0.0-145.126.127.255  (145.126.126.0/17)\n\n  guess we could integartie all kinds of CIDR logic.. but a few comparisons are faster/still less code. test_misc.es will validate the ranges\n\n  https://gitlab.webhare.com/utwente/utwente_base/-/issues/2063:\n  145.126.0.0/18 - 145.126.0.1 - 145.126.63.254\n  145.126.64.0/19 - 145.126.64.1 - 145.126.95.254\n\n  */\n  if (!ip)\n    return '';\n  if (ip.startsWith(\"2001:67c:2564:\")\n    || ip.startsWith(\"2001:610:1908:\")\n    || ip.startsWith(\"130.89.\")\n    || (ip.startsWith(\"145.126.\") && parseInt(ip.split('.')[2]) <= 95)\n  )\n    return 'internal';\n  return 'external';\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nexport default function setupShowAllLinks(node, containerClass, linkClass) {\n  const target = node.querySelector(\".\" + linkClass + \"--showall\");\n  if (target) {\n    // Open/close 'all links' sections\n    target.addEventListener(\"click\", event => {\n      if (target.parentNode) {\n        // Subtract the 'showall' link height from the links section height and remove the 'showall' link\n        const style = getComputedStyle(target);\n        node.setAttribute(\"data-height\", parseInt(node.getAttribute(\"data-height\")) - parseInt(style.height) - parseInt(style.marginTop));\n        target.parentNode.removeChild(target);\n\n        // Force a style recompute after the 'showall' link is removed, so the transition will work properly\n        node._wsTmpHeight = getComputedStyle(node).height;\n      }\n\n      // Save section height so it can be animated using transition (which only animates explicitly set height)\n      const links = node.querySelector(\".\" + containerClass);\n      if (links.classList.contains(containerClass + \"--init\")) {\n        links.setAttribute(\"data-height\", links.clientHeight + \"px\");\n        links.classList.remove(containerClass + \"--init\");\n\n        // Force a style recompute after the links 'init' class is removed, so the transition will work properly\n        links._wsTmpHeight = getComputedStyle(links).height;\n      }\n\n      // Toggle section open/close, update height to trigger height transition (update parent link section height as well)\n      requestAnimationFrame(() => {\n        if (target.classList.contains(linkClass + \"--open\")) {\n          target.classList.remove(linkClass + \"--open\");\n          links.classList.remove(containerClass + \"--open\");\n          links.style.height = \"\";\n\n          node.setAttribute(\"data-height\", (parseInt(node.getAttribute(\"data-height\")) - parseInt(links.getAttribute(\"data-height\"))) + \"px\");\n          node.style.height = node.getAttribute(\"data-height\");\n        } else {\n          target.classList.add(linkClass + \"--open\");\n          links.classList.add(containerClass + \"--open\");\n          links.style.height = links.getAttribute(\"data-height\");\n\n          node.setAttribute(\"data-height\", (parseInt(node.getAttribute(\"data-height\")) + parseInt(links.getAttribute(\"data-height\"))) + \"px\");\n          node.style.height = node.getAttribute(\"data-height\");\n        }\n      });\n    });\n  }\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport KeyboardHandler from \"dompack/extra/keyboard\";\nimport InternetRequester from \"@mod-system/js/net/requester\";\nimport searsia from \"@mod-utwente_base/web/pub/ws2016/searsia\";\n\nexport default class SearsiaAutoSuggest {\n  _node;\n\n  /** options.fixitemswidth Make the items container as wide as the pulldown. Defaults to true */\n  constructor(inputNode: HTMLInputElement, resultsNode, options) {\n    this._class = (options ? options.baseclass : '') || 'selectlist';\n    this._fixitemswidth = !(options && !options.fixitemswidth);\n    this._node = inputNode;\n    this._items = resultsNode;\n\n    this._connection = new InternetRequester();\n    this._connection.on(\"requestend\", event => this._gotSuggestions(event));\n\n    this._lookuppending = false;\n    this._lookuphistory = [];\n    this._lookuplock = null;\n    this._dontresuggest = false;\n\n    this.options = {\n      template: \"\",\n      noresultstext: \"\",\n      minlength: 3,\n      numsuggestions: 10,\n      immediateresuggest: false, //immediately resuggest\n      suggestdelay: 200, //how long to wait before we initiate suggestions\n      triminput: true,\n      ...options\n    };\n\n    this._node.addEventListener(\"input\", () => this._onInput());\n    this._node.addEventListener(\"blur\", event => this._onBlur(event));\n\n    this._items.addEventListener(\"click\", event => this._clickItem(event));\n\n    new KeyboardHandler(this._node, { \"ArrowDown\": event => this._onArrowDown(event) }, { captureunsafekeys: true });\n  }\n\n  cancel() {\n    if (this._updatetimer) {\n      clearTimeout(this._updatetimer);\n      this._updatetimer = 0;\n    }\n    this._endLock();\n  }\n\n  _clickItem(event) {\n    dompack.stop(event);\n\n    const selectitem = event.target.closest('.' + this._class + '__item');\n    if (selectitem)\n      this._doSelectItem(selectitem);\n  }\n\n  _onArrowDown(_event) {\n    //TODO: Select next suggestion?\n  }\n\n  _onInput() {\n    if (this._lookuppending || this._dontresuggest || this._node.disabled || this._node.readOnly)\n      return;\n\n    if (!this._lookuplock) {\n      this._lookuplock = dompack.flagUIBusy();\n      this._node.classList.add(this._class + \"--autosuggesting\");\n    }\n\n    if (this._updatetimer)\n      clearTimeout(this._updatetimer);\n\n    this._updatetimer = setTimeout(() => this._checkInput(), this.options.suggestdelay);\n  }\n\n  _endLock() {\n    if (this._lookuplock) {\n      this._lookuplock.release();\n      this._lookuplock = null;\n      this._node.classList.remove(this._class + \"--autosuggesting\");\n    }\n  }\n\n  _onBlur() {\n    this.cancel();\n  }\n\n  _safeToSuggest(value) {\n    if (value.length < this.options.minlength) //FIXME count last word, not full string\n      return false;\n\n    return true;\n  }\n\n  async _checkInput() {\n    try {\n      await this._offerSuggestions();\n    } finally {\n      this._endLock();\n    }\n  }\n\n  _getCurrentInput() {\n    let input = this._node.value;\n    if (this.options.triminput)\n      input = input.trim();\n    return input;\n  }\n\n  async _offerSuggestions() {\n    let input, values;\n    do //loop until what we looked up matches what we were looking for\n    {\n      input = this._getCurrentInput();\n      if (!this._safeToSuggest(input)) {\n        dompack.dispatchCustomEvent(this._node, \"searsia:hidesuggestions\", { bubbles: true, cancelable: false });\n        return;\n      }\n\n      values = await this._lookup(input);\n    } while (input != this._getCurrentInput());\n\n    if (!values || values.length == 0) {\n      dompack.dispatchCustomEvent(this._node, \"searsia:hidesuggestions\", { bubbles: true, cancelable: false });\n      return;\n    }\n\n    this._generateItems({ input, values });\n    dompack.dispatchCustomEvent(this._node, \"searsia:showsuggestions\", { bubbles: true, cancelable: false });\n  }\n\n  async _lookup(input) {\n    const historyhit = this._lookuphistory.find(entry => entry.input == input);\n    if (historyhit)\n      return historyhit.values;\n\n    this._lookuppending = true;\n\n    const url = searsia.fillUrlTemplate(this.options.template, searsia.encodedQuery(input));\n    this._connection.stopCurrentRequest();\n    this._connection.startXMLHTTPRequest(\"GET\", url);\n    this._deferred = dompack.createDeferred();\n    //TODO: Add timeout?\n\n    const lookupresult = await this._deferred.promise;\n\n    this._lookuphistory.push({ input: input, values: lookupresult });\n    this._lookuppending = false;\n    return lookupresult;\n  }\n\n  _gotSuggestions(event) {\n    if (event.responsejson && event.responsejson.length && event.responsejson.length > 1) {\n      const suggestions = event.responsejson[1].slice(0, this.options.numsuggestions);\n      this._deferred.resolve(suggestions);\n      return;\n    }\n    this._deferred.reject(new Error(\"Unexpected suggestion result\"));\n  }\n\n  _generateItems(options) {\n    this._items.replaceChildren();\n    for (let value of options.values) {\n      const matchIdx = value.toUpperCase().indexOf(options.input.toUpperCase());\n      const match = matchIdx >= 0 ? value.substr(0, options.input.length) : \"\";\n      value = value.substr(match.length);\n      this._items.appendChild(\n        <span class={this._class + \"__item searchsheet__section-link\"}>\n          <span class=\"searchsheet__section-link-icon UT-icon-UT_icon_70_search-16px\"></span>\n          <span class={this._class + \"__itemvalue\"}>\n            {match && <span class=\"searchsheet__suggestmatch\">{match}</span>}\n            {value}\n          </span>\n        </span>);\n    }\n  }\n\n  _doSelectItem(selectitem) {\n    const selectedvalue = selectitem.querySelector('.' + this._class + '__itemvalue').textContent;\n    if (!this.options.immediateresuggest) //prevent us from immediately processing our own input event\n      this._dontresuggest = true;\n    dompack.changeValue(this._node, selectedvalue);\n    this._dontresuggest = false;\n\n    dompack.dispatchCustomEvent(this._node,\n      \"searsia:searchsuggestion\",\n      {\n        bubbles: true,\n        cancelable: false,\n        detail: { value: selectedvalue }\n      });\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport { decodeString } from \"@webhare/std\";\nimport { getTid } from \"@webhare/gettid\";\n\nconst PHONE_UT_REGEX = /\\+3153489(\\d{4})/;\nconst PHONE_MOB_REGEX = /\\+316(\\d{2}){4}/;\n\nfunction addDebuggingInfo(hit, source) {\n  if (debugFlags.searsia) {\n    return (\n      <span class=\"searsia__debuginfo\">\n        {hit.rankscore} ({hit.score}|{source.rank}|{hit.urllang}|{source.resource})\n      </span>);\n  }\n}\n\nexport function createGeneralResult(hit, source, queryWords) {\n  let titleprefix = \"\";\n  let icon = \"ut-searchicon_01-ut-14px\";\n  if (source.type === \"serviceportal\") {\n    if (hit.isprivate)\n      icon = \"ut-searchicon_04-lock-12px\";\n    //ADDME: else icon = Service Portal icon\n  } else if (source.type === \"publication\") {\n    titleprefix = getTid(\"utwente_base:frontend.ws2016.js.searchsheet.publication\") + \" | \";\n    icon = \"ut-searchicon_08-book-12px\";\n  } else if (source.type === \"location\") {\n    titleprefix = getTid(\"utwente_base:frontend.ws2016.js.searchsheet.location\") + \" | \";\n    icon = \"UT-icon-UT_icon_16_pointer-24px\";\n  } else if (source.type === \"courses\") {\n    icon = \"UT-icon-UT_icon_93_education-16px\";\n  }\n\n  return (\n    <a class=\"searsia__result\" href={decodeString(hit.url, \"attribute\")}>\n      {addDebuggingInfo(hit, source)}\n      <span class=\"searsia__title\">{[titleprefix, highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")]}</span>\n      {hit.description &&\n        <span class=\"searsia__desc\">{highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}</span>\n      }\n      <span class=\"searsia__link\">\n        <span class={\"searsia__icon \" + icon}></span>\n        {hit.url && formatURL(decodeString(hit.url, \"attribute\"))}\n      </span>\n    </a>);\n}\n\nexport function createNewsResult(hit, source, extended, queryWords) {\n  if (extended)\n    return (\n      <div class=\"searsia__result searsia__result--news\" href={decodeString(hit.url, \"attribute\")}>\n        {addDebuggingInfo(hit, source)}\n        {hit.image && <a href={decodeString(hit.url, \"attribute\")} class=\"searsia__thumb\" style={`background-image: url(\"${hit.image}\")`}></a>}\n        <a href={decodeString(hit.url, \"attribute\")} class=\"searsia__title\">{highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")}</a>\n        <span class=\"searsia__desc\">\n          {<span class=\"searsia__desc-prefix\">\n            {source.resource === \"utoday\" ? getTid(\"utwente_base:frontend.ws2016.js.searchsheet.utoday\") + \": \" : \"\"}\n            {hit.date && decodeString(hit.date, \"attribute\")}\n          </span>}\n          {hit.description && highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}\n        </span>\n      </div>);\n  return (\n    <a class=\"searsia__result\" href={decodeString(hit.url, \"attribute\")}>\n      {addDebuggingInfo(hit, source)}\n      <span class=\"searsia__title\">{[getTid(\"utwente_base:frontend.ws2016.js.searchsheet.news\") + \" | \", highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")]}</span>\n      <span class=\"searsia__desc\">\n        {hit.date && <span class=\"searsia__desc-prefix\">{decodeString(hit.date, \"attribute\")}</span>}\n        {hit.description && highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}\n      </span>\n      <span class=\"searsia__link\">\n        <span class=\"searsia__icon ut-searchicon_03-news-12px\"></span>\n        {hit.url && formatURL(decodeString(hit.url, \"attribute\"))}\n      </span>\n    </a>);\n}\n\nexport function createEventResult(hit, source, extended, queryWords) {\n  if (extended)\n    return (\n      <div class=\"searsia__result searsia__result--news\" href={decodeString(hit.url, \"attribute\")}>\n        {addDebuggingInfo(hit, source)}\n        {hit.image && <a href={decodeString(hit.url, \"attribute\")} class=\"searsia__thumb\" style={`background-image: url(\"${hit.image}\")`}></a>}\n        <a href={decodeString(hit.url, \"attribute\")} class=\"searsia__title\">{highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")}</a>\n        <span class=\"searsia__desc\">\n          {hit.date && <span class=\"searsia__desc-prefix\">{decodeString(hit.date, \"attribute\")}</span>}\n          {hit.description && highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}\n        </span>\n      </div>);\n  return (\n    <a class=\"searsia__result\" href={decodeString(hit.url, \"attribute\")}>\n      {addDebuggingInfo(hit, source)}\n      <span class=\"searsia__title\">{[getTid(\"utwente_base:frontend.ws2016.js.searchsheet.event\") + \" | \", highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")]}</span>\n      <span class=\"searsia__desc\">\n        {hit.date && <span class=\"searsia__desc-prefix\">{decodeString(hit.date, \"attribute\")}</span>}\n        {hit.description && highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}\n      </span>\n      <span class=\"searsia__link\">\n        <span class=\"searsia__icon ut-searchicon_07-calendar-12px\"></span>\n        {hit.url && formatURL(decodeString(hit.url, \"attribute\"))}\n      </span>\n    </a>);\n}\n\nexport function createPeopleResult(hit, source, extended, queryWords) {\n  if (extended)\n    return (\n      <div class=\"searsia__result searsia__result--people\">\n        {addDebuggingInfo(hit, source)}\n        {hit.image && <span class=\"searsia__thumb\" style={`background-image: url(\"${hit.image}\")`}></span>}\n        <span class=\"searsia__toggle\"></span>\n        <span class=\"searsia__title\">{highlightQueryWords(decodeString(hit.name || hit.title, \"attribute\"), queryWords, \"searsia__title\")}</span>\n        <span class=\"searsia__desc\">\n          {hit.job && highlightQueryWords(decodeString(hit.job, \"attribute\"), queryWords, \"searsia__desc\")}\n        </span>\n        <div class=\"searsia__peopledetails\">\n          <div class=\"searsia__peopledetails-content\">\n            {hit.location &&\n              (hit.latitude && hit.longitude ?\n                <a href={getMapRouteLink(`${hit.latitude},${hit.longitude}`)} class=\"searsia__peopledetail\">\n                  <span class=\"searsia__peopledetail-icon UT-icon-UT_icon_16_pointer-24px\"></span>\n                  {decodeString(hit.location, \"attribute\")}\n                </a>\n                :\n                <span class=\"searsia__peopledetail\">\n                  <span class=\"searsia__peopledetail-icon UT-icon-UT_icon_16_pointer-24px\"></span>\n                  {decodeString(hit.location, \"attribute\")}\n                </span>\n              )\n            }\n            {hit.phone &&\n              <a href={`tel:${hit.phone}`} class=\"searsia__peopledetail\">\n                <span class=\"searsia__peopledetail-icon UT-icon-UT_icon_13_phone-24px\"></span>\n                {formatPhone(decodeString(hit.phone, \"attribute\"))}\n              </a>\n            }\n            {hit.mail &&\n              <a href={`mailto:${hit.mail}`} class=\"searsia__peopledetail\">\n                <span class=\"searsia__peopledetail-icon UT-icon-UT_icon_15_mail-24px\"></span>\n                {decodeString(hit.mail, \"attribute\")}\n              </a>\n            }\n            <a href={hit.url} class=\"searsia__peopledetail\">\n              <span class=\"searsia__peopledetail-icon UT-icon-UT_icon_40_avatar-24px\"></span>\n              {getTid(\"utwente_base:frontend.ws2016.js.searchsheet.peoplepage\")}\n            </a>\n          </div>\n        </div>\n      </div>);\n  return (\n    <a class=\"searsia__result\" href={decodeString(hit.url, \"attribute\")}>\n      {addDebuggingInfo(hit, source)}\n      <span class=\"searsia__title\">{[getTid(\"utwente_base:frontend.ws2016.js.searchsheet.people\") + \" | \", highlightQueryWords(decodeString(hit.name || hit.title, \"attribute\"), queryWords, \"searsia__title\")]}</span>\n      {hit.job &&\n        <span class=\"searsia__desc\">{highlightQueryWords(decodeString(hit.job, \"attribute\"), queryWords, \"searsia__desc\")}</span>\n      }\n      <span class=\"searsia__link\">\n        <span class=\"searsia__icon ut-searchicon_02-people-12px\"></span>\n        {hit.url && formatURL(decodeString(hit.url, \"attribute\"))}\n      </span>\n    </a>);\n}\n\nexport function createVideoResult(hit, source, extended, queryWords) {\n  if (extended)\n    return (\n      <div class=\"searsia__result searsia__result--video\">\n        {addDebuggingInfo(hit, source)}\n        <a href={decodeString(hit.url, \"attribute\")}>\n          {hit.image &&\n            <span class=\"searsia__thumb\" style={`background-image: url(\"${hit.image}\")`}>\n              <span class=\"searsia__playbutton themecolor--bg\"></span>\n              <span class=\"searsia__playbutton-icon themecolor--fg\"></span>\n            </span>\n          }\n          <span class=\"searsia__title\">{highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")}</span>\n          <span class=\"searsia__desc\">\n            {hit.date && <span class=\"searsia__desc-prefix\">{decodeString(hit.date, \"attribute\")}</span>}\n            {hit.description && highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}\n          </span>\n        </a>\n      </div>);\n  return (\n    <a class=\"searsia__result\" href={decodeString(hit.url, \"attribute\")}>\n      {addDebuggingInfo(hit, source)}\n      <span class=\"searsia__title\">{[getTid(\"utwente_base:frontend.ws2016.js.searchsheet.video\") + \" | \", highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")]}</span>\n      {hit.description &&\n        <span class=\"searsia__desc\">{highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}</span>\n      }\n      <span class=\"searsia__link\">\n        <span class=\"searsia__icon ut-searchicon_05-play-12px\"></span>\n        {hit.url && formatURL(decodeString(hit.url, \"attribute\"))}\n      </span>\n    </a>);\n}\n\nexport function createImageResult(hit, source, extended, queryWords) {\n  if (extended) {\n    return (\n      <a class=\"searsia__imagegrid__item\" href={hit.url} title={decodeString(hit.title, \"attribute\")}>\n        <img src={hit.image} class=\"searsia__imagegrid__item__image\" />\n        {addDebuggingInfo(hit, source)}\n      </a>);\n  }\n  return (\n    <a class=\"searsia__result\" href={decodeString(hit.url, \"attribute\")}>\n      {addDebuggingInfo(hit, source)}\n      <span class=\"searsia__title\">{[getTid(\"utwente_base:frontend.ws2016.js.searchsheet.image\") + \" | \", highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__title\")]}</span>\n      {hit.description &&\n        <span class=\"searsia__desc\">{highlightQueryWords(decodeString(hit.description, \"attribute\"), queryWords, \"searsia__desc\")}</span>\n      }\n      <span class=\"searsia__link\">\n        <span class=\"searsia__icon ut-searchicon_01-ut-14px\"></span>\n        {hit.url && formatURL(decodeString(hit.url, \"attribute\"))}\n      </span>\n    </a>);\n}\n\nexport function createRelatedResults(hits, _source, queryWords) {\n  return (\n    <div class=\"searsia__related\">\n      <div class=\"searsia__related__title\">{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.related\") + \":\"}</div>\n      <div class=\"searsia__related__links\">\n        {hits.map(hit =>\n          <span class=\"searsia__related__link\">\n            <span class=\"searsia__related__linkicon UT-icon-UT_icon_70_search-16px\"></span>\n            {highlightQueryWords(decodeString(hit.title, \"attribute\"), queryWords, \"searsia__related__link\")}\n          </span>)\n        }\n      </div>\n    </div>\n  );\n}\n\nexport function createFilteredResult() {\n  return (\n    <div class=\"searsia__filtered\">\n      {getTid(\"utwente_base:frontend.ws2016.js.searchsheet.filteredresults\")}\n    </div>\n  );\n}\n\nfunction highlightQueryWords(text, words, className) {\n  if (!words)\n    return text;\n\n  const result = [];\n  while (text) {\n    // Find the first matching word\n    const match = text.match(words);\n    result.push(match ? text.substr(0, match.index) : text);\n    if (!match)\n      break;\n\n    result.push(<span class={className + \"--match ut-querymatch\"}>{match[0]}</span>);\n    text = text.substr(match.index + match[0].length);\n  }\n  return result;\n}\n\nfunction formatURL(url) {\n  if (url.indexOf(\"http://\") === 0)\n    url = url.substr(7);\n  else if (url.indexOf(\"https://\") === 0)\n    url = url.substr(8);\n  if (url.indexOf(\"www.\") === 0)\n    url = url.substr(4);\n  return url;\n}\n\nexport function formatPhone(phone) {\n  let match = phone.match(PHONE_UT_REGEX);\n  if (match) {\n    return <span class=\"searsia__phone\">+31 (0)53 489 <b>{match[1]}</b></span>;\n  } else {\n    match = phone.match(PHONE_MOB_REGEX);\n    if (match) {\n      return <span class=\"searsia__phone\">+31 (0)6 {match.slice(1).join(\" \")}</span>;\n    }\n  }\n  return phone;\n}\n\nexport function getMapRouteLink(coord) {\n  return `https://maps.google.com/maps?hl=${encodeURIComponent(getTid.tidLanguage)}&daddr=${encodeURIComponent(coord)}&z=15`;\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport { decodeString } from \"@webhare/std\";\nimport { getTid } from \"@webhare/gettid\";\nimport * as searsiaTypes from \"./searsiatypes\";\nimport * as managedctas from \"../crm/managedctas\";\n\n\nlet shownWidget = null;\nlet locationRequestId = 0;\n\nexport function showSearsiaWidgets(hits, ctaslots, ctaprops, eventsurl) {\n  let node;\n  if (!hits) {\n    // If hits is null, this is the first call after the search was initiated\n    shownWidget = null;\n\n    const result = tryMatchSearsiaCTA(ctaslots, ctaprops);\n    if (result) {\n      node = result.node;\n      shownWidget = { type: result.type, node: result.node };\n    }\n  } else {\n    // Check for interesting result types\n    for (const result of hits) {\n      switch (result.source.type) {\n        case \"location\":\n          {\n            node = createLocationWidget(result) || node;\n          } break;\n        case \"event\":\n          {\n            node = createEventsWidget(result, eventsurl) || node;\n          } break;\n      }\n    }\n  }\n  return node;\n}\n\nfunction tryMatchSearsiaCTA(ctaslots, props) {\n  // Try to match search query with search CTAs\n  for (const ctaslot of ctaslots) {\n    for (const cta of ctaslot.cta.ctas) {\n      try {\n        managedctas.tryMatchCTAConfig(cta.ctaconfig, props);\n        if (debugFlags.umc)\n          console.info(`[umc] Showing ${ctaslot.type} CTA ${cta.ctaconfig.tag}`, cta);\n\n        let node;\n        switch (ctaslot.type) {\n          case \"highlight\":\n            {\n              node = createHighlightCTA(cta);\n            } break;\n          case \"widget\":\n            {\n              node = createWidgetCTA(cta);\n            } break;\n          default:\n            throw `Unknown CTA slot type '${ctaslot.type}'`;\n        }\n        if (node)\n          return { type: ctaslot.type, node };\n      } catch (e) {\n        if (e instanceof managedctas.CTAMatchError) {\n          if (debugFlags.umc)\n            console.warn(`[umc] Not showing ${ctaslot.type} CTA ${cta.ctaconfig.tag}: ${e.message}`);\n        } else\n          throw e;\n      }\n    }\n  }\n}\n\nfunction createHighlightCTA(cta) {\n  let title, description;\n  const widgetNode =\n    <div class=\"searsia__widget searsia__widget--highlight\" data-widget-type=\"highlight\">\n      <div class=\"searsia__highlight-text\">\n        {title = cta.title && (cta.buttonlink ?\n          <a class=\"searsia__highlight-title\" href={cta.buttonlink} target={cta.buttonnewwindow ? \"_blank\" : \"\"} rel=\"noreferrer\" />\n          :\n          <div class=\"searsia__highlight-title\" />\n        )}\n        {description = cta.description && <div class=\"searsia__highlight-description\" />}\n        {cta.buttonlink && cta.buttontitle &&\n          <a class=\"searsia__highlight-link\" href={cta.buttonlink} target={cta.buttonnewwindow ? \"_blank\" : \"\"} rel=\"noreferrer\">{cta.buttontitle}</a>\n        }\n      </div>\n      {cta.photo && (cta.buttonlink ?\n        <a class=\"searsia__highlight-image\" style={`background-image: url(\"${cta.photo.link}\");` + (cta.photo.refpoint_backgroundposition ? `background-position: ${cta.photo.refpoint_backgroundposition};` : \"\")} href={cta.buttonlink} target={cta.buttonnewwindow ? \"_blank\" : \"\"} rel=\"noreferrer\">\n          <span class=\"searsia__highlight-suggested\">{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.suggestedresult\")}</span>\n        </a>\n        :\n        <div class=\"searsia__highlight-image\" style={`background-image: url(\"${cta.photo.link}\");` + (cta.photo.refpoint_backgroundposition ? `background-position: ${cta.photo.refpoint_backgroundposition};` : \"\")}>\n          <span class=\"searsia__highlight-suggested\">{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.suggestedresult\")}</span>\n        </div>\n      )\n      }\n    </div>;\n  if (title)\n    title.innerHTML = cta.title;\n  if (description)\n    description.innerHTML = cta.description;\n  return widgetNode;\n}\n\nfunction createWidgetCTA(cta) {\n  let title, description;\n  const widgetNode =\n    <div class=\"searsia__widget searsia__widget--cta\" data-widget-type=\"cta\">\n      {title = cta.title && <div class=\"inlinecta__title\" />}\n      {cta.buttonlink && cta.buttontitle &&\n        <a class=\"inlinecta__button themecolor--bg\" href={cta.buttonlink} data-wh-datalayer-onclick-cta_type=\"inline-button-cta\" data-wh-datalayer-onclick-event=\"cta-click\" data-wh-datalayer-onclick-click_text={cta.buttontitle} data-wh-datalayer-onclick-click_url={cta.buttonlink} target={cta.buttonnewwindow ? \"_blank\" : \"\"} rel=\"noreferrer\">{cta.buttontitle}</a>\n      }\n      {description = cta.description &&\n        <div class=\"inlinecta__description\">\n          <div class=\"inlinecta__icon UT-icon-UT_icon_117_paperclip-64px\"></div>\n        </div>\n      }\n    </div>;\n  if (title)\n    title.innerHTML = cta.title;\n  if (description) {\n    const descriptionHTML = <span />;\n    descriptionHTML.innerHTML = cta.description;\n    description.append(...descriptionHTML.childNodes);\n  }\n  return widgetNode;\n}\n\nfunction createLocationWidget(result) {\n  let node;\n  if (!shownWidget) {\n    if (debugFlags.searsia)\n      console.info(\"[searsia] Showing location widget\", result);\n    node = <div class=\"widget searsia__widget searsia__widget--location searsia__widget--loading\" data-widget-type=\"location\" />;\n    shownWidget = { type: \"location\", result, node, locreqid: ++locationRequestId };\n    setTimeout(() => retrieveLocation(result.hit.title, locationRequestId).then(() => debugFlags.searsia && console.info(`[searsia] Done for '${result.hit.title}'`)));\n  } else if (shownWidget.type == \"location\") {\n    setTimeout(() => retrieveLocation(result.hit.title, locationRequestId).then(() => debugFlags.searsia && console.info(`[searsia] Done for '${result.hit.title}'`)));\n  }\n  return node;\n}\n\nasync function retrieveLocation(name, locreqid) {\n  if (!name || !shownWidget)\n    return;\n\n  if (debugFlags.searsia)\n    console.log(`[searsia] Fetching data for location '${name}'`);\n  const response = await fetch(\"/.publisher/sd/utwente_base/ws2016/location.shtml?name=\" + encodeURIComponent(name) + \"&lang=\" + encodeURIComponent(getTid.tidLanguage), { credentials: 'same-origin' });\n  if (response.status != 200) {\n    if (debugFlags.searsia)\n      console.warn(`[searsia] Location '${name}' not found`);\n    return;\n  }\n  const data = await response.json();\n\n  // A new search may have been started while we were waiting for the fetch result\n  if (!shownWidget || shownWidget.locreqid != locreqid) {\n    if (debugFlags.searsia)\n      console.log(`[searsia] Widget no longer shown`, shownWidget.locreqid, locreqid);\n    return;\n  }\n\n  const node =\n    <div class=\"widget__front\">\n      {data.img &&\n        <div class=\"widget__photos\">\n          <span class=\"widget__photoslide widget__photoslide--fullwidth\" style={`background-image: url(\"${data.img.link}\")`}></span>\n        </div>\n      }\n      <div class=\"widget__title widget__title--belowphotos\">\n        {decodeString(data.title, \"attribute\")}\n        {data.address &&\n          <span>\n            <br />{data.address.street + \" \" + data.address.nr_detail}\n            <br />{data.address.zip + \" \" + data.address.city}\n          </span>\n        }\n      </div>\n      <div class=\"widget__list\">\n        {data.phone &&\n          <a href={\"tel:\" + decodeString(data.phone, \"attribute\")} class=\"widget__listitem widget__listitem--link\">\n            <div class=\"overflow__container\">\n              <span class=\"widget__listitem-icon UT-icon-UT_icon_13_phone-24px\"></span>\n              <span class=\"widget__listitem-text\">{searsiaTypes.formatPhone(decodeString(data.phone, \"attribute\"))}</span>\n            </div>\n          </a>\n        }\n        {data.email &&\n          <a href={\"mailto:\" + decodeString(data.email, \"attribute\")} class=\"widget__listitem widget__listitem--link overflow\">\n            <div class=\"overflow__container\">\n              <span class=\"widget__listitem-icon UT-icon-UT_icon_15_mail-24px\"></span>\n              <span class=\"softbreak\">&nbsp;</span>\n              <span class=\"widget__listitem-text\" data-overflow={getTid(\"utwente_base:frontend.ws2016.js.searchsheet.overflow--email\")}>{decodeString(data.email, \"attribute\")}</span>\n            </div>\n          </a>\n        }\n        <a href={data.mappdfurl} class=\"widget__listitem widget__listitem--link\">\n          <div class=\"overflow__container\">\n            <span class=\"widget__listitem-icon UT-icon-UT_icon_22_file-pdf-24px\"></span>\n            <span class=\"widget__listitem-text\">{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.downloadmap\")}</span>\n          </div>\n        </a>\n        {data.coord &&\n          <a href={searsiaTypes.getMapRouteLink(data.coord)} class=\"widget__listitem widget__listitem--link\">\n            <span class=\"widget__listitem-icon UT-icon-UT_icons_164_navigate-24px\"></span>\n            <span class=\"widget__listitem-text\">{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.route\")}</span>\n          </a>\n        }\n      </div>\n    </div>;\n  shownWidget.node.appendChild(node);\n  shownWidget.node.classList.remove(\"searsia__widget--loading\");\n}\n\nfunction createEventsWidget(result, eventsurl) {\n  let node;\n  if (!shownWidget) {\n    if (debugFlags.searsia)\n      console.info(\"[searsia] Showing events widget\", result);\n\n    // If we don't have an explicit 'all events' url, try to extract it from the first result\n    // (Assume it is always a webhare events page with virtual subpath beginning with '!/')\n    const alleventsurl = eventsurl || result.hit.url.split(\"!/\")[0];\n    node =\n      <div class=\"widget searsia__widget searsia__widget--event\" data-widget-type=\"event\">\n        <div class=\"widget__front\">\n          <div class=\"widget__title widget__title--withicon\">\n            <span class=\"widget__title-icon UT-icon-UT_icon_11_events-24px\" />{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.events\")}\n          </div>\n          {result.hit.image &&\n            <div class=\"widget__photos\">\n              <span class=\"widget__photoslide widget__photoslide--fullwidth\" style={`background-image: url(\"${result.hit.image}\")`}></span>\n            </div>\n          }\n          <div class=\"widget__list\">\n            <a class=\"widget__listitem widget__listitem--link\" href={decodeString(result.hit.url, \"attribute\")}>\n              <span class=\"widget__listitem-text\">{decodeString(result.hit.title, \"attribute\")}</span>\n              {result.hit.date && <span class=\"widget__listitem-subtext\">{decodeString(result.hit.date, \"attribute\")}</span>}\n            </a>\n          </div>\n          <a class=\"widget__link\" href={alleventsurl}>{getTid(\"utwente_base:frontend.ws2016.js.searchsheet.allevents\")}</a>\n        </div>\n      </div>;\n    shownWidget = { type: \"event\", result, node };\n  } else if (shownWidget.type == \"event\") {\n    const eventNode =\n      <a class=\"widget__listitem widget__listitem--link\" href={decodeString(result.hit.url, \"attribute\")}>\n        <span class=\"widget__listitem-text\">{decodeString(result.hit.title, \"attribute\")}</span>\n        {result.hit.date && <span class=\"widget__listitem-subtext\">{decodeString(result.hit.date, \"attribute\")}</span>}\n      </a>;\n    //TODO: Order by date\n    shownWidget.node.querySelector(\".widget__list\").appendChild(eventNode);\n  }\n  return node;\n}\n","import * as dompack from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport { getFrontendData } from \"@webhare/frontend\";\nimport \"./theme-ws2016.tsx\";\nimport \"./theme.css\";\n\n/*\n  To give something an animated color in ws2026, just set the color to var(--theme-color) or var(--theme-color-hover)\n*/\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_design:theme\": {\n      colorScheme: string[];\n      gradientColor?: string;\n    };\n  }\n}\n\ntype AnimationStateEvent = CustomEvent<{ active: boolean }>;\n\ndeclare global {\n  interface GlobalEventHandlersEventMap {\n    \"ws2026:animationstate\": AnimationStateEvent;\n  }\n}\n\n// Disable the color animation on Chrome for Android, see #2712\nconst browser = dompack.getBrowser();\nconst disableColorAnimation = browser.name === \"chrome\" && browser.platform === \"android\";\n\nconst animColorDuration = 10; // seconds per color\nlet animDuration = 0; // seconds\nconst animSteps = 5; // per second\nlet animDelay = 0; // seconds\n\nexport function initTheme() {\n  // ws2016 uses jssiteconfig, ws2026 uses frontendData\n  const frontendData = getFrontendData(\"utwente_design:theme\", { allowMissing: true });\n  if (!frontendData)\n    return;\n\n  if (debugFlags.uds)\n    document.body.append(<theme-state></theme-state>);\n\n  const colorScheme = frontendData.colorScheme;\n  animDuration = colorScheme.length * animColorDuration;\n\n  if (colorScheme.length <= 1) {\n    if (debugFlags.uds)\n      console.log(\"[uds] No color animation\", colorScheme);\n    return;\n  }\n\n  // Read the stored animation start to pick up where we left off\n  let saveStart = dompack.getLocal<number>(\"ucs-start\");\n  if (saveStart) {\n    saveStart = (Date.now() - saveStart) % (animDuration * 1000);\n    if (saveStart > 0)\n      animDelay = -~~(saveStart / 1000);\n  } else\n    dompack.setLocal(\"ucs-start\", Date.now());\n\n  if (!disableColorAnimation && !debugFlags.unc) {\n    if (debugFlags.uds)\n      console.log(\"[uds] Activate the color scheme animations\");\n\n    // Define the custom animation properties\n    document.documentElement.style.setProperty(\"--anim-duration\", `${animDuration}s`);\n    document.documentElement.style.setProperty(\"--anim-delay\", `${animDelay}s`);\n    // steps() works on each keyframe (one keyframe per color), animSteps is in steps per second\n    document.documentElement.style.setProperty(\"--anim-steps\", `steps(${animSteps * animColorDuration}, end)`);\n\n    // Activate the 'color-scheme' animation, which animates the defined --theme-color* and --gradient-color* properties\n    document.documentElement.classList.add(\"ws2026-animation\");\n    document.addEventListener(\"ws2026:animationstate\", event => handleAnimationStateEvent(event));\n  }\n}\n\nfunction handleAnimationStateEvent(event: AnimationStateEvent) {\n  document.documentElement.classList.toggle(\"ws2026-animation\", event.detail.active);\n}\n","import * as whintegration from \"@mod-system/js/wh/integration\";\nimport * as dompack from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport \"./theme.scss\";\n\n/*\n  To give something an animated color in ws2016, just set the color to var(--theme-color), var(--theme-color-cta) or var(--theme-color-cta-hover)\n*/\n\n/* This is the old WS2016 implementation, which relies on whintegration.config and a 'theme__docstate' element */\nif (whintegration.config.site.colorscheme) {\n  // Disable the color animation on Chrome for Android, see #2712\n  const browser = dompack.getBrowser();\n  const disableColorAnimation = browser.name === \"chrome\" && browser.platform === \"android\";\n\n  const colorScheme = whintegration.config.site.colorscheme as string[];\n  const animateThemeColor = (whintegration.config.site.animatethemecolor as boolean) ?? true;\n  const animDuration = colorScheme.length * 10;\n  const animSteps = 5; // per second\n  let animDelay = 0; // seconds\n\n  let colorSchemeNode: HTMLElement | null = null,\n    colorSchemeCTANode: HTMLElement | null = null,\n    colorSchemeCTAHoverNode: HTMLElement | null = null;\n\n  let syncTimeout: number | null = null;\n  let curThemeColor: string | undefined = undefined,\n    curThemeColorCTA: string | undefined = undefined,\n    curThemeColorCTAHover: string | undefined = undefined;\n\n  function initializeTheme(node: HTMLElement) {\n    colorSchemeNode = node;\n    colorSchemeCTANode = dompack.qS<HTMLElement>(\".theme__docstate-cta\")!;\n    colorSchemeCTAHoverNode = dompack.qS<HTMLElement>(\".theme__docstate-cta-hover\")!;\n\n    if (!animateThemeColor || colorScheme.length <= 1) {\n      if (debugFlags.uds)\n        console.log(\"[uds] No color animation\", animateThemeColor, colorScheme);\n      return;\n    }\n\n    // Read the stored animation start to pick up where we left off\n    let saveStart = dompack.getLocal<number>(\"ucs-start\");\n    if (saveStart) {\n      saveStart = (Date.now() - saveStart) % (animDuration * 1000);\n      if (saveStart > 0)\n        animDelay = -~~(saveStart / 1000);\n    } else\n      dompack.setLocal(\"ucs-start\", Date.now());\n\n    // Check if custom properties are supported\n    let registered = false;\n    if (window.CSS.registerProperty) {\n      try {\n        // If '@property' is not available (if it's available, it will have the fallback value), register explicity\n        if (!getComputedStyle(colorSchemeNode).getPropertyValue(\"--theme-color\")) {\n          if (debugFlags.uds)\n            console.log(\"[uds] Register --theme-color* properties\");\n          window.CSS.registerProperty(\n            {\n              name: \"--theme-color\",\n              syntax: \"<color>\",\n              initialValue: \"transparent\",\n              inherits: false\n            });\n          window.CSS.registerProperty(\n            {\n              name: \"--theme-color-cta\",\n              syntax: \"<color>\",\n              initialValue: \"transparent\",\n              inherits: false\n            });\n          window.CSS.registerProperty(\n            {\n              name: \"--theme-color-cta-hover\",\n              syntax: \"<color>\",\n              initialValue: \"transparent\",\n              inherits: false\n            });\n        } else if (debugFlags.uds)\n          console.log(\"[uds] Using --theme-color* @property's\");\n\n        if (!disableColorAnimation && !debugFlags.unc) {\n          // Activate the 'colorscheme*' animations, which animate the defined --theme-color* properties\n          setAnimation(document.documentElement, [\"colorscheme\", \"colorscheme-cta\", \"colorscheme-cta-hover\"]);\n        }\n        // Set the colorscheme nodes background to the --theme-color* properties to visualize it\n        colorSchemeNode.style.backgroundColor = \"var(--theme-color)\";\n        colorSchemeCTANode.style.backgroundColor = \"var(--theme-color-cta)\";\n        colorSchemeCTAHoverNode.style.backgroundColor = \"var(--theme-color-cta-hover)\";\n\n        registered = true;\n      } catch (e) {\n        if (debugFlags.uds)\n          console.error(\"[uds] Registration failed\", e);\n      }\n    }\n    if (!registered) {\n      if (debugFlags.uds)\n        console.log(\"[uds] @property and registerProperty not available, falling back to color sync\");\n\n      if (!disableColorAnimation && !debugFlags.unc) {\n        // Set the 'colorscheme-background*' animations to the colorscheme nodes, which update their background colors\n        setAnimation(colorSchemeNode, \"colorscheme-background\");\n        setAnimation(colorSchemeCTANode, \"colorscheme-background-cta\");\n        setAnimation(colorSchemeCTAHoverNode, \"colorscheme-background-cta-hover\");\n        // Sync the colorscheme node background colors to the --theme-color* variables\n        window.setInterval(checkThemeColors, 1000 / animSteps);\n        // Initial sync\n        checkThemeColors();\n      }\n    }\n\n    if (disableColorAnimation || debugFlags.unc) {\n      // Color animation is disabled, fall back to 'Dogwood Rose' (which is the second color in the scheme; if there's only\n      // one color, there's no animation at all)\n      const randomColor = colorScheme[1];\n      if (debugFlags.uds)\n        console.log(\"[uds] Color animation disabled, showing random color\", randomColor);\n      curThemeColor = randomColor;\n      curThemeColorCTA = randomColor;\n      curThemeColorCTAHover = randomColor;\n      setThemeColors();\n    }\n  }\n\n  function checkThemeColors() {\n    syncTimeout = syncTimeout || requestAnimationFrame(syncThemeColors);\n  }\n\n  function syncThemeColors() {\n    syncTimeout = null;\n    const anyChanges = [];\n    // Get the current colorscheme node background colors and update the --theme-color* variables\n    let themeColor = getComputedStyle(colorSchemeNode!).backgroundColor;\n    if (themeColor !== curThemeColor) {\n      curThemeColor = themeColor;\n      anyChanges.push(\"color\");\n    }\n    themeColor = getComputedStyle(colorSchemeCTANode!).backgroundColor;\n    if (themeColor !== curThemeColorCTA) {\n      curThemeColorCTA = themeColor;\n      anyChanges.push(\"color-cta\");\n    }\n    themeColor = getComputedStyle(colorSchemeCTAHoverNode!).backgroundColor;\n    if (themeColor !== curThemeColorCTAHover) {\n      curThemeColorCTAHover = themeColor;\n      anyChanges.push(\"color-cta-hover\");\n    }\n    if (anyChanges.length)\n      setThemeColors(anyChanges);\n  }\n\n  function setThemeColors(props?: string[]) {\n    if (curThemeColor && (!props || props.includes(\"color\")))\n      document.documentElement.style.setProperty(\"--theme-color\", curThemeColor);\n    if (curThemeColorCTA && (!props || props.includes(\"color-cta\")))\n      document.documentElement.style.setProperty(\"--theme-color-cta\", curThemeColorCTA);\n    if (curThemeColorCTAHover && (!props || props.includes(\"color-cta-hover\")))\n      document.documentElement.style.setProperty(\"--theme-color-cta-hover\", curThemeColorCTAHover);\n  }\n\n  function setAnimation(node: HTMLElement, names: string | string[]) {\n    const playState = disableColorAnimation || debugFlags.unc ? \"paused\" : \"\";\n    // steps() works on each keyframe, which all last 10s, animSteps is in steps per second s\n    const animNames = Array.isArray(names) ? names : [names];\n    const animationStyle = animNames.map(name => `${name} ${animDuration}s ${animDelay}s steps(${animSteps * 10}, end) infinite ${playState}`).join(\", \");\n    node.style.animation = animationStyle;\n\n    // Workaround Safari/Firefix resetting animation delay\n    if (animDelay) {\n      const observer = new MutationObserver(() => {\n        const curDelay = parseInt(node.style.animationDelay);\n        if (!curDelay) {\n          if (debugFlags.uds)\n            console.warn(`[uds] Resetting ${names} animation delay`, curDelay, animDelay);\n          node.style.animationDelay = `${animDelay}s`;\n        }\n        observer.disconnect();\n      });\n      observer.observe(node, { attributes: true, attributeFilter: [\"style\"] });\n    }\n  }\n\n  dompack.register(\".theme__docstate\", node => initializeTheme(node));\n}\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/webdesigns/ws2016/src/site.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_base\",\"nl\",{\"frontend\":{\"ws2016\":{\"js\":{\"addtocalendar\":\"Voeg aan kalender toe\",\"consentblock-accept3thpartycookies\":\"Accepteer cookies van derden\",\"consentblock-facebook-accept3thpartycookies-suffix\":\"om de plugin te laden.\",\"consentblock-facebook-line1\":\"Deze Facebook-plugin plaatst marketingcookies.\",\"consentblock-facebook-title\":\"Dit element plaatst cookies\",\"consentblock-soundcloud-accept3thpartycookies-suffix\":\"om de speler te laden.\",\"consentblock-soundcloud-directlink\":\"de website van SoundCloud.\",\"consentblock-soundcloud-directlink-prefix\":\"Luisteren zonder cookies kan op\",\"consentblock-soundcloud-line1\":[\"De speler van \",1,\" plaatst marketingcookies.\"],\"consentblock-soundcloud-title\":\"Deze audiospeler plaatst cookies\",\"consentblock-twitterembed-accept3thpartycookies-suffix\":\"om de tijdlijn te bekijken.\",\"consentblock-twitterembed-line1\":\"De Twitter/X tijdlijn plaatst marketingcookies.\",\"consentblock-video-accept3thpartycookies-suffix\":\"om de speler te laden.\",\"consentblock-video-directlink\":[\"de website van \",1,\".\"],\"consentblock-video-directlink-prefix\":\"Kijken zonder cookies kan op\",\"consentblock-video-line1\":[\"De speler \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"\",\"subs\":[],\"subselse\":[\"van \",1]},\" plaatst marketingcookies.\"],\"consentblock-video-title\":\"Deze videospeler plaatst cookies\",\"details\":\"Details\",\"dialog-close-arialabel\":\"Sluit popup\",\"email\":\"Je e-mailadres\",\"error-imagenotfound\":\"Afbeelding niet gevonden\",\"error-invalidemail\":\"Fout in e-mailadres\",\"error-invalidurl\":\"Onbekende url\",\"imageissendto\":\"Afbeelding is verstuurd naar:\",\"landmark-deeplinks-arialabel\":\"Inhoudsopgave\",\"list\":\"Lijst\",\"nosuggestresults\":\"Geen resultaten\",\"notavalidmobilephonenumber\":\"Dit is geen geldig mobiel nummer.\",\"notavalidphonenumber\":\"Dit is geen geldig telefoonnummer.\",\"readmore\":\"Lees verder\",\"starsrequired\":\"* betekent dat een veld verplicht is\",\"submit\":\"Verstuur\",\"submitting\":\"Versturen...\",\"calendar\":{\"appleical\":\"Apple iCal\",\"facebook\":\"Facebook Event\",\"google\":\"Google Calendar\",\"outlook\":\"Outlook Calendar\",\"outlookcom\":\"Outlook.com\",\"yahoo\":\"Yahoo Kalender\"},\"filteredoverview\":{\"feedbackbar-noresults\":\"Er zijn geen resultaten\",\"feedbackbar-result\":\"Resultaat\",\"feedbackbar-results\":[1,\" resultaten\"],\"feedbackbar-resultslimited\":[\"De eerste \",2,\" resultaten worden getoond (van de totaal \",1,\" resultaten)\"],\"hidefilters_header\":\"Verberg filters\",\"search\":\"Zoeken\",\"showfilters_header\":\"Toon filters\",\"tease-noresults\":\"Geen resultaten\",\"tease-result\":[\"Toon \",1,\" resultaat\"],\"tease-results\":[\"Toon \",1,\" resultaten\"]},\"managedcta\":{\"beacon\":[\"Het beacon '\",1,\"' is getriggerd\"],\"beacon-maxdays\":[\"Het beacon '\",1,\"' is getriggerd in de afgelopen \",{\"t\":\"ifparam\",\"p\":2,\"value\":\"1\",\"subs\":[\"dag\"],\"subselse\":[2,\" dagen\"]}],\"beacons-skipped\":[\"Het beacon '\",1,\"' is niet getriggerd\"],\"beacons-skipped-none\":\"Geen enkel beacon is getriggerd\",\"beacons-skipped-time\":[\"Het beacon '\",1,\"' zou getriggerd moeten zijn voor \",2,\", maar het is nu \",3],\"countries\":[\"Het GeoIP-land is een van \",1],\"countries-skipped\":[\"De landcode '\",2,\"' is niet een van \",1],\"explanation\":\"Deze CTA wordt getoond wanneer\",\"explanation-skipped\":\"Deze CTA wordt niet getoond omdat\",\"noctatoshow\":\"Geen van de CTA's voldoet aan de voorwaarden\",\"publish_from\":[\"De pagina wordt bekeken na \",1],\"publish_from-skipped\":[\"De huidige datum \",2,\" ligt voor de publicatiedatum \",1],\"publish_until\":[\"De pagina wordt bekeken voor \",1],\"publish_until-skipped\":[\"De huidige datum \",2,\" ligt na de publicatiedatum \",1],\"query\":[\"De zoekterm matcht een van de zoektermen \",1],\"query-skipped\":[\"De zoekterm '\",1,\"' matcht met geen van de zoektermen\"],\"query-skipped-error\":[\"De zoekterm '\",1,\"' veroorzaakte een fout: \",2],\"regex\":[\"De URL matcht een van de reguliere expressies \",1],\"regex-exclude\":[\"De URL matcht geen van de reguliere expressies \",1],\"regex-skipped\":[\"De URL '\",2,\"' matcht de reguliere expressie \",1],\"regex-skipped-error\":[\"De reguliere expressie '\",1,\"' veroorzaakte een fout: \",2],\"regex-skipped-none\":[\"De URL '\",1,\"' matcht geen van de reguliere expressies\"]},\"meetings\":{\"error-description\":[\"Er is een fout opgetreden bij verwerken van de bijeenkomst.\",\"\\n\",\"Probeer het later opnieuw\"],\"error-title\":\"Fout tijdens verwerken\",\"thanks-description\":\"Uw verzoek voor de bijeenkomst is opgeslagen. Er wordt binnenkort contact met u opgenomen.\",\"thanks-title\":\"Bijeenkomst is opgeslagen\"},\"neoform\":{\"authorizednotset\":\"Om de zichtbaarheid te beperken moet minstens één ontvanger of type medewerker worden geselecteerd.\",\"image-invalid-width\":[\"De breedte van de afbeelding voldoet niet aan de eisen van \",2,\" pixels. Het vult niet het hele gebied bovenaan de pagina. We vullen de ontbrekende ruimte met een gegenereerde achtergrond. Als je dit niet wilt, upload dan een afbeelding die voldoet aan de minimale breedteeisen (\",2,\" pixels).\"],\"image-read-error\":\"De geüploade afbeelding kon niet worden gelezen.\",\"minheight\":[\"De afbeelding is te klein. Deze moet minimaal \",2,\" pixels hoog zijn.\"]},\"newsevents\":{\"archive\":\"Toon archief\",\"next_article\":\"Volgend event\",\"next_article-news\":\"Volgend bericht\",\"noresults\":\"Geen resultaten\",\"noupcoming\":\"Er zijn op dit moment geen aankomende evenementen\",\"previous_article\":\"Vorig event\",\"previous_article-news\":\"Vorig bericht\",\"thanks-cultural\":\"Bedankt voor de reservering\",\"thanks-event\":\"Bedankt voor de registratie\",\"upcoming\":\"Ga naar evenementen\"},\"osiris\":{\"back\":\"Terug\",\"goal\":\"Doel\",\"loading\":\"Laden...\",\"more\":\"Lees meer\",\"moredetailslink\":[\"Ga naar <a href=\\\"\",1,\"\\\" target=\\\"osiris\\\">het detailoverzicht</a> in de OSIRIS Onderwijscatalogus\"],\"nocoursefound\":\"Vak niet gevonden\"},\"pagefilters\":{\"close-filters\":\"Verberg filters\",\"daterange-from\":\"Van\",\"daterange-till\":\"Tot\",\"reset\":\"Filters wissen\",\"search-placeholder\":\"Zoeken\",\"search-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 resultaat\"],\"subselse\":[1,\" resultaten\"]}],\"show-filters\":\"Toon filters\",\"show-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"Geen resultaten\"],\"subselse\":[\"Toon \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 resultaat\"],\"subselse\":[1,\" resultaten\"]}]}]},\"searchsheet\":{\"allevents\":\"Toon alle events\",\"downloadmap\":\"Download de plattegrond\",\"event\":\"Event\",\"events\":\"Events\",\"filteredresults\":\"Sommige zoekresultaten zijn verwijderd\",\"image\":\"Afbeelding\",\"location\":\"Locatie\",\"news\":\"Nieuws\",\"overflow--email\":\"Stuur een e-mail\",\"people\":\"Persoon\",\"peoplepage\":\"People Page\",\"publication\":\"Publicatie\",\"related\":\"Gerelateerde zoekopdrachten\",\"results\":[{\"t\":\"tag\",\"tag\":\"b\",\"subs\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"Geen resultaten\"],\"subselse\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 resultaat\"],\"subselse\":[1,\" resultaten\"]}]}]},\" voor \\\"\",2,\"\\\"\",{\"t\":\"ifparam\",\"p\":3,\"value\":\"\",\"subs\":[],\"subselse\":[\". Bedoelde je misschien \\\"%S%\",3,\"%/S%\\\"?\"]}],\"route\":\"Route\",\"searchall\":\". Probeer %S%alles te doorzoeken%/S%.\",\"searchdone\":\"Er zijn geen verdere zoekresultaten!\",\"searching\":[\"Zoeken naar \\\"\",1,\"\\\"...\"],\"suggestedresult\":\"Voorgesteld resultaat\",\"utoday\":\"UToday\",\"video\":\"Video\"},\"tablewithfilter\":{\"downloadxlsx\":\"Download als XLSX\"},\"ufondsdonaties\":{\"error-description\":\"Probeer a.u.b. opnieuw.\",\"error-title\":\"Betaling mislukt.\",\"thanks-description\":[\"Veel dank voor uw donatie!\",\"\\n\",\"\\n\",\"Universiteitsfonds Twente\"],\"thanks-title\":\"Bedankt\"}}}}});\nregisterTexts(\"utwente_base\",\"en\",{\"frontend\":{\"ws2016\":{\"js\":{\"addtocalendar\":\"Add to calendar\",\"consentblock-accept3thpartycookies\":\"Accept third-party cookies\",\"consentblock-facebook-accept3thpartycookies-suffix\":\"to load the plugin.\",\"consentblock-facebook-line1\":\"This Facebook plugin uses marketing cookies.\",\"consentblock-facebook-title\":\"This element uses cookies\",\"consentblock-soundcloud-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-soundcloud-directlink\":\"the SoundCloud website.\",\"consentblock-soundcloud-directlink-prefix\":\"Listen without cookies on\",\"consentblock-soundcloud-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-soundcloud-title\":\"This audio player uses cookies\",\"consentblock-twitterembed-accept3thpartycookies-suffix\":\"to view the timeline.\",\"consentblock-twitterembed-line1\":\"The Twitter/X timeline uses marketing cookies.\",\"consentblock-video-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-video-directlink\":[\"the \",1,\" website.\"],\"consentblock-video-directlink-prefix\":\"Watch without cookies on\",\"consentblock-video-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-video-title\":\"This video player uses cookies\",\"details\":\"Details\",\"dialog-close-arialabel\":\"Close dialog\",\"email\":\"Your email address\",\"error-imagenotfound\":\"Unable to send image\",\"error-invalidemail\":\"Invalid email\",\"error-invalidurl\":\"Invalid url\",\"imageissendto\":\"The image is send to:\",\"landmark-deeplinks-arialabel\":\"Table of contents\",\"list\":\"List\",\"nosuggestresults\":\"No results\",\"notavalidmobilephonenumber\":\"This is not a valid mobile phone number.\",\"notavalidphonenumber\":\"This is not a valid phone number.\",\"readmore\":\"Read more\",\"starsrequired\":\"* indicates a required field\",\"submit\":\"Submit\",\"submitting\":\"Submitting...\",\"calendar\":{\"appleical\":\"Apple iCal\",\"facebook\":\"Facebook Event\",\"google\":\"Google Calendar\",\"outlook\":\"Outlook Calendar\",\"outlookcom\":\"Outlook.com\",\"yahoo\":\"Yahoo Kalender\"},\"filteredoverview\":{\"feedbackbar-noresults\":\"No results\",\"feedbackbar-result\":\"Result\",\"feedbackbar-results\":[1,\" results\"],\"feedbackbar-resultslimited\":[\"Showing the first \",2,\" results (out of a total of \",1,\" results)\"],\"hidefilters_header\":\"Hide filter\",\"search\":\"Search\",\"showfilters_header\":\"Filter\",\"tease-noresults\":\"No results\",\"tease-result\":[\"Show \",1,\" result\"],\"tease-results\":[\"Show \",1,\" results\"]},\"managedcta\":{\"beacon\":[\"The beacon '\",1,\"' has been triggered\"],\"beacon-maxdays\":[\"The beacon '\",1,\"' has been triggered in the last \",{\"t\":\"ifparam\",\"p\":2,\"value\":\"1\",\"subs\":[\"day\"],\"subselse\":[2,\" days\"]}],\"beacons-skipped\":[\"The beacon '\",1,\"' was not triggered\"],\"beacons-skipped-none\":\"No beacons are triggered\",\"beacons-skipped-time\":[\"The beacon '\",1,\"' should have been triggered before \",2,\", but is it \",3],\"countries\":[\"The GeoIP country is one of \",1],\"countries-skipped\":[\"The current country code '\",2,\"' is not one of \",1],\"explanation\":\"This CTA is shown if\",\"explanation-skipped\":\"This CTA is not shown because\",\"noctatoshow\":\"None of the CTAs satisfy the conditions\",\"publish_from\":[\"The page is viewed after \",1],\"publish_from-skipped\":[\"The current date \",2,\" is before the publication date \",1],\"publish_until\":[\"The page is viewed before \",1],\"publish_until-skipped\":[\"The current date \",2,\" is after publication date \",1],\"query\":[\"The search term matches one of the search terms \",1],\"query-skipped\":[\"The search term '\",1,\"'does not match any of the search terms\"],\"query-skipped-error\":[\"The search term '\",1,\"' caused an error: \",2],\"regex\":[\"The URL matches one of the regular expressions \",1],\"regex-exclude\":[\"The URL matches none of the regular expressions \",1],\"regex-skipped\":[\"The URL '\",2,\"' matches regular expression \",1],\"regex-skipped-error\":[\"The regular expression '\",1,\"' caused an error: \",2],\"regex-skipped-none\":[\"The URL '\",1,\"' matches none of the regular expressions\"]},\"meetings\":{\"error-description\":[\"An error occurred while processing the meeting.\",\"\\n\",\"Please try again later.\"],\"error-title\":\"Error while processing\",\"thanks-description\":\"Your request for the meeting is successfully stored. You will be contacted soon.\",\"thanks-title\":\"Meeting is stored\"},\"neoform\":{\"authorizednotset\":\"To limit visibility, select at least one of the recipients or employee types.\",\"image-invalid-width\":[\"The width of the picture does not meet the requirements of \",2,\" pixels. It does not fill the whole header area. We will fill the missing space with a generated background. If you don't want this, please upload a picture that meets the minimum width requirements (\",2,\" pixels).\"],\"image-read-error\":\"The uploaded image could not be read.\",\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"]},\"newsevents\":{\"archive\":\"Show archive\",\"next_article\":\"Next event\",\"next_article-news\":\"Next article\",\"noresults\":\"No results\",\"noupcoming\":\"No upcoming events available\",\"previous_article\":\"Previous event\",\"previous_article-news\":\"Previous article\",\"thanks-cultural\":\"Thank you for the reservation\",\"thanks-event\":\"Thank you for the registration\",\"upcoming\":\"Go to events\"},\"osiris\":{\"back\":\"Back\",\"goal\":\"Goal\",\"loading\":\"Loading...\",\"more\":\"Read more\",\"moredetailslink\":[\"Go to <a href=\\\"\",1,\"\\\" target=\\\"osiris\\\">the detailed overview</a> in the OSIRIS Course Catalog\"],\"nocoursefound\":\"Course not found\"},\"pagefilters\":{\"close-filters\":\"Hide filters\",\"daterange-from\":\"From\",\"daterange-till\":\"Till\",\"reset\":\"Reset filters\",\"search-placeholder\":\"Search\",\"search-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 results\"],\"subselse\":[1,\" results\"]}],\"show-filters\":\"Show filters\",\"show-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[\"Show \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\"searchsheet\":{\"allevents\":\"Show all events\",\"downloadmap\":\"Download the campus map\",\"event\":\"Event\",\"events\":\"Events\",\"filteredresults\":\"Some search results have been deleted\",\"image\":\"Image\",\"location\":\"Location\",\"news\":\"News\",\"overflow--email\":\"Send an email\",\"people\":\"People\",\"peoplepage\":\"People Page\",\"publication\":\"Publication\",\"related\":\"Related searches\",\"results\":[{\"t\":\"tag\",\"tag\":\"b\",\"subs\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\" for \\\"\",2,\"\\\"\",{\"t\":\"ifparam\",\"p\":3,\"value\":\"\",\"subs\":[],\"subselse\":[\". Did you mean \\\"%S%\",3,\"%/S%\\\"?\"]}],\"route\":\"Route\",\"searchall\":\". You can try to %S%search all instead%/S%.\",\"searchdone\":\"We found no further search results!\",\"searching\":[\"Searching for \\\"\",1,\"\\\"...\"],\"suggestedresult\":\"Suggested result\",\"utoday\":\"UToday\",\"video\":\"Video\"},\"tablewithfilter\":{\"downloadxlsx\":\"Download as XLSX\"},\"ufondsdonaties\":{\"error-description\":\"Please try again.\",\"error-title\":\"Payment failed.\",\"thanks-description\":\"Thank you for your donation!\",\"thanks-title\":\"Thank you\"}}}}});\nregisterTexts(\"utwente_base\",\"de\",{\"frontend\":{\"ws2016\":{\"js\":{\"addtocalendar\":\"Zum Kalender hinzufügen\",\"consentblock-accept3thpartycookies\":\"Bitte akzeptiere Cookies von Dritten\",\"consentblock-facebook-accept3thpartycookies-suffix\":\"um dieses Element zu anzuzeigen.\",\"consentblock-facebook-line1\":\"Dieses Element von Facebook setzt Marketing-Cookies.\",\"consentblock-facebook-title\":\"Dieses Element setzt Cookies\",\"consentblock-soundcloud-accept3thpartycookies-suffix\":\"um den Player zu starten.\",\"consentblock-soundcloud-directlink\":\"der Webseite von SoundCloud möglich.\",\"consentblock-soundcloud-directlink-prefix\":\"Abspielen ohne Cookies zu laden ist auf\",\"consentblock-soundcloud-line1\":[\"Der Player von \",1,\" setzt Marketing-Cookies.\"],\"consentblock-soundcloud-title\":\"Dieser Audio-Stream setzt Cookies\",\"consentblock-video-accept3thpartycookies-suffix\":\"um den Player zu starten.\",\"consentblock-video-directlink\":[\"auf der Webseite von \",1,\" möglich.\"],\"consentblock-video-directlink-prefix\":\"Abspielen ohne Cookies zu laden ist\",\"consentblock-video-line1\":[\"Der Player \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"\",\"subs\":[],\"subselse\":[\"von \",1]},\" setzt Marketing-Cookies.\"],\"consentblock-video-title\":\"Dieser Videoplayer setzt Cookies\",\"landmark-deeplinks-arialabel\":\"Inhaltsverzeichnis\",\"list\":\"Liste\",\"nosuggestresults\":\"Keine Ergebnisse\",\"notavalidmobilephonenumber\":\"Dies ist keine gültige Mobilnummer.\",\"notavalidphonenumber\":\"Dies ist keine gültige Telefonnummer.\",\"readmore\":\"Weiter Lesen\",\"starsrequired\":\"* zeigt ein Pflichtfeld an\",\"filteredoverview\":{\"feedbackbar-noresults\":\"Keine Ergebnis\",\"feedbackbar-result\":\"Ergebnis\",\"feedbackbar-results\":[1,\" Ergebnisse\"],\"hidefilters_header\":\"Filter ausblenden\",\"showfilters_header\":\"Filter anzeigen\",\"tease-noresults\":\"Es gibt keine Ergebnisse\",\"tease-result\":[\"Es gibt \",1,\" Ergebnis\"],\"tease-results\":[\"Es gibt \",1,\" Ergebnisse\"]},\"newsevents\":{\"archive\":\"Zum Archief\",\"next_article\":\"Nächste event\",\"next_article-news\":\"Nächste Artikel\",\"noresults\":\"Keine Ergebnisse\",\"noupcoming\":\"Im Moment sind keine neuen Events bekannt\",\"previous_article\":\"Vorhergehende event\",\"previous_article-news\":\"Vorhergehende Artikel\",\"thanks-cultural\":\"Vielen Dank für die Reservierung\",\"thanks-event\":\"Vielen Dank für die Registrierung\",\"upcoming\":\"Zu den aktuellen Events\"},\"osiris\":{\"back\":\"Zurück\",\"goal\":\"Ziel\",\"loading\":\"Laden...\",\"more\":\"Weiterlesen\",\"moredetailslink\":[\"<a href=\\\"\",1,\"\\\" target=\\\"osiris\\\">Mehr Details</a> aus dem OSIRIS Vorlesungsverzeichnis\"],\"nocoursefound\":\"Kurs nicht gefunden\"},\"pagefilters\":{\"close-filters\":\"Filter ausblenden\",\"daterange-from\":\"Von\",\"daterange-till\":\"Bis\",\"reset\":\"Filters Löschen\",\"search-placeholder\":\"Suchen\",\"search-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 Ergebniss\"],\"subselse\":[1,\" Ergebnisse\"]}],\"show-filters\":\"Zeige Filters\",\"show-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"Keine Ergebnisse\"],\"subselse\":[\"Zeige \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 Ergebniss\"],\"subselse\":[1,\" Ergebnisse\"]}]}]},\"searchsheet\":{\"allevents\":\"Alle Events zeigen\",\"downloadmap\":\"Download Campus-Karte\",\"event\":\"Event\",\"events\":\"Events\",\"filteredresults\":\"Einzelne Suchergebnisse wurden gelöscht\",\"image\":\"Foto\",\"location\":\"Ort\",\"news\":\"News\",\"overflow--email\":\"E-Mail versenden\",\"people\":\"Personen\",\"peoplepage\":\"Persönliche Seite\",\"publication\":\"Publikation\",\"related\":\"Ähnliche Suchaufträge\",\"results\":[{\"t\":\"tag\",\"tag\":\"b\",\"subs\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"Keine Ergebnisse\"],\"subselse\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 Ergebnis\"],\"subselse\":[1,\" Ergebnisse\"]}]}]},\" für \\\"\",2,\"\\\"\",{\"t\":\"ifparam\",\"p\":3,\"value\":\"\",\"subs\":[],\"subselse\":[\". Suchst du \\\"%S%\",3,\"%/S%\\\"?\"]}],\"route\":\"Wegbeschreibung\",\"searchall\":\". Du kannst versuchen %S%alle zu suchen%/S%.\",\"searchdone\":\"Keine weiteren Suchergebnisse vorhanden!\",\"searching\":[\"Suche \\\"\",1,\"\\\"...\"],\"suggestedresult\":\"Vorgeschlagene Ergebnisse\",\"utoday\":\"UToday\",\"video\":\"Video\"}}}}});\nregisterTexts(\"utwente_base\",\"es\",{\"frontend\":{\"ws2016\":{\"js\":{\"starsrequired\":\"* campo obligatorio\",\"addtocalendar\":\"Add to calendar\",\"consentblock-accept3thpartycookies\":\"Accept third-party cookies\",\"consentblock-facebook-accept3thpartycookies-suffix\":\"to load the plugin.\",\"consentblock-facebook-line1\":\"This Facebook plugin uses marketing cookies.\",\"consentblock-facebook-title\":\"This element uses cookies\",\"consentblock-soundcloud-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-soundcloud-directlink\":\"the SoundCloud website.\",\"consentblock-soundcloud-directlink-prefix\":\"Listen without cookies on\",\"consentblock-soundcloud-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-soundcloud-title\":\"This audio player uses cookies\",\"consentblock-twitterembed-accept3thpartycookies-suffix\":\"to view the timeline.\",\"consentblock-twitterembed-line1\":\"The Twitter/X timeline uses marketing cookies.\",\"consentblock-video-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-video-directlink\":[\"the \",1,\" website.\"],\"consentblock-video-directlink-prefix\":\"Watch without cookies on\",\"consentblock-video-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-video-title\":\"This video player uses cookies\",\"details\":\"Details\",\"dialog-close-arialabel\":\"Close dialog\",\"email\":\"Your email address\",\"error-imagenotfound\":\"Unable to send image\",\"error-invalidemail\":\"Invalid email\",\"error-invalidurl\":\"Invalid url\",\"imageissendto\":\"The image is send to:\",\"landmark-deeplinks-arialabel\":\"Table of contents\",\"list\":\"List\",\"nosuggestresults\":\"No results\",\"notavalidmobilephonenumber\":\"This is not a valid mobile phone number.\",\"notavalidphonenumber\":\"This is not a valid phone number.\",\"readmore\":\"Read more\",\"submit\":\"Submit\",\"submitting\":\"Submitting...\",\"calendar\":{\"appleical\":\"Apple iCal\",\"facebook\":\"Facebook Event\",\"google\":\"Google Calendar\",\"outlook\":\"Outlook Calendar\",\"outlookcom\":\"Outlook.com\",\"yahoo\":\"Yahoo Kalender\"},\"filteredoverview\":{\"feedbackbar-noresults\":\"No results\",\"feedbackbar-result\":\"Result\",\"feedbackbar-results\":[1,\" results\"],\"feedbackbar-resultslimited\":[\"Showing the first \",2,\" results (out of a total of \",1,\" results)\"],\"hidefilters_header\":\"Hide filter\",\"search\":\"Search\",\"showfilters_header\":\"Filter\",\"tease-noresults\":\"No results\",\"tease-result\":[\"Show \",1,\" result\"],\"tease-results\":[\"Show \",1,\" results\"]},\"managedcta\":{\"beacon\":[\"The beacon '\",1,\"' has been triggered\"],\"beacon-maxdays\":[\"The beacon '\",1,\"' has been triggered in the last \",{\"t\":\"ifparam\",\"p\":2,\"value\":\"1\",\"subs\":[\"day\"],\"subselse\":[2,\" days\"]}],\"beacons-skipped\":[\"The beacon '\",1,\"' was not triggered\"],\"beacons-skipped-none\":\"No beacons are triggered\",\"beacons-skipped-time\":[\"The beacon '\",1,\"' should have been triggered before \",2,\", but is it \",3],\"countries\":[\"The GeoIP country is one of \",1],\"countries-skipped\":[\"The current country code '\",2,\"' is not one of \",1],\"explanation\":\"This CTA is shown if\",\"explanation-skipped\":\"This CTA is not shown because\",\"noctatoshow\":\"None of the CTAs satisfy the conditions\",\"publish_from\":[\"The page is viewed after \",1],\"publish_from-skipped\":[\"The current date \",2,\" is before the publication date \",1],\"publish_until\":[\"The page is viewed before \",1],\"publish_until-skipped\":[\"The current date \",2,\" is after publication date \",1],\"query\":[\"The search term matches one of the search terms \",1],\"query-skipped\":[\"The search term '\",1,\"'does not match any of the search terms\"],\"query-skipped-error\":[\"The search term '\",1,\"' caused an error: \",2],\"regex\":[\"The URL matches one of the regular expressions \",1],\"regex-exclude\":[\"The URL matches none of the regular expressions \",1],\"regex-skipped\":[\"The URL '\",2,\"' matches regular expression \",1],\"regex-skipped-error\":[\"The regular expression '\",1,\"' caused an error: \",2],\"regex-skipped-none\":[\"The URL '\",1,\"' matches none of the regular expressions\"]},\"meetings\":{\"error-description\":[\"An error occurred while processing the meeting.\",\"\\n\",\"Please try again later.\"],\"error-title\":\"Error while processing\",\"thanks-description\":\"Your request for the meeting is successfully stored. You will be contacted soon.\",\"thanks-title\":\"Meeting is stored\"},\"neoform\":{\"authorizednotset\":\"To limit visibility, select at least one of the recipients or employee types.\",\"image-invalid-width\":[\"The width of the picture does not meet the requirements of \",2,\" pixels. It does not fill the whole header area. We will fill the missing space with a generated background. If you don't want this, please upload a picture that meets the minimum width requirements (\",2,\" pixels).\"],\"image-read-error\":\"The uploaded image could not be read.\",\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"]},\"newsevents\":{\"archive\":\"Show archive\",\"next_article\":\"Next event\",\"next_article-news\":\"Next article\",\"noresults\":\"No results\",\"noupcoming\":\"No upcoming events available\",\"previous_article\":\"Previous event\",\"previous_article-news\":\"Previous article\",\"thanks-cultural\":\"Thank you for the reservation\",\"thanks-event\":\"Thank you for the registration\",\"upcoming\":\"Go to events\"},\"osiris\":{\"back\":\"Back\",\"goal\":\"Goal\",\"loading\":\"Loading...\",\"more\":\"Read more\",\"moredetailslink\":[\"Go to <a href=\\\"\",1,\"\\\" target=\\\"osiris\\\">the detailed overview</a> in the OSIRIS Course Catalog\"],\"nocoursefound\":\"Course not found\"},\"pagefilters\":{\"close-filters\":\"Hide filters\",\"daterange-from\":\"From\",\"daterange-till\":\"Till\",\"reset\":\"Reset filters\",\"search-placeholder\":\"Search\",\"search-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 results\"],\"subselse\":[1,\" results\"]}],\"show-filters\":\"Show filters\",\"show-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[\"Show \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\"searchsheet\":{\"allevents\":\"Show all events\",\"downloadmap\":\"Download the campus map\",\"event\":\"Event\",\"events\":\"Events\",\"filteredresults\":\"Some search results have been deleted\",\"image\":\"Image\",\"location\":\"Location\",\"news\":\"News\",\"overflow--email\":\"Send an email\",\"people\":\"People\",\"peoplepage\":\"People Page\",\"publication\":\"Publication\",\"related\":\"Related searches\",\"results\":[{\"t\":\"tag\",\"tag\":\"b\",\"subs\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\" for \\\"\",2,\"\\\"\",{\"t\":\"ifparam\",\"p\":3,\"value\":\"\",\"subs\":[],\"subselse\":[\". Did you mean \\\"%S%\",3,\"%/S%\\\"?\"]}],\"route\":\"Route\",\"searchall\":\". You can try to %S%search all instead%/S%.\",\"searchdone\":\"We found no further search results!\",\"searching\":[\"Searching for \\\"\",1,\"\\\"...\"],\"suggestedresult\":\"Suggested result\",\"utoday\":\"UToday\",\"video\":\"Video\"},\"tablewithfilter\":{\"downloadxlsx\":\"Download as XLSX\"},\"ufondsdonaties\":{\"error-description\":\"Please try again.\",\"error-title\":\"Payment failed.\",\"thanks-description\":\"Thank you for your donation!\",\"thanks-title\":\"Thank you\"}}}}});\nregisterTexts(\"utwente_base\",\"it\",{\"frontend\":{\"ws2016\":{\"js\":{\"addtocalendar\":\"Add to calendar\",\"consentblock-accept3thpartycookies\":\"Accept third-party cookies\",\"consentblock-facebook-accept3thpartycookies-suffix\":\"to load the plugin.\",\"consentblock-facebook-line1\":\"This Facebook plugin uses marketing cookies.\",\"consentblock-facebook-title\":\"This element uses cookies\",\"consentblock-soundcloud-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-soundcloud-directlink\":\"the SoundCloud website.\",\"consentblock-soundcloud-directlink-prefix\":\"Listen without cookies on\",\"consentblock-soundcloud-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-soundcloud-title\":\"This audio player uses cookies\",\"consentblock-twitterembed-accept3thpartycookies-suffix\":\"to view the timeline.\",\"consentblock-twitterembed-line1\":\"The Twitter/X timeline uses marketing cookies.\",\"consentblock-video-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-video-directlink\":[\"the \",1,\" website.\"],\"consentblock-video-directlink-prefix\":\"Watch without cookies on\",\"consentblock-video-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-video-title\":\"This video player uses cookies\",\"details\":\"Details\",\"dialog-close-arialabel\":\"Close dialog\",\"email\":\"Your email address\",\"error-imagenotfound\":\"Unable to send image\",\"error-invalidemail\":\"Invalid email\",\"error-invalidurl\":\"Invalid url\",\"imageissendto\":\"The image is send to:\",\"landmark-deeplinks-arialabel\":\"Table of contents\",\"list\":\"List\",\"nosuggestresults\":\"No results\",\"notavalidmobilephonenumber\":\"This is not a valid mobile phone number.\",\"notavalidphonenumber\":\"This is not a valid phone number.\",\"readmore\":\"Read more\",\"starsrequired\":\"* indicates a required field\",\"submit\":\"Submit\",\"submitting\":\"Submitting...\",\"calendar\":{\"appleical\":\"Apple iCal\",\"facebook\":\"Facebook Event\",\"google\":\"Google Calendar\",\"outlook\":\"Outlook Calendar\",\"outlookcom\":\"Outlook.com\",\"yahoo\":\"Yahoo Kalender\"},\"filteredoverview\":{\"feedbackbar-noresults\":\"No results\",\"feedbackbar-result\":\"Result\",\"feedbackbar-results\":[1,\" results\"],\"feedbackbar-resultslimited\":[\"Showing the first \",2,\" results (out of a total of \",1,\" results)\"],\"hidefilters_header\":\"Hide filter\",\"search\":\"Search\",\"showfilters_header\":\"Filter\",\"tease-noresults\":\"No results\",\"tease-result\":[\"Show \",1,\" result\"],\"tease-results\":[\"Show \",1,\" results\"]},\"managedcta\":{\"beacon\":[\"The beacon '\",1,\"' has been triggered\"],\"beacon-maxdays\":[\"The beacon '\",1,\"' has been triggered in the last \",{\"t\":\"ifparam\",\"p\":2,\"value\":\"1\",\"subs\":[\"day\"],\"subselse\":[2,\" days\"]}],\"beacons-skipped\":[\"The beacon '\",1,\"' was not triggered\"],\"beacons-skipped-none\":\"No beacons are triggered\",\"beacons-skipped-time\":[\"The beacon '\",1,\"' should have been triggered before \",2,\", but is it \",3],\"countries\":[\"The GeoIP country is one of \",1],\"countries-skipped\":[\"The current country code '\",2,\"' is not one of \",1],\"explanation\":\"This CTA is shown if\",\"explanation-skipped\":\"This CTA is not shown because\",\"noctatoshow\":\"None of the CTAs satisfy the conditions\",\"publish_from\":[\"The page is viewed after \",1],\"publish_from-skipped\":[\"The current date \",2,\" is before the publication date \",1],\"publish_until\":[\"The page is viewed before \",1],\"publish_until-skipped\":[\"The current date \",2,\" is after publication date \",1],\"query\":[\"The search term matches one of the search terms \",1],\"query-skipped\":[\"The search term '\",1,\"'does not match any of the search terms\"],\"query-skipped-error\":[\"The search term '\",1,\"' caused an error: \",2],\"regex\":[\"The URL matches one of the regular expressions \",1],\"regex-exclude\":[\"The URL matches none of the regular expressions \",1],\"regex-skipped\":[\"The URL '\",2,\"' matches regular expression \",1],\"regex-skipped-error\":[\"The regular expression '\",1,\"' caused an error: \",2],\"regex-skipped-none\":[\"The URL '\",1,\"' matches none of the regular expressions\"]},\"meetings\":{\"error-description\":[\"An error occurred while processing the meeting.\",\"\\n\",\"Please try again later.\"],\"error-title\":\"Error while processing\",\"thanks-description\":\"Your request for the meeting is successfully stored. You will be contacted soon.\",\"thanks-title\":\"Meeting is stored\"},\"neoform\":{\"authorizednotset\":\"To limit visibility, select at least one of the recipients or employee types.\",\"image-invalid-width\":[\"The width of the picture does not meet the requirements of \",2,\" pixels. It does not fill the whole header area. We will fill the missing space with a generated background. If you don't want this, please upload a picture that meets the minimum width requirements (\",2,\" pixels).\"],\"image-read-error\":\"The uploaded image could not be read.\",\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"]},\"newsevents\":{\"archive\":\"Show archive\",\"next_article\":\"Next event\",\"next_article-news\":\"Next article\",\"noresults\":\"No results\",\"noupcoming\":\"No upcoming events available\",\"previous_article\":\"Previous event\",\"previous_article-news\":\"Previous article\",\"thanks-cultural\":\"Thank you for the reservation\",\"thanks-event\":\"Thank you for the registration\",\"upcoming\":\"Go to events\"},\"osiris\":{\"back\":\"Back\",\"goal\":\"Goal\",\"loading\":\"Loading...\",\"more\":\"Read more\",\"moredetailslink\":[\"Go to <a href=\\\"\",1,\"\\\" target=\\\"osiris\\\">the detailed overview</a> in the OSIRIS Course Catalog\"],\"nocoursefound\":\"Course not found\"},\"pagefilters\":{\"close-filters\":\"Hide filters\",\"daterange-from\":\"From\",\"daterange-till\":\"Till\",\"reset\":\"Reset filters\",\"search-placeholder\":\"Search\",\"search-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 results\"],\"subselse\":[1,\" results\"]}],\"show-filters\":\"Show filters\",\"show-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[\"Show \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\"searchsheet\":{\"allevents\":\"Show all events\",\"downloadmap\":\"Download the campus map\",\"event\":\"Event\",\"events\":\"Events\",\"filteredresults\":\"Some search results have been deleted\",\"image\":\"Image\",\"location\":\"Location\",\"news\":\"News\",\"overflow--email\":\"Send an email\",\"people\":\"People\",\"peoplepage\":\"People Page\",\"publication\":\"Publication\",\"related\":\"Related searches\",\"results\":[{\"t\":\"tag\",\"tag\":\"b\",\"subs\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\" for \\\"\",2,\"\\\"\",{\"t\":\"ifparam\",\"p\":3,\"value\":\"\",\"subs\":[],\"subselse\":[\". Did you mean \\\"%S%\",3,\"%/S%\\\"?\"]}],\"route\":\"Route\",\"searchall\":\". You can try to %S%search all instead%/S%.\",\"searchdone\":\"We found no further search results!\",\"searching\":[\"Searching for \\\"\",1,\"\\\"...\"],\"suggestedresult\":\"Suggested result\",\"utoday\":\"UToday\",\"video\":\"Video\"},\"tablewithfilter\":{\"downloadxlsx\":\"Download as XLSX\"},\"ufondsdonaties\":{\"error-description\":\"Please try again.\",\"error-title\":\"Payment failed.\",\"thanks-description\":\"Thank you for your donation!\",\"thanks-title\":\"Thank you\"}}}}});\nregisterTexts(\"utwente_base\",\"xt\",{\"frontend\":{\"ws2016\":{\"js\":{\"addtocalendar\":\"Add to calendar\",\"consentblock-accept3thpartycookies\":\"Accept third-party cookies\",\"consentblock-facebook-accept3thpartycookies-suffix\":\"to load the plugin.\",\"consentblock-facebook-line1\":\"This Facebook plugin uses marketing cookies.\",\"consentblock-facebook-title\":\"This element uses cookies\",\"consentblock-soundcloud-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-soundcloud-directlink\":\"the SoundCloud website.\",\"consentblock-soundcloud-directlink-prefix\":\"Listen without cookies on\",\"consentblock-soundcloud-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-soundcloud-title\":\"This audio player uses cookies\",\"consentblock-twitterembed-accept3thpartycookies-suffix\":\"to view the timeline.\",\"consentblock-twitterembed-line1\":\"The Twitter/X timeline uses marketing cookies.\",\"consentblock-video-accept3thpartycookies-suffix\":\"to load the player.\",\"consentblock-video-directlink\":[\"the \",1,\" website.\"],\"consentblock-video-directlink-prefix\":\"Watch without cookies on\",\"consentblock-video-line1\":[\"The \",1,\" player uses marketing cookies.\"],\"consentblock-video-title\":\"This video player uses cookies\",\"details\":\"Details\",\"dialog-close-arialabel\":\"Close dialog\",\"email\":\"Your email address\",\"error-imagenotfound\":\"Unable to send image\",\"error-invalidemail\":\"Invalid email\",\"error-invalidurl\":\"Invalid url\",\"imageissendto\":\"The image is send to:\",\"landmark-deeplinks-arialabel\":\"Table of contents\",\"list\":\"List\",\"nosuggestresults\":\"No results\",\"notavalidmobilephonenumber\":\"This is not a valid mobile phone number.\",\"notavalidphonenumber\":\"This is not a valid phone number.\",\"readmore\":\"Read more\",\"starsrequired\":\"* indicates a required field\",\"submit\":\"Submit\",\"submitting\":\"Submitting...\",\"calendar\":{\"appleical\":\"Apple iCal\",\"facebook\":\"Facebook Event\",\"google\":\"Google Calendar\",\"outlook\":\"Outlook Calendar\",\"outlookcom\":\"Outlook.com\",\"yahoo\":\"Yahoo Kalender\"},\"filteredoverview\":{\"feedbackbar-noresults\":\"No results\",\"feedbackbar-result\":\"Result\",\"feedbackbar-results\":[1,\" results\"],\"feedbackbar-resultslimited\":[\"Showing the first \",2,\" results (out of a total of \",1,\" results)\"],\"hidefilters_header\":\"Hide filter\",\"search\":\"Search\",\"showfilters_header\":\"Filter\",\"tease-noresults\":\"No results\",\"tease-result\":[\"Show \",1,\" result\"],\"tease-results\":[\"Show \",1,\" results\"]},\"managedcta\":{\"beacon\":[\"The beacon '\",1,\"' has been triggered\"],\"beacon-maxdays\":[\"The beacon '\",1,\"' has been triggered in the last \",{\"t\":\"ifparam\",\"p\":2,\"value\":\"1\",\"subs\":[\"day\"],\"subselse\":[2,\" days\"]}],\"beacons-skipped\":[\"The beacon '\",1,\"' was not triggered\"],\"beacons-skipped-none\":\"No beacons are triggered\",\"beacons-skipped-time\":[\"The beacon '\",1,\"' should have been triggered before \",2,\", but is it \",3],\"countries\":[\"The GeoIP country is one of \",1],\"countries-skipped\":[\"The current country code '\",2,\"' is not one of \",1],\"explanation\":\"This CTA is shown if\",\"explanation-skipped\":\"This CTA is not shown because\",\"noctatoshow\":\"None of the CTAs satisfy the conditions\",\"publish_from\":[\"The page is viewed after \",1],\"publish_from-skipped\":[\"The current date \",2,\" is before the publication date \",1],\"publish_until\":[\"The page is viewed before \",1],\"publish_until-skipped\":[\"The current date \",2,\" is after publication date \",1],\"query\":[\"The search term matches one of the search terms \",1],\"query-skipped\":[\"The search term '\",1,\"'does not match any of the search terms\"],\"query-skipped-error\":[\"The search term '\",1,\"' caused an error: \",2],\"regex\":[\"The URL matches one of the regular expressions \",1],\"regex-exclude\":[\"The URL matches none of the regular expressions \",1],\"regex-skipped\":[\"The URL '\",2,\"' matches regular expression \",1],\"regex-skipped-error\":[\"The regular expression '\",1,\"' caused an error: \",2],\"regex-skipped-none\":[\"The URL '\",1,\"' matches none of the regular expressions\"]},\"meetings\":{\"error-description\":[\"An error occurred while processing the meeting.\",\"\\n\",\"Please try again later.\"],\"error-title\":\"Error while processing\",\"thanks-description\":\"Your request for the meeting is successfully stored. You will be contacted soon.\",\"thanks-title\":\"Meeting is stored\"},\"neoform\":{\"authorizednotset\":\"To limit visibility, select at least one of the recipients or employee types.\",\"image-invalid-width\":[\"The width of the picture does not meet the requirements of \",2,\" pixels. It does not fill the whole header area. We will fill the missing space with a generated background. If you don't want this, please upload a picture that meets the minimum width requirements (\",2,\" pixels).\"],\"image-read-error\":\"The uploaded image could not be read.\",\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"]},\"newsevents\":{\"archive\":\"Show archive\",\"next_article\":\"Next event\",\"next_article-news\":\"Next article\",\"noresults\":\"No results\",\"noupcoming\":\"No upcoming events available\",\"previous_article\":\"Previous event\",\"previous_article-news\":\"Previous article\",\"thanks-cultural\":\"Thank you for the reservation\",\"thanks-event\":\"Thank you for the registration\",\"upcoming\":\"Go to events\"},\"osiris\":{\"back\":\"Back\",\"goal\":\"Goal\",\"loading\":\"Loading...\",\"more\":\"Read more\",\"moredetailslink\":[\"Go to <a href=\\\"\",1,\"\\\" target=\\\"osiris\\\">the detailed overview</a> in the OSIRIS Course Catalog\"],\"nocoursefound\":\"Course not found\"},\"pagefilters\":{\"close-filters\":\"Hide filters\",\"daterange-from\":\"From\",\"daterange-till\":\"Till\",\"reset\":\"Reset filters\",\"search-placeholder\":\"Search\",\"search-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 results\"],\"subselse\":[1,\" results\"]}],\"show-filters\":\"Show filters\",\"show-xresults\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[\"Show \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\"searchsheet\":{\"allevents\":\"Show all events\",\"downloadmap\":\"Download the campus map\",\"event\":\"Event\",\"events\":\"Events\",\"filteredresults\":\"Some search results have been deleted\",\"image\":\"Image\",\"location\":\"Location\",\"news\":\"News\",\"overflow--email\":\"Send an email\",\"people\":\"People\",\"peoplepage\":\"People Page\",\"publication\":\"Publication\",\"related\":\"Related searches\",\"results\":[{\"t\":\"tag\",\"tag\":\"b\",\"subs\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"0\",\"subs\":[\"No results\"],\"subselse\":[{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 result\"],\"subselse\":[1,\" results\"]}]}]},\" for \\\"\",2,\"\\\"\",{\"t\":\"ifparam\",\"p\":3,\"value\":\"\",\"subs\":[],\"subselse\":[\". Did you mean \\\"%S%\",3,\"%/S%\\\"?\"]}],\"route\":\"Route\",\"searchall\":\". You can try to %S%search all instead%/S%.\",\"searchdone\":\"We found no further search results!\",\"searching\":[\"Searching for \\\"\",1,\"\\\"...\"],\"suggestedresult\":\"Suggested result\",\"utoday\":\"UToday\",\"video\":\"Video\"},\"tablewithfilter\":{\"downloadxlsx\":\"Download as XLSX\"},\"ufondsdonaties\":{\"error-description\":\"Please try again.\",\"error-title\":\"Payment failed.\",\"thanks-description\":\"Thank you for your donation!\",\"thanks-title\":\"Thank you\"}}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/it.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/xt.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n// Addthisevent integration, see https://www.addevent.com/add-to-calendar-button\n\nimport * as dompack from \"@webhare/dompack\";\nimport { getTid } from \"@webhare/gettid\";\nimport \"./addthisevent.css\";\n\nlet eventscriptloaded = false;\n\nexport function onAddThisClick(eventnode: HTMLElement) {\n  if (!eventscriptloaded) {\n    eventscriptloaded = true;\n\n    window.addeventasync = function () {\n      addeventatc.settings({\n        license: \"aHGbRdipTzsgMbuxYmdh49124\",\n        mouse: false,\n        css: false,           //WARNING if you change/move the below texts, studentunion module relies on them too!\n        outlook: { show: true, text: getTid(\"utwente_base:frontend.ws2016.js.calendar.outlook\") },\n        google: { show: true, text: getTid(\"utwente_base:frontend.ws2016.js.calendar.google\") },\n        yahoo: { show: true, text: getTid(\"utwente_base:frontend.ws2016.js.calendar.yahoo\") },\n        outlookcom: { show: true, text: getTid(\"utwente_base:frontend.ws2016.js.calendar.outlookcom\") },\n        appleical: { show: true, text: getTid(\"utwente_base:frontend.ws2016.js.calendar.appleical\") },\n        facebook: { show: true, text: getTid(\"utwente_base:frontend.ws2016.js.calendar.facebook\") },\n        dropdown: { order: \"google,appleical,outlook,outlookcom,facebook,yahoo\" },\n        callback: \"\"\n      });\n\n      //update and open the node\n      addeventatc.refresh(eventnode);\n\n      setTimeout(() => {\n        eventnode.click();\n      }, 10);//small delay else click event to close calendar won't work\n    };\n\n    const addThisScript = document.createElement(\"script\");\n    addThisScript.src = \"https://addevent.com/libs/atc/1.6.1/atc.min.js\";\n    dompack.qR(\"head\").appendChild(addThisScript);\n  }\n}\n\n//TODO cleanup unused addthisevent classes from witty (and css?)\ndompack.register(\".addeventatc\", eventnode => {\n  eventnode.addEventListener(\"click\", () => onAddThisClick(eventnode));\n});\n","import * as dompack from 'dompack';\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport { getFrontendData, sendPxl } from '@webhare/frontend';\nimport { debugFlags } from '@webhare/env';\n\nconst samplerate = 1;\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_base:nextpager\": {  // Used for next page predictions (prefetch suggestions)\n      predictions: string[];\n    };\n  }\n}\n\nasync function fetchPredictions() {\n  for (const prediction of getFrontendData(\"utwente_base:nextpager\", { allowMissing: true })?.predictions || [])\n    await fetch(prediction, { mode: 'no-cors' });\n}\n\nasync function logReferrerIfNeeded() {\n  if (!document.documentElement.lang.startsWith('en')) //only interested in international content\n    return;\n\n  const alwaysoptin = debugFlags[\"ut-performance-optin\"];\n  const usesamplerate = alwaysoptin ? 1 : samplerate;\n  if (Math.random() > usesamplerate)\n    return;\n\n  const country = await crm.requestGeoIP();\n  if (country === 'NL' && !alwaysoptin)\n    return;\n\n  if (document.referrer && document.referrer.startsWith(location.origin)) //internal referrer, we want to track these for better preloading\n    sendPxl<void>(\"utwente_base:internal_referrer\");\n}\n\nexport function setupNextPager() {\n  void logReferrerIfNeeded();\n\n  if (document.documentElement.lang.startsWith('en')) //only prefetching international content\n    dompack.onDomReady(() => window.setTimeout(() => void fetchPredictions(), 5000));\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from 'dompack';\n\n// import * as videotools from \"@mod-publisher/js/richcontent/video\";\nimport * as videotools from \"./video.ts\"; // NOTE: this also activated use of [data-video]\n\nvideotools.registerVideoSource(\"yuja\", { getPlaybackURL: getYujaPlaybackURL });\n\ndompack.register('.wh-video', node => node.dataset.video ? videotools.initializeVideoElementV1(node) : videotools.initializeVideoElementV2(node));\n\n\n/*\n\nhttps://support.yuja.com/hc/en-us/articles/20773906561559-YuJa-Video-Player-API\n\nUitleg hoe je custom code kan toevoegen om events te genereren.\n\n*/\n\n\n\nfunction getYujaPlaybackURL(video, playback) {\n  /*\n  NOTE\n  - autoplay  - NOT supported (Yuja dropped this feature somewhere in 2024/2025)\n  - startTime - supported\n  - endTime   - NOT supported\n  - controls  - NOT available??\n  - loop      - NOT supported\n  */\n\n  const args = [];\n\n  // Convert the parameters into a full playback URL\n  const params = new URL(\"https://www.example.org/?\" + video.id).searchParams;\n  const host = params.get(\"h\");\n  const videoid = params.get(\"v\");\n  const authorizationkey = params.get(\"a\");\n  // let playback_url = `//{host}/V/Video?v={videoid}&a={authorizationkey}`;\n  let playback_url = `//${host}/V/Video`;\n\n  args.push(\"v=\" + encodeURIComponent(videoid));\n  args.push(\"a=\" + encodeURIComponent(authorizationkey));\n\n  /*\n  An autostart existed in 2024:\n  https://web.archive.org/web/20240223172700/https://support.yuja.com/hc/en-us/articles/360051850373-Enabling-Auto-Start-for-a-Video-s-Direct-Link-Embed-Code\n\n  Although it had issues:\n  (it'll start playback muted ... which will confuse users)\n  https://gitlab.webhare.com/utwente/utwente_base/-/issues/1966#note_177518\n\n  But in 2025 it seems to have disappeared\n  */\n  // if (playback.autoplay)\n  // args.push(\"autostart=1\");\n\n  if (playback.starttime)\n    args.push(\"starttime=\" + playback.starttime);\n\n  if (playback.endtime)\n    console.warn(\"setting an endtime doesn't work for Yuja video's\");\n\n  if (!playback.controls)\n    console.warn(\"disabling video controls not possible for Yuja video's\");\n\n  if (playback.loop)\n    console.warn(\"loop isn't supported for Yuja video's\");\n\n  if (args.length > 0)\n    playback_url += \"?\" + args.join(\"&\");\n\n  // alert(playback_url);\n\n  return playback_url;\n}\n","/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\n/*\n\nThis is a modified video.ts (originally from the Publisher)\n\nNOTE!!\n- for networks listed in \"videonetworks_preload\" we preload the video player iframe\n\n\nDifferences:\n- 06/2023 - Support for \"video sources\" (additional video networks which registered)\n- 06/2025 - Support for preloading the embedded video players (in their iframe) so they can directly be started upon clicking the playbutton\n          - Using postMessage to force playback\n- 11/2025 - Preloaded video player iframes will now be made inert until we start playback (the play button has been used)\n            This prevents user being able to interact with the iframe. This prevents using keyboard navigation to get into the iframe and start the video.\n          - launchVideo() renamed to insertVideoPlayer()\n\n\nTestvideo:\nhttps://utwente-test.video.yuja.com/V/Video?v=471208&a=178921546\n\n- We register .wh-video\n- All elements with .wh-video--activate will load/start the video specified at the main .wh-video node (as JSON encoded in the data-wh-video attribute)\n- On the .wh-video--activate elements which store a .__initialized and .__initalized_iframe boolean\n\n\n<div class=\"wh-video wh-video--aspect_16_9 wh-requireconsent\"\n     data-wh-video=\"{&quot;id&quot;:&quot;h=utwente-test.video.yuja.com&amp;v=471208&amp;node=2121329&amp;a=178921546&quot;,&quot;network&quot;:&quot;yuja&quot;,&quot;title&quot;:&quot;ALD video audio adjusted&quot;}\"\n     title=\"ALD video audio adjusted\"\n     data-duration=\"491\"\n     data-wh-consent-required=\"marketing\"\n     >\n  <div class=\"wh-requireconsent__overlay\" hidden=\"\"></div>\n\n  <div class=\"wh-video--activate wh-video__innerframe\">\n    <!-- Our preview (image + custom play button) -->\n    <div class=\"wh-video__innerframe__preview\">\n      <picture>\n        <source srcset=\"/.wh/ea/uc/i01dd07bf0102faf43f00a3978c02e22f392134ec7af80701c28002000085/preview-hutwente-test.video.yuja.comv471208node2121329a178921546.avif\"\n                media=\"(max-width:640px)\"><img src=\"/.wh/ea/uc/i01dd07bf0102faf43f00a3978c02e22f392134ec7af80701c28002000085/preview-hutwente-test.video.yuja.comv471208node2121329a178921546.avif\" alt=\"\">\n      </picture>\n\n      <!-- Playbutton - the UT-icon* is added by Utwente_base -->\n      <div class=\"wh-video__playbutton UT-icon-UT_icon_82_play-16px\"></div>\n    </div>\n\n    <!-- The embedded video player -->\n    <iframe frameborder=\"0\" allowfullscreen=\"\"\n            src=\"//utwente-test.video.yuja.com/V/Video?v=471208&amp;a=178921546\"\n            title=\"Video: ALD video audio adjusted\" style=\"width: 100%; height: 100%;\"></iframe>\n    </div>\n  </div>\n*/\n\nimport * as dompack from 'dompack';\nimport { getTid } from \"@mod-tollium/js/gettid\";\n\n// import \"./video.css\";\n// import \"../internal/rtd.lang.json\";\nimport \"@mod-publisher/js/richcontent/video.css\";\nimport \"@mod-publisher/js/internal/rtd.lang.json\";\n\nimport * as consenthandler from '@mod-publisher/js/analytics/consenthandler';\n\n\nconst youtubedomain = 'www.youtube.com';\n\n\n\nconst videonetworks_preload = [\"yuja\"];\n\n\n\nif (!window.__videosources)\n  window.__videosources = [];\n\n\nexport function registerVideoSource(source, options) {\n  options = { //getPlayerNode: null\n    getPlaybackURL: \"\",\n    ...options\n  };\n\n  window.__videosources.push({ tag: source, ...options });\n}\n\n\nfunction createMyFrame(options) {\n  const inert = options && options.inert;\n\n  const ifrm = document.createElement(\"iframe\");\n  ifrm.style.width = \"100%\";\n  ifrm.style.height = \"100%\";\n  ifrm.setAttribute(\"frameborder\", 0);\n  ifrm.setAttribute(\"allowfullscreen\", \"\");\n\n  // Prevent the user from interacting with the iframe (like using tab navigation to get the focus within the iframe and start the video)\n  if (inert)\n    ifrm.setAttribute(\"inert\", \"\");\n\n  // delegate autoplay (for Chrome) and fullscreen permission to the video player iframe\n  // https://developer.chrome.com/blog/autoplay/#iframe_delegation\n  ifrm.setAttribute(\"allow\", \"autoplay; fullscreen\");\n\n  return ifrm;\n}\n\nfunction initYouTube(node, video, playback) {\n  const ifrm = createMyFrame(playback);\n\n  // List of embed parameters YouTube supports:\n  // https://developers.google.com/youtube/player_parameters\n\n  const args = [];\n\n  if (playback.autoplay)\n    args.push(\"autoplay=1\");\n\n  if (video.mute || playback.mute)\n    args.push(\"mute=1\");\n\n  if (video.starttime)\n    args.push(\"start=\" + Math.floor(video.starttime)); // seconds, whole integer (YouTube also uses t= in the shorturl??)\n\n  if (video.endtime)\n    args.push(\"end=\" + Math.floor(video.endtime));\n\n  if (typeof playback.controls !== \"undefined\" && !playback.controls)\n    args.push(\"controls=0\");\n\n  if (video.loop || playback.loop) {\n    /* from the documentation: https://developers.google.com/youtube/player_parameters\n       Note: This parameter has limited support in IFrame embeds. To loop a single video,\n       set the loop parameter value to 1 and set the playlist parameter value to the\n       same video ID already specified in the Player API URL:\n       https://www.youtube.com/embed/VIDEO_ID?playlist=VIDEO_ID&loop=1\n    */\n    args.push(\"loop=1\", \"playlist=\" + video.id);//To enable loop, set same video as playlist\n  }\n\n  args.push(\"rel=0\", \"enablejsapi=1\", \"origin=\" + location.origin); // disable 'related video's'\n\n  let youtube_url = `//${youtubedomain}/embed/${video.id}`;\n  if (args.length > 0)\n    youtube_url += \"?\" + args.join(\"&\");\n\n  ifrm.src = youtube_url;\n  ifrm.title = video.title ? \"YouTube video: \" + video.title : \"YouTube video\";\n  node.appendChild(ifrm);\n}\n\nfunction initVimeo(node, video, playback) {\n  const ifrm = createMyFrame(playback);\n  const args = [];\n\n  // List of embed parameters Vimeo supports:\n  // https://vimeo.zendesk.com/hc/en-us/articles/360001494447-Player-parameters-overview\n\n  if (playback.autoplay)\n    args.push(\"autoplay=1\");\n\n  if (video.mute || playback.mute)\n    args.push(\"muted=1\");\n\n  if (video.endtime)\n    console.warn(\"setting an endtime doesn't work for Vimeo video's\");\n\n  // NOTE: actually disabling controls is possible, but ONLY if the video is hosted by a Plus account or higher\n  // if (typeof playback.controls != \"undefined\" && !playback.controls)\n  if (playback.controls === false)\n    console.warn(\"disabling video controls not possible for Vimeo video's\");\n\n  if (video.loop || playback.loop)\n    args.push(\"loop=1\");\n\n  if (playback.background)\n    args.push(\"background=1\");\n\n  if (playback.api) {\n    args.push(\"api=\" + playback.api);\n\n    // we need a player_id to distinguish from which iframe a message came.\n    // (in cross domain situations we cannot lookup/compare the event source with iframe.contentWindow)\n    if (playback.player_id)\n      args.push(\"player_id=\" + playback.player_id);\n  }\n\n  let vimeo_url = \"//player.vimeo.com/video/\" + video.id;\n  if (args.length > 0)\n    vimeo_url += \"?\" + args.join(\"&\");\n\n  if (video.starttime) {\n    // #t=3m28s\n    const t = video.starttime;\n    const minutes = Math.floor(t / 60);\n    const seconds = t % 60;\n    vimeo_url += \"#t=\" + minutes + \"m\" + seconds + \"s\";\n  }\n\n  ifrm.src = vimeo_url;\n  ifrm.title = video.title ? \"Vimeo video: \" + video.title : \"Vimeo video\";\n  node.appendChild(ifrm);\n}\n\nfunction insertVideoPlayer(node, video, opts) {\n\n  const options =\n  {\n    inert: false,\n    ...opts\n  };\n\n  if (node.__initalized_iframe)\n    return; // iframe already generated\n\n  node.__initalized_iframe = true;\n  node.setAttribute(\"data-iframeloaded\", \"\");\n\n  switch (video.network) {\n    case 'youtube':\n      initYouTube(node, video, options);\n      break;\n\n    case 'vimeo':\n      initVimeo(node, video, options);\n      break;\n\n    default:\n      {\n        const ifrm = createMyFrame(options);\n\n        // Lookup custom handlers\n        let use_handler = null;\n        for (const handler of window.__videosources) {\n          if (handler.tag === video.network) {\n            use_handler = handler;\n            break;\n          }\n        }\n\n        if (use_handler) {\n          // let node = use_handler.getPlayerNode(video, opts);\n          const playback_url = use_handler.getPlaybackURL(video, options);\n          ifrm.src = playback_url;\n          ifrm.title = video.title ? \"Video: \" + video.title : \"Video\";\n          node.appendChild(ifrm);\n        } else\n          console.warn(`Unknown video network \"${video.network}\".`);\n\n        break;\n      }\n  }\n}\n\nexport function initializeVideoElementV1(node) {\n  const video = JSON.parse(node.dataset.video);\n  const opts = node.dataset.videoOptions ? JSON.parse(node.dataset.videoOptions) : {};\n  node.innerHTML = '';\n  insertVideoPlayer(node, video, opts);\n}\n\n\nexport function initializeVideoElementV2(node) {\n  const video = JSON.parse(node.dataset.whVideo);\n\n  const videonodes = dompack.qSA(node, \".wh-video--activate\");\n\n  // (pre)load the iFrame for the specified networks (usually the Yuja player)\n  // so a click can directly start the video instead of requiring a second click).\n  if (videonetworks_preload.includes(video.network)) {\n    insertVideoPlayer(videonodes[0], video, { autoplay: false, inert: true });\n  }\n\n  for (const videonode of videonodes) {\n\n    videonode.__initialized = false;\n    videonode.__initalized_iframe = false;\n\n    // Make any click on the video area trigger the video to play/autoplay.\n    // (to increate the hitarea beyond the actual play button)\n    videonode.addEventListener(\"click\", function () {\n      activateVideo(videonode, video);\n    });\n\n    // FIXME: We should move to using <button>, because now we need to handle aria- and keyboard handing\n    //        BUT we don't get the default browser focus styling.\n\n    const playbutton = videonode.querySelector(\".wh-video__playbutton\");\n    playbutton.setAttribute(\"tabindex\", \"0\");\n    playbutton.setAttribute(\"role\", \"button\");\n    playbutton.setAttribute(\"aria-label\", getTid(\"publisher:site.rtd.embedvideo.playbutton-aria\"));\n\n    playbutton.addEventListener(\"click\", function () {\n      activateVideo(videonode, video, { autoplay: true });\n    });\n\n    // Because we don't use <button> we must implement it's keyboard interaction\n    playbutton.addEventListener(\"keypress\", function (evt) {\n      // we are only interested in enter and space keypressed\n      if (evt.keyCode !== 13 && evt.keyCode !== 32)\n        return;\n\n      // prevent other code getting the event or the space both triggering the video AND scrolling the page\n      evt.preventDefault();\n\n      activateVideo(videonode, video, { autoplay: true });\n    });\n\n    if (video.autoplay) //activate immediately\n      if (node.dataset.whConsentRequired)\n        consenthandler.onConsent(node.dataset.whConsentRequired, () => activateVideo(videonode, { ...video, mute: true }, { autoplay: true }));\n      else\n        activateVideo(videonode, { ...video, mute: true }, { autoplay: true });\n  }\n}\n\nfunction activateVideo(videonode, video, opts) {\n  if (videonode.__initialized)\n    return;\n\n  videonode.querySelector(\".wh-video__innerframe__preview\").hidden = true;\n  videonode.__initialized = true;\n\n  // If the video iframe was already preloaded we can send a message to the player in the iFrame to start playback.\n  // This may hopefully also cause the play on the video to be triggered within the current click event, so it won't be blocked by the autoplay policy.\n  if (videonode.hasAttribute(\"data-iframeloaded\")) {\n    const iFrame = videonode.querySelector(\"iframe\");\n    iFrame.removeAttribute(\"inert\");\n\n    switch (video.network) {\n      case \"youtube\":\n        iFrame.contentWindow.postMessage(JSON.stringify({ event: 'command', func: 'playVideo' }), 'https://www.youtube.com');\n        break;\n      case \"yuja\":\n        iFrame.contentWindow.postMessage({ name: \"Play\" }, \"*\");\n        break;\n    }\n  } else\n    insertVideoPlayer(videonode, video, opts);\n}\n\n//dompack.register('.wh-video', node => node.dataset.video ? initializeVideoElementV1(node) : initializeVideoElementV2(node));\n","\nimport {\n  getTid as getTidFromJSSDK,\n  getTidLanguage,\n  setTidLanguage,\n  getHTMLTid,\n} from \"@webhare/gettid\";\nimport { registerTexts } from \"@webhare/gettid/src/internal\";\n\n// Fill nodes with a data-texttid attribute with the translated text\nfunction convertElementTids(scope = document.body) {\n  // Only available in a DOM context and if the DOM is ready\n  if (typeof document === \"undefined\" || !scope)\n    return;\n  Array.from(scope.querySelectorAll(\"*[data-texttid]\")).forEach(function (node) {\n    node.textContent = getTid(node.getAttribute(\"data-texttid\") || \"\");\n  });\n}\n\n// If this script is run within a DOM context, convert data-texttid attributes automatically\nif (typeof document !== \"undefined\")\n  document.addEventListener(\"DOMContentLoaded\", () => convertElementTids());\n\nconst getTid = ((...args: Parameters<typeof getTidFromJSSDK>): string => getTidFromJSSDK(...args)) as typeof getTidFromJSSDK & {\n  tidLanguage: string;\n  html: typeof getHTMLTid;\n};\n\n// Define 'tidLanguage' as a property on the main export (so you can use getTid.tidLanguage)\nObject.defineProperty(getTid, \"tidLanguage\", { get: getTidLanguage, set: setTidLanguage });\n// Define 'html' as a method on the main export (so you can use getTid.html)\ngetTid.html = getHTMLTid;\n\n// Export getTid as the default function, explicitly export getTid, getHTMLTid and registerTexts as well\nexport {\n  getTid as default,\n  getTid,\n  getTidLanguage,\n  setTidLanguage,\n  getHTMLTid,\n  convertElementTids,\n  registerTexts\n};\n","// Auto-generated language file from /opt/wh/whtree/modules/publisher/js/internal/rtd.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"publisher\",\"nl\",{\"site\":{\"rtd\":{\"embedvideo\":{\"playbutton-aria\":\"Speel video af\",\"unrecognized\":\"De URL is niet herkend als een ondersteunde video URL\",\"videourl\":\"Video URL\"}}}});\nregisterTexts(\"publisher\",\"en\",{\"site\":{\"rtd\":{\"embedvideo\":{\"playbutton-aria\":\"Play video\",\"unrecognized\":\"The URL is not recognized as a supported video URL\",\"videourl\":\"Video URL\"}}}});\nregisterTexts(\"publisher\",\"de\",{\"site\":{\"rtd\":{\"embedvideo\":{\"playbutton-aria\":\"Play video\",\"unrecognized\":\"The URL is not recognized as a supported video URL\",\"videourl\":\"Video URL\"}}}});\nregisterTexts(\"publisher\",\"es\",{\"site\":{\"rtd\":{\"embedvideo\":{\"playbutton-aria\":\"Play video\",\"unrecognized\":\"The URL is not recognized as a supported video URL\",\"videourl\":\"Video URL\"}}}});\nregisterTexts(\"publisher\",\"it\",{\"site\":{\"rtd\":{\"embedvideo\":{\"playbutton-aria\":\"Riprodurre il video\",\"unrecognized\":\"L'URL non è riconosciuto come URL del video supportato\",\"videourl\":\"Video URL\"}}}});\nregisterTexts(\"publisher\",\"xt\",{\"site\":{\"rtd\":{\"embedvideo\":{\"playbutton-aria\":\"Play video\",\"unrecognized\":\"The URL is not recognized as a supported video URL\",\"videourl\":\"Video URL\"}}}});\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/nl.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/de.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/es.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/it.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n","import \"./rtd.css\";\nimport * as dompack from \"@webhare/dompack\";\n\n/*\n  Check for horizontal scrollability of table wrappers\n  and show a small gradient at right of scrollarea as an indicator if scrollable.\n*/\n\nclass checkScrollableX {\n  node: HTMLElement;\n  scrollcontainer: HTMLElement;\n  constructor(node: HTMLElement) {\n    this.node = node;\n    this.scrollcontainer = dompack.create(\"div\", { class: \"wh-rtd__tablescrollcontainer\" });\n    this.scrollcontainer.classList.add(\"styledscrollbar-x\");\n\n    this.scrollcontainer.append(...Array.from(this.node.childNodes));\n    this.node.appendChild(this.scrollcontainer);\n\n    window.addEventListener(\"load\", () => this.checkOverflow());\n    window.addEventListener(\"resize\", () => this.checkOverflow());\n    document.fonts.ready.then(() => this.checkOverflow()).catch(e => console.error(e));\n    this.checkOverflow();\n  }\n\n  checkOverflow() {\n    const w = this.scrollcontainer.clientWidth;\n    const sw = this.scrollcontainer.scrollWidth;\n    this.node.classList.toggle(\"wh-rtd__tablewrap--scrollable-x\", sw > w);\n  }\n}\n\ndompack.register(\".wh-rtd__tablewrap\", node => new checkScrollableX(node));\n","import { onDomReady } from \"@webhare/dompack\";\nimport \"./univers-next-faces.css\";\n\n//required by license, but this way it won't block any critical asset loading or page rendering\nonDomReady(() =>\n  void setTimeout(() =>\n    void fetch(\"https://cdn.fonts.net/t/1.css?apiType=css&projectid=7c052a08-29f5-4c10-ab60-eeb1623773d6\", { priority: \"low\" }).then(() => { }, () => { }), 200));\n","//TODO include testcode only when building on a development machine for smaller bundle sizes\n\nimport * as dompack from '@webhare/dompack';\nimport { CustomPageFilter, PageFiltersContext, registerCustomFilter } from \"../shared/pagefilters/pagefilters\";\n\nclass TestFilter implements CustomPageFilter {\n\n  async filter(context: PageFiltersContext): Promise<HTMLElement[]> {\n    const els = [];\n\n    if (!context.query.isAnySet || context.query.facets[\"selectone\"].some(_ => _.value === \"option1\"))\n      els.push(<div id=\"dynitem1\">I am item 1</div>);\n    if (!context.query.isAnySet || context.query.facets[\"selectone\"].some(_ => _.value === \"option2\"))\n      els.push(<div id=\"dynitem2\">I am item 2</div>);\n\n    return els;\n  }\n\n}\n\nregisterCustomFilter(\"testFilter\", () => new TestFilter());\n","import { getFrontendData } from \"@webhare/frontend\";\nimport \"./pagefilters.css\";\nimport \"./pagefilters-list.css\";\nimport * as dompack from \"@webhare/dompack\";\nimport { getTid } from \"@webhare/gettid\";\nimport { type MaybePromise, throwError, wrapSerialized } from \"@webhare/std\";\nimport type { SlimSelect } from \"@mod-utwente_design\";\nimport UTAutoComplete from '@mod-utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter';\nimport { SearchIndex } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/searchindex\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_base:pagefilters\": FilteredOverviewSettings;\n  }\n}\n\nexport interface CustomPageFilter {\n  filter: (context: PageFiltersContext) => MaybePromise<HTMLElement[] | null>; // If no update is needed (eg because the filter itself updates the UI), the filter can return null/undefined to skip the update\n}\n\ninterface IndexedItem {\n  title: string;\n  description: string;\n  idx: number;\n}\n\nconst factories: Record<string, (initialItems: HTMLElement[]) => CustomPageFilter> = {};\n\nexport type PageFiltersQuery = {\n  isAnySet: boolean;\n  facets: Record<string, Array<{\n    value: string;\n    title: string;\n  }>>;\n  searchWords: string;\n};\n\nexport type PageFiltersContext = {\n  query: PageFiltersQuery;\n};\n\nexport type FilteredOverviewSettings = {\n  /** Unique name for this filter type. Used for class names/ids */\n  filtername: string;\n  /** Filters to show */\n  filters: Array<{\n    ischeckboxes?: boolean; // Mainly for backwards compatibility, setting 'type' to 'checkboxes' is now preferred\n    name: string;\n    title: string;\n    defaultselection?: string; // Value to set if not set by a variable on the URL\n    type?: \"checkboxes\" | \"radio\" | \"select\" | \"daterange\" | \"hidden\"; // Hidden activates checks for url parameter for now shown filter. Add/implement more types?\n    comment?: string; // Optional comment to show below the filter\n    options?: Array<{\n      rowkey: string;\n      title: string;\n      selected?: boolean; // selected option to set if not set by a variable on the URL\n    }>;\n  }>;\n  /* Show filter tabs above filterpanel/content */\n  headerTabsFilter?: {\n    name: string;\n    options?: Array<{\n        rowkey: string;\n        title: string;\n        selected?: boolean; // selected option to set if not set by a variable on the URL\n      }>;\n  };\n  /** Name of callback function to execute actual filter. This function needs to be a global (ie assign it to the window object) */\n  customFilter?: string;\n  options?: {\n    /** Whether to show the textual search field */\n    showtextsearch?: boolean;\n    /** Use custom suggest handling, used by studyfinder,\n     * else the default implementation will look for elements with data-autocompletesource-title and data-autocompletesource-description inside the filter items to build a search index for suggestions and filtering.\n     */\n    customAutocomplete?: boolean;\n    /** Use custom text search handling, used by coursefinder,\n     * else the default implementation will look for elements with data-autocompletesource-title and data-autocompletesource-description inside the filter items to build a search index for suggestions and filtering.\n     */\n    customTextSearch?: boolean;\n    /** filter at first run even if empty, used to trigger rpc loading initial (filtered) results when page is initial empty */\n    startAtFirstRun?: boolean;\n    /** Whether to show the view mode toggle (Details/List/Calendar/... view), triggers custom events when clicked */\n    viewmodes?: Array<{name: string; icon: string; title: string; titleMobile?: string; selected?: boolean}>;\n    /** Just reload page on filter change (used for itc BTOR) */\n    reloadOnFilterChange?: boolean;\n    /** Custom feedback in toolbar (.page-filterstoolbar__feedback) */\n    customFeedback?: string;\n  };\n  /*  TODO these fields were documented but not yet seen. they may still apply:\n  @param(function ptr) fields.togglebarcustomcontent Extra content to use in the togglebar (between the button and search field)\n  @param(string)  fields.queryname Field name for the textual search (query) field (defaults to \"query\")\n  @param(string)  fields.query     Value to use in the query field\n  */\n};\n\nconst desktopMediaQuery = matchMedia(\"(min-width: 751px)\");\n\nfunction getFlatActiveFilterValuesList(filter: PageFiltersQuery) {\n  // Compile a list of all selected filter values\n  const tags: Array<{\n    /** The title to show */\n    title: string;\n    /** The filters associated with this tag. Might be more than one due to onMapFilterTags combining tags? */\n    associatedFilters: Array<{\n      filter: string;\n      value: string;\n    }>;\n  }> = [];\n\n  for (const [name, entries] of Object.entries(filter.facets)) {\n    const items = entries.filter(e => e.value);\n    for (const { value, title } of items) {\n      tags.push({ title, associatedFilters: [{ filter: name, value }] });\n    }\n  }\n  return tags;\n}\n\nexport class DefaultFilter implements CustomPageFilter {\n  srcItems: HTMLElement[] = [];\n  searchIndex: SearchIndex<IndexedItem> | null = null;\n  customTextSearch: boolean;\n\n  constructor(initialItems: HTMLElement[] | null, options?: FilteredOverviewSettings[\"options\"]) {\n    this.srcItems = initialItems || dompack.qSA(\".pagefilters__item\").map(item => item.cloneNode(true) as HTMLElement);\n\n    this.customTextSearch = options?.customTextSearch || false;\n\n    if( !options?.customAutocomplete ) {\n      this.searchIndex = new SearchIndex<IndexedItem>();\n      this.searchIndex.searchFields = [\"title\", \"description\"];\n      this.searchIndex.completeSuggestFields = [\"title\"];\n\n      this.srcItems.forEach((item, idx) => {\n        // Suggest only uses only title field, description additional used for search\n        dompack.qSA(item, \"[data-autocompletesource-title]\").forEach(titleNode => {\n          const title = titleNode.textContent || \"\";\n          const descriptionNodes = dompack.qSA(item, \"[data-autocompletesource-description]\");\n          const description = descriptionNodes.map(n => n.textContent || \"\").join(\"\\n\");\n          if( title || description )\n            this.searchIndex!.indexItem( {idx, title, description });\n        });\n      });\n\n      // Add autocomplete to search input\n      const searchnode = dompack.qS<HTMLInputElement>(\".page-titlebar__form input[name=query]\");\n      if (searchnode) {\n        UTAutoComplete({\n          input: searchnode,\n          className: 'ut-autocomplete',\n          preventSubmit: 1,\n          fetch: (text, update) => {\n            const suggestions = this.searchIndex!.suggest(text).slice(0, 10);\n            update(suggestions.map(_ => { return { label: _, value: _ }; }));\n          },\n          onSelect: (item) => {\n            searchnode.value = item.label ?? \"\";\n            dompack.dispatchDomEvent(searchnode, \"change\"); // Trigger filtering of pagefilters\n          },\n          customize: (input, inputRect, container, maxHeight) => {\n            // use search form width istead of input width\n            const width = input.parentElement!.offsetWidth;\n            const leftPos = inputRect.left + (inputRect.width - width);\n            container.style.width = width + \"px\";\n            container.style.left = leftPos + \"px\";\n          }\n        });\n      }\n    }\n  }\n\n  filter(context: PageFiltersContext): HTMLElement[] | null {\n    const items: HTMLElement[] = [];\n\n    const limitIdx: number[] = [];\n    if( !this.customTextSearch && this.searchIndex && context.query.searchWords ) {\n      const result = this.searchIndex.search(context.query.searchWords);\n      limitIdx.push(...result.items.map(_ => _.idx));\n    }\n\n    this.srcItems.forEach((item, idx) => {\n      // If customTextSearch, then results should be filtered afterwards by the custom filter implementation\n      if( !this.customTextSearch && this.searchIndex && context.query.searchWords && !limitIdx.includes(idx) )\n        return; // If there are search words but this item is not in the search results, skip it\n\n      const shouldBeVisible = !context.query.isAnySet || Object.entries(context.query.facets).every(([filter, values]) => {\n        if (values.length === 0)\n          return true; //no filter for this, so it doesn't exclude any items\n        // itemValue might be multiple values (eg space separated), in that case we should check if any of the values match the filter, not just the whole string\n        const itemValue = item.getAttribute(`data-filter-${filter}`)?.split(\" \");\n        return itemValue && values.some(v => itemValue.includes(v.value));\n      });\n      if (shouldBeVisible)\n        items.push(item);\n    });\n\n    return items;\n  }\n}\n\nclass FilteredOverview {\n  filtername: string;\n  filter: CustomPageFilter;\n  isFirstRun = true;\n  itemsContainer: HTMLElement;\n  settings: FilteredOverviewSettings;\n  scrollUpdateTimer: NodeJS.Timeout | null = null;\n\n  constructor(settings: FilteredOverviewSettings) {\n    this.settings = settings;\n    this.filtername = settings.filtername;\n\n    if( this.settings.headerTabsFilter )\n      this.setupHeaderTabs();\n\n    if( this.settings.filters.length > 0 )\n      this.buildFilters();\n\n    this.itemsContainer = dompack.qS(\".page-content .pagefilters__itemcontainer\") || dompack.qR(\".page-content\");\n\n    document.documentElement.classList.add(`pagewithfilters`); // Set class on root element to allow styling based on presence of filters\n\n    document.addEventListener(\"keyup\", (ev: KeyboardEvent) => {\n      if (ev.key === \"Escape\")  // Close mobile filters on escape key press\n        document.documentElement.classList.remove(\"pagefilters--mobilefiltersvisible\");\n    });\n\n    if (settings.options?.showtextsearch)\n      this.setupTextSearch();\n\n    if (this.settings.customFilter) {\n      const factory = factories[this.settings.customFilter] ?? throwError(`Callback '${this.settings.customFilter}' not registered (use registerFilterCallback)`);\n      this.filter = factory(dompack.qSA(\".pagefilters__item\"));\n    } else {\n      this.filter = new DefaultFilter(dompack.qSA(\".pagefilters__item\"), this.settings.options);\n    }\n\n    this.setInitialFiltersFromUrl();\n\n    const hash = location.hash.replace(\"#\", \"\").split(\".\")[0]; // Get the first part of the hash (before any dots) to check for view mode, the rest of the hash can be used for viewmode specific info like calendarview.2024.01 for year and month\n    void this.refilter();\n    if( settings.options?.viewmodes && settings.options.viewmodes.some(vm => `${vm.name}view` === hash) ) {\n      this.onViewModeChange(hash.replace(\"view\", \"\"));\n    } else {\n      this.itemsContainer.hidden = false;\n    }\n  }\n\n  private setInitialFiltersFromUrl() {\n    const urlParams = new URLSearchParams(location.search);\n\n    this.settings.filters.forEach(filter => {\n      const filtertype = filter.type ? filter.type : filter.ischeckboxes ? \"checkboxes\" : \"select\";\n\n      if( filtertype === \"daterange\" ) {\n        const startParam = urlParams.get(`${filter.name}.start`);\n        const endParam = urlParams.get(`${filter.name}.end`);\n\n        const startInp = dompack.qS<HTMLInputElement>(`.page-filters__form [name=\"${filter.name}.start\"]`);\n        const endInp = dompack.qS<HTMLInputElement>(`.page-filters__form [name=\"${filter.name}.end\"]`);\n        if (startParam && startInp)\n          startInp.value = startParam;\n        if (endParam && endInp)\n          endInp.value = endParam;\n      } else {\n        let paramValue = urlParams.get(filter.name);\n        if( !paramValue && filter.name === \"themes\" ) { // Legacy support for old filter name \"theme\" which is renamed to \"themes\" in ws2026\n          paramValue = urlParams.get(\"theme\");\n          if( paramValue ) {\n            const loc = new URL(location.href);\n            loc.searchParams.delete(\"theme\");\n            loc.searchParams.set(\"themes\", paramValue);\n            history.replaceState(null, \"\", loc.toString());\n          }\n        }\n\n        if (!paramValue)\n          return;\n\n        const inp = dompack.qS<HTMLInputElement | HTMLSelectElement>(`.page-filters__form [name=\"${filter.name}\"]`);\n        if( inp instanceof HTMLSelectElement ) {\n          if ([...inp.options].some(option => option.value === paramValue)) {\n            if( inp.classList.contains(\"replacedby-ss\") ) {\n              const ss = (inp as HTMLSelectElement & { slim: SlimSelect }).slim;\n              ss.setSelected(paramValue);\n            } else {\n              inp.value = paramValue;\n            }\n          }\n        } else if (inp instanceof HTMLInputElement) {\n          if (inp.type === \"checkbox\") {\n            const valuesToSelect = paramValue.split(\",\");\n            for (const value of valuesToSelect) {\n              const checkbox = dompack.qS<HTMLInputElement>(`.page-filters__form [name=\"${filter.name}\"][value=\"${value}\"]`);\n              if (checkbox)\n                checkbox.checked = true;\n            }\n          } else if (inp.type === \"radio\") {\n            const radio = dompack.qS<HTMLInputElement>(`.page-filters__form [name=\"${filter.name}\"][value=\"${paramValue}\"]`);\n            if (radio)\n              radio.checked = true;\n          } else {\n            inp.value = paramValue;\n          }\n        }\n      }\n    });\n\n    // Set initial value for header tabs filter if present\n    if( this.settings.headerTabsFilter ) {\n      const paramValue = urlParams.get(this.settings.headerTabsFilter.name);\n      if (!paramValue)\n        return;\n      const radio = dompack.qS<HTMLInputElement>(`.page-filterstabs__listitem [name=\"${this.settings.headerTabsFilter.name}\"][value=\"${paramValue}\"]`);\n      if (radio)\n        radio.checked = true;\n    }\n\n    const searchParam = urlParams.get(\"query\");\n    if (searchParam) {\n      const searchInput = dompack.qS<HTMLInputElement>(\".page-titlebar__form [name=query]\");\n      if (searchInput)\n        searchInput.value = searchParam;\n    }\n  }\n\n  buildFilter(filter: FilteredOverviewSettings[\"filters\"][number]) {\n    // Filter inside side panel\n    const filtertype = filter.type ? filter.type : filter.ischeckboxes ? \"checkboxes\" : \"select\";\n\n    const selectedOptions = filter.options?.filter(o => o.selected).map(o => o.rowkey) || [];\n    if( !filter.defaultselection && selectedOptions.length > 0 )\n      filter.defaultselection = selectedOptions.join(\",\"); // If no defaultselection is set, but some options are marked as selected, use selected options as defaultselection.\n\n    if( filter.defaultselection ) {\n      const loc = new URL(location.href);\n      if( !loc.searchParams.get(filter.name) ) {\n        loc.searchParams.set(filter.name, filter.defaultselection);\n        history.replaceState(null, \"\", loc.toString());\n      }\n    }\n\n    if( filtertype === \"hidden\" )\n      return null; // Hidden filters are not rendered, they only get their value from the URL and are used for filtering\n\n    const options = filtertype === \"checkboxes\" && filter.options && filter.options.length > 0 ?\n      filter.options.map(option => <label class=\"checkbox-label\">\n        <input type=\"checkbox\" name={filter.name} value={option.rowkey} onChange={() => this.onFilterChange()} />\n        {option.title}\n      </label>)\n      : filtertype === \"radio\" && filter.options && filter.options.length > 0 ?\n        filter.options.map(option => <label class=\"checkbox-label\">\n        <input type=\"radio\" name={filter.name} value={option.rowkey} onChange={() => this.onFilterChange()} />\n        {option.title}\n      </label>)\n      : filtertype === \"daterange\" ?\n        <div class={`fieldline-${filtertype}`}>\n          <div class={`fieldline-${filtertype}__line`}>\n            <label for={`${this.filtername}-${filter.name}-start`}>{getTid(\"utwente_base:frontend.ws2016.js.pagefilters.daterange-from\")}</label>\n            <input type=\"date\" id={`${this.filtername}-${filter.name}-start`} name={`${filter.name}.start`} onChange={() => this.onFilterChange()} value=\"\" />\n          </div>\n          <div class={`fieldline-${filtertype}__line`}>\n            <label for={`${this.filtername}-${filter.name}-end`}>{getTid(\"utwente_base:frontend.ws2016.js.pagefilters.daterange-till\")}</label>\n            <input type=\"date\" id={`${this.filtername}-${filter.name}-end`} name={`${filter.name}.end`} onChange={() => this.onFilterChange()} value=\"\" />\n          </div>\n        </div>\n      : filtertype === \"select\" && filter.options && filter.options.length > 0 ?\n        <select name={filter.name} id={`${this.filtername}-${filter.name}`} onChange={() => this.onFilterChange()} >\n          {filter.options.map(option => <option value={option.rowkey}>{option.title}</option>)}\n        </select>\n      : \"\";\n\n    return <fieldset><legend>{filter.title}</legend>{options}{filter.comment ? <p class=\"page-filters__form__comment\">{filter.comment}</p> : null}</fieldset>;\n  }\n\n  setupHeaderTabs() {\n    const nrTabs = this.settings.headerTabsFilter?.options ? this.settings.headerTabsFilter.options.length : 0;\n    // Filters as tabs above content\n    const tablist = <div class=\"page-filterstabs\">\n      <div class=\"page-filterstabs__inner\">\n        {nrTabs > 0 ?\n        <ul class=\"page-filterstabs__list\">\n          {this.settings.headerTabsFilter?.options?.map(opt => <li class=\"page-filterstabs__listitem\">\n            <input type=\"radio\" id={`${this.settings.headerTabsFilter?.name}-${opt.rowkey}`} checked={Boolean(opt.selected)} name={this.settings.headerTabsFilter?.name} value={opt.rowkey} onChange={() => this.onFilterChange()} />\n            <label for={`${this.settings.headerTabsFilter?.name}-${opt.rowkey}`}><b aria-hidden=\"true\" {...(!opt.selected ? { hidden: true } : {})}>{`${opt.title}`}</b><span>{`${opt.title}`}</span></label>\n          </li>)}\n        </ul> : null}\n      </div>\n    </div>;\n\n    dompack.qR(\".page-titlebar\").after(tablist);\n  }\n\n  buildFilters() {\n    let selectedViewIdx: number = 0;\n    if( this.settings.options?.viewmodes && this.settings.options.viewmodes.length > 0 ) {\n      selectedViewIdx = this.settings.options.viewmodes.findIndex(vm => vm.selected);\n      if( selectedViewIdx === -1 )\n        selectedViewIdx = 0; // Just set first, if none is selected\n    }\n\n    const filtersToolbar =\n      <div class=\"page-filterstoolbar\">\n        <div class=\"page-filterstoolbar__title\" onClick={() => this.toggleMobileFilters()}>\n          <i class=\"UT-icon-UT_icon_116_filter-16px\"></i>\n          <span>Filter</span>\n        </div>\n        <div class=\"page-filterstoolbar__controls\">\n          <div class=\"page-filterstoolbar__feedback\"></div>\n          { this.settings.options?.viewmodes && this.settings.options.viewmodes.length > 0 ?\n            <div class=\"page-filterstoolbar__options\">\n              {this.settings.options.viewmodes.map((vm,i) => <button type=\"button\" onClick={() => this.onViewModeChange(vm.name)} data-view={vm.name} class={`page-filterstoolbar__button${i === selectedViewIdx ? \" page-filterstoolbar__button--active\" : \"\"}`}>\n                {vm.icon ? <i class={vm.icon}></i> : null}\n                {vm.titleMobile ? <span class=\"page-filterstoolbar__button__title-mobile\" hidden>{vm.titleMobile}</span> : null}\n                <span class=\"page-filterstoolbar__button__title-desktop\">{vm.title}</span>\n              </button>)}\n            </div> : null\n          }\n        </div>\n      </div>;\n\n    const contentWithFilters =\n      <div class=\"page-filters\">\n        <button type=\"button\" tabindex=\"0\" class=\"page-filters__mobileclose\" aria-label={getTid(\"utwente_base:frontend.ws2016.js.pagefilters.close-filters\")} hidden onClick={() => this.toggleMobileFilters()}>\n          <i class=\"UT-icon-UT_icon_47_cross-16px\"></i>\n        </button>\n        <form class=\"page-filters__form wh-styledinput\" method=\"post\" action=\"javascript://\">\n          {this.settings.filters.map(filter => this.buildFilter(filter))}\n          <div class=\"page-filters__form__buttons\">\n            <button type=\"reset\" class=\"page-filters__form__reset\" onClick={() => this.onResetFilters()}>{getTid(\"utwente_base:frontend.ws2016.js.pagefilters.reset\")}</button>\n          </div>\n        </form>\n      </div>;\n\n    dompack.qR(\".page-contentwrapper\").before(filtersToolbar);// Insert toolbar before contentwrapper so it appears above\n    const sidebar = dompack.qR(\".page-sidebar\");\n    sidebar.prepend(contentWithFilters);// Insert filters into sidebar so they are next to the content and sticky when scrolling\n    sidebar.hidden = false;\n\n    window.addEventListener(\"resize\", () => this.onResize(contentWithFilters));\n    this.updateFiltersTop(contentWithFilters);\n\n    const mobileBtn = <button type=\"button\" tabindex=\"0\" class=\"page-filters__mobiletoggle\" onClick={() => this.toggleMobileFilters()} hidden>\n        <i class=\"UT-icon-UT_icon_116_filter-16px\"></i>\n        <span class=\"page-filters__mobiletoggle__showlabel\">{getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-filters\")}</span>\n        <span class=\"page-filters__mobiletoggle__hidelabel\" hidden>{getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-xresults\", \"0\")}</span>\n      </button>;\n    dompack.qR(\".page-contentwrapper\").after(mobileBtn);\n\n    dompack.registerMissed(contentWithFilters);\n  }\n\n  onResize(contentWithFilters: HTMLElement) {\n    if( this.scrollUpdateTimer )\n      clearTimeout(this.scrollUpdateTimer);\n    this.scrollUpdateTimer = setTimeout(() => this.updateFiltersTop(contentWithFilters), 100);\n  }\n\n  updateFiltersTop(node: HTMLElement) {\n    if (!desktopMediaQuery.matches) {\n      node.style.top = \"\"; // Reset top style for mobile view\n      return;\n    }\n\n    // Update the top of the sticky filters node so it scrolls along with the list until the bottom of the filters node reaches bottomMargin\n    const topMargin = 90;\n    const bottomMargin = 20;\n    node.style.top = `${Math.min(topMargin, innerHeight - node.getBoundingClientRect().height - bottomMargin)}px`;\n  }\n\n  onResetFilters() {\n    const searchWords = dompack.qS<HTMLInputElement>(\".page-titlebar__form [name=query]\");\n    if( searchWords )\n      searchWords.value = \"\";\n\n    dompack.qSA<HTMLSelectElement>(`.page-filters__form select.replacedby-ss`).forEach(select => {\n      const ss = (select as HTMLSelectElement & { slim: SlimSelect }).slim;\n      ss.setSelected([], false); // clears the slimSelect selection, don't trigger change event yet because we'll trigger change event after resetting all filters\n    });\n\n    void this.onFilterChange();\n  }\n\n  toggleMobileFilters() {\n    document.documentElement.classList.toggle(\"pagefilters--mobilefiltersvisible\");\n  }\n\n  onViewModeChange(mode: string) {\n    if( this.itemsContainer.classList.contains(`pagefilters__itemcontainer--${mode}view`) ) {\n      this.itemsContainer.hidden = false; // Incase of initial load with hash, the container is hidden until the correct view mode is applied. If we're already in the correct mode, we need to unhide it.\n      return; // Already in this mode, do nothing\n    }\n\n    this.itemsContainer.hidden = true;\n    location.hash = `${mode}view`; // Set hash so it can be linked to and remembered when refreshing.\n    this.settings.options?.viewmodes?.forEach(vm => {\n      this.itemsContainer.classList.toggle(`pagefilters__itemcontainer--${vm.name}view`, vm.name === mode);\n    });\n\n    // Send event if view mode change so content can react to it if needed\n    dompack.dispatchCustomEvent(this.itemsContainer, \"pagefilters:viewmodechange\", { bubbles: true, cancelable: false, detail: { mode } });\n    setTimeout(() => { // Small delay so event handlers for viewmodechange can run before we apply the filter\n      void this.refilter(); // force update so new rendering can be applied\n      this.itemsContainer.hidden = false;\n      // Update active state of buttons\n      dompack.qSA(\".page-filterstoolbar__button\").forEach(button => {\n        button.classList.toggle(\"page-filterstoolbar__button--active\", button.dataset.view === mode);\n      });\n    },100);\n  }\n\n  setupTextSearch() {\n    // Inject into page-titlebar at end (after heading1 if present)\n    const queryform = <form class=\"page-titlebar__form\" method=\"post\" action=\"javascript://\">\n      <button type=\"submit\" class=\"UT-icon-UT_icon_70_search-16px\"></button>\n      <input type=\"search\" name=\"query\" onSearch={() => this.onTextSearch()} onChange={() => this.onTextSearch()} placeholder={getTid(\"utwente_base:frontend.ws2016.js.pagefilters.search-placeholder\")} />\n    </form>;\n\n    queryform.addEventListener(\"submit\", (ev: Event) => {\n      ev.preventDefault();\n      this.onTextSearch();\n    });\n\n    dompack.qR(\".page-titlebar\").append(queryform);\n  }\n\n  onTextSearch() {\n    void this.onFilterChange();\n  }\n\n  getCurrentFilterOptions(): PageFiltersQuery {\n    const facets: PageFiltersQuery[\"facets\"] = {};\n    for (const filter of dompack.qSA(\".page-filters__form input, .page-filters__form select, .page-filterstabs__listitem input\")) {\n      if (filter instanceof HTMLInputElement) {\n        facets[filter.name] ||= [];\n        if ([\"checkbox\", \"radio\"].includes(filter.type)) {\n          if (filter.checked &&  filter.value && filter.value !== \"0\") // Ignore empty and \"0\" which is used by some filters to indicate \"All\"\n            facets[filter.name].push({ value: filter.value, title: filter.closest('label')?.textContent || '' });\n        } else if (filter.value && filter.value !== \"0\") { // Ignore empty and \"0\" which is used by some filters to indicate \"no selection\"\n          facets[filter.name].push({ value: filter.value, title: filter.value });\n        }\n      }\n      if (filter instanceof HTMLSelectElement && filter.value && filter.value !== \"0\") // Ignore empty and \"0\" which is used by some filters to indicate \"no selection\"\n        facets[filter.name] = [{ value: filter.value, title: filter.options[filter.selectedIndex]?.text || '' }];\n    }\n\n    const hiddenFilters = this.settings.filters.filter(_=>_.type === \"hidden\");\n    if( hiddenFilters.length > 0 ) {\n      const urlParams = new URLSearchParams(location.search);\n      hiddenFilters.forEach(filter => {\n        const paramValue = urlParams.get(filter.name);\n        if( paramValue ) { // For now we only support single value hidden filters, if needed this can be extended to support multiple values like the other filters\n          const opt = filter.options?.find(o => o.rowkey === paramValue);\n          if( opt )\n            facets[filter.name] = [{ value: paramValue, title: opt.title }];\n        }\n      });\n    }\n\n    const searchWords = dompack.qS<HTMLInputElement>(\".page-titlebar__form [name=query]\")?.value || '';\n    const isAnySet = Boolean(Object.values(facets).some(values => values.length > 0) || searchWords);\n\n    dompack.qSA(\".page-filters__form__reset\").forEach(el => el.classList.toggle(\"page-filters__form__reset--active\", isAnySet));\n\n    return { facets, searchWords, isAnySet };\n  }\n\n  onFilterChange() {\n    if( this.settings.options?.reloadOnFilterChange ) {\n      if( !this.isFirstRun ) {\n        this.updateFiltersInUrl(this.getCurrentFilterOptions()); // First update url parameters based on the current filter options\n        location.reload();\n      } else if(this.settings.options?.customFeedback) {\n        if( this.settings.options?.customFeedback )\n          dompack.qSA(\".page-filterstoolbar__feedback\").forEach(el => el.textContent = this.settings.options?.customFeedback ?? \"\");\n      }\n\n      return;\n    }\n\n    const lock = dompack.flagUIBusy();\n    void this.refilter().finally(() => lock.release());\n  }\n\n  private refilter = wrapSerialized(async () => {\n    const filters = this.getCurrentFilterOptions();\n    this.updateTagsBar(filters);\n\n    if( this.isFirstRun && (filters.isAnySet || (this.settings.options && this.settings.options.startAtFirstRun)) ) {\n      await this.showItemsBasedOnFilter(filters);\n    } else if (!this.isFirstRun || filters.isAnySet) {\n      this.updateFiltersInUrl(filters);\n      await this.showItemsBasedOnFilter(filters);\n    } else { // No filters, just update counter\n      const items = dompack.qSA(\".pagefilters__item\");\n\n      const fbtxt = this.settings.options?.customFeedback ? this.settings.options.customFeedback : getTid(\"utwente_base:frontend.ws2016.js.pagefilters.search-xresults\", String(items.length));\n      dompack.qSA(\".page-filterstoolbar__feedback\").forEach(el => el.textContent = fbtxt);\n\n      dompack.qSA(\".page-filters__mobiletoggle__hidelabel\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-xresults\", String(items.length)));\n      document.documentElement.classList.toggle(\"page-filters--noresults\", !items.length); // used to show no results message\n    }\n    this.isFirstRun = false;\n  }, { coalesce: true });\n\n  updateFiltersInUrl(filters: PageFiltersQuery) {\n    const loc = new URL(location.href);\n\n    // First remove all filter-related params, then add the currently active ones. This ensures the URL doesn't get cluttered with old params when changing filters\n    this.settings.filters.forEach(filter => {\n      const filtertype = filter.type ? filter.type : filter.ischeckboxes ? \"checkboxes\" : \"select\";\n      if( filtertype === \"daterange\" ) {\n        loc.searchParams.delete(`${filter.name}.start`);\n        loc.searchParams.delete(`${filter.name}.end`);\n      } else {\n        loc.searchParams.delete(filter.name);\n      }\n    });\n\n    if( this.settings.headerTabsFilter )\n      loc.searchParams.delete(this.settings.headerTabsFilter.name);\n\n    for (const [filter, entry] of Object.entries(filters.facets)) {\n      if (entry.length > 0 ) {\n        const vals = entry.filter(v => v.value).map(v => v.value);\n        if( vals.length > 0 )\n          loc.searchParams.set(filter, vals.join(\",\"));\n      }\n    }\n    if( filters.searchWords )\n      loc.searchParams.set(\"query\", filters.searchWords);\n    else\n      loc.searchParams.delete(\"query\");\n\n    history.replaceState(null, \"\", loc.toString());\n  }\n\n  async showItemsBasedOnFilter(filters: PageFiltersQuery) {\n    const itemsRequest = this.filter.filter({ query: filters });\n    const items = itemsRequest instanceof Promise ? await itemsRequest : itemsRequest;\n    if( !items || this.settings.options?.reloadOnFilterChange )\n      return; // If no update is needed (eg because the filter itself updates the UI), the filter can return null/undefined to skip the update\n\n    dompack.qSA(\".pagefilters__item\").forEach(item => item.remove());\n    items.forEach(item => item.classList.add(\"pagefilters__item\"));\n    this.itemsContainer.append(...items);\n\n    const fbtxt = this.settings.options?.customFeedback ? this.settings.options.customFeedback : getTid(\"utwente_base:frontend.ws2016.js.pagefilters.search-xresults\", String(items.length));\n    dompack.qSA(\".page-filterstoolbar__feedback\").forEach(el => el.textContent = fbtxt);\n\n    dompack.qSA(\".page-filters__mobiletoggle__hidelabel\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-xresults\", String(items.length)));\n    document.documentElement.classList.toggle(\"page-filters--noresults\", !items.length); // used to show no results message\n\n    dompack.registerMissed(this.itemsContainer); // Register any new elements in the items container so they can be enhanced by other scripts\n\n    // Send event after update items\n    dompack.dispatchCustomEvent(this.itemsContainer, \"pagefilters:afterfilter\", { bubbles: true, cancelable: false, detail: { totalcount: items.length } });\n  }\n\n  deleteTags(associatedFilters: Array<{ filter: string; value: string }>) {\n    for (const { filter, value } of associatedFilters) {\n\n      const input = dompack.qS<HTMLInputElement>(`.page-filters__form input[name=\"${filter}\"][value=\"${value}\"]`);\n      if (input && [\"checkbox\", \"radio\"].includes(input.type)) {\n        input.checked = false;\n        continue;\n      }\n      const select = dompack.qS<HTMLSelectElement>(`.page-filters__form select[name=\"${filter}\"]`);\n      if (select) {\n        if( select.classList.contains(\"replacedby-ss\") ) {\n          const ss = (select as HTMLSelectElement & { slim: SlimSelect }).slim;\n          ss.setSelected(\"\");\n        } else {\n          select.selectedIndex = 0;\n        }\n        continue;\n      }\n      const txtinput = dompack.qS<HTMLInputElement>(`.page-filters__form input[name=\"${filter}\"]`);\n      if (txtinput && ![\"checkbox\", \"radio\"].includes(txtinput.type)) {\n        txtinput.value = \"\";\n        continue;\n      }\n      const hiddenFilter = this.settings.filters.filter(_=>_.type === \"hidden\" && _.name === filter);\n      if( hiddenFilter ) { // For now we only support single value hidden filters, if needed this can be extended to support multiple values like the other filters\n        const loc = new URL(location.href);\n        loc.searchParams.delete(filter);\n        history.replaceState(null, \"\", loc.toString());\n        continue;\n      }\n\n      console.error(\"Could not find input/select for filter\", filter, value);\n    }\n    void this.onFilterChange();\n  }\n\n  updateTagsBar(filters: PageFiltersQuery) {\n    const tagsBar = dompack.qS(\".pagefilters__tags\");\n    if (!tagsBar)\n      return;\n\n    const tags = getFlatActiveFilterValuesList(filters);\n    /* FIXME ProjectsOverview used this. If we re-add this we need to be more explicit about what filtervalues to delete given a tag\n    Present the oppertunity to merge tags\n    // For example status=graduated+graduationyear=2018 could be mapped to graduationyear=2018 with title \"Completed in 2018\"\n    if (this.onMapFilterTags) {\n      tags = this.onMapFilterTags(tags, this.filters);\n      //console.info(\"TAGS after mapping\", {...tags});\n    }\n    */\n\n    const newtags = tags.map(tag => <span class=\"pagefilters__tag\" onClick={() => this.deleteTags(tag.associatedFilters)}><span>{tag.title}</span><i class=\"UT-icon-UT_icon_47_cross-16px\" aria-label={`Remove filter ${tag.title}`}></i></span>);\n    tagsBar.replaceChildren(...newtags);\n  }\n}\n\nexport function setupAutoPageFilter() {\n  const settings = getFrontendData(\"utwente_base:pagefilters\", { allowMissing: true });\n  if (!settings)\n    return;\n\n  //ensure we wait until #main is present and all filters are registered, and then set it up:\n  setTimeout(() => dompack.onDomReady(() => new FilteredOverview(settings)));\n}\n\nexport function registerCustomFilter(name: string, factory: () => CustomPageFilter) {\n  if (factories[name])\n    throw new Error(`Custom filter with name ${name} is already registered`);\n  factories[name] = factory;\n}\n","/**\n * Copyright (c) 2016 Denis Taran\n * \n * Homepage: https://smartscheduling.com/en/documentation/autocomplete\n * Source: https://github.com/denis-taran/autocomplete\n * \n * MIT License\n */\n\nexport const enum EventTrigger {\n    Keyboard = 0,\n    Focus = 1,\n    Mouse = 2,\n    /**\n     * Fetch is triggered manually by calling `fetch` function returned in `AutocompleteResult`\n     */\n    Manual = 3\n}\n\n/**\n * Enum for controlling form submission when `ENTER` key is pressed in the autocomplete input field.\n */\nexport const enum PreventSubmit {\n    Never = 0,\n    Always = 1,\n    /**\n     * Form submission is prevented only when an item is selected from the autocomplete list.\n     */\n    OnSelect = 2\n}\n\nexport interface AutocompleteItem {\n    label?: string;\n    group?: string;\n}\n\nexport interface AutocompleteEvent<T extends Event> {\n    /**\n     * Native event object passed by browser to the event handler\n     */\n    event: T;\n\n    /**\n     * Fetch data and display autocomplete\n     */\n    fetch: () => void;\n}\n\nexport interface AutocompleteSettings<T extends AutocompleteItem> {\n    /**\n     * Autocomplete will be attached to this element.\n     */\n    input: HTMLInputElement | HTMLTextAreaElement;\n\n    /**\n     * Provide your own container for the widget.\n     * If not specified, a new DIV element will be created.\n     */\n    container?: HTMLDivElement;\n\n    /**\n     * This method allows you to override the default rendering function for items.\n     * It must return a DIV element or undefined to skip rendering.\n     */\n    render?: (item: T, currentValue: string, index: number) => HTMLDivElement | undefined;\n\n    /**\n     * This method allows you to override the default rendering function for item groups.\n     * It must return a DIV element or undefined to skip rendering.\n     */\n    renderGroup?: (name: string, currentValue: string) => HTMLDivElement | undefined;\n\n    /**\n     * If specified, the autocomplete DOM element will have this class assigned to it.\n     */\n    className?: string;\n\n    /**\n     * Specify the minimum text length required to show autocomplete.\n     */\n    minLength?: number;\n\n    /**\n     * The message that will be showed when there are no suggestions that match the entered value.\n     */\n    emptyMsg?: string;\n\n    /**\n     * This method will be called when user choose an item in autocomplete. The selected item will be passed as the first parameter.\n     */\n    onSelect: (item: T, input: HTMLInputElement | HTMLTextAreaElement) => void;\n\n    /**\n     * Show autocomplete on focus event. Focus event will ignore the `minLength` property and will always call `fetch`.\n     */\n    showOnFocus?: boolean;\n\n    /**\n     * This method will be called to prepare suggestions and then pass them to autocomplete.\n     * @param {string} text - text in the input field\n     * @param {(items: T[] | false) => void} update - a callback function that must be called after suggestions are prepared\n     * @param {EventTrigger} trigger - type of the event that triggered the fetch\n     * @param {number} cursorPos - position of the cursor in the input field\n     */\n    fetch: (text: string, update: (items: T[] | false) => void, trigger: EventTrigger, cursorPos: number) => void;\n\n    /**\n     * Enforces that the fetch function will only be called once within the specified time frame (in milliseconds) and\n     * delays execution. This prevents flooding your server with AJAX requests.\n     */\n    debounceWaitMs?: number;\n\n    /**\n     * Callback for additional autocomplete customization\n     * @param {HTMLInputElement | HTMLTextAreaElement} input - input box associated with autocomplete\n     * @param {ClientRect | DOMRect} inputRect - size of the input box and its position relative to the viewport\n     * @param {HTMLDivElement} container - container with suggestions\n     * @param {number} maxHeight - max height that can be used by autocomplete\n     */\n    customize?: (input: HTMLInputElement | HTMLTextAreaElement, inputRect: ClientRect | DOMRect, container: HTMLDivElement, maxHeight: number) => void;\n\n    /**\n     * Controls form submission when the ENTER key is pressed in a input field.\n     */\n    preventSubmit?: PreventSubmit;\n\n    /**\n     * Prevents the first item in the list from being selected automatically. This option allows you\n     * to submit a custom text by pressing ENTER even when autocomplete is displayed.\n     */\n    disableAutoSelect?: boolean;\n\n    /**\n     * Provide your keyup event handler to display autocomplete when a key is pressed that doesn't modify the content. You can also perform some additional actions.\n     */\n    keyup?: (e: AutocompleteEvent<KeyboardEvent>) => void;\n\n    /**\n     * Allows to display autocomplete on mouse clicks or perform some additional actions.\n     */\n    click?: (e: AutocompleteEvent<MouseEvent>) => void;\n}\n\nexport interface AutocompleteResult {\n    /**\n     * Remove event handlers, DOM elements and ARIA/accessibility attributes created by the widget.\n     */\n    destroy: () => void;\n\n    /**\n     * This function allows to manually start data fetching and display autocomplete. Note that\n     * it does not automatically place focus on the input field, so you may need to do so manually\n     * in certain situations.\n     */\n    fetch: () => void;\n}\n\nexport default function autocomplete<T extends AutocompleteItem>(settings: AutocompleteSettings<T>): AutocompleteResult {\n\n    // just an alias to minimize JS file size\n    const doc = document;\n\n    const container: HTMLDivElement = settings.container || doc.createElement('div');\n    const preventSubmit: PreventSubmit = settings.preventSubmit || PreventSubmit.Never;\n\n    container.id = container.id || 'autocomplete-' + uid();\n    const containerStyle = container.style;\n    const debounceWaitMs = settings.debounceWaitMs || 0;\n    const disableAutoSelect = settings.disableAutoSelect || false;\n    const customContainerParent = container.parentElement;\n\n    let items: T[] = [];\n    let inputValue = '';\n    let minLen = 2;\n    const showOnFocus = settings.showOnFocus;\n    let selected: T | undefined;\n    let fetchCounter = 0;\n    let debounceTimer: number | undefined;\n    let destroyed = false;\n\n    // Fixes #104: autocomplete selection is broken on Firefox for Android\n    let suppressAutocomplete = false;\n\n    if (settings.minLength !== undefined) {\n        minLen = settings.minLength;\n    }\n\n    if (!settings.input) {\n        throw new Error('input undefined');\n    }\n\n    const input: HTMLInputElement | HTMLTextAreaElement = settings.input;\n\n    container.className = [container.className, 'autocomplete', settings.className || ''].join(' ').trim();\n    container.setAttribute('role', 'listbox');\n\n    input.setAttribute('role', 'combobox');\n    input.setAttribute('aria-expanded', 'false');\n    input.setAttribute('aria-autocomplete', 'list');\n    input.setAttribute('aria-controls', container.id);\n    input.setAttribute('aria-owns', container.id);\n    input.setAttribute('aria-activedescendant', '');\n    input.setAttribute('aria-haspopup', 'listbox');\n\n    // IOS implementation for fixed positioning has many bugs, so we will use absolute positioning\n    containerStyle.position = 'absolute';\n\n    /**\n     * Generate a very complex textual ID that greatly reduces the chance of a collision with another ID or text.\n     */\n    function uid(): string {\n        return Date.now().toString(36) + Math.random().toString(36).substring(2);\n    }\n\n    /**\n     * Detach the container from DOM\n     */\n    function detach() {\n        const parent = container.parentNode;\n        if (parent) {\n            parent.removeChild(container);\n        }\n    }\n\n    /**\n     * Clear debouncing timer if assigned\n     */\n    function clearDebounceTimer() {\n        if (debounceTimer) {\n            window.clearTimeout(debounceTimer);\n        }\n    }\n\n    /**\n     * Attach the container to DOM\n     */\n    function attach() {\n        if (!container.parentNode) {\n            (customContainerParent || doc.body).appendChild(container);\n        }\n    }\n\n    /**\n     * Check if container for autocomplete is displayed\n     */\n    function containerDisplayed(): boolean {\n        return !!container.parentNode;\n    }\n\n    /**\n     * Clear autocomplete state and hide container\n     */\n    function clear() {\n        // prevent the update call if there are pending AJAX requests\n        fetchCounter++;\n\n        items = [];\n        inputValue = '';\n        selected = undefined;\n        input.setAttribute('aria-activedescendant', '');\n        input.setAttribute('aria-expanded', 'false');\n        detach();\n    }\n\n    /**\n     * Update autocomplete position\n     */\n    function updatePosition() {\n        if (!containerDisplayed()) {\n            return;\n        }\n\n        input.setAttribute('aria-expanded', 'true');\n\n        containerStyle.height = 'auto';\n        containerStyle.width = input.offsetWidth + 'px';\n\n        let maxHeight = 0;\n        let inputRect: DOMRect | undefined;\n\n        function calc() {\n            const docEl = doc.documentElement as HTMLElement;\n            const clientTop = docEl.clientTop || doc.body.clientTop || 0;\n            const clientLeft = docEl.clientLeft || doc.body.clientLeft || 0;\n            const scrollTop = window.pageYOffset || docEl.scrollTop;\n            const scrollLeft = window.pageXOffset || docEl.scrollLeft;\n\n            inputRect = input.getBoundingClientRect();\n\n            const top = inputRect.top + input.offsetHeight + scrollTop - clientTop;\n            const left = inputRect.left + scrollLeft - clientLeft;\n\n            containerStyle.top = top + 'px';\n            containerStyle.left = left + 'px';\n\n            maxHeight = window.innerHeight - (inputRect.top + input.offsetHeight);\n\n            if (maxHeight < 0) {\n                maxHeight = 0;\n            }\n\n            containerStyle.top = top + 'px';\n            containerStyle.bottom = '';\n            containerStyle.left = left + 'px';\n            containerStyle.maxHeight = maxHeight + 'px';\n        }\n\n        // the calc method must be called twice, otherwise the calculation may be wrong on resize event (chrome browser)\n        calc();\n        calc();\n\n        if (settings.customize && inputRect) {\n            settings.customize(input, inputRect, container, maxHeight);\n        }\n    }\n\n    /**\n     * Redraw the autocomplete div element with suggestions\n     */\n    function update() {\n\n        container.textContent = '';\n        input.setAttribute('aria-activedescendant', '');\n\n        // function for rendering autocomplete suggestions\n        let render = function (item: T, _: string, __: number): HTMLDivElement | undefined {\n            const itemElement = doc.createElement('div');\n            itemElement.textContent = item.label || '';\n            return itemElement;\n        };\n        if (settings.render) {\n            render = settings.render;\n        }\n\n        // function to render autocomplete groups\n        let renderGroup = function (groupName: string, _: string): HTMLDivElement | undefined {\n            const groupDiv = doc.createElement('div');\n            groupDiv.textContent = groupName;\n            return groupDiv;\n        };\n        if (settings.renderGroup) {\n            renderGroup = settings.renderGroup;\n        }\n\n        const fragment = doc.createDocumentFragment();\n        let prevGroup = uid();\n\n        items.forEach(function (item: T, index: number): void {\n            if (item.group && item.group !== prevGroup) {\n                prevGroup = item.group;\n                const groupDiv = renderGroup(item.group, inputValue);\n                if (groupDiv) {\n                    groupDiv.className += ' group';\n                    fragment.appendChild(groupDiv);\n                }\n            }\n            const div = render(item, inputValue, index);\n            if (div) {\n                div.id = `${container.id}_${index}`;\n                div.setAttribute('role', 'option');\n                div.addEventListener('click', function (ev: MouseEvent): void {\n                    suppressAutocomplete = true;\n                    try {\n                        settings.onSelect(item, input);\n                    } finally {\n                        suppressAutocomplete = false;\n                    }\n                    clear();\n                    ev.preventDefault();\n                    ev.stopPropagation();\n                });\n                if (item === selected) {\n                    div.className += ' selected';\n                    div.setAttribute('aria-selected', 'true');\n                    input.setAttribute('aria-activedescendant', div.id);\n                }\n                fragment.appendChild(div);\n            }\n        });\n        container.appendChild(fragment);\n        if (items.length < 1) {\n            if (settings.emptyMsg) {\n                const empty = doc.createElement('div');\n                empty.id = `${container.id}_${uid()}`;\n                empty.className = 'empty';\n                empty.textContent = settings.emptyMsg;\n                container.appendChild(empty);\n                input.setAttribute('aria-activedescendant', empty.id);\n            } else {\n                clear();\n                return;\n            }\n        }\n\n        attach();\n        updatePosition();\n\n        updateScroll();\n    }\n\n    function updateIfDisplayed() {\n        if (containerDisplayed()) {\n            update();\n        }\n    }\n\n    function resizeEventHandler() {\n        updateIfDisplayed();\n    }\n\n    function scrollEventHandler(e: Event) {\n        if (e.target !== container) {\n            updateIfDisplayed();\n        } else {\n            e.preventDefault();\n        }\n    }\n\n    function inputEventHandler() {\n        if (!suppressAutocomplete) {\n            fetch(EventTrigger.Keyboard);\n        }\n    }\n\n    /**\n     * Automatically move scroll bar if selected item is not visible\n     */\n    function updateScroll() {\n        const elements = container.getElementsByClassName('selected');\n        if (elements.length > 0) {\n            let element = elements[0] as HTMLDivElement;\n\n            // make group visible\n            const previous = element.previousElementSibling as HTMLDivElement;\n            if (previous && previous.className.indexOf('group') !== -1 && !previous.previousElementSibling) {\n                element = previous;\n            }\n\n            if (element.offsetTop < container.scrollTop) {\n                container.scrollTop = element.offsetTop;\n            } else {\n                const selectBottom = element.offsetTop + element.offsetHeight;\n                const containerBottom = container.scrollTop + container.offsetHeight;\n                if (selectBottom > containerBottom) {\n                    container.scrollTop += selectBottom - containerBottom;\n                }\n            }\n        }\n    }\n\n    function selectPreviousSuggestion() {\n        const index = items.indexOf(selected!);\n\n        selected = index === -1\n            ? undefined\n            : items[(index + items.length - 1) % items.length];\n\n        updateSelectedSuggestion(index);\n    }\n\n    function selectNextSuggestion() {\n        const index = items.indexOf(selected!);\n\n        selected = items.length < 1\n            ? undefined\n            : index === -1\n                ? items[0]\n                : items[(index + 1) % items.length];\n\n        updateSelectedSuggestion(index);\n    }\n\n    function updateSelectedSuggestion(index: number) {\n        if (items.length > 0) {\n            unselectSuggestion(index);\n            selectSuggestion(items.indexOf(selected!));\n            updateScroll();\n        }\n    }\n\n    function selectSuggestion(index: number) {\n        var element = doc.getElementById(container.id + \"_\" + index);\n        if (element) {\n            element.classList.add('selected');\n            element.setAttribute('aria-selected', 'true');\n            input.setAttribute('aria-activedescendant', element.id);\n        }\n    }\n\n    function unselectSuggestion(index: number) {\n        var element = doc.getElementById(container.id + \"_\" + index);\n        if (element) {\n            element.classList.remove('selected');\n            element.removeAttribute('aria-selected');\n            input.removeAttribute('aria-activedescendant');\n        }\n    }\n\n    function handleArrowAndEscapeKeys(ev: KeyboardEvent, key: 'ArrowUp' | 'ArrowDown' | 'Escape') {\n        const containerIsDisplayed = containerDisplayed();\n\n        if (key === 'Escape') {\n            clear();\n        } else {\n            if (!containerIsDisplayed || items.length < 1) {\n                return;\n            }\n            key === 'ArrowUp'\n                ? selectPreviousSuggestion()\n                : selectNextSuggestion();\n        }\n\n        ev.preventDefault();\n\n        if (containerIsDisplayed) {\n            ev.stopPropagation();\n        }\n    }\n\n    function handleEnterKey(ev: KeyboardEvent) {\n        if (selected) {\n            if (preventSubmit === PreventSubmit.OnSelect) {\n                ev.preventDefault();\n            }\n            suppressAutocomplete = true;\n            try {\n                settings.onSelect(selected, input);\n            } finally {\n                suppressAutocomplete = false;\n            }\n            clear();\n        }\n\n        if (preventSubmit === PreventSubmit.Always) {\n            ev.preventDefault();\n        }\n    }\n\n    function keydownEventHandler(ev: KeyboardEvent) {\n        const key = ev.key;\n\n        switch (key) {\n            case 'ArrowUp':\n            case 'ArrowDown':\n            case 'Escape':\n                handleArrowAndEscapeKeys(ev, key);\n                break;\n            case 'Enter':\n                handleEnterKey(ev);\n                break;\n            default:\n                break;\n        }\n    }\n\n    function focusEventHandler() {\n        if (showOnFocus) {\n            fetch(EventTrigger.Focus);\n        }\n    }\n\n    function fetch(trigger: EventTrigger) {\n        if (input.value.length >= minLen || trigger === EventTrigger.Focus) {\n            clearDebounceTimer();\n            debounceTimer = window.setTimeout(\n                () => startFetch(input.value, trigger, input.selectionStart || 0),\n                trigger === EventTrigger.Keyboard || trigger === EventTrigger.Mouse ? debounceWaitMs : 0);\n        } else {\n            clear();\n        }\n    }\n\n    function startFetch(inputText: string, trigger: EventTrigger, cursorPos: number) {\n        if (destroyed) return;\n        const savedFetchCounter = ++fetchCounter;\n        settings.fetch(inputText, function (elements: T[] | false): void {\n            if (fetchCounter === savedFetchCounter && elements) {\n                items = elements;\n                inputValue = inputText;\n                selected = (items.length < 1 || disableAutoSelect) ? undefined : items[0];\n                update();\n            }\n        }, trigger, cursorPos);\n    }\n\n    function keyupEventHandler(e: KeyboardEvent) {\n        if (settings.keyup) {\n            settings.keyup({\n                event: e,\n                fetch: () => fetch(EventTrigger.Keyboard)\n            });\n            return;\n        }\n\n        if (!containerDisplayed() && e.key === 'ArrowDown') {\n            fetch(EventTrigger.Keyboard);\n        }\n    }\n\n    function clickEventHandler(e: MouseEvent) {\n        settings.click && settings.click({\n            event: e,\n            fetch: () => fetch(EventTrigger.Mouse)\n        });\n    }\n\n    function blurEventHandler() {\n        // when an item is selected by mouse click, the blur event will be initiated before the click event and remove DOM elements,\n        // so that the click event will never be triggered. In order to avoid this issue, DOM removal should be delayed.\n        setTimeout(() => {\n            if (doc.activeElement !== input) {\n                clear();\n            }\n        }, 200);\n    }\n\n    function manualFetch() {\n        startFetch(input.value, EventTrigger.Manual, input.selectionStart || 0);\n    }\n\n    /**\n     * Fixes #26: on long clicks focus will be lost and onSelect method will not be called\n     */\n    container.addEventListener('mousedown', function (evt: Event) {\n        evt.stopPropagation();\n        evt.preventDefault();\n    });\n\n    /**\n     * Fixes #30: autocomplete closes when scrollbar is clicked in IE\n     * See: https://stackoverflow.com/a/9210267/13172349\n     */\n    container.addEventListener('focus', () => input.focus());\n\n    // If the custom autocomplete container is already appended to the DOM during widget initialization, detach it.\n    detach();\n\n    /**\n     * This function will remove DOM elements and clear event handlers\n     */\n    function destroy() {\n        input.removeEventListener('focus', focusEventHandler);\n        input.removeEventListener('keyup', keyupEventHandler as EventListenerOrEventListenerObject)\n        input.removeEventListener('click', clickEventHandler as EventListenerOrEventListenerObject)\n        input.removeEventListener('keydown', keydownEventHandler as EventListenerOrEventListenerObject);\n        input.removeEventListener('input', inputEventHandler as EventListenerOrEventListenerObject);\n        input.removeEventListener('blur', blurEventHandler);\n        window.removeEventListener('resize', resizeEventHandler);\n        doc.removeEventListener('scroll', scrollEventHandler, true);\n        input.removeAttribute('role');\n        input.removeAttribute('aria-expanded');\n        input.removeAttribute('aria-autocomplete');\n        input.removeAttribute('aria-controls');\n        input.removeAttribute('aria-activedescendant');\n        input.removeAttribute('aria-owns');\n        input.removeAttribute('aria-haspopup');\n        clearDebounceTimer();\n        clear();\n        destroyed = true;\n    }\n\n    // setup event handlers\n    input.addEventListener('keyup', keyupEventHandler as EventListenerOrEventListenerObject);\n    input.addEventListener('click', clickEventHandler as EventListenerOrEventListenerObject);\n    input.addEventListener('keydown', keydownEventHandler as EventListenerOrEventListenerObject);\n    input.addEventListener('input', inputEventHandler as EventListenerOrEventListenerObject);\n    input.addEventListener('blur', blurEventHandler);\n    input.addEventListener('focus', focusEventHandler);\n    window.addEventListener('resize', resizeEventHandler);\n    doc.addEventListener('scroll', scrollEventHandler, true);\n\n    return {\n        destroy,\n        fetch: manualFetch\n    };\n}\n","import \"./autocomplete.scss\";\nimport autocomplete, { AutocompleteItem, AutocompleteSettings, AutocompleteResult } from \"autocompleter\";\n\n// Wrapper for npm autocompleter so we can use it for other utwente modules with utwente_base dependency\nexport default function UTAutoComplete<T extends AutocompleteItem>(settings: AutocompleteSettings<T>): AutocompleteResult {\n  return autocomplete(settings);\n}\n","import { levenshteinDistance } from \"@webhare/std\";\n\nconst wordRegex = new RegExp(\"\\\\w+\", \"g\");\nconst lastWordRegex = new RegExp(\"(.*[^\\\\w])?(\\\\w+)$\");\n\ntype FieldsMap = Map<string, number>;\ntype Fields = { fields: FieldsMap };\ntype ItemPositions = { positions: number[] };\ntype Entries<ItemType> = Map<ItemType, ItemPositions>;\n\nexport class SearchIndex<ItemType extends object> {\n  // Create a new index mapping\n  index = new Map<string, Entries<ItemType>>;\n  // Global item metadata (e.g. total wordcount per field)\n  items = new Map<ItemType, Fields>;\n\n  // Initialize the search and suggest fields, fill automatically\n  _searchFields: string[] = [];\n  _autoSearchFields = true;\n  _suggestFields: string[] = [];\n  _autoSuggestFields = true;\n  _completeSuggestFields: string[] = [];\n\n  /// The fields that are used for searching, defaults to all of the indexed fields\n  get searchFields() {\n    // Return the search fields\n    return this._searchFields;\n  }\n\n  set searchFields(fields) {\n    // The search fields are set manually\n    this._searchFields = fields;\n    this._autoSearchFields = false;\n  }\n\n  /// The fields that are used for suggestions, defaults to the searchFields\n  get suggestFields() {\n    // If not set manually, return the search fields\n    return this._autoSuggestFields ? this._searchFields : this._suggestFields;\n  }\n\n  set suggestFields(fields) {\n    // The suggest fields are set manually\n    this._suggestFields = fields;\n    this._autoSuggestFields = false;\n  }\n\n  /// If words from this field are suggested, the complete field is returned as a suggestion\n  get completeSuggestFields() {\n    return this._completeSuggestFields;\n  }\n\n  set completeSuggestFields(fields) {\n    this._completeSuggestFields = fields;\n  }\n\n  /** Index an item\n      This function indexes an item. All of the 'string' properties of the item are tokenized and indexed.\n  */\n  indexItem(item: ItemType): void {\n    const fields: FieldsMap = new Map;\n\n    // Index all indexable properties of the incoming item\n    for (const [key, invalue] of Object.entries(item as Record<string, string | unknown>)) {\n      // For now, we'll only index string values\n      if (typeof invalue !== \"string\")\n        continue;\n\n      // If not set manually, search through all indexed fields\n      if (this._autoSearchFields && !this._searchFields.includes(key))\n        this._searchFields.push(key);\n\n      // Normalize the value\n      const value = invalue.toLowerCase();\n\n      // Tokenize into words\n      let match;\n      let count = 0;\n      while ((match = wordRegex.exec(value)) !== null) {\n        const term = key + \":\" + match[0];\n        const pos = match.index;\n\n        // See if this term is already indexed\n        let entry = this.index.get(term);\n        if (!entry) {\n          // Create a new entry for this term\n          entry = new Map();\n          this.index.set(term, entry);\n        }\n\n        // See if this item is already indexed for this term\n        let props = entry.get(item);\n        if (!props) {\n          // Add the item to this term\n          props = { positions: [] } satisfies ItemPositions;\n          entry.set(item, props);\n        }\n\n        // Add the term's position\n        props.positions.push(pos);\n        ++count;\n      }\n      fields.set(key, count);\n\n    }\n    // Store the item's field counts\n    this.items.set(item, { fields });\n  }\n\n  /** Get suggestions for a query\n      @returns A list of suggested queries\n  */\n  suggest(query: string): string[] {\n    const results = new Map<string, number[]>;\n\n    // Split the incoming query into the array [ \"original query\", \"query up until last word\", \"last word of query\" ]\n    const parsedQuery = lastWordRegex.exec(query);\n    if (parsedQuery) {\n      const baseQuery = parsedQuery[1] || \"\";\n      const suggestQuery = parsedQuery[2];\n\n      let baseResults;\n      if (baseQuery)\n        baseResults = this.#searchInternal(baseQuery).results;\n\n      // Iterate over all the terms in the index\n      for (const [term, entry] of this.index) {\n        // Split the term into field and text\n        const termField = term.split(\":\")[0];\n        if (!this.suggestFields.includes(termField))\n          continue; // This is not a suggested field\n\n        const termText = term.substr(termField.length + 1);\n\n        // Check if the text matches the last query word\n        const score = this.#matchesText(suggestQuery, termText, { startsWithScore: .9 });\n        if (score) {\n          // Return the query, completed with the matching term text\n          let suggestion = baseQuery + termText;\n          if (!results.has(suggestion))\n            results.set(suggestion, [score]);\n\n          // If this field should be returned whole, return this field from each of the entry's items\n          if (this.completeSuggestFields.includes(termField)) {\n            for (const item of entry.keys()) {\n              if (baseResults && !baseResults.has(item))\n                continue;\n              const scores = [score];\n              if (baseResults)\n                scores.push(...baseResults.get(item)!); //due to the two 'if's before here, baseResults.get(item) is not null\n\n              suggestion = (item as Record<string, string>)[termField];\n              const result = results.get(suggestion);\n              if (result)\n                result.push(...scores);\n              else\n                results.set(suggestion, scores);\n            }\n          }\n        }\n      }\n    }\n    if (!results)\n      return [];\n\n    // Calcu§late single scores\n    const flatscores = this.#calculateScores(results);\n\n    // Sort by score and return the suggestions as an array\n    return this.#getSortedItems(flatscores);\n  }\n\n  /** Search for items\n      @param query - The query to search for (only words are searched, interpunction is ignored)\n      @returns The matching items, in scoring order\n  */\n  search(query: string): {\n    items: ItemType[];\n    terms: string[];\n  } {\n    const searchResult = this.#searchInternal(query);\n    // Sort by score and return the items as an array\n    const items = this.#getSortedItems(searchResult.results);\n    return { items, terms: searchResult.terms };\n  }\n\n  #searchInternal(query: string) {\n    const results = new Map<ItemType, number[]>();\n    const terms: string[] = [];\n\n    query = query.toLowerCase();\n\n    // Only search through searched fields\n    for (const field of this.searchFields) {\n      let fieldResults;\n      // Iterate over each of the words in the query\n      const matches = query.match(wordRegex);\n      if (matches) {\n        for (const word of matches) {\n          // Search for the word in this field\n          const queryResult = this.#executeQuery(field, word);\n          // If one the words doesn't match anything, return nothing (AND serach)\n          if (!queryResult.results.size)\n            continue;\n\n          for (const term of queryResult.terms)\n            if (!terms.includes(term))\n              terms.push(term);\n\n          // If there are no results yet, add these results\n          if (!fieldResults) {\n            fieldResults = new Map();\n            for (const [item, match] of queryResult.results)\n              fieldResults.set(item, match.scores);\n          } else {\n            // Keep all items that are already there (AND search)\n            for (const [item, match] of queryResult.results) {\n              if (fieldResults.has(item))\n                fieldResults.get(item).push(...match.scores);\n            }\n            // Remove all items that aren't found again (AND search)\n            for (const item of fieldResults.keys())\n              if (!queryResult.results.has(item))\n                fieldResults.delete(item);\n          }\n        }\n      }\n\n      if (fieldResults) {\n        for (const [item, scores] of fieldResults) {\n          const result = results.get(item);\n          if (result)\n            result.push(...scores);\n          else\n            results.set(item, scores);\n        }\n      }\n    }\n\n    // Calculate single scores\n    const flatscores = this.#calculateScores(results);\n    return { results: flatscores, terms };\n  }\n\n  // returns a Map from item to { scores, term, positions }\n  #executeQuery(field: string, text: string) {\n    let results;\n    const terms: string[] = [];\n    // Try a direct match\n    const entry = this.index.get(field + \":\" + text);\n    if (entry) {\n      // The entry's keys are the indexed items\n      results = new Map(Array.from(entry).map(item_positions => {\n        return [item_positions[0], { scores: [1], term: text, positions: item_positions[1].positions }];\n      }));\n      terms.push(text);\n    } else {\n      // Iterate over all the terms in the index\n      results = new Map();\n      for (const [term, indexEntry] of this.index) {\n        // Split the term into field and text\n        const termField = term.split(\":\")[0];\n        if (termField !== field && field !== \"*\")\n          continue; // This is not the field we're looking for\n\n        const termText = term.substr(termField.length + 1);\n\n        // Check if the text matches the query word\n        const score = this.#matchesText(text, termText);\n        if (score) {\n          for (const item_positions of Array.from(indexEntry)) {\n            if (!results.has(item_positions[0]))\n              results.set(item_positions[0], { scores: [score], term: termText, positions: item_positions[1].positions });\n            else\n              results.get(item_positions[0]).scores.push(score);\n          }\n          terms.push(termText);\n        }\n      }\n\n      // Calculate single scores\n      for (const [item, match] of results)\n        results.get(item).scores = [match.scores.reduce((avg: number, cur: number, idx: number) => ((avg * idx) + cur) / (idx + 1))];\n    }\n    return { results, terms };\n  }\n\n  #matchesText(queryWord: string, termWord: string, { limitDistance = 2, startsWithScore = .25 } = {}) {\n    if (queryWord === termWord)\n      return 1;\n    let score = 0;\n    // Require both terms to have a length of at least twice the distance\n    if (Math.min(queryWord.length, termWord.length) >= 2 * limitDistance) {\n      const dist = levenshteinDistance(queryWord, termWord);\n      if (dist <= limitDistance)\n        score = Math.max(score, (limitDistance - dist + 1) / limitDistance);\n    }\n    if (termWord.startsWith(queryWord))\n      score = Math.max(score, startsWithScore);\n    return score;\n  }\n\n  #calculateScores<KeyType>(results: Map<KeyType, number[]>) {\n    const flatscores = new Map<KeyType, number[]>;\n    for (const [key, scores] of results)\n      flatscores.set(key, [scores.reduce((avg, cur, idx) => ((avg * idx) + cur) / (idx + 1))]);\n    return flatscores;\n  }\n\n  #getSortedItems<KeyType>(results: Map<KeyType, number[]>): KeyType[] {\n    return Array.from(results).sort((a, b) => b[1][0] - a[1][0]).map(_ => _[0]);\n  }\n}\n","/* This is the core of ws2026, as shared between UTAP, ITC and UTWENTE_BASE\n   Do not add external module dependencies (other than utwente_design) here!\n   Do not add 'shared/login' here as UTAP/ITC don't need it and may setup their own alternatives\n*/\n\nimport { setupNextPager } from \"@mod-utwente_base/src/nextpager/nextpager\";\n\n//FIXME: to support Yuja we temporary load our own video support\n// import \"@mod-publisher/js/richcontent/all\"; // Cannot use this for now, it loads the standard video handler (which doesn't support Yuja and adding custom videoproviders yet)\nimport \"@mod-publisher/js/richcontent/styling.css\";\nimport \"@mod-utwente_design/webfeatures/videoproviders\";\n\nimport \"@mod-utwente_design/theme/theme\";\n\n// rtd.css is imported separately, because it's also loaded by the rich document editor. It cannot be imported by site.scss,\n// because the SASS parser cannot handle the external font from fonts.net.\nimport \"./shared/rtd/rtd.ts\";\nimport \"./shared/fonts/fonts.css\";\nimport \"@mod-utwente_design/web/utdesign/fonts/univers-next-async\";\n\n//FIXME should be behind addToAssetPack but that's not in moddef.yml yet\nimport \"./testcode/testcode\";\n\nsetupNextPager();\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/webdesigns/ws2026/frontend.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_base\",\"nl\",{\"frontend\":{\"ws2026\":{\"js\":{\"common\":{\"next\":\"Volgende\",\"previous\":\"Vorige\"},\"header\":{\"menu-home\":\"Home\"}}}}});\nregisterTexts(\"utwente_base\",\"en\",{\"frontend\":{\"ws2026\":{\"js\":{\"common\":{\"next\":\"Next\",\"previous\":\"Previous\"},\"header\":{\"menu-home\":\"Home\"}}}}});\nregisterTexts(\"utwente_base\",\"de\",{\"frontend\":{\"ws2026\":{\"js\":{\"common\":{\"next\":\"Nächste\",\"previous\":\"Vorherige\"}}}}});\nregisterTexts(\"utwente_base\",\"es\",{\"frontend\":{\"ws2026\":{\"js\":{\"common\":{\"next\":\"Next\",\"previous\":\"Previous\"},\"header\":{\"menu-home\":\"Home\"}}}}});\nregisterTexts(\"utwente_base\",\"it\",{\"frontend\":{\"ws2026\":{\"js\":{\"common\":{\"next\":\"Next\",\"previous\":\"Previous\"},\"header\":{\"menu-home\":\"Home\"}}}}});\nregisterTexts(\"utwente_base\",\"xt\",{\"frontend\":{\"ws2026\":{\"js\":{\"common\":{\"next\":\"Next\",\"previous\":\"Previous\"},\"header\":{\"menu-home\":\"Home\"}}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/it.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/xt.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n","import * as dompack from \"@webhare/dompack\";\nimport PerfectScrollbar from \"@mod-utwente_design/vendor/perfect-scrollbar-wh\";\n\ndeclare global {\n  interface GlobalEventHandlersEventMap {\n    \"ws2026:custom-menu-action\": CustomEvent<{\n      menuItem: HTMLElement;\n    }>;\n  }\n}\n\n/* A keyboard/mouse handler for menubars. The expected structure is something like:\n\n  <ul>\n    <li tabindex=\"0\" aria-role=\"menuitem\" aria-haspopup=\"menu\">\n      Main menu item\n      <ul>\n        <li aria-role=\"menuitem\"> <!-- No need for tabindex on an 'li' with an 'a' -->\n          <a href=\"https://example.com\">Submenu link</a>\n        </li>\n        <li aria-role=\"menuitem\" aria-haspopup=\"menu\">\n          Submenu with menu\n          <ul>\n            <li aria-role=\"menuitem\"> <!-- No need for tabindex on an 'li' with an 'a' -->\n              <a href=\"https://example.com\">Sub-submenu link</a>\n            </li>\n          </ul>\n        </li>\n        <li aria-role=\"menuitem\" tabindex=\"0\" data-custom-menu-action>\n          Submenu custom action\n        </li>\n      </ul>\n    </li>\n  </ul>\n\n  When a menu item with a submenu (i.e. aria-haspopup=\"menu\") is activated, an 'opened' class is added to it.\n  When a menu item with a custom action (i.e. data-custom-menu-action) is activated, a custom 'ws2026:custom-menu-action'\n  event is fired on the menu item node.\n\n  The user can use a keyboard to navigate through the menu using tab/shift+tab, arrow keys, enter and esc.\n*/\n\nexport class MenuHandler {\n  protected menuNode: HTMLElement;\n  protected menuActive = false;\n  horizontal = true;\n\n  get menuItemSelector() {\n    return \"[tabindex]:not([tabindex='-1']), [href]\";\n  }\n\n  // set scrollNode to null to disable scrolling\n  constructor(menuNode: HTMLElement, options?: { scrollNode?: HTMLElement | null }) {\n    this.menuNode = menuNode;\n    dompack.addDocEventListener(document.documentElement, \"mousedown\", event => this.onMouseDown(event));\n    dompack.addDocEventListener(this.menuNode, \"click\", event => this.onClick(event));\n    dompack.addDocEventListener(this.menuNode, \"keydown\", event => this.onKeyDown(event));\n\n    if (options?.scrollNode !== null) {\n      if (dompack.getBrowser().platform === \"ios\" || dompack.getBrowser().platform === \"android\")\n        (options?.scrollNode ?? this.menuNode).classList.add(\"nativescroll\");\n      else\n        new PerfectScrollbar(options?.scrollNode ?? this.menuNode, {\n          suppressScrollX: true,\n        });\n    }\n  }\n\n  closeAllMenus() {\n    this.closeSubmenus(this.menuNode);\n  }\n\n  protected onMouseDown(event: dompack.DocEvent<MouseEvent>) {\n    if (this.menuActive && !this.menuNode.contains(event.target))\n      this.closeAllMenus();\n  }\n\n  protected onClick(event: dompack.DocEvent<MouseEvent>) {\n    const curItem = event.target.closest<HTMLElement>(\"[aria-role=menuitem]\");\n    if (!curItem)\n      return;\n\n    if (curItem.ariaHasPopup === \"menu\") {\n      // Open this menu\n      dompack.stop(event);\n      this.toggleMenu(curItem);\n    } else if (curItem.hasAttribute(\"data-custom-menu-action\")) {\n      // Execute the custom action\n      dompack.stop(event);\n      dompack.dispatchCustomEvent(curItem, \"ws2026:custom-menu-action\", { bubbles: true, cancelable: false, detail: { menuItem: curItem } });\n    }\n  }\n\n  protected onKeyDown(event: dompack.DocEvent<KeyboardEvent>) {\n    const curItem = event.target.closest<HTMLElement>(\"[aria-role=menuitem]\");\n    if (!curItem)\n      return;\n\n    let level = 0;\n    for (let item = curItem as Element | null; item; item = item.parentElement?.closest(\"[aria-role=menuitem]\") ?? null)\n      ++level;\n\n    let testItem: Element | null = null;\n    let unhandledKey = false;\n    let force: boolean | undefined = undefined;\n\n    /*\n      Usually, 'left' and 'right' go up and down a level, respectively, and 'up' and 'down' select between items on the\n      current level. On the horizontal main level this switches around ('left' and 'right' select between main items, 'down'\n      navigates to the submenu level and up navigates to the main menu from the first submenu item).\n    */\n    const horizontalMain = this.horizontal && level === 1;\n    switch (event.key) {\n      case \"ArrowLeft\": {\n        if (horizontalMain) {\n          testItem = curItem.previousElementSibling;\n          force = this.menuActive; // Keep the menu open/closed when switching between main items\n        } else if (level > 1) {\n          testItem = curItem.parentElement?.closest(\"[aria-role=menuitem]\") ?? null;\n          if (!this.horizontal)\n            force = false;\n        }\n        break;\n      }\n      case \"ArrowRight\": {\n        if (horizontalMain) {\n          testItem = curItem.nextElementSibling;\n          force = this.menuActive; // Keep the menu open/closed when switching between main items\n        } else {\n          if (!this.horizontal)\n            this.toggleMenu(curItem, true); // Open this main menu and select the first item\n          testItem = curItem.querySelector(\"[aria-role=menuitem]\");\n        }\n        break;\n      }\n      case \"ArrowDown\": {\n        if (horizontalMain) {\n          this.toggleMenu(curItem, true); // Open this main menu and select the first item\n          testItem = curItem.querySelector(\"[aria-role=menuitem]\");\n        } else {\n          // Find the next item, which may be the first item of a subsequent submenu\n          testItem = curItem.nextElementSibling ?? curItem.closest(\"ul\")?.nextElementSibling?.querySelector(\"[aria-role=menuitem]\") ?? null;\n          if (!this.horizontal)\n            force = false;\n        }\n        break;\n      }\n      case \"ArrowUp\": {\n        if (!horizontalMain) {\n          if (curItem.previousElementSibling)\n            testItem = curItem.previousElementSibling;\n          else if (curItem.parentElement?.previousElementSibling?.querySelector(\"[aria-role=menuitem]\"))\n            testItem = curItem.parentElement?.previousElementSibling?.querySelector(\"[aria-role=menuitem]:last-of-type\");\n          else if (level === 2 && this.horizontal) // If this is the first submenu item of a main menu, set focus back to the main menu\n            testItem = curItem.parentElement?.closest(\"[aria-role=menuitem]\") ?? null;\n          if (!this.horizontal)\n            force = false;\n        }\n        break;\n      }\n      case \"Enter\": {\n        if (curItem.ariaHasPopup === \"menu\") {\n          // Open the submenu\n          testItem = curItem;\n        } else if (curItem.hasAttribute(\"data-custom-menu-action\")) {\n          // Execute the custom action\n          dompack.dispatchCustomEvent(curItem, \"ws2026:custom-menu-action\", { bubbles: true, cancelable: false, detail: { menuItem: curItem } });\n        } else\n          unhandledKey = true;\n        break;\n      }\n      case \"Escape\": {\n        // Close the menu\n        testItem = event.target.closest<HTMLElement>(\".opened\");\n        if (testItem)\n          force = false;\n        else\n          event.target.blur();\n        break;\n      }\n      default: {\n        unhandledKey = true;\n      }\n    }\n    if (testItem?.matches(\"[aria-role=menuitem]\")) {\n      // Open or close the menu, if necessary\n      const opened = this.toggleMenu(testItem, force ?? testItem.ariaHasPopup === \"menu\");\n      // Check if we have a node to focus\n      if (opened && !this.horizontal)\n        testItem = testItem?.querySelector(`:is(.submenu, .subsubmenu) *:where(${this.menuItemSelector})`) ?? null;\n      else\n        testItem = (testItem as HTMLElement)?.tabIndex >= 0 || testItem?.hasAttribute(\"href\") ? testItem : testItem?.querySelector(`:scope > *:where(${this.menuItemSelector})`) ?? null;\n      if (testItem)\n        (testItem as HTMLElement).focus();\n    }\n    if (!unhandledKey)\n      dompack.stop(event);\n  }\n\n  protected toggleMenu(item: Element, force?: boolean) {\n    let anyOpened = false;\n    for (const sibling of item.parentElement!.children) {\n      const wasOpened = sibling.classList.contains(\"opened\");\n      sibling.classList.toggle(\"opened\", sibling.isSameNode(item) && force); // Toggle item (undefined), switch all other siblings off\n      const opened = sibling.classList.contains(\"opened\"); // Check separately after toggling (classList.toggle only returns true if switched from false to true, so we may miss it when force === true)\n      // If this item was closed, also close its subitems\n      if (wasOpened && !opened)\n        this.closeSubmenus(sibling);\n      anyOpened = anyOpened || opened;\n      if (sibling.ariaHasPopup === \"menu\")\n        sibling.setAttribute(\"aria-expanded\", opened ? \"true\" : \"false\");\n    }\n    this.menuActive = this.menuNode.querySelectorAll(\".opened\").length > 0;\n    return anyOpened;\n  }\n\n  private closeSubmenus(item: Element) {\n    // Reverse the order to close the deepest submenu first and the top menu last\n    for (const node of [...item.querySelectorAll<HTMLElement>(\".opened\")].toReversed())\n      this.toggleMenu(node, false);\n  }\n}\n","import { getTid } from \"@mod-tollium/js/gettid\";\nimport { getLoginLink } from \"@mod-utwente_design/js/crm/auth\";\nimport { UTUserInfo } from \"@mod-utwente_design/js/ut-auth\";\nimport { MenuHandler } from \"@mod-utwente_design/js/ut-menu\";\nimport * as dompack from \"@webhare/dompack\";\nimport { getFrontendData, getUserInfo } from \"@webhare/frontend\";\nimport \"./utilitymenu.css\";\nimport \"./utilitymenu.lang.json\";\n\ndeclare global {\n  interface GlobalEventHandlersEventMap {\n    \"ws2026:togglesearch\": CustomEvent<{\n      q?: string;\n    }>;\n  }\n}\n\nclass UtilityMenu extends MenuHandler {\n  searchNode: HTMLElement | null;\n\n  constructor(node: HTMLElement) {\n    super(node, { scrollNode: null });\n\n    const loginNode = dompack.qS(\".utility-item--login\");\n    if (loginNode)\n      this.setupLoginMenu(loginNode);\n\n    this.searchNode = dompack.qS(\".utility-item--search\");\n    if (this.searchNode) {\n      dompack.addDocEventListener(this.searchNode, \"ws2026:custom-menu-action\", () => this.handleSearchSheetMenu());\n      window.addEventListener(\"keydown\", event => this.maybeOpenSearchSheetMenu(event));\n      document.addEventListener(\"searsia:showsearchsheet\", () => this.searchSheetVisibilityUpdated(true));\n      document.addEventListener(\"searsia:hidesearchsheet\", () => this.searchSheetVisibilityUpdated(false));\n\n      const q = new URL(location.href).searchParams.get(\"q\");\n      if (q)\n        setTimeout(() => this.handleSearchSheetMenu(q), 1);\n    }\n  }\n\n  private setupLoginMenu(node: HTMLElement) {\n    // The foldout node actually holds the menu items\n    const foldoutNode = node.firstElementChild as HTMLElement;\n    const userInfo = getUserInfo<UTUserInfo>();\n    if (userInfo) {\n      const menu = this.getLoginMenuItems(userInfo);\n      foldoutNode.append(\n        <div class=\"utility-toptext\">\n          {userInfo.fullname ? <div class=\"fullname\">{userInfo.fullname}</div> : null}\n          {userInfo.username ? <div class=\"loginname\">{userInfo.username}</div> : null}\n        </div>,\n        <ul class=\"utility-submenu\">\n          {menu.map(item => (\n            <li class=\"utility-subitem\" aria-role=\"menuitem\">\n              <a href={item.link}>{item.title}{item.subTitle ? <span class=\"utility-subitem--subtitle\">{item.subTitle}</span> : null}</a>\n            </li>\n          ))}\n        </ul>,\n      );\n    } else {\n      foldoutNode.append(<ul class=\"utility-submenu\">\n        <li class=\"utility-subitem utility-subitem--icon\" aria-role=\"menuitem\">\n          <a href={getLoginLink()}>{getTid(\"utwente_design:utilitymenu.loginmenu.utlogin\")}</a>\n        </li>\n      </ul>);\n    }\n  }\n\n  getLoginMenuItems(userInfo: UTUserInfo) {\n    const dutch = document.documentElement.lang.startsWith(\"nl\");\n    const frontendData = getFrontendData(\"utwente_design:utilitymenu\", { allowMissing: true });\n    if (!frontendData)\n      return [];\n    const utwenteRoot = frontendData.utwenteRoot.endsWith(\"/\") ? frontendData.utwenteRoot.slice(0, -1) : frontendData.utwenteRoot;\n    const peopleRoot = frontendData.peopleRoot.endsWith(\"/\") ? frontendData.peopleRoot.slice(0, -1) : frontendData.peopleRoot;\n\n    const menu: Array<{ link: string; title: string; subTitle?: string }> = [];\n    if (!userInfo.isstudent && utwenteRoot)\n      menu.push({ link: `${utwenteRoot}/serviceportal`, title: getTid(\"utwente_design:utilitymenu.loginmenu.serviceportal\") });\n    if (userInfo.isemployee && peopleRoot)\n      menu.push({ link: `${peopleRoot}/editprofile`, title: getTid(\"utwente_design:utilitymenu.loginmenu.editprofile\") });\n\n    if (userInfo.studies && utwenteRoot)\n      for (let study of userInfo.studies.split(\",\")) {\n        study = study.trim();\n        menu.push({ link: `${utwenteRoot}/.utwente_base/auth/gotostudy.shtml?study=${encodeURIComponent(study)}`, title: getTid(\"utwente_design:utilitymenu.loginmenu.studywebsite\", study) });\n      }\n\n    if (userInfo.isstudent && utwenteRoot)\n      menu.push({ link: `${utwenteRoot}/students`, title: \"Student Services\" });\n\n    if (utwenteRoot) {\n      menu.push({ link: `${utwenteRoot}/mycourses`, title: userInfo.isemployee ? getTid(\"utwente_design:utilitymenu.loginmenu.mycourses\") : getTid(\"utwente_design:utilitymenu.loginmenu.mylangcourses\") });\n      menu.push({ link: dutch ? `${utwenteRoot}/mijn-eventregistraties/` : `${utwenteRoot}/en/my-event-registrations/`, title: getTid(\"utwente_design:utilitymenu.loginmenu.myevents\") });\n    }\n\n    return menu;\n  }\n\n  private handleSearchSheetMenu(q?: string) {\n    this.closeAllMenus();\n    dompack.dispatchCustomEvent(document, \"ws2026:togglesearch\", { bubbles: false, cancelable: true, detail: { q } });\n  }\n\n  private maybeOpenSearchSheetMenu(event: KeyboardEvent) {\n    // Open the search sheet menu if \"/\" was pressed outside of an editable field\n    if (!this.searchNode!.classList.contains(\"active\")) {\n      if (dompack.isHTMLElement(event.target)\n        && (event.target.isContentEditable\n          || event.target.nodeName === \"TEXTAREA\"\n          || (event.target.nodeName === \"INPUT\"\n            && ![\"checkbox\", \"radio\"].includes((event.target as HTMLInputElement).type))))\n        return;\n      if (event.key === \"/\") {\n        dompack.stop(event);\n        this.handleSearchSheetMenu();\n      }\n    }\n  }\n\n  private searchSheetVisibilityUpdated(visible: boolean) {\n    this.searchNode!.classList.toggle(\"active\", visible);\n    this.searchNode!.setAttribute(\"aria-expanded\", visible ? \"true\" : \"false\");\n    this.searchNode!.focus();\n\n    // If the search sheet is visible, make the rest of the page inert and vice versa\n    for (const selector of [\".header-menu\", \".header-dest\", \".header-breadcrumbs\", \".page-main\", \".page-footer\"]) {\n      const node = dompack.qS(selector);\n      if (node)\n        node.inert = visible;\n    }\n    const node = dompack.qS(\".searchsheet\");\n    if (node)\n      node.inert = !visible;\n  }\n}\n\ndompack.register(\".utility-menu\", node => new UtilityMenu(node));\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/utilitymenu/utilitymenu.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_design\",\"nl\",{\"utilitymenu\":{\"loginmenu\":{\"editprofile\":\"Profiel bewerken\",\"mycourses\":\"Mijn cursussen\",\"myevents\":\"Mijn eventregistraties\",\"mylangcourses\":\"Mijn (taal)cursussen\",\"serviceportal\":\"Service Portal\",\"studywebsite\":[1,\" website\"],\"utlogin\":\"UT Login\"}}});\nregisterTexts(\"utwente_design\",\"en\",{\"utilitymenu\":{\"loginmenu\":{\"editprofile\":\"Edit profile\",\"mycourses\":\"My courses\",\"myevents\":\"My event registrations\",\"mylangcourses\":\"My (language) courses\",\"serviceportal\":\"Service Portal\",\"studywebsite\":[1,\" website\"],\"utlogin\":\"UT Login\"}}});\nregisterTexts(\"utwente_design\",\"de\",{\"utilitymenu\":{\"loginmenu\":{\"editprofile\":\"Edit profile\",\"mycourses\":\"My courses\",\"myevents\":\"My event registrations\",\"mylangcourses\":\"My (language) courses\",\"serviceportal\":\"Service Portal\",\"studywebsite\":[1,\" website\"],\"utlogin\":\"UT Login\"}}});\nregisterTexts(\"utwente_design\",\"es\",{\"utilitymenu\":{\"loginmenu\":{\"editprofile\":\"Edit profile\",\"mycourses\":\"My courses\",\"myevents\":\"My event registrations\",\"mylangcourses\":\"My (language) courses\",\"serviceportal\":\"Service Portal\",\"studywebsite\":[1,\" website\"],\"utlogin\":\"UT Login\"}}});\nregisterTexts(\"utwente_design\",\"it\",{\"utilitymenu\":{\"loginmenu\":{\"editprofile\":\"Edit profile\",\"mycourses\":\"My courses\",\"myevents\":\"My event registrations\",\"mylangcourses\":\"My (language) courses\",\"serviceportal\":\"Service Portal\",\"studywebsite\":[1,\" website\"],\"utlogin\":\"UT Login\"}}});\nregisterTexts(\"utwente_design\",\"xt\",{\"utilitymenu\":{\"loginmenu\":{\"editprofile\":\"Edit profile\",\"mycourses\":\"My courses\",\"myevents\":\"My event registrations\",\"mylangcourses\":\"My (language) courses\",\"serviceportal\":\"Service Portal\",\"studywebsite\":[1,\" website\"],\"utlogin\":\"UT Login\"}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_design.20261029T162040.173Z/language/default.xml\n","import { WS2026Elements } from \"@mod-utwente_base/js/support\";\nimport \"@mod-utwente_design/utilitymenu/utilitymenu.tsx\";\nimport * as dompack from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport { getFrontendData } from \"@webhare/frontend\";\nimport { shuffle } from \"@webhare/std\";\nimport { BreadcrumbList } from \"./breadcrumbs.tsx\";\nimport { getMainMenu, getSecondaryMenu } from \"./menu.tsx\";\nimport \"../shared/skiplinks.ts\";\n\nimport \"./header.css\";\n\n// allowMissing because the frontend data is not available in widget previews\nconst elements = getFrontendData(\"utwente_design:universe\", { allowMissing: true })?.elements;\n\nclass HeaderUniverse {\n  private node: HTMLElement;\n\n  constructor(node: HTMLElement) {\n    this.node = node;\n\n    // Don't show the universe header if the 'unh' debug flag is set, or if this page is displayed within an iframe\n    //ADDME: Disable header for specific browser/platform combinations (e.g. Firefox on Android)?\n    if (!debugFlags.unh && !document.documentElement.classList.contains(\"ws2016--iframed\"))\n      this.init().catch(e => console.error(e));\n  }\n\n  async init() {\n    const element = await this.loadElement(this.node.dataset.universeElement);\n    if (element) {\n      // Insert the SVG into the node using a container\n      const svgNode = document.importNode(element.svg, true);\n      this.node.prepend(<div class=\"header-universe\"><div class=\"header-universe-container\">{svgNode}</div></div>);\n    }\n  }\n\n  async loadElement(name?: string) {\n    if (name === \"-none-\") {\n      return;\n    }\n    let element: WS2026Elements[0] | undefined = undefined;\n    if (name) {\n      // An certain element is specified\n      element = elements?.find(_ => _.filename === name);\n    }\n    if (!element && elements?.length) {\n      // Use a random element, but not the one shown previously (unless there's only one fixed element to choose from)\n      const prevElement = elements.length > 1 ? dompack.getLocal<string>(\"ucs-element\") : \"\";\n      element = shuffle(elements.filter(_ => _.filename !== prevElement) ?? [])[0];\n    }\n    if (element) {\n      // Store the current element, so it's not shown again next time\n      dompack.setLocal(\"ucs-element\", element.filename);\n\n      // Load the SVG document\n      const response = await fetch(`/.wh/mod/utwente_base/public/img/elements/${element.filename}`);\n      if (response.ok) {\n        const text = await response.text();\n        const svgDoc = new DOMParser().parseFromString(text, \"text/xml\");\n        svgDoc.documentElement.classList.add(\"header-universe-element\");\n\n        const frontendData = getFrontendData(\"utwente_design:theme\");\n        const defs: Element[] = [];\n        if (frontendData.gradientColor || frontendData.colorScheme.length === 1) {\n          // Just set the fill to the single color\n          svgDoc.documentElement.setAttribute(\"fill\", frontendData.gradientColor ?? frontendData.colorScheme[0]);\n        } else {\n          // We cannot apply a gradient fill through CSS, so we'll have to create a <radialGradient> within the SVG\n          const svgNS = svgDoc.documentElement.namespaceURI;\n          const gradient = svgDoc.createElementNS(svgNS, \"radialGradient\");\n          gradient.id = \"themeGradient\";\n          const stop1 = svgDoc.createElementNS(svgNS, \"stop\");\n          stop1.setAttribute(\"offset\", \"20%\");\n          stop1.setAttribute(\"stop-color\", \"var(--gradient-color-from)\");\n          const stop2 = svgDoc.createElementNS(svgNS, \"stop\");\n          stop2.setAttribute(\"offset\", \"100%\");\n          stop2.setAttribute(\"stop-color\", \"var(--gradient-color-to)\");\n          gradient.append(stop1, stop2);\n          defs.push(gradient);\n\n          // Apply the fill to the SVG\n          svgDoc.documentElement.setAttribute(\"fill\", `url(\"#themeGradient\")`);\n        }\n\n        // Empty the <defs> (removing the SVG styles) and add any gradient\n        svgDoc.getElementsByTagName(\"defs\")[0]!.replaceChildren(...defs);\n\n        // Store the <svg> node, so it can be imported into the document\n        return { ...element, svg: svgDoc.documentElement };\n      }\n    }\n  }\n}\n\ndompack.register(\"*[data-universe-element]\", node => new HeaderUniverse(node));\ndompack.register(\"#header-main-menu-container\", node => {\n  const lock = dompack.flagUIBusy(); // so tests can wait for ui to wait until menus are loaded\n  getMainMenu()\n    .then(menu => {\n      if (menu) {\n        node.append(menu);\n        dompack.registerMissed();\n      }\n    })\n    .catch(error => console.error(error))\n    .finally(() => lock.release());\n});\ndompack.register(\"#header-secondary-menu-container\", node => {\n  const lock = dompack.flagUIBusy(); // so tests can wait for ui to wait until menus are loaded\n  getSecondaryMenu()\n    .then(menu => {\n      if (menu) {\n        node.append(menu);\n        dompack.registerMissed();\n      }\n    })\n    .catch(error => console.error(error))\n    .finally(() => lock.release());\n});\ndompack.register(\".breadcrumbs\", node => new BreadcrumbList(node as HTMLDivElement));\n","import * as dompack from \"@webhare/dompack\";\nimport \"./breadcrumbs.css\";\n\nexport class BreadcrumbList {\n  node: HTMLDivElement;\n  itemNodes: HTMLDivElement[];\n  itemWidths: number[] = [];\n  listWidth = 0;\n  lastWidth = 0;\n  observer?: ResizeObserver;\n\n  constructor(node: HTMLDivElement) {\n    this.node = node;\n\n    // Get a list of all breadcrumbs\n    this.itemNodes = [...this.node.children] as HTMLDivElement[];\n    if (!this.itemNodes.length)\n      return;\n\n    // Watch for resizes of our node\n    this.observer = new ResizeObserver(entries => this.checkShortenBreadcrumbList(entries[0]));\n    this.observer.observe(this.node);\n\n    // Add the ellipsis (which can be clicked to show all breadcrumbs)\n    const ellipsisNode = <div class=\"breadcrumb breadcrumb--ellipsis\">&hellip;</div>;\n    this.node.firstElementChild!.after(ellipsisNode);\n    ellipsisNode.addEventListener(\"click\", () => this.unshortenBreadcrumbList());\n  }\n\n  checkShortenBreadcrumbList(entry: ResizeObserverEntry) {\n    // Use requestAnimationFrame to prevent 'undelivered notifications' messages from the ResizeObserver when we update\n    // the size of our node (which it observes) when hiding breadcrumbs\n    // See https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors\n    requestAnimationFrame(() => {\n      let width = entry.borderBoxSize[0].inlineSize;\n      if (!width || width === this.lastWidth)\n        return; // Not visible\n      this.lastWidth = width;\n\n      // Calculate item sizes\n      if (!this.listWidth) {\n        this.node.classList.add(\"breadcrumbs--measure\");\n        if (this.node.clientWidth) { // Force CSS update, check if visible\n          // Iterate over all child nodes, including the ellipsis node\n          for (const childNode of this.node.children) {\n            const itemWidth = Math.ceil(childNode.getBoundingClientRect().width);\n            this.itemWidths.push(itemWidth);\n            // For the width to check, only consider the breadcrumbs, the ellipsis doesn't have to fit\n            if (!childNode.classList.contains(\"breadcrumb--ellipsis\"))\n              this.listWidth += itemWidth;\n          }\n        }\n        this.node.classList.remove(\"breadcrumbs--measure\");\n      }\n\n      // Calculate the list's content width\n      const styles = getComputedStyle(this.node);\n      width = Math.floor(width - parseFloat(styles.paddingLeft) - parseFloat(styles.paddingRight));\n      // We must shorten if there's not enough room for all breadcrumbs\n      const shorten = width < this.listWidth;\n      this.node.classList.toggle(\"breadcrumbs--shorten\", shorten);\n      if (shorten) {\n        // From right to left, hide the breadcrumb if there's not enough room for it\n        let itemsWidth = this.itemWidths[0] + this.itemWidths[1]; // home and ellipsis widths\n        for (let item = this.itemNodes.length; item >= 2; --item) {\n          itemsWidth += this.itemWidths[item];\n          // We want to show at least the last (current) item\n          this.itemNodes[item - 1].classList.toggle(\"breadcrumb--hide\", itemsWidth > width && item !== this.itemNodes.length);\n        }\n      }\n    });\n  }\n\n  unshortenBreadcrumbList() {\n    // Once unshortened, the breadcrumb list won't be shortened again, so we no longer have to observe node resizes\n    this.observer!.disconnect();\n    this.node.classList.remove(\"breadcrumbs--shorten\");\n  }\n}\n","import * as dompack from \"@webhare/dompack\";\nimport { getTid } from \"@webhare/gettid\";\nimport { MenuHandler } from \"@mod-utwente_design/js/ut-menu\";\nimport type { MainMenu, SecondaryMenu } from \"../render/ws2026.litty\";\nimport { getCompactMenuBreakpoint } from \"../shared/layout-tools\";\n\nimport \"./menu.css\";\n\n//NOTE: It seems that sometimes not all css is loaded when this constant is used, so we cannot read this value from css using\n//      getComputedStyle().getPropertyValue()\nconst MAX_PAGE_WIDTH = 1350; // Keep in sync with --max-page-width in ws2026.css!\n\nexport type MenuData = {\n  mainMenu: MainMenu;\n  secondaryMenu?: { title?: SecondaryMenu[0]; menu: SecondaryMenu };\n  siteRoot?: string;\n  width?: number;\n};\n\nlet menuPromise: Promise<MenuData | null> | null = null;\n\nasync function getMenusForFolder(): Promise<MenuData | null> {\n  // The publisher preview sets the pageUrl dataset property\n  const url = new URL(\"utwente-navigation.rpc\", document.documentElement.dataset.pageUrl ?? location.href);\n  url.searchParams.set(\"what\", \"menu\");\n  const res = await fetch(url);\n  if (res.ok)\n    return await res.json().catch(() => null) as MenuData | null;\n  return null;\n}\n\nfunction itemClassName(classNames: string[], item: { isCurrent?: boolean; items?: Array<unknown> }) {\n  if (item.isCurrent)\n    classNames.push(\"current\");\n  if (item.items?.length)\n    classNames.push(\"subitems\");\n  return classNames.join(\" \");\n}\n\nfunction renderBanner(data: MainMenu[0][\"banner\"]) {\n  if (!data)\n    return;\n  const banner: HTMLDivElement = <div class=\"menu-banner\">\n    {data.imageSrcSet && <img srcset={data.imageSrcSet.map(_ => `${_.link} ${_.descriptor}`).join(\", \")} alt={data.imageAlt} />}\n    <div class=\"banner-title\">{data.title}</div>\n  </div>;\n  if (data.content) {\n    const content = <span />;\n    content.innerHTML = data.content;\n    banner.append(...content.childNodes);\n  }\n  return banner;\n}\n\nfunction createMenu(data: MainMenu | SecondaryMenu, options?: { hasTitle?: boolean; homeLink?: string }) {\n  const homeLinkCount = options?.homeLink !== undefined ? 1 : 0;\n  return (\n    <ul class=\"menubar\" aria-role=\"menubar\" data-menu-title={homeLinkCount ? getTid(\"utwente_base:frontend.ws2026.js.header.menu-home\") : null} style={`--menu-item-count: ${(data.length + homeLinkCount)};`}>\n      {homeLinkCount ? <li class=\"menu-item home\" style=\"--menu-item-idx: 0;\">{options!.homeLink ? <a class=\"item-title\" href={options!.homeLink}>{getTid(\"utwente_base:frontend.ws2026.js.header.menu-home\")}</a> : <div class=\"item-title\">{getTid(\"utwente_base:frontend.ws2026.js.header.menu-home\")}</div>}</li> : null}\n      {data.map((item, itemIdx) => <li class={itemClassName([\"menu-item\"].concat(options?.hasTitle && !itemIdx ? [\"title\"] : []), item)} style={`--menu-item-idx: ${itemIdx + homeLinkCount};`} aria-role=\"menuitem\" aria-haspopup={item.items?.length || (\"banner\" in item && item.banner) ? \"menu\" : null}>\n        {item.items?.length || (\"banner\" in item && item.banner) ? <><div class=\"item-title\" tabindex=\"0\"><span data-title={item.title}>{item.title}</span></div><div class=\"menu-foldout\" style={item.items?.length ? `--menu-item-count: ${item.items.length};` : \"\"}>\n          {item.items?.length && <ul class=\"submenu\" arial-role=\"menu\" data-menu-title={item.title}>\n            {item.items.map((subItem, subItemIdx) => <li class={itemClassName([\"submenu-item\"], subItem)} style={`--submenu-item-idx: ${subItemIdx};`} aria-role=\"menuitem\" aria-haspopup={\"items\" in subItem && subItem.items?.length ? \"menu\" : null} aria-expanded={\"items\" in subItem && subItem.items?.length ? \"false\" : null}>\n              {\"items\" in subItem && subItem.items?.length ? <><div class=\"item-title\" tabindex=\"0\"><span>{subItem.title}</span></div><ul class=\"subsubmenu\" aria-role=\"menu\" data-menu-title={subItem.title}>\n                {subItem.items.map(subSubItem => <li class={itemClassName([\"subsubmenu-item\"], subSubItem)} aria-role=\"menuitem\">\n                  {subSubItem.link ? <a class=\"item-title\" href={subSubItem.link}>{subSubItem.title}</a> : <div class=\"item-title\">{subSubItem.title}</div>}\n                </li>)}\n              </ul></> : subItem.link && <a class=\"item-title\" href={subItem.link}>{subItem.title}</a>}\n            </li>)}\n          </ul>}\n          {\"banner\" in item && renderBanner(item.banner)}\n        </div></> : item.link ? <a href={item.link} class=\"item-title\">{item.title}</a> : <div class=\"item-title\">{item.title}</div>}\n      </li>)}\n    </ul>);\n}\n\nfunction createSecondaryMenu(data: MenuData[\"secondaryMenu\"]) {\n  return data && <>\n    {data.title ? (data.title.link ? <a href={data.title.link} class={itemClassName([\"title-item\"], data.title)} aria-haspopup=\"menu\">{data.title.title}</a> : <div class={itemClassName([\"title-item\"], data.title)}>{data.title.title}</div>) : <></>}\n    {createMenu(data.menu, { hasTitle: Boolean(data.title) })}\n  </>;\n}\n\nexport async function getMainMenu() {\n  menuPromise ||= getMenusForFolder();\n  const menus = await menuPromise;\n  if (menus)\n    return createMenu(menus.mainMenu, { homeLink: menus.siteRoot ?? \"\" });\n}\n\nexport async function getSecondaryMenu() {\n  menuPromise ||= getMenusForFolder();\n  const menus = await menuPromise;\n  if (menus?.secondaryMenu)\n    return createSecondaryMenu(menus.secondaryMenu);\n}\n\nfunction getMenuWidth() {\n  const mainLeft = document.querySelector(\".header-menu .menubar > li:not(.home)\")?.getBoundingClientRect().left ?? 0;\n  const mainRight = document.querySelector(\".header-menu .menubar > li:last-of-type\")?.getBoundingClientRect().right ?? 0;\n  const secondaryLeft = document.querySelector(\".header-dest .title-item, .header-dest .menubar > li\")?.getBoundingClientRect().left ?? 0;\n  const secondaryRight = document.querySelector(\".header-dest .menubar > li:last-of-type\")?.getBoundingClientRect().right ?? 0;\n  if (secondaryLeft && secondaryRight)\n    return Math.max(mainRight - mainLeft, secondaryRight - secondaryLeft);\n  return mainRight - mainLeft;\n}\n\nlet mobileMenus = 0;\n\nclass MobileMenuHandler extends MenuHandler {\n  private navNode?: HTMLElement | null;\n  private toggleNode?: HTMLElement | null;\n  private backLinkNode?: HTMLElement | null;\n  private firstMenuItem?: HTMLElement | null;\n\n  constructor(node: HTMLElement) {\n    super(node.closest(\".menu-mobile\") || node, { scrollNode: node });\n    // The toggle node is the hamburger menu checkbox for the main menu and the title item for the secondary menu\n    this.navNode = node.closest(\"nav\");\n    this.toggleNode = this.navNode?.querySelector<HTMLElement>(\".menu-open, .title-item\");\n    this.backLinkNode = this.navNode?.querySelector<HTMLElement>(\".menu-back\");\n    this.menuNode.addEventListener(\"transitionend\", () => this.maybeCloseAllMenus());\n\n    if (this.toggleNode) {\n      this.firstMenuItem = this.menuNode.querySelector<HTMLElement>(this.menuItemSelector);\n      if (this.firstMenuItem) {\n        if (\"checked\" in this.toggleNode) {\n          dompack.addDocEventListener(this.toggleNode, \"change\", () => {\n            // When opening the menu, focus the mobile menu if there isn't a 'current' item\n            if (!this.openCurrentSubitem())\n              this.firstMenuItem!.focus();\n            // The (sub)menus are closed after the close transition ends\n          });\n        } else {\n          dompack.addDocEventListener(this.toggleNode, \"click\", event => {\n            if (this.horizontal)\n              return;\n\n            // this is the secondary menu title\n            this.toggleSecondaryMenu();\n            dompack.stop(event);\n          });\n        }\n        dompack.addDocEventListener(this.toggleNode, \"keydown\", event => this.onKeyDown(event));\n        if (this.backLinkNode)\n          dompack.addDocEventListener(this.backLinkNode, \"click\", event => this.levelUp(event));\n      }\n      if (this.backLinkNode)\n        new MutationObserver((mutations: MutationRecord[]) => this.onClassChange(mutations)).observe(node, {\n          attributeFilter: [\"class\"], // we're only interested in the 'opened' class being added/removed\n          attributeOldValue: true, // to see if 'opened' was removed\n          subtree: true,\n        });\n    }\n\n    if (document.documentElement.classList.contains(\"compactmenu--fixed\")) {\n      // Fixed compact menu: never show the horizontal menu\n      this.updateMobile(true);\n    } else {\n      // If the menu is wider than the maximum page width, switch to mobile unconditionally, otherwise switch to the mobile\n      // menu if the screen gets too small\n      const menuWidth = getMenuWidth();\n      if (menuWidth > MAX_PAGE_WIDTH)\n        this.updateMobile(true);\n      else {\n        const mq = matchMedia(`screen and (width <= ${getCompactMenuBreakpoint(menuWidth)}px)`);\n        mq.addEventListener(\"change\", (event) => this.onMediaQueryChange(event));\n        this.onMediaQueryChange(mq);\n      }\n    }\n  }\n\n  private toggleSecondaryMenu(toggle?: boolean) {\n    if (!this.toggleNode)\n      return;\n    if (this.toggleNode.classList.toggle(\"opened\", toggle))\n      this.openCurrentSubitem();\n    else if (toggle !== false)\n      this.closeAllMenus();\n    const opened = this.toggleNode.classList.contains(\"opened\");\n    this.toggleNode.setAttribute(\"aria-expanded\", opened ? \"true\" : \"false\");\n    this.menuActive = opened || this.menuNode.querySelectorAll(\".opened\").length > 0;\n    return opened;\n  }\n\n  private openCurrentSubitem() {\n    // Open the deepest 'current' menu item (i.e. open all 'current' items with subitems)\n    const currentItems = this.menuNode.querySelectorAll(\".current\");\n    for (const item of currentItems) {\n      if (item.classList.contains(\"subitems\")) {\n        item.classList.toggle(\"opened\", true);\n        if (item.ariaHasPopup === \"menu\")\n          item.setAttribute(\"aria-expanded\", item.classList.contains(\"opened\") ? \"true\" : \"false\");\n      } else // this is the current item, focus it\n        item.querySelector<HTMLElement>(this.menuItemSelector)?.focus();\n    }\n    return currentItems.length > 0;\n  }\n\n  private onMediaQueryChange(mq_event: MediaQueryList | MediaQueryListEvent) {\n    this.updateMobile(mq_event.matches);\n  }\n\n  private updateMobile(mobile: boolean) {\n    if (this.navNode && this.navNode.classList.contains(\"compactmenu\") !== mobile) {\n      document.documentElement.classList.remove(\"compactmenu--transition\");\n      if (this.navNode.classList.toggle(\"compactmenu\", mobile))\n        ++mobileMenus;\n      else\n        --mobileMenus;\n      // Apply the slide in/out transition after a timeout, so it won't transition when switching to compact menu\n      if (mobileMenus)\n        setTimeout(() => document.documentElement.classList.add(\"compactmenu--transition\"), 100);\n    }\n\n    if (mobile === this.horizontal) {\n      this.horizontal = !mobile;\n\n      // When switching modes, close the mobile menu\n      if (this.toggleNode) {\n        if (\"checked\" in this.toggleNode)\n          this.toggleNode.checked = false;\n        else\n          this.toggleNode.tabIndex = this.horizontal ? -1 : 0;\n      }\n    }\n  }\n\n  protected onMouseDown(event: dompack.DocEvent<MouseEvent>) {\n    // Only use the toggle node to open the mobile menu or toggle the secondary menu\n    if (this.toggleNode?.contains(event.target)&& (!(\"checked\" in this.toggleNode) || this.toggleNode.checked))\n      return;\n    super.onMouseDown(event);\n  }\n\n  protected onClick(event: dompack.DocEvent<MouseEvent>) {\n    if (this.toggleNode?.contains(event.target) && !this.horizontal) {\n      event.preventDefault(); // Don't follow the link if this is the menu opener\n    } else if (event.target.closest(\".menu-banner\"))\n      return; // Don't steal clicks from menu banner links\n    super.onClick(event);\n  }\n\n  protected onKeyDown(event: dompack.DocEvent<KeyboardEvent>) {\n    // If this is a main menu item, esc closes the mobile menu\n    if (this.toggleNode && !this.horizontal && event.key === \"Escape\") {\n      const curItem = event.target.closest(\"[aria-role=menuitem]\");\n      if (curItem && !curItem.parentElement!.closest(\"[aria-role=menuitem]\")) {\n        if (\"checked\" in this.toggleNode)\n          this.toggleNode.checked = false;\n        else\n          this.closeAllMenus();\n        this.toggleNode.focus(); // Bring focus back to the toggle\n        dompack.stop(event);\n        return;\n      }\n    }\n    if (this.toggleNode?.isSameNode(event.target)) {\n      // If the user presses \"Enter\" on the menu open button, open the mobile menu (space is already handled by the browser)\n      if (event.key === \"Enter\")\n        if (\"checked\" in this.toggleNode)\n          this.toggleNode.click(); // this is the menu hamburger\n        else {\n          // this is the secondary menu title\n          if (this.toggleSecondaryMenu()) {\n            if (!this.openCurrentSubitem() && this.firstMenuItem)\n              this.firstMenuItem.focus();\n          }\n          dompack.stop(event);\n        }\n      // If the user presses \"Esc\" on the menu open button, remove its focus (the mobile menu is already closed)\n      if (event.key === \"Escape\")\n        this.toggleNode.blur();\n      return;\n    }\n    if (event.target.closest(\".menu-close\")) {\n      // If the user presses \"Enter\" or \"Space\" on the menu close button, close the mobile menu\n      if ([\"Enter\", \" \"].includes(event.key)) {\n        this.toggleNode!.click();\n        this.toggleNode!.focus(); // Bring focus back to the toggle\n        dompack.stop(event);\n      }\n      return;\n    }\n    if (event.target.closest(\".menu-back\")) {\n      this.levelUp(event);\n      return;\n    }\n    super.onKeyDown(event);\n  }\n\n  protected onClassChange(mutations: MutationRecord[]) {\n    let menu: HTMLElement | null | undefined = undefined;\n    for (const mutation of mutations) {\n      const oldClass = new Set(mutation.oldValue?.split(\" \") ?? []);\n      const newClass = new Set((mutation.target as HTMLElement).classList.values());\n      const parent = (mutation.target as HTMLElement).closest<HTMLElement>(\"ul\");\n      if (!oldClass.has(\"opened\") && newClass.has(\"opened\")) {\n        // This item's menu was opened, show the title of this item's parent menu\n        menu = parent;\n        // On desktop, if we're opening a main menu that has a 'current' subitem with sub-subitems, automatically open the subitem\n        if (this.horizontal && (mutation.target as HTMLElement).classList.contains(\"menu-item\")) {\n          const currentSubmenu = (mutation.target as HTMLElement).querySelector(\".subitems.current\");\n          if (currentSubmenu)\n            currentSubmenu.classList.add(\"opened\");\n        }\n      } else if (oldClass.has(\"opened\") && !newClass.has(\"opened\")) {\n        // This item's menu was closed, show the title of this item's parent's parent menu\n        menu = (parent?.parentElement as HTMLElement)?.closest<HTMLElement>(\"ul\");\n      }\n    }\n    this.backLinkNode!.hidden = !menu;\n    if (menu === undefined)\n      return;\n\n    this.backLinkNode!.textContent = menu?.dataset.menuTitle ?? \"\";\n    this.backLinkNode!.tabIndex = this.backLinkNode!.textContent ? 0 : -1;\n  }\n\n  protected levelUp(event: dompack.DocEvent<MouseEvent | KeyboardEvent>) {\n    const lastOpened = [...this.menuNode.querySelectorAll<HTMLElement>(\".opened\")].at(-1);\n    if (lastOpened) {\n      dompack.stop(event);\n      this.toggleMenu(lastOpened, false);\n      if (\"key\" in event)\n        lastOpened.querySelector<HTMLElement>(this.menuItemSelector)?.focus();\n    }\n  }\n\n  maybeCloseAllMenus() {\n    // If the mobile menu was closed (this function is called at the transition end of the mobile menu), close any currently\n    // opened submenu\n    if (!this.horizontal && this.toggleNode && \"checked\" in this.toggleNode && !this.toggleNode.checked)\n      this.closeAllMenus();\n  }\n\n  closeAllMenus() {\n    super.closeAllMenus();\n    this.toggleSecondaryMenu(false);\n  }\n}\n\ndompack.register(\".menubar\", node => new MobileMenuHandler(node));\n","import * as dompack from \"@webhare/dompack\";\n\n\nexport function getCompactMenuBreakpoint(menuWidth: number) {\n  // Below 750px the compact menu is shown anyway, above 750px the page margin is at least 90px\n  if ((menuWidth + 90) > 750) {\n    // Add the page margin based on the responsive state for this width\n    if ((menuWidth + 90) <= 1080)\n      menuWidth += 90;\n    else\n      menuWidth += 110;\n    // We want to know when the menu no longer fits, subtract one pixel\n    --menuWidth;\n  }\n  return Math.max(Math.ceil(menuWidth), 750);\n}\n\n/*\n  In a CSS grid layout, floating elements don't escape their grid line, which in effect causes each paragraph to clear any\n  floating elements. If an empty paragraph contains a floating image, the image is displayed on its own, without the text of\n  the next paragraph floating around it. To get around this limitation, we'll wrap consecutive paragraphs into one node, so\n  images can float within that node, which gets aligned to the CSS grid.\n\n  Containers:\n  - .page-content (main content of page)\n  - .wh-form__richtext (richtext field in form page)\n*/\nexport function combineFloatParagraphs() {\n  // Process the main content node and any node that opts\n  for (const container of dompack.qSA(\".page-content, .wh-form__richtext\")) {\n    // Skip this container if it doesn't have children containing floating images\n    if (!dompack.qS(container, \":scope > p > img.wh-rtd__img--floatleft, :scope > p > img.wh-rtd__img--floatright\"))\n      continue;\n\n    let child = container.firstElementChild as HTMLElement | null;\n    let wrapper = null;\n    while (child) {\n      // Keep a reference to the next child node, as we might move the current child to another parent (wrapper) or remove it (if empty after moving the image)\n      const nextChild = child.nextElementSibling as HTMLElement | null;\n      if (child.nodeName === \"P\" ) {\n        // If this is a paragraph with a floating image, or if we already have paragraphs to combine, add it to wrapper\n        // We only check for first floating image!\n        const floatingImg = dompack.qS(child, \":scope > img.wh-rtd__img--floatleft, :scope > img.wh-rtd__img--floatright\");\n        if (floatingImg) {\n          wrapper = <section class=\"ut-floatwrapper\" />;\n          child.before(wrapper);\n          wrapper.append(floatingImg);\n          if( child.childNodes.length === 0 )\n            child.remove();\n          else\n            wrapper.append(child);\n        } else if (wrapper) {\n          wrapper.append(child);\n        }\n      } else {\n        wrapper = null;\n      }\n\n      child = nextChild;\n    }\n  }\n}\n\n\n/** @short Get the value of a CSS variable\n    @long If the DOM is not fully loaded and the CSS is not fully applied, CSS variables may not have been fully computed.\n        This function returns a promise that resolves with the value of the requested CSS variable once it's available. It\n        rejects after a timeout, if set through the options. This function checks if the value is set (getPropertyValue\n        returns an empty string for unknown variables), so it can only be used for variables that eventually will be set to a\n        non-empty value.\n    @param property The CSS variable (custom property) to read\n    @param options.element The element to query, defaults to document.documentElement\n    @param options.timeout The timeout in ms, defaults to 10000, set to 0 to disable timeout and return only after the\n        variable has received a non-empty (and keep running in the background!)\n*/\nexport function getCSSVariable(property: string, options?: { element?: HTMLElement; timeout?: number }) {\n  if( !options )\n    options = {};\n\n  options = {\n    element: document.documentElement,\n    timeout: 10000,\n    ...options\n  };\n\n  return new Promise((resolve, reject) => {\n    // Local state\n    const data : { timeout: number | ReturnType<typeof setTimeout>; property: string; element: HTMLElement; resolve: (value: string) => void } = {\n      timeout: -1, // Signal to timeout has been set\n      property,\n      element: options.element as HTMLElement,\n      resolve\n    };\n\n    // Set a timeout if requested\n    if (options.timeout! > 0)\n      data.timeout = setTimeout(() => {\n        // Clear the timeout value, to signal a timeout to the checkCSSVariable function\n        data.timeout = 0;\n        reject(new Error(`Timeout after ${options.timeout}ms reading CSS variable '${property}'`));\n      }, options.timeout);\n    // Check if the CSS variable is set\n    checkCSSVariable(data);\n  });\n}\n\nfunction checkCSSVariable(data: { timeout: number | ReturnType<typeof setTimeout>; property: string; element: HTMLElement; resolve: (value: string) => void }) {\n  // If the request has timed out (i.e. the variable didn't receive a value within the given time), we're done\n  if (data.timeout === 0)\n    return;\n  // Get the CSS variable value\n  const value = getComputedStyle(data.element).getPropertyValue(data.property);\n  if (value) {\n    // Clear the timeout\n    clearTimeout(data.timeout);\n    // Return the value\n    data.resolve(value);\n    return;\n  }\n  // Check again in the next animation frame\n  requestAnimationFrame(() => checkCSSVariable(data));\n}\n\nexport function setCSSVariable(property: string, value: string, options?: { element?: HTMLElement }) {\n  if( !options )\n    options = {};\n\n  options = {\n    element: document.documentElement,\n    ...options\n  };\n\n  options.element!.style.setProperty(property, value);\n}\n","import * as dompack from \"@webhare/dompack\";\nimport \"./skiplinks.css\";\n\n/*FIXME: This is a direct port of the WS2016 code, adapt for proper use in WS2026 (mainly the code that determines the\n         relevant content node to scroll to) */\n\n// distance we want to keep to the sticky navigationbar when scrolling to an element\nconst toNavBarDistance = 60;\nlet temporaryFocusedNode: HTMLElement | null = null;\nlet temporaryScrolledToNode: HTMLElement | null = null;\n\n\ndompack.onDomReady(init);\n\nwindow.addEventListener(\"focusout\", checkLeavingTemporaryFocusableElement);\n\n\nfunction checkLeavingTemporaryFocusableElement() {\n  if (temporaryFocusedNode) {\n    // FIXME: check if it's the <header> or <main> in case we ever use an element which actually\n    //        is allowed to have focus and has a tabindex attribute ?\n\n    // We only want this element focusable through the skiplinks button,\n    // so remove it to prevent it being focused again through a mouse or touch interaction.\n    temporaryFocusedNode.removeAttribute(\"tabindex\");\n\n    if (temporaryScrolledToNode)\n      temporaryScrolledToNode.style.scrollMarginTop = \"\";\n    temporaryFocusedNode = null;\n  }\n}\n\n\nfunction init() {\n  const button = document.querySelector(\".skiplinksbutton\");\n  if (button) // NOTE: for widget previews we don't render the skiplinks button\n    button.addEventListener(\"click\", doSkipLinks);\n}\n\nfunction doSkipLinks(event: Event) {\n  event.preventDefault();\n\n  const main = document.querySelector(\"main\");\n  const header = document.querySelector<HTMLElement>(\".contentpart__header\");\n  let nodeHeaderMessagesArea = document.querySelector<HTMLElement>(\".contentpart__header-messagesarea\"); // (also contains .utwente-cookiebar)\n  const nodeHeaderCTA = document.querySelector<HTMLElement>(\".headercta\");\n  const nodeTitleContainerBG = document.querySelector<HTMLElement>(\".contentpart__title-background\"); // used on F&F\n  const nodeTitleContainer = document.querySelector<HTMLElement>(\".contentpart__title-container\");\n\n  // Ignore the headermessagesarea if it's currently empty\n  // (it can also contain a managedcta which isn't shown, so instead of\n  // checking the nodes within we check the size of the visible content)\n  if (nodeHeaderMessagesArea && nodeHeaderMessagesArea.clientHeight === 0)\n    nodeHeaderMessagesArea = null;\n\n  /*\n  By focussing the header we ensure:\n  - a screenreader may start to read there (reading the CTA and title)\n  - tab navigation also be able to go through the header elements (such as CYA)\n\n  Suggestions for possible improvements:\n  - ADDME: research whether we would want to also skip header slideshow links\n  - ADDME: .contentpart__title uses the full height of the header meant for text,\n           so we cannot scroll to the visible title. So we don't scroll as far as we want.\n  */\n\n\n  // We need to scroll to the first relevant content.\n  // Hopefully at least enough to signal to the user that the skip action has been performanced (feedback).\n  const scrollToNodeInHeader = nodeHeaderMessagesArea ?? nodeHeaderCTA ?? nodeTitleContainerBG ?? nodeTitleContainer;\n  let focusNode = header;\n  let scrollToNode = null;\n\n  if (scrollToNodeInHeader) { // no textual content in this header? then focus the main\n    focusNode = header; // focus on the whole header\n    scrollToNode = scrollToNodeInHeader; // but scroll to the specific part in the header where there's text (so it looks like something happens when clicking the button)\n  } else {\n    scrollToNode = main;\n    focusNode = main;\n  }\n\n  // the <header> and <main> by default don't have a tabindex.\n  // We want them to only receive focus from the skiplinks features,\n  // we don't want them to recieve focus by either keyboard or mouse interaction.\n  if (focusNode && !focusNode.hasAttribute(\"tabindex\"))\n    focusNode.setAttribute(\"tabindex\", \"-1\"); // temporary grant ability to focus (on focusout event whe'll remove it)\n\n  console.log(\"Set focus to\", focusNode);\n  console.log(\"Scroll to\", scrollToNode);\n\n\n  try {\n    // prevent focus jumping directly (without smooth scroll) to the node (and then our scrollTo causing a bit upwards again)\n    focusNode?.focus({ preventScroll: true });\n  } catch (err) {\n    focusNode?.focus(); // Safari & iOS < 15.5 (may 2022)\n  }\n\n  temporaryFocusedNode = focusNode;\n  temporaryScrolledToNode = scrollToNode;\n\n\n\n  // If the navigationbar is sticky compensate for the part of the viewport (at the top) which is blocked\n  const navContainer = document.querySelector<HTMLElement>(\".contentpart__navbar-container\");\n  const navPosition = navContainer ? getComputedStyle(navContainer).getPropertyValue(\"--navbar-position\").trim() : \"\";\n\n  let obscuredareaheight = 0;\n  if (navPosition === \"sticky\")\n    obscuredareaheight = navContainer!.clientHeight;\n\n  //console.log(navcontainer, navposition, obscuredareaheight);\n\n  if (scrollToNode) {\n    scrollToNode.style.scrollMarginTop = (obscuredareaheight + toNavBarDistance) + \"px\";\n    scrollToNode.scrollIntoView({ behavior: \"smooth\" });\n  }\n}\n","import \"./footer.css\";\nimport * as dompack from \"@webhare/dompack\";\n\n/*\n  foldable footer sections mobile\n*/\ndompack.register(\".page-footer__foldtitle\", node => {\n  node.addEventListener(\"click\", () => node.classList.toggle(\"page-footer__foldtitle--open\"));\n});\n","/* eslint-disable @typescript-eslint/no-explicit-any -- we have no types for the PSA and its loader classes */\n\n/* Due to load ordering issues (https://gitlab.webhare.com/utwente/utwente_base/-/issues/2728#note_242336) and the fact that this code\n   rarely changes, we're integrating it directly into JS and taking a careful approach to executing the sync HTML steps it would originally take\n\n   This is the code that was used to load the PSA widget\n\nThis was the original widget code.\n<link href=\"/repository/utwente-data/psa/css/chat.css\" rel=\"stylesheet\" type=\"text/css\"/>\n<div id=\"container\">\n  <!-- The PSA's GUI controls go here -->\n</div>\n\n<script src=\"/repository/utwente-data/psa/build/autocomplete.js\" type=\"text/javascript\"></script>\n<script src=\"/repository/utwente-data/psa/build/require.js\" type=\"text/javascript\"></script>\n<script>\nrequire.config({baseUrl:\"/repository/utwente-data/psa/build\",paths:{App:\"build/app\"}}),require([\"app\"],function(i){psa=new i.ApplicationAssistant,psa.init()}),requirejs([\"autocomplete\"],function(i){});\n</script>\n\n<div class=\"embeddedobject inlinecta \" id=\"inlinebutton\"><div class=\"inlinecta__content\"><div class=\"inlinecta__title \"></div><a class=\"inlinecta__button \" href=\"#\" onclick=\"psa.showChat(true); return false;\">Okay, let's start!</a><div class=\"inlinecta__description\"></div></div></div>\n*/\n\nimport { loadCSS, loadScript, onDomReady, register } from \"@webhare/dompack\";\n\nregister(\".js-psa-chatbot\", (node: HTMLElement) => {\n  //PSA Chatbot 'Sam' initializing. Load the CSS right away\n  const cssPromise = loadCSS(\"/repository/utwente-data/psa/css/chat.css\");\n  //But delay script loads until the DOM is ready and (by extension) all ws2016 code has parsed\n  const psaPromise: Promise<any> = (async () => {\n    await new Promise<void>(r => onDomReady(r));\n    await loadScript(\"/repository/utwente-data/psa/build/autocomplete.js\"); //we load them one-by-one, as they were originall edsigned to\n    await loadScript(\"/repository/utwente-data/psa/build/require.js\");\n    await cssPromise;\n\n    /* require.config({\n          baseUrl: \"/repository/utwente-data/psa/build\",\n          paths:{App:\"build/app\"}\n          });\n        require([\"app\"],function(i) {\n          psa=new i.ApplicationAssistant;\n          psa.init()\n        });\n      requirejs([\"autocomplete\"],function(i){});\n      */\n\n    //So first we 'require.config' the loader\n    //And then we launch both app and autocomplete, apparently they accept a callback, so we can just use promises for those\n\n    const req: any = globalThis.require;\n    req.config({\n      baseUrl: \"/repository/utwente-data/psa/build\",\n      paths: { App: \"build/app\" }\n    });\n\n    const loadApp = await new Promise<any>(resolve => req([\"app\"], (i: any) => resolve(i)));\n    await new Promise<any>(resolve => req([\"autocomplete\"], (i: any) => resolve(i)));\n    const psa = new loadApp.ApplicationAssistant;\n    psa.init();\n    return psa;\n  })();\n\n  node.addEventListener(\"click\", (e) => {\n    e.preventDefault();\n    void psaPromise.then(psa => psa.showChat(true));\n  });\n});\n","import * as dompack from \"@webhare/dompack\";\nimport \"./overflow-placeholder.css\";\n\n/*\n * Automatically replace the contents of a single-line element if it doesn't fit with the specified placeholder\n *\n * Usage:\n * Set the data-overflow-placeholder to the text you want to show if the contents doesn't fit and give the element a maximum\n * width, e.g.\n *\n *   <a href=\"mailto:user@example.org\" data-overflow-placeholder=\"Email\" style=\"max-width: 100px;\">user@example.org</a>\n *\n * Note that this only works if the element doesn't have to be transparent to show an underlying background image. The way\n * this works is that the text content is placed over the placeholder and wraps to the next line if it doesn't fit, revealing\n * the placeholder. By default, the text content is rendered with a white background, but this can be overridden using the\n * data-overflow-background attribute, e.g.\n *\n *   <a href=\"mailto:user@example.org\" data-overflow-placeholder=\"Email\" data-overflow-background=\"var(--color-black)\" style=\"max-width: 100px;\">user@example.org</a>\n */\ndompack.register(\"[data-overflow-placeholder]\", node => {\n  node.replaceChildren(\n    <span class=\"op-placeholder\" aria-hidden=\"true\">{node.dataset.overflowPlaceholder}</span>,\n    <span class=\"op-spacer\" aria-hidden=\"true\">&nbsp;</span>,\n    <span class=\"op-value\" style={`background-color: ${node.dataset.overflowBackground || \"white\"};`}>{node.textContent}</span>);\n});\n","/* eslint-disable @typescript-eslint/no-floating-promises -- FIXME: needs API rework */\n\nimport * as dompack from '@webhare/dompack';\nimport * as focus from 'dompack/browserfix/focus';\nimport * as merge from './internal/merge';\nimport FormBase, { type FormResultValue, type FormSubmitEmbeddedResult, type FormSubmitMessage, type FormSubmitResult } from './formbase';\nimport { getFormService, getTSFormService, type PublisherFormService } from \"@webhare/forms/src/formservice\";\nimport * as emailvalidation from './internal/emailvalidation';\nimport { runMessageBox } from 'dompack/api/dialog';\nimport { debugFlags, isLive, navigateTo, type NavigateInstruction } from \"@webhare/env\";\nimport { isBlob, pick } from '@webhare/std';\nimport { setFieldError } from './internal/customvalidation';\nimport type { RPCFormTarget, RPCFormInvokeBase, RPCFormSubmission } from '@webhare/forms/src/types';\nimport { SingleFileUploader, type UploadResult } from '@webhare/upload';\nimport { createClient } from '@webhare/jsonrpc-client';\nimport { setupCaptchaFieldGroup } from './fields/captchafield';\nimport { getFormConfiguration } from '@webhare/forms/src/registration';\nimport type { CaptchaProvider } from '../captcha/api';\n\nfunction unpackObject(formvalue: FormResultValue): RPCFormInvokeBase[\"vals\"] {\n  return Object.entries(formvalue).map(_ => ({ name: _[0], value: _[1] }));\n}\n\nexport interface FormSubmitDetails<DataShape extends object = Record<string, unknown>> {\n  form: HTMLElement;\n  rpchandler: RPCFormBase<DataShape>;\n  extrasubmitdata?: unknown;\n  submitted: FormResultValue;\n  result: unknown;\n  errors: FormSubmitMessage[];\n}\n\ntype UploadCache = WeakMap<Blob, UploadResult>;\n\nfunction buildTarget(target: string): RPCFormTarget {\n  return { target, url: location.href.split('/').slice(3).join('/') };\n}\n\nclass FormSubmitter {\n  private readonly target;\n  private readonly cache: UploadCache;\n  private readonly offline: boolean;\n\n  constructor(target: string, cache: UploadCache | null, offline: boolean) {\n    this.target = buildTarget(target);\n    this.cache = cache || new WeakMap();\n    this.offline = offline;\n  }\n\n  private async uploadFile(file: Blob) {\n    if (this.offline)\n      throw new Error(\"Cannot upload files in offline mode\"); //TODO convert to dataurl and test it\n\n    //TODO what if the server discarded the token? we should negotiate with the server which files it (still) wants\n    const completed = this.cache.get(file);\n    if (completed)\n      return completed;\n\n    const uploader = new SingleFileUploader(file);\n    //Ask the server if it's okay to upload these files\n    const uploadinstructions = await getTSFormService().requestUpload(this.target, uploader.manifest);\n    //Run the actual upload. Options: onProgress, signal\n    const uploadedfile: UploadResult = await uploader.upload(uploadinstructions);\n    this.cache.set(file, uploadedfile);\n    return uploadedfile;\n  }\n\n  private async convertSubmittable(formvalue: unknown): Promise<unknown> {\n    //TODO combine multiple uploads into one\n    if (Array.isArray(formvalue))\n      return await Promise.all(formvalue.map(file => this.getSubmittable(file)));\n\n    if (formvalue && typeof formvalue === 'object') {\n      if (isBlob(formvalue))\n        return await this.uploadFile(formvalue as Blob);\n\n      const result: Record<string, unknown> = {};\n      for (const [key, value] of Object.entries(formvalue)) {\n        result[key] = await this.getSubmittable(value);\n        //console.log(key, value, result[key]);\n      }\n      return result;\n    }\n    return formvalue;\n  }\n\n  async getSubmittable(formvalue: object): Promise<FormResultValue> {\n    return await this.convertSubmittable(formvalue) as FormResultValue;\n  }\n}\n\n/** Directly submit a RPC form to WebHare\n *  @param target - Formtarget as obtained from\n * @deprecated Switch to \\@webhare/forms submitForm and buildFormSubmission\n */\nexport async function submitForm(target: string, formvalue: FormResultValue, options?: { extrasubmit: unknown }): Promise<FormSubmitResult> {\n  const submitparameters = await buildRPCFormSubmission(target, formvalue, { extraSubmit: options?.extrasubmit || null, });\n  return await submitRPCForm(submitparameters);\n}\n\n/** Return a value safe for RPC submission or typed serialization */\nexport async function buildRPCFormSubmission<DataShape extends object = Record<string, unknown>>(target: string, formValue: DataShape, options?:\n  {\n    extraSubmit?: unknown;\n    offline?: boolean;\n    uploadCache?: WeakMap<Blob, UploadResult>;\n    __setupEvent?: FormSubmitDetails<DataShape>;\n  }): Promise<RPCFormSubmission> {\n  const submitter = new FormSubmitter(target, options?.uploadCache || null, options?.offline || false);\n\n  const vals = await submitter.getSubmittable(formValue);\n\n  if (options?.__setupEvent) {\n    const eventdetail = options.__setupEvent;\n    eventdetail.extrasubmitdata = options.extraSubmit || null;\n    eventdetail.submitted = vals;\n  }\n\n  const submitparameters: RPCFormSubmission = {\n    ...buildTarget(target),\n    vals: unpackObject(vals),\n    extrasubmit: options?.extraSubmit || null\n  };\n  return submitparameters;\n}\n\nexport async function submitRPCForm(submission: RPCFormSubmission): Promise<FormSubmitResult> {\n  // TODO switch over to typed rpc, allow rpc options that make sense to be specified as options to submitRPCForm\n  const client = createClient<PublisherFormService>(\"publisher:forms\");\n  return await client.formSubmit(submission);\n}\n\nexport default class RPCFormBase<DataShape extends object = Record<string, unknown>> extends FormBase<DataShape> {\n  __formhandler = {\n    errors: [],\n    warnings: [],\n    formid: \"\",\n    url: \"\",\n    target: \"\",\n    submitting: false\n  };\n\n  #hadFocus = false;\n  #completedUploads = new WeakMap<Blob, UploadResult>;\n  #settingUpCaptcha = false;\n\n  pendingrpcs = new Array<Promise<unknown>>;\n\n  constructor(formnode: HTMLFormElement) {\n    super(formnode);\n    this.__formhandler.formid = formnode.dataset.whFormId || ''; //needed for 'old' __formwidget: stuff\n    this.__formhandler.url = location.href.split('/').slice(3).join('/');\n    this.__formhandler.target = formnode.dataset.whFormTarget || '';\n    window.addEventListener(\"wh:form-configure\", () => this.checkCaptcha());\n    this.node.addEventListener(\"focusin\", this.#onFirstFocus, true);\n\n    if (!this.__formhandler.target) {\n      if (this.__formhandler.formid) {\n        console.error(\"This page needs to be republished!\");\n      } else {\n        if (!isLive)\n          console.error(\"Missing data-wh-form-target on form, did your witty apply '[form.formattributes]' to the <form> tag ?\", formnode);\n        throw new Error(\"Form does not appear to be a WebHare form\");\n      }\n    }\n\n    this.checkCaptcha();\n  }\n\n  getRPCFormIdentifier(): RPCFormTarget { //submitinfo as required by some RPCs\n    return buildTarget(this.__formhandler.target);\n  }\n\n  async #getSubmitVals(): Promise<FormResultValue> {\n    const formvalue = await this.getFormValue();\n    const submitter = new FormSubmitter(this.__formhandler.target, this.#completedUploads, false);\n    return await submitter.getSubmittable(formvalue);\n  }\n\n  //Invoke a function on the form on the server\n  async _invokeRPC(background: boolean, methodname: string, args: unknown[]) {\n    const waiter = Promise.withResolvers<void>();\n\n    if (!background)\n      this.onRPC(waiter.promise);\n\n    const lock = dompack.flagUIBusy({ modal: !background });\n    try {\n      const rpc = getFormService().formInvoke({\n        ...this.getRPCFormIdentifier(),\n        vals: unpackObject(await this.#getSubmitVals()),\n        methodname,\n        args\n      });\n      this.pendingrpcs.push(rpc);\n      const result = await rpc;\n      this._processMessages(result.messages);\n      return result.result;\n    } finally {\n      lock.release();\n      waiter.resolve();\n    }\n  }\n\n  /* Override this to implement support for incoming field messages */\n  processFieldMessage(field: string, prop: string, value: unknown) {\n    if (field === \"#form\") {\n      if (prop === \"dataset\") {\n        for (const [key, keyValue] of Object.entries(value || {})) {\n          this.node.setAttribute(`data-${key}`, String(keyValue));\n        }\n        return;\n      }\n      console.warn(\"Message for non-existing form field: %s, prop: %s, value: %s\", field, prop, String(value));\n      return;\n    }\n    if (field.startsWith(\"#page.\")) {\n      const matchpage = field === \"#page.thankyou\" ? this.node.querySelector<HTMLElement>(`.wh-form__page[data-wh-form-pagerole=thankyou]`) : null;\n      if (!matchpage) { //we currently don't have anything to edit on other pages than thankyou\n        console.warn(\"Message for non-page field: %s, prop: %s, value: %s\", field, prop, String(value));\n        return;\n      }\n\n      if (prop === 'data') {\n        const dataval = value as { redirect: NavigateInstruction | null; exitbutton: string };\n        matchpage.dataset.whFormNavigateTo = dataval.redirect ? JSON.stringify(dataval.redirect) : undefined;\n        matchpage.dataset.whFormExitButton = dataval.exitbutton;\n      }\n    } else {\n      const fieldnode = this.node.querySelector<HTMLElement>(`*[name=\"${CSS.escape(field)}\"], *[data-wh-form-name=\"${CSS.escape(field)}\"]`);\n      if (!fieldnode) {\n        console.warn(\"Message for non-existent field: %s, prop: %s, value: %s\", field, prop, String(value));\n        return;\n      }\n      if (prop === 'value') {\n        this.setFieldValue(fieldnode, value);\n        return;\n      } else if (prop === 'richvalue') {\n        if (!fieldnode.classList.contains(\"wh-form__richtext\"))\n          console.warn(\"Message for non-richtext field: %s, prop: %s, value: %s\", field, prop, String(value));\n        else {\n          fieldnode.innerHTML = value as string;\n          dompack.registerMissed(fieldnode);\n        }\n        return;\n      }\n    }\n    console.warn(\"Unknown field message: field: %s, prop: %s, value: %s\", field, prop, String(value));\n  }\n\n  //Override this function to easily submit extra fields\n  getFormExtraSubmitData(): object | Promise<object> {\n    return {};\n  }\n\n  //Invoked when RPC is occuring. Is passed a promise that will resolve on completion\n  //onRPC is DEPRECATED, switching to event based api\n  onRPC(promise: Promise<void>) {\n  }\n\n  /** Invoke a function on the form on the server\n      @param methodname - Name of the function on the form\n      @param args - Arguments for the function\n      @returns Promise that resolves to the result of the rpc call\n  */\n  invokeRPC(methodname: string, ...args: unknown[]) {\n    return this._invokeRPC(false, methodname, args);\n  }\n\n  /** Invoke a function on the form on the server, doesn't call .onRPC or request modality layers\n      @param methodname - Name of the function on the form\n      @param args - Arguments for the function\n      @returns Promise that resolves to the result of the rpc call\n  */\n  invokeBackgroundRPC(methodname: string, ...args: unknown[]) {\n    return this._invokeRPC(true, methodname, args);\n  }\n\n  _processMessages(messages: Array<{ field: string; prop: string; data: unknown }>) {\n    for (const msg of messages) {\n      this.processFieldMessage(msg.field, msg.prop, msg.data);\n    }\n    this.refreshConditions();\n  }\n\n  async _flushPendingRPCs() {\n    while (this.pendingrpcs.length) {\n      try {\n        await this.pendingrpcs.pop();\n      } catch (ignore) {\n        //*we* can't handle those...\n      }\n    }\n  }\n\n  async buildFormSubmission(extradata?: object, options?: { __setupEvent?: FormSubmitDetails<DataShape> }): Promise<RPCFormSubmission> {\n    //Request extrasubmit first, so that if it returns a promise, it can execute in parallel with getFormValue\n    const extraSubmitAwaitable = this.getFormExtraSubmitData();\n    //FIXME we want getFormValue to be sync (and just use 'this.data' here) - who is still sending promises our way? too much to sort out for a backport\n    const formvalue = await this.getFormValue() as DataShape;\n    const extraSubmit = { ...extradata, ...(await extraSubmitAwaitable as Record<string, unknown>) };\n\n    await this._flushPendingRPCs();\n    dompack.dispatchCustomEvent(this.node, \"wh:form-preparesubmit\", {\n      bubbles: true, cancelable: false, detail: {\n        extrasubmit: extraSubmit\n      }\n    });\n\n    const submitparameters = await buildRPCFormSubmission<DataShape>(this.__formhandler.target, formvalue, {\n      extraSubmit,\n      offline: false,\n      uploadCache: this.#completedUploads,\n      //hack because we need to record the 'vars' value before unpackObject flattens it for safe HareScript RPC\n      __setupEvent: options?.__setupEvent\n    });\n\n    return submitparameters;\n  }\n\n  #onFirstFocus = () => {\n    this.#hadFocus = true;\n    this.checkCaptcha();\n  };\n\n  private checkCaptcha() {\n    //Checks whether to show captcha based on configuration. Note that even if *we* think it's not needed, form submission may still require a captcha\n    const config = getFormConfiguration();\n    const shouldShow = config?.captcha === \"onLoad\" || (config?.captcha === \"onActivate\" && this.#hadFocus);\n    if (shouldShow && this.node.dataset.whFormCaptcha !== undefined && !this.#settingUpCaptcha && !this.getElementByName(\"__form_captcha\")) {\n      this.#settingUpCaptcha = true;\n      void getFormService().getCaptchaConfiguration(this.getRPCFormIdentifier()).then(captchaConfig => {\n        if (captchaConfig) {\n          setupCaptchaFieldGroup(this, captchaConfig);\n        }\n      });\n    }\n  }\n\n  async submitForm(parameters: RPCFormSubmission): Promise<FormSubmitResult> {\n    return await submitRPCForm(parameters);\n  }\n\n  async submit(extradata?: object): Promise<{ result?: FormSubmitEmbeddedResult }> {\n    //ADDME timeout and free the form after some time\n    if (this.__formhandler.submitting) //throwing is the safest solution... having the caller register a second resolve is too dangerous\n      throw new Error(\"The form is already being submitted\");\n\n    const waiter = Promise.withResolvers<void>();\n    let insubmitrpc = false;\n    this.onRPC(waiter.promise);\n\n    const eventdetail: FormSubmitDetails<DataShape> = {\n      form: this.node,\n      rpchandler: this,\n      submitted: {},\n      errors: [],\n      result: null\n    };\n\n    try {\n      this.__formhandler.submitting = true;\n\n      const submitparameters = await this.buildFormSubmission(extradata, { __setupEvent: eventdetail });\n\n      if (debugFlags.fhv)\n        console.log('[fhv] start submission', submitparameters);\n\n      insubmitrpc = true; //so we can easily determine exception source\n      const result = await this.submitForm(submitparameters);\n      insubmitrpc = false;\n\n      if (debugFlags.fhv)\n        console.log('[fhv] received response', result);\n\n      this._processMessages(result.messages);\n\n      if (!dompack.dispatchCustomEvent(this.node, \"wh:form-response\", { bubbles: true, cancelable: true, detail: result }))\n        return result;\n\n      eventdetail.result = result.result;\n      eventdetail.errors = result.errors;\n\n      let didfirstfocus = false;\n      const globalerrors = [];\n      for (const error of result.errors) {\n        if (!error.name) {\n          globalerrors.push(error);\n          continue;\n        }\n\n        let failednode = this.node.querySelector('[name=\"' + error.name + '\"], [data-wh-form-name=\"' + error.name + '\"]');\n        if (!failednode) {\n          if (error.name === \"__form_captcha\") { //created on demand\n            const serverMetadata = error.metadata as { provider: CaptchaProvider };\n            failednode = setupCaptchaFieldGroup(this, serverMetadata.provider);\n          } else {\n            console.error(\"[fhv] Unable to find node '\" + error.name + \"' which caused error:\" + error.message);\n            continue;\n          }\n        }\n        if (!didfirstfocus) {\n          dompack.focus(failednode);\n          didfirstfocus = true;\n        }\n        setFieldError(failednode, error.message, { reportimmediately: true, serverside: true, metadata: error.metadata });\n      }\n\n      if (result.success) {\n        this.sendFormEvent({ event: 'submitted' });\n        if (dompack.dispatchCustomEvent(this.node, \"wh:form-submitted\", { bubbles: true, cancelable: true, detail: eventdetail as FormSubmitDetails<Record<string, unknown>> })) {\n          merge.run(this.node, { form: await this.getFormValue() });\n\n          //FIXME why is going to 'thank you' not in the formbase?\n          this._navigateToThankYou(result.result && result.result.richvalues);\n          this.onSubmitSuccess(result.result);\n        }\n      } else {\n        const failedfields = result.errors.map(error => error.name || \"*\").sort().join(\" \");\n        this.sendFormEvent({ event: 'failed', errorfields: failedfields, errorsource: 'server' });\n\n        if (globalerrors.length) {\n          if (dompack.dispatchCustomEvent(this.node, \"wh:form-globalerrors\", { bubbles: true, cancelable: true, detail: { globalerrors } }))\n            this.displayGlobalErrors(globalerrors);\n        }\n\n        if (dompack.dispatchCustomEvent(this.node, \"wh:form-failed\", { bubbles: true, cancelable: true, detail: eventdetail }))\n          this.onSubmitFailed(result.errors, result.result);\n      }\n      return pick(result, [\"result\"]);\n    } catch (e) {\n      this.sendFormEvent({ event: 'exception', exception: String(e), errorsource: insubmitrpc ? 'server' : 'client' });\n\n      if (dompack.dispatchCustomEvent(this.node, \"wh:form-exception\", { bubbles: true, cancelable: true, detail: eventdetail }))\n        this.onSubmitException(e as Error);\n\n      throw e;\n    } finally {\n      waiter.resolve();\n      this.__formhandler.submitting = false;\n    }\n  }\n\n  displayGlobalErrors(globalerrors: FormSubmitMessage[]) {\n    try {\n      const errors = globalerrors.map(error => dompack.create(\"p\", { textContent: error.message }));\n      runMessageBox(errors, [{ title: \"OK\" }]); //TODO: language?\n    } catch (e) {\n      console.error(\"runMessageBox failed\", e);\n      // eslint-disable-next-line no-alert -- alert is our fallback without message boxes\n      alert(globalerrors.map(error => error.message).join(\"\\n\"));\n    }\n  }\n\n  //Get the first group that failed error handling\n  getFirstFailedGroup() {\n    return this.node.querySelector(\".wh-form__fieldgroup-error\");\n  }\n\n  //override this to deal with succesful submissions\n  onSubmitSuccess(result: FormSubmitEmbeddedResult<unknown>) {\n    const formpos = this.node.getBoundingClientRect();\n    if (formpos.top < 0)\n      this.node.scrollIntoView({ block: 'start', behavior: 'smooth' });\n\n    if (result && result.resultsguid)\n      this.node.dataset.whFormResultguid = result.resultsguid;\n\n    if (result && result.submitinstruction)\n      navigateTo(result.submitinstruction);\n  }\n\n  //override this to deal with failed submissions\n  onSubmitFailed(errors: FormSubmitMessage[], result: unknown) {\n  }\n\n  //override this to deal with form exceptions\n  onSubmitException(e: Error) {\n  }\n\n  async validateSingleFormField(field: HTMLElement): Promise<boolean> {\n    if (field instanceof HTMLInputElement && field.type === \"email\") { //TODO perhaps move this to webharefields.es ?\n      if (focus.getCurrentlyFocusedElement() === field) { //TODO clearing suggestion on change should probably be generalized\n        if (field.propWhValidationSuggestion) {\n          field.propWhValidationSuggestion = null;\n        }\n      }\n\n      //Just because it's focused doesn't mean we shouldn't validate it\n      const validation = emailvalidation.validateField(this, field);\n      this.pendingrpcs.push(validation);\n      if (!(await validation))\n        return false;\n    }\n    return true;\n  }\n}\n","export function getActiveElement(doc: Document | null): HTMLElement | null {\n  return doc?.activeElement as HTMLElement || null;\n}\n\nexport function getToplevelWindow() {\n  let toplevelwindow: Window = window;\n  while (toplevelwindow.frameElement)\n    toplevelwindow = toplevelwindow.parent;\n  return toplevelwindow;\n}\n\nexport function asIframe(node: Element | null): HTMLIFrameElement | null {\n  return node && (node as HTMLElement)?.matches?.('iframe') ? node as HTMLIFrameElement : null;\n}\n\n/**\n     Find the currently focused element\n *\n    @param limitdoc - If set, only return compontents in the specified document (prevents editable iframes from returning subframes)\n    @returns The element or null\n */\nexport function getCurrentlyFocusedElement(limitdoc?: Document): HTMLElement | null {\n  try {\n    let focused = getActiveElement(getToplevelWindow().document);\n    for (; ;) {\n      const frame = asIframe(focused);\n      if (frame && (!limitdoc || frame.ownerDocument !== limitdoc))\n        focused = getActiveElement(frame.contentDocument);\n      else\n        break;\n    }\n    if (focused && limitdoc && focused.ownerDocument !== limitdoc)\n      return null;\n    return focused;\n  } catch (e) {\n    return null;\n  }\n}\n\n/** Return whether the node is reachable for focus by keyboard navigation\n   (because tabIndex === -1 will be seen a non(keyboard)focusable by this function)\n\n    @param node - Node to test\n    @param ignoreInert - Ignore the inert attribute\n*/\nexport function canFocusTo(node: Element, { ignoreInertAttribute = false } = {}): node is HTMLElement { //returns if a -visible- node is focusable (this function does not check for visibility itself)\n  if (!node.closest) //callers are not necessarily calling us with HTMLElement, eg getClosestValidFocusTarget might supply a document\n    return false;\n  if (!ignoreInertAttribute && node.closest('[inert]'))\n    return false;\n\n  if ((node as HTMLElement).contentEditable === \"true\")\n    return true;\n  if (node.shadowRoot?.delegatesFocus)\n    return true;\n\n  return (node as HTMLElement).tabIndex >= 0 && !(node as HTMLInputElement).disabled && !(node.tagName === 'A' && !(node as HTMLAnchorElement).href);\n}\n\nexport function getFocusableComponents(startnode: Element | null, options?: boolean | { recurseFrames?: boolean; ignoreInertAttribute?: boolean }): HTMLElement[] {\n  if (typeof options !== \"object\") {\n    options = { recurseFrames: options };\n  }\n  let focusable: HTMLElement[] = [];\n  if (!startnode)\n    return focusable;\n  for (const currentnode of startnode.children) {\n    // Get current style (avoid mootools due to cross-frame issues)\n    const currentstyle = getComputedStyle(currentnode);\n    if (!currentstyle || currentstyle.display === \"none\" || currentstyle.visibility === \"hidden\") {\n      //if(currentnode.getStyle) console.log(\"getFocusableComponents skipping\",currentnode, $(currentnode).getStyle(\"display\"), currentnode.getStyle(\"visibility\"))\n      continue;\n    }\n\n    let iframe;\n    if (options?.recurseFrames && (iframe = asIframe(currentnode))) { //might contain more things to focus\n      try {\n        const subnodes = getFocusableComponents(iframe.contentDocument!.documentElement, options);\n        if (subnodes.length)\n          focusable = focusable.concat(subnodes);\n      } catch {\n        //assume permission error\n      }\n    } else if (canFocusTo(currentnode, options)) {\n      focusable.push(currentnode);\n    }\n\n    if ((currentnode as HTMLElement).isContentEditable)\n      continue; //don't look for further focusable nodes inside, the whole RTE counts as an editable component\n\n    const subnodes = getFocusableComponents(currentnode, options);\n    if (subnodes.length)\n      focusable = focusable.concat(subnodes);\n  }\n  return focusable;\n}\n\nexport function getAllFocusableComponents() {\n  return getFocusableComponents(getToplevelWindow().document.documentElement, true);\n}\n","// eslint-disable-next-line @typescript-eslint/no-explicit-any -- we can't know the types passed to merge call\ntype FormatFunction = (value: any) => string | number;\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- we can't know the types passed to merge call\ntype UpdateFunction = (node: HTMLElement, value: any) => void;\nconst formatters: { [key: string]: FormatFunction } = {};\nconst updaters: { [key: string]: UpdateFunction } = {};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- we can't know the types passed to merge call\nfunction mergeNode(node: HTMLElement, set: string, data: any) {\n  const parts = set.split(\":\");\n  const isNodeFunc = parts.length === 1;\n  if (parts.length > 2) {\n    console.error(`Illegal merge expression: '${set}'`, node);\n    return;\n  }\n\n  let func = \"\";\n  let exprpath = (isNodeFunc ? parts[0] : parts[1]).trim();\n\n  const callparts = exprpath.split(\"(\");\n  if (callparts.length > 1) {\n    if (callparts.length !== 2) {\n      console.error(`Illegal merge value: '${set}'`, node);\n      return;\n    }\n\n    func = callparts[0].trim();\n    const funcrest = callparts[1].split(\")\");\n    if (funcrest.length !== 2 || funcrest[1] !== \"\") {\n      console.error(`Illegal merge value: '${set}'`, node);\n      return;\n    }\n    exprpath = funcrest[0].trim();\n  }\n\n  let value = data;\n  if (exprpath !== \"*\") {\n    const exprpathparts = exprpath.split(\".\");\n    for (let i = 0; i < exprpathparts.length; ++i) {\n      value = value[exprpathparts[i].trim()];\n      if (typeof value === \"undefined\")\n        return;\n    }\n  }\n\n  if (isNodeFunc) {\n    if (func && updaters[func])\n      updaters[func](node, value);\n    else if (func)\n      console.error(`Unknown updating function '${func}' in '${set}'`, node);\n    else\n      console.error(`A function is required for merges without a property (in '${set}')`, node);\n    return;\n  }\n\n  const prop = parts[0].trim();\n  if (func) {\n    if (formatters[func])\n      value = formatters[func](value);\n    else {\n      console.error(`Unknown formatting function '${func}' in '${set}'`, node);\n      return;\n    }\n  }\n\n  if (typeof value !== \"string\" && typeof value !== \"number\") {\n    console.error(`Got a value of type ${typeof value} in '${set}'`, node);\n    return;\n  }\n\n  switch (prop) {\n    case 'events':\n    case 'styles':\n    case 'children':\n    case 'on':\n    case \"className\":\n    case \"class\":\n    case 'style':\n    case 'dataset':\n    case 'childNodes':\n      {\n        console.error(`Cannot modify '${prop}' with merge`, node);\n        return;\n      }\n    default:\n      {\n        // 1-to-1 name to property mapping\n        // eslint-disable-next-line @typescript-eslint/no-explicit-any -- we don't know which keys will be set\n        (node as any)[prop] = value;\n        return;\n      }\n  }\n}\n\n/**\n     Apply all merge fields within a node, recursively\n *\n    @param mergenode - Root node to start merging\n    @param data - Merge data\n    @param options - filter: If set, a function that will be called for every node with merge functions. If it returns a falsy value, the node will be skipped.\n */\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any -- we can't know the types passed to merge call\nexport async function run(mergenode: ParentNode, data: any, { filter }: { filter?: (node: Element) => boolean } = {}) {\n  const nodes = mergenode.querySelectorAll('*[data-merge],*[data-wh-merge]') as NodeListOf<HTMLElement>;\n  for (const node of Array.from(nodes)) { //FIXME drop support for data-wh-merge as soon as we've completed the phase out\n    if (node.nodeType !== 1 || (filter && !filter(node)))\n      continue;\n\n    // Parse 'a=b;c=d(e)'\n    const sets = ((node as HTMLElement).dataset.merge || (node as HTMLElement).dataset.whMerge)?.split(\";\");\n    if (sets)\n      for (const set of sets)\n        mergeNode(node, set, data);\n  }\n}\n\n/**\n     Register a formatter function.\n *\n    @param name - Name of the formatter function\n    @param callback - Formatter function. Called with parameter (value), must return a formatted value to write to the property.\n */\nexport function registerFormatter(name: string, callback: FormatFunction) {\n  formatters[name] = callback;\n}\n\n/**\n     Register an updater function (used to update multiple properties of a node at once)\n *\n    @param name - Name of the updater function\n    @param callback - Updater function. Called with parameters (node: HTMLElement, value: Any).\n */\nexport function registerUpdater(name: string, callback: UpdateFunction) {\n  updaters[name] = callback;\n}\n","/* eslint-disable @typescript-eslint/no-floating-promises -- FIXME: needs API rework */\n\nimport * as dompack from '@webhare/dompack';\nimport { type DocEvent, type FormControlElement, type TakeFocusEvent, addDocEventListener, isFormControl } from '@webhare/dompack';\nimport * as domfocus from 'dompack/browserfix/focus';\nimport * as webharefields from './internal/webharefields';\nimport * as merge from './internal/merge';\nimport './internal/requiredstyles.css';\nimport { type SetFieldErrorData, getValidationState, setFieldError, setupValidator, updateFieldError } from './internal/customvalidation';\nimport { generateRandomId, isPromise, wrapSerialized } from '@webhare/std';\nimport { debugFlags, dtapStage, navigateTo, type NavigateInstruction } from '@webhare/env';\nimport { getFieldDisplayName, isFieldNativeErrored, isRadioOrCheckbox, isRadioNodeList, type ConstrainedRadioNodeList, parseCondition, getFormElementCandidates, isFormFieldLike, queryFormFieldLike, getFieldName } from '@webhare/forms/src/domsupport';\nimport { rfSymbol } from '@webhare/forms/src/registeredfield';\nimport type { FormAnalyticsEventData, FormAnalyticsSubEvents, FormCondition, FormFileValue, RPCFormMessage } from '@webhare/forms/src/types';\nimport { FieldMapDataProxy, FormFieldMap } from '@webhare/forms/src/fieldmap';\nimport { submitselector, type SubmitSelectorType } from '@webhare/dompack/src/browser';\nimport type { FormSubmitDetails } from './rpc';\nimport type { FormConfiguration } from '@webhare/forms';\n\n//Suggestion or error messages\nexport type FormFrontendMessage = HTMLElement | string;\n\ndeclare global {\n  interface HTMLElement {\n    //TODO Clean this up, these are internal. Move to a dataset, safer against DOM manipulation eg as done by slimselect\n    //Used by formgroups:\n    propWhFormInitialRequired?: boolean;\n    propWhFormCurrentEnabled?: boolean;\n    propWhFormCurrentRequired?: boolean;\n    propWhFormCurrentVisible?: boolean;\n    //Used by formlines:\n    propWhFormlineCurrentVisible?: boolean;\n    propWhValidationSuggestion?: FormFrontendMessage | null;\n    propWhCleanupFunction?: () => void;\n    /** @deprecated Use `getFormHandler` or `getFormData` from `@webhare/forms` to access the form's API */\n    propWhFormhandler?: FormBase<object>;\n    whFormsApiChecker?: () => Promise<void> | void;\n    whUseFormGetValue?: boolean;\n    whValidationPolyfilled?: boolean;\n    __didPlaceholderWarning?: boolean;\n  }\n\n  interface GlobalEventHandlersEventMap {\n    \"wh:form-enable\": CustomEvent<{ enabled: boolean }>;\n    \"wh:form-require\": CustomEvent<{ required: boolean }>;\n    \"wh:form-getvalue\": CustomEvent<{ deferred: PromiseWithResolvers<unknown> }>;\n    \"wh:form-setfielderror\": CustomEvent<SetFieldErrorData>; //TODO can we phase this out? it's a too deep integration\n    \"wh:form-configure\": CustomEvent<FormConfiguration>;\n    \"wh:form-pagechange\": CustomEvent<{\n      formHandler: FormBase<object>;\n      /** TODO Add numPages and currentPage, but we'd need to figure out how to properly account for Captcha pages (you don't want either numPages or currentPage to count that one)\n      numPages: number;\n      currentPage: number;\n      */\n    }>;\n    \"wh:form-preparesubmit\": CustomEvent<{ extrasubmit: Record<string, unknown> }>;\n    \"wh:form-response\": CustomEvent<FormSubmitResult>;\n    \"wh:form-submitted\": CustomEvent<FormSubmitDetails>;\n  }\n}\n\ntype ExtraData = unknown;\n\ntype FormControlDescription = {\n  name: string;\n  multi: false;\n  node: HTMLElement;\n} | {\n  name: string;\n  multi: true;\n  nodes: HTMLInputElement[];\n};\n\nexport type FormResultValue = Record<string, unknown>;\n\n/** The result returned to onSubmitSuccess */\nexport type FormSubmitEmbeddedResult<UserResult = { [key: string]: unknown }> = UserResult & {\n  //webtool submit additions. TODO a future API shouldn't mix these at the same level but allow them in the FormSubmitResult\n  submittype?: string;\n  richvalues?: RichValues;\n  resultsguid?: string;\n  submitinstruction?: NavigateInstruction;\n};\n\nexport interface FormSubmitMessage {\n  name: string;\n  message: string;\n  metadata: unknown;\n}\n\nexport interface FormSubmitResult {\n  success: boolean;\n  //TODO a next form iteration should not mix all these additional props into the form user's 'result'\n  result: FormSubmitEmbeddedResult;\n  errors: FormSubmitMessage[];\n  warnings: FormSubmitMessage[];\n  messages: RPCFormMessage[];\n}\n\ntype RichValues = Array<{ field: string; value: string }>;\n\nexport interface FieldErrorOptions {\n  serverside: boolean;\n  reportimmediately: boolean;\n  metadata?: unknown;\n}\n\ntype LimitSet = undefined | HTMLElement | HTMLElement[];\n\ninterface ValidationOptions {\n  // focusfailed Focus the first invalid element (defaults to true)\n  focusfailed?: boolean;\n  iffailedbefore?: boolean;\n}\n\ninterface FormValidationResult {\n  /// True if the fields successfuly validated\n  valid: boolean;\n  failed: HTMLElement[];\n  firstfailed: HTMLElement | null;\n}\n\ninterface ValidationQueueElement {\n  limitset?: LimitSet;\n  options?: ValidationOptions;\n  defer: PromiseWithResolvers<FormValidationResult>;\n}\n\ninterface PageState {\n  pages: HTMLElement[];\n  curpage: number;\n}\n\nlet delayvalidation = false, validationpendingfor: EventTarget | null = null;\nlet didGlobalHandlers: true | undefined;\n\n/** Convert linefeeds to BR tags */\nfunction lineFeedsToBreaks(text: string): DocumentFragment {\n  const frag = new DocumentFragment;\n  for (const part of text.split(/\\r?\\n/)) {\n    if (frag.childNodes.length)\n      frag.appendChild(document.createElement(\"br\"));\n    frag.append(part);\n  }\n  return frag;\n}\n\nfunction getPageIdx(state: PageState, page: number | HTMLElement) {\n  if (typeof page === 'number') {\n    if (page < 0 || page >= state.pages.length)\n      throw new Error(`Cannot navigate to nonexisting page #${page}`);\n    return page;\n  }\n\n  const idx = state.pages.indexOf(page);\n  if (idx === -1) {\n    console.error(`Cannot find page by element`, page);\n    throw new Error(`Cannot find page`);\n  }\n\n  return idx;\n}\n\nfunction getErrorFields(validationresult: FormValidationResult) {\n  return validationresult.failed.map(field => getFieldName(field) || field.dataset.whFormGroupFor || \"?\")\n    .sort()\n    .filter((value, index, self) => self.indexOf(value) === index) //unique filter\n    .join(\" \");\n}\nfunction hasEverFailed(field: HTMLElement) {\n  if (field.matches(\"input[type=radio],input[type=checkbox]\")) //these are handled by their group, so do the failed check there\n    return field.closest(\".wh-form__fieldgroup\")?.classList.contains('wh-form__field--everfailed');\n\n  return field.classList.contains('wh-form__field--everfailed');\n}\nfunction doValidation(field: EventTarget | null, iffailedbefore: boolean) {\n  if (iffailedbefore || validationpendingfor)\n    releasePendingValidations(); //release any earlier validation. this also cancels 'delayvalidation' but better safe than sorry if we double-run here\n\n  if (delayvalidation) { //Can't be \"iffailedbefore\" as that would have been cleared above\n    if (debugFlags.fhv)\n      console.log(\"[fhv] doValidation: validations are delayed. now pending: \", field);\n    validationpendingfor = field;\n    return;\n  }\n\n  const form = (field as HTMLElement).closest?.('form');\n  if (!form || !form.propWhFormhandler)\n    return;\n\n  const formhandler = form.propWhFormhandler;\n  formhandler.validate([field as HTMLElement], { focusfailed: false, iffailedbefore: iffailedbefore });\n}\n\n\nfunction doDelayValidation() {\n  if (delayvalidation)\n    releasePendingValidations();\n\n  delayvalidation = true;\n}\n\nfunction releasePendingValidations() {\n  if (!delayvalidation)\n    return;\n\n  delayvalidation = false;\n\n  if (validationpendingfor) {\n    const tovalidate = validationpendingfor;\n    if (debugFlags.fhv)\n      console.log(\"[fhv] releasePendingValidations: \", tovalidate);\n    validationpendingfor = null;\n    doValidation(tovalidate, false);\n  }\n}\n\n/* Browser extensions such as 1Password interfere with the event model and may\n   cause focusout to not fire for email and password fields. They don't seem\n   to break focusin so we'll watch focusin to detect missed focusout events */\nlet lastfocusout: EventTarget | null = null;\nfunction handleFocusOutEvent(event: FocusEvent) {\n  lastfocusout = event.target;\n  doValidation(event.target, false);\n}\nfunction handleFocusInEvent(event: FocusEvent) {\n  if (event.relatedTarget && lastfocusout !== event.relatedTarget)\n    doValidation(event.relatedTarget, false);\n}\n\nfunction handleValidateAfterEvent(event: Event) {\n  doValidation(event.target, true);\n}\n\nexport default class FormBase<DataShape extends object = Record<string, unknown>> extends FormFieldMap<DataShape> {\n  /** @deprecated Use node.elements if you want a true HTMLFormControlsCollection, use getElementByName since WH5.4+ for properly typed elements */\n  readonly elements: HTMLFormControlsCollection;\n  private _formsessionid = generateRandomId();\n  private _firstinteraction: number | undefined;\n  protected _submitstart: number | undefined;\n  private validationqueue = new Array<ValidationQueueElement>;\n  private _submitter: SubmitSelectorType | null = null;\n  private _submittimeout: NodeJS.Timeout | undefined;\n  /** Is the form currently interactive? Used to ignore changes done by code/setFieldValue */\n  private isInteractive = true;\n  /** Did we warn about old style form controls? */\n  private didLegacyWarning = false;\n  /** Are we currently in the _submit handler? (prevent duplicate submit attemps while eg. inside onBeforeSubmit) */\n  private inSubmit = false;\n  /** Where should the exitButton navigate to? */\n  private exitButtonNavigateTo?: NavigateInstruction;\n  /** Name of last focused element */\n  #lastFocused = \"\";\n\n  readonly data = new Proxy<DataShape>({} as DataShape, new FieldMapDataProxy(this));\n\n  readonly node: HTMLFormElement;\n\n  constructor(node: HTMLFormElement) {\n    if (node.nodeName !== 'FORM')\n      throw new Error(\"Specified node is not a <form>\"); //we want our clients to be able to assume 'this.node.elements' works\n\n    super(\"\", getFormElementCandidates(node, ''));\n\n    this.node = node;\n\n    this.elements = node.elements;\n    if (this.node.propWhFormhandler)\n      throw new Error(\"Specified node already has an attached form handler\");\n    this.node.propWhFormhandler = this;\n\n    //TODO Can we scope these handlers to the form ? Or register only once needed?\n    if (!didGlobalHandlers) {\n      didGlobalHandlers = true;\n      window.addEventListener(\"mouseup\", releasePendingValidations, true);\n      window.addEventListener(\"focusin\", handleFocusInEvent, true);\n    }\n\n    //Implement webhare fields extensions, eg 'now' for date fields or 'enablecomponents'\n    webharefields.setup(this.node);\n    //Implement page navigation\n    addDocEventListener(this.node, \"click\", evt => this._checkClick(evt));\n    addDocEventListener(this.node, \"dompack:takefocus\", evt => this._onTakeFocus(evt));\n    addDocEventListener(this.node, \"input\", evt => this._onInputChange(), { capture: true });\n    addDocEventListener(this.node, \"change\", evt => this._onInputChange(), { capture: true });\n    addDocEventListener(this.node, 'submit', evt => this._submit(evt, null));\n    addDocEventListener(this.node, 'wh:form-dosubmit', evt => { throw new Error(`wh:form-dosubmit is no longer supported`); });\n    addDocEventListener(this.node, \"wh:form-setfielderror\", evt => this._doSetFieldError(evt));\n    addDocEventListener(this.node, \"mousedown\", doDelayValidation);\n    addDocEventListener(this.node, \"focusout\", handleFocusOutEvent, { capture: true });\n    addDocEventListener(this.node, \"input\", handleValidateAfterEvent, { capture: true });\n    addDocEventListener(this.node, \"change\", handleValidateAfterEvent, { capture: true });\n    addDocEventListener(this.node, \"focusin\", this.#recordLastFocus, { capture: true });\n    this.node.noValidate = true;\n\n    this._rewriteEnableOn();\n    this._updateConditions(true); //Update required etc handlers\n    this._applyPrefills();\n\n    //Update page navigation\n    const pagestate = this._getPageState();\n    this._updatePageVisibility(pagestate.pages, 0);\n    this._updatePageNavigation();\n  }\n\n  static getForNode<DataShape extends object = Record<string, unknown>>(node: HTMLElement): FormBase<DataShape> | null {\n    return (node.propWhFormhandler as FormBase<DataShape>) || null;\n  }\n\n  ///like namedItem but improves on the types returned. does *not* lookup by data-wh-form-name!\n  getElementByName(name: string): FormControlElement | ConstrainedRadioNodeList | null {\n    return this.node.elements.namedItem(name) as FormControlElement | ConstrainedRadioNodeList | null;\n  }\n\n  /** Get language for this form */\n  getLangCode() {\n    return this.node.closest<HTMLElement>('[lang]')?.lang ?? 'en';\n  }\n\n  #recordLastFocus = (evt: dompack.DocEvent<FocusEvent>) => {\n    if (this.node.contains(evt.target)) {\n      const name = getFieldName(evt.target) || evt.target.dataset.whFormGroupFor;\n      if (name)\n        this.#lastFocused = name;\n    }\n  };\n\n  #onUnload = () => {\n    this.sendFormEvent({\n      event: 'abandoned',\n      lastfocused: this.#lastFocused,\n      pagenum: this.getCurrentPageNumber()\n    });\n  };\n\n  protected __formStarted() {\n  }\n\n  protected sendFormEvent(event?: FormAnalyticsSubEvents) {\n    const now = Date.now();\n    if (event?.event === 'submitted')\n      removeEventListener(\"pagehide\", this.#onUnload);\n\n    if (!this._firstinteraction) {   //The user hasn't interacted with the form yet\n      if (!this.isInteractive) { //ignore events triggered by code, eg a form prefill\n        if (event?.event && debugFlags.anl)\n          console.log(`[anl] Form is supressing broadcast of '${event?.event}' because it hasn't been interacted with yet`);\n        return;\n      }\n\n      //The user has interacted, start the clock!\n      this._firstinteraction = now; //set for calculation base *and* to prevent endless loops\n      this.sendFormEvent({ event: \"started\" });\n      addEventListener(\"pagehide\", this.#onUnload);\n    }\n\n    if (!event)\n      return; //we were only triggered to signal First Interaction\n    this._firstinteraction ||= now;\n\n    const pagestate = this._getPageState();\n    const eventdata: FormAnalyticsEventData = {\n      ...event,\n      id: this.node.dataset.whFormId || '',\n      session: this._formsessionid,\n      pagetitle: this._getPageTitle(pagestate.curpage),\n      pagenum: pagestate.curpage + 1,\n      time: now - this._firstinteraction,\n      objref: this.node.dataset.whFormObjref || ''\n    };\n\n    if (this._submitstart) //is set during a pending submission\n      eventdata.waittime = Date.now() - this._submitstart;\n\n    dompack.dispatchCustomEvent(this.node, \"wh:form-analytics\", { bubbles: true, cancelable: false, detail: eventdata });\n  }\n\n  _rewriteEnableOn() { //ADDME move this to webhare server\n    // EnablingComponents may set data-wh-form-enable. input(radio/checkbox) and option qualify\n    type EnablingComponent = HTMLInputElement | HTMLOptionElement;\n\n    // This is the initialization, check the enable components for all elements within the form\n    for (const control of dompack.qSA<EnablingComponent>(this.node, \"*[data-wh-form-enable]\"))\n      for (const element of control.dataset.whFormEnable!.split(\" \")) {\n        const target = this.getElementByName(element);\n        if (target && target instanceof HTMLElement) {\n          const name = (control instanceof HTMLOptionElement ? control.closest<HTMLSelectElement>(\"select\") : control)?.name;\n          if (!name) //duplicated node?\n            continue;\n\n          let ourcondition: FormCondition = { field: name, matchtype: \"IN\", value: control.value };\n          if (target.dataset.whFormEnabledIf) //append to existing criterium\n            ourcondition = { conditions: [parseCondition(target.dataset.whFormEnabledIf), ourcondition], matchtype: \"AND\" };\n          target.dataset.whFormEnabledIf = JSON.stringify({ c: ourcondition });\n        }\n      }\n  }\n\n  _applyPrefills() {\n    //Apply prefills. Set in field order, so controls-enabling-controls things will generally work\n    const searchparams = new URL(location.href).searchParams;\n    for (const field of this._queryAllFields()) {\n      const allvalues = searchparams.getAll(field.name);\n      if (!allvalues.length)\n        continue;\n\n      if (field.multi && field.nodes[0].type === 'checkbox') {\n        for (const node of field.nodes) {\n          const shouldbechecked = allvalues.includes(node.value);\n          if (shouldbechecked !== node.checked) //NOTE: used to read 'field.checked' which doesn't exist so this if() would always evaluate to true\n            this.setFieldValue(node, shouldbechecked);\n        }\n      } else if (field.multi) { //implies radio\n        const tocheck = field.nodes.filter(_ => _.value === allvalues[allvalues.length - 1])[0];\n        if (tocheck && !tocheck.checked)\n          this.setFieldValue(tocheck, true);\n        if (!tocheck)\n          field.nodes.filter(_ => _.checked).forEach(_ => this.setFieldValue(_, false));\n      } else if (field.node.matches(\"input:not([type=file]),select,textarea\")) { //Limit URL prefills to simple elements - TODO allow custom components to decide on this themselves OR *explicitly* require fields to opt-in to being prefillable\n        if (!this._isNowSettable(field.node))\n          continue;\n        this.setFieldValue(field.node, allvalues[allvalues.length - 1]); //last value wins\n      }\n    }\n  }\n\n  /**\n   * Set or update the message for the specified field\n   * @param field - node on which the validation triggered\n   * @param type - type of the message (\"error\" or \"suggestion\") - a field or group can have both an \"error\" and \"suggestion\" visible\n   * @param getError - function which returns a reference to the error node (or DocumentFragment) or a text\n   *\n   * .wh-form__field--error      - Used to indicate this element has an error\n   * .wh-form__field--suggestion - Used to indicate this element has an suggestion\n   * .wh-form__error             - The error message container\n   * .wh-form_suggestion         - The suggestion message container\n   */\n  _updateFieldGroupMessageState(field: HTMLElement, type: \"error\" | \"suggestion\", getError: (field: HTMLElement) => FormFrontendMessage | null) {\n    //Please note that _updateFieldGroupMessageState doesn't *validate* anything - it takes the current error/suggestion status and updates the DOM accordingly\n\n    /*\n    ADDME: ability to show multiple messages in case both the toplevel and a subfield have an error/suggestion.\n           Example: a checkboxgroup in which too many options are selected AND the required textfield of a selected option is empty.\n\n    ADDME: how should an error message reference a required nested textfield?\n\n    ADDME: Support progressive enhancements such as splitdatetime which use a native form element\n           to store the value. (it's probably confusing that aria-described by ends up on an\n           element which needs receives focus and cannot be used to influence/fix the value).\n           (such as the splitdatetime)\n\n           Suggestion for possible solution:\n           - have the progressive enchancement code add an attribute to the native form element\n             with the ID of the (group)element.\n    */\n    const fieldgroup = field.closest<HTMLElement>(\".wh-form__fieldgroup\");\n    //console.log(\"_updateFieldGroupMessageState\", field, fieldgroup);\n    if (!fieldgroup)\n      return;\n\n    /* Within the group this field belongs to we lookup the first node we can find which is marked as having the\n       type of message we want (\"error\" or \"suggestion\").\n       First we'll see if the fieldgroup wants to report something (radio & checkboxes handle their errors at the group level)\n       otherwise whe'll look for the first node which has a message.\n    */\n    const field_with_message = fieldgroup.classList.contains(\"wh-form__field--\" + type) ? fieldgroup : fieldgroup.querySelector<HTMLElement>(\".wh-form__field--\" + type);\n    //Do not pick up errors from deeper groups (array rows)\n    const error = (field_with_message && field_with_message.closest(\".wh-form__fieldgroup\") === fieldgroup ? getError(field_with_message) : null) || null;\n\n    // Now mark the whole .wh-form__fieldgroup as having an error/suggestion\n    fieldgroup.classList.toggle(\"wh-form__fieldgroup--\" + type, Boolean(error));\n\n    // Lookup the error message from the field metadata\n    if (error) { //mark the field has having failed at one point. we will now switch to faster updating error state\n      if (!field.classList.contains('wh-form__field--everfailed')) {\n        if (debugFlags.fhv)\n          console.log('[fhv] marking as everfailed', field, 'because of error', error);\n        field.classList.add('wh-form__field--everfailed');\n      }\n    }\n\n    // Determine the contextnode to set ARIA attributes on\n\n    // ADDME: before looking up a group, check if there an attribute specifying\n    //        another element with role=\"group\" handled the input.\n\n    // Find the first role=\"group\" we can find\n    // (ineither the .wh-form__subfield or .wh-form__field)\n    const potentialgroupnode = field.closest<HTMLElement>(\"[role=group],.wh-form__subfield,wh-form__fieldgroup\");\n    const group = potentialgroupnode?.role === \"group\" ? potentialgroupnode : null;\n    const contextnode = group ?? field;\n\n    let messageid = \"\";\n    let messagenode = fieldgroup.querySelector(\".wh-form__\" + type); //either wh-form__error or wh-form__suggestion\n\n    // Create a container for the suggestion or error\n    if (messagenode) {\n      messageid = messagenode.id; // reuse the existing messagenode\n    } else {\n      if (!error)\n        return; //nothing to do\n\n      // Generate a temporary id for the message which we can use in\n      // the aria-describedby to point to the message.\n      const random = Math.floor((1 + Math.random()) * 0x10000000).toString(16);\n      messageid = \"whform-msg-\" + random; // `${fieldname}-${random}`;\n\n      const suggestionholder = field.closest('.wh-form__fields') || fieldgroup.querySelector('.wh-form__fields') || fieldgroup;\n      messagenode = dompack.create(\"div\", { className: \"wh-form__\" + type }); // add a wh-form__error or wh-form__suggestion message container\n      messagenode.id = messageid; // id to reference to in the aria-describedby\n      suggestionholder.appendChild(messagenode);\n    }\n\n    if (error) { // Do we show a message?\n      messagenode.replaceChildren(typeof error === \"string\" ? lineFeedsToBreaks(error) : error);\n      this._addDescribedBy(contextnode, messageid);\n\n      if (type === \"error\")\n        contextnode.setAttribute(\"aria-invalid\", \"true\");\n    } else {\n      messagenode.replaceChildren(); // remove previous errors/suggestions texts from the errornode\n      this._removeDescribedBy(contextnode, messageid);\n      contextnode.removeAttribute(\"aria-invalid\");\n    }\n\n  }\n\n  // add the specified id of the message element to the list of elements in aria-describedby\n  _addDescribedBy(contextnode: HTMLElement, messageid: string) {\n    const describedby = contextnode.getAttribute(\"aria-describedby\") ?? \"\";\n    const describedby_fields = describedby !== \"\" ? describedby.split(\" \") : [];\n\n    if (describedby_fields.indexOf(messageid) === -1) {\n\n      describedby_fields.push(messageid);\n      contextnode.setAttribute(\"aria-describedby\", describedby_fields.join(\" \"));\n    }\n  }\n\n  // remove the specified id of the message element from the list of elements in aria-describedby\n  _removeDescribedBy(contextnode: HTMLElement, messageid: string) {\n    const describedby = contextnode.getAttribute(\"aria-describedby\") ?? \"\";\n    const describedby_fields = describedby !== \"\" ? describedby.split(\" \") : [];\n\n    for (let idx = 0; idx < describedby_fields.length; idx++) {\n      if (describedby_fields[idx] === messageid) {\n        describedby_fields.splice(idx, 1); // remove that item\n        break;\n      }\n    }\n\n    if (describedby_fields.length > 0)\n      contextnode.setAttribute(\"aria-describedby\", describedby_fields.join(\" \"));\n    else\n      contextnode.removeAttribute(\"aria-describedby\");\n  }\n\n  _updateFieldGroupErrorState(field: HTMLElement) {\n    this._updateFieldGroupMessageState(field, 'error', failedfield => getValidationState(failedfield).getError());\n  }\n\n  _updateFieldGroupSuggestionState(field: HTMLElement) {\n    this._updateFieldGroupMessageState(field, 'suggestion', failedfield => failedfield.propWhValidationSuggestion || '');\n  }\n\n  _doSetFieldError(evt: DocEvent<CustomEvent<SetFieldErrorData>>) {\n    //FIXME properly handle multiple fields in this group reporting errors\n    dompack.stop(evt);\n\n\n    this._reportFieldValidity(evt.target);\n  }\n\n  /** @returns false on error */\n  _reportFieldValidity(node: HTMLElement): boolean {\n    const state = getValidationState(node).getState();\n    node.classList.toggle(\"wh-form__field--error\", Boolean(state?.error));\n    node.classList.toggle(\"wh-form__field--suggestion\", Boolean(state?.suggested));\n\n    this._updateFieldGroupErrorState(node);\n    this._updateFieldGroupSuggestionState(node);\n    return !(state && \"error\" in state);\n  }\n\n  //validate and submit. normal submissions should use this function, directly calling submit() skips validation and busy locking\n  async validateAndSubmit(extradata: ExtraData) {\n    await this._submit(null, extradata);\n  }\n\n  /** Override beforeSubmit to have a last chance to block/confirm actual form submission\n   * @returns true to continue submitting\n  */\n  beforeSubmit(extradata: ExtraData): boolean | Promise<boolean> {\n    return true;\n  }\n\n  async _submit(evt: SubmitEvent | null, extradata: ExtraData) {\n    if (this.node.classList.contains('wh-form--submitting') || this.inSubmit) { //already submitting\n      evt?.preventDefault(); //avoid 'No RPC handler installed' noise during 429 errors\n      return;\n    }\n\n    //A form element's default button is the first submit button in tree order whose form owner is that form element.\n    const submitter = this._submitter || this.node.querySelector(submitselector);\n    this._submitter = null;\n\n    if (debugFlags.fhv)\n      console.log('[fhv] received submit event, submitter:', submitter);\n\n    let tempbutton = null;\n    if (submitter) { //temporarily add a hidden field representing the selected button\n      tempbutton = document.createElement('input');\n      tempbutton.name = submitter.name;\n      tempbutton.value = submitter.value;\n      tempbutton.type = \"hidden\";\n      this.node.appendChild(tempbutton);\n    }\n\n    try {\n      this.inSubmit = true;\n      const beforeResult = this.beforeSubmit(extradata);\n      if (!beforeResult || (isPromise(beforeResult) && !await beforeResult))\n        return;\n\n      /* DEPRECATED - Switch to onBeforeSubmit in 5.7+ */\n      if (!dompack.dispatchCustomEvent(this.node, 'wh:form-beforesubmit', { bubbles: true, cancelable: true })) { //allow parsley to hook into us\n        console.error(\"The use of wh:form-beforesubmit is deprecated and will be removed in a future version. Use onBeforeSubmit instead\");\n        return;\n      }\n\n      await this._doSubmit(evt, extradata);\n    } finally {\n      tempbutton?.remove();\n      this.inSubmit = false;\n    }\n  }\n\n  private _shouldValidateField(el: HTMLElement) {\n    //TODO maybe we can get rid of the data attributes by checking for explicit symbols like whFormsApiChecker\n    return (el.whFormsApiChecker || el.matches(`${queryFormFieldLike},*[data-wh-form-name],*[data-wh-form-custom-validator`)) &&\n      this._isPartOfForm(el);\n  }\n\n  _getFieldsToValidate(startingpoint?: HTMLElement) {\n    return dompack.qSA<HTMLElement>(startingpoint ?? this.node, \"*\").filter(el => this._shouldValidateField(el));\n  }\n\n  //reset any serverside generated errors (generally done when preparing a new submission)\n  resetServerSideErrors() {\n    for (const field of this._getFieldsToValidate()) {\n      const state = getValidationState(field);\n      if (state?.explicit?.serverside && field.propWhCleanupFunction)\n        field.propWhCleanupFunction();\n    }\n  }\n\n  async _doSubmit(evt: SubmitEvent | null, extradata: ExtraData) {\n    if (evt)\n      evt.preventDefault();\n\n    const lock = dompack.flagUIBusy({ modal: true });\n    this._submitstart = Date.now();\n    this._submittimeout = setTimeout(() => this._submitHasTimedOut(), 5000);\n    this.node.classList.add('wh-form--submitting');\n\n    try {\n      this.resetServerSideErrors();\n\n      const validationresult = await this.validate();\n      if (validationresult.valid) {\n        const result = await this.submit(extradata);\n        if (result.result && result.result.submittype && result.result.submittype !== this._getVariableValueForConditions(\"formsubmittype\")) {\n          this.node.setAttribute(\"data-wh-form-var-formsubmittype\", result.result.submittype);\n          this._updateConditions(false);\n        }\n      } else {\n        this.sendFormEvent({ event: \"failed\", errorfields: getErrorFields(validationresult), errorsource: 'client' });\n      }\n    } finally {\n      lock.release();\n      this.node.classList.remove('wh-form--submitting');\n      if (this._submittimeout) {\n        clearTimeout(this._submittimeout);\n        this._submittimeout = undefined;\n      }\n      this._submitstart = undefined;\n    }\n  }\n\n  _submitHasTimedOut() { //TODO extend this to (background) RPCs too, and make waitfor more specific. also check whether we're stuck on client or server side\n    this.sendFormEvent({ event: \"slow\", waitfor: \"submit\" });\n  }\n\n  //default submission function. eg. RPC will override this\n  async submit(extradata?: ExtraData): Promise<{ result?: FormSubmitEmbeddedResult }> {\n    this.node.submit();\n    return {};\n  }\n\n  _onTakeFocus(evt: DocEvent<TakeFocusEvent>) {\n    const containingpage = evt.target.closest('.wh-form__page');\n    if (containingpage && containingpage.classList.contains('wh-form__page--hidden')) {\n      //make sure the page containing the errored component is visible\n      const pagenum = dompack.qSA(this.node, '.wh-form__page').findIndex(page => page === containingpage);\n      if (pagenum >= 0)\n        this.gotoPage(pagenum);\n    }\n  }\n\n  _checkClick(evt: DocEvent<MouseEvent>) {\n    const actionnode = evt.target?.closest<HTMLElement>(\"*[data-wh-form-action]\");\n    if (!actionnode) {\n      const submitter = evt.target.closest<SubmitSelectorType>(submitselector);\n      if (submitter?.form === this.node) { //if we found the submit buton AND it's for *this* form. don't intercept otherwise\n        if (!this.node.classList.contains('wh-form--allowsubmit')) { //we're not allowed to submit yet (not on a final page)\n          dompack.stop(evt);\n          if (this.node.classList.contains('wh-form--allownext'))  //but we can convert your action to a NextPage! which is likely what you intended\n            this.executeFormAction('next');\n          return;\n        }\n\n        this._submitter = submitter; //store as submitter in case a submit event actually occurs\n        setTimeout(() => this._submitter = null); //but clear it as soon as event processing ends\n      }\n      return;\n    }\n\n    dompack.stop(evt);\n    this.executeFormAction(actionnode.dataset.whFormAction!);\n  }\n\n  private _getPageState(): PageState {\n    const pages = dompack.qSA<HTMLElement>(this.node, '.wh-form__page');\n    const curpage = pages.findIndex(page => !page.classList.contains('wh-form__page--hidden'));\n    return { pages, curpage };\n  }\n\n  _updatePageVisibility(pagelist: HTMLElement[], currentpage: number) {\n    pagelist.forEach((page, idx) => {\n      page.classList.toggle('wh-form__page--hidden', idx !== currentpage);\n      page.classList.toggle('wh-form__page--visible', idx === currentpage);\n    });\n  }\n\n  ///Get the currently opened page (page node)\n  getCurrentPage() {\n    const state = this._getPageState();\n    return state.curpage >= 0 ? state.pages[state.curpage] : null;\n  }\n\n  /** Position the specified element's group or the form itself into view, using `.wh-anchor` nodes to correct for fixed headers\n      @param scrollto -  Element to position into view. If not set, the form it scrolled into view */\n  scrollIntoView(scrollto?: HTMLElement) {\n    const origscrollto = scrollto;\n    scrollto = (scrollto ? scrollto.closest<HTMLElement>('.wh-form__fieldgroup') : undefined) || this.node;\n    scrollto = scrollto.querySelector<HTMLElement>('.wh-anchor') || scrollto;\n    if (origscrollto && scrollto !== origscrollto && debugFlags.fhv)\n      console.log('[fhv] Modified scroll target from ', origscrollto, ' to anchor ', scrollto);\n    else if (debugFlags.fhv)\n      console.log('[fhv] Scroll to ', scrollto);\n\n    scrollto.scrollIntoView();\n  }\n\n  /** Get the current page number\n      @returns 0-based index of page to jump to */\n  getCurrentPageNumber() {\n    return this._getPageState().curpage;\n  }\n\n  /** Goto a specific page\n      @param page - 0-based index of page or the HTML element of the page to jump to */\n  async gotoPage(page: number | HTMLElement, { __isSubmit = false } = {}): Promise<void> {\n    const state = this._getPageState();\n    const pageidx = getPageIdx(state, page);\n    if (state.curpage === pageidx)\n      return;\n\n    const goingforward = pageidx > state.curpage;\n    if (!__isSubmit)\n      this.sendFormEvent({\n        event: goingforward ? __isSubmit ? 'submitted' : 'nextpage' : 'previouspage',\n        targetpagenum: pageidx + 1,\n        targetpagetitle: this._getPageTitle(pageidx)\n      });\n\n    this._updatePageVisibility(state.pages, pageidx);\n    if (goingforward) //only makes sense to update if we're making progress\n      merge.run(state.pages[pageidx], { form: await this.getFormValue() });\n\n    this._updatePageNavigation();\n\n    //scroll back up\n    this.scrollIntoView();\n\n    /* tell the page it's now visible - note that we specifically don't fire this on init, as it's very likely\n       users would 'miss' the event anyway - registerHandler usually executes faster than your wh:form-pagechange\n       registrations, if you wrapped those in a dompack.register */\n    dompack.dispatchCustomEvent(state.pages[pageidx], \"wh:form-pagechange\", { bubbles: true, cancelable: false, detail: { formHandler: this } });\n  }\n\n  private _getDestinationPage(pagestate: PageState, direction: number) {\n    let pagenum = pagestate.curpage + direction;\n    //TODO \"captcha\" should no longer exist since WH5.9 - unless there are still some static published forms around, so keep skipping them for a while\n    while (pagenum >= 0 && pagenum < pagestate.pages.length && (pagestate.pages[pagenum].propWhFormCurrentVisible === false || pagestate.pages[pagenum].dataset.whFormPagerole === \"captcha\"))\n      pagenum = pagenum + direction;\n    if (pagenum < 0 || pagenum >= pagestate.pages.length)\n      return -1;\n    return pagenum;\n  }\n\n  _getPageTitle(pagenum: number) {\n    const pagenode = this._getPageState().pages[pagenum];\n    if (!pagenode)\n      return \"\";\n    return pagenode.dataset.whFormPagetitle || (\"#\" + (pagenum + 1));\n  }\n\n  async executeFormAction(action: string) {\n    switch (action) {\n      case 'previous':\n        {\n          if (this.node.classList.contains('wh-form--allowprevious')) {\n            const pagestate = this._getPageState();\n            if (pagestate.curpage > 0)\n              this.gotoPage(this._getDestinationPage(pagestate, -1));\n            else if (this.node.dataset.whFormBacklink)\n              navigateTo({ type: \"redirect\", url: this.node.dataset.whFormBacklink });\n          }\n          return;\n        }\n      case 'next':\n        {\n          const pagestate = this._getPageState();\n          if (this.node.classList.contains('wh-form--allownext')) {\n            this.resetServerSideErrors();\n\n            const validationstatus = await this.validate(pagestate.pages[pagestate.curpage]);\n            if (validationstatus.valid) {\n              this.gotoPage(this._getDestinationPage(pagestate, +1));\n            } else {\n              this.sendFormEvent({ event: \"failed\", errorfields: getErrorFields(validationstatus), errorsource: 'nextpage' });\n            }\n          }\n          return;\n        }\n      case 'exit': {\n        if (!this.exitButtonNavigateTo)\n          throw new Error(\"No exit navigation target set for this form\");\n\n        navigateTo(this.exitButtonNavigateTo);\n        return;\n      }\n      default: {\n        console.error(`Unknown form action '${action}'`);\n      }\n    }\n  }\n\n  async refreshConditions() {\n    await this._updateConditions(false);\n  }\n\n  _onInputChange() {\n    this.sendFormEvent(); //only trigger implicit _firstinteraction event\n    this._updateConditions(false);\n  }\n\n  async _updateConditions(isinit: boolean) {\n    // Check pages visibility\n    const hiddenPages = [];\n    const mergeNodes = [];\n    let anychanges = false;\n\n    for (const formpage of dompack.qSA(this.node, \".wh-form__page\")) {\n      let visible = true;\n      if (formpage.dataset.whFormVisibleIf) {\n        visible = this._matchesCondition(formpage.dataset.whFormVisibleIf);\n        if (!visible)\n          hiddenPages.push(formpage); // We don't have to check fields on this page any further\n\n        if (visible !== formpage.propWhFormCurrentVisible) {\n          anychanges = true;\n          formpage.propWhFormCurrentVisible = visible;\n          mergeNodes.push(formpage);\n        }\n      }\n    }\n    if (anychanges)\n      this._updatePageNavigation();\n\n    const tovalidate = new Array<HTMLElement>;\n    const hiddengroups = [], enabledgroups = [], requiredgroups = [];\n    for (const formgroup of dompack.qSA(this.node, \".wh-form__fieldgroup\")) {\n      const groupPage = formgroup.closest<HTMLElement>(\".wh-form__page\");\n      const visible = (!groupPage || !hiddenPages.includes(groupPage)) && this._matchesCondition(formgroup.dataset.whFormVisibleIf);\n      if (!visible)\n        hiddengroups.push(formgroup);\n\n      const enabled = visible\n        && this._matchesCondition(formgroup.dataset.whFormEnabledIf);\n\n      if (enabled)\n        enabledgroups.push(formgroup);\n\n      //load initial status?\n      if (formgroup.propWhFormInitialRequired === undefined)\n        formgroup.propWhFormInitialRequired = formgroup.classList.contains(\"wh-form__fieldgroup--required\");\n\n      const required = enabled\n        && (formgroup.dataset.whFormRequiredIf ? this._matchesCondition(formgroup.dataset.whFormRequiredIf) : formgroup.propWhFormInitialRequired);\n\n      if (required)\n        requiredgroups.push(formgroup);\n\n      if (visible !== formgroup.propWhFormCurrentVisible // These are initially undefined, so this code will always run first time\n        || enabled !== formgroup.propWhFormCurrentEnabled\n        || required !== formgroup.propWhFormCurrentRequired) {\n        formgroup.propWhFormCurrentVisible = visible;\n        formgroup.propWhFormCurrentEnabled = enabled;\n        formgroup.propWhFormCurrentRequired = required;\n\n        formgroup.classList.toggle(\"wh-form__fieldgroup--disabled\", !enabled);\n        formgroup.classList.toggle(\"wh-form__fieldgroup--hidden\", !visible);\n        formgroup.classList.toggle(\"wh-form__fieldgroup--required\", required);\n\n        mergeNodes.push(formgroup);\n      }\n    }\n\n    for (const formline of dompack.qSA(this.node, \".wh-form__fieldline\")) {\n      const formgroup = formline.closest<HTMLElement>(\".wh-form__fieldgroup\");\n      if (!formgroup)\n        continue;\n      const visible = !hiddengroups.includes(formgroup) && this._matchesCondition(formline.dataset.whFormVisibleIf);\n      const enabled = visible && enabledgroups.includes(formgroup) && this._matchesCondition(formline.dataset.whFormEnabledIf);\n      const required = enabled && requiredgroups.includes(formgroup);\n\n      if (visible !== formline.propWhFormlineCurrentVisible) {  // These are initially undefined, so this code will always run first time\n        formline.propWhFormlineCurrentVisible = visible;\n        formline.classList.toggle(\"wh-form__fieldline--hidden\", !visible);\n      }\n\n      // Look for nodes that are explicit enable state (enablee/require) listeners, or that need to do so because they're real input controls\n      const inputtargets = dompack.qSA(formline, `${queryFormFieldLike},[data-wh-form-state-listener='true']`);\n\n      for (const node of inputtargets) {\n        //Record initial states\n        if (!node.dataset.whFormSavedEnabled)\n          node.dataset.whFormSavedEnabled = (\"disabled\" in node ? !node.disabled : !(\"whFormDisabled\" in node.dataset)).toString();\n\n        if (!node.dataset.whFormSavedRequired)\n          node.dataset.whFormSavedRequired = Boolean(\"required\" in node && node.required).toString();\n\n        // The field is enabled if all of these are matched:\n        // - we're setting it to enabled now\n        // - it hasn't been disabled explicitly (set initially on the node)\n        // - it hasn't been disabled through enablecomponents\n        const node_enabled = enabled && node.dataset.whFormSavedEnabled === \"true\" && this._matchesCondition(node.dataset.whFormEnabledIf);\n\n        /* TODO ideally we'd eliminate 'current enabled/required' states, but we need them as long as some components intercept wh:form-enable and wh:form-require events\n                to know the state we told them to put the component in. we may be able to eliminate those events */\n        //if node.dataset.whFormCurrentEnabled is unset, we may still need to apply disabled state to a fresh field\n        if (!node.dataset.whFormCurrentEnabled || node_enabled !== (node.dataset.whFormCurrentEnabled === \"true\")) {\n          node.dataset.whFormCurrentEnabled = node_enabled ? \"true\" : \"false\";\n\n          // Give the formgroup a chance to handle it\n          if (dompack.dispatchCustomEvent(node, \"wh:form-enable\", { bubbles: true, cancelable: true, detail: { enabled: node_enabled } })) {\n            // Not cancelled, so run our default handler\n            if (isFormFieldLike(node)) //For true html5 inputs we'll use the native attributes. formstatelisteners: we use data attributes\n              node.disabled = !node_enabled;\n            else if (node_enabled)\n              node.removeAttribute(\"data-wh-form-disabled\");\n            else\n              node.setAttribute(\"data-wh-form-disabled\", \"\");\n          }\n\n          if (!isinit && !node_enabled && !tovalidate.includes(node))\n            tovalidate.push(node); // to clear errors for this disabled field\n        }\n\n        const node_required = (node.dataset.whFormSavedRequired === \"true\" || required) && node_enabled && visible;\n        //if node.dataset.whFormCurrentEnabled is unset, we may still need to apply disabled state to a fresh field\n        //if node.dataset.whFormCurrentRequired is unset, we may still need to apply required state to a fresh field\n        if (!node.dataset.whFormCurrentRequired || node.dataset.whFormCurrentRequired !== (node_required ? \"true\" : \"false\")) {\n          node.dataset.whFormCurrentRequired = node_required ? \"true\" : \"false\";\n\n          // Give the formgroup a chance to handle it\n          if (dompack.dispatchCustomEvent(node, \"wh:form-require\", { bubbles: true, cancelable: true, detail: { required: node_required } })) {\n            // Not cancelled, so run our default handler\n            if (isFormFieldLike(node)) { //For true html5 inputs we'll use the native attributes. formstatelisteners: we use data attributes\n              if (!isFormControl(node) || node.type !== 'checkbox') //don't set required on checkboxes, that doesn't do what you want\n                node.required = node_required;\n            } else if (node_required)\n              node.setAttribute(\"data-wh-form-required\", \"\");\n            else\n              node.removeAttribute(\"data-wh-form-required\");\n          }\n\n          if (!isinit && !node_required && formgroup.classList.contains(\"wh-form__fieldgroup--error\") && !tovalidate.includes(node))\n            tovalidate.push(node); // to clear errors for this now optional field\n        }\n      }\n    }\n\n    for (const option of dompack.qSA<HTMLOptionElement>(this.node, \".wh-form__fieldgroup select option\")) {\n      const visible = this._matchesCondition(option.dataset.whFormVisibleIf);\n\n      //Record initial states\n      if (!option.dataset.whFormSavedEnabled)\n        option.dataset.whFormSavedEnabled = (!option.disabled).toString();\n      if (!option.dataset.whFormSavedHidden)\n        option.dataset.whFormSavedHidden = option.hidden.toString();\n\n      const option_enabled = visible && option.dataset.whFormSavedEnabled === \"true\";\n      const option_hidden = !visible || option.dataset.whFormSavedHidden === \"true\";\n\n      if (option_enabled !== (option.dataset.whFormCurrentEnabled === \"true\") || option_hidden !== (option.dataset.whFormCurrentHidden === \"true\")) {\n        option.dataset.whFormCurrentEnabled = option_enabled ? \"true\" : \"false\";\n        option.dataset.whFormCurrentHidden = option_hidden ? \"true\" : \"false\";\n        option.disabled = !option_enabled;\n        option.hidden = option_hidden;\n\n        // If this option was the selected option, but is now disabled (but not the placeholder), reset the select's value\n        const selectnode = option.closest<HTMLSelectElement>(\"select\");\n        if (selectnode && option.selected && (!option_enabled || option_hidden) && option.dataset.placeholder === undefined) {\n          if (selectnode.options[0].dataset.placeholder !== undefined) { //we have a placeholder...\n            selectnode.selectedIndex = 0;\n          } else {\n            selectnode.selectedIndex = -1;\n            if (!selectnode.__didPlaceholderWarning) {\n              selectnode.__didPlaceholderWarning = true;\n              console.warn(\"This <select> lacks an explicit placeholder so we had to set selectedIndex to -1\", selectnode);\n            }\n          }\n        }\n\n        if (selectnode && !isinit && !tovalidate.includes(selectnode))\n          tovalidate.push(selectnode); // to clear errors for this option's select field\n      }\n    }\n\n    if (tovalidate.length)\n      await this.validate(tovalidate, { focusfailed: false, iffailedbefore: true });\n\n    this.fixupMergeFields(mergeNodes);\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-misused-promises -- FIXME: needs API rework\n  __scheduleUpdateConditions = wrapSerialized(() => this._updateConditions(false), { coalesce: true });\n\n  async fixupMergeFields(nodes: HTMLElement[]) {\n    // Rename the data-wh-merge attribute to data-wh-dont-merge on hidden pages and within hidden formgroups to prevent\n    // merging invisible nodes\n    // FIXME 'merge' has a filter option now - convert to that!\n    const formvalue = await this.getFormValue();\n    for (const node of nodes) {\n      if (node.propWhFormCurrentVisible) {\n        for (const mergeNode of dompack.qSA(node, '*[data-wh-dont-merge]')) {\n          mergeNode.dataset.merge = mergeNode.dataset.whDontMerge;\n          mergeNode.removeAttribute(\"data-wh-dont-merge\");\n        }\n        merge.run(node, { form: formvalue });\n      } else {\n        for (const mergeNode of dompack.qSA(node, '*[data-merge]')) {\n          mergeNode.dataset.whDontMerge = mergeNode.dataset.merge;\n          mergeNode.removeAttribute(\"data-merge\");\n        }\n      }\n    }\n  }\n\n  _matchesCondition(conditiontext: string | undefined) {\n    if (!conditiontext)\n      return true;\n\n    return this._matchesConditionRecursive(parseCondition(conditiontext));\n  }\n\n  _getConditionRawValue(fieldname: string, options?: { checkdisabled?: boolean }) {\n    if (this.node.hasAttribute(\"data-wh-form-var-\" + fieldname))\n      return this.node.getAttribute(\"data-wh-form-var-\" + fieldname);\n\n    const matchfield = this.getElementByName(fieldname);\n    if (!matchfield) {\n      console.error(`No match for conditional required field '${fieldname}'`);\n      return null;\n    }\n\n    if (isRadioNodeList(matchfield)) {\n      let currentvalue = null;\n\n      for (const field of matchfield)\n        if (((options && options.checkdisabled) || this._isNowSettable(field)) && field.checked) {\n          if (field.type !== \"checkbox\")\n            return field.value;\n\n          if (!currentvalue)\n            currentvalue = [];\n          currentvalue.push(field.value);\n        }\n      return currentvalue;\n    } else {\n      //Can we set this field?\n      if ((!options || !options.checkdisabled) && !this._isNowSettable(matchfield))\n        return null;\n    }\n\n    if (matchfield.type === \"checkbox\")\n      return (matchfield as HTMLInputElement).checked ? [matchfield.value] : null;\n\n    if (matchfield.type === \"radio\")\n      return (matchfield as HTMLInputElement).checked ? matchfield.value : null;\n\n    return matchfield.value;\n  }\n\n  _getVariableValueForConditions(conditionfield: string, options?: { matchcase?: boolean; checkdisabled?: boolean }) {\n    if (this.node.hasAttribute(\"data-wh-form-var-\" + conditionfield))\n      return this.node.getAttribute(\"data-wh-form-var-\" + conditionfield);\n\n    const fields = conditionfield.split(\"$\");\n\n    if (fields.length > 1) {\n      // If the condition field has a subfield, check if it's available through a form var\n      // The '$' in the attribute name is replaced with '.' to make the attribute name valid\n      const attrname = fields.join(\".\");\n      if (this.node.hasAttribute(\"data-wh-form-var-\" + attrname))\n        return this.node.getAttribute(\"data-wh-form-var-\" + attrname);\n    }\n\n    let currentvalue = this._getConditionRawValue(fields[0], options);\n    if (fields.length === 1 || currentvalue === null) //no subs to process\n      return currentvalue;\n\n    // Look for an extrafield match\n    const matchfield = this.getElementByName(fields[0]);\n    if (!matchfield) {\n      console.error(`No match for conditional required field '${conditionfield}'`);\n      return null;\n    }\n\n    if (matchfield instanceof HTMLSelectElement) {\n      if (Array.isArray(currentvalue)) {\n        const selectedvalue = currentvalue;\n        currentvalue = [];\n        for (const val of selectedvalue) {\n          const selected = dompack.qS<HTMLOptionElement>(matchfield, `option[value=\"${CSS.escape(val)}\"]`);\n          if (!selected?.dataset.__extrafields)\n            return null;\n          const extrafields = JSON.parse(selected.dataset.__extrafields);\n          currentvalue.push(extrafields[fields[1]]);\n        }\n      } else {\n        const selected = dompack.qS<HTMLOptionElement>(matchfield, `option[value=\"${CSS.escape(currentvalue)}\"]`);\n        if (!selected?.dataset.__extrafields)\n          return null;\n        const extrafields = JSON.parse(selected.dataset.__extrafields);\n        currentvalue = extrafields[fields[1]];\n      }\n      return currentvalue;\n    } else {\n      console.error(\"Subfield matching not supported for non-select fields\");\n      return null;\n    }\n  }\n\n\n  _matchesConditionRecursive(condition: FormCondition): boolean {\n    switch (condition.matchtype) {\n      case \"AND\":\n        for (const subcondition of condition.conditions)\n          if (!this._matchesConditionRecursive(subcondition))\n            return false;\n        return true;\n\n      case \"OR\":\n        for (const subcondition of condition.conditions)\n          if (this._matchesConditionRecursive(subcondition))\n            return true;\n        return false;\n\n      case \"NOT\":\n        return !this._matchesConditionRecursive(condition.condition);\n\n      case \"AGE<\":\n      case \"AGE>=\": {\n        const currentvalue = this._getVariableValueForConditions(condition.field);\n        if (!currentvalue)\n          return false;\n\n        const now = new Date, birthdate = new Date(Array.isArray(currentvalue) ? currentvalue[0] : currentvalue); //should never be an array, but _getVariableValueForConditions is generic\n        let age = now.getFullYear() - birthdate.getFullYear();\n        //birthdate not hit yet this year? then you lose a year\n        if (now.getMonth() < birthdate.getMonth()\n          || (now.getMonth() === birthdate.getMonth() && now.getDate() < birthdate.getDate())) {\n          --age;\n        }\n\n        return (condition.matchtype === 'AGE<' ? age < condition.value : age >= condition.value);\n      }\n    }\n\n    const currentvalue = this._getVariableValueForConditions(condition.field, condition.options);\n\n    if (condition.matchtype === \"HASVALUE\")\n      return Boolean(currentvalue) === Boolean(condition.value);\n\n    if ([\"IN\", \"HAS\", \"IS\"].includes(condition.matchtype)) {\n      const matchcase = condition.options?.matchcase !== false; // Defaults to true\n      const compareagainst = Array.isArray(condition.value) ? condition.value : condition.value ? [condition.value] : [];\n      const currentValArray: string[] = Array.isArray(currentvalue) ? currentvalue : currentvalue ? [currentvalue] : [];\n\n      // If the match is not case-sensitive, the condition value is already uppercased, so we only have to uppercase the\n      // current value(s) when checking\n      if (!matchcase)\n        currentValArray.forEach((_, idx) => currentValArray[idx] = currentValArray[idx].toUpperCase());\n\n      // The current value and the condition value should (at least) overlap\n      if (!currentValArray.some(value => compareagainst.includes(value)))\n        return false;\n\n      // For \"HAS\" and \"IS\" conditions, all of the required values should be selected (there shouldn't be required values\n      // that are not selected)\n      if ((condition.matchtype === \"HAS\" || condition.matchtype === \"IS\") && compareagainst.some(value => !currentValArray.includes(value)))\n        return false;\n\n      // For an \"IS\" condition, all of the selected values should be required (there shouldn't be selected values that are\n      // not required)\n      if (condition.matchtype === \"IS\" && currentValArray.some(value => !compareagainst.includes(value)))\n        return false;\n\n      return true;\n    }\n\n    return console.error(`No support for conditional type '${condition.matchtype}'`), false;\n  }\n\n  _updatePageNavigation() {\n    const pagestate = this._getPageState();\n    const nextpage = this._getDestinationPage(pagestate, +1);\n    const morepages = nextpage !== -1;\n    const curpagerole = pagestate.pages[pagestate.curpage] ? pagestate.pages[pagestate.curpage].dataset.whFormPagerole : '';\n    const nextpagerole = morepages ? pagestate.pages[nextpage].dataset.whFormPagerole : \"\";\n\n    this.node.classList.toggle(\"wh-form--allowprevious\", Boolean((pagestate.curpage > 0 && curpagerole !== 'thankyou') || (pagestate.curpage <= 0 && this.node.dataset.whFormBacklink)));\n    this.node.classList.toggle(\"wh-form--allownext\", morepages && nextpagerole !== 'thankyou');\n    this.node.classList.toggle(\"wh-form--allowsubmit\", curpagerole === 'thankyou'\n      ? pagestate.pages[pagestate.curpage].dataset.whFormExitButton !== undefined\n      : (!morepages || nextpagerole === 'thankyou'));\n\n    // Also handle the thank you page preparation (changing submit labels, redirecting if necessary)\n    this._prepareThankYouPage(pagestate.curpage);\n  }\n\n  _prepareThankYouPage(nextpage: number) {\n    const state = this._getPageState();\n    if (nextpage !== -1 && state.pages[nextpage] && state.pages[nextpage].dataset.whFormPagerole === 'thankyou') {\n      const rawNavigateTo = state.pages[nextpage].dataset.whFormNavigateTo;\n      const exitButton = state.pages[nextpage].dataset.whFormExitButton;\n      const parsedNavTo = rawNavigateTo ? JSON.parse(rawNavigateTo) : null;\n      if (parsedNavTo)\n        this.exitButtonNavigateTo = parsedNavTo;\n\n      const redirectdelay = parseInt(state.pages[nextpage].dataset.whFormPageredirectDelay ?? \"\");\n\n      if (exitButton) {\n        const submitButton = this.node.querySelector<HTMLElement>(\".wh-form__button--submit\");\n        const submitButtonLabel = submitButton?.querySelector<HTMLElement>(\".wh-form__buttonlabel\");\n        if (submitButton && submitButtonLabel) {\n          submitButton.dataset.whFormAction = \"exit\";\n          submitButtonLabel.textContent = exitButton;\n        } else {\n          console.error(`Unable to find the submit button '.wh-form__button--submit .wh-form__buttonlabel' - I need to replace its label with '${exitButton}'!`);\n        }\n      }\n\n      if (parsedNavTo && !(redirectdelay >= 0) && !exitButton) {\n        navigateTo(parsedNavTo);\n        return;\n      }\n\n      if (parsedNavTo && redirectdelay >= 0) {\n        // If redirectdelay==0 (redirect immediately, while showing the thank you page), redirect after a small delay to\n        // give the browser time to hide the busy layer\n        // Might be caused by this: https://stackoverflow.com/a/60439478\n        setTimeout(() => navigateTo(parsedNavTo), redirectdelay * 1000 || 100);\n      }\n    }\n  }\n\n  _navigateToThankYou(richvalues?: RichValues) {\n    const state = this._getPageState();\n\n    if (state.curpage >= 0) {\n      const nextpage = this._getDestinationPage(state, +1);\n      if (nextpage !== -1 && state.pages[nextpage] && state.pages[nextpage].dataset.whFormPagerole === 'thankyou') {\n        this.updateRichValues(state.pages[nextpage], richvalues);\n        this.gotoPage(nextpage, { __isSubmit: true });\n      }\n    }\n  }\n  updateRichValues(page: HTMLElement, richvalues?: RichValues) {\n    if (richvalues) {\n      for (const { field, value } of richvalues) {\n        const node = page.querySelector(`.wh-form__fieldgroup--richtext[data-wh-form-group-for=\"${CSS.escape(field)}\"] .wh-form__richtext`);\n        if (node) {\n          node.innerHTML = value;\n          dompack.registerMissed(node);\n        }\n      }\n    }\n  }\n\n  private ensureLegacyWarning(field: HTMLElement) {\n    if (!this.didLegacyWarning && dtapStage !== \"production\")\n      console.warn(`[form] ${getFieldDisplayName(field)} is using wh:form-getvalue/wh:form-setvalue events. It should switch to JSFormElement`);\n\n    this.didLegacyWarning = true;\n  }\n\n  /* Override this to overwrite the processing of individual fields. Note that\n     radio and checkboxes are not passed through getFieldValue, and that\n     getFieldValue may return undefined or a promise. */\n  async getFieldValue(field: HTMLElement) {\n    if (field[rfSymbol])\n      return field[rfSymbol].getValue();\n\n    if (field.hasAttribute('data-wh-form-name') || field.whUseFormGetValue) {\n      //create a deferred promise for the field to fulfill\n      const deferred = Promise.withResolvers<unknown>();\n      //if cancelled, we'll assume the promise is taken over\n      if (!dompack.dispatchCustomEvent(field, 'wh:form-getvalue', { bubbles: true, cancelable: true, detail: { deferred } })) {\n        this.ensureLegacyWarning(field);\n        return deferred.promise;\n      }\n    }\n    if (!isFormFieldLike(field)) {\n      /* Can't fail on these, weird embeddings do weird things. Eg google's recaptcha v2 triggers this because it assigns a random name=\n         to the iframe it injects and then we pick that up.. (may need to move this error behind a debugflag if that's the only likely cause) */\n      if (debugFlags.fhv)\n        console.log(`[fhv] Cannot get value on non-FormControl`, field);\n      return undefined; //TODO throw? but wasn't currently fatal\n    }\n\n    if (field.matches('input[type=file]')) //We don't care for multiple yet, as our form RPC APIs don't support that either\n      return [...(field as HTMLInputElement).files || []].map(file => ({ fileName: file.name, file: file, link: null })) satisfies FormFileValue[];\n\n    return field.value;\n  }\n\n  /* Override this to overwrite the setting of individual fields. In contrast\n     to getFieldValue, this function will also be invoked for radio and checkboxes */\n  setFieldValue(fieldnode: HTMLElement, value: unknown) {\n    if (fieldnode[rfSymbol])\n      return fieldnode[rfSymbol].setValue(value);\n\n    if (fieldnode.hasAttribute('data-wh-form-name')) {\n      if (!dompack.dispatchCustomEvent(fieldnode, 'wh:form-setvalue', { bubbles: true, cancelable: true, detail: { value } })) {\n        this.ensureLegacyWarning(fieldnode);\n        return;\n      }\n      // Event is not cancelled, set node value directly\n    }\n\n    if (!isFormFieldLike(fieldnode)) {\n      console.error(`Cannot set value on non-FormControl`, fieldnode, value);\n      return; //TODO throw? but wasn't currently fatal\n    }\n\n    //NOTE this blocks a lot of 'new sets' being done through setFieldValue, eg resetting an array by setting it to []. which is fine for me, just use the data proxy..\n    if (typeof value !== \"string\" && typeof value !== \"number\" && typeof value !== \"boolean\") {\n      console.error(`Setting value of type ${typeof value} on a FormControl`, fieldnode, value);\n      return; //TODO throw? but wasn't currently fatal\n    }\n\n    const saveInteractive = this.isInteractive;\n    try {\n      this.isInteractive = false;\n      if (isFormControl(fieldnode))\n        dompack.changeValue(fieldnode, value);\n      else\n        fieldnode.value = value;\n    } finally {\n      this.isInteractive = saveInteractive;\n    }\n  }\n\n  _isPartOfForm(el: HTMLElement) {\n    //In HTML terms, an input must either have *no* form attribute or explicitly point to us. eg <input form> is *outside* a form\n    //However nodes may live in fragments (eg arrayedits) that are not in the DOM and not attached anywhere, so we also consider anything outside the DOM to be in our form...\n    return !(\"form\" in el) || el.form === this.node || !document.contains(el)\n      || (!this.node && !el.hasAttribute(\"form\")); //FIXME remove this workaround needed now to work around form init race where arrayfields try to use _queryAllFields\n  }\n\n  _queryAllFields(options?: {\n    skiparraymembers?: boolean;\n    skipfield?: HTMLElement;\n    onlysettable?: boolean;\n    startnode?: HTMLElement;\n  }): FormControlDescription[] {\n    const foundfields = new Array<FormControlDescription>;\n    const skiparraymembers = options && options.skiparraymembers;\n\n    for (const field of this._getFieldsToValidate(options?.startnode)) {\n      if (options && field === options.skipfield) //arrayfield.es needs it\n        continue;\n      if (!this._isPartOfForm(field))\n        continue;\n      if (options && options.onlysettable && !this._isNowSettable(field))\n        continue;\n      if (skiparraymembers && field.closest(\".wh-form__arrayrow\"))\n        continue;\n\n      const name = getFieldName(field);\n      if (!name)\n        continue;\n\n      let addto = foundfields.find(_ => _.name === name);\n      if (isRadioOrCheckbox(field)) { //expect multiple inputs with this name?\n        if (!addto) {\n          addto = { name: name, multi: true, nodes: [] };\n          foundfields.push(addto);\n        } else if (!addto.multi) {\n          console.error(`[fhv] Encountered duplicate field '${name}'`, field);\n          continue;\n        }\n        addto.nodes.push(field);\n      } else {\n        if (addto) {\n          console.error(`[fhv] Encountered duplicate field '${name}'`, field);\n          continue;\n        }\n\n        foundfields.push({ name: name, multi: false, node: field });\n      }\n    }\n\n    return foundfields;\n  }\n\n  /** Return the names of all form elements */\n  getFormElementNames() {\n    return this._queryAllFields().map(_ => _.name);\n  }\n\n  /** getValue from a field as returned by _queryAllFields (supporting both multilevel and plain fields)\n      @returns promise */\n  _getQueryiedFieldValue(field: FormControlDescription) {\n    if (!field.multi)\n      return this.getFieldValue(field.node);\n\n    return field.nodes.filter(node => node.checked).map(node => node.value);\n  }\n\n  /** Return a promise resolving to the submittable form value */\n  async getFormValue(): Promise<FormResultValue> {\n    const outdata: FormResultValue = {};\n    const fieldpromises = new Array<Promise<void>>;\n\n    for (const field of this._queryAllFields({ onlysettable: true, skiparraymembers: true }))\n      this._processFieldValue(outdata, fieldpromises, field.name, this._getQueryiedFieldValue(field));\n\n    await Promise.all(fieldpromises);\n    return outdata;\n  }\n\n  _isNowSettable(node: HTMLElement) {\n    // If the node is disabled, it's not settable\n    if (\"disabled\" in node && node.disabled)\n      return false;\n\n    // If the node's field group is disabled or hidden, it's not settable\n    const formgroup = node.closest(\".wh-form__fieldgroup\");\n    if (formgroup) {\n      if (formgroup.classList.contains(\"wh-form__fieldgroup--disabled\"))\n        return false;\n      if (formgroup.classList.contains(\"wh-form__fieldgroup--hidden\"))\n        return false;\n    }\n\n    // If the node's form page is hidden dynamically, it's not settable\n    const formpage = node.closest<HTMLElement>(\".wh-form__page\");\n    if (formpage) {\n      if (formpage.propWhFormCurrentVisible === false)\n        return false;\n    }\n    // The node is settable\n    return true;\n  }\n\n  _processFieldValue(outdata: FormResultValue, fieldpromises: Array<Promise<void>>, fieldname: string, receivedvalue: unknown) {\n    if (receivedvalue === undefined)\n      return;\n    if (isPromise(receivedvalue)) {\n      fieldpromises.push(new Promise<void>((resolve, reject) => {\n        receivedvalue.then(result => {\n          if (result !== undefined)\n            outdata[fieldname] = result;\n\n          resolve();\n        }).catch(e => reject(e as Error));\n      }));\n    } else {\n      outdata[fieldname] = receivedvalue;\n    }\n  }\n\n  //get the option lines associated with a specific radio/checkbox group\n  getOptions(name: string) {\n    const nodes = this.getElementByName(name);\n    if (!(nodes instanceof RadioNodeList))\n      return [];\n\n    return [...nodes].map(node => ({\n      inputnode: node,\n      fieldline: node.closest<HTMLElement>('.wh-form__fieldline'),\n      value: node.value\n    }));\n  }\n\n  /** gets the selected option associated with a radio/checkbox group as an array\n      */\n  getSelectedOptions(name: string) {\n    let opts = this.getOptions(name);\n    opts = opts.filter(node => node.inputnode.checked);\n    return opts;\n  }\n\n  /** get the selected option associated with a radio/checkbox group. returns an object that's either null or the first selected option\n      */\n  getSelectedOption(name: string) {\n    const opts = this.getSelectedOptions(name);\n    return opts.length ? opts[0] : null;\n  }\n\n  /** get the fieldgroup for an element */\n  getFieldGroup(name: string): HTMLElement | null {\n    let node = this.getElementByName(name);\n    if (node instanceof RadioNodeList)\n      node = node[0];\n\n    return node ? node.closest<HTMLElement>('.wh-form__fieldgroup') : null;\n  }\n\n  /** get the values of the currently selected radio/checkbox group */\n  private getValues(name: string) {\n    return this.getSelectedOptions(name).map(node => node.value);\n  }\n  /** get the value of the first currently selected radio/checkbox group */\n  private getValue(name: string) {\n    const vals = this.getValues(name);\n    return vals.length ? vals[0] : null;\n  }\n\n  /** @deprecated Just import setupValidator from \\@mod-publisher/js/forms */\n  static setupValidator(node: HTMLElement, checker: (node: HTMLElement) => Promise<string> | string) {\n    setupValidator(node, checker);\n  }\n\n  /** @deprecated Just import setFieldError from \\@mod-publisher/js/forms */\n  static setFieldError(field: HTMLElement, error: string, options?: Partial<FieldErrorOptions>) {\n    setFieldError(field, error, options);\n  }\n\n  setFieldError(field: HTMLElement, error: string, options?: Partial<FieldErrorOptions>) {\n    setFieldError(field, error, options);\n  }\n\n  async validateSingleFormField(field: HTMLElement): Promise<boolean> {\n    return true;\n  }\n\n  async _validateSingleFieldOurselves(field: HTMLElement): Promise<boolean> {\n    const state = getValidationState(field);\n\n    if (!state.explicit && isFieldNativeErrored(field)) {\n      //browser checks go first, any additional checks are always additive (just disable browserchecks you don't want to apply)\n      updateFieldError(field);\n      return this._reportFieldValidity(field);\n    }\n\n    //TODO we probably *shouldn't* be bothering running our validations if state.explicit is set, but then setFieldError needs to rerun the checks once the explicit error is dropped\n    state.dynamicError = null;\n    await this.validateSingleFormField(field);\n\n    if (!state.dynamicError)\n      for (const validator of state.validators) {\n        state.dynamicError = await validator(field) || null;\n        if (state.dynamicError)\n          break; //one is enough\n      }\n\n    if (!state.dynamicError && field.whFormsApiChecker)\n      await field.whFormsApiChecker();\n\n    return this._reportFieldValidity(field);\n  }\n\n  /** validate the form\n      @param limitset - A single element, nodelist or array of elements to validate (or their children)\n      @returns a promise that will fulfill when the form is validated\n       */\n  async validate(limitset?: LimitSet, options?: ValidationOptions): Promise<FormValidationResult> {\n    if (debugFlags.fdv) {\n      console.warn(`[fdv] Validation of form was skipped`);\n      return { valid: true, failed: [], firstfailed: null };\n    }\n\n    //Overlapping validations are dangerous, because we can't evaluate 'hasEverFailed' too early... if an earlier validation is still running it may still decide to mark fields as failed.\n    const defer = Promise.withResolvers<FormValidationResult>();\n    this.validationqueue.push({ defer, limitset, options });\n    if (this.validationqueue.length === 1)\n      this._executeNextValidation(); //we're first on the queue so process it\n\n    return defer.promise;\n  }\n\n  async _executeNextValidation() {\n    while (this.validationqueue.length) {\n      const item = this.validationqueue[0];\n      try {\n        const result = await this._executeQueuedValidation(item.limitset, item.options);\n        item.defer.resolve(result);\n      } catch (error) {\n        item.defer.reject(error as Error);\n      }\n      this.validationqueue.shift(); //remove the top item\n    }\n  }\n\n  async _executeQueuedValidation(limitset?: LimitSet, options?: ValidationOptions): Promise<FormValidationResult> {\n    const original = limitset;\n    if (!limitset)  //validate entire form if unspecified what to validate\n      limitset = this._getFieldsToValidate();\n\n    const tovalidate = new Set<HTMLElement>;\n    for (const node of Array.isArray(limitset) ? limitset : [limitset]) {\n      /* If you're explicitly validating a radio/checkbox, we need to validate its group (but not recurse down) as that's where radiogroup.es and checkboxgroup.es attach their validations\n         If you're targeting a group, we'll end up validating both the radio/checkbox (directly attached here) and any eg. embedded textedits  */\n      if (node.matches(`input[type=radio],input[type=checkbox]`)) {\n        const group = node.closest<HTMLElement>(\".wh-form__fieldgroup\");\n        if (group)\n          tovalidate.add(group);\n        continue;\n      }\n\n      if (this._shouldValidateField(node))\n        tovalidate.add(node);\n      for (const subnode of this._getFieldsToValidate(node)) //TODO this is overly recursive esp. if limitset is empty...\n        tovalidate.add(subnode);\n    }\n\n    /* This was:\n    tovalidate = Array.from(tovalidate); //we need an array now for further processing\n       but that breaks on some old mootools integrations, see https://gitlab.webhare.com/webharebv/codekloppers/-/issues/677#note_146801\n       wokaround: */\n    let tovalidatelist = [...tovalidate]; //we need an array now for further processing\n\n    if (options && options.iffailedbefore)\n      tovalidatelist = tovalidatelist.filter(node => hasEverFailed(node));\n\n    if (debugFlags.fhv)\n      console.log(\"[fhv] Validation of %o expanded to %d elements: %o\", original, tovalidatelist.length, [...tovalidatelist]);\n\n    const lock = dompack.flagUIBusy();\n    try {\n      if (!tovalidatelist.length)\n        return { valid: true, failed: [], firstfailed: null };\n\n      const validationresults = await Promise.all(tovalidatelist.map(fld => this._validateSingleFieldOurselves(fld)));\n      //remove the elements from validate for which the promise failed\n      const failed = tovalidatelist.filter((fld, idx) => !validationresults[idx]);\n      const result: FormValidationResult = {\n        valid: failed.length === 0,\n        failed: failed,\n        firstfailed: null\n      };\n\n      result.firstfailed = result.failed.length ? result.failed[0] : null;\n      if (result.firstfailed && (!options || options.focusfailed)) {\n        //FIXME shouldn't getFocusableComponents also return startnode if focusable?\n        const tofocus = domfocus.canFocusTo(result.firstfailed) ? result.firstfailed : domfocus.getFocusableComponents(result.firstfailed)[0];\n        if (tofocus)\n          dompack.focus(tofocus, { preventScroll: true });\n\n        this.scrollIntoView(result.firstfailed);\n      }\n\n      if (debugFlags.fhv)\n        console.log(`[fhv] Validation of ${tovalidatelist.length} fields done, ${result.failed.length} failed`, result);\n\n      return result;\n    } finally {\n      lock.release();\n    }\n  }\n\n  async reset() {\n    this.node.reset();\n    if (this.getCurrentPageNumber() > 0)\n      await this.gotoPage(0);\n  }\n}\n","import * as dompack from 'dompack';\nimport { qSA } from 'dompack';\nimport * as datetime from 'dompack/types/datetime';\nimport AddressField from '@mod-publisher/js/forms/fields/addressfield';\nimport { setupValidator } from './customvalidation';\n\nimport { getTid } from \"@webhare/gettid\";\nimport { formatDate, parseISODate } from './datehelpers';\nimport { isValidDate } from '@webhare/std';\n\nfunction validateCheckboxGroup(groupnode: HTMLElement) {\n  const nodes = dompack.qSA<HTMLInputElement>(groupnode, \"input[type='checkbox']\");\n  const min = Number(groupnode.dataset.whMin) || 0;\n  const max = Number(groupnode.dataset.whMax) || 0;\n\n  const anyenabled = nodes.some(node => !node.disabled);\n  const numChecked = nodes.filter(node => node.checked).length;\n\n  if (anyenabled) {\n    if (numChecked < min)\n      return getTid(\"publisher:site.forms.commonerrors.mincheck\", min);\n    else if (max > 0 && numChecked > max)\n      return getTid(\"publisher:site.forms.commonerrors.maxcheck\", max);\n  }\n}\n\nfunction validateRadioGroup(groupnode: HTMLElement) {\n  const nodes = dompack.qSA<HTMLInputElement>(groupnode, \"input[type='radio']\");\n  const isrequired = nodes.some(node => node.required);\n\n  if (isrequired) {\n    const isanychecked = nodes.some(node => node.checked && !node.disabled);\n    if (!isanychecked)\n      return getTid(\"publisher:site.forms.commonerrors.required\");\n  }\n}\n\nexport function reformatDate(datestr: string): string {\n  const parsed = parseISODate(datestr);\n  return parsed ? formatDate(\"D-M-Y\", parsed.year, parsed.month, parsed.day) : \"\";\n}\n\nfunction validateDate(date: HTMLInputElement) {\n  if (date.getAttribute('type') !== 'date') //it's no longer a date field\n    return '';\n  if (!date.value) //any required checks should be handled by the HTML5 compat layer, nothing for us to check\n    return '';\n\n  const dateparts = date.value.match(/^([0-9]+)-([0-9]+)-([0-9]+)$/) || [];\n  const year = parseInt(dateparts[1]), month = parseInt(dateparts[2]), day = parseInt(dateparts[3]);\n  if (!isValidDate(year, month, day))\n    return getTid(\"publisher:site.forms.commonerrors.default\");\n\n  const normalizeddate = ('0000' + year).substr(-4) + '-' + ('00' + month).substr(-2) + '-' + ('00' + day).substr(-2);\n  const min = date.getAttribute(\"min\"), max = date.getAttribute(\"max\");\n  if (min && normalizeddate < min)\n    return getTid(\"publisher:site.forms.commonerrors.min\", reformatDate(min));\n  if (max && normalizeddate > max)\n    return getTid(\"publisher:site.forms.commonerrors.max\", reformatDate(max));\n\n  return '';\n}\n\nfunction validateTime(time: HTMLInputElement) {\n  if (time.getAttribute('type') !== 'time') //it's no longer a time field\n    return '';\n  if (!time.value) //any required checks should be handled by the HTML5 compat layer, nothing for us to check\n    return '';\n\n  const timeparts = time.value.match(/^([0-9]+):([0-9]+)(:([0-9]+))?$/) || [];\n  const hours = parseInt(timeparts[1]), minutes = parseInt(timeparts[2]), seconds = parseInt(timeparts[3]);\n  if (isNaN(hours) || isNaN(minutes) || hours < 0 || hours > 23 || minutes < 0 || minutes > 59 || (!isNaN(seconds) && (seconds < 0 || seconds > 59)))\n    return getTid(\"publisher:site.forms.commonerrors.default\");\n\n  return '';\n}\n\nexport function setup(form: HTMLElement) {\n  for (const datecontrol of qSA<HTMLInputElement>(form, 'input[type=date]')) {\n    for (const field of ['whMin', 'whMax', 'whValue'])\n      if (datecontrol.dataset[field]) {\n        //parse 'now' or 'now+5d'. be able to extract '+5d'\n        const datematch = datecontrol.dataset[field]!.match(/^now((\\+|-)\\d+d)?$/);\n\n        if (datematch) {\n          const propname = field.substr(2).toLowerCase();\n          let thedate;\n          if (datematch[1])\n            thedate = new Date(Date.now() + parseInt(datematch[1]) * 86400 * 1000);\n          else\n            thedate = new Date;\n\n          (datecontrol as unknown as Record<string, string>)[propname] = datetime.getISOLocalDate(thedate);\n        }\n      }\n\n    if (datecontrol.type !== 'date' && !datecontrol.whValidationPolyfilled) { //this browser doesn't natively support date fields\n      datecontrol.whValidationPolyfilled = true;\n      //ADDME some sort of global validator would be better so we don't get confused by fields that change their type\n      setupValidator(datecontrol, validateDate);\n    }\n  }\n\n  for (const timecontrol of qSA<HTMLInputElement>(form, 'input[type=time][data-wh-value]')) {\n    //parse 'now'\n    //ADDME: Support for stuff like 'now + 15 minutes' 'next whole hour + 2.5 hours'?\n    const timematch = timecontrol.dataset.whValue!.match(/^now$/);\n\n    if (timematch) {\n      const thedate = new Date;\n\n      let propvalue = ('0' + thedate.getHours()).substr(-2) + '-' + ('0' + thedate.getMinutes()).substr(-2);\n      if (parseInt(timecontrol.getAttribute(\"step\") || '0') % 60) //step not multiple of 60? seconds\n        propvalue += '-' + ('0' + thedate.getSeconds()).substr(-2);\n      timecontrol.value = propvalue;\n    }\n\n    if (timecontrol.type !== 'time' && !timecontrol.whValidationPolyfilled) { //this browser doesn't natively support time fields\n      timecontrol.whValidationPolyfilled = true;\n      //ADDME some sort of global validator would be better so we don't get confused by fields that change their type\n      setupValidator(timecontrol, validateTime);\n    }\n  }\n\n  // Setup checkbox group (min/max checked) validation\n  for (const checkboxgroup of qSA(form, \".wh-form__fieldgroup--checkboxgroup\"))\n    setupValidator(checkboxgroup, validateCheckboxGroup);\n\n  // Setup radio group (hidden/disabled) validation\n  for (const radiogroup of qSA(form, \".wh-form__fieldgroup--radiogroup\")) {\n    setupValidator(radiogroup, validateRadioGroup);\n\n    //we should probably disable by name (or form.elements[name] but validate() and form isn't really tracking name either...\n    dompack.qSA<HTMLInputElement>(radiogroup, `input[type='radio']`).forEach(\n      node => node.dataset.whFormSkipnativevalidation = \"true\"); //don't handle by both RadioGroupField *and* native validation\n\n  }\n\n  // Setup address field validation\n  for (const addresscontrol of qSA(form, \".wh-form__fieldgroup--addressfield\"))\n    new AddressField(addresscontrol);\n}\n","/**\n * Get ISO-formatted local date from a date (getISOString returns an UTC datetime)\n *\n * @param date - Date to return\n * @returns Date as a YYYY-MM-DD string\n */\nexport function getISOLocalDate(date: Date) {\n  return date.getFullYear() + '-' + ('0' + (date.getMonth() + 1)).slice(-2) + '-' + ('0' + date.getDate()).slice(-2);\n}\n","/* eslint-disable @typescript-eslint/no-floating-promises -- FIXME: needs API rework */\n\nimport * as dompack from \"@webhare/dompack\";\nimport FormBase from \"../formbase\";\nimport { debugFlags } from \"@webhare/env\";\nimport { verifyHareScriptAddress, type HareScriptAddressValidationResult, type AddressChecks, type HareScriptAddressValue } from \"@webhare/forms/src/address\";\nimport { setFieldError } from \"../internal/customvalidation\";\nimport { throwError } from \"@webhare/std\";\n\nclass SubField {\n  node;\n  fieldgroup: HTMLElement;\n  pos: number;\n\n  constructor(node: dompack.FormControlElement, pos: number) {\n    this.node = node;\n    this.pos = pos;\n    this.fieldgroup = node.closest(\".wh-form__fieldgroup\") ?? throwError(\"Could not find fieldgroup for field\");\n  }\n}\n\ninterface OrderingData {\n  countries: string[];\n  fieldorder: string[];\n}\n\nexport default class AddressField {\n  numvaliditycalls = 0;\n  node: HTMLElement;\n  formnode: HTMLFormElement;\n  countryNode: HTMLSelectElement;\n  currentcountry: string;\n  fieldName: string;\n  orderingData: OrderingData[];\n  allFields = new Map<string, SubField>;\n  _updatingFields = false;\n\n  constructor(node: HTMLElement) {\n    this.node = node;\n    //We won't FormBase.getForNode yet here so we're not too dependent on registration ordering\n    this.formnode = node.closest(\"form\") ?? throwError(\"Could not find form for addressfield\");\n\n    // AddressField is initialized for the address's country field, so first find the other fields\n    this.countryNode = dompack.qR(this.node, \"select.wh-form__pulldown\"); //TODO why aren't we targetting by ID ? this will work but seems ambiguous\n    if (!this.countryNode)\n      throw new Error(\"Could not find country select node\");\n    if (!this.countryNode.dataset.orderingdata)\n      throw new Error(\"Addressfield not properly configured\");\n\n    this.currentcountry = this.countryNode.value;\n    this.fieldName = this.countryNode.name.substr(0, this.countryNode.name.lastIndexOf(\".\"));\n    this.orderingData = JSON.parse(this.countryNode.dataset.orderingdata) as OrderingData[];\n    const prefixLength = this.fieldName.length + 1; // fieldName + \".\"\n    this.allFields = new Map();\n    let fieldpos = 0;\n    this.allFields.set(this.countryNode.name.substr(prefixLength), new SubField(this.countryNode, ++fieldpos));\n\n    for (const field of dompack.qSA<HTMLInputElement | HTMLTextAreaElement>(this.formnode, `[name^='${this.fieldName}.']`)) {\n      this.allFields.set(field.name.substring(prefixLength), new SubField(field, ++fieldpos));\n\n      field.addEventListener(\"change\", event => this._gotFieldChange(event));\n    }\n\n    if (this.orderingData) {\n      this.countryNode.addEventListener(\"change\", () => this._reconfigureFieldOrdering());\n      this._reconfigureFieldOrdering();\n    }\n  }\n\n  _gotFieldChange(event: Event) {\n    if (this._updatingFields)\n      return; // We're updating our own fields\n\n    if (event.target === this.countryNode && this.currentcountry !== this.countryNode.value) {\n      //country changed. clear errors on all fields before revalidating.. otherwise the errors will just seem to 'linger' for a while after switching\n      this._clearErrors();\n      this.currentcountry = this.countryNode.value;\n    }\n\n    if (this._getFieldValue(\"country\") === \"NL\") {\n      if (!this._getFieldValue(\"zip\") || !this._getFieldValue(\"nr_detail\"))\n        return;\n    }\n    this._checkValidity(event);\n  }\n\n  _getFieldValue(fieldname: string) {\n    const data = this.allFields.get(fieldname);\n    if (data)\n      return data.node.value;\n    return \"\";\n  }\n\n  _getFirstCountrySpecificField() {\n    let firstfield = null;\n    for (const [key, field] of this.allFields.entries())\n      if (key !== \"country\" && !field.fieldgroup.classList.contains(\"wh-form__fieldgroup--hidden\") && (!firstfield || firstfield.pos > field.pos))\n        firstfield = field;\n\n    return firstfield ?? throwError(\"Cannot find field for error\");\n  }\n\n  _reconfigureFieldOrdering() {\n    const country = this.countryNode.value;\n    if (country) {\n      const ordering = this.orderingData.find(e => e.countries.length === 0 || e.countries.includes(country));\n      if (ordering) {\n        let prevgroup;\n        for (let idx = 0; idx < ordering.fieldorder.length; ++idx) {\n          const item = this.allFields.get(ordering.fieldorder[idx]);\n          if (!item)\n            continue; //ordering may appear to fields that have not been rendered, eg 'state'\n\n          item.pos = idx + 1;\n          const fieldgroup = item.fieldgroup;\n          if (prevgroup) {\n            const compareres = prevgroup!.compareDocumentPosition(fieldgroup);\n            if (compareres & Node.DOCUMENT_POSITION_PRECEDING)\n              prevgroup!.parentNode!.insertBefore(fieldgroup, prevgroup!.nextSibling);\n          }\n          prevgroup = fieldgroup;\n        }\n      }\n    }\n\n    //street + city should skip client side validation for NL, we will be looking it up server side (FIXME we should consider overwriting our validation to delay validation until address lookups are complete)\n    for (const fieldname of ['street', 'city']) {\n      const field = this.allFields.get(fieldname);\n      if (field)\n        if (country.toUpperCase() === 'NL')\n          field.node.setAttribute(\"data-wh-form-skipnativevalidation\", \"\");\n        else\n          field.node.removeAttribute(\"data-wh-form-skipnativevalidation\");\n    }\n  }\n\n  _clearErrors() {\n    this.allFields.forEach(field => setFieldError(field.node, \"\", { reportimmediately: true }));\n  }\n\n  _getCurState() {\n    const value: HareScriptAddressValue = { country: \"\" };\n    const visiblefields: HTMLElement[] = [];\n    let anyset = false, allrequiredset = true;\n    this.allFields.forEach((field, key) => {\n      if (!field.fieldgroup.classList.contains(\"wh-form__fieldgroup--hidden\")) {\n        visiblefields.push(field.node.closest(\".wh-form__fieldgroup\")!);\n        value[key as keyof HareScriptAddressValue] = field.node.value;\n\n        if (!anyset && key !== 'country' && field.node.value)\n          anyset = true;\n        if (field.node.required && !field.node.value && !field.node.hasAttribute(\"data-wh-form-skipnativevalidation\"))\n          allrequiredset = false;\n      }\n    });\n\n    return { value, visiblefields, anyset, allrequiredset, lookupkey: JSON.stringify(value) };\n  }\n\n  async _checkValidity(event: Event) {\n    const form = FormBase.getForNode(this.formnode) ?? throwError(\"Parent form for address field not yet initialized\");\n    /* we used to clear fields that are no longer visible after a country change, add visible fields to the value we're checking\n       but not sure why. ignoring those fields should be okay? and this is a very eager trigger, so if we really do this, do\n       this on base of the country actually changing, not an external checkbox controlling visibility of the whole country field\n       and a stray update event\n       */\n    const curstate = this._getCurState();\n    if (!curstate.anyset) { //fields are empty..\n      this._clearErrors();\n      return; //then don't validate\n    }\n    if (!curstate.allrequiredset)\n      return; //no need to validate if we don't even have the required fields in place\n\n    let result: HareScriptAddressValidationResult;\n    const lock = dompack.flagUIBusy();\n    try {\n      curstate.visiblefields.forEach(el => el.classList.add(\"wh-form__fieldgroup--addresslookup\"));\n      ++this.numvaliditycalls;\n      result = await verifyHareScriptAddress(curstate.value as HareScriptAddressValue, {\n        lang: form.getLangCode(),\n        checks: (this.node.dataset.checks?.split(' ') ?? []) as AddressChecks[]\n      });\n    } catch (e) {\n      console.error(`Error while validating value: ${e}`);\n      return;\n    } finally {\n      if (--this.numvaliditycalls === 0) //we're the last call\n        curstate.visiblefields.forEach(el => el.classList.remove(\"wh-form__fieldgroup--addresslookup\"));\n\n      lock.release();\n    }\n    if (this._getCurState().lookupkey !== curstate.lookupkey)\n      return; //abandon this _checkValidity call, the field has already changed.\n\n    if (debugFlags.fhv)\n      console.log(`[fhv] Validation result for address '${this.fieldName}': ${result.status}`);\n\n    if (debugFlags.fdv) {\n      if ([\"different_citystreet\", \"incomplete\"].includes(result.status))\n        console.warn(`[fdv] Address validation was performed, processing incomplete address (status: '${result.status}')`);\n      else {\n        console.warn(`[fdv] Ignoring return status '${result.status}' of address validation`);\n        result.status = \"ok\";\n      }\n    }\n\n    this._clearErrors();\n\n    for (const err of result.errors) {\n      const field = this.allFields.get(err.fields[0]) ?? this._getFirstCountrySpecificField();\n      if (field)\n        form.setFieldError(field.node, err.message, { reportimmediately: true });\n    }\n\n    if (result.corrections) {\n      let anychanges = false;\n      this._updatingFields = true;\n\n      for (const [key, newvalue] of Object.entries(result.corrections)) {\n        const field = this.allFields.get(key);\n        if (field && field.node.value !== newvalue) {\n          dompack.changeValue(field.node, newvalue);\n          anychanges = true;\n        }\n      }\n\n      this._updatingFields = false;\n      if (anychanges)\n        form.refreshConditions();\n    }\n  }\n}\n","import type { AddressValue } from \"@webhare/address\";\nimport { stringify, emplace, omit } from \"@webhare/std\";\nimport { getFormService, type HareScriptAddressValidationResult, type HareScriptAddressValue } from \"./formservice\";\n\nexport type { HareScriptAddressValue, HareScriptAddressValidationResult } from \"./formservice\";\n\nexport type AddressChecks = \"nl-zip-suggest\" | \"nl-zip-force\";\n\nexport type AddressValidationStatus = \"ok\" | \"unknown\" | \"error\";\n// not_supported\" | \"ok\" | \"not_enough_data\" | \"invalid_city\" | \"invalid_zip\" | \"invalid_nr_detail\" | \"zip_not_found\" | \"address_not_found\" | \"different_citystreet\" | \"incomplete\" | \"lookup_failed\";\n\nexport interface AddressValidationOptions {\n  checks?: AddressChecks[];\n  lang?: string;\n}\n\nexport interface AddressValidationResult {\n  status: AddressValidationStatus;\n  errors: Array<{\n    ///Fields affected by the error\n    fields: string[];\n    ///Error message in the requested language\n    message: string;\n  }>;\n  corrections: Partial<Record<keyof AddressValue, string>> | null;\n}\n\nlet lookupcache: Map<string, Promise<AddressValidationResult>> | undefined;\n\nexport async function verifyHareScriptAddress(address: HareScriptAddressValue, options: AddressValidationOptions = {}): Promise<HareScriptAddressValidationResult> {\n  if (!lookupcache)\n    lookupcache = new Map<string, Promise<AddressValidationResult>>;\n\n  const lookupkey = stringify({ address, options }, { stable: true });\n  const lookup = emplace(lookupcache, lookupkey, {\n    insert: () => getFormService().verifyAddress(location.pathname, address, options)\n  });\n  return await lookup;\n}\n\nexport async function verifyAddress(address: AddressValue, options: AddressValidationOptions = {}): Promise<AddressValidationResult> {\n  if (!lookupcache)\n    lookupcache = new Map<string, Promise<AddressValidationResult>>;\n\n  // convert houseNumber to nr_detail\n  const hsAddress = { ...omit(address, [\"houseNumber\"]), nr_detail: address.houseNumber };\n\n  const hsresult = await verifyHareScriptAddress(hsAddress, options);\n\n  // back-convert nr_detail to houseNumber\n  let corrections: AddressValidationResult[\"corrections\"] = null;\n  if (hsresult.corrections) {\n    corrections = {};\n    for (const [key, value] of Object.entries(hsresult.corrections) as Array<[keyof HareScriptAddressValue, string]>) {\n      corrections[key === \"nr_detail\" ? \"houseNumber\" as const : key] = value;\n    }\n  }\n  return {\n    status: hsresult.status,\n    errors: hsresult.errors.map(error => ({ fields: error.fields.map(f => f === \"houseNumber\" ? \"nr_detail\" : f), message: error.message })),\n    corrections,\n  };\n}\n","import * as dompack from '@webhare/dompack';\nimport type { FieldErrorOptions, FormFrontendMessage } from '../formbase';\nimport { debugFlags } from '@webhare/env';\nimport { getFieldDisplayName, getFieldNativeError } from '@webhare/forms/src/domsupport';\n\n///Fired at nodes to apply error\nexport type SetFieldErrorData = {\n  error: FormFrontendMessage;\n  reportimmediately: boolean;\n  serverside: boolean;\n  metadata: unknown;\n};\n\nexport type FieldValidator<E extends HTMLElement = HTMLElement> = (node: E) => Promise<FormFrontendMessage | undefined> | FormFrontendMessage | undefined;\n\nfunction setupServerErrorClear(field: HTMLElement) {\n  const group = field.closest<HTMLElement>('.wh-form__fieldgroup') || field;\n  field.propWhCleanupFunction = () => {\n    group.removeEventListener(\"change\", field.propWhCleanupFunction!, true);\n    group.removeEventListener(\"input\", field.propWhCleanupFunction!, true);\n    group.removeEventListener(\"blur\", field.propWhCleanupFunction!, true);\n    setFieldError(field, '', { serverside: true });\n    field.propWhCleanupFunction = undefined;\n  };\n\n  // to be rightly paranoid (plugins and JS directly editing other fields) we'll blur when anything anywhere seems to change\n  // eg wrd.testwrdauth-emailchange would fail on Chrome without this if the browser window was not currently focused\n  group.addEventListener(\"change\", field.propWhCleanupFunction, true);\n  group.addEventListener(\"input\", field.propWhCleanupFunction, true);\n  if (!field.closest('form[novalidate]')) //if we're doing html5 validation, errors will block submit, so let's already clear on blur\n    group.addEventListener(\"blur\", field.propWhCleanupFunction, true);\n}\n\nclass ComponentValidationState {\n  el: HTMLElement;\n\n  /** Explicitly set error */\n  explicit: {\n    error: FormFrontendMessage;\n    serverside: boolean;\n    reportimmediately: boolean;\n    metadata?: unknown;\n\n  } | null = null;\n\n  /** Dynamic errors (generated by the validation steps, refreshable instead of waiting for explciit errors) */\n  dynamicError: FormFrontendMessage | null = null;\n\n  validators: FieldValidator[] = [];\n\n  constructor(el: HTMLElement) {\n    this.el = el;\n  }\n\n  getState(): { error: FormFrontendMessage; suggested?: never } | { error?: never; suggested: FormFrontendMessage } | null {\n    const err = this.getError();\n    if (err)\n      return { error: err };\n\n    if (this.el.propWhValidationSuggestion)\n      return { suggested: this.el.propWhValidationSuggestion };\n\n    return null;\n  }\n\n  getError(): FormFrontendMessage | null {\n    return this.explicit?.error || this.dynamicError || getFieldNativeError(this.el) || null;\n  }\n\n  hasError(): boolean {\n    return Boolean(this.getError());\n  }\n}\n\nconst validations = new WeakMap<HTMLElement, ComponentValidationState>();\n\nexport function getValidationState(field: HTMLElement) {\n\n  const state = validations.get(field);\n  if (state)\n    return state;\n\n  const newstate = new ComponentValidationState(field);\n  validations.set(field, newstate);\n  return newstate;\n}\n\n/* TODO Are we sure we should expose this API? A form-level setupValidator might be better as we can then re-validate at the proper point in time\n   instead of relying on an external user to enable and shutdown the error. We're mixing two completely different systems with setupValidator (which\n   works nicely with our focusout hadling) and setFieldError (which is extremely stateful and relies on the error-setter managing all the edge cases)\n\n   Oh and serverside errors float somewhere halfway that spectrum.. as we setup explicit clearing callbacks to remove the state we created ourselves.\n*/\nexport function setFieldError(field: Element, error: FormFrontendMessage, options?: Partial<FieldErrorOptions>) {\n  if (!dompack.isHTMLElement(field))\n    throw new Error(`Field is not a valid target for handling errors`);\n\n  const state = getValidationState(field);\n  if (!error) {  //clearing\n    if (!state.explicit)\n      return; //no change\n\n    state.explicit = null;\n    if (debugFlags.fhv)\n      console.log(`[fhv] Clearing error state for ${getFieldDisplayName(field)}`, field, error, options);\n  } else { //changing ?\n    if (debugFlags.fhv)\n      console.log(`[fhv] ${state.explicit ? 'Updating' : 'Setting'} error state for ${getFieldDisplayName(field)}`, field, error, options);\n\n    state.explicit = {\n      error,\n      serverside: options?.serverside || false,\n      reportimmediately: options?.reportimmediately || false,\n      metadata: options?.metadata\n    };\n\n    if (options?.serverside)\n      setupServerErrorClear(field);\n  }\n\n  updateFieldError(field);\n}\n\nexport function updateFieldError(field: HTMLElement) {\n  const state = getValidationState(field);\n\n  dompack.dispatchCustomEvent(field, 'wh:form-setfielderror', //this is where parsley hooks in and cancels to handle the rendering of faults itself\n    {\n      bubbles: true,\n      cancelable: true,\n      detail: {\n        error: state.explicit?.error || getFieldNativeError(field) || '',\n        reportimmediately: state.explicit?.reportimmediately || false,\n        serverside: state.explicit?.serverside || false,\n        metadata: state.explicit?.metadata\n      }\n    });\n}\n\n/** Set up a custom validator\n * @param node - Form element to validate\n * @param checker - Sync or async function that returns a string with an error message or undefined if the field is valid.\n*/\nexport function setupValidator<NodeType extends HTMLElement>(node: NodeType, checker: FieldValidator<NodeType>): void {\n  getValidationState(node).validators.push(checker as FieldValidator);\n\n  //if the checker as a name, we'll add it. otherwise we'll ensure that data-wh-form-custom-validator is set so we can scan for it (and it's probably nice to see it in the dom)\n  node.dataset.whFormCustomValidator = ((node.dataset.whFormCustomValidator || \"\") + \" \" + (checker.name || \"?\")).trim();\n}\n","/* Support APIs to deal with DOM native form elements (eg input, select, textarea) */\n\nimport type FormBase from '@mod-publisher/js/forms/formbase';\nimport { reformatDate } from \"@mod-publisher/js/forms/internal/webharefields\";\nimport { getTid } from \"@webhare/gettid\";\nimport { isFormControl, isHTMLElement, qSA, type FormControlElement } from \"@webhare/dompack\";\nimport type { FormCondition } from \"./types\";\nimport { JSFormElement, type FormFieldLike } from \"./jsformelement\";\nimport { throwError } from '@webhare/std';\n\nexport type ConstrainedRadioNodeList = RadioNodeList & NodeListOf<HTMLInputElement>;\n\n//Query elements that are likely to be formfieldlike. Anything with a [name] but not eg button (and not data-wh-form-name which usually relies on getformvalue events)\nexport const queryFormFieldLike = `[name]:not(button):not(a):not(output)`;\n\nexport function isInputElement(field: Element): field is HTMLInputElement {\n  return isHTMLElement(field) && field.tagName === 'INPUT';\n}\n\n/// Implements required, disabled, ..\nexport function isFormFieldLike(control: HTMLElement): control is FormFieldLike {\n  return isFormControl(control as HTMLElement) || control instanceof JSFormElement;\n}\n\nexport function isRadioOrCheckbox(field: Element): field is HTMLInputElement {\n  return isInputElement(field) && [\"radio\", \"checkbox\"].includes(field.type);\n}\n\n// Constrains the RadioNodeList type to only return HTMLInputElements. reduces number of casts we need\nexport function isRadioNodeList(el: RadioNodeList | Element): el is ConstrainedRadioNodeList {\n  return el instanceof RadioNodeList;\n}\n\nexport function getFieldName(field: HTMLElement): string {\n  return field.dataset.whFormName || (field as HTMLInputElement).name || '';\n}\n\nexport function setFieldName(field: HTMLElement, newname: string) {\n  if (field.dataset.whFormName !== undefined)\n    field.dataset.whFormName = newname;\n  else if ((field as HTMLInputElement).name !== undefined)\n    (field as HTMLInputElement).name = newname;\n  else\n    throw new Error('Cannot set name on field without existing name');\n}\n\nexport function getFieldDisplayName(field: HTMLElement | ConstrainedRadioNodeList): string {\n  if (isRadioNodeList(field))\n    return `radiogroup '${(field.item(0) as HTMLInputElement)?.name || (field.item(0) as HTMLElement)?.id || '<unnamed>'}'`;\n  if (isFormControl(field))\n    return `native field '${field.name || field.id || '<unnamed>'}'`;\n  if (field.dataset.whFormName)\n    return `custom field '${field.dataset.whFormName || field.id || '<unnamed>'}'`;\n  if (field.classList.contains('wh-form__fieldgroup'))\n    return `field group '${field.dataset.whFormGroupFor || field.id || '<unnamed>'}'`;\n  return `${field.tagName} element '${field.id || '<unnamed>'}'`;\n}\n\n/** The WH Form rendering generates wh-fileedit elements. If no handler is detected for them, we downgrade them to input type=file before\n *  the form actually sets up its handler (it's still safe to rewrite top level form elements then)\n*/\nexport function downgradeUploadFields(form: HTMLElement) {\n  for (const uploadfield of qSA(form, \"wh-fileedit\")) {\n    const input = document.createElement(\"input\");\n    input.type = \"file\";\n    for (const attr of uploadfield.attributes)\n      input.setAttribute(attr.name, attr.value);\n\n    uploadfield.replaceWith(input);\n  }\n}\n\nexport function getErrorForValidity(field: FormControlElement): string {\n  const validity = field.validity;\n  if (validity.customError && field.validationMessage)\n    return field.validationMessage;\n\n  if (validity.valueMissing)\n    return getTid(\"publisher:site.forms.commonerrors.required\");\n  if (field instanceof HTMLInputElement) {\n    if (validity.rangeOverflow) {\n      const max = field.type === 'date' ? reformatDate(field.max) : field.max;\n      return getTid(\"publisher:site.forms.commonerrors.max\", max);\n    }\n    if (validity.rangeUnderflow) {\n      const min = field.type === 'date' ? reformatDate(field.min) : field.min;\n      return getTid(\"publisher:site.forms.commonerrors.min\", min);\n    }\n    if (validity.tooShort)\n      return getTid(\"publisher:site.forms.commonerrors.minlength\", field.minLength);\n    if (validity.tooLong)\n      return getTid(\"publisher:site.forms.commonerrors.maxlength\", field.maxLength);\n    if (validity.stepMismatch)\n      if (!field.step || parseInt(field.step) === 1)\n        return getTid(\"publisher:site.forms.commonerrors.step1mismatch\");\n      else\n        return getTid(\"publisher:site.forms.commonerrors.stepmismatch\", field.step);\n  }\n\n  if (validity.badInput)\n    return getTid(\"publisher:site.forms.commonerrors.default\");\n  if (validity.typeMismatch)\n    if ([\"email\", \"url\", \"number\"].includes(field.type))\n      return getTid(\"publisher:site.forms.commonerrors.\" + field.type);\n\n  for (const key of [\"badInput\", \"customError\", \"patternMismatch\", \"rangeOverflow\", \"rangeUnderflow\", \"stepMismatch\", \"typeMismatch\", \"valueMissing\"] as const)\n    if (validity[key])\n      return key;\n\n  return '?';\n}\n\nexport function isFieldNativeErrored(field: HTMLElement): field is FormControlElement {\n  return isFormControl(field) && !field.hasAttribute(\"data-wh-form-skipnativevalidation\") && !field.checkValidity();\n}\n\nexport function getFieldNativeError(field: HTMLElement) {\n  if (isFieldNativeErrored(field))\n    return getErrorForValidity(field);\n\n  return null;\n}\n\n\nexport function parseCondition(conditiontext: string): FormCondition {\n  interface FormConditionWrapper {\n    c: FormCondition;\n  }\n\n  return (JSON.parse(conditiontext) as FormConditionWrapper).c;\n}\n\nexport function getFormElementCandidates(basenode: HTMLElement, namePrefix: string) {\n  const parentForm = basenode.closest('form');\n  if (!parentForm)\n    throw new Error('No form found for element');\n\n  const candidates = qSA<HTMLElement>(basenode, queryFormFieldLike).filter(el => !(\"form\" in el) || el.form === parentForm);\n  if (namePrefix)\n    return candidates.filter(el => getFieldName(el).startsWith(namePrefix + '.'));\n  else\n    return candidates;\n}\n\n/** Get the handler for a form element */\nexport function getFormHandler<FormType extends FormBase<object> = FormBase>(node: HTMLFormElement, options: { allowMissing: true }): FormType | null;\nexport function getFormHandler<FormType extends FormBase<object> = FormBase>(node: HTMLFormElement, options?: { allowMissing?: boolean }): FormType;\n\nexport function getFormHandler<FormType extends FormBase<object> = FormBase>(node: HTMLFormElement, { allowMissing = false } = {}): FormType | null {\n  //FIXME convert to Symbol? but make sure we work cross-realm (ie tests)\n  return (node.propWhFormhandler as FormType) || (allowMissing ? null : throwError('No form handler found for form'));\n}\n\n/** Get the data for a form element. Shorthand for getFormHandler\\<FormBase\\<Shape\\>\\>(xx).data */\nexport function getFormData<DataShape extends object = Record<string, unknown>>(node: HTMLFormElement, options: { allowMissing: true }): DataShape | null;\nexport function getFormData<DataShape extends object = Record<string, unknown>>(node: HTMLFormElement, options?: { allowMissing?: boolean }): DataShape;\n\nexport function getFormData<DataShape extends object = Record<string, unknown>>(node: HTMLFormElement, { allowMissing = false } = {}): DataShape | null {\n  return getFormHandler<FormBase<DataShape>>(node, { allowMissing })?.data;\n}\n","export interface FormFieldLike extends HTMLElement {\n  disabled: boolean;\n  name: string;\n  required: boolean;\n  value: unknown;\n}\n\n/** Base class for customElements that need to act as WebHare (Publisher) form elements */\nexport abstract class JSFormElement<ValueType> extends HTMLElement implements FormFieldLike {\n  static formAssociated = true;\n  static observedAttributes = [\"required\", \"disabled\"];\n\n  // #internals = this.attachInternals();\n\n  constructor() {\n    super();\n  }\n\n  get name() {\n    return this.getAttribute('name') || '';\n  }\n  set name(newname: string) {\n    this.setAttribute('name', newname);\n  }\n  get required(): boolean {\n    return this.hasAttribute('required');\n  }\n  set required(required: boolean) {\n    if (required)\n      this.setAttribute(\"required\", \"\");\n    else\n      this.removeAttribute(\"required\");\n\n    this.refreshState();\n  }\n\n  get disabled(): boolean {\n    return this.hasAttribute('disabled');\n  }\n  set disabled(disable: boolean) {\n    if (disable)\n      this.setAttribute(\"disabled\", \"\");\n    else\n      this.removeAttribute(\"disabled\");\n\n    this.refreshState();\n  }\n\n  abstract value: ValueType;\n\n  /** Invoked whenever disabled/required states change */\n  protected refreshState() {\n  }\n\n  attributeChangedCallback(name: string, oldValue: unknown, newValue: unknown) {\n    if ([\"disabled\", \"required\"].includes(name))\n      this.refreshState();\n  }\n}\n","import { isValidDate, isValidTime } from '@webhare/std';\n\nexport function formatDate(dateformat: string, year: number, month: number, day: number): string {\n  if (!isValidDate(year, month, day, { minYear: 1 }))\n    return '';\n\n  let output = '';\n\n  for (const c of dateformat.split(\"\")) {\n    switch (c.toUpperCase()) {\n      case \"Y\":\n        output += ('000' + year).slice(-4);\n        break;\n      case \"M\":\n        output += ('0' + month).slice(-2);\n        break;\n      case \"D\":\n        output += ('0' + day).slice(-2);\n        break;\n      default:\n        output += c;\n        break;\n    }\n  }\n  return output;\n}\n\nexport function formatISODate(year: number, month: number, date: number) {\n  return formatDate(\"Y-M-D\", year, month, date);\n}\n\nexport function formatISOTime(hour: number, minute: number, second: number | null, msec: number | null) {\n  if (!isValidTime(hour, minute, second !== null ? second : 0, msec !== null ? msec : 0))\n    return '';\n\n  let time = ('0' + hour).slice(-2) + ':' + ('0' + minute).slice(-2);\n  if (second !== null)\n    time += ':' + ('0' + second).slice(-2);\n  if (msec !== null)\n    time += '.' + ('00' + msec).slice(-3);\n  return time;\n}\n\nexport interface DateParts {\n  day: number;\n  month: number;\n  year: number;\n}\n\nexport function parseDate(format: string, newdate: string, options?: { nofail: boolean }): DateParts | null {\n  if (!newdate) //empty\n    return null;\n\n  //replace . and / with -\n  const setdate = newdate.replace(/[./]/g, '-');\n  const parts = setdate.split('-');\n\n  if (parts.length === 3) { //parseable\n    format = format.toLowerCase();\n    const dayoffset = format.indexOf('d');\n    const monthoffset = format.indexOf('m');\n    const yearoffset = format.indexOf('y');\n\n    const daypos = 0 + (dayoffset > monthoffset ? 1 : 0) + (dayoffset > yearoffset ? 1 : 0);\n    const monthpos = 0 + (monthoffset > dayoffset ? 1 : 0) + (monthoffset > yearoffset ? 1 : 0);\n    const yearpos = 0 + (yearoffset > dayoffset ? 1 : 0) + (yearoffset > monthoffset ? 1 : 0);\n\n    const day = parseInt(parts[daypos], 0);\n    const month = parseInt(parts[monthpos], 0);\n    const year = parseInt(parts[yearpos], 0);\n\n    // The browser will always add 1900 for years 0-99, so handle years < 100\n    // if (year >= 0 && year < 100 && this.options.cutoffyear > 0)\n    // {\n    //   if (year < this.options.cutoffyear)\n    //     year += 2000;\n    //   else\n    //     year += 1900;\n    // }\n    if (isValidDate(year, month, day))\n      return { year, month, day };\n  }\n  if (options && options.nofail)\n    return null;\n\n  throw new Error(`Invalid date value: '${newdate}'`);\n}\n\n//compare two dates. return -1 if lhs<rhs, 0 if lhs==rhs, 1 if lhs>rhs\nexport function compareDate(lhs: DateParts | null, rhs: DateParts | null) {\n  if (!lhs)\n    return rhs ? -1 : 0; //if rhs is set, <null> is before anything. oterhwise equal\n  else if (!rhs)\n    return 1; //lhs must be set, so lhs>rhs\n\n  return lhs.year < rhs.year ? -1\n    : lhs.year > rhs.year ? 1\n      : lhs.month < rhs.month ? -1\n        : lhs.month > rhs.month ? 1\n          : lhs.day < rhs.day ? -1\n            : lhs.day > rhs.day ? 1\n              : 0;\n}\n\nexport function parseISODate(newdate: string, options?: { nofail: boolean }) {\n  return parseDate('y-m-d', newdate, options);\n}\n\nexport function getLocalToday(): DateParts {\n  const today = new Date;\n  return { year: today.getFullYear(), month: 1 + today.getMonth(), day: today.getDate() };\n}\n\nexport function parseISOTime(intime: string, { nofail = false } = {}) {\n  const split = intime.match(/^([0-9]+):([0-9]+)(:([0-9]+))?(\\.([0-9]+))?$/);\n  if (split) {\n    const hour = parseInt(split[1], 10);\n    const minute = parseInt(split[2], 10);\n    const second = parseInt(split[4] || \"0\", 10);\n    const msec = parseInt(split[6] || \"0\", 10);\n    return { hour, minute, second, msec };\n  }\n  if (nofail)\n    return undefined;\n\n  throw new Error(`Invalid time value: '${intime}'`);\n}\n\nexport function getWeekNumber(jsdate: Date) {\n  jsdate = new Date(jsdate); //don't modify the caller's date!\n  jsdate.setHours(0, 0, 0, 0);\n  // Thursday in current week decides the year.\n  jsdate.setDate(jsdate.getDate() + 3 - (jsdate.getDay() + 6) % 7);\n  // January 4 is always in week 1.\n  const week1 = new Date(jsdate.getFullYear(), 0, 4);\n  // Adjust to Thursday in week 1 and count number of weeks from jsdate to week1.\n  return 1 + Math.round(((jsdate.getTime() - week1.getTime()) / 86400000 - 3 + (week1.getDay() + 6) % 7) / 7);\n}\n\nexport function makeJSUTCDate(dateparts: DateParts) {\n  return new Date(Date.UTC(dateparts.year, dateparts.month - 1, dateparts.day));\n}\n\nexport function formatJSUTCISODate(dateobj: Date) {\n  return dateobj.getUTCFullYear() + '-' + ('0' + (dateobj.getUTCMonth() + 1)).slice(-2) + '-' + ('0' + dateobj.getUTCDate()).slice(-2);\n}\n","export const rfSymbol = Symbol('RegisteredField');\n\ndeclare global {\n  interface HTMLElement {\n    [rfSymbol]?: FormFieldAPI;\n  }\n}\n\nexport interface FormFieldAPI {\n  getValue(): unknown;\n  setValue(newvalue: unknown): void;\n}\n","/* eslint-disable @typescript-eslint/no-floating-promises -- FIXME: needs API rework */\n\nimport { getTid } from \"@webhare/gettid\";\nimport \"./arrayfield.css\";\nimport { throwError } from \"@webhare/std\";\nimport { addDocEventListener, qS, qSA, type DocEvent, registerMissed, stop } from \"@webhare/dompack\";\nimport { getFieldName, getFormElementCandidates, getFormHandler, parseCondition, setFieldName } from \"@webhare/forms/src/domsupport\";\nimport type { FormCondition } from \"@webhare/forms/src/types\";\nimport { RecordFieldHandler, type FormParent } from \"@webhare/forms/src/fieldmap\";\nimport type FormBase from \"../formbase\";\nimport { setup } from \"../internal/webharefields\";\n\n\nfunction fixupConditionRecursive(node: HTMLElement, condition: FormCondition, mapping: Map<string, string>): boolean {\n  switch (condition.matchtype) {\n    case \"AND\":\n    case \"OR\":\n      {\n        let anychanges = false;\n        for (const subcondition of condition.conditions)\n          anychanges = fixupConditionRecursive(node, subcondition, mapping) || anychanges;\n        return anychanges;\n      }\n    case \"NOT\":\n      {\n        return fixupConditionRecursive(node, condition.condition, mapping);\n      }\n    default:\n      {\n        const newName = mapping.get(condition.field);\n        if (newName && node.querySelector(`[name=\"${newName}\"]`)) {\n          condition.field = newName;\n          return true;\n        }\n      }\n  }\n  return false;\n}\n\ntype NewType = FormParent;\n\nexport default class ArrayField {\n  valueNode: HTMLInputElement;\n  nextrowid = 0;\n  template;\n  insertPoint: HTMLElement;\n  arrayBaseName;\n  handler: NewType;\n  node: HTMLElement;\n  name: string;\n\n  constructor(handler: NewType, node: HTMLElement, items: HTMLElement[], name: string) {\n    this.handler = handler;\n    this.node = node;\n    this.name = name;\n    this.arrayBaseName = node.dataset.whFormGroupFor || throwError(\"Missing array base name\");\n\n    // The template for new rows. If we have arrays-in-array, it will still be the first <template>\n    this.template = qS<HTMLTemplateElement>(node, \"template\") || throwError(\"Missing array template\");\n    // The node before which to add new rows\n    this.insertPoint = this.template.parentNode!.lastElementChild! as HTMLElement;\n    if (!this.insertPoint.matches(\".wh-form__arrayadd\"))\n      throw new Error(\"Missing array insert point\");\n\n    // Event handler for add/delete button clicks\n    this.insertPoint.addEventListener(\"click\", event => this.onAddRow(event));\n    addDocEventListener(node, \"click\", event => this._onClick(event));\n\n    // Proxy node for getting/setting properties and receiving events\n    this.valueNode = qS<HTMLInputElement>(node, \"input.wh-form__arrayinput\") ?? throwError(\"Missing array input\");\n    this.valueNode.whUseFormGetValue = true;\n    this.valueNode.addEventListener(\"wh:form-getvalue\", event => this._onGetValue(event));\n    //@ts-expect-error wh:form-setvalue isn't defined - but it'll go away anyway\n    this.valueNode.addEventListener(\"wh:form-setvalue\", event => this._onSetValue(event));\n\n    // Initialize initial value rows\n    for (const rownode of qSA(this.node, \".wh-form__arrayrow\"))\n      this._fixupRowNode(rownode);\n\n    this._checkValidity();\n  }\n\n  get form(): FormBase {\n    const form = getFormHandler(this.node.closest(\"form\") ?? throwError(\"Could not find <form>\")) ?? throwError(\"Could not find form for arrayfield\");\n    if (!form._getFieldsToValidate) //avoid calling into formbase from our constructor, it may not be there yet...\n      throw new Error(\"The <form> is not ready yet\");\n    return form;\n  }\n\n  addRow(): HTMLElement {\n    // Instatiate a new row\n    const newrow = this.template.content.cloneNode(true) as HTMLElement;\n    (newrow.firstElementChild! as HTMLElement).dataset.whFormRowid = String(this.nextrowid++);\n\n    // Insert the new row\n    this.insertPoint.parentNode!.insertBefore(newrow, this.insertPoint);\n    const addedrow = this.insertPoint.previousElementSibling! as HTMLElement;\n\n    /* If the form is relying on legacy dompack.register to go through ImgEditField and do the actual\n       customElements.define call.... then the 'name' attributes won't actually work on the 'new' elements.\n       therefore dompack.registerMissed must run before _fixupRowNode */\n    registerMissed(addedrow);\n    setup(addedrow);\n\n    this._fixupRowNode(addedrow as HTMLElement);\n    this._checkValidity();\n    this.form.__scheduleUpdateConditions();\n    return this.insertPoint.previousSibling as HTMLElement;\n  }\n\n  /* seems a unused API ?.  .. if we need to provide this, just let people pass us a row node instead of understanding IDs\n    removeRow(id)\n    {\n      // Remove a row by id\n      let node = this.node.querySelector(`.wh-form__arrayrow[data-row-id=${id}]`);\n      if (node)\n        this._removeRowNode(node);\n    }\n  */\n\n  private onAddRow(event: Event) {\n    stop(event);\n    this.addRow();\n  }\n  _onClick(event: DocEvent<MouseEvent>) {\n    // Check if a delete button was clicked\n    const delNode = event.target.closest(\".wh-form__arraydelete\");\n    if (delNode) {\n      event.preventDefault();\n      this._removeRowNode(delNode.closest(\".wh-form__arrayrow\")!);\n    }\n  }\n\n  getRowHandler(row: HTMLElement): RecordFieldHandler {\n    const rowBaseName = this.valueNode.name + \".\" + row.dataset.whFormRowid;\n    const rowFields = getFormElementCandidates(row, rowBaseName).filter(_ => _.dataset.whFormCellname !== \"row_uid\"); //row_uid points back to us, so requesting that triggers a loop\n    return new RecordFieldHandler(this.handler, rowBaseName, rowFields);\n  }\n\n  getValue() {\n    const rows = [];\n    for (const row of qSA(this.node, \".wh-form__arrayrow\").filter(n => n.parentNode === this.template.parentNode)) {\n      const handler = this.getRowHandler(row);\n      const rowval = handler.getValue();\n      rows.push(rowval);\n    }\n    return rows;\n  }\n\n  _onGetValue(event: CustomEvent<{ deferred: PromiseWithResolvers<unknown> }>) {\n    // We're using the deferred promise to return our value\n    event.preventDefault();\n    event.stopPropagation();\n\n    // Create a promise for each row that resolves with the combined value of all fields in the row\n    const valuePromises = [];\n    for (const row of qSA(this.node, \".wh-form__arrayrow\").filter(n => n.parentNode === this.template.parentNode)) {\n      const rowFields = this._queryAllFields(row);\n      // Create a promise for each of the row's subfields to get its value\n      const rowPromises = rowFields.map(field => (this.form as FormBase)._getQueryiedFieldValue(field)); //FIXME get rid of 'as FormBase' to support array-in-array\n      // Add an all promise for the value promises and add it to the list of row promises\n      valuePromises.push(Promise.all(rowPromises).then(values => {\n        // Combine the values into a value object for this row\n        const rowValue: Record<string, unknown> = { formrowid: row.dataset.whFormRowid };\n        values.forEach((value, idx) => {\n          // The values are returned in the order that the promises were added to the list of value promises, so we can use\n          // the index of the value to get the original field\n          const rowField = rowFields[idx];\n          const firstnode = rowField.multi ? rowField.nodes[0] : rowField.node;\n          rowValue[firstnode.dataset.whFormCellname!] = value;\n        });\n        return rowValue;\n      }));\n    }\n    // Wait for all the row promises (which resolves with a list of promise resolution values, which will be the final value\n    // of the array field)\n    Promise.all(valuePromises).then(valueRows => event.detail.deferred.resolve(valueRows));\n  }\n\n  setValue(newvalue: unknown[]) {\n    if (!Array.isArray(newvalue))\n      throw new Error(`Invalid value for array field '${this.name}': ${JSON.stringify(newvalue)}`);\n\n    // Remove all current rows (TODO optimize)\n    while (this.insertPoint.previousElementSibling?.classList.contains(\"wh-form__arrayrow\"))\n      this._removeRowNode(this.insertPoint.previousElementSibling);\n\n    // Check if we have an array value\n    for (const value of newvalue) {\n      // Add a row\n      const row = this.addRow();\n      const handler = this.getRowHandler(row);\n      handler.setValue(value);\n    }\n    this._checkValidity();\n  }\n\n  _onSetValue(event: CustomEvent<{ value: unknown }>) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    // Remove all current rows\n    while (this.insertPoint.previousElementSibling?.classList.contains(\"wh-form__arrayrow\"))\n      this._removeRowNode(this.insertPoint.previousElementSibling);\n\n    // Check if we have an array value\n    if (Array.isArray(event.detail.value)) {\n      for (const value of event.detail.value) {\n        // Add a row\n        const row = this.addRow();\n        // Initialize the row's fields\n        for (const field of this._queryAllFields(row)) {\n          for (const fieldnode of (field.multi ? field.nodes : [field.node])) {\n            if (fieldnode.dataset.whFormCellname && fieldnode.dataset.whFormCellname in value) {\n              (this.form as FormBase).setFieldValue(fieldnode, value[fieldnode.dataset.whFormCellname]); //FIXME get rid of 'as FormBase' to support array-in-array\n            }\n          }\n        }\n      }\n    }\n    this._checkValidity();\n  }\n\n  _fixupRowNode(node: HTMLElement) {\n    const rowid = node.dataset.whFormRowid;\n\n    // Rename all fields to avoid duplicate field names\n    const mapping = new Map<string, string>;\n    for (const fieldnode of getFormElementCandidates(node, this.arrayBaseName)) {\n\n      // Leave embedded arrayfields alone! Except if this is specifically the wh-form__arrayinput one level down\n      const nodeArray = fieldnode.closest(\".wh-form__fieldgroup--array\");\n      if (nodeArray && nodeArray !== this.node && !(fieldnode.matches(\".wh-form__arrayinput\") && (nodeArray.parentNode! as HTMLElement).closest(\".wh-form__fieldgroup--array\") === this.node)) {\n        // console.log(\"Skipping\", fieldnode, \"as it's not in our array\");\n        continue;\n      }\n\n      // Rename fields\n      const fieldname = getFieldName(fieldnode);\n      // When rendering, the fields simply have their arrayname prefixed in their name=, see InstantiateField in array.whlib (TODO seems dangerous, eg preset radio buttons interfering with each other?\n      // So we'll just take the part after the first dot as the cellname\n      fieldnode.dataset.whFormCellname ||= fieldname.substring(this.arrayBaseName.length + 1);\n\n      const cellname: string = fieldnode.dataset.whFormCellname;\n      const subname = this.valueNode.name + \".\" + rowid + \".\" + cellname;\n      // console.log(\"for\", this.name, \"rename\", fieldname, \"to\", subname, fieldnode);\n      setFieldName(fieldnode, subname);\n      mapping.set(fieldname, subname);\n\n      // Rename id's to make them unique; update the labels within the field's fieldgroup to point to the new id\n      if (fieldnode.id) {\n        const labelnodes = qSA<HTMLLabelElement>(node, `label[for=\"${fieldnode.id}\"]`);\n        fieldnode.id += \"-\" + rowid;\n        for (const labelnode of labelnodes)\n          labelnode.htmlFor = fieldnode.id;\n      }\n\n      // Rewrite conditions after all fields have been renamed\n      for (const type of [\"visible\", \"enabled\", \"required\"]) {\n        for (const conditionnode of qSA(node, `[data-wh-form-${type}-if]`)) {\n          const condition = parseCondition(conditionnode.dataset[`whForm${type[0].toUpperCase() + type.slice(1)}If`]!);\n          if (fixupConditionRecursive(node, condition, mapping))\n            conditionnode.dataset[`whForm${type[0].toUpperCase() + type.slice(1)}If`] = JSON.stringify({ c: condition });\n        }\n      }\n    }\n\n    this.getRowHandler(node); //initializes deeper arrays. fieldmap should probably be handling this and build a full mapping top to botom...\n  }\n\n  _removeRowNode(node: Element) {\n    // Remove the row node\n    node.remove();\n    this._checkValidity();\n  }\n\n  _checkValidity() {\n    const minRows = parseInt(this.valueNode.dataset.whMin || \"0\");\n    const maxRows = parseInt(this.valueNode.dataset.whMax || \"0\");\n\n    const numRows = this.node.querySelectorAll(\".wh-form__arrayrow\").length;\n    if (numRows < minRows)\n      this.valueNode.setCustomValidity(getTid(\"publisher:site.forms.commonerrors.minarray\", minRows));\n    else if (maxRows > 0 && numRows > maxRows)\n      this.valueNode.setCustomValidity(getTid(\"publisher:site.forms.commonerrors.maxarray\", maxRows));\n    else\n      this.valueNode.setCustomValidity(\"\");\n\n    // Disable the add button if the maximum number of rows is reached\n    if (maxRows > 0 && numRows >= maxRows)\n      this.node.classList.add(\"wh-form__array--maxrows\");\n    else\n      this.node.classList.remove(\"wh-form__array--maxrows\");\n  }\n\n  _queryAllFields(node: HTMLElement) {\n    return (this.form as FormBase)._queryAllFields({ startnode: node, skipfield: this.valueNode });  //FIXME get rid of 'as FormBase' to support array-in-array\n  }\n}\n","import { getFieldName } from \"./domsupport\";\nimport { rfSymbol, type FormFieldAPI } from \"./registeredfield\";\nimport ArrayField from \"@mod-publisher/js/forms/fields/arrayfield\";\nimport type { AddressValue } from \"@webhare/address\";\nimport { omit, nameToSnakeCase, nameToCamelCase, throwError, isDate } from \"@webhare/std\";\nimport type { RecursivePartial } from \"@webhare/js-api-tools\";\nimport type { FormFieldLike } from \"./jsformelement\";\n\nexport interface FormParent {\n  __scheduleUpdateConditions(): void;\n}\n\n\ninterface FormField {\n  getValue(): unknown;\n\n  /** Set a value\n   * @param newvalue - The new value to set\n   * @param ignoreInvalid - Do not throw if the value is invalid. Used for eg. prefills which can't usefully handle it anyway\n   * @returns True if succesfully set */\n\n  setValue(newvalue: unknown): void;\n}\n\ntype ValueType = \"number\" | \"boolean\" | \"date\";\n\nfunction unmapFieldName(camelCaseName: string) {\n  return camelCaseName.startsWith(\"__formfield\") ? camelCaseName : nameToSnakeCase(camelCaseName);\n\n}\nfunction mapFieldName(htmlName: string) {\n  return htmlName.startsWith(\"__formfield\") ? htmlName : nameToCamelCase(htmlName);\n}\n\nfunction mapValue(type: ValueType, invalue: string) {\n  switch (type) {\n    case \"number\":\n      return parseFloat(invalue);\n    case \"boolean\":\n      return invalue === \"true\";\n    case \"date\":\n      return new Date(invalue);\n  }\n}\n\nfunction unmapValue(type: ValueType | undefined, invalue: unknown, fieldDescr: string) {\n  switch (type) {\n    case null:\n      if (typeof invalue !== \"string\")\n        throw new Error(`Invalid type ${typeof invalue} for string field ${fieldDescr}: ${invalue}`);\n      return invalue;\n\n    case \"number\":\n      if (typeof invalue !== \"number\")\n        throw new Error(`Invalid type ${typeof invalue} for number field ${fieldDescr}: ${invalue}`);\n      return String(invalue);\n\n    case \"boolean\":\n      if (typeof invalue !== \"boolean\")\n        throw new Error(`Invalid type ${typeof invalue} for boolean field ${fieldDescr}: ${invalue}`);\n      return String(invalue);\n\n    case \"date\":\n      if (!isDate(invalue))\n        throw new Error(`Invalid type ${typeof invalue} for date field ${fieldDescr}: ${invalue}`);\n      return invalue.toISOString();\n  }\n}\n\nclass HTMLFormFieldHandler implements FormField {\n  valuetype?: ValueType;\n  private form: FormParent;\n  private readonly field: FormFieldLike;\n\n  constructor(form: FormParent, field: FormFieldLike) {\n    this.form = form;\n    this.field = field;\n    this.valuetype = field.dataset.whFormValueType as undefined | ValueType;\n    if (!this.valuetype && field.matches('input[type=number]'))\n      this.valuetype = \"number\";\n  }\n\n  getValue(): unknown {\n    if (this.field.matches('input[type=checkbox]'))\n      return (this.field as HTMLInputElement).checked;\n    if (this.field.matches('input[type=date]'))\n      return (this.field as HTMLInputElement).valueAsDate;\n\n    if (this.field.tagName === \"SELECT\") {\n      const selectedrow = (this.field as HTMLSelectElement).selectedOptions[0];\n      if (!selectedrow || selectedrow.dataset.placeholder !== undefined)\n        return null; //didn't select a 'real' option\n\n      return this.valuetype ? mapValue(this.valuetype, selectedrow.value) : selectedrow.value;\n    }\n\n    return this.valuetype ? mapValue(this.valuetype, this.field.value as string) : this.field.value;\n  }\n\n  setValue(newvalue: unknown): void {\n    if (this.field.matches('input[type=checkbox]')) {\n      //For convenience we're interpreting setting a checkbox as 'truthy' instead of explicit true/false\n      const setvalue = Boolean(newvalue);\n      if (setvalue === (this.field as HTMLInputElement).checked)\n        return;\n\n      (this.field as HTMLInputElement).checked = setvalue;\n    } else if (this.field.matches('input[type=date]')) {\n      if ((this.field as HTMLInputElement)?.valueAsDate?.getTime() === (newvalue as Date | null)?.getTime())\n        return;\n      (this.field as HTMLInputElement).valueAsDate = newvalue as Date;\n    } else if (this.field.tagName === \"SELECT\" && newvalue === null) { //'null' resets the select to 'no value', so figure out if there's a placeholder row\n      const setvalue = (this.field as HTMLSelectElement).options[0]?.dataset.placeholder !== undefined ? 0 : -1;\n      if ((this.field as HTMLSelectElement).selectedIndex === setvalue)\n        return;\n      (this.field as HTMLSelectElement).selectedIndex = setvalue;\n    } else {\n      const setvalue = this.valuetype ? unmapValue(this.valuetype, newvalue, this.field.name) : newvalue;\n      if (this.field.value === setvalue)\n        return;\n      this.field.value = setvalue;\n    }\n    this.form.__scheduleUpdateConditions();\n  }\n}\n\nclass RadioFormFieldHandler implements FormField {\n  valuetype?: ValueType;\n  private form: FormParent;\n  private readonly name: string;\n  private readonly rnodes: HTMLInputElement[];\n\n  constructor(form: FormParent, name: string, rnodes: HTMLInputElement[]) {\n    this.form = form;\n    this.name = name;\n    this.rnodes = rnodes;\n    const group = rnodes[0].closest<HTMLElement>(\".wh-form__fieldgroup\");\n    if (!group) { //value metadata is stored at the fieldgroup level, so reject these\n      console.error(\"Missing group for radiofield \", group);\n      console.error('if a radio field does not want to participate in the form, it should set attribute form=\"\"');\n    } else {\n      this.valuetype = group.dataset.whFormValueType as undefined | ValueType;\n    }\n  }\n  getValue(): unknown {\n    const node = this.rnodes.find(_ => _.checked);\n    return (node ? this.valuetype ? mapValue(this.valuetype, node.value) : node.value : null);\n  }\n  setValue(newvalue: unknown): void {\n    if (newvalue === null) {\n      for (const node of this.rnodes)\n        node.checked = false;\n\n      this.form.__scheduleUpdateConditions();\n      return;\n    }\n\n    const myname = `radio group ${this.name}`;\n    const setvalue = unmapValue(this.valuetype, newvalue, myname);\n\n    const node = this.rnodes.find(_ => _.value === setvalue);\n    if (!node)\n      throw new Error(`No such value '${setvalue}' in radio group '${this.name}`);\n\n    node.checked = true;\n    this.form.__scheduleUpdateConditions();\n  }\n}\n\nclass CheckboxGroupHandler implements FormField {\n  valuetype?: ValueType;\n  private form: FormParent;\n  private readonly name: string;\n  private readonly cboxes: HTMLInputElement[];\n\n  constructor(form: FormParent, name: string, cboxes: HTMLInputElement[]) {\n    this.form = form;\n    this.name = name;\n    this.cboxes = cboxes;\n    this.valuetype = (cboxes[0].closest<HTMLElement>(\".wh-form__fieldgroup\") ?? throwError(\"RadioFormFieldHandler: Missing group\")).dataset.whFormValueType as undefined | ValueType;\n  }\n  getValue(): unknown {\n    return this.cboxes.filter(_ => _.checked).map(_ => this.valuetype ? mapValue(this.valuetype, _.value) : _.value);\n  }\n  setValue(newvalue: unknown): void {\n    const myname = `checkbox group '${this.name}'`;\n    if (!Array.isArray(newvalue))\n      throw new Error(`Value for ${myname} should be an array, got '${JSON.stringify(newvalue)}'`);\n\n    const toset = newvalue.map(_ => unmapValue(this.valuetype, _, myname));\n\n    this.cboxes.forEach(_ => _.checked = toset.includes(_.value));\n    this.form.__scheduleUpdateConditions();\n\n    //in case the error is caught and ignored (eg prefill), we'll update what we can\n    const missing = toset.filter(_ => !this.cboxes.some(cbox => cbox.value === _));\n    if (missing.length)\n      throw new Error(`Invalid value(s) for ${myname}: ${missing.join(', ')}`);\n  }\n}\n\nclass RegisteredFieldHandler implements FormField {\n  protected form: FormParent;\n  private readonly field: FormFieldAPI;\n\n  constructor(form: FormParent, field: FormFieldAPI) {\n    this.form = form;\n    this.field = field;\n  }\n\n  getValue(): unknown {\n    return this.field.getValue();\n  }\n  setValue(newvalue: unknown): void {\n    this.field.setValue(newvalue);\n  }\n}\n\nexport class ArrayFieldHandler extends RegisteredFieldHandler implements FormField {\n  private node: HTMLElement;\n\n  constructor(form: FormParent, node: HTMLElement, items: HTMLElement[]) {\n    node[rfSymbol] ||= new ArrayField(form, node, items, getFieldName(items[0]));\n    super(form, node[rfSymbol]);\n    this.node = node;\n  }\n\n  __scheduleUpdateConditions() {\n    this.form.__scheduleUpdateConditions();\n  }\n}\n\n/** The FormFieldMap exposes a multi-level (ie unflattened) view of the form values. Internally it works with the\n   original names because generated fields names, eg __formfieldbbbwVsWih_0DrJOc0beS7Q_, cannot be assumed to be snake_case and convertable */\nexport abstract class FormFieldMap<DataShape> {\n  /** Field mapping. Uses original names */\n  protected fieldmap = new Map<string, FormField>();\n  protected fieldName: string;\n\n  constructor(fieldName: string, nodes: HTMLElement[]) {\n    this.fieldName = fieldName;\n    const subpos = fieldName ? fieldName.length + 1 : 0;\n    const groups = Map.groupBy(nodes, _ => getFieldName(_).substring(subpos).split('.')[0]);\n\n    for (const [name, items] of groups) {\n      const fullName = (fieldName ? fieldName + '.' : '') + name;\n      if (!name) {\n        console.error(`There are fields without a name:`, items);\n        continue;\n      }\n\n      if (items[0].matches('input[type=radio]')) {\n        this.fieldmap.set(name, new RadioFormFieldHandler(this, fullName, items as HTMLInputElement[]));\n        continue;\n      }\n\n      if (items[0].matches('.wh-form__arrayinput')) {\n        const arraygroup = items[0].closest<HTMLElement>('.wh-form__fieldgroup--array');\n        if (arraygroup) {\n          this.fieldmap.set(name, new ArrayFieldHandler(this, arraygroup, items));\n          continue;\n        }\n      }\n\n      const hasGroupLeader = getFieldName(items[0]) === fullName; //ie name has no followup '.xx'\n      if (hasGroupLeader) { //if no subname, it's the group leader ?\n        if (items[0].matches('input[type=checkbox]')) {//is it a checkbox group?\n          const cboxgroup = items[0].closest(\".wh-form__fieldgroup--checkboxgroup\");\n          if (cboxgroup) {\n            this.fieldmap.set(name, new CheckboxGroupHandler(this, fullName, items as HTMLInputElement[]));\n            continue;\n          }\n        }\n\n        this.fieldmap.set(name, new HTMLFormFieldHandler(this, items[0] as FormFieldLike));\n        continue;\n      }\n\n      //We're an implicit record (even if with just one member)\n      if (items[0].matches('select[name$=\".country\"][data-orderingdata]')) //looks like address.whlib\n        this.fieldmap.set(name, new AddressFieldHandler(this, fullName, items));\n      else\n        this.fieldmap.set(name, new RecordFieldHandler(this, fullName, items));\n    }\n  }\n\n  abstract __scheduleUpdateConditions(): void;\n\n  /** Get a field handler by name */\n  getField(name: string, options: { allowMissing: true }): FormField | null;\n  getField(name: string, options?: { allowMissing?: boolean }): FormField;\n\n  getField(name: string, options?: { allowMissing?: boolean }): FormField | null {\n    const mapName = unmapFieldName(name);\n    const match = this.fieldmap.get(mapName);\n    if (match)\n      return match;\n    if (options?.allowMissing)\n      return null;\n\n    throw new Error(`Field '${name}' not found in this form`); //TODO report the fukll anme\n  }\n\n  getFieldNames(): string[] {\n    return [...this.fieldmap.keys()].map(mapFieldName);\n  }\n\n  /** Set a value for multiple fields\n   * @param data - The data to set\n   * @param ignoreUnknownFields - Do not throw if a field is not found in the form. This is the default\n   */\n  assign(data: RecursivePartial<DataShape>, { ignoreUnknownFields = true } = {}) {\n    for (const [key, value] of Object.entries(data as object)) {\n      const field = this.getField(key, { allowMissing: ignoreUnknownFields });\n      if (field)\n        field.setValue(value);\n    }\n  }\n}\n\nexport class RecordFieldHandler extends FormFieldMap<object> implements FormField {\n  private form: FormParent;\n\n  constructor(form: FormParent, baseName: string, nodes: HTMLElement[]) {\n    super(baseName, nodes);\n    this.form = form;\n  }\n\n  getValue(): unknown {\n    const retval: Record<string, unknown> = {};\n    for (const [name, field] of this.fieldmap) {\n      const val = field.getValue();\n      if (val !== undefined) //Suppress undefined values (where we cannot safely re-set them, eg images in Object.keys\n        retval[mapFieldName(name)] = val;\n    }\n\n    return retval;\n  }\n\n  setValue(newvalue: unknown): void {\n    if (typeof newvalue !== 'object' || newvalue === null)\n      throw new Error(`Invalid value for record field '${this.fieldName}': ${newvalue}`);\n\n    for (const [name, field] of this.fieldmap) {\n      const prettyName = mapFieldName(name);\n      if (prettyName in newvalue)\n        field.setValue((newvalue as Record<string, unknown>)[prettyName]);\n    }\n  }\n\n  __scheduleUpdateConditions() {\n    this.form.__scheduleUpdateConditions();\n  }\n}\n\n/* TODO cleanup... this is a workaround to translate nr_detail to houseNumber. ideally the server would just send house_number as field\n        name but that transition will take time. also we need a nice way to 'take over' addressifelds rather than fieldmapper special casing\n        its detection\n*/\ntype OldAddressValue = Omit<AddressValue, \"houseNumber\"> & { nrDetail?: string };\n\nclass AddressFieldHandler extends RecordFieldHandler {\n  constructor(form: FormParent, baseName: string, nodes: HTMLElement[]) {\n    super(form, baseName, nodes);\n  }\n\n  getValue(): unknown {\n    const val = super.getValue() as OldAddressValue;\n    if (!val?.country)\n      return null;\n\n    return val?.nrDetail !== undefined ? { ...omit(val, [\"nrDetail\"]), houseNumber: val.nrDetail } : val;\n  }\n\n  setValue(val: unknown) {\n    if (val === null) {\n      super.setValue({ country: null, city: \"\", street: \"\", zip: \"\", nrDetail: \"\", state: \"\" });\n      return;\n    }\n\n    ///@ts-expect-error ugly hack, not really worth overwriting with as\n    super.setValue(val?.houseNumber !== undefined ? { ...omit(val, [\"houseNumber\"]), nrDetail: val.houseNumber } : val);\n  }\n}\n\nexport class FieldMapDataProxy implements ProxyHandler<object> {\n  private readonly form: FormFieldMap<object>;\n\n  constructor(form: FormFieldMap<object>) {\n    this.form = form;\n  }\n  get(target: object, p: string | symbol) {\n    //Don't attempt to validate getters... it will break various introspection calls (eg requesting constructor, checking for 'then'...)\n    const field = typeof p === \"string\" ? this.form.getField(p, { allowMissing: true }) : null;\n    return field ? field.getValue() : (target as Record<string | symbol, unknown>)[p];\n  }\n  set(target: unknown, p: string, value: unknown): boolean {\n    this.form.getField(p).setValue(value);\n    return true;\n  }\n  ownKeys(target: object): ArrayLike<string | symbol> {\n    return this.form.getFieldNames();\n  }\n  getOwnPropertyDescriptor(target: unknown, prop: string) { // allows ownKeys to actually return to Object.keys\n    return { enumerable: true, configurable: true };\n  }\n}\n","import * as dompack from 'dompack';\nimport { getTid, getTidLanguage } from \"@webhare/gettid\";\nimport { getFormService } from \"@webhare/forms/src/formservice\";\nimport { isValidEmail, wrapInTimeout } from '@webhare/std';\nimport { setFieldError } from './customvalidation';\nimport type { EmailValidationResult } from '@webhare/forms/src/types';\nimport type FormBase from '../formbase';\nimport type RPCFormBase from '../rpc';\nimport { debugFlags } from '@webhare/env';\n\nconst cache:\n  {\n    [key: string]: Promise<EmailValidationResult>;\n  } = {};\n\nfunction mayValidateField(field: HTMLInputElement) {\n  if (field.disabled || field.readOnly) //FIXME shouldn't we just decide not to validate at a much higher level if something cannot be changed ?\n    return false;\n\n  if (field.autocomplete && field.autocomplete.split(' ').includes(\"username\")) //Well, we shouldn't *force* usernames as a blacklisted domain might still have been explicitly added as login. but suggestions are still useful?\n    return false;\n  return true;\n}\n\nfunction acceptEmailSuggestion<DataShape extends object = Record<string, unknown>>(evt: Event, form: FormBase<DataShape>, field: HTMLInputElement, suggestion: string) {\n  dompack.stop(evt);\n  field.value = suggestion;\n  field.propWhValidationSuggestion = null;\n  form._reportFieldValidity(field);\n}\n\nexport async function validateField<DataShape extends object = Record<string, unknown>>(form: FormBase<DataShape> | RPCFormBase<DataShape>, field: HTMLInputElement) {\n  if (field.dataset.whFormEmailBlocked) {\n    delete field.dataset.whFormEmailBlocked;\n    setFieldError(field, \"\"); //explicitly clear our earlier setFieldError, but only if we set it. FIXME To really cleanly solve this we need better integration with rpc.ts - we want to be in the setupValidation chain and simply return errors instead of being explictly invoked\n  }\n\n  const checkvalue: string = field.value;\n  if (!checkvalue || !mayValidateField(field)) {\n    return true; //not a problem\n  }\n\n  if (!isValidEmail(checkvalue)) {\n    //TODO why aren't we just returning the error like a validator callback? may also help avoid the whFormEamailBlocked hack..\n    field.dataset.whFormEmailBlocked = \"true\";\n    setFieldError(field, getTid(\"publisher:site.forms.commonerrors.email\"));\n    return false;\n  }\n\n  //user is 'done' with email field apparently. remotely validate it\n  const key = \"e_\" + field.name + \".\" + checkvalue; //e_ prefix protects against funny people using 'constructor' etc. TODO just switch to a Map<> or similar. TODO only include field.name if needed, and also bind to the form then\n  if (cache[key] === undefined) {\n    const rpcCall = \"getRPCFormIdentifier\" in form ?\n      //TODO rendering.whlib should add a data attribute if there are form+field-specific checks, perhaps we can even generalize that for all fields instead of just email whenever they need to do direct validation\n      getFormService().formValidateEmail({ ...form.getRPCFormIdentifier(), field: field.name }, checkvalue)\n      : getFormService().validateEmail(getTidLanguage(), checkvalue);\n\n    //wrap in timeout\n    cache[key] = wrapInTimeout(rpcCall, 3000, \"Timeout\");\n  }\n\n  //TODO should we ever clear the cache? only relevant probably if someone is on the frontend testing emails and doesn't want to refresh\n  let result: EmailValidationResult | undefined;\n\n  try {\n    result = await cache[key];\n  } catch (e) { //timeout or other error, or offline form (PWA?)\n    if (debugFlags.fhv)\n      console.log('[fhv] Email validation error or timeout for value', checkvalue, e);\n  }\n\n  if (checkvalue !== field.value || !mayValidateField(field))\n    return true; //the field already changed, don't report about old errors\n\n  if (result?.blocked) {\n    field.dataset.whFormEmailBlocked = \"true\";\n    setFieldError(field, result.blocked);\n    return false;\n  }\n\n  if (result?.force) {\n    field.value = result.force;\n\n    //we should be able to assume we won't have to revalidate a server-provided suggestion\n    cache[\"e_\" + field.name + \".\" + result.force] = Promise.resolve<EmailValidationResult>({});\n\n    return true;\n  } else if (result?.suggestion) {\n    const suggestion = getTid(\"publisher:site.forms.commonerrors.email_suggestion\", \"___SUGGESTION___\").split(\"___SUGGESTION___\");\n\n    //we should be able to assume we won't have to revalidate a server-provided suggestion\n    cache[\"e_\" + field.name + \".\" + result.suggestion] = Promise.resolve<EmailValidationResult>({});\n\n    field.propWhValidationSuggestion =\n      <span class=\"wh-form__emailcorrection\">\n        {suggestion[0]}\n        <a href=\"#\" class=\"wh-form__emailcorrected\" on={{ click: (evt: Event) => acceptEmailSuggestion(evt, form, field, result.suggestion as string) }}>{result.suggestion}</a>\n        {suggestion[1]}\n      </span>;\n    return true;\n  }\n  return true;\n}\n","/* Dialogapi offers an API to which dialog providers cannot connect. It does\n   not implement the dialogs themselves\n*/\n\nimport * as dompack from 'dompack';\nimport * as domfocus from 'dompack/browserfix/focus';\nimport KeyboardHandler from \"dompack/extra/keyboard\";\n\nexport type DialogOptions =\n  {\n    /**  Allow the dialog to be cancelled by clicking outside the dialog. Defaults to true if no choices are specified */\n    allowcancel?: boolean;\n    /**  Element to focus on closing the dialog */\n    focusonclose?: HTMLElement;\n    /**  An AbortSignal which if set will close the dialog and resolve it with a null response */\n    signal?: EventTarget;\n    /**  Additional class to set on the dialog */\n    messageboxclassbase?: string;\n\n    borrow?: Element | string;\n  };\ntype DialogConstructor = (options?: DialogOptions) => DialogBase;\n\nconst dialogstack: DialogBase[] = [];\nlet keyhandler: KeyboardHandler | null = null;\nlet dialogconstructor: DialogConstructor | null = null;\nlet dialogoptions: DialogOptions | null = null;\n\nfunction onEscape(event: KeyboardEvent) {\n  if (!dialogstack.length)\n    return;\n\n  dompack.stop(event);\n  if (dialogstack[dialogstack.length - 1].options.allowcancel)\n    dialogstack[dialogstack.length - 1].resolve(null);\n}\n\nfunction onTab(event: KeyboardEvent, direction: number) {\n  if (!dialogstack.length)\n    return;\n\n  dompack.stop(event);\n\n  const focusable = domfocus.getFocusableComponents(dialogstack[dialogstack.length - 1].contentnode, true);\n  const el = domfocus.getCurrentlyFocusedElement();\n  const tofocusidx = el ? focusable.indexOf(el) + direction : -1;\n  const tofocus = tofocusidx < 0 ? focusable[focusable.length - 1] : tofocusidx >= focusable.length ? focusable[0] : focusable[tofocusidx];\n  if (tofocus)\n    dompack.focus(tofocus);\n}\n\nexport class DialogBase {\n  options: DialogOptions;\n  private _borrowedfrom: Element | null = null;\n  private _borrowednext: Element | null = null;\n  contentnode: Element | null; //FIXME a successor to DialogBase should not allow these to be | null. have our child inform us through super() about the contentnode and buttonsnode so we can ensure it's set\n  buttonsnode: Element | null = null;\n  private _deferred: PromiseWithResolvers<string | null>;\n  open: boolean;\n  private _previousfocus: Element | null = null;\n\n  constructor(options?: DialogOptions) {\n    this.options = {\n      allowcancel: true,\n      ...options\n    };\n\n    if (this.options.borrow && typeof this.options.borrow === 'string') {\n      const borrow = document.querySelector(this.options.borrow);\n      if (!borrow)\n        throw new Error(\"Invalid 'borrow' selectior: \" + this.options.borrow);\n      this.options.borrow = borrow;\n    }\n    // At this point, if this.options.borrow was a string, it's been resolved to an Element\n\n    if (this.options.borrow) {\n      this._borrowedfrom = (this.options.borrow as Element).parentElement;\n      this._borrowednext = (this.options.borrow as Element).nextElementSibling;\n    }\n\n    if (this.options.signal)\n      this.options.signal.addEventListener(\"abort\", () => { this.resolve(null); });\n\n    this.contentnode = null;\n    this._deferred = Promise.withResolvers();\n    this.open = false;\n  }\n\n  async runModal() {\n    if (this.open)\n      throw new Error(\"Attempting to re-open already opened dialog\");\n\n    if (!keyhandler)\n      keyhandler = new KeyboardHandler(window, {\n        \"Escape\": (evt: KeyboardEvent) => onEscape(evt),\n        \"Tab\": (evt: KeyboardEvent) => onTab(evt, +1),\n        \"Shift+Tab\": (evt: KeyboardEvent) => onTab(evt, -1)\n      }, { captureunsafekeys: true, listenoptions: { capture: true } });\n\n    this._previousfocus = domfocus.getCurrentlyFocusedElement();\n    this._openDialog();\n\n    this.open = true;\n    dialogstack.push(this);\n\n    try {\n      this.afterShow();\n      this._checkFocus();\n      return await this._deferred.promise;\n    } finally {\n      if (this.open)\n        this.closeDialog();\n    }\n  }\n\n  _openDialog() {\n    throw new Error(\"_openDialog not overridden by dialog class\");\n  }\n\n  _checkFocus() {\n    const focusable = domfocus.getFocusableComponents(this.contentnode, true);\n    if (focusable.length !== 0)\n      dompack.focus(focusable[0]);\n    else\n      dompack.focus(document.body);\n  }\n\n  //close the dialog. this may be invoked even when inside runModal to ensure synchronous dialog cleanup\n  closeDialog() {\n    if (!this.open)\n      return;\n\n    const myoffset = dialogstack.indexOf(this);\n    if (myoffset >= 0)\n      dialogstack.splice(myoffset, 1);\n\n    this.open = false;\n    if (this.options.borrow)\n      if (this._borrowedfrom)\n        this._borrowedfrom.insertBefore(this.options.borrow as Element, this._borrowednext);\n      else\n        this._borrowednext?.remove();\n\n    if (this.options.focusonclose)\n      dompack.focus(this.options.focusonclose);\n    else if (this._previousfocus)\n      dompack.focus(this._previousfocus as HTMLElement);\n\n    if (dialogstack.length === 0 && keyhandler) {\n      keyhandler.destroy();\n      keyhandler = null;\n    }\n  }\n\n  /**\n   * resolve the dialog with the specified answer\n   *\n   * @param response - Response (or choice) to return. null if the dialog was simply cancelled\n   */\n  resolve(response: string | null) {\n    if (this.open)\n      this.closeDialog();\n    this._deferred.resolve(response);\n  }\n\n  afterShow() {\n    // supposed to be empty but extenders can override\n  }\n}\n\nexport function setupDialogs(newdialogconstructor: DialogConstructor, options?: DialogOptions) {\n  if (dialogconstructor) {\n    console.error(\"Duplicate setupDialogs call!\");\n    return;\n  }\n\n  dialogconstructor = newdialogconstructor;\n  dialogoptions = { messageboxclassbase: 'dompack-messagebox__', ...options };\n}\n\n/** Verify whether the dialog api is initialized */\nexport function isCreateDialogAvailable(): boolean {\n  return Boolean(dialogconstructor);\n}\n\n/**\n * Create a dialog\n *\n * @param options - dialog settings\n */\nexport function createDialog(options?: DialogOptions) {\n  if (!dialogconstructor)\n    throw new Error(\"Cannot create dialog, no dialog class defined\");\n\n  const dialog = dialogconstructor(options);\n  if (dialog.options.borrow)\n    dialog.contentnode?.appendChild(dialog.options.borrow as Element);\n  return dialog;\n}\n\ntype DialogChoice =\n  {\n    /** Title for the choice */\n    title: string;\n    /** Override result to return if clicked (otherwise you'll just receive the title) */\n    result?: string;\n    className?: string;\n  };\n\n\n/**\n                     @param question - if a string, will be wrapped as textContent into a <p> and presented as the question\n                    - if a html node, will appear as the question (allowing you to insert html)\n                    - if an array of nodes, all these nodes will be inserted\n    @param choices - Buttons (choices) the message box will offer, eg Ok and Cancel\n    @param options - Dialog options\n */\nexport async function runMessageBox(question: string | HTMLElement | HTMLElement[], choices: DialogChoice[], options?: DialogOptions) {\n  choices = choices || [];\n  options = { allowcancel: choices.length === 0, ...options };\n\n  const dialog = createDialog(options);\n  const choicebuttons = choices.map(choice =>\n    dompack.create(\"button\", {\n      type: \"button\",\n      className: dialogoptions ? dialogoptions.messageboxclassbase + \"button \" + (choice.className || \"\") : \"\",\n      textContent: choice.title,\n      on: { click: () => dialog.resolve(choice.result || choice.title) },\n      dataset: { messageboxResult: choice.result || choice.title }\n    }));\n\n  if (typeof question === 'string')\n    question = dompack.create(\"p\", { textContent: question });\n\n  if (Array.isArray(question))\n    dialog.contentnode?.append(...question);\n  else\n    dialog.contentnode?.append(question);\n\n  if (dialog.buttonsnode) //this dialog has a separte node for the button area\n    dialog.buttonsnode.append(...choicebuttons);\n  else\n    dialog.contentnode?.append(dompack.create(\"div\", {\n      className: dialogoptions ? dialogoptions.messageboxclassbase + \"buttongroup\" : \"\",\n      childNodes: choicebuttons\n    }));\n\n  return dialog.runModal();\n}\n","import * as dompack from '@webhare/dompack';\nimport { initializeCaptcha, type CaptchaProvider } from \"@mod-publisher/js/captcha/api\";\nimport { setFieldError, type SetFieldErrorData } from '../internal/customvalidation';\n\nimport \"../../captcha/__captcha.lang.json\"; //TODO or have forms send this tid (so it can also be overridden there)\nimport { JSFormElement } from '@webhare/forms';\nimport { getTid } from '@webhare/gettid';\nimport type RPCFormBase from '../rpc';\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    \"wh-captcha\": CaptchaField;\n  }\n}\n\nexport default class CaptchaField extends JSFormElement<string> {\n  value = '';\n  provider: CaptchaProvider | null = null;\n\n  constructor() {\n    super();\n    this.addEventListener('wh:form-setfielderror', evt => void this._setFieldError(evt));\n    this.whFormsApiChecker = () => this.check();\n\n    const form = this.closest('form');\n    if (form)\n      form.addEventListener('reset', () => this.onReset());\n  }\n\n  check(): void {\n    if (!this.value)\n      setFieldError(this, getTid(\"publisher:site.forms.commonerrors.required\"), { reportimmediately: false });\n    else\n      setFieldError(this, \"\", { reportimmediately: false });\n  }\n\n  setup(provider: CaptchaProvider) {\n    if (this.provider)\n      throw new Error(\"CaptchaField is already setup\");\n\n    this.provider = provider;\n    this.initialize();\n  }\n\n  private initialize() {\n    this.value = '';\n    this.replaceChildren();\n    void initializeCaptcha(this.provider!, this, {\n      onResponse: (result: string) => { this.value = result; }\n    });\n  }\n\n  private onReset() {\n    void this.initialize();\n  }\n\n  async _setFieldError(evt: CustomEvent<SetFieldErrorData>) {\n    dompack.stop(evt);\n    if (!evt.detail.error) //error cleared\n      return;\n\n    if (this.value) { //we were already sending a response!\n      console.log(\"Captcha response was rejected, resetting\");\n      this.onReset(); //better restart the control, timeout or duplicate submission\n    }\n  }\n}\n\nexport function setupCaptchaFieldGroup(form: RPCFormBase<object>, provider: CaptchaProvider): CaptchaField {\n  /* Setup a page-less holder for the captcha field\n\n    <div class=\"wh-form__page wh-form__page--visible\">\n      <div class=\"wh-form__fieldgroup\" data-wh-form-group-for=\"__form_captcha\">\n        ...\n    */\n\n  const captchaControl = dompack.create(\"wh-captcha\", { class: \"wh-form__captcha\", dataset: { whFormName: \"__form_captcha\", whFormRequired: \"true\" } });\n\n  const virtualCaptchaPage = dompack.create(\"div\", { class: \"wh-form__captchapage\" }, [\n    dompack.create(\"div\", { class: \"wh-form__fieldgroup\", dataset: { whFormGroupFor: \"__form_captcha\" } }, [\n      dompack.create(\"label\", { class: \"wh-form__label\" }, [getTid(\"publisher:site.captcha.title\")]),\n      dompack.create(\"div\", { class: \"wh-form__fields\" },\n        [dompack.create(\"div\", { class: \"wh-form__fieldline\" }, [captchaControl])]\n      )\n    ])\n  ]);\n\n  //Position it before the navbuttons, but if they are missing for whatever reason, just add to the end of the form\n  const buttonarea = dompack.qS(form.node, \".wh-form__navbuttons\");\n  if (buttonarea)\n    buttonarea.before(virtualCaptchaPage);\n  else\n    form.node.appendChild(virtualCaptchaPage);\n\n  void captchaControl.setup(provider);\n\n  return captchaControl;\n}\n\n\ncustomElements.define(\"wh-captcha\", CaptchaField);\n","import { getTid } from \"@webhare/gettid\";\nimport \"./__captcha.lang.json\";\n\nexport interface CaptchaProvider {\n  name: string;\n  apikey: string;\n}\n\nexport interface CaptchaSettings {\n  title: string;\n  onResponse: (response: string) => void;\n}\n\nexport interface CaptchaProviderRegistration {\n  initialize: (provider: CaptchaProvider, injectInto: HTMLElement, settings: CaptchaSettings) => Promise<void>;\n}\n\nexport const captcharegistry: Record<string, CaptchaProviderRegistration> = {};\n\n\nexport async function initializeCaptcha(provider: CaptchaProvider, injectInto: HTMLElement, settings?: Partial<CaptchaSettings>): Promise<void> {\n  if (!captcharegistry[provider.name])\n    throw new Error(`Captcha provider '${provider.name}' not registered`);\n  if (!settings?.onResponse)\n    throw new Error(\"onResponse callback is required\");\n\n  const finalsettings: CaptchaSettings = {\n    title: settings?.title ?? getTid(\"publisher:site.captcha.title\"),\n    onResponse: settings?.onResponse ?? (() => { }),\n  };\n\n  await captcharegistry[provider.name].initialize(provider, injectInto, finalsettings);\n}\n","// Auto-generated language file from /opt/wh/whtree/modules/publisher/js/captcha/__captcha.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"publisher\",\"nl\",{\"site\":{\"captcha\":{\"explain\":\"Vink het vakje hieronder aan\",\"title\":\"Verificatie\"}}});\nregisterTexts(\"publisher\",\"en\",{\"site\":{\"captcha\":{\"explain\":\"Please check the box below\",\"title\":\"Verification\"}}});\nregisterTexts(\"publisher\",\"de\",{\"site\":{\"captcha\":{\"explain\":\"Bitte setze das Häkchen\",\"title\":\"Kontrolle\"}}});\nregisterTexts(\"publisher\",\"es\",{\"site\":{\"captcha\":{\"explain\":\"Por favor, marque la casilla a continuación\",\"title\":\"Casi listo\"}}});\nregisterTexts(\"publisher\",\"it\",{\"site\":{\"captcha\":{\"explain\":\"Seleziona la casella qui sotto\",\"title\":\"Verifica\"}}});\nregisterTexts(\"publisher\",\"xt\",{\"site\":{\"captcha\":{\"explain\":\"Please check the box below\",\"title\":\"Verification\"}}});\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/nl.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/de.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/es.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/it.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n","import FormBase from '@mod-publisher/js/forms/rpc';\nimport type { FormConfiguration, FormHandlerFactory } from \"@webhare/forms\";\nimport { dispatchCustomEvent, flagUIBusy, qSA, register } from \"@webhare/dompack\";\nimport { emplace, sleep } from \"@webhare/std\";\nimport { downgradeUploadFields } from \"./domsupport\";\n\nlet formConfiguration: FormConfiguration | undefined;\nlet handlers: Map<string, FormHandlerFactory | PromiseWithResolvers<FormHandlerFactory>> | undefined;\nlet configuredRegistrations: true | undefined;\nconst firstWarningMs = 150, warningIntervalMs = 5000;\n\nasync function scheduleFormSetup(form: HTMLFormElement, factory: FormHandlerFactory) {\n  using lock = flagUIBusy();\n  void (lock);\n\n  //Ensure any custom elements in the form are actually registered or our communication with these elements may fail\n  const customEls = [...new Set(qSA(form, \"[name]\").map(_ => _.tagName.toLowerCase()))].filter(_ => _.includes(\"-\"));\n  if (customEls.length) {\n    const initPromise = Promise.all(customEls.map(_ => customElements.whenDefined(_))).then(() => ({ timeout: false }));\n\n    let nextWarning = Date.now() + firstWarningMs;\n    for (; ;) {\n      const timeoutPromise = sleep(new Date(nextWarning)).then(() => ({ timeout: true }));\n      const result = await Promise.race([initPromise, timeoutPromise]);\n      if (!result.timeout)\n        break;\n\n      const missing = customEls.filter(tag => !customElements.get(tag)).join(\", \");\n      if (missing === 'wh-fileedit') {\n        console.warn(`Developers: we recommend explicitly registering a component for \".wh-form__upload\"`);\n        downgradeUploadFields(form);\n        break;\n      }\n      console.warn(`Still waiting for the following custom elements to be defined in form ${form.id ?? form.dataset.whFormId}:`, missing);\n      nextWarning = Date.now() + warningIntervalMs;\n    }\n  }\n  factory(form);\n}\n\nexport function configureForms(setup: FormConfiguration) {\n  if (!Object.keys(setup).length)\n    return;\n\n  formConfiguration = { ...formConfiguration, ...setup };\n  dispatchCustomEvent(window, \"wh:form-configure\", { bubbles: true, cancelable: false, detail: formConfiguration });\n}\n\nexport function registerHandlers(addHandlers: Record<string, FormHandlerFactory>) {\n  if (!handlers) { //register initial handlers (now that form support is activated)\n    //we want to stop distinguishing between these, not worth the effort/complexity seperating  them\n    const defaultHandler = (form: HTMLFormElement) => new FormBase(form);\n    addHandlers = {\n      \"publisher:form\": defaultHandler,\n      \"publisher:rpc\": defaultHandler,\n      ...addHandlers\n    };\n    handlers = new Map;\n  }\n\n  //Configure the handlers. If there's a resolvable promise waiting for us, resolve it, otherwise directly insert the handler\n  for (const [handlername, handler] of Object.entries(addHandlers))\n    emplace(handlers, handlername, {\n      insert: () => handler,\n      update: current => {\n        if (\"promise\" in current) {\n          current.resolve(handler);\n          return current;\n        } else\n          throw new Error(`Handler '${handlername}' is already registered`);\n      }\n    });\n\n  //Set up a registration for form elements, but ensure they only go through one scheduleFormSetup ever\n  if (!configuredRegistrations) { //register for forms that have yet to appear\n    register<HTMLFormElement>(\"form[data-wh-form-handler]\", form => {\n      //Get the current handler or set up a promise that will receive the handler\n      const handler = emplace(handlers!, form.dataset.whFormHandler!, { insert: () => Promise.withResolvers<FormHandlerFactory>() });\n      if (\"promise\" in handler)\n        void handler.promise.then(factory => scheduleFormSetup(form, factory));\n      else\n        void scheduleFormSetup(form, handler);\n\n    });\n    configuredRegistrations = true;\n  }\n}\n\nexport function registerHandler(handlername: string, handler: FormHandlerFactory) {\n  registerHandlers({ [handlername]: handler });\n}\n\nexport function getFormConfiguration(): FormConfiguration | undefined {\n  return formConfiguration;\n}\n","import * as dompack from 'dompack';\nimport { getTid } from \"@webhare/gettid\";\nimport { FileEditElement as FileEditElementBase } from './fileeditbase';\nimport './upload.css';\nimport { isFile } from '@webhare/std';\n\n\n\n//FIXME nicer class name? eg add form or field to these (and imgedit) class names?\nexport class FileUploadFormElement extends FileEditElementBase {\n  constructor() {\n    super();\n    this.refresh();\n  }\n\n  #constructFileHolder() {\n    const fileholder = document.createElement(\"div\");\n    fileholder.classList.add('file');\n    return fileholder;\n  }\n\n  refresh() {\n    const nodes = [];\n\n    for (const [idx, file] of this.currentFiles.entries()) {\n      const fileholder = this.#constructFileHolder();\n\n      // const label = getLabelText(this.node);\n      // aria-label={label}\n      const filename = isFile(file) ? file.name : file.fileName;\n      /* for ease of 'form like' presentation, we're currently using an <input>. but quite hacky, eg. we need readonly to have it not interfere with clicks. */\n      const filenamefield =\n        <input part=\"filename\" class=\"file__name\" type=\"text\" value={filename} readonly />;\n\n      const deletebutton = <button part=\"button deletebutton\" class=\"deletebutton file__deletebutton\" />;\n      this.setupDeleteButton(deletebutton, idx);\n\n      fileholder.append(filenamefield, deletebutton);\n      nodes.push(fileholder);\n    }\n\n    if (this.currentFiles.length < this.maxFiles) {\n      const fileholder = this.#constructFileHolder();\n      fileholder.classList.add('file--placeholder');\n\n      const filenamefield =\n        <input part=\"filename\" class=\"file__name\" type=\"text\" value=\"\" placeholder={getTid(\"publisher:site.forms.upload-emptytext\")} disabled readonly />;\n\n      const uploadbutton = <button part=\"button selectbutton\" type=\"button\" class=\"wh-form__uploadfieldselect wh-form__button\"><span class=\"wh-form__buttonlabel\">{getTid(\"publisher:site.forms.selectfile\")}</span></button>;\n      this.setupUploadButton(fileholder);\n      fileholder.append(filenamefield, uploadbutton);\n      nodes.push(fileholder);\n    }\n\n    this.maindiv.replaceChildren(...nodes);\n  }\n}\n\n//////// Legacy version. We expect existing users to migrate to the version above\n\nexport default class UploadField {\n  constructor(node: HTMLElement) {\n    if (!customElements.get(\"wh-fileedit\"))\n      customElements.define(\"wh-fileedit\", FileUploadFormElement);\n  }\n}\n","/* eslint-disable @typescript-eslint/no-floating-promises -- FIXME: needs API rework */\n\nimport * as dompack from 'dompack';\nimport { requestFile } from \"@webhare/upload\";\n\nimport { getTid } from \"@webhare/gettid\";\nimport { setFieldError } from '@mod-publisher/js/forms/internal/customvalidation';\nimport { getFieldDisplayName } from '@webhare/forms/src/domsupport';\nimport { JSFormElement } from '@webhare/forms/src/jsformelement';\nimport type { FormFileValue } from '@webhare/forms/src/types';\nimport \"@mod-publisher/js/forms/internal/form.lang.json\"; //we need eg publisher:site.forms.selectfile\n\nfunction isAcceptableType(fileType: string, masks: string[]) {\n  if (masks.includes(fileType))\n    return true;\n\n  const basetype = fileType.split('/')[0];\n  if (['image', 'video', 'audio'].includes(basetype) && masks.includes(basetype + '/*'))\n    return true;\n\n  return false;\n}\n\n\nexport abstract class FileEditElement extends JSFormElement<FormFileValue[]> {\n  root;\n  maindiv;\n  readonly group: HTMLElement | null;\n\n  /** The current uploaded files */\n  protected currentFiles = new Array<FormFileValue>;\n  /** Maximum number of files */\n  protected maxFiles;\n\n  constructor() {\n    super();\n    this.root = this.attachShadow({ mode: 'open', delegatesFocus: true });\n    this.maindiv = document.createElement(\"div\");\n    this.maindiv.inert = this.disabled;\n\n    const csslink = document.createElement(\"link\");\n    csslink.rel = \"stylesheet\";\n    csslink.href = \"/.wh/ea/p/forms/controls.css\";\n    this.root.append(csslink, this.maindiv);\n\n    this.group = this.closest<HTMLElement>(\".wh-form__fieldgroup\");\n    this.whFormsApiChecker = async () => { await this._check(); };\n    this.maxFiles = parseInt(this.getAttribute(\"max-files\")!) || 1;\n    if (this.getAttribute(\"value\"))\n      this.#setValue(JSON.parse(this.getAttribute(\"value\")!));\n\n    if (this.group) {\n      this.group.addEventListener(\"dragover\", evt => evt.preventDefault());\n      this.group.addEventListener(\"dragenter\", evt => evt.preventDefault());\n      this.group.addEventListener(\"drop\", evt => this.doDrop(evt));\n    }\n  }\n  abstract refresh(): void;\n  isSet(): boolean {\n    return this.currentFiles.length > 0;\n  }\n  async _check() {\n    const error = this.required && !this.isSet();\n    if (error)\n      setFieldError(this, getTid(\"publisher:site.forms.commonerrors.required\"), { reportimmediately: false });\n    else\n      setFieldError(this, \"\", { reportimmediately: false });\n    return error;\n  }\n\n  protected refreshState() {\n    this.maindiv.inert = this.disabled;\n  }\n\n  get value(): FormFileValue[] {\n    return this.currentFiles;\n  }\n\n  set value(value: FormFileValue[]) {\n    this.#setValue(value);\n    this.refresh();\n  }\n\n  #setValue(value: Array<Partial<FormFileValue>>) { //taking a partial so we can do a better job at fixing missing fields from incorrect callers\n    //updates the value but does not fire events/refresh()\n    const toset: FormFileValue[] = [];\n\n    for (const row of value) {\n      if (row?.file) {\n        if (!this._isAcceptableType(row.file.type))\n          throw new Error(`File type ${row.file.type} is not acceptable for ${getFieldDisplayName(this)}`);\n        toset.push({ fileName: row.fileName || row.file.name, file: row.file, link: null });\n      } else if (row?.link) {\n        toset.push({ fileName: row.fileName || \"\", file: null, link: row.link });\n      } else {\n        throw new Error(`Incorrect value type received for ${getFieldDisplayName(this)} - expect 'file' or 'link' to be set`);\n      }\n\n      if (toset.length >= this.maxFiles)\n        break;\n    }\n    this.currentFiles = toset;\n  }\n\n  _isAcceptableType(mimetype: string) {\n    const accept = this.getAttribute(\"accept\")?.split(',').map(mask => mask.trim()) ?? [];\n    return !accept.length || isAcceptableType(mimetype, accept);\n  }\n\n  private doDrop(evt: DragEvent) {\n    //FIXME check 'accept' - or can the drag handlers do that?\n    evt.preventDefault();\n\n    const files = evt.dataTransfer?.files;\n    if (files)\n      this.processUpload(files[0]);\n  }\n\n  async uploadFile(evt: Event) {\n    evt.preventDefault();\n\n    if (this.disabled || this.currentFiles.length >= this.maxFiles)\n      return; //should not even have been offered?\n\n    const accept = this.getAttribute(\"accept\")?.split(',') ?? [];\n    using lock = dompack.flagUIBusy();\n    void (lock);\n\n    const file = await requestFile({ accept });\n    if (!file)\n      return;\n\n    await this.processUpload(file);\n  }\n\n  private async processUpload(file: File) {\n    if (this.disabled || this.currentFiles.length >= this.maxFiles)\n      return; //should not even have been offered?\n\n    if (!this._isAcceptableType(file.type)) {\n      //TODO tell server it can destroy the file immediately (should have told uploadsession at the start?\n      const msg = this.dataset.whAccepterror || getTid(\"publisher:site.forms.commonerrors.badfiletype\");\n      setFieldError(this, msg, { reportimmediately: true });\n      return;\n    }\n\n    this.currentFiles.push({ fileName: file.name, file: file, link: null });\n    this.refresh();\n    dompack.dispatchCustomEvent(this, 'change', { bubbles: true, cancelable: false });\n  }\n\n  protected deleteFile(evt: Event, idx: number) {\n    if (evt)\n      dompack.stop(evt);\n\n    this.currentFiles.splice(idx, 1);\n    this.refresh();\n    dompack.dispatchCustomEvent(this, 'change', { bubbles: true, cancelable: false });\n  }\n\n  protected setupUploadButton(button: HTMLElement) {\n    button.addEventListener(\"click\", evt => void this.uploadFile(evt));\n  }\n\n  protected setupDeleteButton(button: HTMLElement, idx: number) {\n    button.addEventListener(\"click\", evt => this.deleteFile(evt, idx));\n    button.ariaLabel = getTid(\"publisher:site.forms.imgedit-remove\");\n  }\n}\n","// Auto-generated language file from /opt/wh/whtree/modules/publisher/js/forms/internal/form.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"publisher\",\"nl\",{\"site\":{\"forms\":{\"imgedit-explain-upload\":\"Sleep bestanden hier of klik om te uploaden\",\"imgedit-groupelement-replace\":[1,\", Vervang afbeelding\"],\"imgedit-groupelement-upload\":[1,\", Upload afbeelding\"],\"imgedit-remove\":\"Verwijder afbeelding\",\"nextpage\":\"Volgende\",\"previouspage\":\"Vorige\",\"selectfile\":\"Selecteer bestand\",\"splitdatetime-day-arialabel\":\"dag\",\"splitdatetime-hours-arialabel\":\"uur\",\"splitdatetime-minutes-arialabel\":\"minuut\",\"splitdatetime-month-arialabel\":\"maand\",\"splitdatetime-seconds-arialabel\":\"seconde\",\"splitdatetime-year-arialabel\":\"jaar\",\"starsrequired\":\"* betekent dat een veld verplicht is\",\"submit\":\"Versturen\",\"upload-emptytext\":\"Geen bestand geselecteerd\",\"upload-filename\":[\"Geselecteerde bestand is \",1],\"upload-remove\":\"Verwijder bestand\",\"addressfield\":{\"address_not_found\":\"Het adres kon niet worden gevonden.\",\"invalid_nr_detail\":\"Ongeldig huisnummer.\",\"invalid_zip\":\"Ongeldige postcode.\",\"zip_not_found\":\"Combinatie van postcode en huisnummer komt niet voor.\"},\"commonerrors\":{\"alphanum\":\"De waarde moet alfanumeriek zijn.\",\"badfiletype\":\"Dit bestandstype is niet toegestaan\",\"check\":[\"Kies minimaal \",1,\" en maximaal \",2,\" items.\"],\"date\":\"Dit is geen geldige datum.\",\"default\":\"Deze waarde is onjuist.\",\"digits\":\"De waarde moet numeriek zijn.\",\"email\":\"Dit is geen geldig e-mailadres.\",\"email_baddomain\":[\"Vanwege problemen met het e-mailen naar \",1,\" e-mailadressen, willen we je vragen om een alternatief e-mailadres te gebruiken.\"],\"email_suggestion\":[\"Bedoel je \",1,\"?\"],\"equalto\":\"De waardes moeten identiek zijn.\",\"formunavailable\":\"Dit formulier is momenteel niet beschikbaar\",\"integer\":\"De waarde moet een nummer zijn.\",\"length\":[\"De waarde moet tussen \",1,\" en \",2,\" karakters lang zijn.\"],\"max\":[\"De waarde mag niet groter zijn dan \",1,\".\"],\"maxarray\":[\"U kunt maximaal \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 onderdeel\"],\"subselse\":[1,\" onderdelen\"]},\" toevoegen.\"],\"maxcheck\":[\"Kies maximaal \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"maxheight\":[\"De afbeelding is te groot. Deze mag maximaal \",2,\" pixels hoog zijn.\"],\"maxlength\":[\"De waarde is te lang. Deze mag maximaal \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 karakter\"],\"subselse\":[1,\" karakters\"]},\" lang zijn.\"],\"maxwidth\":[\"De afbeelding is te groot. Deze mag maximaal \",2,\" pixels breed zijn.\"],\"min\":[\"De waarde mag niet lager zijn dan \",1,\".\"],\"minarray\":[\"U moet minimaal \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 onderdeel\"],\"subselse\":[1,\" onderdelen\"]},\" toevoegen.\"],\"mincheck\":[\"Kies minimaal \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"minheight\":[\"De afbeelding is te klein. Deze moet minimaal \",2,\" pixels hoog zijn.\"],\"minlength\":[\"De tekst is te kort. Deze moet uit minimaal \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 karakter\"],\"subselse\":[1,\" karakters\"]},\" bestaan.\"],\"minwidth\":[\"De afbeelding is te klein. Deze moet minimaal \",2,\" pixels breed zijn.\"],\"notblank\":\"De waarde mag niet leeg zijn.\",\"number\":\"De waarde moet een nummer zijn.\",\"pattern\":\"De waarde is onjuist.\",\"range\":[\"De waarde moet tussen \",1,\" en \",2,\" liggen.\"],\"required\":\"Dit veld is verplicht.\",\"step1mismatch\":\"De waarde moet een geheel getal zijn\",\"stepmismatch\":[\"De waarde moet een meervoud zijn van \",1,\".\"],\"time\":\"Dit is geen geldige tijd.\",\"unacceptableemail\":\"Dit e-mailadres is hier niet toegestaan\",\"upload_cannotcheck\":\"Dit bestand kan niet geüpload worden omdat we het momenteel niet kunnen verifiëren\",\"upload_suspicious\":\"Dit bestand ziet er verdacht uit en kan helaas niet geüpload worden\",\"url\":\"Dit is geen geldige URL.\"}}}});\nregisterTexts(\"publisher\",\"en\",{\"site\":{\"forms\":{\"imgedit-explain-upload\":\"Drag and drop files here or click to upload\",\"imgedit-groupelement-replace\":[1,\", Replace image\"],\"imgedit-groupelement-upload\":[1,\", Upload image\"],\"imgedit-remove\":\"Remove image\",\"nextpage\":\"Next\",\"previouspage\":\"Previous\",\"selectfile\":\"Select file\",\"splitdatetime-day-arialabel\":\"day\",\"splitdatetime-hours-arialabel\":\"hour\",\"splitdatetime-minutes-arialabel\":\"minute\",\"splitdatetime-month-arialabel\":\"month\",\"splitdatetime-seconds-arialabel\":\"second\",\"splitdatetime-year-arialabel\":\"year\",\"starsrequired\":\"* indicates a required field\",\"submit\":\"Submit\",\"upload-emptytext\":\"No file chosen\",\"upload-filename\":[\"Uploaded file is \",1],\"upload-remove\":\"Remove file\",\"addressfield\":{\"address_not_found\":\"The address could not be found.\",\"invalid_nr_detail\":\"Invalid house number.\",\"invalid_zip\":\"Invalid ZIP or postal code.\",\"zip_not_found\":\"Unknown combination of postal code and house number.\"},\"commonerrors\":{\"alphanum\":\"This value should be alphanumeric.\",\"badfiletype\":\"This file type is not allowed\",\"cannotprocessfile\":\"This file looks suspicious and can unfortunately not be uploaded\",\"check\":[\"You must select between \",1,\" and \",2,\" choices.\"],\"date\":\"This is not a valid date\",\"default\":\"This value seems to be invalid.\",\"digits\":\"This value should be digits.\",\"email\":\"This value should be a valid email.\",\"email_baddomain\":[\"Due to difficulties with mailing to \",1,\" email addresses we kindly request you to use an alternative email provider.\"],\"email_suggestion\":[\"Did you mean \",1,\"?\"],\"equalto\":\"This value should be the same.\",\"formunavailable\":\"This form is currently unavailable\",\"integer\":\"This value should be a valid integer.\",\"length\":[\"This value length is invalid. It should be between \",1,\" and \",2,\" characters long.\"],\"max\":[\"This value should be lower than or equal to \",1,\".\"],\"maxarray\":[\"You can add at most \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"maxcheck\":[\"You must select \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 choice\"],\"subselse\":[1,\" choices\"]},\" or fewer.\"],\"maxheight\":[\"The image is too big. It should be at most \",2,\" pixels high.\"],\"maxlength\":[\"This value is too long. It should have \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 character\"],\"subselse\":[1,\" characters\"]},\" or fewer.\"],\"maxsignupsreached\":\"The maximum number of signups has been reached\",\"maxwidth\":[\"The image is too big. It should be at most \",2,\" pixels wide.\"],\"min\":[\"This value should be greater than or equal to \",1,\".\"],\"minarray\":[\"You must add at least \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"mincheck\":[\"You must select at least \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 choice\"],\"subselse\":[1,\" choices\"]},\".\"],\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"],\"minlength\":[\"This value is too short. It should have \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 character\"],\"subselse\":[1,\" characters\"]},\" or more.\"],\"minwidth\":[\"The image is too small. It should be at least \",2,\" pixels wide.\"],\"notblank\":\"This value should not be blank.\",\"number\":\"This value should be a valid number.\",\"pattern\":\"This value seems to be invalid.\",\"range\":[\"This value should be between \",1,\" and \",2,\".\"],\"required\":\"This value is required.\",\"step1mismatch\":\"The value must be a whole number\",\"stepmismatch\":[\"The value should be a multiple of \",1,\".\"],\"time\":\"This is not a valid time\",\"unacceptableemail\":\"This email address is not acceptable here\",\"upload_cannotcheck\":\"This file cannot be uploaded as we are currently unable to verify it\",\"upload_suspicious\":\"This file looks suspicious and can unfortunately not be uploaded\",\"url\":\"This value should be a valid url.\"}}}});\nregisterTexts(\"publisher\",\"de\",{\"site\":{\"forms\":{\"nextpage\":\"Weiter\",\"previouspage\":\"Zurück\",\"selectfile\":\"Datei auswählen\",\"starsrequired\":\"* zeigt ein Pflichtfeld an\",\"submit\":\"Abschicken\",\"addressfield\":{\"address_not_found\":\"Die Adresse konnte nicht gefunden werden.\",\"invalid_nr_detail\":\"Ungültige Hausnummer.\",\"invalid_zip\":\"Ungültige Postleitzahl.\",\"zip_not_found\":\"Unbekannte Postleitzahl/Hausnummer Kombination.\"},\"commonerrors\":{\"alphanum\":\"Die Eingabe darf nur Zahlen und/oder Buchstaben befassen.\",\"check\":[\"Wähle zwischen \",1,\" und \",2,\" Angaben.\"],\"default\":\"Die Eingabe ist nicht korrekt.\",\"digits\":\"Die Eingabe darf nur Zahlen enthalten.\",\"email\":\"Die Eingabe muss eine gültige E-Mail-Adresse sein.\",\"email_baddomain\":[\"Aufgrund von technischen Schwierigkeiten mit dem Mailprovider \",1,\" benötigen wir eine andere E-Mail Adresse.\"],\"email_suggestion\":[\"Meinst du \",1,\"?\"],\"equalto\":\"Dieses Feld muss übereinstimmen mit dem anderen Feld.\",\"integer\":\"Die Eingabe muss eine Zahl sein.\",\"length\":[\"Die Länge der Eingabe ist ungültig. Es können zwischen \",1,\" und \",2,\" Zeichen eingegeben werden.\"],\"max\":[\"Die Eingabe muss kleiner oder gleich \",1,\" sein.\"],\"maxcheck\":[\"Wähle maximal \",1,\" Angaben aus.\"],\"maxlength\":[\"Die Eingabe ist zu lang. Es dürfen höchstens \",1,\" Zeichen eingegeben werden.\"],\"min\":[\"Die Eingabe muss größer oder gleich \",1,\" sein.\"],\"mincheck\":[\"Die Eingabe ist zu kurz. Es müssen mindestens \",1,\" Zeichen eingegeben werden.\"],\"minlength\":[\"Wähle mindestens \",1,\" Optionen aus.\"],\"notblank\":\"Die Eingabe darf nicht leer sein.\",\"number\":\"Die Eingabe muss eine Zahl sein.\",\"pattern\":\"Die Eingabe ist ungültig.\",\"range\":[\"Die Eingabe muss zwischen \",1,\" und \",2,\" liegen.\"],\"required\":\"Dies ist ein Pflichtfeld.\",\"url\":\"Die Eingabe muss eine gültige URL sein.\",\"badfiletype\":\"This file type is not allowed\",\"cannotprocessfile\":\"This file looks suspicious and can unfortunately not be uploaded\",\"date\":\"This is not a valid date\",\"formunavailable\":\"This form is currently unavailable\",\"maxarray\":[\"You can add at most \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"maxheight\":[\"The image is too big. It should be at most \",2,\" pixels high.\"],\"maxsignupsreached\":\"The maximum number of signups has been reached\",\"maxwidth\":[\"The image is too big. It should be at most \",2,\" pixels wide.\"],\"minarray\":[\"You must add at least \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"],\"minwidth\":[\"The image is too small. It should be at least \",2,\" pixels wide.\"],\"step1mismatch\":\"The value must be a whole number\",\"stepmismatch\":[\"The value should be a multiple of \",1,\".\"],\"time\":\"This is not a valid time\",\"unacceptableemail\":\"This email address is not acceptable here\",\"upload_cannotcheck\":\"This file cannot be uploaded as we are currently unable to verify it\",\"upload_suspicious\":\"This file looks suspicious and can unfortunately not be uploaded\"},\"imgedit-explain-upload\":\"Drag and drop files here or click to upload\",\"imgedit-groupelement-replace\":[1,\", Replace image\"],\"imgedit-groupelement-upload\":[1,\", Upload image\"],\"imgedit-remove\":\"Remove image\",\"splitdatetime-day-arialabel\":\"day\",\"splitdatetime-hours-arialabel\":\"hour\",\"splitdatetime-minutes-arialabel\":\"minute\",\"splitdatetime-month-arialabel\":\"month\",\"splitdatetime-seconds-arialabel\":\"second\",\"splitdatetime-year-arialabel\":\"year\",\"upload-emptytext\":\"No file chosen\",\"upload-filename\":[\"Uploaded file is \",1],\"upload-remove\":\"Remove file\"}}});\nregisterTexts(\"publisher\",\"es\",{\"site\":{\"forms\":{\"nextpage\":\"Siguiente\",\"previouspage\":\"Anterior\",\"selectfile\":\"Seleccionar archivo\",\"starsrequired\":\"* Campos obligatorios\",\"submit\":\"Enviar\",\"addressfield\":{\"address_not_found\":\"La dirección no pudo ser encontrada.\",\"invalid_nr_detail\":\"Número de casa con adición inválido.\",\"invalid_zip\":\"Código postal inválido.\",\"zip_not_found\":\"Combinación desconocida de código postal y número de casa.\"},\"commonerrors\":{\"alphanum\":\"Este valor debe ser alfanumérico.\",\"check\":[\"Debe seleccionar entre \",1,\" y \",2,\" opciones.\"],\"default\":\"Este valor parece ser inválido.\",\"digits\":\"Este valor debe ser un dígito válido.\",\"email\":\"Este valor debe ser un correo válido.\",\"email_baddomain\":[\"Debido a las dificultades con el envío de correos a \",1,\" direcciones de correo electrónico, le pedimos amablemente que utilice un proveedor de correo electrónico alternativo.\"],\"email_suggestion\":[\"¿Se refiere a \",1,\"?\"],\"equalto\":\"Este valor debe ser idéntico.\",\"integer\":\"Este valor debe ser un número entero válido.\",\"length\":[\"Esta longitud de valor no es válida. Debe tener entre \",1,\" y \",2,\" caracteres de longitud.\"],\"max\":[\"Este valor debe ser menor o igual a \",1,\".\"],\"maxcheck\":[\"Debe seleccionar \",1,\" opciones o menos.\"],\"maxlength\":[\"Este valor es muy largo. La longitud máxima es de \",1,\" caracteres.\"],\"min\":[\"Este valor debe ser mayor o igual que \",1,\".\"],\"mincheck\":[\"Debe seleccionar al menos \",1,\" opciones.\"],\"minlength\":[\"Este valor es muy corto. La longitud mínima es de \",1,\" caracteres.\"],\"notblank\":\"Este valor no debe estar en blanco.\",\"number\":\"Este valor debe ser un número válido.\",\"pattern\":\"Este valor parece ser inválido.\",\"range\":[\"Este valor debe estar entre \",1,\" y \",2,\".\"],\"required\":\"Este valor es necesario.\",\"url\":\"Este valor debe ser una URL válida.\",\"badfiletype\":\"This file type is not allowed\",\"cannotprocessfile\":\"This file looks suspicious and can unfortunately not be uploaded\",\"date\":\"This is not a valid date\",\"formunavailable\":\"This form is currently unavailable\",\"maxarray\":[\"You can add at most \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"maxheight\":[\"The image is too big. It should be at most \",2,\" pixels high.\"],\"maxsignupsreached\":\"The maximum number of signups has been reached\",\"maxwidth\":[\"The image is too big. It should be at most \",2,\" pixels wide.\"],\"minarray\":[\"You must add at least \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"],\"minwidth\":[\"The image is too small. It should be at least \",2,\" pixels wide.\"],\"step1mismatch\":\"The value must be a whole number\",\"stepmismatch\":[\"The value should be a multiple of \",1,\".\"],\"time\":\"This is not a valid time\",\"unacceptableemail\":\"This email address is not acceptable here\",\"upload_cannotcheck\":\"This file cannot be uploaded as we are currently unable to verify it\",\"upload_suspicious\":\"This file looks suspicious and can unfortunately not be uploaded\"},\"imgedit-explain-upload\":\"Drag and drop files here or click to upload\",\"imgedit-groupelement-replace\":[1,\", Replace image\"],\"imgedit-groupelement-upload\":[1,\", Upload image\"],\"imgedit-remove\":\"Remove image\",\"splitdatetime-day-arialabel\":\"day\",\"splitdatetime-hours-arialabel\":\"hour\",\"splitdatetime-minutes-arialabel\":\"minute\",\"splitdatetime-month-arialabel\":\"month\",\"splitdatetime-seconds-arialabel\":\"second\",\"splitdatetime-year-arialabel\":\"year\",\"upload-emptytext\":\"No file chosen\",\"upload-filename\":[\"Uploaded file is \",1],\"upload-remove\":\"Remove file\"}}});\nregisterTexts(\"publisher\",\"it\",{\"site\":{\"forms\":{\"imgedit-groupelement-replace\":[1,\", sostituire immagine\"],\"imgedit-groupelement-upload\":[1,\", caricare immagine\"],\"imgedit-remove\":\"Rimuovere immagine\",\"nextpage\":\"Prossimo\",\"previouspage\":\"Precedente\",\"selectfile\":\"Seleziona il file\",\"splitdatetime-day-arialabel\":\"Giorno\",\"splitdatetime-hours-arialabel\":\"Ora\",\"splitdatetime-minutes-arialabel\":\"Minuto\",\"splitdatetime-month-arialabel\":\"Mese\",\"splitdatetime-seconds-arialabel\":\"Secondo\",\"splitdatetime-year-arialabel\":\"Anno\",\"starsrequired\":\"* indica un campo richiesto\",\"submit\":\"Invia\",\"upload-emptytext\":\"Nessun file scelto\",\"upload-filename\":[\"Il file caricato è \",1],\"upload-remove\":\"Rimuovere file\",\"addressfield\":{\"address_not_found\":\"Non è stato possibile trovare l'indirizzo.\",\"invalid_nr_detail\":\"Numero civico non valido.\",\"invalid_zip\":\"CAP o codice postale non valido.\",\"zip_not_found\":\"Combinazione sconosciuta di codice postale e numero civico.\"},\"commonerrors\":{\"alphanum\":\"Questo valore deve essere di tipo alfanumerico.\",\"badfiletype\":\"Questo tipo di file non è consentito\",\"cannotprocessfile\":\"Questo file sembra sospetto e purtroppo non può essere caricato\",\"check\":[\"Devi scegliere tra \",1,\" e \",2,\" opzioni.\"],\"date\":\"Questa non è una data valida\",\"default\":\"Questo valore sembra essere non valido.\",\"digits\":\"Questo valore deve essere di tipo numerico.\",\"email\":\"Questo valore deve essere un indirizzo email valido.\",\"email_baddomain\":[\"A causa di difficoltà con l'invio agli indirizzi email \",1,\", lo richiediamo gentilmente\"],\"email_suggestion\":[\"Intendevi \",1,\"?\"],\"equalto\":\"Questo valore deve essere identico.\",\"integer\":\"Questo valore deve essere un numero valido.\",\"length\":[\"La lunghezza di questo valore deve essere compresa fra \",1,\" e \",2,\" caratteri.\"],\"max\":[\"Questo valore deve essere minore di \",1,\".\"],\"maxarray\":[\"Puoi aggiungere al massimo \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 articolo\"],\"subselse\":[1,\" articoli\"]},\".\"],\"maxcheck\":[\"Devi scegliere al più \",1,\" opzioni.\"],\"maxlength\":[\"Questo valore è troppo lungo. La lunghezza massima è di \",1,\" caratteri.\"],\"min\":[\"Questo valore deve essere maggiore di \",1,\".\"],\"minarray\":[\"Devi aggiungere almeno \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 articolo\"],\"subselse\":[1,\" articoli\"]},\".\"],\"mincheck\":[\"Devi scegliere almeno \",1,\" opzioni.\"],\"minlength\":[\"Questo valore è troppo corto. La lunghezza minima è di \",1,\" caratteri.\"],\"notblank\":\"Questo valore non deve essere vuoto.\",\"number\":\"Questo valore deve essere un numero valido.\",\"pattern\":\"Questo valore non è corretto.\",\"range\":[\"Questo valore deve essere compreso tra \",1,\" e \",2,\".\"],\"required\":\"Questo valore è richiesto.\",\"step1mismatch\":\"Il valore deve essere un numero intero\",\"stepmismatch\":[\"Il valore dovrebbe essere un multiplo di \",1,\".\"],\"time\":\"Questo non è un orario valido\",\"unacceptableemail\":\"Questo indirizzo email non è accettabile qui\",\"upload_cannotcheck\":\"Questo file non può essere caricato poiché al momento non siamo in grado di verificarlo\",\"upload_suspicious\":\"Questo file sembra sospetto e purtroppo non può essere caricato\",\"url\":\"Questo valore deve essere un URL valido.\",\"formunavailable\":\"This form is currently unavailable\",\"maxheight\":[\"The image is too big. It should be at most \",2,\" pixels high.\"],\"maxsignupsreached\":\"The maximum number of signups has been reached\",\"maxwidth\":[\"The image is too big. It should be at most \",2,\" pixels wide.\"],\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"],\"minwidth\":[\"The image is too small. It should be at least \",2,\" pixels wide.\"]},\"imgedit-explain-upload\":\"Drag and drop files here or click to upload\"}}});\nregisterTexts(\"publisher\",\"xt\",{\"site\":{\"forms\":{\"imgedit-explain-upload\":\"Drag and drop files here or click to upload\",\"imgedit-groupelement-replace\":[1,\", Replace image\"],\"imgedit-groupelement-upload\":[1,\", Upload image\"],\"imgedit-remove\":\"Remove image\",\"nextpage\":\"Next\",\"previouspage\":\"Previous\",\"selectfile\":\"Select file\",\"splitdatetime-day-arialabel\":\"day\",\"splitdatetime-hours-arialabel\":\"hour\",\"splitdatetime-minutes-arialabel\":\"minute\",\"splitdatetime-month-arialabel\":\"month\",\"splitdatetime-seconds-arialabel\":\"second\",\"splitdatetime-year-arialabel\":\"year\",\"starsrequired\":\"* indicates a required field\",\"submit\":\"Submit\",\"upload-emptytext\":\"No file chosen\",\"upload-filename\":[\"Uploaded file is \",1],\"upload-remove\":\"Remove file\",\"addressfield\":{\"address_not_found\":\"The address could not be found.\",\"invalid_nr_detail\":\"Invalid house number.\",\"invalid_zip\":\"Invalid ZIP or postal code.\",\"zip_not_found\":\"Unknown combination of postal code and house number.\"},\"commonerrors\":{\"alphanum\":\"This value should be alphanumeric.\",\"badfiletype\":\"This file type is not allowed\",\"cannotprocessfile\":\"This file looks suspicious and can unfortunately not be uploaded\",\"check\":[\"You must select between \",1,\" and \",2,\" choices.\"],\"date\":\"This is not a valid date\",\"default\":\"This value seems to be invalid.\",\"digits\":\"This value should be digits.\",\"email\":\"This value should be a valid email.\",\"email_baddomain\":[\"Due to difficulties with mailing to \",1,\" email addresses we kindly request you to use an alternative email provider.\"],\"email_suggestion\":[\"Did you mean \",1,\"?\"],\"equalto\":\"This value should be the same.\",\"formunavailable\":\"This form is currently unavailable\",\"integer\":\"This value should be a valid integer.\",\"length\":[\"This value length is invalid. It should be between \",1,\" and \",2,\" characters long.\"],\"max\":[\"This value should be lower than or equal to \",1,\".\"],\"maxarray\":[\"You can add at most \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"maxcheck\":[\"You must select \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 choice\"],\"subselse\":[1,\" choices\"]},\" or fewer.\"],\"maxheight\":[\"The image is too big. It should be at most \",2,\" pixels high.\"],\"maxlength\":[\"This value is too long. It should have \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 character\"],\"subselse\":[1,\" characters\"]},\" or fewer.\"],\"maxsignupsreached\":\"The maximum number of signups has been reached\",\"maxwidth\":[\"The image is too big. It should be at most \",2,\" pixels wide.\"],\"min\":[\"This value should be greater than or equal to \",1,\".\"],\"minarray\":[\"You must add at least \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 item\"],\"subselse\":[1,\" items\"]},\".\"],\"mincheck\":[\"You must select at least \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 choice\"],\"subselse\":[1,\" choices\"]},\".\"],\"minheight\":[\"The image is too small. It should be at least \",2,\" pixels high.\"],\"minlength\":[\"This value is too short. It should have \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"1 character\"],\"subselse\":[1,\" characters\"]},\" or more.\"],\"minwidth\":[\"The image is too small. It should be at least \",2,\" pixels wide.\"],\"notblank\":\"This value should not be blank.\",\"number\":\"This value should be a valid number.\",\"pattern\":\"This value seems to be invalid.\",\"range\":[\"This value should be between \",1,\" and \",2,\".\"],\"required\":\"This value is required.\",\"step1mismatch\":\"The value must be a whole number\",\"stepmismatch\":[\"The value should be a multiple of \",1,\".\"],\"time\":\"This is not a valid time\",\"unacceptableemail\":\"This email address is not acceptable here\",\"upload_cannotcheck\":\"This file cannot be uploaded as we are currently unable to verify it\",\"upload_suspicious\":\"This file looks suspicious and can unfortunately not be uploaded\",\"url\":\"This value should be a valid url.\"}}}});\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/nl.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/de.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/es.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/it.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n// Adding dependency: /opt/wh/whtree/modules/publisher/language/default.xml\n","/* import ImgEditField from '@mod-publisher/js/forms/fields/imgedit';\n*/\nimport * as dompack from '@webhare/dompack';\nimport { FileEditElement } from './fileeditbase';\nimport { emplace } from '@webhare/std';\nimport { getTid } from '@webhare/gettid';\nimport { getFileAsDataURL } from '@webhare/upload';\nimport { setFieldError } from '@mod-publisher/js/forms/internal/customvalidation';\n\nlet revoker: FinalizationRegistry<string> | undefined;\nconst cachedURLs = new WeakMap<File, string>();\n\nfunction createFileURL(file: File): string {\n  return emplace(cachedURLs, file, {\n    insert: () => {\n      const newurl = URL.createObjectURL(file);\n      //setup a finalizer to revoke object urls\n      revoker ||= new FinalizationRegistry<string>((oldurl) => URL.revokeObjectURL(oldurl));\n      //as soon as file is lost to us\n      revoker.register(file, newurl);\n      return newurl;\n    }\n  });\n}\n\nasync function getImageDimensions(file: File): Promise<{ width: number; height: number }> {\n  const img = await dompack.loadImage(await getFileAsDataURL(file));\n  return { width: img.naturalWidth, height: img.naturalHeight };\n}\n\ninterface ImgEditTexts {\n  explainUpload?: string;\n}\n\nexport class ImgEditElement extends FileEditElement {\n  static observedAttributes = [\"min-width\", \"max-width\", \"min-height\", \"max-height\"];\n\n  private static texts: ImgEditTexts | null = null;\n\n  minWidth: number;\n  maxWidth: number;\n  minHeight: number;\n  maxHeight: number;\n\n  constructor() {\n    super();\n    // this.addEventListener(\"keypress\", evt => this.checkForUploadOrClear(evt)); // handle space+enter to active\n\n    this.maindiv.classList.add(\"images\");\n\n    this.minWidth = parseInt(this.getAttribute(\"min-width\") || \"0\") || 0;\n    this.maxWidth = parseInt(this.getAttribute(\"max-width\") || \"0\") || 0;\n    this.minHeight = parseInt(this.getAttribute(\"min-height\") || \"0\") || 0;\n    this.maxHeight = parseInt(this.getAttribute(\"max-height\") || \"0\") || 0;\n\n    this.refresh();\n  }\n\n  attributeChangedCallback(name: string, _oldValue: string, newValue: string) {\n    const value = parseInt(newValue);\n    if (isNaN(value))\n      return;\n    switch (name) {\n      case \"min-width\": {\n        this.minWidth = value;\n        break;\n      }\n      case \"max-width\": {\n        this.maxWidth = value;\n        break;\n      }\n      case \"min-height\": {\n        this.minHeight = value;\n        break;\n      }\n      case \"max-height\": {\n        this.maxHeight = value;\n        break;\n      }\n    }\n  }\n\n  static setTexts(textupdate: ImgEditTexts) {\n    if (!ImgEditElement.texts)\n      ImgEditElement.texts = {};\n\n    Object.assign(ImgEditElement.texts, textupdate);\n    dompack.qSA<ImgEditElement>(\"wh-imgedit\").forEach(node => node.refresh()); //update any existing nodes\n  }\n\n  async _check() {\n    const error = await super._check();\n    if (!error && this.isSet() && (this.minWidth || this.maxWidth || this.minHeight || this.maxHeight)) {\n      for (const file of this.currentFiles) {\n        if (file.file) {\n          const size = await getImageDimensions(file.file);\n          if (this.minWidth && size.width < this.minWidth)\n            setFieldError(this, getTid(\"publisher:site.forms.commonerrors.minwidth\", size.width, this.minWidth), { reportimmediately: false });\n          else if (this.maxWidth && size.width > this.maxWidth)\n            setFieldError(this, getTid(\"publisher:site.forms.commonerrors.maxwidth\", size.width, this.maxWidth), { reportimmediately: false });\n          else if (this.minHeight && size.height < this.minHeight)\n            setFieldError(this, getTid(\"publisher:site.forms.commonerrors.minheight\", size.height, this.minHeight), { reportimmediately: false });\n          else if (this.maxHeight && size.height > this.maxHeight)\n            setFieldError(this, getTid(\"publisher:site.forms.commonerrors.maxheight\", size.height, this.maxHeight), { reportimmediately: false });\n        }\n      }\n    }\n    return error;\n  }\n\n  refresh() {\n    const nodes = [];\n    for (const [idx, file] of this.currentFiles.entries()) {\n      const imgholder = dompack.create(\"div\", { class: \"image\", part: \"image\" });\n      const img = dompack.create(\"img\", { class: 'image__img', src: file.link ?? createFileURL(file.file) });\n\n      const deletebutton = dompack.create(\"button\", { part: \"button deletebutton\", class: \"deletebutton image__deletebutton\" });\n      this.setupDeleteButton(deletebutton, idx);\n\n      imgholder.append(img, deletebutton);\n      nodes.push(imgholder);\n    }\n\n    if (this.currentFiles.length < this.maxFiles) {\n      //add an extra 'image' which is the placeholder for additional uploads\n      const imgholder = dompack.create(\"div\", { class: \"image image--placeholder\", part: \"image placeholder\" });\n      const contentwrapper = dompack.create(\"div\", { class: \"image__content\" });\n      const uploadicon = dompack.create(\"div\", { class: \"image__uploadicon\", part: \"uploadicon\" });\n      const explain = dompack.create(\"div\", {\n        class: \"image__explain\",\n        textContent: ImgEditElement.texts?.explainUpload || getTid(\"publisher:site.forms.imgedit-explain-upload\")\n      });\n      imgholder.append(contentwrapper);\n      contentwrapper.append(uploadicon, explain);\n      imgholder.tabIndex = 0;\n      this.setupUploadButton(imgholder);\n      nodes.push(imgholder);\n    }\n\n    /* FIXME aria label, currently set at group level, should be per image?\n\n          // Set the aria-label to a combined label of the field together with the action which activating it through click/enter/space will perform\n          this.node.setAttribute(\"aria-label\", getTid(\"publisher:site.forms.imgedit-groupelement-upload\", this.node.dataset.arialabel));\n\n                    // Set the aria-label to a combined label of the field together with the action which activating it through click/enter/space will perform\n          this.node.setAttribute(\"aria-label\", getTid(\"publisher:site.forms.imgedit-groupelement-replace\", this.node.dataset.arialabel));\n*/\n\n    this.maindiv.replaceChildren(...nodes);\n  }\n}\n\n//////// Legacy version. We expect existing users to migrate to the version above\n\nexport default class ImgEditField {\n  constructor(node: HTMLElement) {\n    if (!customElements.get(\"wh-imgedit\"))\n      customElements.define(\"wh-imgedit\", ImgEditElement);\n  }\n}\n","/* To verify tree shaking viability, try:\n   whcd\n   cd whtree\n   echo 'import \"@webhare/forms\"' | node_modules/.bin/esbuild --loader:.css=empty --tsconfig=tsconfig.json --bundle --minify\n*/\n\n// This gets TypeScript to refer to us by our @webhare/... name in auto imports:\ndeclare module \"@webhare/forms\" {\n}\n\nimport FormBase from '@mod-publisher/js/forms/rpc';\nimport { default as LocalFormBase } from \"@mod-publisher/js/forms/formbase\"; //'FormBase', the RPC-ing one, is the one you want 99% of the time. LocalFormBase is for pure local handling (eg a PWA Config screen)\nimport { verifyAddress, type AddressValidationResult, type AddressChecks } from './address';\nimport { FileUploadFormElement as FileEditElement } from \"@mod-publisher/js/forms/fields/upload\";\nimport { ImgEditElement } from \"@mod-publisher/js/forms/fields/imgedit\";\nimport { JSFormElement } from './jsformelement';\nimport type { FormFileValue, FormAnalyticsEvent } from './types';\nimport { getFormHandler, getFormData } from './domsupport';\nimport { configureForms, registerHandlers } from './registration';\n\n/* TODO / NOTES\n  - we cannot move this file into jssdk namespace, the lang.json compiler doesn't accept paths that cannot be translated to a WH resource\n  - lang.json isn't really TS compatible, a nicer followup TS interface would allow something like\n    import myModuleTexts from \"wh:tid/mymodle\";\n    and offer intellisense (after solving the problems like \"what if a module wants to export multiple sets, how to implement HTMLTid and variables, etc\")\n  - so for now we'll hardcode importing form.lang.json so external users don't have to do this, take the treeshaking hit, and plan to move builtin texts\n    to some sort of /.wh/generated/builtin-language-texts system where we load the common builtin texts per language on demand\n*/\nimport \"@mod-publisher/js/forms/internal/form.lang.json\";\nimport { omit } from '@webhare/std';\n\nexport { FormBase, verifyAddress, ImgEditElement, FileEditElement, JSFormElement, getFormHandler, getFormData };\nexport type { FormSubmitResult } from \"@mod-publisher/js/forms/formbase\";\nexport { buildRPCFormSubmission as buildFormSubmission, submitRPCForm as submitForm } from \"@mod-publisher/js/forms/rpc\";\nexport type { RPCFormSubmission as FormSubmission } from \"./types\";\nexport type { AddressValidationResult, AddressChecks, FormFileValue, FormAnalyticsEvent };\nexport { DateField, TimeField } from \"@mod-publisher/js/forms/fields/datetime\";\nexport { registerHandler } from \"./registration\";\nexport { setupGoogleRecaptcha } from \"@mod-publisher/js/captcha/google-recaptcha\";\nexport { setupFriendlyCaptcha } from \"./friendly-captcha\";\nexport { setupValidator } from \"@mod-publisher/js/forms/internal/customvalidation\";\nexport { LocalFormBase };\n\nexport type FormHandlerFactory = (form: HTMLFormElement) => LocalFormBase;\n\nexport type FormConfiguration = {\n  captcha?: \"onLoad\" | \"onActivate\";\n};\n\nexport type FormSetupOptions = FormConfiguration & {\n  handlers: Record<string, FormHandlerFactory>;\n};\n\n/// Initialize all forms we already have the handler for\nexport function setupForms(options?: Partial<FormSetupOptions>) {\n  registerHandlers(options?.handlers ?? {});\n  if (options)\n    configureForms(omit(options, [\"handlers\"]));\n}\n","/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\nimport * as dompack from \"dompack\";\nimport * as datehelpers from \"../internal/datehelpers\";\nimport Keyboard from 'dompack/extra/keyboard';\nimport DatePicker from '@mod-publisher/js/forms/internal/datepicker';\n\nimport { __setUnderlyingValue, setupMyValueProperty } from \"../internal/datetime-valueprops\";\nimport { getTid } from \"@webhare/gettid\";\nimport { getLang } from \"@webhare/dompack\";\nexport { __setUnderlyingValue } from \"../internal/datetime-valueprops\";\n\n/*\nReplaces date/time inputs into separate number type inputs\nField ordering can be set by data attribute data-dateformat\n\nnice to have:\n - placeholder translations\n - Field ordering by localization\n*/\n\ninterface MultiInputSubstitionOptions {\n  baseclass: string;\n}\n\nabstract class MultiInputSubstition {\n  protected _replacednode: HTMLInputElement;\n  protected placeholders: Record<string, string> = {};\n  options: MultiInputSubstitionOptions;\n\n  constructor(inpnode: HTMLInputElement, options: Partial<MultiInputSubstitionOptions>) {\n    this.options = {\n      baseclass: 'datetime',\n      ...options\n    };\n\n    this._baseclass = this.options.baseclass;\n    this._replacednode = inpnode;\n    this._replacednode._split_doupdate = () => this._split_doupdate();\n    this._replacednode.classList.add(this._baseclass + '--replaced');\n    this._replacednode.setAttribute(\"tabindex\", \"-1\"); //disable focus by tabbing replaced field\n    this._replacednode.addEventListener('change', () => this._onOriginalChange());\n\n    if (window.MutationObserver) {\n      const _observer = new MutationObserver(() => this._onObserve());\n      _observer.observe(this._replacednode, { attributes: true, attributeFilter: ['disabled', 'required', 'class'], subtree: false, childList: false });\n    }\n\n    this._nodes = {};\n    setupMyValueProperty(this._replacednode);\n  }\n  _onOriginalChange() { //capture browser initiated changes (they don't go through our value property)\n    if (this._replacednode.value === this._lastsetvalue)\n      return;\n\n    this._lastsetvalue = this._replacednode.value;\n    this._refreshReplacingFields();\n  }\n  _onBlur(field) {\n    if (!isNaN(parseInt(field.value)))\n      field.value = ('000' + parseInt(field.value)).slice(-this._getFieldTextLength(field));\n  }\n  _onReset(evt) {\n    dompack.stop(evt);\n    if (this._replacednode.disabled)\n      return;\n\n    this._replacednode.value = '';\n    dompack.dispatchDomEvent(this._replacednode, 'input');\n    dompack.dispatchDomEvent(this._replacednode, 'change');\n  }\n  _handlePastedValue(inval) {\n    return false;\n  }\n  protected _onInput(field: HTMLInputElement | null) {\n    //now with EARLY focus\n    //FIXME cleanup field first?\n    //FIXME determine whether to use NUMBER of TEL.\n    // if(field && field.input.length === )\n    if (!field)\n      return false;\n\n    if (this._handlePastedValue(field.value)) {\n      this._refreshReplacingFields();\n      return true;\n    }\n\n    const maxlength = this._getFieldTextLength(field);\n    if (field.value.length >= maxlength) {\n      const nextfield = this._getNextField(field);\n      if (nextfield) {\n        dompack.focus(nextfield);\n\n        if (field.value.length > maxlength) { //copy over remaining contents\n          nextfield.value = field.value.substr(maxlength);\n          field.value = field.value.substr(0, maxlength);\n          dompack.dispatchDomEvent(nextfield, 'input');\n          return true; //the next field's _onInput will deal with all the normal validations\n        }\n      }\n    }\n    return false;\n  }\n  protected getLanguageCode() {\n    return getLang(this._replacednode).language;\n  }\n\n  _finalize() {\n    this._refreshAttributes();\n    this._refreshReplacingFields();\n\n    this._controlsnode = <span class={`${this._baseclass}__controls`}></span>;\n    this._inputgroup.appendChild(this._controlsnode);\n    dompack.after(this._replacednode, this._inputgroup);\n\n    this._inputgroup.addEventListener(\"input\", ev => this._onInput(ev.target), true);\n    this._inputgroup.addEventListener(\"focus\", ev => this._onFocus(ev.target), true);\n    this._inputgroup.addEventListener('blur', evt => this._onBlur(evt.target), true);\n\n    new Keyboard(this._inputgroup, {\n      \"ArrowDown\": (evt) => this._trySpin(evt, -1),\n      \"ArrowUp\": (evt) => this._trySpin(evt, +1),\n      \"ArrowLeft\": (evt) => this._arrowHorizontal(evt, -1),\n      \"ArrowRight\": (evt) => this._arrowHorizontal(evt, +1),\n      \"Backspace\": (evt) => this._handleBackspace(evt)\n    }, {\n      captureunsafekeys: true,\n      onkeypress: (evt, key) => this._onKeyPress(evt, key)\n    });\n\n  }\n  _constructPart(partname, options) {\n    return dompack.create(\"input\", {\n      className: `${this._baseclass}__part ${this._baseclass}__${partname}`,\n      pattern: \"[0-9]*\",\n      inputmode: \"numeric\",\n      autocomplete: \"off\",\n      placeholder: this.placeholders[partname],\n      type: \"tel\", //we need 'tel' for fine selection control, we can't control selectionStart/End of a type=number\n      ...options\n    });\n  }\n  _onObserve() {\n    this._refreshAttributes();\n  }\n\n  _split_doupdate() {\n    this._refreshReplacingFields();\n    if (this._currentdatepicker)\n      this._currentdatepicker.readDateNode();\n  }\n\n  _refreshAttributes() {\n    const isdisabled = this._replacednode.disabled;\n    const isrequired = this._replacednode.required;\n\n    dompack.toggleClass(this._inputgroup, this._baseclass + '--disabled', isdisabled);\n    dompack.toggleClass(this._inputgroup, this._baseclass + '--required', isrequired);\n    this._getSubInputs().forEach(node => { node.disabled = isdisabled; node.required = isrequired; });\n  }\n\n  _getSubInputs() {\n    throw new Error(\"Override!\");\n  }\n\n  _setReplacedValue(setvalue) {\n    if (setvalue !== this._lastsetvalue) {\n      __setUnderlyingValue(this._replacednode, setvalue); //direct update to prevent it from rewriting our fields\n      this._lastsetvalue = setvalue;\n\n      //TODO would be more correct to fire 'input' on any value change, but 'change' only on calendar pick OR blur\n      dompack.dispatchDomEvent(this._replacednode, 'input');\n      dompack.dispatchDomEvent(this._replacednode, 'change');\n    }\n  }\n\n  _onFocus(field) {\n    if (this._getSubInputs().indexOf(field) >= 0) //one of our handled fields\n      field.select(); //select contents fully on focus, makes it easier to start typing new values\n  }\n\n  _trySpin(evt, change) {\n    const field = evt.target;\n    const nodeidx = this._getSubInputs().indexOf(field);\n    if (nodeidx < 0) //not one of our inputs\n      return; //not handling!\n\n    dompack.stop(evt);\n    if (this._spinNode(field, nodeidx, change))\n      this._onInput(null);\n    return true;\n  }\n\n  _arrowHorizontal(evt, dir) {\n    const field = evt.target;\n\n    if ((field.selectionStart !== field.selectionEnd) //theres a selection, let the browser deal with that\n      || (dir < 0 && field.selectionStart > 0) //not at the left edge\n      || (dir > 0 && field.selectionEnd < field.value.length)) // not at the right edge\n      return;\n\n    dompack.stop(evt);\n\n    const subinputs = this._getSubInputs();\n    const gotofield = subinputs[subinputs.indexOf(field) + dir];\n    if (gotofield) {\n      dompack.focus(gotofield);\n      gotofield.selectionEnd = gotofield.selectionStart = dir > 0 ? 0 : gotofield.value.length;\n    }\n  }\n\n  _onKeyPress(evt, key) {\n    if ((key >= '0' && key <= '9') || key.length > 1) //digit or special key\n      return true;\n    dompack.stop(evt);\n  }\n\n  _handleBackspace(evt) {\n    const field = evt.target;\n    const nodeidx = this._getSubInputs().indexOf(field);\n    if (nodeidx <= 0) //not one of our fields, or the first (where we can't go back anywhere)\n      return false; //not handling\n\n    if (field.selectionEnd > 0) //selection does not include the left side of the field\n      return false;\n\n    //remove selection, if any (we're a \"backspace\" after all)\n    dompack.stop(evt);\n    field.value = field.value.substr(0, field.selectionStart) + field.value.substr(field.selectionEnd);\n\n    const prevfield = this._getSubInputs()[nodeidx - 1];\n    dompack.focus(prevfield);\n    if (prevfield.value.length > 0) //do a backspace in the previous field as if we were one\n      prevfield.value = prevfield.value.substr(0, prevfield.value.length - 1);\n\n    prevfield.selectionEnd = prevfield.selectionStart = prevfield.value.length;\n    return true;\n  }\n}\n\nexport interface DateFieldOptions extends MultiInputSubstitionOptions {\n  placeholders: {\n    year: string;\n    month: string;\n    day: string;\n  };\n  datepicker: boolean;\n  resetcontrol: boolean;\n  weeknumbers: boolean;\n}\n\nexport class DateField extends MultiInputSubstition {\n  declare options: DateFieldOptions;\n\n  constructor(inpnode: HTMLInputElement, options?: Partial<DateFieldOptions>);\n  /** @deprecated You should ensure the inputnode is a HTMLInputElement */\n  constructor(inpnode: HTMLElement, options?: Partial<DateFieldOptions>);\n\n  constructor(inpnode: HTMLInputElement, options?: Partial<DateFieldOptions>) {\n    options = {\n      datepicker: true,\n      resetcontrol: true,\n      weeknumbers: false,\n      ...options\n    };\n\n    super(inpnode, options);\n    if (!this._replacednode)\n      return;\n\n    this.placeholders = this.options.placeholders ?? (this.getLanguageCode()?.startsWith('nl') ? { year: \"jjjj\", month: \"mm\", day: \"dd\" } : { year: \"yyyy\", month: \"mm\", day: \"dd\" });\n    this.previous = { value: '' };\n\n    const dateformat = inpnode.dataset.format || \"d-m-y\";\n    const parseddate = dateformat.match(/^([dmy])([^dmy]*)([dmy])([^dmy]*)([dmy])$/);\n    if (!parseddate)\n      throw new Error(`Unrecognized date format '${dateformat}'`);\n\n    this._inputgroup = <span class={`${this._baseclass} ${this._baseclass}__date`}>\n      {this._constructDatePart(parseddate[1])}\n      <span class={`${this._baseclass}__sep`}>{parseddate[2]}</span>\n      {this._constructDatePart(parseddate[3])}\n      <span class={`${this._baseclass}__sep`}>{parseddate[4]}</span>\n      {this._constructDatePart(parseddate[5])}\n    </span>;\n\n    this._nodes.day.min = 1;\n    this._nodes.day.max = 31;\n    this._nodes.month.min = 1;\n    this._nodes.month.max = 12;\n\n    if (this._replacednode.min !== \"\") { //Should be iso date\n      const minyear = this._replacednode.min.split(/[^0-9]+/)[0];\n      if (minyear !== \"\")\n        this._nodes.year.min = minyear;\n    }\n\n    if (this._replacednode.max !== \"\") { //Should be iso date\n      const maxyear = this._replacednode.max.split(/[^0-9]+/)[0];\n      if (maxyear !== \"\")\n        this._nodes.year.max = maxyear;\n    }\n\n    this._finalize();\n\n    if (this.options.datepicker) {\n      this._datepickercontrol = <span class={`${this._baseclass}__togglepicker`}></span>;\n      this._datepickercontrol.addEventListener(\"click\", evt => this._onDatePickerClick(evt));\n      this._controlsnode.appendChild(this._datepickercontrol);\n    }\n    if (this.options.resetcontrol) {\n      this._resetcontrol = <span class={`${this._baseclass}__reset`}></span>;\n      this._resetcontrol.addEventListener(\"click\", evt => this._onReset(evt));\n      this._controlsnode.appendChild(this._resetcontrol);\n    }\n  }\n\n  _onDatePickerClick(evt) {\n    dompack.stop(evt);\n\n    if (this._currentdatepicker || this._replacednode.disabled)\n      return;\n    this._currentdatepicker = new DatePicker(this);\n  }\n  __closedDatepicker() {\n    this._currentdatepicker = null;\n\n    //return focus to last replacement input (so if using tab you go to next field)\n    const inplst = this._inputgroup.querySelectorAll(\"input\");\n    if (inplst.length)\n      inplst[inplst.length - 1].focus();\n  }\n\n  _constructDatePart(which) {\n    const partname = { d: \"day\", m: \"month\", y: \"year\" }[which];\n    if (this._nodes[partname])\n      throw new Error(`Duplicate '${partname}' node`);\n\n    this._nodes[partname] = this._constructPart(partname, { maxlength: partname === \"year\" ? 4 : 2 });\n    return this._nodes[partname];\n  }\n\n  _getSubInputs() {\n    return [this._nodes.day, this._nodes.month, this._nodes.year];\n  }\n\n  _setDateByParts(parts) {\n    this._nodes.day.value = ('0' + parts.day).substr(-2);\n    this._nodes.month.value = ('0' + parts.month).substr(-2);\n    this._nodes.year.value = ('000' + parts.year).substr(-4);\n  }\n\n  _refreshReplacingFields() {\n    this._lastsetvalue = this._replacednode.value;\n\n    if (this._replacednode.value) { //Should be iso date\n      this._currentdate = datehelpers.parseISODate(this._replacednode.value, { nofail: true });\n      if (this._currentdate) {\n        this._setDateByParts(this._currentdate);\n        return;\n      }\n    }\n    this._nodes.day.value = \"\";\n    this._nodes.month.value = \"\";\n    this._nodes.year.value = \"\";\n  }\n\n  _getFieldTextLength(field) {\n    return field === this._nodes.year ? 4 : 2;\n  }\n  _getNextField(field) {\n    return field === this._nodes.day ? this._nodes.month\n      : field === this._nodes.month ? this._nodes.year\n        : null;\n\n  }\n\n  _getCurrentAsISODate() {\n    let year = parseInt(this._nodes.year.value, 0);\n    const month = parseInt(this._nodes.month.value, 0);\n    const day = parseInt(this._nodes.day.value, 0);\n\n    if (year >= 0 && year <= 99 && this._replacednode.dataset.shortyearcutoff !== \"\") {\n      const cutoff = parseInt(this._replacednode.dataset.shortyearcutoff);\n      if (year < cutoff) //to do someday.. current century might not be 2000 anymore\n        year += 2000;\n      else\n        year += 1900;\n    }\n\n    return datehelpers.formatISODate(year, month, day);\n  }\n\n  _spinNode(node, nodeidx, change) {\n    const isodate = this._getCurrentAsISODate();\n    if (!isodate)\n      return; //not sure what to do with a corrupt\n\n    let newdate = new Date(isodate);\n    if (node === this._nodes.day) {\n      newdate = new Date(Number(newdate) + (change * 86400000));\n    } else if (node === this._nodes.month) {\n      newdate.setUTCMonth(newdate.getUTCMonth() + change);\n    } else if (node === this._nodes.year) {\n      newdate.setUTCFullYear(newdate.getUTCFullYear() + change);\n    } else {\n      return;\n    }\n\n    this._setReplacedValue(datehelpers.formatJSUTCISODate(newdate));\n    this._split_doupdate();\n    return true;\n  }\n\n  _handlePastedValue(inval) {\n    //if we're spotting a xx-xx-xx or xx/xx/xx pattern, assume a paste\n    const is_dashed = inval.match(/.+-.+-.+/);\n    const is_slashed = inval.match(/.+\\/.+\\/.+/);\n    if (is_dashed || is_slashed) {\n      const parseddate = datehelpers.parseDate('d-m-y', inval, { nofail: true });\n      if (parseddate) {\n        this._setReplacedValue(datehelpers.formatISODate(parseddate.year, parseddate.month, parseddate.day));\n        this._refreshReplacingFields();\n        return true;\n      }\n    }\n    return false;\n  }\n\n  private getInputValues() {\n    return {\n      year: this._nodes.year.value,\n      month: this._nodes.month.value,\n      day: this._nodes.day.value\n    };\n  }\n\n  _onInput(field: HTMLInputElement | null) {\n    if (super._onInput(field))\n      return true;\n\n    const fields = this.getInputValues();\n    if (!fields.year && !fields.month && !fields.day) { //full field clear\n      this._replacednode.setCustomValidity('');\n      this._setReplacedValue(\"\");\n      return;\n    }\n\n    let year = parseInt(fields.year, 0);\n    const month = parseInt(fields.month, 0);\n    const day = parseInt(fields.day, 0);\n\n    if (year >= 0 && year <= 99 && this._replacednode.dataset.shortyearcutoff !== \"\") {\n      const cutoff = parseInt(this._replacednode.dataset.shortyearcutoff);\n      if (year < cutoff) //TODO current century might not be 2000 anymore\n        year += 2000;\n      else\n        year += 1900;\n    }\n\n    const finaldate = datehelpers.formatISODate(year, month, day);\n    this._replacednode.setCustomValidity(finaldate ? \"\" : getTid(\"publisher:site.forms.commonerrors.date\"));\n    this._setReplacedValue(finaldate);\n    return true;\n  }\n\n  _onKeyPress(evt, key) {\n    if (key === '-' || key === '/') {\n      const nextfield = this._getNextField(evt.target);\n      if (nextfield)\n        dompack.focus(nextfield);\n      return false;\n    }\n    return super._onKeyPress(evt, key);\n  }\n\n  /*\n    onKeyUp( ev, node )\n    {\n      ev.preventDefault();\n      ev.stopPropagation();\n\n      let prevval = this.previous.value;\n      this.previous.value = node.value;\n\n      if( ev.keyCode === 8 && node.value === \"\" && prevval === \"\" )//backspace\n      {\n        //Try to set focus on previous input\n        let prevnode = node.parentNode.previousSibling;\n        if( prevnode )\n        {\n          let previnp = prevnode.querySelector(\"input\");\n          if( previnp )\n            previnp.focus();\n        }\n\n        return;\n      }\n\n      //First some basic validation\n      let value = node.value.replace(/[^0-9]+/g,'');\n\n      if( value === \"\" || value !== node.value || 1*value < 1*node.min || 1*value > 1*node.max )\n        return;\n\n      //Is field value minimal length\n      if( (node === this.yearnode && value.length < 4) || (node !== this.yearnode && value.length < 2) )\n        return;\n\n      if( prevval === node.value )\n          return;//Only go to next input if value changed\n\n      //Try to set focus on next input\n      let nextnode = node.parentNode.nextSibling;\n      if( !nextnode )\n        return;\n\n      let nextinp = nextnode.querySelector(\"input\");\n      if( nextinp )\n        nextinp.focus();\n    }\n  */\n\n  _onReset(evt) {\n    this.closePicker();\n    super._onReset(evt);\n  }\n\n  //-------- PUBLIC API ---------------\n  closePicker() { //close any open date picker\n    if (this._currentdatepicker)\n      this._currentdatepicker._dismissOverlay();\n  }\n}\n\nexport interface TimeFieldOptions extends MultiInputSubstitionOptions {\n  placeholders: {\n    hour: string;\n    minute: string;\n    second: string;\n    msec: string;\n  };\n  resetcontrol: boolean;\n}\n\nexport class TimeField extends MultiInputSubstition {\n\n  constructor(inpnode: HTMLInputElement, options?: Partial<TimeFieldOptions>);\n  /** @deprecated You should ensure the inputnode is a HTMLInputElement */\n  constructor(inpnode: HTMLElement, options?: Partial<TimeFieldOptions>);\n\n  constructor(inpnode: HTMLInputElement, options?: Partial<TimeFieldOptions>) {\n    options = {\n      resetcontrol: true,\n      ...options\n    };\n\n    super(inpnode, options);\n    if (!this._replacednode)\n      return;\n\n    this.placeholders = this.options.placeholders ?? (this.getLanguageCode() === 'nl' ? { hour: \"uu\", minute: \"mm\", second: \"ss\", msec: \"mmm\" } : { hour: \"hh\", minute: \"mm\", second: \"ss\", msec: \"mmm\" });\n    const step = parseFloat(this._replacednode.getAttribute(\"step\") || '0');\n    this.previous = { value: '' };\n    this._showmsec = step !== Math.floor(step); //fraction\n    this._showsecond = this._showmsec || (step % 60 !== 0); //unable to round to minute... so seconds\n\n    this._inputgroup = <span class={`${this._baseclass} ${this._baseclass}__time`}>\n      {this._constructTimePart(\"hour\")}\n      <span class={`${this._baseclass}__sep`}>:</span>\n      {this._constructTimePart(\"minute\")}\n    </span>;\n\n    this._nodes.hour.max = 23;\n    this._nodes.minute.max = 59;\n\n    if (this._showsecond) {\n      this._inputgroup.appendChild(<span class={`${this._baseclass}__sep`}>:</span>);\n      this._inputgroup.appendChild(this._constructTimePart(\"second\"));\n      this._nodes.second.max = 59;\n    }\n    if (this._showmsec) {\n      this._inputgroup.appendChild(<span class={`${this._baseclass}__sep`}>.</span>);\n      this._inputgroup.appendChild(this._constructTimePart(\"msec\"));\n      this._nodes.msec.max = 999;\n    }\n\n    this._finalize();\n\n    if (this.options.resetcontrol) {\n      this._resetcontrol = <span class={`${this._baseclass}__reset`}></span>;\n      this._resetcontrol.addEventListener(\"click\", evt => this._onReset(evt));\n      this._controlsnode.appendChild(this._resetcontrol);\n    }\n  }\n\n  _spinNode(node, nodeidx, change) {\n    let newval = (parseInt(node.value) || 0) + change;\n    const max = parseInt(node.getAttribute(\"max\"));\n\n    if (newval < 0 || newval > max) {\n      if (nodeidx === 0) //already at top level, no wrapping..\n        return false;\n\n      newval = change < 0 ? max : 0; //wrap it!\n      if (nodeidx > 0) //spin higher node too\n        if (!this._spinNode(this._getSubInputs()[nodeidx - 1], nodeidx - 1, change))\n          return false;\n    }\n\n    //Cannot use dompack.changeValue here as we need to explicitly tell onInput not to move the next field\n    node.value = ('000' + newval).slice(nodeidx === 3 ? -3 : -2);\n    return true;\n  }\n\n  _constructTimePart(partname) {\n    if (this._nodes[partname])\n      throw new Error(`Duplicate '${partname}' node`);\n\n    this._nodes[partname] = this._constructPart(partname, {\n      maxlength: partname === 'msec' ? 3 : 2,\n      min: \"0\"\n    });\n\n    return this._nodes[partname];\n  }\n\n  _refreshReplacingFields() {\n    this._lastsetvalue = this._replacednode.value;\n\n    const time = datehelpers.parseISOTime(this._replacednode.value, { nofail: true });\n    if (time) {\n      this._currenttime = time;\n      this._nodes.hour.value = (\"0\" + this._currenttime.hour).slice(-2);\n      this._nodes.minute.value = (\"0\" + this._currenttime.minute).slice(-2);\n      if (this._nodes.second)\n        this._nodes.second.value = (\"0\" + this._currenttime.second).slice(-2);\n      if (this._nodes.msec)\n        this._nodes.msec.value = (\"00\" + this._currenttime.msec).slice(-3);\n      return;\n    }\n\n    this._nodes.hour.value = \"\";\n    this._nodes.minute.value = \"\";\n    if (this._nodes.second)\n      this._nodes.second.value = \"\";\n    if (this._nodes.msec)\n      this._nodes.msec.value = \"\";\n  }\n\n  _getFieldTextLength(field) {\n    return field === this._nodes.msec ? 3 : 2;\n  }\n  _getSubInputs() {\n    return [\n      this._nodes.hour,\n      this._nodes.minute,\n      ...(this._nodes.second ? [this._nodes.second] : []),\n      ...(this._nodes.msec ? [this._nodes.msec] : [])\n    ];\n  }\n\n  private getInputValues() {\n    return {\n      hour: this._nodes.hour.value,\n      minute: this._nodes.minute.value,\n      second: this._nodes.second?.value ?? \"\",\n      msec: this._nodes.msec?.value ?? \"\"\n    };\n  }\n\n  _onInput(field: HTMLInputElement | null) {\n    if (super._onInput(field))\n      return true;\n\n    const fields = this.getInputValues();\n    if (!fields.hour && !fields.minute && !fields.second && !fields.msec) { //full field clear\n      this._replacednode.setCustomValidity('');\n      this._setReplacedValue(\"\");\n      return;\n    }\n\n    const hour = parseInt(fields.hour, 0);\n    const minute = parseInt(fields.minute, 0);\n    const second = parseInt(fields.second, 0);\n    const msec = parseInt(fields.msec, 0);\n\n    const finaltime = datehelpers.formatISOTime(hour, minute, this._showsecond ? second : null, this._showmsec ? msec : null);\n    this._replacednode.setCustomValidity(finaltime ? \"\" : getTid(\"publisher:site.forms.commonerrors.time\"));\n    this._setReplacedValue(finaltime);\n    return true;\n  }\n\n  _onKeyPress(evt, key) {\n    if (key === ':' || key === '.') {\n      const nextfield = this._getNextField(evt.target);\n      if (nextfield)\n        dompack.focus(nextfield);\n      return false;\n    }\n    return super._onKeyPress(evt, key);\n  }\n\n  _getNextField(field) {\n    return field === this._nodes.hour ? this._nodes.minute\n      : field === this._nodes.minute ? this._nodes.second\n        : null;\n\n  }\n\n\n  /*\n    onKeyUp( ev, node )\n    {\n      ev.preventDefault();\n      ev.stopPropagation();\n\n      let prevval = this.previous.value;\n      this.previous.value = node.value;\n\n      if( ev.keyCode === 8 && node.value === \"\" && prevval === \"\" )//backspace\n      {\n        //Try to set focus on previous input\n        let prevnode = node.parentNode.previousSibling;\n        if( prevnode )\n        {\n          let previnp = prevnode.querySelector(\"input\");\n          if( previnp )\n            previnp.focus();\n        }\n\n        return;\n      }\n\n      //First some basic validation\n      let value = node.value.replace(/[^0-9]+/g,'');\n      if( value === \"\" || value !== node.value || 1*value < 1*node.min || 1*value > 1*node.max )\n        return;\n\n      //Is field value minimal length\n      if( value.length < 2 )\n        return;\n\n      if( prevval === node.value )\n          return;//Only go to next input if value changed\n\n      //Try to set focus on next input\n      let nextnode = node.parentNode.nextSibling;\n      if( !nextnode )\n        return;\n\n      let nextinp = nextnode.querySelector(\"input\");\n      if( nextinp )\n        nextinp.focus();\n    }\n  */\n}\n","/* eslint-disable */\n/// @ts-nocheck -- Bulk rename to enable TypeScript validation\n\nimport * as dompack from 'dompack';\nimport KeyboardHandler from \"dompack/extra/keyboard\";\nimport * as datehelpers from \"./datehelpers\";\nimport { getLang } from '@webhare/dompack/src/tree';\n// import \"./datestrings.lang.json\";\n//import { getTid } from \"@webhare/gettid\";\n\n// FIXME work with backend\nconst langcodes =\n{\n  \"nl\": \"am;pm;januari;februari;maart;april;mei;juni;juli;augustus;september;oktober;november;december;maandag;dinsdag;woensdag;donderdag;vrijdag;zaterdag;zondag;jan;feb;mrt;apr;mei;jun;jul;aug;sep;okt;nov;dec;ma;di;wo;do;vr;za;zo\",\n  \"de\": \"am;pm;Januar;Februar;März;April;Mai;Juni;Juli;August;September;Oktober;November;Dezember;Montag;Dienstag;Mittwoch;Donnerstag;Freitag;Samstag;Sonntag;Jan.;Febr.;März;Apr.;Mai;Juni;Juli;Aug.;Sept.;Okt.;Nov.;Dez.;Mo;Di;Mi;Do;Fr;Sa;So\",\n  \"en\": \"am;pm;January;February;March;April;May;June;July;August;September;October;November;December;Monday;Tuesday;Wednesday;Thursday;Friday;Saturday;Sunday;Jan;Feb;Mar;Apr;May;Jun;Jul;Aug;Sep;Oct;Nov;Dec;Mon;Tue;Wed;Thu;Fri;Sat;Sun\"\n};\n\n//Load any needed localizations yourself: frameworks.mootools.more.locale.nl-nl.date, frameworks.mootools.more.locale.es-es.date, frameworks.mootools.more.locale.de-de.date, frameworks.mootools.more.locale.fr-fr.date\n\n/*\n\nConverting calendar.js code to calendar2.js\n\n    Changed classes\n      - .-wh-calendar-popup   ->   .wh-datepicker > .value\n      - .-wh-calendar-icon    ->   .wh-datepicker > .arrow\n\n    Changed <input> attributes:\n      - data-formatting -> data-format\n      - data-empty -> placeholder\n\n    Load:\n      LOAD: wh.ui.calendar2\n      LOAD: wh.locale.common.de-de.date\n      LOAD: wh.locale.common.en-us.date\n      LOAD: wh.locale.common.nl-nl.date\n\n    Taal instellen:\n      Locale.use(\"de-DE\");\n      Locale.use(\"en-US\");\n      Locale.use(\"nl-NL\");\n*/\n\n\n/////////////////////\n//\n//\n\n//NOTE preparing to sync this with dompack selectlist.es\n\nclass ComponentOverlay {\n  constructor() {\n    this._boundGlobalEvents = null;\n  }\n  _startOverlayDismissCapture() {\n    //set up capturing handlers to kill our pulldowns asap when something else is clicked\n    if (!this._boundGlobalEvents)\n      this._boundGlobalEvents = evt => this._globalEvents(evt);\n\n    if (!dompack.debugflags.meo) {\n      window.addEventListener(\"keyup\", this._boundGlobalEvents, true);\n      window.addEventListener(\"mousedown\", this._boundGlobalEvents, true);\n      window.addEventListener(\"touchstart\", this._boundGlobalEvents, true);\n    }\n  }\n  _endOverlayDismissCapture() {\n    window.removeEventListener(\"keyup\", this._boundGlobalEvents, true);\n    window.removeEventListener(\"mousedown\", this._boundGlobalEvents, true);\n    window.removeEventListener(\"touchstart\", this._boundGlobalEvents, true);\n  }\n  _globalEvents(evt) {\n    if (evt && evt.type === \"keyup\") {\n      if (evt.keyCode === 27)\n        this._dismissOverlay();\n      return;\n    }\n\n    if (!dompack.contains(this._anchornode, evt.target) && !dompack.contains(this._items, evt.target))\n      this._dismissOverlay();\n  }\n}\n\n\n\n//\n//\n////////////////////\n\n\n\n/*\n * $wh.CalendarTable\n * Builds a plain calendar table based on mootools locale settings\n *\n */\n\nclass CalendarTable extends ComponentOverlay {\n  constructor() {\n    super();\n    this.options = {\n      weeknumbers: false,\n      header_weeknr: '', //weeknr.\n      min: null, //minimal date\n      max: null //maximal date (out of range gets disabled class\n    };\n    this.cdate = null;\n    this.showdate = null;\n  }\n\n  _onDayClick(evt) {\n    const clickedday = evt.target.closest(`.${this.options.baseclass}__day--selectable`);\n    // console.error(clickedday, clickedday.dataset.whDatepickerDate);\n    if (!clickedday)\n      return;\n\n    dompack.stop(evt);\n    this._dismissOverlay();\n\n    dompack.changeValue(this._datenode, clickedday.dataset.whDatepickerDate);\n  }\n\n  getTable(showdate, options) {\n    this.options = { ...this.options, options };\n\n    const caltable = dompack.create('table', {\n      className: this.options.baseclass + '__days',\n      on: { click: evt => this._onDayClick(evt) }\n    });\n    const calbody = dompack.create('tbody');\n    caltable.appendChild(calbody);\n\n    //Build week rows\n    const rownode = <tr class={this.options.baseclass + '__weekdays'}></tr>;\n    if (this.options.weeknumbers)\n      rownode.appendChild(<td></td>); //placeholder for upperleft corner\n\n    for (let w = 0; w < 7; ++w) {\n      rownode.appendChild(<th scope=\"column\" class={this.options.baseclass + '__weekday'}><span>{this._languagetexts[w + 33]}</span></th>);\n    }\n    calbody.appendChild(rownode);\n\n    const mindate = this.options.min ? {\n      day: this.options.min.getUTCDay(),\n      month: this.options.min.getUTCMonth(),\n      year: this.options.min.getUTCFullYear()\n    } : null;\n\n    const maxdate = this.options.max ? {\n      day: this.options.max.getUTCDay(),\n      month: this.options.max.getUTCMonth(),\n      year: this.options.max.getUTCFullYear()\n    } : null;\n\n    //What is the weekday for the first day of the selected month ?\n    const startofmonth = datehelpers.makeJSUTCDate({ ...showdate, day: 1 });\n    const showmonth = startofmonth.getUTCMonth();\n    const showyear = startofmonth.getUTCFullYear();\n\n    //    console.log(startofmonth);\n    const startofmonth_weekday = startofmonth.getUTCDay(); //0-6 where 0=Sunday\n\n    //Work backwards to a monday (start of the week)\n    const backwardsdays = startofmonth_weekday === 0 ? 6 : startofmonth_weekday - 1;\n    let currentgriddate = startofmonth.getTime() - (backwardsdays * 86400 * 1000);\n\n    //Build the grid!\n    for (let week = 0; week < 6; ++week) {\n      const rownode = dompack.create('tr', { className: this.options.baseclass + '__week' });\n\n      for (let day = 0; day < 7; ++day) {\n        const date = new Date(currentgriddate);\n        if (this.options.weeknumbers && day === 0)\n          rownode.appendChild(<th class={this.options.baseclass + '__weeknr'} scope=\"row\"><span>{datehelpers.getWeekNumber(date)}</span></th>);\n\n        const dateY = date.getUTCFullYear();\n        const dateM = date.getUTCMonth();\n        const dateD = date.getUTCDate();\n\n        const celldate = { year: dateY, month: dateM + 1, day: dateD };\n\n        const dayclass = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'][day];\n        const daynode = dompack.create('td', {\n          className: `${this.options.baseclass}__day ${this.options.baseclass}__day--${dayclass}`,\n          childNodes: [dompack.create(\"span\", { textContent: date.getUTCDate() })],\n          dataset: { whDatepickerDate: datehelpers.formatJSUTCISODate(date) }\n        });\n\n        if (dateM !== showmonth || dateY !== showyear)\n          daynode.classList.add(this.options.baseclass + '__day--othermonth');\n\n        if ((mindate && dateY < mindate.year && dateM < mindate.month && dateD < mindate.day)\n          || (maxdate && dateY > maxdate.year && dateM > maxdate.month && dateD > maxdate.day)) {\n          daynode.classList.add(this.options.baseclass + '__day--disabled');\n        } else {\n          daynode.setAttribute(\"tabindex\", \"0\");\n          daynode.classList.add(this.options.baseclass + '__day--selectable');\n        }\n\n        if (datehelpers.compareDate(this.today, celldate) === 0)\n          daynode.classList.add(this.options.baseclass + '__day--today');\n\n        if (this.date && datehelpers.compareDate(this.date, celldate) === 0)\n          daynode.classList.add(this.options.baseclass + '__day--selected');\n\n        rownode.appendChild(daynode);\n        currentgriddate += 86400 * 1000;\n      }\n      calbody.appendChild(rownode);\n    }\n\n    return caltable;\n  }\n}\n\nclass Calendar2 extends CalendarTable {\n  constructor(options) {\n    super();\n    this.options = {\n      weeknumbers: false,\n      date: null,   // initial value\n      min: null,\n      max: null,\n      ...options\n    };\n    this.node = null;\n    this.tablenode = null;\n    this.yearspinner = null;\n    this.monthselectnode = null;\n    this.date = null; //selected date\n    this.keys = null;\n    this.focusednode = null;\n  }\n\n  _onYearMonthChange(evt) {\n    this.options.date = {\n      year: this.yearspinner.value,\n      month: this.monthselectnode.value,\n      day: this._currentdate ? this._currentdate.day : 1\n    };\n\n    this._currentdate.month = parseInt(this.monthselectnode.value);\n    this._currentdate.year = parseInt(this.yearspinner.value);\n\n    this.setMonthTable(this.options.date);\n  }\n\n  readDateNode() {\n    this.mindate = datehelpers.parseISODate(this._datenode.min, { nofail: true });\n    this.maxdate = datehelpers.parseISODate(this._datenode.max, { nofail: true });\n    this.date = datehelpers.parseISODate(this._datenode.value, { nofail: true });\n    const suggestion = datehelpers.parseISODate(this._datenode.dataset.suggestion, { nofail: true });\n    const max = datehelpers.parseISODate(this._datenode.max);\n    this.today = datehelpers.getLocalToday();\n\n    this.yearspinner.min = this.mindate ? this.mindate.year : 1901;\n    this.yearspinner.max = this.maxdate ? this.maxdate.year : 2099;\n\n    let showdate = this.date ?? suggestion ?? this.today;\n    if (this.mindate && datehelpers.makeJSUTCDate(showdate) < datehelpers.makeJSUTCDate(this.mindate))\n      showdate = this.mindate;\n    if (this.maxdate && datehelpers.makeJSUTCDate(showdate) > datehelpers.makeJSUTCDate(this.maxdate))\n      showdate = this.maxdate;\n\n    if (!this._currentdate)\n      this._currentdate = showdate;\n\n    this.setMonthTable(showdate);\n  }\n\n  _addMeToNode(container) {\n    this.node = container;\n\n    this.yearspinner = <input type=\"number\" class={`${this.options.baseclass}__yearselect`} step=\"1\" on={{ change: evt => this._onYearMonthChange(evt) }} />;\n    this.monthselectnode = <select class={`${this.options.baseclass}__monthselect`} on={{ change: evt => this._onYearMonthChange(evt) }} />;\n\n    this.readDateNode();\n\n    //build calendar interface:\n    const headernode = <div class={this.options.baseclass + \"__header\"}>\n      <div class={this.options.baseclass + \"__previous\"} onClick={evt => this.changeMonth(evt, -1)} />\n      {this.monthselectnode}\n      {this.yearspinner}\n      <div class={this.options.baseclass + \"__next\"} onClick={evt => this.changeMonth(evt, +1)} />\n    </div>;\n\n    //month pulldown\n    const selectedmonth = this._currentdate.month;\n    for (let m = 0; m < 12; ++m)\n      this.monthselectnode.appendChild(<option value={m + 1} selected={m === selectedmonth - 1}>{this._languagetexts[m + 2]}</option>);\n\n    this.node.append(headernode, this.tablenode);//, btnbarnode);\n\n    //looks like we're visible ! install a capturing\n    new KeyboardHandler(this.node, {\n      \"Enter\": ev => this.onKeyEnter(ev)\n    }\n      , { captureunsafekeys: true }\n    );\n\n    // Locale.addEvent(\"change\", this.onLanguageChange.bind(this));\n    this._startOverlayDismissCapture();\n    this._onYearMonthChange();\n  }\n\n  setMonthTable(showdate) {\n    this.yearspinner.value = showdate.year;\n    this.monthselectnode.value = showdate.month;\n\n    const newtable = this.getTable(showdate);\n\n    if (this.tablenode)\n      this.tablenode.replaceWith(newtable);\n    this.tablenode = newtable;\n\n    this.setFocus();\n  }\n\n  setFocus() {\n    if (!this.tablenode.clientWidth)\n      return;//Not (yet) visible\n\n    //Set focus on showdate or else first selectable date\n    let fnode;\n    if (this.date)\n      fnode = this.tablenode.querySelector(\"td[data-wh-datepicker-date='\" + datehelpers.formatISODate(this.date.year, this.date.month, this.date.day) + \"']\");\n    if (!fnode) //else pick first selectable day\n      fnode = this.tablenode.querySelector(\".\" + this.options.baseclass + '__day--selectable');\n    if (fnode)\n      fnode.focus();\n  }\n\n  onKeyEnter(ev) {\n    const daynode = ev.target.closest(\".\" + this.options.baseclass + '__day--selectable');\n    if (!daynode)\n      return;\n\n    this._onDayClick(ev);\n  }\n\n  _dismissOverlay() {\n    this.node.remove();\n    this._endOverlayDismissCapture();\n    this._owner.__closedDatepicker();\n  }\n\n  changeMonth(evt, direction) {\n    dompack.stop(evt);\n\n    let newyear = parseInt(this.yearspinner.value);\n    let newmonth = parseInt(this.monthselectnode.value) + direction;\n\n    if (newmonth > 12 || newmonth < 1) //wrap it\n    {\n      newyear += direction;\n      newmonth = direction > 0 ? 1 : 12;\n    }\n    this.setMonthTable({ year: newyear, month: newmonth });\n  }\n}\n\nclass DatePicker extends Calendar2 {\n  /** options.baseclass Base class to use for the elements in the date picker. Defaults to 'datepicker' */\n  constructor(owner) {\n    super({ ...owner.options, baseclass: owner._baseclass + '__picker' });\n    this._owner = owner;\n    this._datenode = owner._replacednode;\n    this.options = {\n      ...this.options,\n      language: null\n    };\n    //TODO limit by supportedlanguages and use gettid(\"~locale.datetimestrings\")\n    if (!this.options.language)\n      this.options.language = getLang().language;\n\n    this._languagetexts = (langcodes[this.options.language] || langcodes.en).split(';');\n\n    //we use the node to store our result, so verify it\n    //FIXME maybe this should be optional and you be allowed to create a datepicker without a corresponding node if you just manage getvalue/setvalue yourself, or maybe this glue code belongs outside us\n    //     if(node.nodeName !== 'INPUT' || node.getAttribute('type') !== 'date')\n    //       throw new Error(\"The DatePicker expects to be associated with a input[type=date]\");\n\n    //     this._node = node;\n    //     this._class = (options ? options.baseclass : '') || 'datepicker';\n    //     this._node.classList.add(this._class + \"--attached\");\n    // //\n    // this._node.addEventListener(\"wh:datepicker-request\");\n\n    this._anchornode = this._datenode.nextSibling;\n\n    this._calendarnode = dompack.create('div', { className: this.options.baseclass }); //tabindex:0 ?\n    this._addMeToNode(this._calendarnode);\n\n    this._items = this._calendarnode; //TODO bit ugly but keeps us compatible with selectlist.es\n\n    this._calendarnode.addEventListener(\"change\", ev => {\n      console.log(ev);\n    });\n\n    //Allow users to hook into the datepicker\n    dompack.dispatchCustomEvent(this._datenode, \"wh:datepicker-built\", { bubbles: true, cancelable: false, detail: { input: this._datenode, datepicker: this._calendarnode } });\n\n    //ADDME can we borrow positioning code from the dompack pulldown?\n    //for now, attach to bottom\n    document.body.appendChild(this._calendarnode);\n    const calendarnodesize = this._calendarnode.getBoundingClientRect();\n    const anchornode = this._anchornode.getBoundingClientRect();\n\n    //fits left aligned?\n    if (anchornode.left + calendarnodesize.width > window.innerWidth) { //doesn't fit left aligned, we must right align\n      this._calendarnode.style.right = '0px';\n    } else //left align\n    {\n      this._calendarnode.style.left = Math.ceil(anchornode.left) + 'px';\n    }\n\n    //fits top aligned?\n    if (anchornode.top + calendarnodesize.height > window.innerHeight) { //doesn't fit below, send above\n      let y = (window.innerHeight - anchornode.top);\n      if ((window.innerHeight - y) - calendarnodesize.height < 0) //Prevent calendar hiding behind top of window\n        y = window.innerHeight - calendarnodesize.height;\n      this._calendarnode.style.bottom = y + 'px';\n    } else //left align\n    {\n      this._calendarnode.style.top = Math.ceil(anchornode.bottom) + 'px';\n    }\n\n    this.setFocus();\n  }\n}\n\nexport default DatePicker;\n","import * as dompack from '@webhare/dompack';\nimport { type CaptchaProvider, type CaptchaSettings, captcharegistry } from \"@mod-publisher/js/captcha/api\";\n\n//recaptcha API: https://developers.google.com/recaptcha/docs/display\nlet recaptchaload: PromiseWithResolvers<void> | undefined;\n\ntype RecaptchaOptions = { language?: string };\nlet recaptchaOptions: RecaptchaOptions | undefined;\n\ndeclare global {\n  interface Window {\n    $wh__ongooglerecaptchaloaded: () => void;\n    grecaptcha: {\n      render: (node: HTMLElement, options: { sitekey: string; callback: () => void }) => string;\n      getResponse: (id: string) => string;\n    };\n  }\n}\n\nwindow.$wh__ongooglerecaptchaloaded = function () {\n  recaptchaload!.resolve();\n};\n\nfunction makeRecaptchaLoadPromise() {\n  recaptchaload = Promise.withResolvers<void>();\n  document.querySelector<HTMLElement>(\"head,body\")!.append(<script src=\"https://www.google.com/recaptcha/api.js?onload=$wh__ongooglerecaptchaloaded&amp;render=explicit\" />);\n  return recaptchaload.promise;\n}\n\nexport async function runRecaptcha(provider: CaptchaProvider, injectInto: HTMLElement, settings: CaptchaSettings) {\n  const lock = dompack.flagUIBusy({ modal: true });\n  try {\n    await (recaptchaload ? recaptchaload.promise : makeRecaptchaLoadPromise());\n\n    const captchanode = <div class=\"wh-captcha__googlerecaptchaholder\"></div>;\n    injectInto.append(captchanode);\n\n    if (provider.apikey === 'mock') {\n      captchanode.appendChild(<label class=\"wh-captcha__mock\"><input type=\"checkbox\" on={{ click: () => settings.onResponse('mock') }} />I am a human, beep-bop</label>);\n    } else {\n      const recaptchaid = window.grecaptcha.render(captchanode, {\n        sitekey: provider.apikey,\n        ...recaptchaOptions?.language ? { hl: recaptchaOptions.language } : {},\n        callback: () => {\n          const response = window.grecaptcha ? window.grecaptcha.getResponse(recaptchaid) : '';\n          settings.onResponse(response);\n        }\n      });\n    }\n  } finally {\n    lock.release();\n  }\n}\n\n\n/** Setup Google reCAPTCHA rendering\n * @param options Optional settings, currently supports:\n *  - language: The language code to use for the reCAPTCHA widget. See https://developers.google.com/recaptcha/docs/language for supported language codes\n */\nexport function setupGoogleRecaptcha(options?: RecaptchaOptions) {\n  if (captcharegistry[\"google-recaptcha\"])\n    throw new Error(\"Duplicate google recaptcha initialization\");\n\n  recaptchaOptions = { ...recaptchaOptions, ...options };\n  captcharegistry[\"google-recaptcha\"] = { initialize: runRecaptcha };\n}\n","import * as dompack from '@webhare/dompack';\nimport { type CaptchaProvider, type CaptchaSettings, captcharegistry } from \"@mod-publisher/js/captcha/api\";\n\n//friendly captcha API: https://developer.friendlycaptcha.com/docs/v2/sdk/configuration\nlet script = \"https://cdn.jsdelivr.net/npm/@friendlycaptcha/sdk@0.1.31/site.min.js\";\nlet endpoint: string | undefined;\nlet isLoaded = false;\n\nexport async function runFriendlyCaptcha(provider: CaptchaProvider, injectInto: HTMLElement, settings: CaptchaSettings): Promise<void> {\n  const captcha = document.createElement('div');\n  captcha.className = \"frc-captcha\";\n  captcha.dataset.sitekey = provider.apikey;\n  if (endpoint === \"eu\")\n    captcha.dataset.apiEndpoint = \"eu\"; //https://developer.friendlycaptcha.com/docs/v2/sdk/configuration#data-api-endpoint\n  captcha.addEventListener(\"frc:widget.complete\", ((evt: CustomEvent<{ response: string }>) => settings.onResponse(evt.detail.response)) as EventListener);\n\n  injectInto.append(captcha);\n\n  if (isLoaded) {\n    //@ts-expect-error -- undocumented but this seems to properly refresh the unit\n    window.frcaptcha.attach();\n  } else { //Now initialize it\n    using lock = dompack.flagUIBusy();\n    void (lock);\n    //TODO listen for widget.statechange - https://developer.friendlycaptcha.com/docs/v2/sdk/events#frcwidgetstatechange before releasing the lock\n    await dompack.loadScript(script, { module: true });\n    isLoaded = true;\n  }\n}\n\n/** Setup friendlycaptcha integration */\nexport function setupFriendlyCaptcha(options?: { script?: string; endpoint?: \"eu\" }) {\n  if (captcharegistry[\"friendly-captcha\"])\n    throw new Error(\"Duplicate friendly captcha initialization\");\n\n  if (options?.script)\n    script = options.script;\n  if (options?.endpoint)\n    endpoint = options.endpoint;\n\n  captcharegistry[\"friendly-captcha\"] = { initialize: runFriendlyCaptcha };\n}\n","import \"./forms-vars.css\";\nimport \"./forms.scss\";\nimport \"./checkboxradio.css\";\nimport \"./slimselect.scss\";\nimport * as forms from \"@webhare/forms\";\nimport * as dompack from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\nimport { SlimSelect } from \"@mod-utwente_design\";\nimport \"./phone\"; // Custom phone form component\nimport RTDField from \"@mod-publisher/js/forms/fields/rtd\"; // used by ut-neoform\nimport * as embedvideo from '@mod-publisher/js/forms/fields/rtd/embedvideo'; // used by ut-neoform\nimport { setTidLanguage, getTid } from \"@mod-tollium/js/gettid\";\nimport \"./dialogs\"; // For the busy modal, used by ut-neoform and publisher forms\nimport { rfSymbol } from \"@webhare/forms/src/registeredfield\";\nimport { setupFormLinkHandling } from \"@mod-utwente_base/webdesigns/ws2016/src/shared/utforms/linkhandling\";\nexport { UTRPCFormBase } from \"./utformbase\";\n\nsetupFormLinkHandling();\n\nconst lang = document.documentElement.lang.split(\"-\")[0];\n\ncustomElements.define(\"wh-fileedit\", forms.FileEditElement);\ncustomElements.define(\"wh-imgedit\", forms.ImgEditElement);\n\ndompack.register(\".wh-form__rtd\", node => new RTDField(node, { // used by ut-neoform\n  hidebuttons: ['table'],\n  onInsertVideo: void embedvideo.insertVideo\n}));\n\nforms.setupFriendlyCaptcha({ endpoint: \"eu\" });\nforms.setupGoogleRecaptcha();\nforms.setupForms({ captcha: \"onLoad\" });\n\nif (!debugFlags[\"ut-nocustomselect\"]) {\n  dompack.register<HTMLSelectElement>(\".wh-styledinput select:not(:is(.wh-form__prefillcontrol, .wh-rtd__toolbarstyle))\", node => {\n    if (!node.closest(\".wh-form__fieldgroup--slimselect\") && !node.classList.contains(\"replacedby-ss\")) { // Don't apply to selects in fieldgroups marked as slimselect, those have customized handling (like the custom forms phone component)\n      if (node.utSlimSelect) {\n        console.error(\"SlimSelect already initialized on this node\", node, node.utSlimSelect);\n        throw new Error(\"SlimSelect already initialized on this node\");\n      }\n\n      const showSearch = node.dataset.utShowsearch === \"true\"\n        || (node.dataset.utShowsearch === undefined && dompack.qSA(node, \"option\").length > 10 && (node.name.indexOf(\"country\") >= 0 || node.name.indexOf(\"nationality\") >= 0 || node.name.indexOf(\"language\") >= 0));\n      const ss = new SlimSelect({\n        select: node,\n        settings: {\n          showSearch,\n          modal: 'off', // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n          searchPlaceholder: lang === \"nl\" ? \"Zoek...\" : \"Search...\",\n          searchText: lang === \"nl\" ? \"Geen resultaten\" : \"No results\",\n        }\n      });\n      node.utSlimSelect = ss;\n      node.classList.add(\"replacedby-ss\");\n\n      //FIXME we need an official API to register get/set for custom fields - even if we manage to fix slimselect itself\n      node[rfSymbol] = {\n        getValue() {\n          return node.value;\n        },\n        setValue(val: string | string[]) {\n          ss.setSelected(val);\n        }\n      };\n    }\n  });\n}\n\n//Add required text under webforms pages\ndompack.register(\".wh-form.wh-styledinput\", node => {\n  setTidLanguage(lang ?? 'en');\n  if (node.querySelector(\".wh-form__fieldgroup--required\"))\n    node.appendChild(<div class=\"wh-form__requirednote\"><p>{getTid('utwente_base:frontend.ws2016.js.starsrequired')}</p></div>);\n});\n\n// check if prefilled field is changed so styling can be updated if changed\ndompack.qSA(\".wh-form .wh-form__fieldgroup.ut-prefilled\").forEach(grp => {\n  const fields = dompack.qSA(grp, \"input:not([readonly]):not([disabled]),select:not([readonly]):not([disabled]),textarea:not([readonly]):not([disabled])\");\n  fields.forEach(inp => inp.addEventListener(\"change\", () => grp.classList.add(\"ut-prefilled--changed\")));\n});\n\n/* studylink trick: webform questions tagged check_studylink_number should verify to have exactly 9 positions */\ndompack.register<HTMLInputElement>(\".utwente-check-studylink-number input\", node => {\n  node.minLength = 7;\n  node.maxLength = 7;\n  node.type = \"tel\";\n  node.pattern = \"[0-9]{7}\";\n\n  forms.setupValidator(node, el => {\n    if (!el.value.match(/^[0-9]{7}$/))\n      return \"This is not a valid student number. To find your student number please check your Osiris application mail or login to the Osiris application system.\";\n  });\n});\n\ndompack.qSA<HTMLInputElement>(\".wh-form input[type=date]\").forEach(inp => {\n  // See: https://gitlab.webhare.com/utwente/utwente_base/-/work_items/2955\n  const dateFormat = getVisualDateFormat();\n  if (dateFormat.length > 7)\n    inp.after(<span class=\"wh-form__suffix\">({dateFormat})</span>);\n});\n\nfunction getVisualDateFormat() {\n  // Use a specific date: December 31, 2026\n  const testDate = new Date(2026, 11, 31);\n  const sample = new Intl.DateTimeFormat(undefined).format(testDate);\n\n  // Replace the numbers with letters to show the format\n  return sample\n    .replace('31', 'dd')\n    .replace('12', 'mm')\n    .replace('2026', 'yyyy')\n    .replace('26', 'yy'); // fallback for 2-digit years\n}\n\n// Limit all email fields to 100 chars: https://gitlab.webhare.com/utwente/utwente_base/-/issues/2059#note_167567\ndompack.register<HTMLInputElement>(`input[type=email]`, emailfield => {\n  if (emailfield.maxLength <= 0 || emailfield.maxLength > 100)\n    emailfield.maxLength = 100;\n});\n","export default class CssClasses {\n  public main: string\n  // Placeholder\n  public placeholder: string\n\n  // Values\n  public values: string\n  public single: string\n  public multiString: string\n  public max: string\n  public value: string\n  public valueText: string\n  public valueDelete: string\n  public valueOut: string\n\n  // Deselect\n  public deselect: string\n  public deselectPath: string // Not a class but whatever\n\n  // Arrow\n  public arrow: string\n  public arrowClose: string // Not a class but whatever\n  public arrowOpen: string // Not a class but whatever\n\n  // Content\n  public content: string\n  public contentOpen: string\n  public dirAbove: string\n  public dirBelow: string\n\n  // Search\n  public search: string\n  public searchHighlighter: string\n  public searching: string\n  public status: string\n  public addable: string\n  public addablePath: string // Not a class but whatever\n\n  // List optgroups/options\n  public list: string\n\n  // Optgroup\n  public optgroup: string\n  public optgroupLabel: string\n  public optgroupLabelText: string\n  public optgroupActions: string\n  public optgroupSelectAll: string // optgroup select all\n  public optgroupSelectAllBox: string // Not a class but whatever\n  public optgroupSelectAllCheck: string // Not a class but whatever\n  public optgroupClosable: string\n\n  // Option\n  public option: string\n  public optionDelete: string // Not a class but whatever\n  public highlighted: string\n\n  // Modal\n  public modalOverlay: string\n  public modalDialog: string\n  public modalTitle: string\n  public modalClose: string\n  public modalContent: string\n\n  // Misc\n  public mainOpen: string\n  public close: string\n  public selected: string\n  public error: string\n  public disabled: string\n  public hide: string\n\n  constructor(classes?: Partial<CssClasses>) {\n    if (!classes) {\n      classes = {}\n    }\n\n    let join = (a = '', b = '') => `${a} ${b}`.trim()\n\n    this.main = join('ss-main', classes.main)\n    this.placeholder = join('ss-placeholder', classes.placeholder)\n    this.values = join('ss-values', classes.values)\n    this.single = join('ss-single', classes.single)\n    this.multiString = join('ss-multi-string', classes.multiString)\n    this.max = join('ss-max', classes.max)\n    this.value = join('ss-value', classes.value)\n    this.valueText = join('ss-value-text', classes.valueText)\n    this.valueDelete = join('ss-value-delete', classes.valueDelete)\n    this.valueOut = join('ss-value-out', classes.valueOut)\n\n    this.deselect = join('ss-deselect', classes.deselect)\n    this.deselectPath = classes.deselectPath || 'M10,10 L90,90 M10,90 L90,10'\n    this.arrow = join('ss-arrow', classes.arrow)\n    this.arrowClose = classes.arrowClose || 'M10,30 L50,70 L90,30'\n    this.arrowOpen = classes.arrowOpen || 'M10,70 L50,30 L90,70'\n    this.content = join('ss-content', classes.content)\n    this.contentOpen = join('ss-open', classes.contentOpen)\n    this.dirAbove = join('ss-dir-above', classes.dirAbove)\n    this.dirBelow = join('ss-dir-below', classes.dirBelow)\n    this.search = join('ss-search', classes.search)\n    this.searchHighlighter = join(\n      'ss-search-highlight',\n      classes.searchHighlighter\n    )\n    this.searching = join('ss-searching', classes.searching)\n    this.status = join('ss-status', classes.status)\n    this.addable = join('ss-addable', classes.addable)\n    this.addablePath = classes.addablePath || 'M50,10 L50,90 M10,50 L90,50'\n    this.list = join('ss-list', classes.list)\n    this.optgroup = join('ss-optgroup', classes.optgroup)\n    this.optgroupLabel = join('ss-optgroup-label', classes.optgroupLabel)\n    this.optgroupLabelText = join(\n      'ss-optgroup-label-text',\n      classes.optgroupLabelText\n    )\n    this.optgroupActions = join('ss-optgroup-actions', classes.optgroupActions)\n    this.optgroupSelectAll = join('ss-selectall', classes.optgroupSelectAll)\n    this.optgroupSelectAllBox =\n      classes.optgroupSelectAllBox || 'M15,15 L85,15 L85,85 L15,85 Z'\n    this.optgroupSelectAllCheck =\n      classes.optgroupSelectAllCheck || 'M25,50 L42,68 L75,32'\n    this.optgroupClosable = join('ss-closable', classes.optgroupClosable)\n    this.option = join('ss-option', classes.option)\n    this.optionDelete = classes.optionDelete || 'M10,10 L90,90 M10,90 L90,10'\n    this.highlighted = join('ss-highlighted', classes.highlighted)\n    this.modalOverlay = join('ss-modal-overlay', classes.modalOverlay)\n    this.modalDialog = join('ss-modal-dialog', classes.modalDialog)\n    this.modalTitle = join('ss-modal-title', classes.modalTitle)\n    this.modalClose = join('ss-modal-close', classes.modalClose)\n    this.modalContent = join('ss-modal-content', classes.modalContent)\n    this.mainOpen = join('ss-open', classes.mainOpen)\n    this.close = join('ss-close', classes.close)\n    this.selected = join('ss-selected', classes.selected)\n    this.error = join('ss-error', classes.error)\n    this.disabled = join('ss-disabled', classes.disabled)\n    this.hide = join('ss-hide', classes.hide)\n  }\n\n  public getFirst(name: keyof Omit<CssClasses, 'getFirst'>): string {\n    return this[name].split(' ')[0]\n  }\n}\n","/**\n * Animation timing helpers.\n *\n * CSS still runs the motion — these keep lifecycle and DOM cleanup aligned with\n * --ss-animation-timing so we are not guessing with hardcoded setTimeout values.\n */\n\n/** Matches default --ss-animation-timing in slimselect.scss */\nconst DEFAULT_DURATION_MS = 200\n\n/** Extra ms added to CSS duration for transitionend/animationend safety-net timeouts. */\nexport const ANIMATION_TIMEOUT_BUFFER_MS = 50\n\n/** .ss-content open/close transitions — wait for both before lifecycle continues. */\nexport const CONTENT_PANEL_TRANSITION_PROPERTIES = [\n  'transform',\n  'opacity'\n] as const\n\n/** Parse a CSS time value (e.g. \"0.2s\", \"200ms\") into milliseconds. */\nexport function parseAnimationDuration(\n  cssValue: string,\n  fallback = DEFAULT_DURATION_MS\n): number {\n  const trimmed = cssValue.trim()\n  if (!trimmed) {\n    return fallback\n  }\n\n  if (trimmed.endsWith('ms')) {\n    const ms = parseFloat(trimmed)\n    return Number.isNaN(ms) ? fallback : ms\n  }\n\n  if (trimmed.endsWith('s')) {\n    const seconds = parseFloat(trimmed)\n    return Number.isNaN(seconds) ? fallback : seconds * 1000\n  }\n\n  const numeric = parseFloat(trimmed)\n  return Number.isNaN(numeric) ? fallback : numeric\n}\n\n/** Read --ss-animation-timing from an element's computed styles. */\nexport function getAnimationDuration(\n  element: HTMLElement,\n  fallback = DEFAULT_DURATION_MS\n): number {\n  const computedStyle = getComputedStyle(element)\n  const cssValue = computedStyle\n    .getPropertyValue('--ss-animation-timing')\n    .trim()\n  return parseAnimationDuration(cssValue, fallback)\n}\n\n/**\n * Safety-net timeout for animation waits.\n * Derived from --ss-animation-timing (+ buffer). An explicit settings.timeoutDelay\n * is treated as a minimum — never shorter than the CSS-driven duration.\n */\nexport function getAnimationTimeout(\n  element: HTMLElement,\n  userTimeout?: number,\n  fallback = DEFAULT_DURATION_MS\n): number {\n  const fromCss =\n    getAnimationDuration(element, fallback) + ANIMATION_TIMEOUT_BUFFER_MS\n\n  if (userTimeout === undefined) {\n    return fromCss\n  }\n\n  return Math.max(fromCss, userTimeout)\n}\n\n/** Respect user OS accessibility preference and jsdom (no matchMedia). */\nexport function prefersReducedMotion(): boolean {\n  if (\n    typeof window === 'undefined' ||\n    typeof window.matchMedia !== 'function'\n  ) {\n    return false\n  }\n\n  return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\nfunction normalizeTransitionProperties(\n  propertyNames?: string | readonly string[]\n): Set<string> | null {\n  if (propertyNames === undefined) {\n    return null\n  }\n\n  const list = Array.isArray(propertyNames) ? propertyNames : [propertyNames]\n  return new Set(list)\n}\n\n/**\n * Wait for CSS transition(s) to finish, with a timeout fallback.\n *\n * Pass a single property name to resolve on that transitionend, or an array to\n * wait until every listed property has fired (e.g. transform + opacity on .ss-content).\n * Optional AbortSignal cleans up listeners when lifecycle cancels a rapid toggle.\n */\nexport function waitForTransitionEnd(\n  element: HTMLElement,\n  propertyNames?: string | readonly string[],\n  timeoutMs = DEFAULT_DURATION_MS,\n  signal?: AbortSignal\n): Promise<void> {\n  if (prefersReducedMotion() || signal?.aborted) {\n    return Promise.resolve()\n  }\n\n  const pending = normalizeTransitionProperties(propertyNames)\n\n  return new Promise<void>((resolve) => {\n    let timer: ReturnType<typeof setTimeout> | null = null\n    let settled = false\n\n    const finish = () => {\n      if (settled) {\n        return\n      }\n      settled = true\n      element.removeEventListener('transitionend', onTransitionEnd)\n      signal?.removeEventListener('abort', onAbort)\n      if (timer) {\n        clearTimeout(timer)\n      }\n      resolve()\n    }\n\n    const onAbort = () => finish()\n\n    const onTransitionEnd = (event: TransitionEvent) => {\n      if (event.target !== element) {\n        return\n      }\n\n      if (pending) {\n        if (!pending.has(event.propertyName)) {\n          return\n        }\n        pending.delete(event.propertyName)\n        if (pending.size > 0) {\n          return\n        }\n      }\n\n      finish()\n    }\n\n    signal?.addEventListener('abort', onAbort, { once: true })\n    element.addEventListener('transitionend', onTransitionEnd)\n    timer = setTimeout(finish, timeoutMs)\n  })\n}\n\n/**\n * Wait for a CSS @keyframes animation to finish, with a timeout fallback.\n *\n * Used when removing multi-select value chips (.ss-value-out). jsdom does not\n * fire animationend, so the timeout wins in unit tests.\n */\nexport function waitForAnimationEnd(\n  element: HTMLElement,\n  animationName?: string,\n  timeoutMs = DEFAULT_DURATION_MS,\n  signal?: AbortSignal\n): Promise<void> {\n  if (prefersReducedMotion() || signal?.aborted) {\n    return Promise.resolve()\n  }\n\n  return new Promise<void>((resolve) => {\n    let timer: ReturnType<typeof setTimeout> | null = null\n    let settled = false\n\n    const finish = () => {\n      if (settled) {\n        return\n      }\n      settled = true\n      element.removeEventListener('animationend', onAnimationEnd)\n      signal?.removeEventListener('abort', onAbort)\n      if (timer) {\n        clearTimeout(timer)\n      }\n      resolve()\n    }\n\n    const onAbort = () => finish()\n\n    const onAnimationEnd = (event: AnimationEvent) => {\n      if (event.target !== element) {\n        return\n      }\n      if (animationName && event.animationName !== animationName) {\n        return\n      }\n      finish()\n    }\n\n    signal?.addEventListener('abort', onAbort, { once: true })\n    element.addEventListener('animationend', onAnimationEnd)\n    timer = setTimeout(finish, timeoutMs)\n  })\n}\n","import { generateID } from './helpers'\n\nexport type ModalSetting = 'off' | 'on' | 'mobile'\n\nexport const MODAL_MOBILE_BREAKPOINT = 768\n\nexport default class Settings {\n  public id: string = '' // Primary ID for the select\n  public style: string = '' // Style attribute from the select element\n  public class: string[] = [] // Class attribute from the select element\n\n  // Dynamic settings\n  public isMultiple: boolean = false\n  public isOpen: boolean = false\n  public isFullOpen: boolean = false\n\n  // Fields set from constructor\n  public disabled: boolean\n  public alwaysOpen: boolean\n  public showSearch: boolean\n  public focusSearch: boolean\n  public keepSearch: boolean\n  public ariaLabel: string\n  public searchPlaceholder: string\n  public searchText: string\n  public searchingText: string\n  public resultsText: string\n  public deselectText: string\n  public removeText: string\n  public searchHighlight: boolean\n  public closeOnSelect: boolean\n  public contentLocation: HTMLElement | null\n  public contentPosition: 'relative' | 'absolute' | 'fixed'\n  public contentWidth: string\n  public openPosition: 'auto' | 'up' | 'down'\n  public placeholderText: string\n  public allowDeselect: boolean\n  public removeLastSelectedOnBackspace: boolean\n  public hideSelected: boolean\n  public multiString: boolean\n  public keepOrder: boolean\n  public showOptionTooltips: boolean\n  public minSelected: number\n  public maxSelected: number\n  public timeoutDelay: number\n  public maxValuesShown: number\n  public maxValuesMessage: string\n  public addableText: string\n  public selectAll: boolean\n  public selectAllText: string\n  public unselectAllText: string\n  public modal: ModalSetting\n  public modalTitle: string\n\n  constructor(settings?: Partial<Settings>) {\n    if (!settings) {\n      settings = {}\n    }\n\n    this.id = 'ss-' + generateID()\n    this.style = settings.style || ''\n    this.class = settings.class || []\n\n    this.disabled = settings.disabled !== undefined ? settings.disabled : false\n    this.alwaysOpen = settings.alwaysOpen !== undefined ? settings.alwaysOpen : false\n    this.showSearch = settings.showSearch !== undefined ? settings.showSearch : true\n    this.focusSearch =\n      settings.focusSearch !== undefined\n        ? settings.focusSearch\n        : typeof window === 'undefined' || window.innerWidth >= MODAL_MOBILE_BREAKPOINT\n    this.keepSearch = settings.keepSearch !== undefined ? settings.keepSearch : false\n    this.ariaLabel = settings.ariaLabel || 'Combobox'\n    this.searchPlaceholder = settings.searchPlaceholder || 'Search...'\n    this.searchText = settings.searchText || 'No Results'\n    this.searchingText = settings.searchingText || 'Searching...'\n    this.resultsText = settings.resultsText || '{count} results available'\n    this.deselectText = settings.deselectText || 'Clear'\n    this.removeText = settings.removeText || 'Remove'\n    this.searchHighlight = settings.searchHighlight !== undefined ? settings.searchHighlight : false\n    this.closeOnSelect = settings.closeOnSelect !== undefined ? settings.closeOnSelect : true\n    this.contentLocation = settings.contentLocation || document.body\n    this.contentPosition = settings.contentPosition || 'absolute'\n    this.contentWidth = settings.contentWidth || ''\n    this.openPosition = settings.openPosition || 'auto' // options: auto, up, down\n    this.placeholderText = settings.placeholderText !== undefined ? settings.placeholderText : 'Select Value'\n    this.allowDeselect = settings.allowDeselect !== undefined ? settings.allowDeselect : false\n    this.removeLastSelectedOnBackspace =\n      settings.removeLastSelectedOnBackspace !== undefined ? settings.removeLastSelectedOnBackspace : true\n    this.hideSelected = settings.hideSelected !== undefined ? settings.hideSelected : false\n    this.multiString = settings.multiString !== undefined ? settings.multiString : false\n    this.keepOrder = settings.keepOrder !== undefined ? settings.keepOrder : false\n    this.showOptionTooltips = settings.showOptionTooltips !== undefined ? settings.showOptionTooltips : false\n    this.minSelected = settings.minSelected || 0\n    this.maxSelected = settings.maxSelected || 1000\n    this.timeoutDelay = settings.timeoutDelay || 200 // Default until SlimSelect reads --ss-animation-timing\n    this.maxValuesShown = settings.maxValuesShown || 20\n    this.maxValuesMessage = settings.maxValuesMessage || '{number} selected'\n    this.addableText = settings.addableText || 'Press \"Enter\" to add {value}'\n    this.selectAll = settings.selectAll !== undefined ? settings.selectAll : false\n    this.selectAllText = settings.selectAllText || 'Select All'\n    this.unselectAllText = settings.unselectAllText || 'Unselect All'\n    this.modal = settings.modal || 'mobile'\n    this.modalTitle = settings.modalTitle || ''\n  }\n}\n","import type { Optgroup, Option } from './store'\nimport { MODAL_MOBILE_BREAKPOINT, type ModalSetting } from './settings'\n\ntype DataItem = Partial<Option> | Partial<Optgroup>\n\n/** Copy option data attributes into a plain object (not a live DOMStringMap). */\nexport function copyOptionData(data?: { [key: string]: string } | DOMStringMap | null): { [key: string]: string } {\n  if (!data) {\n    return {}\n  }\n\n  const result: { [key: string]: string } = {}\n  for (const key of Object.keys(data)) {\n    const value = data[key]\n    if (value !== undefined) {\n      result[key] = value\n    }\n  }\n  return result\n}\n\n/** Label text only — excludes nested form controls (e.g. wrapped select options). */\nexport function getLabelElementText(label: HTMLLabelElement): string {\n  const clone = label.cloneNode(true) as HTMLLabelElement\n  clone.querySelectorAll('select, option, optgroup, textarea, input, button').forEach((el) => el.remove())\n\n  return clone.textContent?.replace(/\\s+/g, ' ').trim() || ''\n}\n\n/** Associated label text for a select, or its aria-label when no label is linked. */\nexport function getAssociatedLabelText(select: HTMLSelectElement): string {\n  if (select.labels && select.labels.length > 0) {\n    const texts = Array.from(select.labels).map(getLabelElementText).filter(Boolean)\n\n    if (texts.length > 0) {\n      return [...new Set(texts)].join(' ')\n    }\n  }\n\n  return select.getAttribute('aria-label')?.trim() || ''\n}\n\n// Generate an 8 character random string\nexport function generateID(): string {\n  return Math.random().toString(36).substring(2, 10)\n}\n\nexport function hasClassInTree(element: HTMLElement, className: string): HTMLElement | null {\n  function hasClass(e: HTMLElement, c: string) {\n    // If the element has the class return element\n    if (c && e && e.classList && e.classList.contains(c)) {\n      return e\n    }\n\n    // If the element has a dataset id of the class return element\n    if (c && e && e.dataset && e.dataset.id && e.dataset.id === className) {\n      return e\n    }\n\n    return null\n  }\n\n  function parentByClass(e: any, c: string): any {\n    if (!e || e === (document as any)) {\n      return null\n    } else if (hasClass(e, c)) {\n      return e\n    } else {\n      return parentByClass(e.parentNode, c)\n    }\n  }\n\n  return hasClass(element, className) || parentByClass(element, className)\n}\n\n// debounce will call the last requested function after the wait time\nexport function debounce<T extends (...args: any[]) => void>(func: T, wait = 50, immediate = false): () => void {\n  let timeout: any\n  return function (this: any, ...args: any[]): void {\n    const context = self\n    const later = () => {\n      timeout = null\n      if (!immediate) {\n        func.apply(context, args)\n      }\n    }\n    const callNow = immediate && !timeout\n    clearTimeout(timeout)\n    timeout = setTimeout(later, wait)\n    if (callNow) {\n      func.apply(context, args)\n    }\n  }\n}\n\nexport function isEqual(a: any, b: any): boolean {\n  return JSON.stringify(a) === JSON.stringify(b)\n}\n\n/** Compare selected id sets regardless of order (multi-select). */\nexport function selectedIdsEqual(a: string[], b: string[]): boolean {\n  if (a.length !== b.length) {\n    return false\n  }\n\n  const sortedA = [...a].sort()\n  const sortedB = [...b].sort()\n  return sortedA.every((id, i) => id === sortedB[i])\n}\n\nconst OPTION_FIELDS = [\n  'id',\n  'value',\n  'text',\n  'html',\n  'defaultSelected',\n  'selected',\n  'display',\n  'disabled',\n  'placeholder',\n  'class',\n  'style',\n  'mandatory'\n] as const\n\nfunction shallowRecordEqual(a: Record<string, string>, b: Record<string, string>): boolean {\n  const aKeys = Object.keys(a)\n  const bKeys = Object.keys(b)\n\n  if (aKeys.length !== bKeys.length) {\n    return false\n  }\n\n  for (const key of aKeys) {\n    if (a[key] !== b[key]) {\n      return false\n    }\n  }\n\n  return true\n}\n\nfunction normalizedOptionField(\n  option: Partial<Option>,\n  field: (typeof OPTION_FIELDS)[number]\n): string | boolean | Record<string, string> {\n  switch (field) {\n    case 'id':\n      return option.id || ''\n    case 'value':\n      return option.value === undefined ? option.text || '' : option.value || ''\n    case 'text':\n      return option.text || ''\n    case 'html':\n      return option.html || ''\n    case 'defaultSelected':\n      return option.defaultSelected ?? false\n    case 'selected':\n      return option.selected ?? false\n    case 'display':\n      return option.display ?? true\n    case 'disabled':\n      return option.disabled ?? false\n    case 'placeholder':\n      return option.placeholder ?? false\n    case 'class':\n      return option.class || ''\n    case 'style':\n      return option.style || ''\n    case 'mandatory':\n      return option.mandatory ?? false\n    default:\n      return option.data || {}\n  }\n}\n\nfunction isOptgroupItem(item: DataItem): item is Partial<Optgroup> {\n  return !!item && typeof item === 'object' && 'label' in item && 'options' in item\n}\n\nfunction optionStructureEqual(a: Partial<Option>, b: Partial<Option>): boolean {\n  for (const field of OPTION_FIELDS) {\n    const av = normalizedOptionField(a, field)\n    const bv = normalizedOptionField(b, field)\n\n    if (av !== bv) {\n      return false\n    }\n  }\n\n  return shallowRecordEqual(a.data || {}, b.data || {})\n}\n\nfunction optgroupStructureEqual(a: Partial<Optgroup>, b: Partial<Optgroup>): boolean {\n  const normalized = (optgroup: Partial<Optgroup>) => ({\n    id: optgroup.id || '',\n    label: optgroup.label || '',\n    selectAll: optgroup.selectAll ?? false,\n    closable: optgroup.closable || 'off'\n  })\n\n  const aNormalized = normalized(a)\n  const bNormalized = normalized(b)\n\n  if (\n    aNormalized.id !== bNormalized.id ||\n    aNormalized.label !== bNormalized.label ||\n    aNormalized.selectAll !== bNormalized.selectAll ||\n    aNormalized.closable !== bNormalized.closable\n  ) {\n    return false\n  }\n\n  const aOptions = a.options || []\n  const bOptions = b.options || []\n\n  if (aOptions.length !== bOptions.length) {\n    return false\n  }\n\n  for (let i = 0; i < aOptions.length; i++) {\n    if (!optionStructureEqual(aOptions[i], bOptions[i])) {\n      return false\n    }\n  }\n\n  return true\n}\n\n/** Compare option/optgroup arrays without JSON.stringify. */\nexport function dataStructureEqual(a: DataItem[], b: DataItem[]): boolean {\n  if (a === b) {\n    return true\n  }\n\n  if (a.length !== b.length) {\n    return false\n  }\n\n  for (let i = 0; i < a.length; i++) {\n    const aItem = a[i]\n    const bItem = b[i]\n    const aIsOptgroup = isOptgroupItem(aItem)\n    const bIsOptgroup = isOptgroupItem(bItem)\n\n    if (aIsOptgroup !== bIsOptgroup) {\n      return false\n    }\n\n    if (aIsOptgroup) {\n      if (!optgroupStructureEqual(aItem, bItem)) {\n        return false\n      }\n      continue\n    }\n\n    if (!optionStructureEqual(aItem as Partial<Option>, bItem as Partial<Option>)) {\n      return false\n    }\n  }\n\n  return true\n}\n\nexport function kebabCase(str: string): string {\n  const result = str.replace(/[A-Z\\u00C0-\\u00D6\\u00D8-\\u00DE]/g, (match) => '-' + match.toLowerCase())\n  return str[0] === str[0].toUpperCase() ? result.substring(1) : result\n}\n\nexport function shouldUseModalView(\n  modal: ModalSetting,\n  viewportWidth: number = typeof window !== 'undefined' ? window.innerWidth : MODAL_MOBILE_BREAKPOINT\n): boolean {\n  if (modal === 'on') {\n    return true\n  }\n  if (modal === 'mobile') {\n    return viewportWidth < MODAL_MOBILE_BREAKPOINT\n  }\n  return false\n}\n","/**\n * Global window/document listeners extracted from SlimSelect.\n *\n * Keeps index.ts thinner and makes listener attach/detach testable in isolation.\n * Document click is separate from attach() so it only runs while dropdown is\n * fully open (wired via Lifecycle onOpenReady / onCloseReady).\n */\n\nimport { debounce, hasClassInTree } from './helpers'\n\nexport interface GlobalEventHandlers {\n  onDocumentClick: (e: Event) => void\n  onWindowResize: () => void\n  onWindowScroll: () => void\n  onVisibilityChange: () => void\n}\n\nexport default class GlobalEvents {\n  private attached = false\n\n  constructor(private handlers: GlobalEventHandlers) {}\n\n  /** Attach long-lived listeners for the SlimSelect instance lifetime. */\n  public attach(options: { listenScroll: boolean }): void {\n    if (this.attached) {\n      return\n    }\n\n    this.attached = true\n    window.addEventListener('resize', this.resizeHandler, false)\n\n    // Scroll listener only needed when openPosition is auto (reposition on scroll)\n    if (options.listenScroll) {\n      window.addEventListener('scroll', this.scrollHandler, false)\n    }\n\n    document.addEventListener('visibilitychange', this.visibilityHandler)\n  }\n\n  /** Attached after open animation completes — closes on outside click. */\n  public attachDocumentClick(): void {\n    document.addEventListener('click', this.handlers.onDocumentClick)\n  }\n\n  public detachDocumentClick(): void {\n    document.removeEventListener('click', this.handlers.onDocumentClick)\n  }\n\n  public detach(options: { listenScroll: boolean }): void {\n    if (!this.attached) {\n      return\n    }\n\n    this.attached = false\n    this.detachDocumentClick()\n    window.removeEventListener('resize', this.resizeHandler, false)\n\n    if (options.listenScroll) {\n      window.removeEventListener('scroll', this.scrollHandler, false)\n    }\n\n    document.removeEventListener('visibilitychange', this.visibilityHandler)\n  }\n\n  private resizeHandler = debounce(() => {\n    this.handlers.onWindowResize()\n  })\n\n  private scrollHandler = debounce(() => {\n    this.handlers.onWindowScroll()\n  })\n\n  private visibilityHandler = () => {\n    this.handlers.onVisibilityChange()\n  }\n}\n\nexport { hasClassInTree }\n","/**\n * Open/close state machine for SlimSelect.\n *\n * Replaces scattered openTimeout/closeTimeout in index.ts with a single flow:\n *   closed → opening → open → closing → closed\n *\n * Maps to settings consumers expect:\n *   - isOpen: true during opening + open\n *   - isFullOpen: true only in open state (after animation / afterOpen)\n *\n * Lifecycle waits for render.waitForAnimation() before firing afterOpen/afterClose.\n * When no animation waiter is provided, falls back to settings.timeoutDelay.\n *\n * Close flow: beforeClose (veto) → onClose (sync DOM/settings) → animation → afterClose\n */\n\nimport type { CloseInfo } from './render'\n\nexport type LifecycleState = 'closed' | 'opening' | 'open' | 'closing'\n\nexport interface LifecycleHandlers {\n  beforeOpen?: () => void\n  afterOpen?: () => void\n  /** Return false to cancel close before any DOM changes. */\n  beforeClose?: (info: CloseInfo) => boolean | void\n  /** Sync close work — render, focus, settings. Runs after beforeClose approves. */\n  onClose?: (info: CloseInfo) => void\n  afterClose?: () => void\n  /** Fires when fully open — used to attach document click-outside listener. */\n  onOpenReady?: () => void\n  /** Fires when fully closed — used to detach document click-outside listener. */\n  onCloseReady?: () => void\n}\n\nexport interface LifecycleOptions {\n  /** Fallback when waitForAnimation is not provided (no CSS element yet). */\n  timeoutDelay: number\n  waitForAnimation?: (\n    phase: 'open' | 'close',\n    signal?: AbortSignal\n  ) => Promise<void>\n}\n\nexport default class Lifecycle {\n  public state: LifecycleState = 'closed'\n  private pendingTimer: ReturnType<typeof setTimeout> | null = null\n  /** Resolvers for in-flight waitForPhase promises — cancelled on rapid toggle. */\n  private waitResolvers: Array<() => void> = []\n  /** Incremented on cancelPending(); stale async completions check this before firing handlers. */\n  private generation = 0\n  private animationAbort: AbortController | null = null\n\n  constructor(\n    private handlers: LifecycleHandlers,\n    private options: LifecycleOptions\n  ) {}\n\n  public get isOpen(): boolean {\n    return this.state === 'opening' || this.state === 'open'\n  }\n\n  public get isFullOpen(): boolean {\n    return this.state === 'open'\n  }\n\n  public async requestOpen(): Promise<void> {\n    if (this.state === 'opening' || this.state === 'open') {\n      return\n    }\n\n    this.cancelPending()\n    const gen = ++this.generation\n\n    if (this.handlers.beforeOpen) {\n      this.handlers.beforeOpen()\n    }\n\n    this.state = 'opening'\n    await this.waitForPhase('open', gen)\n\n    // User closed before open animation finished (issue #397)\n    if (gen !== this.generation) {\n      if (this.state === 'opening') {\n        this.state = 'closed'\n      }\n      return\n    }\n\n    this.state = 'open'\n\n    if (this.handlers.afterOpen) {\n      this.handlers.afterOpen()\n    }\n\n    if (this.handlers.onOpenReady) {\n      this.handlers.onOpenReady()\n    }\n  }\n\n  public async requestClose(\n    info: CloseInfo = { source: 'api', selectionChanged: false }\n  ): Promise<boolean> {\n    if (this.state === 'closed' || this.state === 'closing') {\n      return false\n    }\n\n    if (this.handlers.beforeClose && this.handlers.beforeClose(info) === false) {\n      return false\n    }\n\n    this.cancelPending()\n    const gen = ++this.generation\n\n    if (this.handlers.onClose) {\n      this.handlers.onClose(info)\n    }\n\n    this.state = 'closing'\n    await this.waitForPhase('close', gen)\n\n    if (gen !== this.generation) {\n      return false\n    }\n\n    this.state = 'closed'\n\n    if (this.handlers.afterClose) {\n      this.handlers.afterClose()\n    }\n\n    if (this.handlers.onCloseReady) {\n      this.handlers.onCloseReady()\n    }\n\n    return true\n  }\n\n  /** Cancel timers and resolve waiting phases — called when open/close race each other. */\n  public cancelPending(): void {\n    this.generation++\n    this.animationAbort?.abort()\n    this.animationAbort = null\n    if (this.pendingTimer) {\n      clearTimeout(this.pendingTimer)\n      this.pendingTimer = null\n    }\n    const resolvers = this.waitResolvers.splice(0)\n    for (const resolve of resolvers) {\n      resolve()\n    }\n  }\n\n  public destroy(): void {\n    this.cancelPending()\n    this.state = 'closed'\n  }\n\n  /**\n   * Wait for the CSS animation to finish (or timeoutDelay when no waiter exists).\n   * cancelPending() resolves the wait early for rapid open/close toggles.\n   */\n  private waitForPhase(\n    phase: 'open' | 'close',\n    gen: number\n  ): Promise<void> {\n    return new Promise<void>((resolve) => {\n      let settled = false\n      const finish = () => {\n        if (settled) {\n          return\n        }\n        settled = true\n        const idx = this.waitResolvers.indexOf(finish)\n        if (idx !== -1) {\n          this.waitResolvers.splice(idx, 1)\n        }\n        resolve()\n      }\n\n      this.waitResolvers.push(finish)\n\n      if (this.options.waitForAnimation) {\n        const controller = new AbortController()\n        this.animationAbort = controller\n        void this.options\n          .waitForAnimation(phase, controller.signal)\n          .catch(() => undefined)\n          .finally(() => {\n            if (this.animationAbort === controller) {\n              this.animationAbort = null\n            }\n            finish()\n          })\n      } else {\n        this.pendingTimer = setTimeout(() => {\n          this.pendingTimer = null\n          finish()\n        }, this.options.timeoutDelay)\n      }\n    }).then(() => {\n      if (gen !== this.generation) {\n        return\n      }\n    })\n  }\n}\n","import { copyOptionData, generateID } from './helpers'\n\nexport class Option {\n  id: string\n  value: string\n  text: string\n  html: string\n  defaultSelected: boolean\n  selected: boolean\n  display: boolean\n  disabled: boolean\n  placeholder: boolean\n  class: string\n  style: string\n  data: { [key: string]: string }\n  mandatory: boolean\n\n  constructor(option: Partial<Option>) {\n    this.id = !option.id || option.id === '' ? generateID() : option.id\n    this.value =\n      option.value === undefined ? option.text || '' : option.value || ''\n    this.text = option.text || ''\n    this.html = option.html || ''\n    this.defaultSelected =\n      option.defaultSelected !== undefined ? option.defaultSelected : false\n    this.selected = option.selected !== undefined ? option.selected : false\n    this.display = option.display !== undefined ? option.display : true\n    this.disabled = option.disabled !== undefined ? option.disabled : false\n    this.mandatory = option.mandatory !== undefined ? option.mandatory : false\n    this.placeholder =\n      option.placeholder !== undefined ? option.placeholder : false\n    this.class = option.class || ''\n    this.style = option.style || ''\n    this.data = copyOptionData(option.data)\n  }\n}\nexport class Optgroup {\n  public id: string\n  public label: string\n  public selectAll: boolean\n  public closable: 'off' | 'open' | 'close'\n  public options: Partial<Option>[]\n\n  constructor(optgroup: Partial<Optgroup>) {\n    this.id = !optgroup.id || optgroup.id === '' ? generateID() : optgroup.id\n    this.label = optgroup.label || ''\n    this.selectAll =\n      optgroup.selectAll === undefined ? false : optgroup.selectAll\n    this.closable = optgroup.closable || 'off'\n\n    // If options exist, loop through options and create new option class\n    // and set the options to the optgroup options field\n    this.options = []\n    if (optgroup.options) {\n      for (const o of optgroup.options) {\n        this.options.push(new Option(o))\n      }\n    }\n  }\n}\n\nexport default class Store {\n  private selectType: 'single' | 'multiple' = 'single'\n\n  // Main data set, never null\n  private data: (Option | Optgroup)[] = []\n  private selectedOrder: string[] = []\n  /** Baseline option list — restored when search is cleared (API results are temporary). */\n  private catalog: (Option | Optgroup)[] | null = null\n\n  constructor(\n    type: 'single' | 'multiple',\n    data: (Partial<Option> | Partial<Optgroup>)[]\n  ) {\n    this.selectType = type\n    this.setData(data)\n    this.snapshotCatalog()\n  }\n\n  // Validate DataArrayPartial\n  public validateDataArray(\n    data: (Partial<Option> | Partial<Optgroup>)[]\n  ): Error | null {\n    if (!Array.isArray(data)) {\n      return new Error('Data must be an array')\n    }\n\n    // Loop through each data object\n    for (let dataObj of data) {\n      if (!dataObj) continue\n\n      // Optgroup\n      if (dataObj instanceof Optgroup || 'label' in dataObj) {\n        if (!('label' in dataObj)) {\n          return new Error('Optgroup must have a label')\n        }\n\n        if ('options' in dataObj && dataObj.options) {\n          for (let option of dataObj.options) {\n            const validationError = this.validateOption(option)\n            if (validationError) {\n              return validationError\n            }\n          }\n        }\n      } else if (dataObj instanceof Option || 'text' in dataObj) {\n        const validationError = this.validateOption(dataObj)\n        if (validationError) {\n          return validationError\n        }\n      } else {\n        return new Error('Data object must be a valid optgroup or option')\n      }\n    }\n\n    return null\n  }\n\n  // Validate Option\n  public validateOption(option: Partial<Option>): Error | null {\n    if (!('text' in option)) {\n      return new Error('Option must have a text')\n    }\n\n    return null\n  }\n\n  public partialToFullData(\n    data: (Partial<Option> | Partial<Optgroup>)[]\n  ): (Option | Optgroup)[] {\n    let dataFinal: (Option | Optgroup)[] = []\n    data.forEach((dataObj) => {\n      if (!dataObj) return\n\n      // Optgroup\n      if (dataObj instanceof Optgroup || 'label' in dataObj) {\n        let optOptions: Option[] = []\n        if ('options' in dataObj && dataObj.options) {\n          dataObj.options.forEach((option: Partial<Option>) => {\n            optOptions.push(new Option(option))\n          })\n        }\n\n        if (optOptions.length > 0) {\n          dataFinal.push(new Optgroup(dataObj as Partial<Optgroup>))\n        }\n      }\n\n      // Option\n      if (dataObj instanceof Option || 'text' in dataObj) {\n        dataFinal.push(new Option(dataObj as Partial<Option>))\n      }\n    })\n\n    return dataFinal\n  }\n\n  /** Snapshot the current data as the catalog baseline (not called for API search results). */\n  public snapshotCatalog(): void {\n    this.catalog = this.cloneData(this.data)\n  }\n\n  /** Catalog baseline used when clearing search. */\n  public getCatalogData(): (Option | Optgroup)[] {\n    return this.cloneData(this.catalog ?? this.data)\n  }\n\n  private cloneData(data: (Option | Optgroup)[]): (Option | Optgroup)[] {\n    return data.map((item) => {\n      if (item instanceof Optgroup) {\n        return new Optgroup({\n          id: item.id,\n          label: item.label,\n          selectAll: item.selectAll,\n          closable: item.closable,\n          options: item.options.map((option) =>\n            new Option(option instanceof Option ? { ...option } : option)\n          )\n        })\n      }\n\n      return new Option({ ...(item as Option) })\n    })\n  }\n\n  private optionMatchesSelected(\n    candidate: Option,\n    selected: Option\n  ): boolean {\n    if (candidate.id === selected.id) {\n      return true\n    }\n\n    return (\n      selected.value !== '' &&\n      candidate.value !== '' &&\n      candidate.value === selected.value\n    )\n  }\n\n  private findOptionInData(\n    data: (Option | Optgroup)[],\n    selected: Option\n  ): Option | null {\n    for (const item of data) {\n      if (item instanceof Option) {\n        if (this.optionMatchesSelected(item, selected)) {\n          return item\n        }\n        continue\n      }\n\n      for (const option of item.options as Option[]) {\n        if (this.optionMatchesSelected(option, selected)) {\n          return option\n        }\n      }\n    }\n\n    return null\n  }\n\n  public setData(\n    data: (Partial<Option> | Partial<Optgroup>)[],\n    preserveSelected: boolean = false\n  ) {\n    // Convert new data to full data array\n    const newData = this.partialToFullData(data)\n\n    let selectedOptionsBeforeUpdate: Option[] = []\n\n    if (preserveSelected) {\n      // Get currently selected options before updating data\n      selectedOptionsBeforeUpdate = this.getSelectedOptions()\n\n      // Check which selected options are missing from new data\n      const missingSelected: Option[] = []\n      selectedOptionsBeforeUpdate.forEach((selectedOption) => {\n        if (!this.findOptionInData(newData, selectedOption)) {\n          missingSelected.push(selectedOption)\n        }\n      })\n\n      // Add missing selected options to the beginning of the data\n      this.data = [...missingSelected, ...newData]\n\n      const allowEmptySelection =\n        this.selectType === 'single' &&\n        selectedOptionsBeforeUpdate.length === 0\n      const selectedIds = selectedOptionsBeforeUpdate.map((selected) => {\n        const match = this.findOptionInData(this.data, selected)\n        return match ? match.id : selected.id\n      })\n\n      this.setSelectedBy('id', selectedIds, allowEmptySelection)\n    } else {\n      this.data = newData\n    }\n\n    // Run this.data through setSelected by value\n    // to set the selected property and clean any wrong selected\n    if (!preserveSelected && this.selectType === 'single') {\n      this.setSelectedBy('id', this.getSelected(), false)\n    }\n  }\n\n  // Get data will return all the data (cloned by default for public API safety)\n  public getData(clone = true): Option[] | Optgroup[] {\n    return this.filter(null, true, clone) as Option[] | Optgroup[]\n  }\n\n  // Get data options will return the data as a flat array of just options\n  public getDataOptions(clone = true): Option[] {\n    return this.filter(null, false, clone) as Option[]\n  }\n\n  public addOption(option: Partial<Option>, addToStart: boolean = false) {\n    if (addToStart) {\n      let data = [new Option(option)] as (Option | Optgroup)[]\n      this.setData(data.concat(this.getData()))\n    } else {\n      this.setData(this.getData().concat(new Option(option)))\n    }\n  }\n\n  // Pass in an array of id that will loop through\n  // each option and set the selected property to true\n  // but also clean selected by determining selectType\n  // When allowEmptySelection is true (e.g. after search with no prior selection), single select will not auto-select the first option\n  public setSelectedBy(\n    selectedType: 'id' | 'value',\n    selectedValues: string[],\n    allowEmptySelection: boolean = false\n  ) {\n    let firstOption: Partial<Option> | null = null\n    let hasSelected = false\n    const selectedObjects: Partial<Option>[] = []\n\n    for (let dataObj of this.data) {\n      // Optgroup\n      if (dataObj instanceof Optgroup) {\n        for (let option of dataObj.options as Partial<Option>[]) {\n          if (!firstOption) {\n            firstOption = option\n          }\n\n          let optionValue = option[selectedType] || ''\n          option.selected = hasSelected\n            ? false\n            : selectedValues.includes(optionValue)\n\n          // If the option is selected, set hasSelected to true\n          // for single based selects\n          if (option.selected) {\n            selectedObjects.push(option)\n\n            if (this.selectType === 'single') {\n              hasSelected = true\n            }\n          }\n        }\n      }\n\n      // Option\n      if (dataObj instanceof Option) {\n        if (!firstOption) {\n          firstOption = dataObj\n        }\n\n        dataObj.selected = hasSelected\n          ? false\n          : selectedValues.includes(dataObj[selectedType])\n\n        // If the option is selected, set hasSelected to true\n        // for single based selects\n        if (dataObj.selected) {\n          selectedObjects.push(dataObj)\n\n          if (this.selectType === 'single') {\n            hasSelected = true\n          }\n        }\n      }\n    }\n\n    // If no options are selected, select the first option (unless allowEmptySelection, e.g. after search with no selection)\n    if (\n      this.selectType === 'single' &&\n      firstOption &&\n      !hasSelected &&\n      !allowEmptySelection\n    ) {\n      firstOption.selected = true\n      selectedObjects.push(firstOption)\n    }\n\n    // Put together a list of selected ids in the order of the selected values\n    const selectedIds = selectedValues.map((value) => {\n      return (\n        selectedObjects.find((option) => option[selectedType] === value)?.id ||\n        ''\n      )\n    })\n\n    this.selectedOrder = selectedIds\n  }\n\n  public getSelected(): string[] {\n    return this.getSelectedOptions().map((option) => option.id)\n  }\n\n  public getSelectedValues(): string[] {\n    return this.getSelectedOptions().map((option) => option.value)\n  }\n\n  public getSelectedOptions(): Option[] {\n    const selected: Option[] = []\n\n    for (const dataObj of this.data) {\n      if (dataObj instanceof Optgroup) {\n        for (const option of dataObj.options as Option[]) {\n          if (option.selected) {\n            selected.push(option)\n          }\n        }\n      } else if (dataObj.selected) {\n        selected.push(dataObj)\n      }\n    }\n\n    return selected\n  }\n\n  public getOptgroupByID(id: string): Optgroup | null {\n    // Loop through each data object\n    // and if optgroup is found, return it\n    for (let dataObj of this.data) {\n      if (dataObj instanceof Optgroup && dataObj.id === id) {\n        return dataObj\n      }\n    }\n\n    return null\n  }\n\n  public getOptionByID(id: string): Option | null {\n    for (const dataObj of this.data) {\n      if (dataObj instanceof Optgroup) {\n        for (const option of dataObj.options as Option[]) {\n          if (option.id === id) {\n            return option\n          }\n        }\n      } else if (dataObj.id === id) {\n        return dataObj\n      }\n    }\n\n    return null\n  }\n\n  public getSelectType(): string {\n    return this.selectType\n  }\n\n  public getFirstOption(): Option | null {\n    let option: Option | null = null\n    for (let dataObj of this.data) {\n      if (dataObj instanceof Optgroup) {\n        option = dataObj.options[0] as Option\n      } else if (dataObj instanceof Option) {\n        option = dataObj\n      }\n\n      if (option) {\n        break\n      }\n    }\n    return option\n  }\n\n  // Take in search string and return filtered list of values\n  public search(\n    search: string,\n    searchFilter: (opt: Option, search: string) => boolean\n  ): (Option | Optgroup)[] {\n    search = search.trim()\n\n    // If search is empty, return all data\n    if (search === '') {\n      return this.getData(false)\n    }\n\n    // Run filter with search function (read-only view for render)\n    return this.filter((opt: Option): boolean => {\n      return searchFilter(opt, search)\n    }, true, false)\n  }\n\n  private createOptgroupView(\n    source: Optgroup,\n    options: Option[]\n  ): Optgroup {\n    const view = new Optgroup({\n      id: source.id,\n      label: source.label,\n      selectAll: source.selectAll,\n      closable: source.closable,\n      options: []\n    })\n    view.options = options\n    return view\n  }\n\n  // Filter takes in a function that will be used to filter the data\n  // This will also keep optgroups of sub options meet the filter requirements\n  public filter(\n    filter: { (opt: Option): boolean } | null,\n    includeOptgroup: boolean,\n    clone = true\n  ): (Option | Optgroup)[] {\n    const dataSearch: (Option | Optgroup)[] = []\n    this.data.forEach((dataObj: Option | Optgroup) => {\n      // Optgroup\n      if (dataObj instanceof Optgroup) {\n        let optOptions: Option[] = []\n        let options = dataObj.options as Option[]\n        options.forEach((option: Option) => {\n          if (!filter || filter(option as Option)) {\n            // If you dont want to include optgroups\n            // just push to the dataSearch array\n            if (!includeOptgroup) {\n              dataSearch.push(clone ? new Option(option) : option)\n            } else {\n              optOptions.push(clone ? new Option(option) : option)\n            }\n          }\n        })\n\n        // If we pushed any options to the optOptions array\n        // push the optgroup to the dataSearch array\n        if (optOptions.length > 0) {\n          if (clone) {\n            let optgroup = new Optgroup(dataObj)\n            optgroup.options = optOptions\n            dataSearch.push(optgroup)\n          } else {\n            dataSearch.push(this.createOptgroupView(dataObj, optOptions))\n          }\n        }\n      }\n\n      // Option\n      if (dataObj instanceof Option) {\n        if (!filter || filter(dataObj)) {\n          dataSearch.push(clone ? new Option(dataObj) : dataObj)\n        }\n      }\n    })\n\n    return dataSearch\n  }\n\n  // Take in an array of options and reoder them based upon the selected order\n  public selectedOrderOptions(options: Option[]): Option[] {\n    const newOrder: Option[] = []\n    this.selectedOrder.forEach((id) => {\n      const option = options.find((opt) => opt.id === id)\n      if (option) {\n        newOrder.push(option)\n      }\n    })\n\n    // add any remaining options that were not in the selected order\n    options.forEach((option) => {\n      let isIn = false\n      newOrder.forEach((selectedOption) => {\n        if (option.id === selectedOption.id) {\n          isIn = true\n\n          return\n        }\n      })\n\n      if (!isIn) {\n        newOrder.push(option)\n      }\n    })\n\n    return newOrder\n  }\n}\n","import { debounce, shouldUseModalView } from './helpers'\nimport {\n  CONTENT_PANEL_TRANSITION_PROPERTIES,\n  getAnimationDuration,\n  getAnimationTimeout,\n  waitForAnimationEnd,\n  waitForTransitionEnd\n} from './animations'\nimport Settings from './settings'\nimport Store, { Optgroup, Option } from './store'\nimport CssClasses from './classes'\n\n/** How long typed characters stay one prefix before the next key starts a new search. */\nconst TYPEAHEAD_RESET_MS = 1000\n\nexport type CloseSource = 'select' | 'deselect' | 'outside' | 'toggle' | 'escape' | 'tab' | 'modal' | 'api'\n\nexport interface CloseInfo {\n  source: CloseSource\n  option?: Option\n  selectionChanged: boolean\n}\n\nexport interface Callbacks {\n  open: () => void\n  close: (info?: CloseInfo) => void\n  addable?: (\n    value: string\n  ) => Promise<Partial<Option> | string> | Partial<Option> | string | false | undefined | null | Error\n  setSelected: (value: string | string[], runAfterChange: boolean) => void\n  addOption: (option: Option) => void\n  search: (search: string) => void\n  /** Internal reset that must not fire the consumer search event. */\n  clearSearch: () => void\n  beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void\n  afterChange?: (newVal: Option[]) => void\n}\n\nexport interface Main {\n  main: HTMLDivElement\n  values: HTMLDivElement\n  deselect: {\n    main: HTMLDivElement\n    svg: SVGSVGElement\n    path: SVGPathElement\n  }\n  arrow: {\n    main: SVGSVGElement\n    path: SVGPathElement\n  }\n}\n\nexport interface Content {\n  main: HTMLDivElement\n  search: Search\n  status: HTMLDivElement\n  list: HTMLDivElement\n}\n\nexport interface Search {\n  main: HTMLDivElement\n  input: HTMLInputElement\n  selectAll?: HTMLDivElement\n  addable?: {\n    main: HTMLDivElement\n    svg: SVGSVGElement\n    path: SVGPathElement\n  }\n}\n\nexport interface ModalElements {\n  overlay: HTMLDivElement\n  dialog: HTMLDivElement\n  closeButton: HTMLButtonElement\n  title: HTMLDivElement | null\n}\n\nexport default class Render {\n  public settings: Settings\n  public store: Store\n  public callbacks: Callbacks\n\n  // Used to compute the range selection\n  private lastSelectedOption: Option | null\n  private lastRenderedOptions: Option[]\n  private optionsListIsFullData = false\n  private lastSearchFilterTerm = ''\n\n  // Timeout tracking for cleanup\n\n  // Elements\n  public main: Main\n  public content: Content\n\n  // Classes\n  public classes: CssClasses\n\n  private positionObserver: ResizeObserver | null = null\n  private positionObserverRaf = 0\n  private lastObservedContentHeight = -1\n  private overflowShiftRaf = 0\n\n  /** Characters typed in quick succession when search is off. */\n  private typeaheadQuery = ''\n  private typeaheadTimer: ReturnType<typeof setTimeout> | null = null\n\n  private modalElements: ModalElements | null = null\n  private modalSessionActive: boolean | null = null\n  private bodyScrollLocked = false\n  private savedBodyOverflow = ''\n\n  constructor(settings: Required<Settings>, classes: Required<CssClasses>, store: Store, callbacks: Callbacks) {\n    this.store = store\n    this.settings = settings\n    this.classes = classes\n    this.callbacks = callbacks\n    this.lastSelectedOption = null\n    this.lastRenderedOptions = []\n\n    this.main = this.mainDiv()\n    this.content = this.contentDiv()\n\n    // Add classes and styles to main/content\n    this.updateClassStyles()\n    this.updateAriaAttributes()\n\n    // Position content off-screen initially to prevent scrollbars\n    // This must be after updateClassStyles() since it removes all style attributes\n    // The main element isn't in the DOM yet, so getBoundingClientRect() would return zeros\n    // Once opened, moveContent() will position it correctly\n    if (this.settings.contentPosition !== 'relative') {\n      this.content.main.style.top = '-9999px'\n      this.content.main.style.left = '-9999px'\n      this.content.main.style.margin = '0'\n      this.content.main.style.width = 'auto'\n    }\n\n    // Add content to the content location settings\n    if (this.settings.contentLocation) {\n      this.settings.contentLocation.appendChild(this.content.main)\n    }\n\n    if (this.settings.modal !== 'off' && !this.settings.alwaysOpen) {\n      this.modalElements = this.createModalElements()\n      document.body.appendChild(this.modalElements.overlay)\n    }\n  }\n\n  // Helper method to add classes that may contain spaces\n  // Splits by spaces and adds each class individually to avoid DOMException\n  private requestClose(source: CloseSource, options?: { option?: Option; selectionChanged?: boolean }): void {\n    this.callbacks.close({\n      source,\n      option: options?.option,\n      selectionChanged: options?.selectionChanged ?? false\n    })\n  }\n\n  private selectionChanged(before: Option[], after: Option[]): boolean {\n    if (before.length !== after.length) {\n      return true\n    }\n\n    const beforeIds = before.map((o) => o.id).sort()\n    const afterIds = after.map((o) => o.id).sort()\n\n    return beforeIds.some((id, index) => id !== afterIds[index])\n  }\n\n  private closeOnSingleSelectReclick(storeOption: Option): void {\n    if (this.settings.closeOnSelect) {\n      this.requestClose('select', {\n        option: storeOption,\n        selectionChanged: false\n      })\n    }\n  }\n\n  public addClasses(element: HTMLElement | SVGElement, classValue: string): void {\n    if (!classValue || classValue.trim() === '') {\n      return\n    }\n    const classes = classValue.split(' ').filter((c) => c.trim() !== '')\n    for (const cls of classes) {\n      element.classList.add(cls.trim())\n    }\n  }\n\n  // Helper method to remove classes that may contain spaces\n  public removeClasses(element: HTMLElement | SVGElement, classValue: string): void {\n    if (!classValue || classValue.trim() === '') {\n      return\n    }\n    const classes = classValue.split(' ').filter((c) => c.trim() !== '')\n    for (const cls of classes) {\n      element.classList.remove(cls.trim())\n    }\n  }\n\n  // Remove disabled classes\n  public enable(): void {\n    // Remove disabled class\n    this.removeClasses(this.main.main, this.classes.disabled)\n    this.main.main.setAttribute('aria-disabled', 'false')\n\n    // Set search input to \"enabled\"\n    this.content.search.input.disabled = false\n  }\n\n  // Set disabled classes\n  public disable(): void {\n    // Add disabled class\n    this.addClasses(this.main.main, this.classes.disabled)\n    this.main.main.setAttribute('aria-disabled', 'true')\n\n    // Set search input to disabled\n    this.content.search.input.disabled = true\n  }\n\n  public open(): void {\n    this.main.arrow.path.setAttribute('d', this.classes.arrowOpen)\n    this.main.main.setAttribute('aria-expanded', 'true')\n\n    const useModal = this.resolveModalView()\n\n    if (!useModal) {\n      const isAbove = this.settings.openPosition === 'up'\n      const dirClass = isAbove ? this.classes.dirAbove : this.classes.dirBelow\n      this.addClasses(this.main.main, dirClass)\n      this.addClasses(this.content.main, dirClass)\n    }\n\n    // Add open class to content to trigger open animation\n    this.addClasses(this.content.main, this.classes.contentOpen)\n\n    // Make search visible to screen readers when opened\n    this.content.search.input.removeAttribute('aria-hidden')\n\n    if (useModal) {\n      this.showModal()\n    } else {\n      this.moveContent()\n    }\n\n    // Move to last selected option\n    const selectedOptions = this.store.getSelectedOptions()\n    if (selectedOptions.length) {\n      const selectedId = selectedOptions[selectedOptions.length - 1].id\n      const selectedOption = this.content.list.querySelector('[data-id=\"' + selectedId + '\"]') as HTMLElement\n      if (selectedOption) {\n        this.ensureElementInView(this.content.list, selectedOption)\n      }\n    }\n  }\n\n  public isModalViewActive(): boolean {\n    return this.modalSessionActive === true\n  }\n\n  private resolveModalView(): boolean {\n    if (this.settings.alwaysOpen || this.settings.modal === 'off' || !this.modalElements) {\n      return false\n    }\n\n    if (this.modalSessionActive === null) {\n      this.modalSessionActive = shouldUseModalView(this.settings.modal)\n    }\n\n    return this.modalSessionActive\n  }\n\n  private createModalElements(): ModalElements {\n    const overlay = document.createElement('div')\n    this.addClasses(overlay, this.classes.modalOverlay)\n    this.addClasses(overlay, this.classes.hide)\n    overlay.dataset.id = this.settings.id\n\n    const dialog = document.createElement('div')\n    this.addClasses(dialog, this.classes.modalDialog)\n    dialog.setAttribute('role', 'dialog')\n    dialog.setAttribute('aria-modal', 'true')\n\n    let title: HTMLDivElement | null = null\n    if (this.settings.modalTitle) {\n      title = document.createElement('div')\n      this.addClasses(title, this.classes.modalTitle)\n      title.id = `${this.settings.id}-modal-title`\n      title.textContent = this.settings.modalTitle\n      dialog.setAttribute('aria-labelledby', title.id)\n    } else {\n      dialog.setAttribute('aria-label', this.settings.ariaLabel)\n    }\n\n    const closeButton = document.createElement('button')\n    closeButton.type = 'button'\n    this.addClasses(closeButton, this.classes.modalClose)\n    closeButton.setAttribute('aria-label', 'Close')\n    closeButton.onclick = (e: Event) => {\n      e.stopPropagation()\n      this.requestClose('modal')\n    }\n\n    const closeSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n    closeSvg.setAttribute('viewBox', '0 0 100 100')\n    const closePath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n    closePath.setAttribute('d', this.classes.deselectPath)\n    closeSvg.appendChild(closePath)\n    closeButton.appendChild(closeSvg)\n\n    overlay.onclick = (e: Event) => {\n      if (e.target === overlay) {\n        this.requestClose('modal')\n      }\n    }\n\n    if (title) {\n      dialog.appendChild(title)\n    }\n    overlay.appendChild(dialog)\n\n    return { overlay, dialog, closeButton, title }\n  }\n\n  private showModal(): void {\n    if (!this.modalElements) {\n      return\n    }\n\n    this.modalElements.dialog.appendChild(this.content.main)\n    this.addClasses(this.content.main, this.classes.modalContent)\n    this.content.main.appendChild(this.modalElements.closeButton)\n    this.content.main.style.top = ''\n    this.content.main.style.left = ''\n    this.content.main.style.margin = ''\n    this.content.main.style.width = ''\n\n    this.removeClasses(this.modalElements.overlay, this.classes.hide)\n    requestAnimationFrame(() => {\n      if (!this.modalElements) {\n        return\n      }\n      this.addClasses(this.modalElements.overlay, this.classes.contentOpen)\n    })\n\n    this.lockBodyScroll()\n  }\n\n  private lockBodyScroll(): void {\n    if (this.bodyScrollLocked) {\n      return\n    }\n\n    this.savedBodyOverflow = document.body.style.overflow\n    document.body.style.overflow = 'hidden'\n    this.bodyScrollLocked = true\n  }\n\n  private unlockBodyScroll(): void {\n    if (!this.bodyScrollLocked) {\n      return\n    }\n\n    document.body.style.overflow = this.savedBodyOverflow\n    this.bodyScrollLocked = false\n    this.savedBodyOverflow = ''\n  }\n\n  private restoreContentOffscreen(): void {\n    if (this.settings.contentLocation) {\n      this.settings.contentLocation.appendChild(this.content.main)\n    }\n\n    if (this.settings.contentPosition !== 'relative') {\n      this.content.main.style.top = '-9999px'\n      this.content.main.style.left = '-9999px'\n      this.content.main.style.margin = '0'\n      this.content.main.style.width = 'auto'\n    }\n  }\n\n  /** Tear down modal shell after close animation completes. */\n  public finalizeModalClose(): void {\n    if (!this.modalElements) {\n      return\n    }\n\n    if (this.content.main.parentElement !== this.modalElements.dialog) {\n      return\n    }\n\n    this.addClasses(this.modalElements.overlay, this.classes.hide)\n    this.removeClasses(this.modalElements.overlay, this.classes.contentOpen)\n    this.removeClasses(this.content.main, this.classes.modalContent)\n    this.modalElements.closeButton.remove()\n    this.restoreContentOffscreen()\n    this.unlockBodyScroll()\n  }\n\n  /** Used by Lifecycle — wait for .ss-content CSS transition before afterOpen/afterClose. */\n  public waitForAnimation(phase: 'open' | 'close', signal?: AbortSignal): Promise<void> {\n    const timeout = getAnimationTimeout(this.content.main, this.settings.timeoutDelay)\n    return waitForTransitionEnd(this.content.main, CONTENT_PANEL_TRANSITION_PROPERTIES, timeout, signal)\n  }\n\n  public close(): void {\n    this.main.main.setAttribute('aria-expanded', 'false')\n    this.main.arrow.path.setAttribute('d', this.classes.arrowClose)\n\n    const wasModal = this.modalSessionActive === true\n\n    // Remove open class from content to trigger close animation\n    // Direction on content persists for transform-origin during the panel animation\n    this.removeClasses(this.content.main, this.classes.contentOpen)\n\n    if (!wasModal) {\n      this.removeClasses(this.main.main, this.classes.dirAbove)\n      this.removeClasses(this.main.main, this.classes.dirBelow)\n    }\n\n    if (wasModal && this.modalElements) {\n      this.removeClasses(this.modalElements.overlay, this.classes.contentOpen)\n    }\n\n    this.modalSessionActive = null\n\n    // Hide search from screen readers when closed\n    this.content.search.input.setAttribute('aria-hidden', 'true')\n\n    // Clear active descendant when closed\n    this.main.main.removeAttribute('aria-activedescendant')\n    this.clearValueChipHighlight()\n  }\n\n  /** Remove open-direction classes after close animation (lifecycle afterClose). */\n  public clearDirectionClasses(): void {\n    this.removeClasses(this.main.main, this.classes.dirAbove)\n    this.removeClasses(this.main.main, this.classes.dirBelow)\n    this.removeClasses(this.content.main, this.classes.dirAbove)\n    this.removeClasses(this.content.main, this.classes.dirBelow)\n  }\n\n  public updateClassStyles(): void {\n    // Clear all classes and styles\n    this.main.main.className = ''\n    this.main.main.removeAttribute('style')\n    this.content.main.className = ''\n    this.content.main.removeAttribute('style')\n\n    // Make sure main/content has its base class\n    this.addClasses(this.main.main, this.classes.main)\n    this.addClasses(this.content.main, this.classes.content)\n\n    // Add styles\n    if (this.settings.style !== '') {\n      this.main.main.style.cssText = this.settings.style\n      this.content.main.style.cssText = this.settings.style\n    }\n\n    // Add classes from the native select to both main and content\n    if (this.settings.class.length) {\n      for (const c of this.settings.class) {\n        if (c.trim() !== '') {\n          this.main.main.classList.add(c.trim())\n          this.content.main.classList.add(c.trim())\n        }\n      }\n    }\n\n    // Misc classes\n    // Add content position class\n    if (this.settings.contentPosition === 'relative' || this.settings.contentPosition === 'fixed') {\n      this.content.main.classList.add('ss-' + this.settings.contentPosition)\n    }\n  }\n\n  /**\n   * Mirror the native select's title attribute onto the rendered control so\n   * browser tooltips keep working after the select is swapped for the div UI.\n   * Tooltips are inherited by descendants, so setting it on ss-main covers\n   * ss-values and ss-single as well.\n   */\n  public updateTitle(title: string | null): void {\n    if (title) {\n      this.main.main.setAttribute('title', title)\n    } else {\n      this.main.main.removeAttribute('title')\n    }\n  }\n\n  public updateAriaAttributes() {\n    const listboxId = this.content.list.id\n\n    // Main combobox\n    this.main.main.role = 'combobox'\n    this.main.main.setAttribute('aria-haspopup', 'listbox')\n    this.main.main.setAttribute('aria-controls', listboxId)\n    this.main.main.setAttribute('aria-expanded', 'false')\n\n    this.content.list.setAttribute('role', 'listbox')\n    this.content.list.setAttribute('aria-label', this.settings.ariaLabel + ' listbox')\n\n    // Add aria-multiselectable for multiple selects\n    if (this.settings.isMultiple) {\n      this.content.list.setAttribute('aria-multiselectable', 'true')\n    }\n\n    // Search input should also control the listbox\n    this.content.search.input.setAttribute('aria-controls', listboxId)\n  }\n\n  public mainDiv(): Main {\n    // Create main container\n    const main = document.createElement('div')\n\n    // Add id to data-id\n    main.dataset.id = this.settings.id\n    // main.id = this.settings.id+'-main' // Remove for now as it is not needed and add duplicate id errors\n\n    // Add label\n    main.setAttribute('aria-label', this.settings.ariaLabel)\n\n    // Set tabable to allow tabbing to the element\n    main.tabIndex = 0\n\n    // Deal with keyboard events on the main div.\n    // With search off, letters and digits jump to a matching option.\n    // With search on, printable keys still open so focus can move to the field.\n    main.onkeydown = (e: KeyboardEvent): boolean => {\n      if (this.isTypeaheadKey(e)) {\n        e.preventDefault()\n        this.callbacks.open()\n        this.typeahead(e.key)\n        return false\n      }\n\n      switch (e.key) {\n        case 'ArrowUp':\n        case 'ArrowDown':\n          this.clearTypeahead()\n          this.callbacks.open()\n          e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up')\n          return false\n        case 'Tab':\n          this.clearTypeahead()\n          this.requestClose('tab')\n          return true // Continue doing normal tabbing\n        case 'Enter':\n        case ' ':\n          this.clearTypeahead()\n          this.callbacks.open()\n          const highlighted = this.content.list.querySelector(\n            '.' + this.classes.getFirst('highlighted')\n          ) as HTMLDivElement\n          if (highlighted) {\n            highlighted.click()\n          }\n          return false\n        case 'Escape':\n          this.clearTypeahead()\n          this.requestClose('escape')\n          return false\n      }\n\n      // Check if they type a-z, A-Z and 0-9\n      if (e.key.length === 1) {\n        this.callbacks.open()\n      }\n\n      return true\n    }\n\n    // Add onclick for main div\n    main.onclick = (e: Event): void => {\n      // Dont do anything if disabled\n      if (this.settings.disabled) {\n        return\n      }\n\n      this.settings.isOpen ? this.requestClose('toggle') : this.callbacks.open()\n    }\n\n    // Add values\n    const values = document.createElement('div')\n    this.addClasses(values, this.classes.values)\n    main.appendChild(values)\n\n    // Add deselect\n    const deselect = document.createElement('div')\n    this.addClasses(deselect, this.classes.deselect)\n    deselect.setAttribute('role', 'button')\n    deselect.setAttribute('aria-label', this.settings.deselectText)\n    deselect.setAttribute('tabindex', '0')\n\n    // Check if deselect is to be shown or not\n    const selectedOptions = this.store?.getSelectedOptions()\n    if (\n      !this.settings.allowDeselect ||\n      (this.settings.isMultiple && selectedOptions && selectedOptions.length <= 0) ||\n      this.isAtMinSelected()\n    ) {\n      this.addClasses(deselect, this.classes.hide)\n    } else {\n      this.removeClasses(deselect, this.classes.hide)\n    }\n\n    // Add deselect onclick event\n    deselect.onclick = (e: Event) => {\n      e.stopPropagation()\n\n      // Dont do anything if disabled\n      if (this.settings.disabled) {\n        return\n      }\n\n      if (this.settings.isMultiple && this.isAtMinSelected()) {\n        return\n      }\n\n      // By Default we will delete\n      let shouldDelete = true\n      const before = this.store.getSelectedOptions()\n      let after = [] as Option[]\n      let newSelectedIds: string[] | string = ''\n\n      if (this.settings.isMultiple) {\n        const min = this.settings.minSelected\n        const currentIds = this.store.getSelected()\n\n        if (min > 0 && currentIds.length > min) {\n          newSelectedIds = this.getMinimumSelectionIds()\n          after = before.filter((o) => newSelectedIds.includes(o.id))\n        } else if (min <= 0) {\n          newSelectedIds = []\n        } else {\n          return\n        }\n      }\n\n      // Add beforeChange callback\n      if (this.callbacks.beforeChange) {\n        shouldDelete = this.callbacks.beforeChange(after, before) === true\n      }\n\n      if (shouldDelete) {\n        if (this.settings.isMultiple) {\n          this.callbacks.setSelected(newSelectedIds, false)\n          this.updateDeselectAll()\n        } else {\n          // Get first option and set it as selected\n          const firstOption = this.store.getFirstOption()\n          const id = firstOption ? firstOption.id : ''\n\n          this.callbacks.setSelected(id, false)\n        }\n\n        // Check if we need to close the dropdown\n        if (this.settings.closeOnSelect) {\n          this.requestClose('deselect', { selectionChanged: true })\n        }\n\n        // Run afterChange callback\n        if (this.callbacks.afterChange) {\n          this.callbacks.afterChange(this.store.getSelectedOptions())\n        }\n      }\n    }\n\n    deselect.onkeydown = (e: KeyboardEvent) => {\n      if (e.key === 'Enter' || e.key === ' ') {\n        e.preventDefault()\n        deselect.click()\n      }\n    }\n\n    // Add deselect svg\n    const deselectSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n    deselectSvg.setAttribute('viewBox', '0 0 100 100')\n    const deselectPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n    deselectPath.setAttribute('d', this.classes.deselectPath)\n    deselectSvg.appendChild(deselectPath)\n    deselect.appendChild(deselectSvg)\n    main.appendChild(deselect)\n\n    // Add arrow\n    const arrow = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n    this.addClasses(arrow, this.classes.arrow)\n    arrow.setAttribute('viewBox', '0 0 100 100')\n    const arrowPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n    arrowPath.setAttribute('d', this.classes.arrowClose)\n    if (this.settings.alwaysOpen) {\n      this.addClasses(arrow, this.classes.hide)\n    }\n    arrow.appendChild(arrowPath)\n    main.appendChild(arrow)\n\n    return {\n      main: main,\n      values: values,\n      deselect: {\n        main: deselect,\n        svg: deselectSvg,\n        path: deselectPath\n      },\n      arrow: {\n        main: arrow,\n        path: arrowPath\n      }\n    }\n  }\n\n  public mainFocus(eventType: string | null): void {\n    // Trigger focus but dont scroll to it\n    // Need for prevent refocus the element if event is not keyboard event.\n    // For example if event is mouse click or tachpad click this condition prevent refocus on element\n    // because click by mouse change focus position and not need return focus to element.\n    if (eventType !== 'click') {\n      this.main.main.focus({ preventScroll: true })\n    }\n  }\n\n  public placeholder(): HTMLDivElement {\n    // Figure out if there is a placeholder option\n    const placeholderOption = this.store.filter((o) => o.placeholder, false, false) as Option[]\n\n    // If there is a placeholder option use that\n    // If placeholder has an html value, use that\n    // If placeholder has a text, use that\n    // If nothing is set, use the placeholder text\n    let placeholderText = this.settings.placeholderText\n    if (placeholderOption.length) {\n      if (placeholderOption[0].html !== '') {\n        placeholderText = placeholderOption[0].html\n      } else if (placeholderOption[0].text !== '') {\n        placeholderText = placeholderOption[0].text\n      }\n    }\n\n    // Create placeholder div\n    const placeholder = document.createElement('div')\n    this.addClasses(placeholder, this.classes.placeholder)\n    placeholder.innerHTML = placeholderText\n    return placeholder\n  }\n\n  // Get selected values and append to multiSelected values container\n  // and remove those who shouldnt exist\n  public renderValues(): void {\n    // If single select set placeholder or selected value\n    if (!this.settings.isMultiple) {\n      this.renderSingleValue()\n      return\n    }\n\n    this.renderMultipleValues()\n\n    this.updateDeselectAll()\n  }\n\n  private renderSingleValue(): void {\n    const selected = this.store.filter(\n      (o: Option): boolean => {\n        return o.selected && !o.placeholder\n      },\n      false,\n      false\n    ) as Option[]\n    const selectedSingle = selected.length > 0 ? selected[0] : null\n\n    // If nothing is seleected use settings placeholder text\n    if (!selectedSingle) {\n      this.main.values.innerHTML = this.placeholder().outerHTML\n    } else {\n      // Create single value container\n      const singleValue = document.createElement('div')\n      this.addClasses(singleValue, this.classes.single)\n      if (selectedSingle.html) {\n        singleValue.innerHTML = selectedSingle.html\n      } else {\n        singleValue.innerText = selectedSingle.text\n      }\n\n      // If there is a selected value, set a single div\n      this.main.values.innerHTML = singleValue.outerHTML\n    }\n\n    // If allowDeselect is false or selected value is empty just hide deselect\n    if (!this.settings.allowDeselect || !selected.length) {\n      this.addClasses(this.main.deselect.main, this.classes.hide)\n    } else {\n      this.removeClasses(this.main.deselect.main, this.classes.hide)\n    }\n  }\n\n  private renderMultipleValues(): void {\n    // Get various pieces of data\n    let currentNodes = this.main.values.childNodes as NodeListOf<HTMLDivElement>\n    let selectedOptions = this.store.filter(\n      (opt: Option) => {\n        // Only grab options that are selected and display is true\n        return opt.selected && opt.display\n      },\n      false,\n      false\n    ) as Option[]\n\n    // If selectedOptions is empty set placeholder\n    if (selectedOptions.length === 0) {\n      this.main.values.innerHTML = this.placeholder().outerHTML\n      return\n    } else {\n      // If there is a placeholder, remove it\n      const placeholder = this.main.values.querySelector('.' + this.classes.getFirst('placeholder'))\n      if (placeholder) {\n        placeholder.remove()\n      }\n    }\n\n    // If multiString is enabled, render a single text element containing the\n    // selected values joined by commas instead of individual value pills.\n    // CSS truncates the text with an ellipsis when it exceeds the container width.\n    if (this.settings.multiString) {\n      let commaOptions = selectedOptions\n      if (this.settings.keepOrder) {\n        commaOptions = this.store.selectedOrderOptions(commaOptions)\n      }\n\n      const commaValue = document.createElement('div')\n      this.addClasses(commaValue, this.classes.multiString)\n      commaValue.textContent = commaOptions.map((o: Option) => o.text).join(', ')\n\n      if (this.settings.showOptionTooltips) {\n        commaValue.setAttribute('title', commaValue.textContent)\n      }\n\n      this.main.values.innerHTML = commaValue.outerHTML\n      return\n    }\n\n    // If selectedOptions is greater than maxItems, set maxValuesMessage\n    if (selectedOptions.length > this.settings.maxValuesShown) {\n      // Creating the element that shows the number of selected items\n      const singleValue = document.createElement('div')\n      this.addClasses(singleValue, this.classes.max)\n      singleValue.textContent = this.settings.maxValuesMessage.replace('{number}', selectedOptions.length.toString())\n\n      // If there is a selected value, set a single div\n      this.main.values.innerHTML = singleValue.outerHTML\n      return\n    } else {\n      // If there is a message, remove it\n      const maxValuesMessage = this.main.values.querySelector('.' + this.classes.getFirst('max'))\n      if (maxValuesMessage) {\n        maxValuesMessage.remove()\n      }\n    }\n\n    // Lets check for data selected order\n    if (this.settings.keepOrder) {\n      selectedOptions = this.store.selectedOrderOptions(selectedOptions)\n    }\n\n    // Loop through currentNodes and only include ones that are not in selectedIDs\n    let removeNodes: HTMLDivElement[] = []\n    for (let i = 0; i < currentNodes.length; i++) {\n      const node = currentNodes[i]\n      const id = node.getAttribute('data-id')\n      if (id) {\n        // Check if id is in selectedOptions\n        const found = selectedOptions.filter((opt: Option) => {\n          return opt.id === id\n        }, false)\n\n        // If not found, add to removeNodes\n        if (!found.length) {\n          removeNodes.push(node)\n        }\n      }\n    }\n\n    const animationDuration = getAnimationTimeout(this.content.main, this.settings.timeoutDelay)\n\n    // Loop through and remove\n    for (const n of removeNodes) {\n      this.addClasses(n, this.classes.valueOut)\n      void waitForAnimationEnd(n, 'ss-valueOut', animationDuration).then(() => {\n        if (this.main.values.hasChildNodes() && this.main.values.contains(n)) {\n          this.main.values.removeChild(n)\n        }\n      })\n    }\n\n    // Add values that dont currently exist\n    currentNodes = this.main.values.childNodes as NodeListOf<HTMLDivElement>\n    for (let d = 0; d < selectedOptions.length; d++) {\n      let shouldAdd = true\n      for (let i = 0; i < currentNodes.length; i++) {\n        if (selectedOptions[d].id === String(currentNodes[i].dataset.id)) {\n          shouldAdd = false\n        }\n      }\n\n      // If shouldAdd, insertAdjacentElement it to the values container in the order of the selectedOptions\n      if (shouldAdd) {\n        // If keepOrder is true, we will just append it to the end\n        if (this.settings.keepOrder) {\n          this.main.values.appendChild(this.multipleValue(selectedOptions[d]))\n        } else {\n          // else we will insert it in the order of the selectedOptions\n          if (currentNodes.length === 0) {\n            this.main.values.appendChild(this.multipleValue(selectedOptions[d]))\n          } else if (d === 0) {\n            this.main.values.insertBefore(this.multipleValue(selectedOptions[d]), currentNodes[d])\n          } else {\n            currentNodes[d - 1].insertAdjacentElement('afterend', this.multipleValue(selectedOptions[d]))\n          }\n        }\n      }\n    }\n\n    this.updateMultipleValueDeleteVisibility()\n  }\n\n  private isAtMinSelected(): boolean {\n    return (\n      this.settings.isMultiple &&\n      this.settings.minSelected > 0 &&\n      this.store.getSelectedOptions().length <= this.settings.minSelected\n    )\n  }\n\n  private getMinimumSelectionIds(): string[] {\n    let selected = this.store.getSelectedOptions()\n    if (this.settings.keepOrder) {\n      selected = this.store.selectedOrderOptions(selected)\n    }\n\n    return selected.slice(0, this.settings.minSelected).map((option) => option.id)\n  }\n\n  private getValueChips(): HTMLDivElement[] {\n    if (!this.settings.isMultiple || this.settings.multiString) {\n      return []\n    }\n\n    const chips = Array.from(\n      this.main.values.querySelectorAll('.' + this.classes.getFirst('value'))\n    ) as HTMLDivElement[]\n\n    return chips.filter((chip) => {\n      if (chip.classList.contains(this.classes.getFirst('valueOut'))) {\n        return false\n      }\n\n      const deleteButton = chip.querySelector('.' + this.classes.getFirst('valueDelete')) as HTMLElement | null\n\n      return !!deleteButton && !deleteButton.classList.contains(this.classes.getFirst('hide'))\n    })\n  }\n\n  private getHighlightedValueChip(): HTMLDivElement | null {\n    return this.getValueChips().find((chip) => chip.classList.contains(this.classes.getFirst('highlighted'))) ?? null\n  }\n\n  private clearValueChipHighlight(): void {\n    for (const chip of Array.from(\n      this.main.values.querySelectorAll('.' + this.classes.getFirst('value'))\n    ) as HTMLDivElement[]) {\n      this.removeClasses(chip, this.classes.highlighted)\n    }\n  }\n\n  private highlightValueChip(chip: HTMLDivElement | null): void {\n    this.clearValueChipHighlight()\n    if (chip) {\n      this.addClasses(chip, this.classes.highlighted)\n    }\n  }\n\n  /** Returns true when Left/Right were used to move among selected value chips. */\n  private navigateValueChips(dir: 'left' | 'right'): boolean {\n    const chips = this.getValueChips()\n    if (chips.length === 0) {\n      return false\n    }\n\n    const current = this.getHighlightedValueChip()\n    const index = current ? chips.indexOf(current) : -1\n\n    if (dir === 'left') {\n      if (index === -1) {\n        this.highlightValueChip(chips[chips.length - 1])\n      } else if (index > 0) {\n        this.highlightValueChip(chips[index - 1])\n      }\n      return true\n    }\n\n    if (index === -1) {\n      return false\n    }\n\n    if (index < chips.length - 1) {\n      this.highlightValueChip(chips[index + 1])\n    } else {\n      this.clearValueChipHighlight()\n    }\n\n    return true\n  }\n\n  /**\n   * Remove the highlighted chip, or the last chip when none is highlighted.\n   * Returns true when a delete was triggered.\n   */\n  private deleteValueChip(onlyHighlighted = false): boolean {\n    const chips = this.getValueChips()\n    if (chips.length === 0) {\n      return false\n    }\n\n    const current = this.getHighlightedValueChip()\n    if (onlyHighlighted && !current) {\n      return false\n    }\n\n    const target = current ?? chips[chips.length - 1]\n    const deleteButton = target.querySelector('.' + this.classes.getFirst('valueDelete')) as HTMLElement | null\n    if (!deleteButton) {\n      return false\n    }\n\n    const index = chips.indexOf(target)\n    const next = current ? (chips[index - 1] ?? chips[index + 1] ?? null) : null\n\n    deleteButton.click()\n\n    if (next && next !== target && this.main.values.contains(next)) {\n      this.highlightValueChip(next)\n    } else {\n      this.clearValueChipHighlight()\n    }\n\n    return true\n  }\n\n  private updateMultipleValueDeleteVisibility(): void {\n    if (!this.settings.isMultiple || this.settings.multiString) {\n      return\n    }\n\n    const canRemove = !this.isAtMinSelected()\n    const deleteButtons = this.main.values.querySelectorAll('.' + this.classes.getFirst('valueDelete'))\n\n    for (const deleteButton of deleteButtons) {\n      if (canRemove) {\n        this.removeClasses(deleteButton as HTMLElement, this.classes.hide)\n      } else {\n        this.addClasses(deleteButton as HTMLElement, this.classes.hide)\n      }\n    }\n  }\n\n  public multipleValue(option: Option): HTMLDivElement {\n    const value = document.createElement('div')\n    this.addClasses(value, this.classes.value)\n    value.dataset.id = option.id\n\n    const text = document.createElement('div')\n    this.addClasses(text, this.classes.valueText)\n    text.textContent = option.text // For multiple values always use text\n    value.appendChild(text)\n\n    // Only add deletion if the option is not mandatory\n    if (!option.mandatory) {\n      // Create delete div element\n      const deleteDiv = document.createElement('div')\n      this.addClasses(deleteDiv, this.classes.valueDelete)\n      deleteDiv.setAttribute('tabindex', '0') // Make the div focusable for tab navigation\n      deleteDiv.setAttribute('role', 'button')\n      deleteDiv.setAttribute('aria-label', `${this.settings.removeText} ${option.text}`)\n\n      if (this.isAtMinSelected()) {\n        this.addClasses(deleteDiv, this.classes.hide)\n      }\n\n      // Add delete onclick event\n      deleteDiv.onclick = (e: Event) => {\n        e.preventDefault()\n        e.stopPropagation()\n\n        // Dont do anything if disabled\n        if (this.settings.disabled) {\n          return\n        }\n\n        // By Default we will delete\n        let shouldDelete = true\n        const before = this.store.getSelectedOptions()\n        const after = before.filter((o) => {\n          return o.selected && o.id !== option.id\n        }, true)\n\n        // Check if minSelected is set and if after length so, return\n        if (this.settings.minSelected && after.length < this.settings.minSelected) {\n          return\n        }\n\n        // If there is a beforeDeselect function run it\n        if (this.callbacks.beforeChange) {\n          shouldDelete = this.callbacks.beforeChange(after, before) === true\n        }\n\n        if (shouldDelete) {\n          // Loop through after and append ids to a variable called selected\n          let selectedIds: string[] = []\n          for (const o of after) {\n            if (o instanceof Optgroup) {\n              for (const c of o.options) {\n                if (c.id) {\n                  selectedIds.push(c.id)\n                }\n              }\n            }\n\n            if (o instanceof Option) {\n              selectedIds.push(o.id)\n            }\n          }\n          this.callbacks.setSelected(selectedIds, false)\n\n          // Check if we need to close the dropdown\n          if (this.settings.closeOnSelect) {\n            this.requestClose('deselect', { selectionChanged: true })\n          }\n\n          // Run afterChange callback\n          if (this.callbacks.afterChange) {\n            this.callbacks.afterChange(after)\n          }\n\n          this.updateDeselectAll()\n          this.updateMultipleValueDeleteVisibility()\n        }\n      }\n\n      // Add delete svg\n      const deleteSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n      deleteSvg.setAttribute('viewBox', '0 0 100 100')\n      const deletePath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n      deletePath.setAttribute('d', this.classes.optionDelete)\n      deleteSvg.appendChild(deletePath)\n      deleteDiv.appendChild(deleteSvg)\n\n      value.appendChild(deleteDiv)\n\n      // Add keydown event listener for keyboard navigation (Enter key)\n      deleteDiv.onkeydown = (e) => {\n        if (e.key === 'Enter') {\n          deleteDiv.click() // Trigger the click event when Enter is pressed\n        }\n      }\n    }\n\n    return value\n  }\n\n  public contentDiv(): Content {\n    const main = document.createElement('div')\n\n    // Add id to data-id\n    main.dataset.id = this.settings.id\n    // main.id = this.settings.id + '-content' // Remove for now as it is not needed and add duplicate id errors\n\n    // Add search\n    const search = this.searchDiv()\n    main.appendChild(search.main)\n\n    // Screen reader announcements for search result updates\n    const status = document.createElement('div')\n    this.addClasses(status, this.classes.status)\n    status.setAttribute('aria-live', 'polite')\n    status.setAttribute('aria-atomic', 'true')\n    status.setAttribute('role', 'status')\n    main.appendChild(status)\n\n    // Add list\n    const list = this.listDiv()\n    main.appendChild(list)\n\n    return {\n      main: main,\n      search: search,\n      status: status,\n      list: list\n    }\n  }\n\n  private announce(message: string): void {\n    if (!this.settings.showSearch) {\n      return\n    }\n\n    this.content.status.textContent = message\n  }\n\n  /**\n   * After list height changes (search, results, optgroup toggle), keep an\n   * already-open \"above\" panel attached. Does not re-run auto up/down so\n   * filtering cannot flip the list while the user is typing.\n   */\n  private repositionOpenContent(): void {\n    if (!this.settings.isOpen || this.isModalViewActive()) {\n      return\n    }\n\n    if (this.settings.contentPosition === 'relative') {\n      return\n    }\n\n    if (!this.content.main.classList.contains(this.classes.getFirst('dirAbove'))) {\n      return\n    }\n\n    this.moveContentAbove()\n  }\n\n  public moveContent(): void {\n    if (this.isModalViewActive()) {\n      return\n    }\n\n    if (this.settings.contentPosition === 'relative') {\n      this.moveContentBelow()\n      return\n    }\n\n    if (this.settings.openPosition === 'down') {\n      this.moveContentBelow()\n      return\n    } else if (this.settings.openPosition === 'up') {\n      this.moveContentAbove()\n      return\n    }\n\n    if (this.putContent() === 'up') {\n      this.moveContentAbove()\n    } else {\n      this.moveContentBelow()\n    }\n  }\n\n  /** Track trigger/content layout changes and reposition the dropdown panel. */\n  public startPositionTracking(): void {\n    if (this.settings.contentPosition !== 'absolute' || this.isModalViewActive()) {\n      return\n    }\n\n    this.stopPositionTracking()\n\n    if (typeof ResizeObserver === 'undefined') {\n      return\n    }\n\n    this.lastObservedContentHeight = -1\n    this.positionObserver = new ResizeObserver((entries) => {\n      if (!this.settings.isOpen) {\n        return\n      }\n\n      let contentHeightChanged = false\n      let layoutChanged = false\n\n      for (const entry of entries) {\n        if (entry.target === this.content.main) {\n          const height = entry.contentRect.height\n          if (height !== this.lastObservedContentHeight) {\n            this.lastObservedContentHeight = height\n            contentHeightChanged = true\n          }\n        } else {\n          layoutChanged = true\n        }\n      }\n\n      if (!contentHeightChanged && !layoutChanged) {\n        return\n      }\n\n      cancelAnimationFrame(this.positionObserverRaf)\n      this.positionObserverRaf = requestAnimationFrame(() => {\n        // Trigger/ancestor changes may need auto up/down. Content height\n        // changes should keep the current direction so search does not flip.\n        if (layoutChanged) {\n          this.moveContent()\n        } else {\n          this.repositionOpenContent()\n        }\n      })\n    })\n\n    this.observePositionTargets()\n  }\n\n  public stopPositionTracking(): void {\n    cancelAnimationFrame(this.positionObserverRaf)\n    this.positionObserver?.disconnect()\n    this.positionObserver = null\n    this.lastObservedContentHeight = -1\n    this.cancelOverflowShift()\n  }\n\n  private observePositionTargets(): void {\n    if (!this.positionObserver) {\n      return\n    }\n\n    const observed = new Set<Element>()\n    const observe = (el: Element | null): void => {\n      if (!el || observed.has(el)) {\n        return\n      }\n\n      observed.add(el)\n      this.positionObserver!.observe(el)\n    }\n\n    observe(this.main.main)\n    // Observe content height only (width-only overflow/position updates are ignored\n    // in the observer callback so we do not re-enter and jitter horizontally).\n    observe(this.content.main)\n\n    let parent: HTMLElement | null = this.main.main.parentElement\n    const stopAt = this.settings.contentLocation\n\n    for (let depth = 0; parent && depth < 8; depth++) {\n      observe(parent)\n      if (parent === stopAt) {\n        break\n      }\n      parent = parent.parentElement\n    }\n  }\n\n  public searchDiv(): Search {\n    const main = document.createElement('div')\n    const input = document.createElement('input')\n    const addable = document.createElement('div')\n    this.addClasses(main, this.classes.search)\n\n    // Setup search return object\n    const searchReturn: Search = {\n      main,\n      input\n    }\n\n    const showGlobalSelectAll = this.settings.selectAll && this.settings.isMultiple\n\n    // We still want the search to be tabable but not shown\n    if (!this.settings.showSearch) {\n      input.readOnly = true\n      // Keep the search row visible when global select all needs a place to live\n      if (showGlobalSelectAll) {\n        this.addClasses(input, this.classes.hide)\n      } else {\n        this.addClasses(main, this.classes.hide)\n      }\n    }\n\n    input.type = 'search'\n    input.id = `${this.settings.id}-search`\n    input.placeholder = this.settings.searchPlaceholder\n    input.tabIndex = -1\n    input.setAttribute('aria-label', this.settings.searchPlaceholder)\n    input.setAttribute('aria-autocomplete', 'list')\n    input.setAttribute('autocapitalize', 'off')\n    input.setAttribute('autocomplete', 'off')\n    input.setAttribute('autocorrect', 'off')\n    // Hide from screen readers by default (shown when opened)\n    input.setAttribute('aria-hidden', 'true')\n\n    const debouncedSearch = debounce(() => {\n      this.callbacks.search(input.value)\n    }, 100)\n\n    input.oninput = (e: Event) => {\n      if ((e.target as HTMLInputElement).value !== '') {\n        this.clearValueChipHighlight()\n      }\n      debouncedSearch()\n    }\n\n    // Deal with keyboard events on search input field\n    input.onkeydown = (e: KeyboardEvent): boolean => {\n      // Convert above if else statemets to switch\n      switch (e.key) {\n        case 'ArrowUp':\n        case 'ArrowDown':\n          this.clearValueChipHighlight()\n          e.key === 'ArrowDown' ? this.highlight('down') : this.highlight('up')\n          return false\n        case 'ArrowLeft':\n        case 'ArrowRight':\n          // Caret movement wins while the search field has text\n          if (input.value !== '') {\n            return true\n          }\n          if (this.navigateValueChips(e.key === 'ArrowLeft' ? 'left' : 'right')) {\n            e.preventDefault()\n            return false\n          }\n          return true\n        case 'Backspace':\n          if (input.value !== '') {\n            return true\n          }\n          if (!this.settings.removeLastSelectedOnBackspace && !this.getHighlightedValueChip()) {\n            return true\n          }\n          if (this.deleteValueChip()) {\n            e.preventDefault()\n            return false\n          }\n          return true\n        case 'Delete':\n          if (input.value !== '' || !this.getHighlightedValueChip()) {\n            return true\n          }\n          if (this.deleteValueChip(true)) {\n            e.preventDefault()\n            return false\n          }\n          return true\n        case 'Tab':\n          // When tabbing close the dropdown\n          // which will also focus on main div\n          // and then continuing normal tabbing\n          this.requestClose('tab')\n          return true // Continue doing normal tabbing\n        case 'Escape':\n          this.requestClose('escape')\n          return false\n        case 'Enter':\n          // Check if there's a highlighted option first\n          const highlightedEnter = this.content.list.querySelector(\n            '.' + this.classes.getFirst('highlighted')\n          ) as HTMLDivElement\n          if (highlightedEnter) {\n            // If an option is highlighted, select it (even if addable is enabled)\n            highlightedEnter.click()\n            return false\n          } else if (this.callbacks.addable) {\n            // If no option is highlighted and addable is enabled, add new item\n            addable.click()\n            return false\n          }\n          return true\n      }\n\n      if (e.key.length === 1) {\n        this.clearValueChipHighlight()\n      }\n\n      return true // Allow normal typing\n    }\n\n    main.appendChild(input)\n\n    // Global select all sits next to the search input for a condensed height\n    if (showGlobalSelectAll) {\n      const selectAll = this.createSelectAllControl(() => this.toggleGlobalSelectAll())\n      main.appendChild(selectAll)\n      searchReturn.selectAll = selectAll\n    }\n\n    // If addable is enabled, add the addable div\n    if (this.callbacks.addable) {\n      // Add main class\n      this.addClasses(addable, this.classes.addable)\n\n      // Add svg icon\n      const plus = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n      plus.setAttribute('viewBox', '0 0 100 100')\n      const plusPath = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n      plusPath.setAttribute('d', this.classes.addablePath)\n      plus.appendChild(plusPath)\n      addable.appendChild(plus)\n\n      // Add click event to addable div\n      addable.onclick = (e: Event) => {\n        e.preventDefault()\n        e.stopPropagation()\n\n        // Do nothing if addable is not set\n        if (!this.callbacks.addable) {\n          return\n        }\n\n        // Grab input value\n        const inputValue = this.content.search.input.value.trim()\n        if (inputValue === '') {\n          this.content.search.input.focus()\n          return\n        }\n\n        // Run finish will be ran at the end of the addable function.\n        // Reason its in a function is so we can run it after the\n        // addable function is done for promise based addables\n        const runFinish = (oo: Partial<Option>) => {\n          let newOption = new Option(oo)\n\n          // Call addOption to add the new option\n          this.callbacks.addOption(newOption)\n\n          // set selected value for single and multiple\n          if (this.settings.isMultiple) {\n            let ids = this.store.getSelected()\n            ids.push(newOption.id)\n            this.callbacks.setSelected(ids, true)\n          } else {\n            this.callbacks.setSelected([newOption.id], true)\n          }\n\n          // Clear search (internal reset — must not fire the consumer search event)\n          this.callbacks.clearSearch()\n\n          // Close it only if closeOnSelect = true\n          if (this.settings.closeOnSelect) {\n            const animationDuration = getAnimationDuration(this.content.main)\n            setTimeout(() => {\n              this.requestClose('select', { selectionChanged: true })\n            }, animationDuration)\n          }\n        }\n\n        // Call addable callback\n        const addableValue = this.callbacks.addable(inputValue)\n\n        // If addableValue is false, undefined or null, do nothing\n        if (addableValue === false || addableValue === undefined || addableValue === null) {\n          return\n        }\n\n        // If addableValue is a promise, wait for it to resolve\n        if (addableValue instanceof Promise) {\n          addableValue.then((value) => {\n            if (typeof value === 'string') {\n              runFinish({\n                text: value,\n                value: value\n              })\n            } else if (addableValue instanceof Error) {\n              this.renderError(addableValue.message)\n            } else {\n              runFinish(value)\n            }\n          })\n        } else if (typeof addableValue === 'string') {\n          runFinish({\n            text: addableValue,\n            value: addableValue\n          })\n        } else if (addableValue instanceof Error) {\n          this.renderError(addableValue.message)\n        } else {\n          runFinish(addableValue)\n        }\n\n        return\n      }\n      main.appendChild(addable)\n\n      // Add the addable to the search return\n      searchReturn.addable = {\n        main: addable,\n        svg: plus,\n        path: plusPath\n      }\n    }\n\n    return searchReturn\n  }\n\n  public searchFocus(): void {\n    this.content.search.input.focus({ preventScroll: true })\n  }\n\n  public getOptions(notPlaceholder = false, notDisabled = false, notHidden = false): HTMLDivElement[] {\n    // Put together query string\n    let query = '.' + this.classes.getFirst('option')\n    if (notPlaceholder) {\n      query += ':not(.' + this.classes.getFirst('placeholder') + ')'\n    }\n    if (notDisabled) {\n      query += ':not(.' + this.classes.getFirst('disabled') + ')'\n    }\n    if (notHidden) {\n      query += ':not(.' + this.classes.getFirst('hide') + ')'\n    }\n\n    return Array.from(this.content.list.querySelectorAll(query))\n  }\n\n  // highlightUp is used to highlight the previous option in the list\n  public highlight(dir: 'up' | 'down'): void {\n    // Get full list of options in list\n    const options = this.getOptions(true, true, true)\n\n    // If there are no options, do nothing\n    if (options.length === 0) {\n      return\n    }\n\n    // If length is 1, highlight it\n    if (options.length === 1) {\n      // Check if option doesnt already have highlighted class\n      if (!options[0].classList.contains(this.classes.getFirst('highlighted'))) {\n        this.addClasses(options[0], this.classes.highlighted)\n        return\n      }\n    }\n\n    // Loop through options and see if there are no highlighted ones\n    let highlighted = false\n    for (const o of options) {\n      if (o.classList.contains(this.classes.getFirst('highlighted'))) {\n        highlighted = true\n      }\n    }\n\n    // If no highlighted, see if any are selected and if so highlight selected first one\n    if (!highlighted) {\n      for (const o of options) {\n        if (o.classList.contains(this.classes.getFirst('selected'))) {\n          this.addClasses(o, this.classes.highlighted)\n          break\n        }\n      }\n    }\n\n    // Loop through options and find the highlighted one\n    for (let i = 0; i < options.length; i++) {\n      // Found highlighted option\n      if (options[i].classList.contains(this.classes.getFirst('highlighted'))) {\n        const prevOption = options[i]\n        // Remove highlighted class from current one\n        this.removeClasses(prevOption, this.classes.highlighted)\n\n        // If previous option has parent classes ss-optgroup with ss-open then click it\n        const prevParent = prevOption.parentElement\n        if (prevParent && prevParent.classList.contains(this.classes.getFirst('mainOpen'))) {\n          const optgroupLabel = prevParent.querySelector('.' + this.classes.getFirst('optgroupLabel')) as HTMLDivElement\n          if (optgroupLabel) {\n            optgroupLabel.click()\n          }\n        }\n\n        // Highlight the next one\n        let selectOption =\n          options[dir === 'down' ? (i + 1 < options.length ? i + 1 : 0) : i - 1 >= 0 ? i - 1 : options.length - 1]\n        this.addClasses(selectOption, this.classes.highlighted)\n        this.ensureElementInView(this.content.list, selectOption)\n\n        // Update aria-activedescendant for screen readers\n        if (selectOption.id) {\n          this.main.main.setAttribute('aria-activedescendant', selectOption.id)\n        }\n\n        // If selected option has parent classes ss-optgroup with ss-close then click it\n        const selectParent = selectOption.parentElement\n        if (selectParent && selectParent.classList.contains(this.classes.getFirst('close'))) {\n          const optgroupLabel = selectParent.querySelector(\n            '.' + this.classes.getFirst('optgroupLabel')\n          ) as HTMLDivElement\n          if (optgroupLabel) {\n            optgroupLabel.click()\n          }\n        }\n\n        return\n      }\n    }\n\n    // If we get here, there is no highlighted option\n    // So we will highlight the first or last based upon direction\n    const firstHighlight = options[dir === 'down' ? 0 : options.length - 1]\n    this.addClasses(firstHighlight, this.classes.highlighted)\n\n    // Update aria-activedescendant for screen readers\n    if (firstHighlight.id) {\n      this.main.main.setAttribute('aria-activedescendant', firstHighlight.id)\n    }\n\n    // Scroll to highlighted one\n    this.ensureElementInView(this.content.list, firstHighlight)\n  }\n\n  /**\n   * Letters and digits when search is hidden. Builds a short prefix and highlights\n   * the matching option without selecting it. Repeating the same character cycles.\n   */\n  private isTypeaheadKey(e: KeyboardEvent): boolean {\n    if (this.settings.showSearch || this.settings.disabled) {\n      return false\n    }\n\n    if (e.ctrlKey || e.metaKey || e.altKey || e.isComposing) {\n      return false\n    }\n\n    return e.key.length === 1 && /[\\p{L}\\p{N}]/u.test(e.key)\n  }\n\n  private typeahead(char: string): void {\n    const options = this.getOptions(true, true, true)\n    if (options.length === 0) {\n      return\n    }\n\n    const key = char.toLowerCase()\n    const repeating = this.typeaheadQuery.length > 0 && [...this.typeaheadQuery].every((c) => c === key)\n\n    if (this.typeaheadTimer !== null) {\n      clearTimeout(this.typeaheadTimer)\n    }\n    this.typeaheadTimer = setTimeout(() => {\n      this.typeaheadQuery = ''\n      this.typeaheadTimer = null\n    }, TYPEAHEAD_RESET_MS)\n\n    const highlightedClass = this.classes.getFirst('highlighted')\n    const selectedClass = this.classes.getFirst('selected')\n    let origin = options.findIndex((option) => option.classList.contains(highlightedClass))\n    if (origin < 0) {\n      origin = options.findIndex((option) => option.classList.contains(selectedClass))\n    }\n\n    let startIndex: number\n    if (repeating) {\n      this.typeaheadQuery = key\n      startIndex = origin >= 0 ? (origin + 1) % options.length : 0\n    } else {\n      this.typeaheadQuery += key\n      startIndex = origin >= 0 ? origin : 0\n    }\n\n    const match = this.findTypeaheadOption(options, this.typeaheadQuery, startIndex)\n    if (match) {\n      this.highlightOption(match)\n    }\n  }\n\n  private findTypeaheadOption(options: HTMLDivElement[], query: string, startIndex: number): HTMLDivElement | null {\n    for (let i = 0; i < options.length; i++) {\n      const option = options[(startIndex + i) % options.length]\n      const label = (option.textContent || '').trim().toLowerCase()\n      if (label.startsWith(query)) {\n        return option\n      }\n    }\n\n    return null\n  }\n\n  private highlightOption(optionEl: HTMLDivElement): void {\n    const highlightedClass = this.classes.getFirst('highlighted')\n    const current = this.content.list.querySelectorAll('.' + highlightedClass)\n    current.forEach((el) => {\n      if (el !== optionEl) {\n        this.removeClasses(el as HTMLElement, this.classes.highlighted)\n      }\n    })\n\n    this.addClasses(optionEl, this.classes.highlighted)\n\n    if (optionEl.id) {\n      this.main.main.setAttribute('aria-activedescendant', optionEl.id)\n    }\n\n    const parent = optionEl.parentElement\n    if (parent && parent.classList.contains(this.classes.getFirst('close'))) {\n      const label = parent.querySelector('.' + this.classes.getFirst('optgroupLabel')) as HTMLDivElement | null\n      label?.click()\n    }\n\n    this.ensureElementInView(this.content.list, optionEl)\n  }\n\n  private clearTypeahead(): void {\n    this.typeaheadQuery = ''\n    if (this.typeaheadTimer !== null) {\n      clearTimeout(this.typeaheadTimer)\n      this.typeaheadTimer = null\n    }\n  }\n\n  // Create main container that options will reside\n  public listDiv(): HTMLDivElement {\n    const options = document.createElement('div')\n    this.addClasses(options, this.classes.list)\n\n    // Add id for ARIA controls reference\n    const listId = this.settings.id + '-list'\n    options.id = listId\n    options.dataset.id = listId\n\n    return options\n  }\n\n  public renderError(error: string) {\n    this.optionsListIsFullData = false\n    // Clear out innerHtml\n    this.content.list.innerHTML = ''\n\n    const errorDiv = document.createElement('div')\n    this.addClasses(errorDiv, this.classes.error)\n    errorDiv.textContent = error\n    this.content.list.appendChild(errorDiv)\n    this.repositionOpenContent()\n  }\n\n  public renderSearching() {\n    this.optionsListIsFullData = false\n    // Clear out innerHtml\n    this.content.list.innerHTML = ''\n\n    const searchingDiv = document.createElement('div')\n    this.addClasses(searchingDiv, this.classes.searching)\n    searchingDiv.textContent = this.settings.searchingText\n    this.content.list.appendChild(searchingDiv)\n    this.announce(this.settings.searchingText)\n    this.repositionOpenContent()\n  }\n\n  // Take in data and add options to\n  public renderOptions(data: (Option | Optgroup)[]): void {\n    this.lastSearchFilterTerm = ''\n    this.lastRenderedOptions = data\n      .map((o) => (o instanceof Option ? [o] : o.options.map((po) => new Option(po))))\n      .flat()\n\n    // Clear out innerHtml\n    this.content.list.innerHTML = ''\n\n    // If no results show no results text\n    if (data.length === 0) {\n      this.optionsListIsFullData = false\n      const noResults = document.createElement('div')\n      this.addClasses(noResults, this.classes.search)\n\n      //\n      if (this.callbacks.addable) {\n        const addableMessage = this.settings.addableText.replace('{value}', this.content.search.input.value)\n        noResults.innerHTML = addableMessage\n        this.announce(addableMessage)\n      } else {\n        noResults.innerHTML = this.settings.searchText\n        this.announce(this.settings.searchText)\n      }\n      this.content.list.appendChild(noResults)\n      this.repositionOpenContent()\n      return\n    }\n\n    // If settings has allowDeselect and isSingle, add empty placeholder in the event they want to deselect\n    if (this.settings.allowDeselect && !this.settings.isMultiple) {\n      // Check if store options have a placeholder\n      const placeholderOption = this.store.filter((o) => o.placeholder, false, false) as Option[]\n      if (!placeholderOption.length) {\n        this.store.addOption(\n          new Option({\n            text: '',\n            value: '',\n            selected: false,\n            placeholder: true\n          }),\n          true\n        )\n      }\n    }\n\n    // Append individual options to div container\n    const fragment = document.createDocumentFragment()\n    for (const d of data) {\n      // Create optgroup\n      if (d instanceof Optgroup) {\n        // Create optgroup\n        const optgroupEl = document.createElement('div')\n        this.addClasses(optgroupEl, this.classes.optgroup)\n\n        // Create label\n        const optgroupLabel = document.createElement('div')\n        this.addClasses(optgroupLabel, this.classes.optgroupLabel)\n        optgroupEl.appendChild(optgroupLabel)\n\n        // Create label text div element\n        const optgroupLabelText = document.createElement('div')\n        this.addClasses(optgroupLabelText, this.classes.optgroupLabelText)\n        optgroupLabelText.textContent = d.label\n        optgroupLabel.appendChild(optgroupLabelText)\n\n        // Create options container\n        const optgroupActions = document.createElement('div')\n        this.addClasses(optgroupActions, this.classes.optgroupActions)\n        optgroupLabel.appendChild(optgroupActions)\n\n        // If selectByGroup is true and isMultiple then add click event to label\n        if (this.settings.isMultiple && d.selectAll) {\n          // Create select all control with shared checkbox markup\n          const selectAll = this.createSelectAllControl(\n            () => {\n              // Get the store current selected values\n              const currentSelected = this.store.getSelected()\n              const allSelectedNow = this.isOptgroupAllSelected(d.options as Option[], new Set(currentSelected))\n\n              // If all selected, remove all options from selected\n              if (allSelectedNow) {\n                // Put together new list minus all options in this optgroup\n                const newSelected = currentSelected.filter((s) => {\n                  for (const o of d.options) {\n                    if (s === o.id) {\n                      return false\n                    }\n                  }\n\n                  return true\n                })\n\n                this.callbacks.setSelected(newSelected, true)\n                return\n              } else {\n                // Put together new list with all options in this optgroup\n                let optionIds = d.options.map((o) => o.id).filter((id) => id !== undefined)\n                const newSelected = currentSelected.concat(optionIds)\n\n                // Loop through options and if they don't exist in the store\n                // run addOption callback\n                for (const o of d.options) {\n                  if (o.id && !this.store.getOptionByID(o.id)) {\n                    this.callbacks.addOption(new Option(o))\n                  }\n                }\n\n                this.callbacks.setSelected(newSelected, true)\n                return\n              }\n            },\n            this.isOptgroupAllSelected(d.options as Option[])\n          )\n\n          // Append select all to label\n          optgroupActions.appendChild(selectAll)\n        }\n\n        // If optgroup has collapsable\n        if (d.closable !== 'off') {\n          // Create new div to hold a checkbox svg\n          const optgroupClosable = document.createElement('div')\n          this.addClasses(optgroupClosable, this.classes.optgroupClosable)\n\n          // Create svg arrow\n          const optgroupClosableSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n          optgroupClosableSvg.setAttribute('viewBox', '0 0 100 100')\n          this.addClasses(optgroupClosableSvg, this.classes.arrow)\n          optgroupClosable.appendChild(optgroupClosableSvg)\n\n          // Create new path for arrow\n          const optgroupClosableArrow = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n          optgroupClosableSvg.appendChild(optgroupClosableArrow)\n\n          // If any options are selected or someone is searching, set optgroup to open\n          if (d.options.some((o) => o.selected) || this.content.search.input.value.trim() !== '') {\n            this.addClasses(optgroupClosable, this.classes.mainOpen)\n            optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n          } else if (d.closable === 'open') {\n            this.addClasses(optgroupEl, this.classes.mainOpen)\n            optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n          } else if (d.closable === 'close') {\n            this.addClasses(optgroupEl, this.classes.close)\n            optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)\n          }\n\n          // Add click event listener to close\n          optgroupLabel.addEventListener('click', (e: MouseEvent) => {\n            e.preventDefault()\n            e.stopPropagation()\n\n            const isOpen = this.isClosableOptgroupOpen(optgroupEl, optgroupClosable)\n\n            if (!isOpen) {\n              this.closeOtherClosableOptgroups(optgroupEl)\n              this.removeClasses(optgroupEl, this.classes.close)\n              this.removeClasses(optgroupClosable, this.classes.mainOpen)\n              this.addClasses(optgroupEl, this.classes.mainOpen)\n              optgroupClosableArrow.setAttribute('d', this.classes.arrowOpen)\n            } else {\n              this.removeClasses(optgroupEl, this.classes.mainOpen)\n              this.removeClasses(optgroupClosable, this.classes.mainOpen)\n              this.addClasses(optgroupEl, this.classes.close)\n              optgroupClosableArrow.setAttribute('d', this.classes.arrowClose)\n            }\n\n            this.repositionOpenContent()\n          })\n\n          // Append close to label\n          optgroupActions.appendChild(optgroupClosable)\n        }\n\n        // Add optgroup label\n        optgroupEl.appendChild(optgroupLabel)\n\n        // Loop through options\n        for (const option of d.options) {\n          optgroupEl.appendChild(this.option(new Option(option)))\n          fragment.appendChild(optgroupEl)\n        }\n      }\n\n      // Create option\n      if (d instanceof Option) {\n        fragment.appendChild(this.option(d as Option))\n      }\n    }\n\n    // Append fragment to list\n    this.content.list.appendChild(fragment)\n    this.setOptionsListFullData(data)\n    this.announce(this.settings.resultsText.replace('{count}', String(this.lastRenderedOptions.length)))\n    this.updateGlobalSelectAllState()\n    this.repositionOpenContent()\n  }\n\n  /** True when the list DOM contains every store option (local search can show/hide in place). */\n  public canFilterOptionsInPlace(): boolean {\n    if (!this.optionsListIsFullData) {\n      return false\n    }\n\n    return this.content.list.querySelector('.' + this.classes.getFirst('option')) !== null\n  }\n\n  public resetSearchFilterState(): void {\n    this.lastSearchFilterTerm = ''\n  }\n\n  /** Filter visible options by search without rebuilding the list. */\n  public filterOptionsInPlace(search: string, searchFilter: (opt: Option, search: string) => boolean): void {\n    const searchTrim = search.trim()\n    if (searchTrim === this.lastSearchFilterTerm) {\n      return\n    }\n    this.lastSearchFilterTerm = searchTrim\n\n    const visibleOptions: Option[] = []\n    const optionEls = this.content.list.querySelectorAll(\n      '.' + this.classes.getFirst('option')\n    ) as NodeListOf<HTMLDivElement>\n\n    for (const optionEl of optionEls) {\n      const id = optionEl.dataset.id\n      if (!id) {\n        continue\n      }\n\n      const storeOption = this.store.getOptionByID(id)\n      if (!storeOption) {\n        continue\n      }\n\n      const isPermanentlyHidden =\n        storeOption.placeholder || !storeOption.display || (storeOption.selected && this.settings.hideSelected)\n\n      const matchesSearch = searchFilter(storeOption, searchTrim)\n\n      if (isPermanentlyHidden || !matchesSearch) {\n        this.addClasses(optionEl, this.classes.hide)\n        this.removeClasses(optionEl, this.classes.highlighted)\n      } else {\n        this.removeClasses(optionEl, this.classes.hide)\n        this.setOptionElementContent(optionEl, storeOption, searchTrim)\n        visibleOptions.push(storeOption)\n      }\n\n      if (storeOption.selected) {\n        this.addClasses(optionEl, this.classes.selected)\n        optionEl.setAttribute('aria-selected', 'true')\n      } else {\n        this.removeClasses(optionEl, this.classes.selected)\n        optionEl.setAttribute('aria-selected', 'false')\n      }\n    }\n\n    this.lastRenderedOptions = visibleOptions\n    this.updateOptgroupVisibilityAfterSearch(searchTrim)\n\n    if (visibleOptions.length === 0) {\n      this.updateSearchResultsMessage(0, searchTrim)\n    } else {\n      this.removeListSearchMessage()\n      this.announce(this.settings.resultsText.replace('{count}', String(visibleOptions.length)))\n    }\n\n    this.updateOptgroupSelectAllStates()\n    this.updateGlobalSelectAllState()\n    this.repositionOpenContent()\n  }\n\n  private setOptionsListFullData(data: (Option | Optgroup)[]): void {\n    const storeOptions = this.store.getDataOptions(false)\n    const renderedOptions = data.map((o) => (o instanceof Option ? [o] : o.options.map((po) => new Option(po)))).flat()\n\n    if (renderedOptions.length !== storeOptions.length) {\n      this.optionsListIsFullData = false\n      return\n    }\n\n    const storeIds = new Set(storeOptions.map((o) => o.id))\n    this.optionsListIsFullData = renderedOptions.every((o) => storeIds.has(o.id))\n  }\n\n  private isClosableOptgroupOpen(optgroupEl: HTMLElement, optgroupClosable: HTMLElement): boolean {\n    if (optgroupEl.classList.contains(this.classes.getFirst('close'))) {\n      return false\n    }\n\n    return (\n      optgroupEl.classList.contains(this.classes.getFirst('mainOpen')) ||\n      optgroupClosable.classList.contains(this.classes.getFirst('mainOpen'))\n    )\n  }\n\n  private closeClosableOptgroup(optgroupEl: HTMLElement): void {\n    const closable = optgroupEl.querySelector('.' + this.classes.getFirst('optgroupClosable')) as HTMLElement | null\n    if (!closable) {\n      return\n    }\n\n    if (optgroupEl.classList.contains(this.classes.getFirst('close'))) {\n      return\n    }\n\n    this.removeClasses(optgroupEl, this.classes.mainOpen)\n    this.removeClasses(closable, this.classes.mainOpen)\n    this.addClasses(optgroupEl, this.classes.close)\n\n    const arrow = closable.querySelector('path')\n    if (arrow) {\n      arrow.setAttribute('d', this.classes.arrowClose)\n    }\n  }\n\n  private closeOtherClosableOptgroups(exceptOptgroupEl: HTMLElement): void {\n    const optgroups = this.content.list.querySelectorAll('.' + this.classes.getFirst('optgroup'))\n\n    for (const optgroupEl of optgroups) {\n      if (optgroupEl === exceptOptgroupEl) {\n        continue\n      }\n\n      this.closeClosableOptgroup(optgroupEl as HTMLElement)\n    }\n  }\n\n  private updateOptgroupVisibilityAfterSearch(searchTrim: string): void {\n    const optgroups = this.content.list.querySelectorAll('.' + this.classes.getFirst('optgroup'))\n\n    for (const optgroupEl of optgroups) {\n      const optionEls = optgroupEl.querySelectorAll('.' + this.classes.getFirst('option')) as NodeListOf<HTMLDivElement>\n\n      let hasVisibleOption = false\n      for (const optionEl of optionEls) {\n        if (!optionEl.classList.contains(this.classes.getFirst('hide'))) {\n          hasVisibleOption = true\n          break\n        }\n      }\n\n      if (!hasVisibleOption) {\n        this.addClasses(optgroupEl as HTMLDivElement, this.classes.hide)\n        continue\n      }\n\n      this.removeClasses(optgroupEl as HTMLDivElement, this.classes.hide)\n\n      if (searchTrim !== '') {\n        this.removeClasses(optgroupEl as HTMLDivElement, this.classes.close)\n        this.addClasses(optgroupEl as HTMLDivElement, this.classes.mainOpen)\n      }\n    }\n  }\n\n  private updateSearchResultsMessage(visibleCount: number, searchTrim: string): void {\n    this.removeListSearchMessage()\n\n    if (visibleCount > 0) {\n      return\n    }\n\n    const noResults = document.createElement('div')\n    this.addClasses(noResults, this.classes.search)\n\n    if (this.callbacks.addable) {\n      const addableMessage = this.settings.addableText.replace('{value}', searchTrim)\n      noResults.innerHTML = addableMessage\n      this.announce(addableMessage)\n    } else {\n      noResults.innerHTML = this.settings.searchText\n      this.announce(this.settings.searchText)\n    }\n\n    this.content.list.appendChild(noResults)\n  }\n\n  private removeListSearchMessage(): void {\n    const messages = this.content.list.querySelectorAll('.' + this.classes.getFirst('search'))\n    messages.forEach((message) => message.remove())\n  }\n\n  private setOptionElementContent(optionEl: HTMLDivElement, option: Option, search: string): void {\n    const searchTrim = search.trim()\n    if (this.settings.searchHighlight && searchTrim !== '') {\n      optionEl.innerHTML = this.highlightText(\n        option.html !== '' ? option.html : option.text,\n        searchTrim,\n        this.classes.searchHighlighter\n      )\n    } else if (option.html !== '') {\n      optionEl.innerHTML = option.html\n    } else {\n      optionEl.textContent = option.text\n    }\n\n    if (this.settings.showOptionTooltips && optionEl.textContent) {\n      optionEl.setAttribute('title', optionEl.textContent)\n    } else {\n      optionEl.removeAttribute('title')\n    }\n  }\n\n  /** True when option nodes exist in the list (selection can sync without re-searching). */\n  public hasRenderedOptions(): boolean {\n    return this.content.list.querySelector('.' + this.classes.getFirst('option')) !== null\n  }\n\n  /** True when the open list already has options and search is not filtering. */\n  public canUpdateOptionSelectionInPlace(): boolean {\n    if (this.content.search.input.value.trim() !== '') {\n      return false\n    }\n\n    return this.hasRenderedOptions()\n  }\n\n  /** Sync selected/hidden state on existing option nodes without rebuilding the list. */\n  public updateOptionSelection(): void {\n    const selectedIds = new Set(this.store.getSelected())\n    const optionEls = this.content.list.querySelectorAll(\n      '.' + this.classes.getFirst('option')\n    ) as NodeListOf<HTMLDivElement>\n\n    let lastSelectedEl: HTMLDivElement | null = null\n\n    for (const optionEl of optionEls) {\n      const id = optionEl.dataset.id\n      if (!id) {\n        continue\n      }\n\n      const storeOption = this.store.getOptionByID(id)\n      if (!storeOption) {\n        continue\n      }\n\n      const isSelected = selectedIds.has(id)\n\n      if (isSelected) {\n        this.addClasses(optionEl, this.classes.selected)\n        optionEl.setAttribute('aria-selected', 'true')\n        lastSelectedEl = optionEl\n      } else {\n        this.removeClasses(optionEl, this.classes.selected)\n        optionEl.setAttribute('aria-selected', 'false')\n      }\n\n      if (this.settings.hideSelected) {\n        if (isSelected) {\n          this.addClasses(optionEl, this.classes.hide)\n        } else {\n          this.removeClasses(optionEl, this.classes.hide)\n          if (!storeOption.display) {\n            this.addClasses(optionEl, this.classes.hide)\n          }\n        }\n      }\n    }\n\n    if (!this.settings.isMultiple && lastSelectedEl) {\n      this.main.main.setAttribute('aria-activedescendant', lastSelectedEl.id)\n    } else if (!this.settings.isMultiple && selectedIds.size === 0) {\n      this.main.main.removeAttribute('aria-activedescendant')\n    }\n\n    this.updateOptgroupSelectAllStates()\n    this.updateGlobalSelectAllState()\n    this.repositionOpenContent()\n  }\n\n  private createSelectAllControl(onClick: () => void, allSelected = false): HTMLDivElement {\n    const selectAll = document.createElement('div')\n    this.addClasses(selectAll, this.classes.optgroupSelectAll)\n    selectAll.setAttribute('role', 'checkbox')\n    selectAll.setAttribute('aria-checked', allSelected ? 'true' : 'false')\n    selectAll.setAttribute('aria-label', this.selectAllLabel(allSelected))\n    selectAll.tabIndex = -1\n\n    if (allSelected) {\n      this.addClasses(selectAll, this.classes.selected)\n    }\n\n    const selectAllLabel = document.createElement('span')\n    selectAllLabel.textContent = this.selectAllLabel(allSelected)\n    selectAll.appendChild(selectAllLabel)\n\n    const selectAllSvg = document.createElementNS('http://www.w3.org/2000/svg', 'svg')\n    selectAllSvg.setAttribute('viewBox', '0 0 100 100')\n    selectAllSvg.setAttribute('aria-hidden', 'true')\n    selectAll.appendChild(selectAllSvg)\n\n    const selectAllBox = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n    selectAllBox.setAttribute('d', this.classes.optgroupSelectAllBox)\n    selectAllSvg.appendChild(selectAllBox)\n\n    const selectAllCheck = document.createElementNS('http://www.w3.org/2000/svg', 'path')\n    selectAllCheck.setAttribute('d', this.classes.optgroupSelectAllCheck)\n    selectAllSvg.appendChild(selectAllCheck)\n\n    selectAll.addEventListener('click', (e: MouseEvent) => {\n      e.preventDefault()\n      e.stopPropagation()\n      onClick()\n    })\n\n    return selectAll\n  }\n\n  private getSelectableOptions(): Option[] {\n    return this.store.getDataOptions(false).filter((option) => {\n      return !option.disabled && !option.placeholder && option.display\n    })\n  }\n\n  private isGlobalAllSelected(selectedIds?: Set<string>): boolean {\n    const options = this.getSelectableOptions()\n    if (options.length === 0) {\n      return false\n    }\n\n    const selected = selectedIds || new Set(this.store.getSelected())\n    for (const option of options) {\n      if (!selected.has(option.id)) {\n        return false\n      }\n    }\n\n    return true\n  }\n\n  private toggleGlobalSelectAll(): void {\n    const selectable = this.getSelectableOptions()\n    const selectedIds = new Set(this.store.getSelected())\n\n    if (this.isGlobalAllSelected(selectedIds)) {\n      const selectableIds = new Set(selectable.map((option) => option.id))\n      const newSelected = this.store.getSelected().filter((id) => !selectableIds.has(id))\n      this.callbacks.setSelected(newSelected, true)\n      return\n    }\n\n    this.callbacks.setSelected(\n      selectable.map((option) => option.id),\n      true\n    )\n  }\n\n  private updateGlobalSelectAllState(): void {\n    const selectAll = this.content.search.selectAll\n    if (!selectAll || !this.settings.isMultiple || !this.settings.selectAll) {\n      return\n    }\n\n    const allSelected = this.isGlobalAllSelected()\n    if (allSelected) {\n      this.addClasses(selectAll, this.classes.selected)\n    } else {\n      this.removeClasses(selectAll, this.classes.selected)\n    }\n\n    selectAll.setAttribute('aria-checked', allSelected ? 'true' : 'false')\n    selectAll.setAttribute('aria-label', this.selectAllLabel(allSelected))\n\n    const selectAllLabel = selectAll.querySelector('span')\n    if (selectAllLabel) {\n      selectAllLabel.textContent = this.selectAllLabel(allSelected)\n    }\n  }\n\n  private updateOptgroupSelectAllStates(): void {\n    if (!this.settings.isMultiple) {\n      return\n    }\n\n    const selectedIds = new Set(this.store.getSelected())\n    const optgroups = this.content.list.querySelectorAll('.' + this.classes.getFirst('optgroup'))\n\n    for (const optgroupEl of optgroups) {\n      const selectAll = optgroupEl.querySelector(\n        '.' + this.classes.getFirst('optgroupSelectAll')\n      ) as HTMLDivElement | null\n\n      if (!selectAll) {\n        continue\n      }\n\n      const optionEls = optgroupEl.querySelectorAll('.' + this.classes.getFirst('option')) as NodeListOf<HTMLDivElement>\n\n      let allSelected = optionEls.length > 0\n      for (const optionEl of optionEls) {\n        const id = optionEl.dataset.id\n        if (!id || !selectedIds.has(id)) {\n          allSelected = false\n          break\n        }\n      }\n\n      if (allSelected) {\n        this.addClasses(selectAll, this.classes.selected)\n      } else {\n        this.removeClasses(selectAll, this.classes.selected)\n      }\n\n      selectAll.setAttribute('aria-checked', allSelected ? 'true' : 'false')\n      selectAll.setAttribute('aria-label', this.selectAllLabel(allSelected))\n\n      const selectAllLabel = selectAll.querySelector('span')\n      if (selectAllLabel) {\n        selectAllLabel.textContent = this.selectAllLabel(allSelected)\n      }\n    }\n  }\n\n  private selectAllLabel(allSelected: boolean): string {\n    return allSelected ? this.settings.unselectAllText : this.settings.selectAllText\n  }\n\n  private isOptgroupAllSelected(options: Option[], selectedIds?: Set<string>): boolean {\n    if (options.length === 0) {\n      return false\n    }\n\n    for (const option of options) {\n      const isSelected = selectedIds ? Boolean(option.id && selectedIds.has(option.id)) : option.selected\n\n      if (!isSelected) {\n        return false\n      }\n    }\n\n    return true\n  }\n\n  // Create option div element\n  public option(option: Option): HTMLDivElement {\n    // Add hidden placeholder\n    if (option.placeholder) {\n      const placeholder = document.createElement('div')\n      this.addClasses(placeholder, this.classes.option)\n      this.addClasses(placeholder, this.classes.hide)\n      return placeholder\n    }\n\n    // Create option\n    const optionEl = document.createElement('div')\n    optionEl.dataset.id = option.id // Dataset id for identifying an option\n    optionEl.id = this.settings.id + '-' + option.id // Unique ID for ARIA references\n    this.addClasses(optionEl, this.classes.option)\n    optionEl.setAttribute('role', 'option') // WCAG attribute\n    if (option.class) {\n      option.class.split(' ').forEach((dataClass: string) => {\n        optionEl.classList.add(dataClass)\n      })\n    }\n    if (option.style) {\n      optionEl.style.cssText = option.style\n    }\n\n    // Set option content\n    this.setOptionElementContent(optionEl, option, this.content.search.input.value)\n\n    // If option is disabled\n    if (!option.display) {\n      this.addClasses(optionEl, this.classes.hide)\n    }\n\n    // If allowed to deselect, null onclick and add disabled\n    if (option.disabled) {\n      this.addClasses(optionEl, this.classes.disabled)\n    }\n\n    // If option is selected and hideSelectedOption is true, hide it\n    if (option.selected && this.settings.hideSelected) {\n      this.addClasses(optionEl, this.classes.hide)\n    }\n\n    // If option is selected\n    if (option.selected) {\n      this.addClasses(optionEl, this.classes.selected)\n      optionEl.setAttribute('aria-selected', 'true')\n      this.main.main.setAttribute('aria-activedescendant', optionEl.id)\n    } else {\n      this.removeClasses(optionEl, this.classes.selected)\n      optionEl.setAttribute('aria-selected', 'false')\n    }\n\n    // Add click event listener\n    optionEl.addEventListener('click', (e: MouseEvent) => {\n      e.preventDefault()\n      e.stopPropagation()\n\n      // Setup variables\n      const selectedOptions = this.store.getSelected()\n      const element = e.currentTarget as HTMLDivElement\n      const elementID = String(element.dataset.id)\n      const storeOption = this.store.getOptionByID(elementID) ?? option\n      const isCurrentlySelected = selectedOptions.includes(elementID)\n      const isCmd = e.ctrlKey || e.metaKey // Cmd (Mac) or Ctrl (Windows/Linux)\n\n      // If the option is disabled, do nothing\n      if (option.disabled) {\n        return\n      }\n\n      // allowDeselect only applies to single-select mode\n      // In multi-select, you can always toggle options on/off\n      if (!this.settings.isMultiple && isCurrentlySelected && !this.settings.allowDeselect) {\n        this.closeOnSingleSelectReclick(storeOption)\n        return\n      }\n\n      // Prevent deselection of mandatory options\n      if (isCurrentlySelected && storeOption.mandatory) {\n        this.closeOnSingleSelectReclick(storeOption)\n        return\n      }\n\n      // Check limit and do nothing if limit is reached and the option is not selected\n      // Also check reverse for min limit and is selected (allow Cmd to bypass minSelected)\n      if (\n        (this.settings.isMultiple && this.settings.maxSelected <= selectedOptions.length && !isCurrentlySelected) ||\n        (this.settings.isMultiple &&\n          this.settings.minSelected >= selectedOptions.length &&\n          isCurrentlySelected &&\n          !isCmd)\n      ) {\n        return\n      }\n\n      // Setup variables\n      let shouldUpdate = false\n      const before = this.store.getSelectedOptions()\n      let after = [] as Option[]\n\n      // If multiple - mimic native browser multi-select behavior\n      if (this.settings.isMultiple) {\n        const isCurrentlySelected = before.some((o: Option) => o.id === elementID)\n        const isShift = e.shiftKey\n\n        // Shift+Click: Select range from last clicked to current\n        if (isShift && this.lastSelectedOption) {\n          const options = this.lastRenderedOptions\n          const lastIndex = options.findIndex((o: Option) => o.id === this.lastSelectedOption!.id)\n          const currentIndex = options.findIndex((o: Option) => o.id === option.id)\n\n          if (lastIndex >= 0 && currentIndex >= 0) {\n            const startIndex = Math.min(lastIndex, currentIndex)\n            const endIndex = Math.max(lastIndex, currentIndex)\n            const rangeOptions = options.slice(startIndex, endIndex + 1)\n\n            // Check if range would exceed maxSelected\n            const newSelections = rangeOptions.filter((opt) => !before.find((b) => b.id === opt.id))\n            if (before.length + newSelections.length <= this.settings.maxSelected) {\n              // Add range to existing selections\n              after = before.concat(newSelections)\n            } else {\n              // Range too large, keep existing selections\n              after = before\n            }\n          } else {\n            after = before\n          }\n        }\n        // Cmd/Ctrl+Click: Toggle selection without affecting others (keeps dropdown open)\n        else if (isCmd) {\n          if (isCurrentlySelected) {\n            // Deselect this option\n            after = before.filter((o: Option) => o.id !== elementID)\n          } else {\n            // Add this option to selection\n            after = before.concat(storeOption)\n          }\n          this.lastSelectedOption = storeOption\n        }\n        // Regular Click: Toggle this option (add/remove), will close dropdown\n        else {\n          if (isCurrentlySelected) {\n            // Deselect this option\n            after = before.filter((o: Option) => o.id !== elementID)\n          } else {\n            // Add this option to selection\n            after = before.concat(storeOption)\n          }\n          this.lastSelectedOption = storeOption\n        }\n      }\n\n      // If single\n      if (!this.settings.isMultiple) {\n        if (isCurrentlySelected) {\n          // If selected after would remove\n          after = []\n        } else {\n          // If not selected after would add\n          after = [storeOption]\n        }\n      }\n\n      // If no beforeOnChange is set automatically update at end\n      if (!this.callbacks.beforeChange) {\n        shouldUpdate = true\n      }\n\n      if (this.callbacks.beforeChange) {\n        // Check if beforeChange returns false\n        if (this.callbacks.beforeChange(after, before) === false) {\n          shouldUpdate = false\n        } else {\n          shouldUpdate = true\n        }\n      }\n\n      if (shouldUpdate) {\n        // Check if the option exists in the store\n        // if not run addOption callback\n        if (!this.store.getOptionByID(elementID)) {\n          this.callbacks.addOption(option)\n        }\n\n        // Get values from after and set as selected\n        this.callbacks.setSelected(\n          after.map((o: Option) => o.id),\n          false\n        )\n\n        // Close dropdown unless using modifier keys in multi-select\n        // (mimics native multi-select behavior where you can keep selecting)\n        const isModifierKey = e.ctrlKey || e.metaKey || e.shiftKey // Cmd/Ctrl or Shift\n        const shouldClose = this.settings.closeOnSelect && !(this.settings.isMultiple && isModifierKey)\n\n        if (shouldClose) {\n          this.requestClose('select', {\n            option: storeOption,\n            selectionChanged: this.selectionChanged(before, after)\n          })\n        }\n\n        // callback that the value has changed\n        if (this.callbacks.afterChange) {\n          this.callbacks.afterChange(after)\n        }\n      }\n    })\n\n    return optionEl\n  }\n\n  public destroy(): void {\n    this.clearTypeahead()\n    this.stopPositionTracking()\n\n    if (this.modalElements) {\n      this.unlockBodyScroll()\n      if (this.content.main.parentElement === this.modalElements.dialog) {\n        this.restoreContentOffscreen()\n      }\n      this.modalElements.overlay.remove()\n      this.modalElements = null\n    } else if (this.bodyScrollLocked) {\n      this.unlockBodyScroll()\n    }\n\n    // Remove main\n    this.main.main.remove()\n\n    // Remove content\n    this.content.main.remove()\n\n    this.removeDetachedInstanceDom()\n  }\n\n  /** Remove any leftover main/content/modal nodes for this instance (e.g. on body). */\n  private removeDetachedInstanceDom(): void {\n    const id = this.settings.id\n    const mainClass = this.classes.getFirst('main')\n    const contentClass = this.classes.getFirst('content')\n    const modalClass = this.classes.getFirst('modalOverlay')\n\n    document.querySelectorAll<HTMLElement>(`[data-id=\"${id}\"]`).forEach((el) => {\n      if (\n        el.classList.contains(mainClass) ||\n        el.classList.contains(contentClass) ||\n        el.classList.contains(modalClass)\n      ) {\n        el.remove()\n      }\n    })\n  }\n\n  private highlightText(str: string, search: any, className: string) {\n    const searchTerm = search.trim()\n    if (searchTerm === '') {\n      return str\n    }\n\n    // Escape special regex characters in the search term to prevent regex injection\n    const escapedSearch = searchTerm.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n\n    // Create a temporary div to parse HTML and work with text nodes only\n    const tempDiv = document.createElement('div')\n    tempDiv.innerHTML = str\n\n    // Function to recursively process text nodes\n    const highlightTextNodes = (node: Node) => {\n      if (node.nodeType === Node.TEXT_NODE) {\n        const text = node.textContent || ''\n        const regex = new RegExp('(' + escapedSearch + ')', 'i')\n\n        if (regex.test(text)) {\n          // Create a temporary container for the highlighted content\n          const wrapper = document.createElement('span')\n          const parts = text.split(regex)\n\n          parts.forEach((part, index) => {\n            if (part && regex.test(part)) {\n              // This is the matched part - wrap it in mark\n              const mark = document.createElement('mark')\n              mark.className = className\n              mark.textContent = part\n              wrapper.appendChild(mark)\n            } else if (part) {\n              // This is not the matched part - keep as text\n              wrapper.appendChild(document.createTextNode(part))\n            }\n          })\n\n          // Replace the text node with the wrapper\n          node.parentNode?.replaceChild(wrapper, node)\n        }\n      } else if (node.nodeType === Node.ELEMENT_NODE) {\n        // Recursively process child nodes\n        Array.from(node.childNodes).forEach((child) => highlightTextNodes(child))\n      }\n    }\n\n    // Process all text nodes in the temporary div\n    Array.from(tempDiv.childNodes).forEach((node) => highlightTextNodes(node))\n\n    return tempDiv.innerHTML\n  }\n\n  private setContentDirection(direction: 'above' | 'below'): void {\n    const isAbove = direction === 'above'\n    const addClass = isAbove ? this.classes.dirAbove : this.classes.dirBelow\n    const removeClass = isAbove ? this.classes.dirBelow : this.classes.dirAbove\n\n    this.removeClasses(this.main.main, removeClass)\n    this.addClasses(this.main.main, addClass)\n    this.removeClasses(this.content.main, removeClass)\n    this.addClasses(this.content.main, addClass)\n\n    if (isAbove) {\n      const mainHeight = this.main.main.offsetHeight\n      const contentHeight = this.content.main.offsetHeight\n      this.content.main.style.margin = '-' + (mainHeight + contentHeight - 1) + 'px 0px 0px 0px'\n    } else {\n      this.content.main.style.margin = '-1px 0px 0px 0px'\n    }\n  }\n\n  private setContentPosition(): void {\n    const containerRect = this.main.main.getBoundingClientRect()\n\n    if (this.settings.contentPosition === 'relative') {\n      this.applyContentWidth(containerRect)\n      return\n    }\n\n    this.cancelOverflowShift()\n\n    let top: number\n    let left: number\n\n    if (this.settings.contentPosition === 'fixed') {\n      top = containerRect.top + containerRect.height\n      left = containerRect.left\n    } else {\n      top = containerRect.top + window.scrollY + containerRect.height\n      left = containerRect.left + window.scrollX\n    }\n\n    this.content.main.style.top = top + 'px'\n    this.content.main.style.left = left + 'px'\n\n    this.applyContentWidth(containerRect)\n\n    const knownWidth = this.getKnownContentWidth(containerRect)\n    if (knownWidth !== null) {\n      this.content.main.style.left = this.adjustLeftForOverflow(left, containerRect.left, knownWidth) + 'px'\n      return\n    }\n\n    // min/max/auto width needs one layout pass before measuring\n    this.overflowShiftRaf = requestAnimationFrame(() => {\n      this.overflowShiftRaf = 0\n      this.applyOverflowShiftFromMeasure()\n    })\n  }\n\n  private applyContentWidth(containerRect: DOMRect): void {\n    const cw = this.settings.contentWidth\n    this.content.main.style.width = ''\n    this.content.main.style.minWidth = ''\n    this.content.main.style.maxWidth = ''\n\n    if (!cw) {\n      if (this.settings.contentPosition !== 'relative') {\n        this.content.main.style.width = containerRect.width + 'px'\n      }\n      return\n    }\n\n    if (cw === 'auto') {\n      this.content.main.style.minWidth = containerRect.width + 'px'\n    } else if (cw.startsWith('>')) {\n      this.content.main.style.minWidth = cw.slice(1)\n    } else if (cw.startsWith('<')) {\n      this.content.main.style.maxWidth = cw.slice(1)\n    } else {\n      this.content.main.style.width = cw\n    }\n  }\n\n  private cancelOverflowShift(): void {\n    if (this.overflowShiftRaf) {\n      cancelAnimationFrame(this.overflowShiftRaf)\n      this.overflowShiftRaf = 0\n    }\n  }\n\n  /** Width in px when known before layout; null when width must be measured. */\n  private getKnownContentWidth(containerRect: DOMRect): number | null {\n    const cw = this.settings.contentWidth\n    if (!cw) {\n      return containerRect.width\n    }\n    if (cw.startsWith('>') || cw.startsWith('<') || cw.includes('%')) {\n      return null\n    }\n\n    const px = parseFloat(cw)\n    return Number.isNaN(px) ? null : px\n  }\n\n  private adjustLeftForOverflow(docLeft: number, viewportLeft: number, width: number): number {\n    const padding = 20\n    const contentRight = viewportLeft + width\n    if (contentRight <= window.innerWidth) {\n      return docLeft\n    }\n\n    const overflow = contentRight - (window.innerWidth - padding)\n    const newLeft = docLeft - overflow\n\n    if (this.settings.contentPosition === 'fixed') {\n      return Math.max(0, newLeft)\n    }\n    return Math.max(window.scrollX, newLeft)\n  }\n\n  private applyOverflowShiftFromMeasure(): void {\n    const contentRect = this.content.main.getBoundingClientRect()\n    const contentRight = contentRect.right\n    if (contentRight <= window.innerWidth) {\n      return\n    }\n\n    const padding = 20\n    const overflow = contentRight - (window.innerWidth - padding)\n    const currentLeft = parseFloat(this.content.main.style.left) || 0\n    const newLeft = currentLeft - overflow\n\n    if (this.settings.contentPosition === 'fixed') {\n      this.content.main.style.left = Math.max(0, newLeft) + 'px'\n    } else {\n      this.content.main.style.left = Math.max(window.scrollX, newLeft) + 'px'\n    }\n  }\n\n  public moveContentAbove(): void {\n    this.setContentDirection('above')\n    this.setContentPosition()\n  }\n\n  public moveContentBelow(): void {\n    this.setContentDirection('below')\n    this.setContentPosition()\n  }\n\n  public ensureElementInView(container: HTMLElement, element: HTMLElement): void {\n    const cTop = container.scrollTop + container.offsetTop\n    const cBottom = cTop + container.clientHeight\n    const eTop = element.offsetTop\n    const eBottom = eTop + element.clientHeight\n\n    if (eTop < cTop) {\n      container.scrollTop -= cTop - eTop\n    } else if (eBottom > cBottom) {\n      container.scrollTop += eBottom - cBottom\n    }\n  }\n\n  public putContent(): 'up' | 'down' {\n    const mainHeight = this.main.main.offsetHeight\n    const mainRect = this.main.main.getBoundingClientRect()\n    const contentHeight = this.content.main.offsetHeight\n    const spaceBelow = window.innerHeight - (mainRect.top + mainHeight)\n\n    if (spaceBelow <= contentHeight) {\n      if (mainRect.top > contentHeight) {\n        return 'up'\n      }\n      return 'down'\n    }\n\n    return 'down'\n  }\n\n  // Updates deselect based on item count and allowDeselect setting\n  public updateDeselectAll(): void {\n    if (!this.store || !this.settings) {\n      return\n    }\n    const selected = this.store.getSelectedOptions()\n    const hasSelectedItems = selected && selected.length > 0\n    const isMultiple = this.settings.isMultiple\n    const allowDeselect = this.settings.allowDeselect\n    const atMinSelected = this.isAtMinSelected()\n\n    const deselectButton = this.main.deselect.main\n    const hideClass = this.classes.hide\n\n    if (allowDeselect && !(isMultiple && !hasSelectedItems) && !atMinSelected) {\n      this.removeClasses(deselectButton, hideClass)\n    } else {\n      this.addClasses(deselectButton, hideClass)\n    }\n  }\n}\n","/**\n * Pure classification of MutationObserver records on the native <select>.\n *\n * Select.observeCall() uses these flags to decide which sync path to run\n * (class/disabled vs full structure vs selection-only). Keeping this logic\n * separate makes it testable without spinning up a full SlimSelect instance.\n */\n\n/** What changed in a single observer callback batch (flags can all be true). */\nexport interface MutationFlags {\n  /** Native select class attribute changed — sync to render styles only. */\n  classChanged: boolean\n  /** Native select title attribute changed — sync the tooltip onto the rendered control. */\n  titleChanged: boolean\n  /** Native select disabled attribute changed — enable/disable SlimSelect. */\n  disabledChanged: boolean\n  /**\n   * Options or optgroups were added, removed, or had attributes edited.\n   * Triggers a full structure sync (store + native DOM + render).\n   */\n  optgroupOptionChanged: boolean\n  /**\n   * Selection may have changed without a separate `change` event yet.\n   * Used when a newly added <option> is already the select's value.\n   */\n  selectionChanged: boolean\n}\n\n/**\n * Scan a MutationObserver batch and return which kinds of updates are needed.\n *\n * The observer watches the <select> with subtree: true, so mutations can\n * target the select itself or any child <option> / <optgroup>.\n */\nexport function classifyMutations(\n  mutations: MutationRecord[],\n  select: HTMLSelectElement\n): MutationFlags {\n  const flags: MutationFlags = {\n    classChanged: false,\n    titleChanged: false,\n    disabledChanged: false,\n    optgroupOptionChanged: false,\n    selectionChanged: false\n  }\n\n  for (const m of mutations) {\n    // Mutations directly on the <select> element\n    if (m.target === select) {\n      if (m.attributeName === 'disabled') {\n        flags.disabledChanged = true\n      }\n\n      if (m.attributeName === 'class') {\n        flags.classChanged = true\n      }\n\n      if (m.attributeName === 'title') {\n        flags.titleChanged = true\n      }\n\n      if (m.type === 'childList') {\n        // Detect \"add option and it becomes selected\" in one DOM update\n        // (e.g. appendChild + select.value = 'x'). Without this, we'd only\n        // run structure sync and miss that selection also changed.\n        for (const n of Array.from(m.addedNodes)) {\n          if (\n            n.nodeName === 'OPTION' &&\n            (n as HTMLOptionElement).value === select.value\n          ) {\n            flags.selectionChanged = true\n            break\n          }\n        }\n\n        // Any childList on the select means options were added/removed/replaced\n        flags.optgroupOptionChanged = true\n      }\n    }\n\n    // Attribute edits on options (selected, text, data-*) or optgroup changes\n    // bubble up as mutations on child nodes, not on the select itself\n    if (m.target.nodeName === 'OPTGROUP' || m.target.nodeName === 'OPTION') {\n      flags.optgroupOptionChanged = true\n    }\n  }\n\n  return flags\n}\n","import { copyOptionData, kebabCase, hasClassInTree, selectedIdsEqual } from './helpers'\nimport { classifyMutations } from './mutations'\nimport { Optgroup, Option } from './store'\n\nexport default class Select {\n  public select: HTMLSelectElement\n\n  // Mutation observer fields\n  public onValueChange?: (value: Option[]) => void\n  public onClassChange?: (classes: string[]) => void\n  public onTitleChange?: (title: string) => void\n  public onDisabledChange?: (disabled: boolean) => void\n  public onOptionsChange?: (data: (Option | Optgroup)[]) => void\n  public onLabelClick?: () => void\n\n  // Change observers\n  private listen: boolean = false\n  private observer: MutationObserver | null = null\n  private isUpdating: boolean = false\n  private pendingOptionsChange: (Option | Optgroup)[] | null = null\n\n  // Event handlers for preventing native select behavior (especially on iOS Safari)\n  private preventNativeSelect: ((e: Event) => void) | null = null\n  private preventNativeSelectMousedown: ((e: Event) => void) | null = null\n  private preventNativeSelectFocus: ((e: Event) => void) | null = null\n  private restoreAriaHiddenOnBlur: ((e: Event) => void) | null = null\n\n  constructor(select: HTMLSelectElement) {\n    this.select = select\n\n    this.valueChange = this.valueChange.bind(this)\n    // Add change event listener\n    this.select.addEventListener('change', this.valueChange, {\n      // allow bubbling of event\n      passive: true\n    })\n\n    // Initiate mutation observer\n    this.observer = new MutationObserver(this.observeCall.bind(this))\n\n    // Start listening for changes\n    this.changeListen(true)\n  }\n\n  public enable(): void {\n    this.select.disabled = false\n  }\n\n  public disable(): void {\n    this.select.disabled = true\n  }\n\n  public hideUI(): void {\n    this.select.tabIndex = -1\n    // Visually hide but keep focusable for form validation\n    // Use 1px dimensions so browser validation popup can display\n    this.select.style.position = 'absolute'\n    this.select.style.width = '1px'\n    this.select.style.height = '1px'\n    this.select.style.opacity = '0'\n    this.select.style.overflow = 'hidden'\n    this.select.style.pointerEvents = 'none'\n    // Remove any spacing or borders that could affect layout\n    this.select.style.margin = '0'\n    this.select.style.padding = '0'\n    this.select.style.borderWidth = '0'\n    // Clip to completely hide the 1px\n    this.select.style.clipPath = 'inset(50%)'\n    // Only apply aria-hidden if the select doesn't currently hold focus.\n    // Browsers (Chrome) block aria-hidden on a focused element and log a\n    // warning, since focus must not be hidden from assistive technology.\n    // If the select is focused right now, the blur handler below will\n    // apply aria-hidden once focus leaves the element.\n    if (document.activeElement !== this.select) {\n      this.select.setAttribute('aria-hidden', 'true')\n    }\n\n    // Prevent native select from opening when label is clicked (especially on iOS Safari)\n    // iOS Safari programmatically focuses/clicks the select when label is clicked,\n    // bypassing pointer-events: none, so we need to prevent these events\n    // Only add listeners if they haven't been added yet\n    if (!this.preventNativeSelect) {\n      this.preventNativeSelect = (e: Event) => {\n        e.preventDefault()\n        e.stopPropagation()\n        e.stopImmediatePropagation()\n      }\n\n      this.preventNativeSelectMousedown = (e: Event) => {\n        e.preventDefault()\n        e.stopPropagation()\n        e.stopImmediatePropagation()\n      }\n\n      this.preventNativeSelectFocus = (e: Event) => {\n        // Focus events are not cancelable, so the select may still end up\n        // focused (e.g. the browser focusing an invalid control during form\n        // validation, or a programmatic select.focus() call). Lift aria-hidden\n        // while the element holds focus so assistive technology isn't blocked\n        // from it; it gets restored by the blur handler.\n        this.select.removeAttribute('aria-hidden')\n        e.preventDefault()\n        e.stopPropagation()\n        e.stopImmediatePropagation()\n      }\n\n      // Re-apply aria-hidden once focus leaves the hidden select\n      this.restoreAriaHiddenOnBlur = () => {\n        this.select.setAttribute('aria-hidden', 'true')\n      }\n\n      // Add event listeners with capture phase to catch events before they reach the select\n      this.select.addEventListener('click', this.preventNativeSelect, {\n        capture: true,\n        passive: false\n      })\n      this.select.addEventListener('mousedown', this.preventNativeSelectMousedown, { capture: true, passive: false })\n      this.select.addEventListener('focus', this.preventNativeSelectFocus, {\n        capture: true,\n        passive: false\n      })\n      this.select.addEventListener('blur', this.restoreAriaHiddenOnBlur, {\n        capture: true,\n        passive: true\n      })\n    }\n  }\n\n  public showUI(): void {\n    this.select.removeAttribute('tabindex')\n    // Reset visual hiding styles\n    this.select.style.position = ''\n    this.select.style.width = ''\n    this.select.style.height = ''\n    this.select.style.opacity = ''\n    this.select.style.overflow = ''\n    this.select.style.pointerEvents = ''\n    this.select.style.margin = ''\n    this.select.style.padding = ''\n    this.select.style.borderWidth = ''\n    this.select.style.clipPath = ''\n    this.select.removeAttribute('aria-hidden')\n\n    // Remove event listeners that prevent native select behavior\n    if (this.preventNativeSelect) {\n      this.select.removeEventListener('click', this.preventNativeSelect, {\n        capture: true\n      })\n      this.preventNativeSelect = null\n    }\n    if (this.preventNativeSelectMousedown) {\n      this.select.removeEventListener('mousedown', this.preventNativeSelectMousedown, { capture: true })\n      this.preventNativeSelectMousedown = null\n    }\n    if (this.preventNativeSelectFocus) {\n      this.select.removeEventListener('focus', this.preventNativeSelectFocus, {\n        capture: true\n      })\n      this.preventNativeSelectFocus = null\n    }\n    if (this.restoreAriaHiddenOnBlur) {\n      this.select.removeEventListener('blur', this.restoreAriaHiddenOnBlur, {\n        capture: true\n      })\n      this.restoreAriaHiddenOnBlur = null\n    }\n  }\n\n  public changeListen(listen: boolean) {\n    this.listen = listen\n\n    // Start listening for changes\n    if (listen) {\n      if (this.observer) {\n        this.observer.observe(this.select, {\n          subtree: true, // subtree for optgroups options\n          childList: true, // children changes\n          attributes: true // attributes changes\n        })\n      }\n    }\n\n    // Stop listening for changes\n    if (!listen) {\n      if (this.observer) {\n        this.observer.disconnect()\n      }\n    }\n  }\n\n  // This function get triggers when the select value changes\n  // and will call the onValueChange function if it exists\n  public valueChange(ev: Event): boolean {\n    if (this.listen && this.onValueChange) {\n      this.onValueChange(this.getSelectedOptions())\n    }\n\n    // Allow bubbling back to other change event listeners\n    return true\n  }\n\n  private observeCall(mutations: MutationRecord[]): void {\n    // If we are not listening, do nothing.\n    if (!this.listen) {\n      return\n    }\n\n    // Pure classifier — separates class/disabled/structure/selection mutations\n    const {\n      classChanged,\n      titleChanged,\n      disabledChanged,\n      optgroupOptionChanged,\n      selectionChanged: initialSelectionChanged\n    } = classifyMutations(mutations, this.select)\n    let selectionChanged = initialSelectionChanged\n\n    // If class has changed then call the class change function\n    if (classChanged && this.onClassChange) {\n      this.onClassChange(this.select.className.split(' '))\n    }\n\n    // If title has changed then call the title change function\n    if (titleChanged && this.onTitleChange) {\n      this.onTitleChange(this.select.getAttribute('title') || '')\n    }\n\n    // If disabled has changed then call the disabled change function\n    if (disabledChanged && this.onDisabledChange) {\n      this.changeListen(false)\n      this.onDisabledChange(this.select.disabled)\n      this.changeListen(true)\n    }\n\n    // If optgroup or option has changed then call the select change function\n    if (optgroupOptionChanged) {\n      this.clearLeftoverHiddenDisplay(mutations)\n    }\n\n    if (optgroupOptionChanged && this.onOptionsChange) {\n      // If we're currently updating, queue this change to process after update completes\n      if (this.isUpdating) {\n        // Only queue if the select element actually has options (not empty from updateOptions clearing)\n        // Check the select element directly, not getData() which might return stale data\n        if (this.select.options.length > 0) {\n          const currentData = this.getData()\n          // Only queue if we have actual data\n          if (currentData.length > 0) {\n            this.pendingOptionsChange = currentData\n          }\n        }\n        if (selectionChanged) {\n          this.select.dispatchEvent(new Event('change'))\n        }\n        return\n      }\n\n      this.changeListen(false)\n      this.onOptionsChange(this.getData())\n      this.changeListen(true)\n\n      // Structure sync includes selection from getData(); skip redundant change event\n      selectionChanged = false\n    }\n\n    if (selectionChanged) {\n      this.select.dispatchEvent(new Event('change'))\n    }\n  }\n\n  // From the select element pull optgroup and options into data\n  public getData(): (Option | Optgroup)[] {\n    let data = []\n\n    // Loop through nodes and get data\n    const nodes = this.select.childNodes as any as HTMLOptGroupElement[] | HTMLOptionElement[]\n    for (const n of nodes) {\n      // Optgroup\n      if (n.nodeName === 'OPTGROUP') {\n        data.push(this.getDataFromOptgroup(n as HTMLOptGroupElement))\n      }\n\n      // Option\n      if (n.nodeName === 'OPTION') {\n        data.push(this.getDataFromOption(n as HTMLOptionElement))\n      }\n    }\n\n    return data\n  }\n\n  public getDataFromOptgroup(optgroup: HTMLOptGroupElement): Optgroup {\n    let data = {\n      id: optgroup.id,\n      label: optgroup.label,\n      selectAll: optgroup.dataset ? optgroup.dataset.selectall === 'true' : false,\n      closable: optgroup.dataset ? optgroup.dataset.closable : 'off',\n      options: []\n    } as Optgroup\n\n    const options = optgroup.childNodes as any as HTMLOptionElement[]\n    for (const o of options) {\n      if (o.nodeName === 'OPTION') {\n        data.options!.push(this.getDataFromOption(o as HTMLOptionElement))\n      }\n    }\n\n    return data\n  }\n\n  /**\n   * Clearing `hidden` must also drop leftover `style.display = none` from\n   * earlier rebuilds, or getDataFromOption still treats the option as hidden.\n   */\n  private clearLeftoverHiddenDisplay(mutations: MutationRecord[]): void {\n    for (const mutation of mutations) {\n      if (mutation.target.nodeName !== 'OPTION' || mutation.attributeName !== 'hidden') {\n        continue\n      }\n\n      const option = mutation.target as HTMLOptionElement\n      if (!option.hidden && option.style.display === 'none') {\n        option.style.display = ''\n      }\n    }\n  }\n\n  // From passed in option pull pieces of usable information\n  public getDataFromOption(option: HTMLOptionElement): Option {\n    // The hidden attribute is not guaranteed to set inline style.display.\n    // SlimSelect uses `display` to decide which options to show in the UI.\n    const isHidden = option.hidden || option.hasAttribute('hidden')\n\n    return {\n      id: option.id,\n      value: option.value,\n      text: option.text,\n      html: option.dataset && option.dataset.html ? option.dataset.html : '',\n      defaultSelected: option.defaultSelected,\n      selected: option.selected,\n      display: option.style.display !== 'none' && !isHidden,\n      disabled: option.disabled,\n      mandatory: option.dataset ? option.dataset.mandatory === 'true' : false,\n      placeholder: option.dataset.placeholder === 'true',\n      class: option.className,\n      style: option.style.cssText,\n      data: copyOptionData(option.dataset)\n    } as Option\n  }\n\n  public getSelectedOptions(): Option[] {\n    let options = []\n\n    // Loop through options and set selected\n    const opts = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]\n    for (const o of opts) {\n      if (o.nodeName === 'OPTGROUP') {\n        const optgroupOptions = o.childNodes as any as HTMLOptionElement[]\n        for (const oo of optgroupOptions) {\n          if (oo.nodeName === 'OPTION') {\n            const option = oo as HTMLOptionElement\n            if (option.selected) {\n              options.push(this.getDataFromOption(option))\n            }\n          }\n        }\n      }\n\n      if (o.nodeName === 'OPTION') {\n        const option = o as HTMLOptionElement\n        if (option.selected) {\n          options.push(this.getDataFromOption(option))\n        }\n      }\n    }\n\n    return options\n  }\n\n  public getSelectedValues(): string[] {\n    return this.getSelectedOptions().map((option) => option.value)\n  }\n\n  /** True when every value has a matching native <option> (empty list is vacuously true). */\n  public hasOptionValues(values: string[]): boolean {\n    if (values.length === 0) {\n      return true\n    }\n\n    const nativeValues = new Set(Array.from(this.select.options).map((option) => option.value))\n    return values.every((value) => nativeValues.has(value))\n  }\n\n  public setSelected(ids: string[]): void {\n    // Stop listening to changes\n    this.changeListen(false)\n\n    // Loop through options and set selected\n    const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]\n    for (const o of options) {\n      if (o.nodeName === 'OPTGROUP') {\n        const optgroup = o as HTMLOptGroupElement\n        const optgroupOptions = optgroup.childNodes as any as HTMLOptionElement[]\n        for (const oo of optgroupOptions) {\n          if (oo.nodeName === 'OPTION') {\n            const option = oo as HTMLOptionElement\n            option.selected = ids.includes(option.id)\n          }\n        }\n      }\n\n      if (o.nodeName === 'OPTION') {\n        const option = o as HTMLOptionElement\n        option.selected = ids.includes(option.id)\n      }\n    }\n\n    // Keep native value in sync for form validation and parent bindings\n    const selected = this.getSelectedOptions()\n    if (!this.select.multiple) {\n      this.select.value = selected.length === 1 ? selected[0].value : ''\n    }\n\n    // Fire native change listeners while observer is paused to avoid re-entrant sync\n    this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n    this.changeListen(true)\n  }\n\n  // Set selected options by value instead of id.\n  // SyncCoordinator uses this path — HTML option ids are often empty.\n  // This is useful when the id is not known\n  // and only the value is known\n  // but the value is not unique and can be duplicated\n  public setSelectedByValue(values: string[]): void {\n    // Stop listening to changes\n    this.changeListen(false)\n\n    // Loop through options and set selected\n    const options = this.select.childNodes as any as (HTMLOptGroupElement | HTMLOptionElement)[]\n    for (const o of options) {\n      if (o.nodeName === 'OPTGROUP') {\n        const optgroup = o as HTMLOptGroupElement\n        const optgroupOptions = optgroup.childNodes as any as HTMLOptionElement[]\n        for (const oo of optgroupOptions) {\n          if (oo.nodeName === 'OPTION') {\n            const option = oo as HTMLOptionElement\n            option.selected = values.includes(option.value)\n          }\n        }\n      }\n\n      if (o.nodeName === 'OPTION') {\n        const option = o as HTMLOptionElement\n        option.selected = values.includes(option.value)\n      }\n    }\n\n    const selected = this.getSelectedOptions()\n    if (!this.select.multiple) {\n      // Sync native value for form validation / Vue v-model\n      this.select.value = selected.length === 1 ? selected[0].value : ''\n    }\n\n    // Fire native change listeners while observer is paused to avoid re-entrant sync\n    this.select.dispatchEvent(new Event('change', { bubbles: true }))\n\n    this.changeListen(true)\n  }\n\n  public updateSelect(id?: string, style?: string, classes?: string[]): void {\n    // Stop listening to changes\n    this.changeListen(false)\n\n    // Update id, only if the id isnt already set\n    if (id) {\n      this.select.dataset.id = id\n    }\n\n    // Update style\n    if (style) {\n      this.select.style.cssText = style\n    }\n\n    // Update classes\n    if (classes) {\n      this.select.className = ''\n      classes.forEach((c) => {\n        if (c.trim() !== '') {\n          this.select.classList.add(c.trim())\n        }\n      })\n    }\n\n    // Start listening to changes\n    this.changeListen(true)\n  }\n\n  public updateOptions(data: (Option | Optgroup)[]): void {\n    // Don't update if data is empty (prevents clearing select when no data)\n    if (!data || data.length === 0) {\n      return\n    }\n\n    // Set updating flag FIRST to prevent mutation observer from processing during update\n    // This must be set before stopping listening so any queued mutations see the flag\n    this.isUpdating = true\n    this.pendingOptionsChange = null\n\n    // Stop listening to changes\n    this.changeListen(false)\n\n    // Option-list rebuilds (e.g. API search) must not fire change unless selection changes\n    const selectedBefore = this.getSelectedValues()\n\n    // Clear out select\n    this.select.innerHTML = ''\n\n    for (const d of data) {\n      if (d instanceof Optgroup) {\n        this.select.appendChild(this.createOptgroup(d))\n      }\n\n      if (d instanceof Option) {\n        this.select.appendChild(this.createOption(d))\n      }\n    }\n\n    // Only fire native change when the selected value(s) actually changed (#696)\n    if (!selectedIdsEqual(selectedBefore, this.getSelectedValues())) {\n      this.select.dispatchEvent(new Event('change', { bubbles: true }))\n    }\n\n    // Start listening to changes\n    this.changeListen(true)\n\n    // Clear updating flag\n    this.isUpdating = false\n\n    // Process any pending options change that was queued during the update\n    // Only process if it has data (don't process empty data from innerHTML clearing)\n    if (this.pendingOptionsChange !== null) {\n      const pending: (Option | Optgroup)[] = this.pendingOptionsChange\n      if (pending.length > 0 && this.onOptionsChange) {\n        this.pendingOptionsChange = null\n        // Process the queued change\n        this.changeListen(false)\n        this.onOptionsChange(pending)\n        this.changeListen(true)\n      } else {\n        // Clear pending if it was empty\n        this.pendingOptionsChange = null\n      }\n    }\n  }\n\n  public createOptgroup(optgroup: Optgroup): HTMLOptGroupElement {\n    const optgroupEl = document.createElement('optgroup')\n    optgroupEl.id = optgroup.id\n    optgroupEl.label = optgroup.label\n    if (optgroup.selectAll) {\n      optgroupEl.dataset.selectAll = 'true'\n    }\n    if (optgroup.closable !== 'off') {\n      optgroupEl.dataset.closable = optgroup.closable\n    }\n    if (optgroup.options) {\n      for (const option of optgroup.options) {\n        optgroupEl.appendChild(this.createOption(option as Option))\n      }\n    }\n    return optgroupEl\n  }\n\n  public createOption(info: Option): HTMLOptionElement {\n    const optionEl = document.createElement('option')\n    optionEl.id = info.id\n    optionEl.value = info.value\n    optionEl.textContent = info.text\n    if (info.html !== '') {\n      optionEl.setAttribute('data-html', info.html)\n    }\n    optionEl.defaultSelected = info.defaultSelected\n    optionEl.selected = info.selected // Explicitly set selected because defaultSelected: true sets selected to true\n    if (info.disabled) {\n      optionEl.disabled = true\n    }\n    if (!info.display) {\n      optionEl.hidden = true\n    } else {\n      optionEl.hidden = false\n    }\n    if (info.placeholder) {\n      optionEl.setAttribute('data-placeholder', 'true')\n    }\n    if (info.mandatory) {\n      optionEl.setAttribute('data-mandatory', 'true')\n    }\n    if (info.class) {\n      info.class.split(' ').forEach((optionClass: string) => {\n        optionEl.classList.add(optionClass)\n      })\n    }\n    if (info.data && typeof info.data === 'object') {\n      Object.keys(info.data).forEach((key) => {\n        optionEl.setAttribute('data-' + kebabCase(key), info.data[key])\n      })\n    }\n\n    return optionEl\n  }\n\n  // Find and handle labels associated with this select\n  public setupLabelHandlers(): void {\n    const labels: HTMLLabelElement[] = []\n\n    // Find labels that point to this select via 'for' attribute\n    const selectId = this.select.id\n    if (selectId) {\n      const labelsByFor = document.querySelectorAll<HTMLLabelElement>(`label[for=\"${selectId}\"]`)\n      labelsByFor.forEach((label) => labels.push(label))\n    }\n\n    // Find labels that wrap this select (label contains select)\n    let parent = this.select.parentElement\n    while (parent && parent !== document.body) {\n      if (parent.tagName === 'LABEL') {\n        labels.push(parent as HTMLLabelElement)\n        break\n      }\n      parent = parent.parentElement\n    }\n\n    // Remove duplicates\n    const uniqueLabels = Array.from(new Set(labels))\n\n    uniqueLabels.forEach((label) => {\n      // Skip if already handled\n      if ((label as any).__slimSelectLabelHandler) {\n        return\n      }\n\n      // Add click handler to label\n      const labelClickHandler = (e: MouseEvent) => {\n        const target = e.target as HTMLElement\n\n        // Check if click is on SlimSelect UI elements (main div or content)\n        const isSlimSelectElement = hasClassInTree(target, this.select.dataset.id!)\n\n        // Prevent default label behavior (focusing the select)\n        // This needs to happen for all clicks on the label or its children\n        // to prevent the browser from focusing the hidden select\n        e.preventDefault()\n        // e.stopPropagation() // dont stop propagation\n\n        // Only trigger the toggle if the click is NOT on SlimSelect elements\n        // This allows clicking label text/children to toggle, while wrapped SlimSelect handles its own clicks\n        if (!isSlimSelectElement && this.onLabelClick) {\n          this.onLabelClick()\n        }\n      }\n\n      // Store the handler on the label for cleanup later\n      ;(label as any).__slimSelectLabelHandler = labelClickHandler\n      label.addEventListener('click', labelClickHandler, {\n        capture: true,\n        passive: false\n      })\n    })\n  }\n\n  // Remove label handlers\n  public removeLabelHandlers(): void {\n    const labels: HTMLLabelElement[] = []\n\n    // Find labels that point to this select via 'for' attribute\n    const selectId = this.select.id\n    if (selectId) {\n      const labelsByFor = document.querySelectorAll<HTMLLabelElement>(`label[for=\"${selectId}\"]`)\n      labelsByFor.forEach((label) => labels.push(label))\n    }\n\n    // Find labels that wrap this select\n    let parent = this.select.parentElement\n    while (parent && parent !== document.body) {\n      if (parent.tagName === 'LABEL') {\n        labels.push(parent as HTMLLabelElement)\n        break\n      }\n      parent = parent.parentElement\n    }\n\n    // Remove duplicates\n    const uniqueLabels = Array.from(new Set(labels))\n\n    uniqueLabels.forEach((label) => {\n      const handler = (label as any).__slimSelectLabelHandler\n      if (handler) {\n        label.removeEventListener('click', handler, { capture: true })\n        delete (label as any).__slimSelectLabelHandler\n      }\n    })\n  }\n\n  public destroy() {\n    this.changeListen(false)\n\n    // Remove event change listener\n    this.select.removeEventListener('change', this.valueChange)\n\n    // Remove event listeners that prevent native select behavior\n    if (this.preventNativeSelect) {\n      this.select.removeEventListener('click', this.preventNativeSelect, {\n        capture: true\n      })\n      this.preventNativeSelect = null\n    }\n    if (this.preventNativeSelectMousedown) {\n      this.select.removeEventListener('mousedown', this.preventNativeSelectMousedown, { capture: true })\n      this.preventNativeSelectMousedown = null\n    }\n    if (this.preventNativeSelectFocus) {\n      this.select.removeEventListener('focus', this.preventNativeSelectFocus, {\n        capture: true\n      })\n      this.preventNativeSelectFocus = null\n    }\n    if (this.restoreAriaHiddenOnBlur) {\n      this.select.removeEventListener('blur', this.restoreAriaHiddenOnBlur, {\n        capture: true\n      })\n      this.restoreAriaHiddenOnBlur = null\n    }\n\n    // Disconnect observer and null\n    if (this.observer) {\n      this.observer.disconnect()\n      this.observer = null\n    }\n\n    // Remove label handlers\n    this.removeLabelHandlers()\n\n    // Remove dataset id from original select\n    delete this.select.dataset.id\n\n    // Show the original select\n    this.showUI()\n  }\n}\n","/**\n * Central sync pipeline for SlimSelect.\n *\n * All paths that change store, native <select>, or custom UI should go through\n * SyncCoordinator instead of calling setData/setSelected directly. This gives us:\n *   - One place to batch/coalesce updates\n *   - Lightweight selection sync (no full native DOM rebuild)\n *   - No-op skips when nothing actually changed\n *\n * Wired from SlimSelect: native observer → enqueue(native), public API → enqueue(api),\n * render callbacks → enqueue(ui).\n */\n\nimport Render from './render'\nimport Select from './select'\nimport Store, { Optgroup, Option } from './store'\nimport { dataStructureEqual, selectedIdsEqual } from './helpers'\n\n/** Where a change originated — affects batching and render behavior. */\nexport type ChangeSource = 'native' | 'ui' | 'api'\n\nexport interface SyncEvents {\n  afterChange?: (newVal: Option[]) => void\n  error?: (err: Error) => void\n  /** Consumer API search. When set, the store holds search hits while a search is active. */\n  search?: (\n    searchValue: string,\n    selected: Option[],\n    catalog?: (Option | Optgroup)[]\n  ) =>\n    | Promise<(Partial<Option> | Partial<Optgroup>)[]>\n    | (Partial<Option> | Partial<Optgroup>)[]\n}\n\n/**\n * A single unit of work in the sync queue.\n * Structure = replace option list; selection = change selected only; addOption = append one.\n */\nexport type SyncChange =\n  | {\n      type: 'structure'\n      data: (Partial<Option> | Partial<Optgroup>)[]\n      source: ChangeSource\n      /** Keep current selection when replacing data (async search results). */\n      preserveSelection?: boolean\n      /** API search results — do not update the catalog baseline. */\n      isSearchResult?: boolean\n    }\n  | {\n      type: 'selection'\n      values: string | string[]\n      source: ChangeSource\n      /** false when Vue/parent is pushing modelValue down (avoid emit loop). */\n      runAfterChange?: boolean\n    }\n  | { type: 'addOption'; option: Partial<Option>; source: ChangeSource }\n\nexport interface SyncDeps {\n  select: Select\n  store: Store\n  render: Render\n  events: SyncEvents\n  search?: (value: string) => void\n  onError?: (err: Error) => void\n}\n\n/** Skip structure sync when incoming data matches what's already in the store. */\nexport function shouldSkipStructureUpdate(\n  store: Store,\n  data: (Partial<Option> | Partial<Optgroup>)[]\n): boolean {\n  return dataStructureEqual(store.getData(false), data)\n}\n\n/**\n * Resolve setSelected() arguments to option ids.\n * Accepts either ids or values for backward compatibility.\n */\nexport function resolveSelectedIds(\n  store: Store,\n  values: string | string[]\n): string[] {\n  const valueList = Array.isArray(values) ? values : [values]\n  const options = store.getDataOptions(false)\n  const ids: string[] = []\n\n  for (const value of valueList) {\n    if (options.find((option) => option.id == value)) {\n      ids.push(value)\n      continue\n    }\n\n    // Value may match multiple options (duplicate values) — select all matches\n    for (const option of options.filter((option) => option.value == value)) {\n      ids.push(option.id)\n    }\n  }\n\n  return ids\n}\n\nexport default class SyncCoordinator {\n  private queue: SyncChange[] = []\n  private flushScheduled = false\n  /** True while applyChange is running — prevents re-entrant flush loops. */\n  public isSyncing = false\n\n  constructor(private deps: SyncDeps) {}\n\n  public enqueue(change: SyncChange): void {\n    this.queue.push(change)\n\n    // Native mutations often arrive in bursts from MutationObserver; coalesce\n    // them in one microtask so we render once per frame.\n    if (change.source === 'native') {\n      if (!this.flushScheduled) {\n        this.flushScheduled = true\n        queueMicrotask(() => this.flush())\n      }\n      return\n    }\n\n    // API/UI (setData, setSelected, clicks) should feel instant to callers.\n    // If we're already inside flush(), defer until the current batch finishes.\n    if (!this.isSyncing) {\n      this.flush()\n    }\n  }\n\n  /** Process everything in the queue. Callable from tests for deterministic native sync. */\n  public flush(): void {\n    this.flushScheduled = false\n\n    if (this.queue.length === 0) {\n      return\n    }\n\n    const batch = this.coalesceBatch(this.queue)\n    this.queue = []\n\n    this.isSyncing = true\n    try {\n      for (const change of batch) {\n        this.applyChange(change)\n      }\n    } finally {\n      this.isSyncing = false\n      // Changes enqueued during applyChange (e.g. async search) run next\n      if (this.queue.length > 0) {\n        this.flush()\n      }\n    }\n  }\n\n  /**\n   * Collapse a batch into the minimum work needed.\n   * Structure sync already includes selection from getData(), so drop redundant\n   * selection changes in the same batch. When multiple structure updates arrive,\n   * only the last one wins.\n   */\n  private coalesceBatch(changes: SyncChange[]): SyncChange[] {\n    const hasStructure = changes.some((c) => c.type === 'structure')\n    const hasAddOption = changes.some((c) => c.type === 'addOption')\n\n    if (hasStructure || hasAddOption) {\n      const structureChanges = changes.filter(\n        (c) => c.type === 'structure' || c.type === 'addOption'\n      )\n      const lastStructure = structureChanges[structureChanges.length - 1]\n\n      if (lastStructure?.type === 'structure') {\n        return [lastStructure]\n      }\n\n      return structureChanges\n    }\n\n    const selectionChanges = changes.filter((c) => c.type === 'selection')\n    if (selectionChanges.length > 0) {\n      return [selectionChanges[selectionChanges.length - 1]]\n    }\n\n    return changes\n  }\n\n  private applyChange(change: SyncChange): void {\n    switch (change.type) {\n      case 'structure':\n        this.applyStructure(\n          change.data,\n          change.source,\n          change.preserveSelection,\n          change.isSearchResult\n        )\n        break\n      case 'selection':\n        this.applySelection(\n          change.values,\n          change.source,\n          change.runAfterChange !== false\n        )\n        break\n      case 'addOption':\n        this.applyAddOption(change.option)\n        break\n    }\n  }\n\n  /**\n   * Full sync: store → native <select> rebuild → render values + options.\n   * Used when the option list itself changes (setData, native DOM edits).\n   * API search results update store + UI only — native select stays form/selection state.\n   */\n  private applyStructure(\n    data: (Partial<Option> | Partial<Optgroup>)[],\n    _source: ChangeSource,\n    preserveSelection = false,\n    isSearchResult = false\n  ): void {\n    const { store, select, render, events } = this.deps\n\n    // API search always shows \"Searching...\" first — even when results match the\n    // current store, we must re-render the UI so that placeholder is cleared (#695).\n    // Search hits stay out of the native <select> (form options update on selection).\n    if (!isSearchResult && shouldSkipStructureUpdate(store, data)) {\n      return\n    }\n\n    const selected = store.getSelected()\n\n    const err = store.validateDataArray(data)\n    if (err) {\n      if (events.error) {\n        events.error(err)\n      } else if (this.deps.onError) {\n        this.deps.onError(err)\n      }\n      return\n    }\n\n    store.setData(data, preserveSelection)\n    const dataClean = store.getData(false)\n\n    if (!isSearchResult) {\n      store.snapshotCatalog()\n    }\n\n    // Ephemeral API search pages must not rewrite the native <select>\n    if (!isSearchResult) {\n      select.updateOptions(dataClean)\n    }\n\n    render.renderValues()\n    render.renderOptions(dataClean)\n\n    if (events.afterChange && !selectedIdsEqual(selected, store.getSelected())) {\n      events.afterChange(store.getSelectedOptions())\n    }\n  }\n\n  /**\n   * Sync native <select> to current selection (form truth).\n   * When selected options are missing from the native DOM (e.g. picked from API\n   * search results), rebuild from selected options only — never from search hits.\n   */\n  private syncNativeSelection(): void {\n    const { store, select } = this.deps\n    const selectedOptions = store.getSelectedOptions()\n    const selectedValues = store.getSelectedValues()\n\n    if (!select.hasOptionValues(selectedValues)) {\n      if (selectedOptions.length > 0) {\n        select.updateOptions(selectedOptions)\n        return\n      }\n\n      // Empty selection with no matching native options: prefer catalog placeholder\n      const placeholder = store\n        .getCatalogData()\n        .find(\n          (item): item is Option =>\n            item instanceof Option && item.placeholder === true\n        )\n      if (placeholder) {\n        select.updateOptions([new Option({ ...placeholder, selected: true })])\n        return\n      }\n    }\n\n    // Use values on the native DOM — HTML option ids may be empty while store uses generated ids\n    select.setSelectedByValue(selectedValues)\n  }\n\n  /**\n   * Lightweight selection sync: flip option.selected on native DOM only.\n   * Avoids select.updateOptions() (innerHTML rebuild) for selection-only changes\n   * when the options already exist on the native select.\n   */\n  private applySelection(\n    values: string | string[],\n    _source: ChangeSource,\n    runAfterChange: boolean\n  ): void {\n    const { store, select, render, events } = this.deps\n\n    const selected = store.getSelected()\n    const ids = resolveSelectedIds(store, values)\n\n    if (selectedIdsEqual(selected, ids)) {\n      return\n    }\n\n    store.setSelectedBy('id', ids)\n    this.syncNativeSelection()\n    render.renderValues()\n\n    const searchValue = render.content.search.input.value.trim()\n    if (searchValue !== '') {\n      if (render.hasRenderedOptions()) {\n        render.updateOptionSelection()\n      } else if (this.deps.search) {\n        this.deps.search(searchValue)\n      }\n    } else if (render.canUpdateOptionSelectionInPlace()) {\n      render.updateOptionSelection()\n    } else {\n      render.renderOptions(store.getData(false))\n    }\n\n    if (\n      runAfterChange &&\n      events.afterChange &&\n      !selectedIdsEqual(selected, store.getSelected())\n    ) {\n      events.afterChange(store.getSelectedOptions())\n    }\n  }\n\n  /** Append a single option then full-sync native + render (same as legacy addOption). */\n  private applyAddOption(option: Partial<Option>): void {\n    const { store, select, render, events } = this.deps\n    const selected = store.getSelected()\n    const searchValue = render.content.search.input.value.trim()\n    // deps.search is always wired; only a consumer search event puts hits in the store\n    const isApiSearchOverlay = searchValue !== '' && !!events.search\n    const optionValue = option.value ?? option.text ?? ''\n\n    const optionExists = (data: (Option | Optgroup)[]): boolean => {\n      for (const item of data) {\n        if (item instanceof Optgroup) {\n          if (\n            item.options.some((opt) => (opt.value ?? opt.text) === optionValue)\n          ) {\n            return true\n          }\n          continue\n        }\n\n        if ((item.value ?? item.text) === optionValue) {\n          return true\n        }\n      }\n\n      return false\n    }\n\n    if (!optionExists(store.getData(false))) {\n      if (isApiSearchOverlay) {\n        const baseline = store.getCatalogData()\n        if (!optionExists(baseline)) {\n          store.setData([...baseline, new Option(option)], true)\n        }\n        store.snapshotCatalog()\n      } else {\n        store.addOption(option)\n        store.snapshotCatalog()\n      }\n    }\n\n    const data = store.getData(false)\n\n    // During API search, native select is form truth (selected options), not search hits\n    if (isApiSearchOverlay) {\n      const selectedOptions = store.getSelectedOptions()\n      if (selectedOptions.length > 0) {\n        select.updateOptions(selectedOptions)\n      }\n    } else {\n      select.updateOptions(data)\n    }\n\n    render.renderValues()\n    render.renderOptions(data)\n\n    if (events.afterChange && !selectedIdsEqual(selected, store.getSelected())) {\n      events.afterChange(store.getSelectedOptions())\n    }\n  }\n}\n","import CssClasses from './classes'\nimport { getAnimationTimeout } from './animations'\nimport GlobalEvents, { hasClassInTree } from './events'\nimport { debounce, getAssociatedLabelText } from './helpers'\nimport Lifecycle from './lifecycle'\nimport Render, { CloseInfo } from './render'\nimport Select from './select'\nimport Settings, { MODAL_MOBILE_BREAKPOINT } from './settings'\nimport Store, { Option, Optgroup } from './store'\nimport SyncCoordinator from './sync'\n\n// Export classes\nexport { Settings, Option, Optgroup, MODAL_MOBILE_BREAKPOINT }\nexport type { ModalSetting } from './settings'\n\n// Export interfaces from render\nexport type { Main, Content, Search, CloseInfo, CloseSource } from './render'\n\nexport interface Config {\n  select: string | Element\n  data?: (Partial<Option> | Partial<Optgroup>)[]\n  settings?: Partial<Settings>\n  cssClasses?: Partial<CssClasses>\n  events?: Events\n}\n\nexport interface Events {\n  search?: (\n    searchValue: string,\n    selected: Option[],\n    catalog?: (Option | Optgroup)[]\n  ) => Promise<(Partial<Option> | Partial<Optgroup>)[]> | (Partial<Option> | Partial<Optgroup>)[]\n  searchFilter?: (option: Option, search: string) => boolean\n  addable?: (\n    value: string\n  ) => Promise<Partial<Option> | string> | Partial<Option> | string | false | null | undefined | Error\n  beforeChange?: (newVal: Option[], oldVal: Option[]) => boolean | void\n  afterChange?: (newVal: Option[]) => void\n  beforeOpen?: () => void\n  afterOpen?: () => void\n  beforeClose?: (info: CloseInfo) => boolean | void\n  afterClose?: () => void\n  error?: (err: Error) => void\n}\n\nexport default class SlimSelect {\n  public selectEl: HTMLSelectElement\n\n  // Classes\n  public settings!: Settings\n  public cssClasses!: CssClasses\n  public select!: Select\n  public store!: Store\n  public render!: Render\n  public sync!: SyncCoordinator\n  public lifecycle!: Lifecycle\n  private globalEvents!: GlobalEvents\n  /** Invalidates in-flight API search responses when the query changes or clears. */\n  private searchGeneration = 0\n\n  // Events\n  public events = {\n    search: undefined,\n    searchFilter: (opt: Option, search: string) => {\n      return opt.text.toLowerCase().indexOf(search.toLowerCase()) !== -1\n    },\n    addable: undefined,\n    beforeChange: undefined,\n    afterChange: undefined,\n    beforeOpen: undefined,\n    afterOpen: undefined,\n    beforeClose: undefined,\n    afterClose: undefined\n  } as Events\n\n  constructor(config: Config) {\n    // Make sure you get the right element\n    this.selectEl = (\n      typeof config.select === 'string' ? document.querySelector(config.select) : config.select\n    ) as HTMLSelectElement\n    if (!this.selectEl) {\n      if (config.events && config.events.error) {\n        config.events.error(new Error('Could not find select element'))\n      }\n      return\n    }\n    if (this.selectEl.tagName !== 'SELECT') {\n      if (config.events && config.events.error) {\n        config.events.error(new Error('Element isnt of type select'))\n      }\n      return\n    }\n\n    // If select already has a slim select id on it lets destroy it first\n    if (this.selectEl.dataset.ssid) {\n      this.destroy()\n    }\n\n    // Set settings\n    this.settings = new Settings(config.settings)\n\n    // Allow data-selectall on the <select> when settings.selectAll is unset\n    if (config.settings?.selectAll === undefined && this.selectEl.dataset.selectall === 'true') {\n      this.settings.selectAll = true\n    }\n\n    // Set CSS classes\n    this.cssClasses = new CssClasses(config.cssClasses)\n\n    // Set events\n    const debounceEvents = ['beforeOpen', 'afterOpen', 'afterClose']\n    for (const key in config.events) {\n      // Check if key exists in events\n      if (!config.events.hasOwnProperty(key)) {\n        continue\n      }\n\n      // Check if key is in debounceEvents\n      if (debounceEvents.indexOf(key) !== -1) {\n        ;(this.events as { [key: string]: any })[key] = debounce((config.events as { [key: string]: any })[key], 100)\n      } else {\n        ;(this.events as { [key: string]: any })[key] = (config.events as { [key: string]: any })[key]\n      }\n    }\n\n    // Upate settings with type, style and classname\n    this.settings.disabled = config.settings?.disabled ? config.settings.disabled : this.selectEl.disabled\n    this.settings.isMultiple = this.selectEl.multiple\n    this.settings.style = this.selectEl.style.cssText\n    this.settings.class = this.selectEl.className.split(' ')\n\n    // Set select class\n    this.select = new Select(this.selectEl)\n    // Ensure the select has an id for label associations\n    if (!this.selectEl.id) {\n      this.selectEl.id = this.settings.id\n    }\n    this.select.updateSelect(this.settings.id, this.settings.style, this.settings.class)\n    this.select.hideUI() // Hide the original select element\n\n    this.select.onClassChange = (classes: string[]) => {\n      // Update settings with new class\n      this.settings.class = classes\n\n      // Run render updateClassStyles\n      this.render.updateClassStyles()\n    }\n    this.select.onTitleChange = (title: string) => {\n      // Keep the rendered control's tooltip in sync with the native select\n      this.render.updateTitle(title)\n    }\n    this.select.onDisabledChange = (disabled: boolean) => {\n      if (disabled) {\n        this.disable()\n      } else {\n        this.enable()\n      }\n    }\n\n    // Set up label click handler to toggle SlimSelect\n    // This allows clicking the label to open/close, matching the main div behavior\n    this.select.onLabelClick = () => {\n      if (!this.settings.disabled) {\n        this.settings.isOpen ? this.close({ source: 'toggle', selectionChanged: false }) : this.open()\n      }\n    }\n\n    // Set store class\n    const data = config.data ? config.data : this.select.getData()\n    this.store = new Store(this.settings.isMultiple ? 'multiple' : 'single', data)\n\n    // If data is passed update the original select element\n    if (config.data) {\n      this.select.updateOptions(this.store.getData())\n    }\n\n    // Set render renderCallbacks\n    const renderCallbacks = {\n      open: this.open.bind(this),\n      close: this.close.bind(this),\n      addable: this.events.addable ? this.events.addable : undefined,\n      // UI clicks route through SyncCoordinator (batched, avoids double updates)\n      setSelected: (values: string | string[], runAfterChange: boolean) => {\n        this.sync.enqueue({\n          type: 'selection',\n          values,\n          source: 'ui',\n          runAfterChange\n        })\n      },\n      addOption: (option: Partial<Option>) => {\n        this.sync.enqueue({\n          type: 'addOption',\n          option,\n          source: 'ui'\n        })\n      },\n      search: this.search.bind(this),\n      clearSearch: this.clearSearch.bind(this),\n      beforeChange: this.events.beforeChange,\n      afterChange: this.events.afterChange\n    }\n\n    // Setup render class\n    this.settings.modalTitle = config.settings?.modalTitle ?? getAssociatedLabelText(this.selectEl)\n\n    this.render = new Render(this.settings, this.cssClasses, this.store, renderCallbacks)\n\n    // Align JS timeout with --ss-animation-timing (CSS is source of truth)\n    this.settings.timeoutDelay = getAnimationTimeout(this.render.content.main, config.settings?.timeoutDelay)\n\n    // Single coordinator batches native + API + UI updates (see sync.ts)\n    this.sync = new SyncCoordinator({\n      select: this.select,\n      store: this.store,\n      render: this.render,\n      events: this.events,\n      search: this.search.bind(this)\n    })\n\n    this.select.onValueChange = (options: Option[]) => {\n      // Native <option> ids are often empty; store ids are generated at init\n      // and not written back unless updateOptions() runs. Prefer id, fall back\n      // to value so synthetic `select.value = x` + `change` still syncs.\n      this.sync.enqueue({\n        type: 'selection',\n        values: options.map((option) => option.id || option.value),\n        source: 'native'\n      })\n    }\n    this.select.onOptionsChange = (data: (Option | Optgroup)[]) => {\n      this.sync.enqueue({\n        type: 'structure',\n        data: data || [],\n        source: 'native'\n      })\n    }\n\n    // Open/close state machine — animation wait + outside-click attach timing\n    this.lifecycle = new Lifecycle(\n      {\n        beforeOpen: this.events.beforeOpen,\n        afterOpen: this.events.afterOpen,\n        beforeClose: (info) => this.events.beforeClose?.(info),\n        onClose: (info) => this.applyClose(info),\n        afterClose: () => {\n          this.render.clearDirectionClasses()\n          this.render.finalizeModalClose()\n          if (this.events.afterClose) {\n            this.events.afterClose()\n          }\n        },\n        onOpenReady: () => this.globalEvents.attachDocumentClick(),\n        onCloseReady: () => this.globalEvents.detachDocumentClick()\n      },\n      {\n        timeoutDelay: this.settings.timeoutDelay,\n        waitForAnimation: (phase, signal) => this.render.waitForAnimation(phase, signal)\n      }\n    )\n\n    // Resize/scroll/visibility listeners (document click via lifecycle onOpenReady)\n    this.globalEvents = new GlobalEvents({\n      onDocumentClick: this.documentClick.bind(this),\n      onWindowResize: () => {\n        if (!this.settings.isOpen && !this.settings.isFullOpen) {\n          return\n        }\n        this.render.moveContent()\n      },\n      onWindowScroll: () => {\n        if (!this.settings.isOpen && !this.settings.isFullOpen) {\n          return\n        }\n        this.render.moveContent()\n      },\n      onVisibilityChange: () => {\n        if (document.hidden) {\n          this.close({ source: 'api', selectionChanged: false })\n        }\n      }\n    })\n\n    this.render.renderValues()\n    this.render.renderOptions(this.store.getData(false))\n\n    // Add aria-label or aria-labelledby if exists\n    const selectAriaLabel = this.selectEl.getAttribute('aria-label')\n    const selectAriaLabelledBy = this.selectEl.getAttribute('aria-labelledby')\n\n    if (selectAriaLabel) {\n      this.render.main.main.setAttribute('aria-label', selectAriaLabel)\n    } else if (selectAriaLabelledBy) {\n      this.render.main.main.removeAttribute('aria-label')\n      this.render.main.main.setAttribute('aria-labelledby', selectAriaLabelledBy)\n    } else if (this.selectEl.labels && this.selectEl.labels.length > 0) {\n      const labelledByIds = Array.from(this.selectEl.labels).map((label, i) => {\n        if (!label.id) {\n          label.id = `${this.settings.id}-label-${i}`\n        }\n        return label.id\n      })\n      this.render.main.main.removeAttribute('aria-label')\n      this.render.main.main.setAttribute('aria-labelledby', labelledByIds.join(' '))\n    }\n\n    // Carry the native select's title attribute over to the rendered control so\n    // browser tooltips keep working (the original select is visually hidden)\n    this.render.updateTitle(this.selectEl.getAttribute('title'))\n\n    // Add render after original select element\n    if (this.selectEl.parentNode) {\n      this.selectEl.parentNode.insertBefore(this.render.main.main, this.selectEl.nextSibling)\n    }\n\n    this.globalEvents.attach({\n      listenScroll: this.settings.openPosition === 'auto'\n    })\n\n    // If disabled lets call it\n    if (this.settings.disabled) {\n      this.disable()\n    }\n\n    // If alwaysOpnen then open it\n    if (this.settings.alwaysOpen) {\n      this.open()\n    }\n\n    // Set up label handlers to open SlimSelect when label is clicked\n    this.select.setupLabelHandlers()\n\n    // Add SlimSelect to select element\n    ;(this.selectEl as any).slim = this\n  }\n\n  // Set to enabled and remove disabled classes\n  public enable(): void {\n    this.settings.disabled = false\n\n    this.select.enable()\n    this.render.enable()\n  }\n\n  // Set to disabled and add disabled classes\n  public disable(): void {\n    this.settings.disabled = true\n\n    this.select.disable()\n    this.render.disable()\n  }\n\n  public getData(): Option[] | Optgroup[] {\n    return this.store.getData()\n  }\n\n  public setData(data: (Partial<Option> | Partial<Optgroup>)[]): void {\n    // Batched structure sync — rebuilds native select, store, and option list\n    this.sync.enqueue({\n      type: 'structure',\n      data,\n      source: 'api'\n    })\n  }\n\n  public getSelected(): string[] {\n    let options = this.store.getSelectedOptions()\n    if (this.settings.keepOrder) {\n      options = this.store.selectedOrderOptions(options)\n    }\n    return options.map((option) => option.value)\n  }\n\n  // Will take in a string or array of strings and set the selected by either the id or value\n  public setSelected(values: string | string[], runAfterChange = true): void {\n    // Lightweight path — store + native + chips only (no full DOM rebuild)\n    this.sync.enqueue({\n      type: 'selection',\n      values,\n      source: 'api',\n      runAfterChange\n    })\n  }\n\n  public addOption(option: Partial<Option>): void {\n    this.sync.enqueue({\n      type: 'addOption',\n      option,\n      source: 'api'\n    })\n  }\n\n  public open(): void {\n    // Dont open if disabled\n    // Dont do anything if the content is already open\n    if (this.settings.disabled || this.settings.isOpen) {\n      return\n    }\n\n    // Cancel in-flight open/close animation wait (rapid toggle)\n    this.lifecycle.cancelPending()\n\n    // Tell render to open\n    this.render.open()\n\n    // Focus on input field only if search is enabled\n    if (this.settings.showSearch && this.settings.focusSearch) {\n      this.render.searchFocus()\n    }\n\n    this.settings.isOpen = true\n\n    // Sync isFullOpen/isOpen after CSS transition (or timeoutDelay fallback)\n    void this.lifecycle.requestOpen().then(() => {\n      // close() may have run before this async completion (e.g. closeOnSelect)\n      if (!this.settings.isOpen) {\n        return\n      }\n      this.settings.isFullOpen = this.lifecycle.isFullOpen\n      this.settings.isOpen = this.lifecycle.isOpen\n    })\n\n    // Reposition when trigger or ancestors resize (absolute content only)\n    if (this.settings.contentPosition === 'absolute' && !this.render.isModalViewActive()) {\n      this.render.startPositionTracking()\n    }\n\n    const searchValue = this.render.content.search.input.value.trim()\n    if (searchValue !== '') {\n      this.search(searchValue)\n    }\n  }\n\n  public close(info: CloseInfo = { source: 'api', selectionChanged: false }): void {\n    // Dont do anything if the content is already closed\n    // Dont do anything if alwaysOpen is true\n    if (!this.settings.isOpen || this.settings.alwaysOpen) {\n      return\n    }\n\n    void this.lifecycle.requestClose(info).then((closed) => {\n      if (!closed) {\n        return\n      }\n\n      // open() may have run before this async completion\n      if (this.settings.isOpen) {\n        return\n      }\n\n      this.settings.isOpen = this.lifecycle.isOpen\n      this.settings.isFullOpen = this.lifecycle.isFullOpen\n    })\n  }\n\n  /** Sync close — invoked by lifecycle after beforeClose approves. */\n  private applyClose(info: CloseInfo): void {\n    // Tell render to close\n    this.render.close()\n\n    // Clear search only if not empty and keepSearch is false\n    if (!this.settings.keepSearch && this.render.content.search.input.value !== '') {\n      this.sync.flush()\n      this.clearSearch() // Internal reset — must not fire the consumer search event\n    }\n\n    // If we arent tabbing focus back on the main element\n    const skipRefocus = info.source === 'outside' || info.source === 'toggle'\n    this.render.mainFocus(skipRefocus ? 'click' : null)\n\n    // Update settings\n    this.settings.isOpen = false\n    this.settings.isFullOpen = false\n\n    this.render.stopPositionTracking()\n  }\n\n  // Take in string value and search current options\n  public search(value: string): void {\n    const trimmed = value.trim()\n\n    if (trimmed === '') {\n      // Empty queries are forwarded to the consumer's search event, letting the\n      // callback decide what \"no search\" means (e.g. return the catalog baseline).\n      // Without a search event there is nothing to forward to, so local search\n      // resets to the catalog baseline via clearSearch() below.\n      this.render.content.search.input.value = ''\n    } else if (this.render.content.search.input.value !== value) {\n      // Sync programmatic search calls, but never strip spaces from user input\n      this.render.content.search.input.value = value\n    }\n\n    if (this.events.search) {\n      this.runApiSearch(trimmed)\n      return\n    }\n\n    if (trimmed === '') {\n      this.clearSearch()\n      return\n    }\n\n    this.runLocalSearch(trimmed)\n  }\n\n  /** Reset search state without invoking the consumer search event. */\n  private clearSearch(): void {\n    this.render.content.search.input.value = ''\n    this.searchGeneration++\n\n    if (!this.events.search && this.render.canFilterOptionsInPlace()) {\n      this.render.filterOptionsInPlace('', this.events.searchFilter!)\n      this.render.resetSearchFilterState()\n      return\n    }\n\n    this.render.resetSearchFilterState()\n    this.sync.enqueue({\n      type: 'structure',\n      data: this.store.getCatalogData(),\n      source: 'api',\n      preserveSelection: true\n    })\n  }\n\n  private runLocalSearch(value: string): void {\n    if (this.render.canFilterOptionsInPlace()) {\n      this.render.filterOptionsInPlace(value, this.events.searchFilter!)\n      return\n    }\n\n    const searchResults = this.store.search(value, this.events.searchFilter!)\n    this.render.renderOptions(searchResults)\n  }\n\n  private runApiSearch(value: string): void {\n    const generation = ++this.searchGeneration\n    this.render.renderSearching()\n\n    const searchResp = this.events.search!(value, this.store.getSelectedOptions(), this.store.getCatalogData())\n\n    const applyResults = (data: (Partial<Option> | Partial<Optgroup>)[]): void => {\n      if (generation !== this.searchGeneration) {\n        return\n      }\n      if (this.render.content.search.input.value.trim() !== value) {\n        return\n      }\n\n      this.sync.enqueue({\n        type: 'structure',\n        data,\n        source: 'api',\n        preserveSelection: true,\n        isSearchResult: true\n      })\n    }\n\n    if (searchResp instanceof Promise) {\n      searchResp.then(applyResults).catch((err: Error | string) => {\n        if (generation !== this.searchGeneration) {\n          return\n        }\n        this.render.renderError(typeof err === 'string' ? err : err.message)\n      })\n\n      return\n    }\n\n    if (Array.isArray(searchResp)) {\n      applyResults(searchResp)\n      return\n    }\n\n    this.render.renderError('Search event must return a promise or an array of data')\n  }\n\n  public destroy(): void {\n    this.lifecycle.destroy()\n\n    this.render.stopPositionTracking()\n\n    this.globalEvents.detach({\n      listenScroll: this.settings.openPosition === 'auto'\n    })\n\n    // Delete the store data\n    this.store.setData([])\n\n    // Remove the render\n    this.render.destroy()\n\n    // Show the original select element\n    this.select.destroy()\n\n    delete (this.selectEl as HTMLSelectElement & { slim?: SlimSelect }).slim\n  }\n\n  // Event listener for document click\n  private documentClick(e: Event): void {\n    // If the content is not open, there is no need to close it\n    if (!this.settings.isOpen) {\n      return\n    }\n\n    // Check if the click was on the content by looking at the parents\n    if (e.target && !hasClassInTree(e.target as HTMLElement, this.settings.id)) {\n      this.close({ source: 'outside', selectionChanged: false })\n    }\n  }\n}\n","function getTrigrams(str: string): string[] {\n  str = ` ${str.replace(/ +/g, \" \").trim().toLowerCase()} `;\n\n  const trigrams: string[] = [];\n  for (let i = 0; i < str.length - 2; ++i) {\n    const trigram = str.substring(i, i + 3);\n    if (trigram[1] === ' ')\n      continue;\n    trigrams.push(trigram);\n  }\n  return trigrams;\n}\n\nexport class TrigramMatcher {\n  private total;\n  private trigram_occ = new Map<string, number>();\n  private l = new Array<{ str: string; trigrams: string[] }>;\n\n  constructor(public strs: string[]) {\n    this.total = strs.length;\n\n    for (const str of strs) {\n      const trigrams = getTrigrams(str);\n      const s = new Set(trigrams);\n      for (const ut of s) {\n        const occ = this.trigram_occ.get(ut) || 0;\n        this.trigram_occ.set(ut, occ + 1);\n      }\n      const v = { str, trigrams };\n      this.l.push(v);\n    }\n  }\n\n  score(str: string) {\n    // for scoring, we ignore end-of-word trigrams, because we assume users don't complete their words\n    const trigrams = getTrigrams(str).filter(s => s[2] !== ' ');\n    const retval: Array<{ str: string; score: number }> = [];\n\n    for (const v of this.l) {\n      let score = 0;\n      for (const t of trigrams) {\n        const i = v.trigrams.indexOf(t);\n        if (i !== -1)\n          score += this.total / (this.trigram_occ.get(t) || 999999);\n      }\n      retval.push({ str: v.str, score });\n    }\n    return retval.toSorted((a, b) => (b.score - a.score)); //highest score first\n  }\n}\n\n/*\nconst prep = prepareMatcher([\n  `csg dingstede`,\n  `landstede`\n]);\n\n//console.log(scoreStuff(prep, 'lamdstede'));\n*/\n","import * as dompack from \"@webhare/dompack\";\nimport { SlimSelect } from \"@mod-utwente_design\";\nimport { setupValidator } from '@mod-publisher/js/forms';\nimport { getTid } from \"@webhare/gettid\";\nimport { requestGeoIP } from \"@mod-utwente_base/webdesigns/ws2016/src/shared/crm\";\nimport \"@mod-utwente_design/web/img/flags/flags.css\";\nimport \"./phone.scss\";\n\nclass PhoneField {\n  input: HTMLInputElement;\n  ss: SlimSelect;\n  phoneinput: HTMLInputElement;\n  countries: Array<{ code: string; title: string; phone: string }> = [];\n  mobileonly: boolean = false;\n\n  constructor(input: HTMLInputElement) {\n    this.input = input;\n    this.input.hidden = true;\n    this.mobileonly = this.input.dataset.mobileonly === \"1\";\n    this.input.addEventListener(\"input\", () => this.syncValueToCustomComponents());\n\n    const fieldgroup = this.input.closest(\".wh-form__fieldgroup\");\n    if (fieldgroup) // Mark fieldgroup so ut select pulldown is not applied\n      fieldgroup.classList.add(\"wh-form__fieldgroup--slimselect\");\n\n    const wrapper = <div class=\"phonefield-fieldswrapper\" />;\n    this.input.before(wrapper);\n\n    this.countries = JSON.parse(this.input.dataset.countries || '[]');\n    const countries = this.countries.map(country => ({\n      text: `${country.title} (+${country.phone})`,\n      value: country.code,\n      html: `<span class=\"utwente-flags utwente-flags-${country.code.toLowerCase()}\"></span><div class=\"title\">${country.title}</div><span class=\"phoneprefix\">+${country.phone}</span>`,\n    }));\n\n    const select = <select class=\"webform-utwente--phonefield__country\" /> as HTMLSelectElement;\n    wrapper.append(select);\n    this.ss = new SlimSelect({\n      select: select,\n      data: [\n        { text: \"\", label: \"\", value: \"\", data: { placeholder: \"true\" } },\n        ...countries\n      ],\n      events: {\n        afterChange: () => this.syncValueFromCustomComponents()\n      },\n      settings: {\n        modal: 'off', // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n        placeholderText: \"\"\n      },\n    });\n\n    this.phoneinput = <input type=\"tel\" class=\"webform-utwente--phonefield__input\" placeholder={this.input.placeholder} /> as HTMLInputElement;\n    this.phoneinput.value = this.input.value.replace(/[^0-9+\\s]/g, '').trim();\n    this.phoneinput.addEventListener(\"input\", () => this.syncValueFromCustomComponents());\n    this.phoneinput.addEventListener(\"change\", () => this.onChange());\n\n    if (this.input.value)\n      this.syncValueToCustomComponents();\n\n    wrapper.append(this.phoneinput);\n\n    setupValidator(this.input, inp => this.validatePhoneNumber(inp));\n\n    if (this.phoneinput.value === \"\")\n      void this.prefillCountryCode();\n    else\n      this.syncValueFromCustomComponents();\n  }\n\n  onChange() {\n    const matchcountry = this.countries.find(c => this.input.value.startsWith(`+${c.phone}`));\n    if (matchcountry) {\n      let phoneNumber = this.input.value.substring(matchcountry.phone.length + 1).trim();\n\n      if ([\"BE\", \"DE\", \"NL\"].includes(matchcountry.code)) {\n        while (phoneNumber.startsWith('0')) // Strip leading zeros, we will add one back later if needed\n          phoneNumber = phoneNumber.substring(1);\n        this.phoneinput.value = phoneNumber && !phoneNumber.startsWith('+') ? \"0\" + phoneNumber : phoneNumber;\n      } else {\n        this.phoneinput.value = phoneNumber;\n      }\n    }\n  }\n\n  validatePhoneNumber(inp: HTMLInputElement) {\n    const selectedCode = this.ss ? this.ss.getSelected() : [];\n    const countryCode = selectedCode.length ? selectedCode[0] : \"\";\n    const countryinfo = countryCode ? this.countries.find(c => c.code === countryCode) : \"\";\n    const phonePrefix = countryinfo ? `+${countryinfo.phone}` : '';\n    const digits = inp.value.replace(/[^0-9]/g, ''); // First check basic digit count\n\n    if (this.input.required) {\n      if (digits.length < 6 || digits.length > 15)\n        return getTid('utwente_base:frontend.ws2016.js.notavalidphonenumber');\n    } else {\n      if (phonePrefix !== \"\" && this.input.value === phonePrefix)\n        this.input.value = \"\";// Just country code, treat as empty\n\n      if (this.input.value !== \"\" && (digits.length < 6 || digits.length > 15))\n        return getTid('utwente_base:frontend.ws2016.js.notavalidphonenumber');\n    }\n\n    if (this.mobileonly && this.input.value !== \"\" && !this.isValidMobileNumber(countryCode, this.input.value))\n      return getTid('utwente_base:frontend.ws2016.js.notavalidmobilephonenumber');\n  }\n\n  isValidMobileNumber(countryCode: string, phoneNumber: string) {\n    // Just check for be,de,nl if mobileonly. See issue #2868\n    const chknumber = '+' + phoneNumber.replace(/[^0-9]/g, '');\n    if (countryCode === \"BE\") {\n      const regex = /^\\+324[56789]\\d{7}$/;\n      return regex.test(chknumber);\n    } else if (countryCode === \"DE\") {\n      const regex = /^\\+49[1-9]\\d{1,4}\\d{6,10}$/;\n      return regex.test(chknumber);\n    } else if (countryCode === \"NL\") {\n      const regex = /^\\+316\\d{8}$/;\n      return regex.test(chknumber);\n    }\n\n    return true; // For other countries we don't have specific rules, so just accept any number of digits\n  }\n\n  syncValueFromCustomComponents() {\n    const selectedCode = this.ss ? this.ss.getSelected() : [];\n    const countryCode = selectedCode.length ? selectedCode[0] : \"\";\n    const country = selectedCode.length ? this.countries.find(c => c.code === countryCode) : \"\";\n    let phonePrefix = country ? `+${country.phone}` : '';\n    let phoneNumber = this.phoneinput.value.replace(/[^0-9+\\s]/g, '').trim();\n    if (phoneNumber.startsWith('+')) {\n      const match = this.countries.find(c => phoneNumber.startsWith(`+${c.phone}`));\n      if (match) {\n        this.ss.setSelected(match.code, false);\n        phonePrefix = `+${match.phone}`;\n        phoneNumber = phoneNumber.substring(match.phone.length + 1).trim();\n        this.phoneinput.value = phoneNumber;\n      }\n    }\n\n    this.updatePlaceholderForCountry(countryCode);\n\n    if ([\"BE\", \"DE\", \"NL\"].includes(countryCode)) {\n      while (phoneNumber.startsWith('0')) // Strip leading zeros, we will add one back later if needed\n        phoneNumber = phoneNumber.substring(1);\n    }\n\n    const setValue = phoneNumber ? phonePrefix + phoneNumber : \"\";\n    if (this.input.value !== setValue)\n      dompack.changeValue(this.input, setValue);\n  }\n\n  updatePlaceholderForCountry(countryCode: string) {\n    if (countryCode === \"BE\")\n      this.phoneinput.placeholder = \"(0)470123456\";\n    else if (countryCode === \"DE\")\n      this.phoneinput.placeholder = \"(0)1701234567\";\n    else if (countryCode === \"NL\")\n      this.phoneinput.placeholder = \"(0)612345678\";\n  }\n\n  syncValueToCustomComponents() {\n    const matchcountry = this.countries.find(c => this.input.value.startsWith(`+${c.phone}`));\n    if (matchcountry) { //TODO deal with canada/us. do we have their country prefixes?\n      this.ss.setSelected(matchcountry.code, false);\n    } else {\n      this.syncValueFromCustomComponents();\n    }\n  }\n\n  async prefillCountryCode() {\n    const country = await requestGeoIP();\n    if (country && this.countries.find(c => c.code === country)) {\n      this.ss.selectEl.dataset.prefilledCountry = country;\n      this.ss.setSelected(country);\n    }\n  }\n}\n\ndompack.register<HTMLInputElement>(\".webform-utwente--phonefield input[name$='.phone'][data-countries]\", node => new PhoneField(node));\n","/* PLEASE NOTE - including @mod-publisher/js/forms is considered including the 'legacy form api'. It comes\n   without tree shaking support and autoregisters forms\n\n   @webhare/forms provides a tree-shakable implementation (but requires more setup). To switch please see dev module forms.ts\n  setupForms();\n*/\n\nimport './internal/requiredstyles.css';\nimport * as merge from './internal/merge';\nimport { setFieldError, setupValidator } from './internal/customvalidation';\nimport FormBase, { type FormSubmitEmbeddedResult } from './formbase';\nimport RPCFormBase from './rpc';\nimport { setupForms, registerHandler } from '@webhare/forms';\nimport { isLive } from '@webhare/env';\nimport { setupFormAnalytics } from '@webhare/frontend/src/pxl';\n\nexport { FormBase, RPCFormBase, setFieldError, setupValidator, type FormSubmitEmbeddedResult };\n\nexport const registerMergeFormatter = merge.registerFormatter;\n\ntype LegacyFormHandlerFactory = (form: HTMLFormElement) => FormBase;\n\nfunction legacyRegisterFormHandler(handlername: string, handler: LegacyFormHandlerFactory) {\n  registerHandler(handlername, (form: HTMLFormElement) => {\n    const createdForm = handler(form);\n    if (!isLive && createdForm instanceof FormBase && !(createdForm instanceof RPCFormBase)) {\n      console.warn(`Form handler for '${handlername}' is deriving from @mod-publisher/js/forms#FormBase - it should derive from RPCFormBase (In WH5.7+, the FormBase exported by @webhare/forms will *be* the RPCFormBase)`);\n    }\n    return createdForm as RPCFormBase;\n  });\n}\n\n/** @deprecated setup() is no longer needed */\nexport function setup(options: unknown) {\n}\n\n// We explicitly bind the 'publisher:form' forms to FormBase. The modern version doesn't distinguish between these anymore (and we want to move away from that difference anyawy, RPCBase isn't that much different)\nsetupForms({\n  handlers: { \"publisher:form\": form => new FormBase(form) as RPCFormBase }\n});\n\n// We assume if you're importing @mod-publisher/js/forms you don't know about having to do setupFormAnalytics to keep analytics in WH 5.7+\nsetupFormAnalytics();\n\nexport { legacyRegisterFormHandler as registerHandler };\n","/* eslint-disable @typescript-eslint/no-floating-promises -- FIXME: needs API rework */\n\n/** Generic support for .wh-form .wh-rtd--forminput */\nimport * as dompack from 'dompack';\n\n//we delay load the RTE, but we still need its styling - we don't have a delayed load for SCSS yet.\nimport '@mod-tollium/web/ui/components/richeditor/styling';\n\nimport type * as RichEditor from '@mod-tollium/web/ui/components/richeditor';\nimport type FreeEditor from '@mod-tollium/web/ui/components/richeditor/internal/free-editor';\nimport type StructuredEditor from '@mod-tollium/web/ui/components/richeditor/internal/structurededitor';\nimport type { ExternalStructureDef } from '@mod-tollium/web/ui/components/richeditor/internal/parsedstructure';\nimport type { EditorBaseOptions } from '@mod-tollium/web/ui/components/richeditor/internal/editorbase';\nimport type RPCFormBase from '../../rpc';\nimport type { RTEWidget } from '@mod-tollium/web/ui/components/richeditor/internal/types';\nimport { JSFormElement } from '@webhare/forms/src/jsformelement';\n\n//FIXME  Are we sure we want to have one control handling both Free and Structured RTD? does the form RPC currently even support Free? might remove 'as' below if we dont eg insertVideo...\n\nexport interface RTDFieldOptions {\n  /** options.onInsertVideo: function (node) - should return a promise resolving to an instance if the insertion is successful, or resolve to null if cancelled. receives the html rteedit node on which we're invoked */\n  onInsertVideo?: (node: HTMLElement) => void;\n  hidebuttons?: string[];\n  rtdoptions?: EditorBaseOptions;\n}\n\nexport class RTDEditElement extends JSFormElement<string> {\n  rte: FreeEditor | StructuredEditor | null = null;\n  // options: RTDFieldOptions;\n  // _fieldgroup: HTMLElement | null;\n  node;\n  onInsertVideo?: (node: HTMLElement) => void;\n\n  constructor() {\n    super();\n    this.node = this;\n    //@ts-expect-error cleanup registration\n    this.node.whRTDField = this;\n  }\n\n  async connectedCallback() {\n    const specifiedopts = JSON.parse(this.node.dataset.whRtdoptions || '{}') as { structure?: ExternalStructureDef };\n    const structure = specifiedopts.structure || null;\n    const hidebuttons = this.node.getAttribute(\"hidebuttons\")?.split(\" \") || [];\n\n    if (structure && !structure.blockstyles.some(style => style.type === \"table\"))\n      hidebuttons.push(\"table\");\n    hidebuttons.push('object-insert');\n    hidebuttons.push('action-showformatting');\n\n    // //We shouldn't be waiting to receive enable/disable until the RTD is there\n    // this._fieldgroup = this.node.closest(\".wh-form__fieldgroup\");\n    // if (this._fieldgroup) {\n    //   this.node.dataset.whFormStateListener = \"true\";\n    //   this.node.addEventListener('wh:form-enable', evt => this._handleEnable(evt));\n    // }\n\n    const rtdoptions: Partial<EditorBaseOptions> =\n    {\n      enabled: true,\n      readonly: false,\n      structure,\n      allowtags: null,//data.allowtags.length ? data.allowtags : null\n      hidebuttons: hidebuttons,\n      editembeddedobjects: false,\n      ...specifiedopts\n    };\n    //FIXME\n    //, onStatechange: this._onRTEStateChange.bind(this)\n    //FIXME\n    //, language: 'en'//parent.app.lang      // FIXME\n    //, log:true\n    //FIXME , structure: data.structure\n    //, csslinks: [data.cssurl]\n    //, cssinstance: data.cssinstance\n    //, breakupnodes: this.isemaileditor ? [ 'blockquote' ] : []\n    //, hidebuttons: hidebuttons\n    //, htmlclass: data.htmlclass\n    //, bodyclass: data.bodyclass\n    //, csscode: data.csscode\n\n    //Mark the UI as busy while we're loading the RTE\n    using lock = dompack.flagUIBusy();\n    void (lock);\n\n    const richeditor = await import('@mod-tollium/web/ui/components/richeditor') as typeof RichEditor;\n\n    this.rte = richeditor.createRTE(this.node, {\n      ...rtdoptions,\n      enabled: !this.disabled //initial enabled state\n    });\n\n    this.node.rte = this.rte;\n    //@ts-expect-error -- remove as soon as wh:richeditor-action is defined\n    this.node.addEventListener('wh:richeditor-action', evt => void this.executeAction(evt));\n    this.node.addEventListener('wh:richeditor-dirty', evt => dompack.dispatchCustomEvent(this.node, 'input', { bubbles: true, cancelable: false }));\n  }\n\n  get value(): string {\n    return this.rte ? this.rte.getValue() : this.node.innerHTML;\n  }\n\n  set value(newvalue: string) {\n    if (typeof newvalue !== 'string')\n      throw new Error(`Invalid value for RTE field: ${typeof newvalue}`);\n\n    if (this.rte)\n      this.rte.setValue(newvalue);\n    else\n      this.node.innerHTML = newvalue;\n  }\n\n  async executeAction(evt: CustomEvent<{ action: string }>) {\n    if (evt.detail.action === 'object-video' && this.onInsertVideo) {\n      evt.stopPropagation();\n      evt.preventDefault();\n      this.onInsertVideo(this.node);\n      return;\n    }\n  }\n\n  async insertVideoByURL(url: string) {\n    const formhandler = this.node.closest('form')?.propWhFormhandler;\n    if (!formhandler)\n      throw new Error(`RTE no longer associated with a form`);\n\n    const result = await (formhandler as RPCFormBase).invokeRPC(this.name + '.insertVideoByUrl', url) as { success: boolean; embeddedobject?: RTEWidget };\n    if (!result.success)\n      return { success: false, message: \"Video URL not understood\" };\n\n    (this.rte!.getEditor() as StructuredEditor).insertEmbeddedObject(result.embeddedobject!);\n    return { success: true };\n  }\n\n  set disabled(disable: boolean) {\n    super.disabled = disable;\n    this._updateEnabledStatus(!disable);\n  }\n  _updateEnabledStatus(nowenabled: boolean) {\n    this.rte?.setEnabled(nowenabled);\n    if (nowenabled)\n      this.node.removeAttribute(\"data-wh-form-disabled\");\n    else\n      this.node.setAttribute(\"data-wh-form-disabled\", \"\");\n  }\n\n  static getForNode(node: HTMLElement): RTDField | null {\n    //@ts-expect-error cleanup registration\n    return (node.whRTDField as RTDField) || null;\n  }\n}\n\nexport default class RTDField {\n  constructor(node: HTMLElement, options?: RTDFieldOptions) {\n    const hidebuttons = options?.hidebuttons || [];\n    if (!options?.onInsertVideo)\n      hidebuttons.push('object-video');\n    if (hidebuttons.length)\n      node.setAttribute(\"hidebuttons\", hidebuttons.join(\" \"));\n\n    customElements.whenDefined(\"wh-rtdedit\").then(() => {\n      if (options?.onInsertVideo) //TODO cleaner, use event handlers? RTD already has some action-eventhandler stuff though..\n        (node as RTDEditElement).onInsertVideo = options.onInsertVideo;\n    });\n\n    if (!customElements.get(\"wh-rtdedit\"))\n      customElements.define(\"wh-rtdedit\", RTDEditElement);\n  }\n}\n","/* eslint-disable @typescript-eslint/no-misused-promises, @typescript-eslint/no-floating-promises -- FIXME: needs API rework  */\n\nimport * as dompack from '@webhare/dompack';\nimport * as dialogapi from 'dompack/api/dialog';\nimport type { RTDEditElement } from './index';\nimport RPCFormBase from '../../rpc';\nimport { getFormService } from \"@webhare/forms/src/formservice\";\nimport type { FormSubmitEmbeddedResult } from '../../formbase';\n\nclass EmbedVideoForm extends RPCFormBase {\n  private dialog: dialogapi.DialogBase;\n  private rtd: RTDEditElement;\n\n  constructor(node: HTMLFormElement, dialog: dialogapi.DialogBase, rtd: RTDEditElement) {\n    super(node);\n    this.dialog = dialog;\n    this.rtd = rtd;\n  }\n\n  async onSubmitSuccess(result: FormSubmitEmbeddedResult<{\n    video: {\n      network: string;\n      videoid: string;\n    };\n  }>) {\n    if (result.video) {\n      this.rtd.insertVideoByURL('x-wh-embedvideo:' + result.video.network + ':' + result.video.videoid);\n      this.dialog.resolve(null);\n    }\n  }\n}\n\nexport async function insertVideo(rtd: HTMLElement) {\n  const formloadlock = dompack.flagUIBusy();\n  const formhandler = rtd.closest('form')?.propWhFormhandler;\n  if (!formhandler) {\n    console.error(\"Cannot find formhandler for node\", rtd);\n    throw new Error(\"Cannot find formhandler for RTD node\");\n  }\n  const formdata = await getFormService().requestBuiltinForm((formhandler as RPCFormBase).getRPCFormIdentifier(), 'rtd', 'embedvideo');\n\n  const dialog = dialogapi.createDialog();\n  dialog.contentnode!.innerHTML = formdata.html;\n\n  new EmbedVideoForm(dompack.qR(dialog.contentnode!, 'form'), dialog, rtd as RTDEditElement);\n  formloadlock.release();\n\n  await dialog.runModal();\n}\n","import \"./dialogs.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport \"./dialogs.lang.json\";\nimport { getTid } from \"@webhare/gettid\";\nimport PerfectScrollbar from \"@mod-utwente_design/vendor/perfect-scrollbar-wh\";\nimport * as dialog from 'dompack/components/dialog';\nimport * as dialogapi from 'dompack/api/dialog';\nimport \"../styledscrollbar.css\"; // native styled scrollbar\n\nconst lang = document.documentElement.lang.split(\"-\")[0];\n\nexport interface UTDialogOptions {\n  allowcancel?: boolean;\n  nativescroll?: boolean;\n  messageboxclassbase?: string;\n}\n\n// setup dialog box. note that the options here are also used by runMessageBox\ndialogapi.setupDialogs(options => new UTDialog(options), { messageboxclassbase: 'wh-form__' });\n\nexport async function runYesNoMessageBox(question: string) {\n  //support linefeeds\n  const node = <span>{question.split('\\n').map(n => [n, <br />])}</span>;\n  return dialogapi.runMessageBox(node, [\n    { result: \"yes\", title: getTid(\"utwente_base:site-common.texts.yes\") },\n    { result: \"no\", title: getTid(\"utwente_base:site-common.texts.no\") }\n  ], { allowcancel: true });\n}\n\nexport class UTDialog extends dialog.BasicDialog {\n  utheadernode = <div class=\"ut-dialog__header\"></div>;\n  ps: PerfectScrollbar | undefined;\n\n  constructor(options?: UTDialogOptions) {\n    super('ut-dialog', options);\n\n    if (options && options.allowcancel) {\n      const closebtn = <button class=\"ut-dialog--isclose ut-dialog__closeicon UT-icon-UT_icon_47_cross-16px\"\n        onClick={(evt: MouseEvent) => { dompack.stop(evt); this.resolve(\"close\"); }}\n        aria-label={getTid(\"utwente_base:frontend.ws2016.js.dialog-close-arialabel\")}\n        type=\"button\"></button>;\n      this.holdernode.appendChild(closebtn);\n    }\n\n    this.contentnode!.before(this.utheadernode);\n\n    if (!options || !options.nativescroll)\n      this.ps = new PerfectScrollbar(this.contentnode!, {\n        // swipePropagation: false,\n        wheelPropagation: false,\n        suppressScrollX: true\n      });\n\n    const observer = new ResizeObserver(() => this._checkContents());\n    observer.observe(this.contentnode!);\n  }\n\n  afterShow() {\n    //basic animation\n    void (this.holdernode.clientHeight);//force css update\n    this.holdernode.classList.add(\"ut-dialog--aftershow\");\n\n    // We must either set focus to the new content or use aria-live to announce the new content.\n    // Otherwise the screenreader user may not know something has happened at all.\n    this.holdernode.setAttribute(\"tabindex\", \"-1\");\n    (this.holdernode as HTMLElement).focus();\n\n    dompack.registerMissed(this.holdernode);\n\n    if (this.ps)\n      setTimeout(() => this.ps!.update(), 510); //update scrollbare after animation\n  }\n\n  _checkContents() {\n    const contentnode = this.contentnode! as HTMLElement;\n    // add the bottom 30px if the popup would need to scroll\n    (this.holdernode.parentNode as HTMLElement)/*this.modalitynode*/.classList.toggle(\"ut-dialog--scrollable\", contentnode.scrollHeight > contentnode.offsetHeight);\n    if (this.ps) // Update perfect scrollbar\n      this.ps.update();\n  }\n}\n\nfunction clickOutsideElement(element: HTMLElement, event: MouseEvent) {\n  const rect = element.getBoundingClientRect();\n\n  return (\n    event.clientX < rect.left ||\n    event.clientX > rect.right ||\n    event.clientY < rect.top ||\n    event.clientY > rect.bottom\n  );\n}\n// New dialog implementation using native <dialog> element\nexport class utDialog2 {\n  dialognode: HTMLDialogElement;\n  name: string;\n  _timer: ReturnType<typeof setTimeout> | undefined;\n  constructor(contentnode: HTMLElement, name: string, options: { classname?: string; onClose?: () => void } = {}) {\n    this.name = name;\n    this.dialognode = <dialog class={\"utdialog2-dialog \" + this.name + \"-dialog \" + (options.classname ? options.classname : \"\")} />;\n    contentnode.classList.add(this.name + \"-dialog__inner\", \"styledscrollbar-y\", \"utdialog2-dialog__inner\");\n    this.dialognode.appendChild(contentnode);\n    document.body.appendChild(this.dialognode);\n\n    dompack.registerMissed(contentnode);\n\n    this.dialognode.appendChild(<button type=\"button\" data-action=\"close\" aria-label={getTid(\"utwente_base:frontend.ws2016.js.dialog-close-arialabel\")} class={\"utdialog2-dialog__close \" + this.name + \"-dialog__close\"}></button>);\n    this.dialognode.addEventListener(\"click\", ev => { // click outside dialog or on close button\n      const targetnode = ev.target as HTMLElement;\n\n      // Directly check for clicking outside the visible dialog or close button\n      // (don't check whether the click landed in our visual dialog (&__inner)\n      // because some password managers insert their prefill buttons as direct child in the <dialog>)\n      if (targetnode.closest(\"[data-action='close']\") || clickOutsideElement(this.dialognode, ev))\n        this.dialognode?.close();\n    });\n\n    this.dialognode.addEventListener(\"close\", () => {\n      if (options.onClose)\n        options.onClose();\n\n      clearTimeout(this._timer);\n      if (this.dialognode) {\n        this.dialognode.classList.remove(\"utdialog2-dialog--aftershow\", this.name + \"-dialog--aftershow\");\n        this._timer = setTimeout(() => {\n          if (this.dialognode)\n            this.dialognode.remove();\n        }, 300);\n      }\n    });\n  }\n\n  showModal() {\n    if (this.dialognode.open)\n      return;// already open\n\n    this.dialognode.showModal();\n    this.dialognode.classList.add(\"utdialog2-dialog--aftershow\", this.name + \"-dialog--aftershow\");\n  }\n}\n\n\nlet overlaylayer: HTMLElement | null = null;\n\nwindow.addEventListener(\"dompack:busymodal\", ev => {\n  const waittext = lang === 'nl' ? 'Een ogenblik geduld...' : lang === 'de' ? 'Bitte warte einen Moment...' : 'Please wait a moment...';\n\n  overlaylayer ||= <div class=\"rpc__overlay ut-spinner--showembeddedspinner\">\n    <div class=\"rpc__overlaywait\">\n      <span class=\"rpc__spinner\">\n        <span class=\"ut-spinner2\"></span>\n      </span>\n      {waittext}\n    </div>\n  </div>;\n\n  if (ev.detail.show) {\n    document.body.appendChild(overlaylayer!);\n    void (overlaylayer!.clientHeight); // force css update so fadein/delay works\n    overlaylayer!.classList.add(\"rpc__overlay--visible\");\n  } else {\n    overlaylayer!.classList.remove(\"rpc__overlay--visible\");\n    document.body.removeChild(overlaylayer!);\n  }\n});\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/webdesigns/ws2026/shared/forms/dialogs.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_base\",\"nl\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accepteer\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"Om deze functionaliteit te gebruiken:\",\"no\":\"Nee\",\"yes\":\"Ja\"}}});\nregisterTexts(\"utwente_base\",\"en\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\nregisterTexts(\"utwente_base\",\"de\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"akzeptieren\",\"cookies-cookies\":\"Cookies\",\"cookies-touse\":\"Zur Nutzung dieser Funktion:\",\"no\":\"Nein\",\"yes\":\"Ja\"}}});\nregisterTexts(\"utwente_base\",\"es\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\nregisterTexts(\"utwente_base\",\"it\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\nregisterTexts(\"utwente_base\",\"xt\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/it.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/xt.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n","import * as dompack from '../../index';\nimport * as dialogapi from '../../api/dialog';\n\ninterface DialogOptions extends dialogapi.DialogOptions {\n  theme?: string;\n}\n\nexport class BasicDialog extends dialogapi.DialogBase {\n  private _dialogclass: string;\n  holdernode: Element;\n  modalitynode: Element;\n\n  constructor(classname: string, options?: DialogOptions) {\n    super(options);\n    this._dialogclass = classname;\n\n    this.contentnode = dompack.create('div', { className: this._dialogclass });\n    this.holdernode = dompack.create('div',\n      {\n        className: this._dialogclass + \"__holder\",\n        childNodes: [this.contentnode]\n      });\n    this.modalitynode = dompack.create('div',\n      {\n        className: this._dialogclass + \"__modalbg\",\n        childNodes: [this.holdernode],\n        on: {\n          click: (evt: MouseEvent) => this._onModalityClick(evt),\n          wheel: (evt: WheelEvent) => dompack.stop(evt) //prevent scrolling modal-covered site using mousewheel\n        }\n      });\n\n    if (options?.theme)\n      this.modalitynode.classList.add(options.theme);\n  }\n\n  _openDialog() {\n    document.body.appendChild(this.modalitynode);\n  }\n\n  closeDialog() {\n    this.modalitynode.remove();\n    super.closeDialog();\n  }\n\n  _onModalityClick(evt: MouseEvent) {\n    if (this.holdernode.contains(evt.target as Node))\n      return; //event was targetted at our holder\n\n    dompack.stop(evt);\n    if (this.options.allowcancel)\n      this.resolve(null);\n  }\n\n  afterShow() {\n    dompack.registerMissed(this.holdernode);\n  }\n}\n\nexport function createDialog(classname: string, options?: DialogOptions) {\n  return new BasicDialog(classname, options);\n}\n","import * as dompack from \"dompack\";\n\n/*\n   https://gitlab.webhare.com/utwente/utwente_base/-/issues/1076\n\n   hyperlinks in forms after the first question but before submission, should open in a new window\n*/\n\nfunction shouldOpenInNewWindow(link: HTMLAnchorElement) {\n  const page = link.closest<HTMLElement>(\".wh-form__page\");\n  if (!page)\n    return false;\n  if (page.dataset.whFormPagerole === \"thankyou\")\n    return false; //this is the conclusion, stay on page\n  if (page.parentNode?.querySelectorAll(\".wh-form__page\")[0] !== page)\n    return true; //we are not the first page, so open in new window!\n\n  //we are on the first page... is there any question before our text ?\n  const ourtextnode = link.closest<HTMLElement>(\".wh-form__fieldgroup\");\n  if (!ourtextnode)\n    return false; //confused about where this link came from\n\n  for (let node = ourtextnode as Element | null; node; node = node.previousElementSibling) {\n    //is this a fieldgroup but not RTE/grouphader?\n    if (node.classList.contains(\"wh-form__fieldgroup\")\n      && !node.classList.contains(\"wh-form__fieldgroup--richtext\")\n      && !node.classList.contains(\"wh-form__fieldgroup--group\"))\n      return true; //then we're after a question.. so new window is a go!\n  }\n\n  return false;\n}\nfunction checkNewWindowLink(link: HTMLAnchorElement) {\n  if (shouldOpenInNewWindow(link))\n    link.target = \"_blank\";\n}\n\nexport function setupFormLinkHandling() {\n  dompack.register<HTMLAnchorElement>(\"form.wh-form a[href]\", checkNewWindowLink);\n}\n","import RPCFormBase from \"@mod-publisher/js/forms/rpc\";\nimport { getReferralInfo } from \"@mod-utwente_base/webdesigns/ws2016/src/shared/crm/referralinfo\";\nimport { getLang } from \"@webhare/dompack\";\n\nexport class UTRPCFormBase extends RPCFormBase {\n  async getFormExtraSubmitData() {\n    return {\n      ...await super.getFormExtraSubmitData(),\n      referralinfo: getReferralInfo(),\n      targetinterest: document.documentElement.dataset.targetinterest || '',\n      targetlanguage: getLang().language\n    };\n  }\n}\n","import \"./ctabuttonsbar.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport type { UTDialog } from \"../shared/forms/dialogs\";\n\n/*\nControls sticky cta bar behavior and layout of the last cta button.\nIf there is no managed cta with a button visible, the last button in the cta bar will be styled as a primary button (theme background/arrow).\n*/\n\nclass StickyCTAbar {\n  node: HTMLElement;\n  y: number = 0;\n  isSticky: boolean = false;\n  ctablock: HTMLElement | null = null;\n  managedcta: HTMLElement | null = null;\n  ctabar: HTMLElement | null = null;\n  ctabtns: HTMLElement[] = [];\n\n  constructor(node: HTMLElement) {\n    this.node = node;\n\n    window.addEventListener(\"scroll\", () => this.onScroll(), { passive: true });\n    window.addEventListener(\"load\", () => this.onResize());\n    window.addEventListener(\"resize\", () => this.onResize());\n    document.addEventListener(\"ws:programmedetailsheader-toggle\", () => this.onResize());\n    document.fonts.ready.then(() => this.onResize()).catch(e => console.error(e));\n    this.onResize();\n    this.ctablock = dompack.qS(\".page-contentheader__bottomctacontainer\");\n    if (this.ctablock) {\n      this.ctabtns = dompack.qSA(this.ctablock, \".ctabutton-with-rightarrow\");\n      this.managedcta = dompack.qS(this.ctablock, \".managedcta\");\n\n      this.checkCTAVisibility();\n\n      new MutationObserver(() => this.checkCTAVisibility()).observe(this.ctablock, { subtree: false, attributes: true, characterData: false });\n      if (this.managedcta)\n        new MutationObserver(() => this.checkCTAVisibility()).observe(this.managedcta, { subtree: false, attributes: true, characterData: false });\n    } else {\n      this.node.classList.add(\"page-contentheader__ctabuttonsbar--showprimary\");\n    }\n  }\n\n  checkCTAVisibility() {\n    if (this.managedcta && this.ctablock) {\n      this.ctablock.hidden = false; // set visible first to measure correctly\n      this.ctablock.hidden ||= this.managedcta.offsetParent === null; // Check if managedcta is hidden\n    }\n\n    let btnvisible = false;\n    if (!this.ctablock!.hidden) {\n      this.ctabtns.forEach(btn => {\n        btnvisible ||= btn.offsetParent !== null;\n        if (btn.closest(\".has-expired-countdown\") && btn.closest(\".header-countdown-inprogress\"))\n          btnvisible = false;\n      });\n    }\n\n    this.node.classList.toggle(\"page-contentheader__ctabuttonsbar--showprimary\", !btnvisible);\n  }\n\n  onResize() {\n    this.node.classList.remove(\"page-contentheader__ctabuttonsbar--sticky\"); // first reset\n    this.isSticky = false;\n    this.y = this.node.getBoundingClientRect().top + window.scrollY - 61; // 61px = height of main nav + 1px border\n\n    this.onScroll();\n  }\n\n  onScroll() {\n    const sticky = window.scrollY > this.y;\n    if (sticky === this.isSticky) return;\n\n    this.isSticky = sticky;\n    this.node.classList.toggle(\"page-contentheader__ctabuttonsbar--sticky\", sticky);\n  }\n}\n\n// Catch clicks on brochure request buttons to open the dialog with the brochure request form\ndompack.register<HTMLTemplateElement>(\"#dialog-brochurerequestform-template\", template => {\n  const brochurewidget = dompack.qS(template.content, \".brochurerequestform-container\");\n  if (brochurewidget) {\n    brochurewidget.classList.add(\"wh-form--labelleft\");\n    dompack.qSA(brochurewidget, \".wh-form\").forEach(form => form.classList.add(\"largedialog\")); // make sure forms in the template are visible for screenreaders\n    dompack.qSA(\".page-contentheader__ctabuttonsbar__button--brochure\").forEach(btn => {\n      btn.addEventListener(\"click\", () => {\n        const dialog = dialogapi.createDialog({ allowcancel: true, borrow: brochurewidget }) as UTDialog;\n        dialog.contentnode?.classList.add(\"ut-dialog--large\");\n        void dialog.runModal();\n      });\n    });\n  } else {\n    const formwidget = dompack.qS(template.content, \".widget-wh-form\");\n    if (formwidget) {\n      formwidget.classList.add(\"largedialog\"); // make sure forms in the template are visible for screenreaders\n      dompack.qSA(\".page-contentheader__ctabuttonsbar__button--brochure\").forEach(btn => {\n        btn.addEventListener(\"click\", () => {\n          const dialog = dialogapi.createDialog({ allowcancel: true, borrow: formwidget }) as UTDialog;\n          dialog.contentnode?.classList.add(\"ut-dialog--large\");\n          void dialog.runModal();\n        });\n      });\n    }\n  }\n});\n\ndompack.register(\".page-contentheader__ctabuttonsbar\", node => new StickyCTAbar(node));\n","import \"./contentheader.css\";\nimport \"./ctabuttonsbar\";\n\nimport * as dompack from \"@webhare/dompack\";\nimport * as videotools from \"@mod-utwente_base/webdesigns/ws2016/src/components/video\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/managed-cta/\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/shared/addthisevent/\";\nimport \"@mod-utwente_base/webfeatures/utcomponents/countdown/countdown2026\";\n\nimport { fadeInOutSlides } from \"../shared/slidesanimation\";\n\nconst videoSlideTimeout = 8000;\nconst videoClass = \"page-contentheader__video\";\nconst breakpoint_deeplinks = \"750px\";\n\nclass videoSlideShow {\n  videos: Array<{ node: HTMLDivElement; player: HTMLVideoElement | null }>;\n  curVideo: number = -1;\n  node: HTMLElement;\n  isActive: boolean = false;\n  fallbackTimeout: ReturnType<typeof setTimeout> | undefined;\n  autoplaySupported: boolean | null = null;\n  constructor(node: HTMLElement) {\n    this.node = node;\n    this.videos = dompack.qSA<HTMLDivElement>(node, \".\" + videoClass).map(videoNode => ({ node: videoNode, player: null }));\n    if (!this.videos.length)\n      return; // our header is empty\n\n    const videoPauseMedia = matchMedia(`(max-width: ${breakpoint_deeplinks})`);\n    // Setup an onchange listener\n    videoPauseMedia.addEventListener(\"change\", event => this.checkVideo(event.matches));\n    this.checkVideo(videoPauseMedia.matches);\n  }\n\n  checkVideo(pauseVideo: boolean) {\n    if (pauseVideo)\n      this.pauseVideo();\n    else\n      this.startVideo();\n  }\n\n  pauseVideo() {\n    this.isActive = false;\n    // If there is a video loaded, pause it\n    if (this.autoplaySupported === false) {\n      clearTimeout(this.fallbackTimeout);\n      this.fallbackTimeout = undefined;\n    } else if (this.curVideo >= 0)\n      this.videos[this.curVideo].player!.pause();\n  }\n\n  async nextVideo() {\n    if (!this.isActive)\n      return;\n\n    if (++this.curVideo >= this.videos.length)\n      this.curVideo = 0;\n\n    const video = this.videos[this.curVideo];\n    if (!video.player) {\n      // Initialize and load the video\n      video.player = await videotools.initializeVideoNode(video.node, {}) as HTMLVideoElement;\n\n      // If the video started playing, hide the poster image\n      video.node.addEventListener(\"video:play\", () => this.videoStarted());\n\n      // If the video has finished playing, show the next video\n      video.node.addEventListener(\"video:finish\", () => void this.nextVideo());\n\n      // Start the video when it's ready\n      video.node.addEventListener(\"video:ready\", () => this.playVideo());\n    } else if (video.player) {\n      // Resume/replay the video\n      this.playVideo();\n    }\n  }\n\n  playVideo() {\n    const video = this.videos[this.curVideo];\n\n    // Show the current video's poster image\n    video.node.classList.add(`${videoClass}--current`);\n\n    // Hide the previous video\n    let prevVideo = this.curVideo - 1;\n    if (prevVideo < 0)\n      prevVideo = this.videos.length - 1;\n    this.videos[prevVideo].node.classList.remove(`${videoClass}--current`, `${videoClass}--playing`);\n    this.videos[prevVideo].node.hidden = true;\n\n    // Start the video\n    void video.player!.play();\n\n    // Set a timeout to check if the video is actually playing\n    if (!this.fallbackTimeout)\n      this.fallbackTimeout = setTimeout(() => this.videoFallback(), videoSlideTimeout);\n  }\n\n  videoStarted() {\n    // Remove the poster image\n    this.videos[this.curVideo].node.hidden = false;\n    this.videos[this.curVideo].node.classList.add(`${videoClass}--playing`);\n    // Clear the fallback timeout, fallback isn't needed\n    clearTimeout(this.fallbackTimeout);\n    this.fallbackTimeout = undefined;\n    // If this function is called, we know autoplay is supported\n    this.autoplaySupported = true;\n  }\n\n  videoFallback() {\n    // If this function is called, the video never actually started playing\n    console.warn(\"Video fallback mode activated\");\n    this.autoplaySupported = false;\n\n    this.node.classList.add(\"page-contentheader--fallback\");\n\n    // Show next video poster slide\n    this.nextVideoSlide();\n  }\n\n  startVideo() {\n    this.isActive = true;\n    // There is no video loaded yet, load the first video, otherwise play the\n    // current video\n    if (this.curVideo < 0)\n      void this.nextVideo();\n    else if (this.autoplaySupported === false)\n      this.fallbackTimeout = setTimeout(() => this.nextVideoSlide(), videoSlideTimeout);\n    else\n      void this.videos[this.curVideo].player!.play();\n  }\n\n  nextVideoSlide() {\n    if (!this.isActive)\n      return;\n\n    if (++this.curVideo >= this.videos.length)\n      this.curVideo = 0;\n\n    // Show the new video poster slide\n    this.videos[this.curVideo].node.classList.add(`${videoClass}--current`);\n\n    // Hide the previous video poster slide\n    let prevVideo = this.curVideo - 1;\n    if (prevVideo < 0)\n      prevVideo = this.videos.length - 1;\n    this.videos[prevVideo].node.classList.remove(`${videoClass}--current`);\n\n    // Show next video poster slide after timeout\n    this.fallbackTimeout = setTimeout(() => this.nextVideoSlide(), videoSlideTimeout);\n  }\n}\n\ndompack.register(\".page-contentheader--toplevelhome\", node => new videoSlideShow(node));\n\n/*\n  ScrollListener contentHeaderWidthAnimation to animate the width of the content header as the user scrolls down the page.\n  Would be nice to use CSS scroll-timeline for this, but it's not widely supported yet\n  .page-contentheader .page-contentheader__inner {\n    animation-name: widthAnimation;\n    animation-duration: 1ms;\n    animation-timeline: scroll(root);\n  }\n\n  @keyframes widthAnimation {\n    from {\n      width: 1380px;\n    }\n    to {\n      width: 200%;\n    }\n  }\n*/\nclass contentHeaderWidthAnimation {\n  node: HTMLElement;\n  width: number = 0;\n  minWidth: number = 0;\n  maxWidth: number = 0;\n  constructor(node: HTMLElement) {\n    this.node = node;\n\n    window.addEventListener(\"scroll\", () => this.onScroll(), { passive: true });\n    window.addEventListener(\"load\", () => this.onResize());\n    window.addEventListener(\"resize\", () => this.onResize());\n    this.onResize();\n  }\n\n  onResize() {\n    this.node.style.width = \"\"; // First reset\n    this.width = 0;\n    this.node.parentElement!.classList.remove(\"page-contentheader--fullwidth\");\n    this.minWidth = this.node.offsetWidth;\n    this.maxWidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;\n  }\n\n  onScroll() {\n    if( !this.minWidth )\n      return;\n\n    const y = window.scrollY > 0 ? window.scrollY : 0;\n    let width = Math.floor(this.minWidth * (1 + y / 2000));\n    if( width > this.maxWidth )\n      width = this.maxWidth;\n\n    if( width !== this.width ) {\n      this.node.style.width = width + \"px\";\n\n      if( width >= this.maxWidth )\n        this.node.parentElement!.classList.add(\"page-contentheader--fullwidth\");\n      else if( this.width >= this.maxWidth ) // Previously fullwidth, now not anymore\n        this.node.parentElement!.classList.remove(\"page-contentheader--fullwidth\");\n\n      this.width = width;\n    }\n  }\n}\n\ndompack.register(\".page-contentheader:not(.page-contentheader--photosleft) .page-contentheader__inner\", node => new contentHeaderWidthAnimation(node));\n\ndompack.register(\".page-contentheader__photoscontainer\", node => {\n  new fadeInOutSlides(node, { timeout: 7000, selector: \".page-contentheader__photo\" });\n\n  // Catch clicks on the page content wrapper (which obscures the photo author buttons),\n  // if the click is above a photo author button, focus the button for the currently visible photo\n  const photoInfobtns = dompack.qSA(node, \".page-contentheader__photo__author__button\");\n  if( photoInfobtns.length > 0 ) {\n    dompack.qR(\".page-contentwrapper\").addEventListener(\"click\", ev => {\n      const elements = document.elementsFromPoint(ev.clientX, ev.clientY).filter(el => photoInfobtns.includes(el as HTMLElement)) as HTMLElement[];\n      if( elements.length > 0 ) {\n        const visiblePhoto = dompack.qS(node, \".page-contentheader__photo:not([hidden])\");\n        if( visiblePhoto ) {\n          const authorinfo = elements.find(el => el.dataset.idx === visiblePhoto.dataset.idx);\n          console.log(visiblePhoto.dataset.idx, elements);\n          if( authorinfo )\n            authorinfo.focus();\n        }\n      }\n    });\n  }\n});\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\nconst videoNodeInitialized = Symbol();\nconst vimeoFrameLoaded = Symbol();\n\nconst default_video_playback =\n{\n  autoplay: false,\n  muted: false, // don't play audio by default (to enable autostart on iOS 10+, currently only supported for videofile)\n  controls: true,  // use the controls the video networks provide\n  loop: false, // only supported in Vimeo\n  poster: \"\"    // poster image, currently only supported for videofile\n};\n\n/** @short generate a video player to play the specified video with the specified settings\n    @cell video\n    @cell video.network 'youtube', 'vimeo', 'youku', 'videofile' (experimental)\n    @cell video.id\n    @cell playback\n    @cell playback.autoplay\n    @cell playback.api make sure we can interact with the video (FIXME: current always done on YouTube)\n    @cell playback.muted\n    @cell playback.start\n    @cell playback.end\n    @cell playback.controls\n    @cell playback.loop\n    @cell playback.background (Vimeo play video in background. This hides controls but this activates: loop, mute, autoplay)\n*/\nfunction generateVideoNode(video, playback) {\n  const mergedoptions = Object.assign(default_video_playback, playback); // make a clone, so we don't edit the original options object\n  playback = Object.assign(mergedoptions, playback);\n\n  let playernode;\n  const args = [];\n\n  switch (video.network) {\n    case \"youtube\":\n\n      // https://developers.google.com/youtube/player_parameters\n      args.push(\"autoplay=\" + (playback.autoplay ? \"1\" : \"0\"));\n\n      if (video.starttime)\n        args.push(\"start=\" + Math.floor(video.starttime)); // seconds, whole integer (YouTube also uses t= in the shorturl??)\n\n      if (video.endtime)\n        args.push(\"end=\" + Math.floor(video.endtime));\n\n      if (!playback.controls)\n        args.push(\"controls=0\");\n\n      if (playback.loop) {\n        args.push(\"loop=1\");\n        args.push(\"playlist=\" + video.id); // not sure if required in HTML5 player or only in AS3 player\n      }\n\n      args.push(\"rel=0\"); // disable 'related video's'\n\n      args.push(\"enablejsapi=1\");\n      args.push(\"origin=\" + location.protocol + \"//\" + location.hostname);\n\n      //args.push(\"showinfo=0\"); // deprecated\n\n      // Try to hide some stuff (not much is possible anymore)\n      args.push(\"iv_load_policy=3\"); // don't show video annotations\n      args.push(\"modestbranding=1\");\n\n      // ADDME: playsinline parameter for inline or fullscreen playback on iOS\n      /*\n      YouTube\n\n      - hl=(languagecode ISO 639-1 or fully specifiedlocale such as fr-ca)\n\n      -   start=\n        & end=\n        & controls=0\n        & modestbranding=0\n        & rel=0  (don't show related videos from outside the channel)\n      */\n\n      let youtube_url = \"//www.youtube.com/embed/\" + video.id;\n      if (args.length > 0)\n        youtube_url += \"?\" + args.join(\"&\");\n\n      playernode = __getPlayerFrame();\n      playernode.src = youtube_url;\n      return playback.api ? getYouTubePlayer(playernode) : getStaticVideoPlayer(playernode);\n\n    case \"vimeo\":\n\n      // http://developer.vimeo.com/player/embedding\n      args.push(\"autoplay=\" + (playback.autoplay ? \"1\" : \"0\"));\n\n      if (video.endtime)\n        console.warn(\"setting an endtime doesn't work for Vimeo video's\");\n\n      if (!playback.controls)\n        console.warn(\"disabling video controls not possible for Vimeo video's\");\n\n      if (playback.loop)\n        args.push(\"loop=1\");\n\n      if (playback.background)\n        args.push(\"background=1\");\n\n      let vimeo_url = \"//player.vimeo.com/video/\" + video.id;\n      if (args.length > 0)\n        vimeo_url += \"?\" + args.join(\"&\");\n\n      if (video.starttime) {\n        // #t=3m28s\n        const t = video.starttime;\n        const minutes = Math.floor(t / 60);\n        const seconds = t % 60;\n        vimeo_url += \"#t=\" + minutes + \"m\" + seconds + \"s\";\n      }\n\n\n      // title=0 - hides the title\n\n      playernode = __getPlayerFrame();\n\n      // Set vimeoFrameLoaded to true on load (detect if the iframe contents is loaded before the vimeo player script is)\n      playernode[vimeoFrameLoaded] = false;\n      playernode.addEventListener(\"load\", event => playernode[vimeoFrameLoaded] = true);\n\n      playernode.src = vimeo_url;\n      return playback.api ? getVimeoPlayer(playernode) : getStaticVideoPlayer(playernode);\n\n\n\n    case \"yuja\":\n      {\n        // Convert the parameters into a full playback URL\n        const params = new URL(\"https://www.example.org/?\" + video.id).searchParams;\n        const host = params.get(\"h\");\n        const videoid = params.get(\"v\");\n        const authorizationkey = params.get(\"a\");\n        // let playback_url = `//{host}/V/Video?v={videoid}&a={authorizationkey}`;\n        let playback_url = `//${host}/V/Video`;\n\n        args.push(\"v=\" + encodeURIComponent(videoid));\n        args.push(\"a=\" + encodeURIComponent(authorizationkey));\n\n\n        /*\n        // https://support.yuja.com/hc/en-us/articles/360051850373-Enabling-Auto-Start-for-a-Video-s-Direct-Link-Embed-Code\n        // FIXME: for now we disabled this, because it'll start playback muted ... which will confuse users\n        if (playback.autoplay)\n          args.push(\"autostart=1\");\n          // args.push(\"isPlaying=true\");\n        */\n\n        if (playback.starttime)\n          args.push(\"starttime=\" + playback.starttime);\n\n        if (playback.endtime)\n          console.warn(\"setting an endtime doesn't work for Yuja video's\");\n\n        if (!playback.controls)\n          console.warn(\"disabling video controls not possible for Yuja video's\");\n\n        if (playback.loop)\n          console.warn(\"loop isn't supported for Yuja video's\");\n\n        if (args.length > 0)\n          playback_url += \"?\" + args.join(\"&\");\n\n        playernode = __getPlayerFrame();\n        playernode.src = playback_url;\n        // return playback.api ? getYouTubePlayer(playernode) : getStaticVideoPlayer(playernode);\n        return getYujaPlayer(playernode);\n\n        break;\n      }\n\n    case \"videofile\":\n      playernode = document.createElement(\"video\");\n      playernode.loop = Boolean(playback.loop);\n      playernode.controls = Boolean(playback.controls);\n      playernode.muted = Boolean(playback.muted);\n      if (playback.poster)\n        playernode.poster = playback.poster;\n      playernode.style.width = \"100%\";\n      playernode.style.height = \"100%\";\n      playernode.src = video.id;\n      return playback.api ? getHtml5Player(playernode) : getStaticVideoPlayer(playernode);\n\n    default:\n      console.error(\"Unknown video type\");\n      break;\n  }\n\n  return playernode;\n}\n\nfunction __getPlayerFrame() {\n  const ifrm = document.createElement(\"iframe\");\n  ifrm.style.width = \"100%\";\n  ifrm.style.height = \"100%\";\n  ifrm.frameBorder = 0;\n  ifrm.allowFullscreen = true;\n  ifrm.setAttribute(\"allow\", \"autoplay\"); // new in 2018, see https://developers.google.com/web/updates/2017/09/autoplay-policy-changes\n  return ifrm;\n}\n\nfunction isVideoNodeInitialized(node) {\n  return Boolean(node[videoNodeInitialized]);\n}\n\n// Returns a Promise that resolves with a VideoPlayer object\nfunction initializeVideoNode(node, options) {\n  if (node[videoNodeInitialized])\n    return;\n\n  node.innerHTML = \"\";\n  node[videoNodeInitialized] = true;\n\n  const video = JSON.parse(node.getAttribute(\"data-video\"));\n  let opts = node.hasAttribute(\"data-video-options\") ? JSON.parse(node.getAttribute(\"data-video-options\")) : {};\n  opts = Object.assign(opts, options);\n\n  return new Promise((resolve, reject) => {\n    generateVideoNode(video, opts).then(player => {\n      node.appendChild(player.node);\n      resolve(player);\n    });\n  });\n}\n\n\n\nclass StaticVideoPlayer {\n  constructor(node) {\n    this.node = node;\n    this.network = \"static\";\n  }\n\n  /// Play the video\n  play() {\n  }\n\n  /// Pause the video\n  pause() {\n  }\n\n  /// Is the player currently paused?\n  getPaused() {\n    return Promise.resolve();\n  }\n\n  /// Has the player finished playing?\n  getFinished() {\n    return Promise.resolve();\n  }\n\n  /// Play the video in a loop\n  setLoop(loop) {\n  }\n\n  /// Seek to the given position in the video, in seconds\n  seekTo(seconds) {\n  }\n\n  /// Get the current playback position, in seconds\n  getCurrentTime() {\n    return Promise.resolve();\n  }\n\n  /// Get the total length of the video, in seconds\n  getDuration() {\n    return Promise.resolve();\n  }\n\n  /// Set the playback volume, range 0-100\n  setVolume(volume) {\n  }\n\n  /// Get the current playback volume, range 0-100\n  getVolume() {\n    return Promise.resolve();\n  }\n\n  /// Get a URL for the video\n  getVideoUrl() {\n    return Promise.resolve();\n  }\n\n  /// When the player is ready to play, a bubbling \"video:ready\" event is\n  /// dispatched on the player node\n  onReady() {\n    dompack.dispatchCustomEvent(this.node, \"video:ready\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n\n  /// When the player starts playing, a bubbling \"video:play\" event is\n  /// dispatched on the player node\n  onPlay() {\n    dompack.dispatchCustomEvent(this.node, \"video:play\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n\n  /// When the playback is paused, a bubbling \"video:pause\" event is dispatched\n  /// on the player node\n  onPause() {\n    dompack.dispatchCustomEvent(this.node, \"video:pause\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n\n  /// When the player has finished playing the video, a bubbling \"video:play\"\n  /// event is dispatched on the player node\n  onFinish() {\n    dompack.dispatchCustomEvent(this.node, \"video:finish\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n}\n\n// https://developers.google.com/youtube/iframe_api_reference\nclass YouTubeVideoPlayer extends StaticVideoPlayer {\n  constructor(node) {\n    super(node);\n    this.network = \"youtube\";\n    this.player = new YT.Player(this.node,\n      {\n        events: {\n          onReady: this.onReady.bind(this),\n          onStateChange: this.onStateEvent.bind(this)\n        }\n      });\n  }\n\n  play() {\n    this.player.playVideo();\n  }\n\n  pause() {\n    this.player.pauseVideo();\n  }\n\n  getPaused() {\n    return Promise.resolve(this.player.getPlayerState() === YT.PlayerState.PAUSED);\n  }\n\n  getFinished() {\n    return Promise.resolve(this.player.getPlayerState() === YT.PlayerState.ENDED);\n  }\n\n  setLoop(loop) {\n    this.player.setLoop(Boolean(loop));\n  }\n\n  seekTo(seconds) {\n    this.player.seekTo(seconds, true);\n  }\n\n  getCurrentTime() {\n    return Promise.resolve(this.player.getCurrentTime());\n  }\n\n  getDuration() {\n    return Promise.resolve(this.player.getDuration());\n  }\n\n  setVolume(volume) {\n    this.player.setVolume(volume);\n  }\n\n  getVolume() {\n    return Promise.resolve(this.player.getVolume());\n  }\n\n  getVideoUrl() {\n    return Promise.resolve(this.player.getVideoUrl());\n  }\n\n  onStateEvent(event) {\n    if (event.data === YT.PlayerState.PLAYING)\n      this.onPlay();\n    else if (event.data === YT.PlayerState.PAUSED)\n      this.onPause();\n    else if (event.data === YT.PlayerState.ENDED)\n      this.onFinish();\n  }\n}\n\n// https://developer.vimeo.com/player/js-api\n// https://github.com/vimeo/player.js\nclass VimeoVideoPlayer extends StaticVideoPlayer {\n  constructor(node) {\n    super(node);\n    this.network = \"vimeo\";\n    if (this.node[vimeoFrameLoaded]) // iframe is already loaded\n      this.initPlayer();\n    else // wait for iframe to load\n      this.node.addEventListener(\"load\", this.initPlayer.bind(this));\n  }\n\n  initPlayer() {\n    this.player = new Vimeo.Player(this.node);\n    this.player.ready().then(this.onReady.bind(this));\n    this.player.on(\"play\", this.onPlay.bind(this));\n    this.player.on(\"pause\", this.onPause.bind(this));\n    this.player.on(\"ended\", this.onFinish.bind(this));\n  }\n\n  play() {\n    if (!this.player)\n      return;\n    this.player.play();\n  }\n\n  pause() {\n    if (!this.player)\n      return;\n    this.player.pause();\n  }\n\n  getPaused() {\n    if (!this.player)\n      return Promise.reject();\n    return this.player.getPaused();\n  }\n\n  getFinished() {\n    if (!this.player)\n      return Promise.reject();\n    return this.player.getFinished();\n  }\n\n  setLoop(loop) {\n    if (!this.player)\n      return Promise.reject();\n    this.player.setLoop(loop);\n  }\n\n  seekTo(seconds) {\n    if (!this.player)\n      return Promise.reject();\n    this.player.setCurrentTime(seconds);\n  }\n\n  getCurrentTime() {\n    if (!this.player)\n      return Promise.reject();\n    return this.player.getCurrentTime();\n  }\n\n  getDuration() {\n    if (!this.player)\n      return Promise.reject();\n    return this.player.getDuration();\n  }\n\n  setVolume(volume) {\n    if (!this.player)\n      return Promise.reject();\n    this.player.setVolume(volume / 100);\n  }\n\n  getVolume() {\n    if (!this.player)\n      return Promise.reject();\n    return this.player.getVolume().then(volume => volume * 100);\n  }\n\n  getVideoUrl() {\n    if (!this.player)\n      return Promise.reject();\n    return this.player.getVideoUrl();\n  }\n}\n\n// https://developer.mozilla.org/en-US/docs/Web/API/HTMLMediaElement\n// https://developer.mozilla.org/en-US/docs/Web/Guide/Events/Media_events\nclass Html5VideoPlayer extends StaticVideoPlayer {\n  constructor(node) {\n    super(node);\n    this.network = \"html5\";\n    this.node.addEventListener(\"loadedmetadata\", this.onReady.bind(this));\n    this.node.addEventListener(\"play\", this.onPlay.bind(this));\n    this.node.addEventListener(\"pause\", this.onPause.bind(this));\n    this.node.addEventListener(\"ended\", this.onFinish.bind(this));\n  }\n\n  play() {\n    this.node.play();\n  }\n\n  pause() {\n    this.node.pause();\n  }\n\n  getPaused() {\n    return Promise.resolve(this.node.paused);\n  }\n\n  getFinished() {\n    return Promise.resolve(this.node.ended);\n  }\n\n  setLoop(loop) {\n    this.node.loop = Boolean(loop);\n  }\n\n  seekTo(seconds) {\n    this.node.currentTime = seconds;\n  }\n\n  getCurrentTime() {\n    return Promise.resolve(this.node.currentTime);\n  }\n\n  getDuration() {\n    return Promise.resolve(this.node.duration);\n  }\n\n  setVolume(volume) {\n    this.node.volume = volume / 100;\n  }\n\n  getVolume() {\n    return Promise.resolve(this.node.volume * 100);\n  }\n\n  getVideoUrl() {\n    return Promise.resolve(this.node.src);\n  }\n}\n\n\n\n\nclass YuJaVideoPlayer {\n  constructor(node) {\n    this.node = node;\n    this.network = \"static\";\n\n    this.node_parent = node.parentNode;\n  }\n\n  /// Play the video\n  play() {\n    console.info(\"asking to play\");\n    // this.node.postMessage({ name: \"Play\" }, \"*\");\n    this.node.contentWindow.postMessage(JSON.stringify({ name: \"Play\" }), \"*\");\n    return Promise.resolve();\n  }\n\n  /// Pause the video\n  pause() {\n    console.info(\"asking to pause\");\n    // this.node.postMessage({ name: \"Pause\" }, \"*\");\n    this.node.contentWindow.postMessage(JSON.stringify({ name: \"Pause\" }), \"*\");\n    return Promise.resolve();\n  }\n\n  /// Is the player currently paused?\n  getPaused() {\n    return Promise.resolve();\n  }\n\n  /// Has the player finished playing?\n  getFinished() {\n    return Promise.resolve();\n  }\n\n  /// Play the video in a loop\n  setLoop(loop) {\n  }\n\n  /// Seek to the given position in the video, in seconds\n  seekTo(seconds) {\n  }\n\n  /// Get the current playback position, in seconds\n  getCurrentTime() {\n    return Promise.resolve();\n  }\n\n  /// Get the total length of the video, in seconds\n  getDuration() {\n    return Promise.resolve();\n  }\n\n  /// Set the playback volume, range 0-100\n  setVolume(volume) {\n  }\n\n  /// Get the current playback volume, range 0-100\n  getVolume() {\n    return Promise.resolve();\n  }\n\n  /// Get a URL for the video\n  getVideoUrl() {\n    return Promise.resolve();\n  }\n\n  /// When the player is ready to play, a bubbling \"video:ready\" event is\n  /// dispatched on the player node\n  onReady() {\n    dompack.dispatchCustomEvent(this.node, \"video:ready\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n\n  /// When the player starts playing, a bubbling \"video:play\" event is\n  /// dispatched on the player node\n  onPlay() {\n    dompack.dispatchCustomEvent(this.node, \"video:play\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n\n  /// When the playback is paused, a bubbling \"video:pause\" event is dispatched\n  /// on the player node\n  onPause() {\n    dompack.dispatchCustomEvent(this.node, \"video:pause\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n\n  /// When the player has finished playing the video, a bubbling \"video:play\"\n  /// event is dispatched on the player node\n  onFinish() {\n    dompack.dispatchCustomEvent(this.node, \"video:finish\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { player: this }\n    });\n  }\n}\n\n\n\n\n\n// A video player without API\nfunction getStaticVideoPlayer(node) {\n  return Promise.resolve(new StaticVideoPlayer(node, \"static\"));\n}\n\n// A list of player API scripts with status\nconst playerScripts = {};\n\n// This function is called by the loaded YouTube API script\nwindow.onYouTubeIframeAPIReady = function () {\n  playerScripts.youtube.ready = true;\n  for (const waiter of playerScripts.youtube.waiters)\n    waiter.deferred.resolve(new YouTubeVideoPlayer(waiter.node));\n};\n\nfunction getYouTubePlayer(node) {\n  if (!playerScripts.youtube) {\n    playerScripts.youtube = {\n      ready: false,\n      waiters: []\n    };\n\n    const script = document.createElement(\"script\");\n    script.src = \"//www.youtube.com/iframe_api\";\n    script.async = true;\n    document.head.appendChild(script);\n  }\n\n  if (!playerScripts.youtube.ready) {\n    const deferred = dompack.createDeferred();\n    if (!playerScripts.youtube.waiters)\n      playerScripts.youtube.waiters = [];\n    playerScripts.youtube.waiters.push({ deferred, node });\n    return deferred.promise;\n  } else\n    return Promise.resolve(new YouTubeVideoPlayer(node));\n}\n\nfunction getVimeoPlayer(node) {\n  if (!playerScripts.vimeo) {\n    playerScripts.vimeo = {\n      ready: false,\n      waiters: []\n    };\n\n    const script = document.createElement(\"script\");\n    script.src = \"//player.vimeo.com/api/player.js\";\n    script.async = true;\n    script.addEventListener(\"load\", event => {\n      playerScripts.vimeo.ready = true;\n      for (const waiter of playerScripts.vimeo.waiters)\n        waiter.deferred.resolve(new VimeoVideoPlayer(waiter.node));\n    });\n    document.head.appendChild(script);\n  }\n\n  if (!playerScripts.vimeo.ready) {\n    const deferred = dompack.createDeferred();\n    if (!playerScripts.vimeo.waiters)\n      playerScripts.vimeo.waiters = [];\n    playerScripts.vimeo.waiters.push({ deferred, node });\n    return deferred.promise;\n  } else\n    return Promise.resolve(new VimeoVideoPlayer(node));\n}\n\nfunction getYujaPlayer(node) {\n  return Promise.resolve(new YuJaVideoPlayer(node));\n}\n\n\nfunction getHtml5Player(node) {\n  return Promise.resolve(new Html5VideoPlayer(node));\n}\n\n\n\nexport {\n  initializeVideoNode,\n  isVideoNodeInitialized\n};\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport * as crm from \"../../../shared/crm\";\nimport * as managedctas from \"../../../shared/crm/managedctas\";\nimport { getTid } from \"@webhare/gettid\";\nimport * as tagmanager from '@mod-publisher/js/analytics/gtm';\nimport scrollListener from \"../../../components/scrolllistener\";\nimport { pushToDataLayer } from \"@webhare/frontend\";\n\nconst managedCTASlot = Symbol();\nlet userCountry = \"\", userBeacons = null, ctas = [];\n\n\nfunction setupManagedCTA(node) {\n  userCountry = userCountry || crm.getUserCountry();\n  if (!userBeacons) {\n    userBeacons = crm.getUserBeacons();\n    if (dompack.debugflags.umc)\n      console.log(`[umc] User beacons`, userBeacons);\n  }\n\n  const ctadata = {\n    displayed: false,\n    ctas: [],\n    curcta: \"\" // tag of currently visible CTA\n  };\n\n  for (const subnode of node.querySelectorAll(\".cta--managed\")) {\n    ctadata.ctas.push({\n      node: subnode,\n      config: managedctas.parseManagedCTAConfig(subnode.dataset.ctaconfig)\n    });\n  }\n\n  if (dompack.debugflags.umc) {\n    const ctatags = ctadata.ctas.map(cta => cta.config.tag).join(', ');\n    console.log(`[umc] Found a managed CTA ${node.dataset.ctatag} with ${ctadata.ctas.length} CTAs: ${ctatags}`);\n  }\n\n  node[managedCTASlot] = ctadata;\n  updateManagedCTA(node);\n  ctas.push(node);\n\n  if (!userCountry) {\n    if (dompack.debugflags.umc)\n      console.log(`[umc] Requesting user country`);\n    crm.requestGeoIP().then(country => {\n      userCountry = country;\n      updateManagedCTA(node);\n    });\n  }\n\n  // Send a \"cta-display\" event when the CTA is in view\n  scrollListener.addNodes([node]);\n  node.addEventListener(\"wh:visibilitychange\", onManagedCTADisplay);\n\n  // Send a \"cta-display\" event on page load\n  node.addEventListener(\"click\", onManagedCTAClick);\n\n  // Listen for beacon updates\n  window.addEventListener(\"ut-beaconchange\", updateAllManagedCTAs);\n}\n\nfunction updateAllManagedCTAs() {\n  ctas.forEach(updateManagedCTA);\n}\nfunction updateManagedCTA(node) {\n  // If this CTA has already been into view, we cannot change it\n  if (!node[managedCTASlot] || node[managedCTASlot].displayed) {\n    if (dompack.debugflags.umc)\n      console.log(`[umc] Not updating managed CTA ${node.dataset.ctatag}, it's already been displayed`);\n    return;\n  }\n\n  if (document.documentElement.dataset.site?.match(/Repository/i) || document.documentElement.classList.contains(\"wh-widgetpreview\")) {\n    document.documentElement.classList.add(\"ut--ctapreview\");\n    showManagedCTAPreview(node);\n    return;\n  }\n\n  let haveCTA = false;\n\n  const params = new URL(location.href).searchParams;\n  const forced = (params.get(\"showcta\") || '').split(\":\"); //to show a specific cta use eg ?showcta=open_dagen_algemeen_bachelor_nl:speciaal\n\n  node[managedCTASlot].curcta = null;\n  let displaycta = null;\n  for (const cta of node[managedCTASlot].ctas) {\n    if (forced[0] == node.dataset.ctatag) {\n      if (forced.length == 1 || forced[1] == cta.config.tag) {\n        if (dompack.debugflags.umc)\n          console.info(`[umc] Showing forced CTA ${cta.config.tag}`);\n        cta.node.classList.add(\"cta--show\");\n        displaycta = cta;\n      } else {\n        if (dompack.debugflags.umc)\n          console.warn(`[umc] Not showing CTA ${cta.config.tag}: Not matched by URL variable: '${cta.config.tag}' != '${forced[1]}'`);\n        cta.node.classList.remove(\"cta--show\");\n      }\n    } else if (!haveCTA) {\n      try {\n        managedctas.tryMatchCTAConfig(cta.config, { country: userCountry, beacons: userBeacons, url: location.href });\n\n        if (dompack.debugflags.umc)\n          console.info(`[umc] Showing CTA ${cta.config.tag}`);\n        cta.node.classList.add(\"cta--show\");\n        node[managedCTASlot].curcta = cta.config.tag;\n        displaycta = cta;\n        haveCTA = true;\n      } catch (e) {\n        if (e instanceof managedctas.CTAMatchError) {\n          if (dompack.debugflags.umc)\n            console.warn(`[umc] Not showing CTA ${cta.config.tag}: ${e.message}`);\n          cta.node.classList.remove(\"cta--show\");\n        } else\n          throw e;\n      }\n    } else {\n      cta.node.classList.remove(\"cta--show\");\n    }\n    cta.node._wsTmpDisplay = getComputedStyle(cta.node).display;\n  }\n  if (displaycta) {\n    node.style.display = \"block\";\n    node.hidden = false;\n    node._wsTmpDisplay = getComputedStyle(node).display;\n    setTimeout(() => {\n      dompack.dispatchCustomEvent(node, \"ws:managed-cta\",\n        {\n          bubbles: true,\n          cancelable: false,\n          detail: { cta: displaycta }\n        });\n    }, 1);\n  }\n}\n\nfunction showManagedCTAPreview(node) {\n  const params = new URL(location.href).searchParams;\n  let testprops = JSON.parse(params.get(\"testprops\"));\n  if (testprops)\n    testprops = { ...testprops, url: testprops.url || location.href };\n\n  node.style.display = \"block\";\n  node.hidden = false;\n  node[managedCTASlot].curcta = null;\n  const any_shown = node[managedCTASlot].ctas.some(cta => {\n    let matcherror;\n    if (testprops) {\n      try {\n        managedctas.tryMatchCTAConfig(cta.config, testprops);\n\n        if (dompack.debugflags.umc)\n          console.info(`[umc] Showing CTA ${cta.config.tag}`);\n        cta.node.classList.add(\"cta--show\");\n        node[managedCTASlot].curcta = cta.config.tag;\n        return true; // Break out of the 'some' loop\n      } catch (e) {\n        if (e instanceof managedctas.CTAMatchError) {\n          if (dompack.debugflags.umc)\n            console.warn(`[umc] Not showing CTA ${cta.config.tag}: ${e.message}`);\n\n          if (!testprops || !testprops.showskipped) {\n            cta.node.classList.remove(\"cta--show\");\n            return; // Go to next CTA\n          }\n          matcherror = e;\n        } else\n          throw e;\n      }\n    }\n\n    cta.node.classList.add(\"cta--show\");\n\n    if (cta.node.querySelector(\".ut--cta__explain\"))\n      return; // Already explained\n\n    const explanations = [];\n    if (cta.config.publish_from) {\n      if (matcherror && matcherror.prop == \"publish_from\")\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.publish_from-skipped\", new Date(matcherror.values.expected).toLocaleString(), new Date(matcherror.values.got).toLocaleString()));\n      else if (!matcherror)\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.publish_from\", new Date(cta.config.publish_from).toLocaleString()));\n    }\n    if (cta.config.publish_until) {\n      if (matcherror && matcherror.prop == \"publish_until\")\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.publish_until-skipped\", new Date(matcherror.values.expected).toLocaleString(), new Date(matcherror.values.got).toLocaleString()));\n      else if (!matcherror)\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.publish_until\", new Date(cta.config.publish_until).toLocaleString()));\n    }\n    if (cta.config.countries && cta.config.countries.length) {\n      if (matcherror && matcherror.prop == \"countries\")\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.countries-skipped\", matcherror.values.expected.join(\", \"), matcherror.values.got));\n      else if (!matcherror)\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.countries\", cta.config.countries.join(\", \")));\n    }\n    if (cta.config.beacons) {\n      if (matcherror && matcherror.prop == \"beacons\") {\n        if (!matcherror.values.expected && !matcherror.values.got)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.beacons-skipped-none\"));\n        else if (!matcherror.values.got)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.beacons-skipped\", matcherror.values.expected));\n        else\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.beacons-skipped-time\", matcherror.values.tag, new Date(matcherror.values.expected).toLocaleString(), new Date(matcherror.values.got).toLocaleString()));\n      } else if (!matcherror)\n        explanations.push(...cta.config.beacons.map(beacon => {\n          if (beacon.maxdays)\n            return getTid(\"utwente_base:frontend.ws2016.js.managedcta.beacon-maxdays\", beacon.tag, beacon.maxdays);\n          return getTid(\"utwente_base:frontend.ws2016.js.managedcta.beacon\", beacon.tag);\n        }));\n    }\n    if (cta.config.regexes && cta.config.regexes.length) {\n      if (matcherror && matcherror.prop == \"regexes\") {\n        if (matcherror.values.error)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.regex-skipped-error\", matcherror.values.expected, matcherror.values.error));\n        else if (matcherror.values.expected)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.regex-skipped\", `/${matcherror.values.expected}/`, matcherror.values.got));\n        else\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.regex-skipped-none\", matcherror.values.got));\n      } else if (!matcherror) {\n        const positives = cta.config.regexes.filter(_ => !_.exclude).map(_ => _.regex.source);\n        if (positives.length)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.regex\", `[ /${positives.join(\"/, /\")}/ ]`));\n        const negatives = cta.config.regexes.filter(_ => _.exclude).map(_ => _.regex.source);\n        if (negatives.length)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.regex-exclude\", `[ /${negatives.join(\"/, /\")}/ ]`));\n      }\n    }\n    if (cta.config.queries && cta.config.queries.length) {\n      if (matcherror && matcherror.prop == \"queries\") {\n        if (matcherror.values.error)\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.query-skipped-error\", matcherror.values.expected, matcherror.values.error));\n        else\n          explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.query-skipped\", matcherror.values.got));\n      } else if (!matcherror) {\n        explanations.push(getTid(\"utwente_base:frontend.ws2016.js.managedcta.query\", `[ '${cta.config.queries.map(_ => _._term).join(\"', '\")}' ]`));\n      }\n    }\n\n    if (explanations.length)\n      cta.node.after(\n        <div class=\"ut--cta__explain\">\n          {testprops && testprops.showskipped ? getTid(\"utwente_base:frontend.ws2016.js.managedcta.explanation-skipped\") : getTid(\"utwente_base:frontend.ws2016.js.managedcta.explanation\")}:\n          <ul class=\"unordered\">\n            {explanations.map(text => <li>{text}</li>)}\n          </ul>\n        </div>);\n    else\n      cta.node.after(<div class=\"ut--cta__explain ut--cta__explain--empty\"></div>);\n  });\n  if (testprops && testprops.showskipped && !any_shown) {\n    node.append(<div class=\"ut--cta__explain ut--cta__explain--nocta\">{getTid(\"utwente_base:frontend.ws2016.js.managedcta.noctatoshow\")}</div>);\n  }\n}\n\nfunction onManagedCTADisplay(event) {\n  // If the CTA is now visible, but hasn't been visible yet, push a \"cta-display\" event\n  const node = event.target;\n  if (event.detail.visible && !node[managedCTASlot].displayed) {\n    if (dompack.debugflags.umc)\n      console.info(`[umc] Managed CTA ${node.dataset.ctatag} is displayed`, node);\n\n    node[managedCTASlot].displayed = true;\n    if (window.dataLayer && node[managedCTASlot].curcta) {\n      const eventValues = {\n        event: \"cta-display\",\n        \"cta-tag-main\": node.dataset.ctatag\n      };\n      if (node[managedCTASlot].curcta)\n        eventValues[\"cta-tag-variant\"] = node[managedCTASlot].curcta;\n      window.dataLayer.push(eventValues);\n    }\n  }\n}\n\nfunction onManagedCTAClick(event) {\n  let target = event.target;\n  if (!target.href)\n    target = target.closest(\"[href]\");\n  if (target) {\n    const node = target.closest(\".managedcta\");\n    if (node && node[managedCTASlot]) {\n      if (dompack.debugflags.umc)\n        console.info(`[umc] Received link click in managed CTA ${node.dataset.ctatag}`);\n\n      // Prevent navigation when clicking the link\n      event.stopPropagation();\n      event.preventDefault();\n\n      // Push a \"cta-click\" event and handle the navigation afterwards\n      pushToDataLayer({\n        event: 'cta-click',\n        \"cta-tag-main\": node.dataset.ctatag,\n        \"cta-tag-variant\": node[managedCTASlot].curcta || undefined,\n        eventCallback: () => location.href = target.href\n      });\n    }\n  }\n}\n\ndompack.register(\".managedcta\", setupManagedCTA);\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\n\n\n/*\n  Scrolllistener is used to trigger loading/animations when selected elements get inside/outside the viewport.\n  Use attribute 'data-scrollevent' to bind event 'wh:visibilitychange' to element\n  With the data-scrollevent an threshold can be set like data-scrollevent=\"100\".\n  Then event will be triggered when at least 100px of element gets visible or is hidden.\n  (On first time 'onload' all thresholds are 0)\n  Extras: data-scrollparallax and data-scrollzoom for parallax/zoom effect while scrolling\n  value of these attributes are the factors of the parallax speed / zoom factor\n\n*/\nclass ScrollListener {\n  constructor() {\n    this.scrollactions = [];//contains nodes with active functions during scrolling\n    this.elements = [];\n\n    this.scrollfn = this.onScroll.bind(this);//bind to functions so we can remove listener if all elements are visible\n    this.resizefn = this.onResize.bind(this);\n\n    window.addEventListener(\"scroll\", this.scrollfn);\n    window.addEventListener(\"resize\", this.resizefn);\n\n    this.isinit = true;\n    this.onResize();\n\n    dompack.onDomReady(() => {\n      this.addNodes(document.querySelectorAll(\"[data-scrollevent]\"));\n    });\n  }\n\n  // Add nodes to listen to\n  addNodes(selnodes) {\n    if (!selnodes.length)\n      return;\n\n    for (let i = 0; i < selnodes.length; ++i) {\n      let treshhold = selnodes[i].getAttribute(\"data-scrollevent\");\n      treshhold = !treshhold ? 0 : parseInt(treshhold);\n\n      const nodeinfo = {\n        \"state\": \"\",\n        \"node\": selnodes[i],\n        \"treshhold\": treshhold,\n        \"boundingrect\": null,\n        \"actions\": [],\n        \"data\": null,\n        \"measure\": \"\"\n      };\n\n      const scrollvisibleclass = selnodes[i].getAttribute(\"data-scrollvisibleclass\");\n      if (scrollvisibleclass)\n        selnodes[i].addEventListener(\"wh:visibilitychange\", () => selnodes[i].classList.add(scrollvisibleclass));\n\n      const measuremethod = selnodes[i].getAttribute(\"data-scrolleventmeasure\");\n      if (measuremethod != \"\")\n        nodeinfo.measure = measuremethod;\n\n\n      const parallax = selnodes[i].getAttribute(\"data-scrollparallax\");\n      if (typeof parallax === \"string\") {\n        const free = selnodes[i].hasAttribute(\"data-scrollparallaxfree\"); // if used, we won't limit the amount the element can be shifted based on how much clipped content there is\n\n        // let innernode = selnodes[i].querySelector(\":first-child\");\n        const innernode = selnodes[i].firstElementChild;\n        if (innernode) {\n          const factor = Number(parallax);//movement factor\n          nodeinfo.data = {\n            innernode: innernode,\n            parallax: factor || 0.2,\n            limitparallax: !free\n          };\n          nodeinfo.actions.push(\"parallax\");\n          this.scrollactions.push(nodeinfo);\n        }\n      }\n\n      const zoom = selnodes[i].getAttribute(\"data-scrollzoom\");\n      if (typeof zoom === \"string\") {\n        // let innernode = selnodes[i].querySelector(\":first-child\");\n        const innernode = selnodes[i].firstElementChild;\n        if (innernode) {\n          //let factor = 1*zoom;//zoom factor\n          nodeinfo.data = {\n            innernode: innernode,\n            zoom: zoom !== 0 ? Math.abs(zoom) : 1\n          };\n          nodeinfo.actions.push(\"zoom\");\n          this.scrollactions.push(nodeinfo);\n        }\n      }\n      this.elements = this.elements.filter(info => info.node != selnodes[i]);\n      this.elements.push(nodeinfo);\n    }\n  }\n\n  onScrollActions() {\n    for (let i = 0; i < this.scrollactions.length; i++) {\n      const action = this.scrollactions[i];\n\n      if (action.state != \"visible\")\n        continue;\n\n      //Parallax\n      if (action.actions.indexOf(\"parallax\") != -1) {\n        const elementheight = action.data.innernode.clientHeight;\n        if (action.data.limitparallax && !elementheight) {\n          // if we cannot measure the content (absolute positioned content within the innernode?)\n          // we cannot limit the parallax.\n          continue;\n        }\n\n        const containerheight = action.node.clientHeight;\n\n        // determine how much larger the element to animate is compared to it's container\n        const overflowsize = elementheight - containerheight;\n\n        const p = 2 * (action.boundingrect.bottom / (this.viewport_height + containerheight) - 0.5);//range -1 .. 1\n        const center = overflowsize * -0.5;\n\n        let factor = action.data.parallax; // range of the parallax motion (how much it moves up to counter the page scroll)\n\n        // By default prevent the image moving outside of the container (leaving a gap)\n        if (action.data.limitparallax && Math.abs(factor) > overflowsize) // is the amount of movement (in px) specified on the element larger than the amount the image inside has larger?\n          factor = factor < 0 ? -overflowsize : overflowsize;\n\n\n        if (!action.data.innernode.style.transform) {\n          //first time: set top/bottom on auto\n          action.data.innernode.style.top = \"auto\";//(center + p * factor ) + \"px\";\n          action.data.innernode.style.bottom = \"auto\";\n        }\n\n        action.data.innernode.style.transform = \"translate(0,\" + (center + p * factor) + \"px)\";\n      }\n\n      //Zoom effect\n      if (action.actions.indexOf(\"zoom\") != -1) {\n        if (action.boundingrect.top <= 0) //start zoom effect if container starts to hide in top\n        {\n          const containerheight = action.node.clientHeight;\n          const p = -action.boundingrect.top / containerheight;\n\n          const factor = 1 + p * action.data.zoom;\n          action.data.innernode.style.transform = \"scale(\" + factor + \",\" + factor + \")\";\n          action.data.innernode.style.opacity = 1 - p;\n        } else {\n          action.data.innernode.style.transform = \"scale(1,1)\";\n          action.data.innernode.style.opacity = 1;\n        }\n      }\n\n    }\n  }\n\n  onScroll(ev) {\n    const scrollpos = window.scrollY;\n    this.isscrollup = this.lastscroll ? this.lastscroll > scrollpos : false;\n    this.lastscroll = scrollpos;\n\n    this.checkElementsVisibility();\n\n    this.onScrollActions();\n  }\n\n  checkElementsVisibility() { //check if elements getting visible or hides\n    for (let i = this.elements.length - 1; i >= 0; --i) {\n      let visible = false;\n\n      const treshhold = this.isinit ? 0 : this.elements[i].treshhold;\n      let rect;\n\n      //console.log(\"Check visibility\", this.elements[i]);\n\n      // This was added for elements which itself cannot be measured correctly.\n      // (either because of use display: contents; of childnodes overflowing)\n      if (this.elements[i].measure == \"content\") {\n        let node = this.elements[i].node.firstElementChild;\n        while (node) {\n          rect = node.getBoundingClientRect();\n          if (rect.height > 0) {\n            // FIXME: if we want to support scroll effects we also need to combine the clientrects\n            //        of children and set this.elements[i].boundingrect = rect;\n            visible = (rect.top >= treshhold && this.viewport_height - rect.top >= treshhold) || (rect.bottom > treshhold && this.viewport_height - rect.bottom > treshhold);\n            if (visible)\n              break; // stop checking elements, part of the element is visible anyway\n          }\n\n          node = node.nextElementSibling;\n        }\n      } else {\n        rect = this.elements[i].node.getBoundingClientRect();\n        if (rect.height == 0) // currently not visible\n          continue;\n\n        this.elements[i].boundingrect = rect;\n        visible = (rect.top >= treshhold && this.viewport_height - rect.top >= treshhold) || (rect.bottom > treshhold && this.viewport_height - rect.bottom > treshhold);\n      }\n\n      if (visible) {\n        if (this.elements[i].state != \"visible\") {\n          this.elements[i].state = \"visible\";\n          dompack.dispatchCustomEvent(this.elements[i].node, \"wh:visibilitychange\", {\n            bubbles: true,\n            cancelable: false,\n            detail: {\n              scrolldirection: this.isinit ? \"\" : (this.isscrollup ? \"up\" : \"down\"),\n              target: this.elements[i],\n              visible: true,\n              nodebounds: rect\n            }\n          });\n        }\n      } else {\n        if (this.elements[i].state == \"visible\") {\n          this.elements[i].state = \"hide\";\n          dompack.dispatchCustomEvent(this.elements[i].node, \"wh:visibilitychange\", {\n            bubbles: true,\n            cancelable: false,\n            detail: {\n              scrolldirection: this.isinit ? \"\" : (this.isscrollup ? \"up\" : \"down\"),\n              target: this.elements[i],\n              visible: false,\n              nodebounds: rect\n            }\n          });\n        }\n      }\n    }\n\n    this.isinit = false;\n  }\n\n  onResize(ev) {\n    const win_height = window.innerHeight;\n    if (this.viewport_height && this.viewport_height == win_height)\n      return;\n\n    this.viewport_height = win_height;\n\n    this.onScroll();\n  }\n\n}\n\nconst scrollListener = new ScrollListener();\nexport default scrollListener;\n","import \"./countdown.css\";\nimport * as dompack from \"@webhare/dompack\";\n\n// Extend Element interface to allow __countdown_value property\ndeclare global {\n  interface Element {\n    __countdown_value?: number;\n    __countdown_digitidx?: number;\n  }\n}\n\ntype onExpiredCallbackFunction = () => void;\n\nexport class CountDownComponent {\n  node: HTMLElement;\n  node_day: HTMLElement;\n  node_daydigits: HTMLElement[];\n  node_hours: HTMLElement;\n  node_hourdigits: HTMLElement[];\n  node_minutes: HTMLElement;\n  node_minutedigits: HTMLElement[];\n  node_seconds: HTMLElement;\n  node_seconddigits: HTMLElement[];\n  node_digits: HTMLElement[];\n  animframetimer: null | number = null;\n  options: {\n    countdownto: string;\n    countdownfrom: string;\n    onexpired: onExpiredCallbackFunction | null; //Function;\n  };\n\n  beforeContainer: HTMLElement | null = null;\n  inprogressContainer: HTMLElement | null = null;\n  expiredContainer: HTMLElement | null = null;\n  state: \"before\" | \"inprogress\" | \"expired\" | \"\" = \"\"; // Empty if not yet initialized, otherwise one of the other values\n\n  countdownvalue: {\n    days: number;\n    hours: number;\n    minutes: number;\n    seconds: number;\n    expired: boolean;\n  } | null = null;\n  countdownto: Date | null = null;\n  countdownfrom: Date | null = null;\n  countdownto_timestamp: number = 0; // Timestamp\n  countdownfrom_timestamp: number = 0; // Timestamp\n\n  previousroundedtime: number = 0;\n\n  debug: boolean = false;\n  initialized: boolean = false;\n\n  constructor(node: HTMLElement, options: { countdownto?: string; countdownfrom?: string; onexpired?: onExpiredCallbackFunction | null }) {\n    this.node = node;\n\n    this.options = {\n      countdownto: \"\",\n      countdownfrom: \"\",\n      onexpired: null,\n      ...options\n    };\n\n    if (this.debug)\n      console.log(\"[CountDownComponent] initializing\", options);\n\n    const wrapper = node.closest(\".widget-countdown, .header-countdown\");\n    if (wrapper) {\n      this.beforeContainer = dompack.qS(wrapper, \".widget-countdown__before, .header-countdown-before\");\n      this.inprogressContainer = dompack.qS(wrapper, \".widget-countdown__inprogress, .header-countdown-inprogress\");\n      this.expiredContainer = dompack.qS(wrapper, \".widget-countdown__expired, .header-countdown-expired\");\n    }\n\n    this.node_day = node.querySelector(\".countdown__section--days\") as HTMLElement;\n    this.node_daydigits = Array.from(this.node_day.querySelectorAll(\".countdown__digit\"));\n    this.node_hours = node.querySelector(\".countdown__section--hours\") as HTMLElement;\n    this.node_hourdigits = Array.from(this.node_hours.querySelectorAll(\".countdown__digit\"));\n    this.node_minutes = node.querySelector(\".countdown__section--minutes\") as HTMLElement;\n    this.node_minutedigits = Array.from(this.node_minutes.querySelectorAll(\".countdown__digit\"));\n    this.node_seconds = node.querySelector(\".countdown__section--seconds\") as HTMLElement;\n    this.node_seconddigits = Array.from(this.node_seconds.querySelectorAll(\".countdown__digit\"));\n\n    this.node_digits = Array.from(node.querySelectorAll(\".countdown__digit\"));\n\n    if (this.debug)\n      console.info(\"[CountDownComponent] Counting down to %s\", node.dataset.countdownto, this.countdownto_timestamp);\n\n    this.enhanceDOM();\n\n    if (options.countdownfrom)\n      this.setCountdownFrom(options.countdownfrom);\n    else if (node.dataset.countdownfrom)\n      this.setCountdownFrom(node.dataset.countdownfrom);\n\n    if (options.countdownto)\n      this.setCountdownTo(options.countdownto);\n    else if (node.dataset.countdownto)\n      this.setCountdownTo(node.dataset.countdownto);\n    else\n      console.error(\"[CountDownComponent] initialized without setting options.countdownto or a data-countdownto attribute on .component-countdown\");\n\n    this.refreshAndScheduleNextFrame();\n\n    // FIXME: how to handle this with multiple events !!?\n    if (this.countdownvalue && this.countdownvalue.days === 0)\n      this.node_day.classList.add(\"countdown__section--initiallyleadingzero\");\n\n    node.classList.add(\"component-countdown--allowanimation\");\n\n    this.node.addEventListener(\"transitionend\", evt => this.onTransitionEnd(evt));\n    document.addEventListener(\"visibilitychange\", () => this.onPageVisibilityChange());\n\n    this.initialized = true;\n  }\n\n  setCountdownBlockVisibility(state: \"before\" | \"inprogress\" | \"expired\") {\n\n    if (this.state === state)\n      return;\n\n    if (this.debug)\n      console.info(\"[CountDownComponent] Changing countdown block visibility from '\" + this.state + \"' to '\" + state + \"'\");\n\n    this.state = state;\n\n    if (this.beforeContainer)\n      this.beforeContainer.hidden = state !== \"before\";\n    if (this.inprogressContainer)\n      this.inprogressContainer.hidden = state !== \"inprogress\";\n    if (this.expiredContainer)\n      this.expiredContainer.hidden = state !== \"expired\";\n  }\n\n  setCountdownFrom(countdownfrom: string) {\n    this.countdownfrom = parseCountdownToString(countdownfrom);\n    this.countdownfrom_timestamp = this.countdownfrom.getTime();\n\n    if (this.countdownfrom_timestamp && new Date().getTime() < this.countdownfrom_timestamp) {\n      if (this.debug)\n        console.info(\"[CountDownComponent] The countdown has not started yet!\");\n\n      this.setCountdownBlockVisibility(\"before\");\n    }\n  }\n\n  setCountdownTo(countdownto: string) {\n    this.countdownto = parseCountdownToString(countdownto);\n    this.countdownto_timestamp = this.countdownto.getTime();\n    this.countdownvalue = null; // the next refresh() (called in onAnimFrame) will set this.countdownvalue again\n    this.previousroundedtime = 0; // timestamp used last time for drawing the countdown\n\n    // refreshing is meant for when external code calls setCountdownTo().\n    // When we call setCountdownTo() during initialization we aren't ready yet for this.\n    if (this.initialized)\n      this.refreshAndScheduleNextFrame();\n  }\n\n  stopCountdown() {\n    if (!this.animframetimer)\n      return;\n\n    cancelAnimationFrame(this.animframetimer);\n    this.animframetimer = null;\n  }\n\n  onPageVisibilityChange() {\n    if (document.visibilityState === \"hidden\") {\n      this.node.classList.remove(\"component-countdown--allowanimation\");\n      return;\n    }\n\n    // When returning to a previous invisible page CSS will be computed again and transitions will\n    // we triggered which were meant to have been finished earlyer.\n    // To prevent this whe'll disable transitions for a moment.\n    if (document.visibilityState === \"visible\") {\n      // Fix any zero's which we haven't moved\n      // (because we useually do this in the transitionend, but transitions aren't done\n      // while the document isn't visible (tab hidden or browser window minimized)\n      for (const digitnode of this.node_digits) {\n        if (digitnode.firstElementChild!.__countdown_value! === 0) {\n          const wrapidx = this.__getWrapDigitIDX(digitnode);\n          this.setTrackPosition(digitnode, wrapidx);\n        }\n      }\n\n      requestAnimationFrame(this.reenableTransitions.bind(this));\n    }\n  }\n\n  reenableTransitions() {\n    // first frame after we became visible.\n    // This animation frame will trigger a transition if we directly enable transitions,\n    // so whe'll delay until the next one.\n    requestAnimationFrame(this.reenableTransitions2.bind(this));\n  }\n\n  reenableTransitions2() {\n    this.node.classList.add(\"component-countdown--allowanimation\");\n  }\n\n  onAnimFrame() {\n    this.animframetimer = null;\n    this.refreshAndScheduleNextFrame();\n  }\n\n  refreshAndScheduleNextFrame() {\n    this.refresh();\n\n    if (!this.animframetimer\n      && (!this.countdownvalue // first frame for the current countdown value (so no value available yet)\n        || !this.countdownvalue.expired)) {\n      this.animframetimer = requestAnimationFrame(this.onAnimFrame.bind(this));\n    }\n  }\n\n  refresh() {\n    const now = new Date();\n    let now_timestamp = now.getTime();\n\n    if (now_timestamp % 1000 > 950)\n      now_timestamp += 1000 - now_timestamp % 1000;\n    else\n      now_timestamp = now_timestamp - now_timestamp % 1000;\n\n    if (now_timestamp === this.previousroundedtime)\n      return;\n\n    this.previousroundedtime = now_timestamp;\n    this.refreshFor(now_timestamp);\n  }\n\n  refreshFor(now: number) {\n    if (this.beforeContainer) {\n      if (this.countdownfrom_timestamp && now >= this.countdownfrom_timestamp) {\n        if (this.debug)\n          console.info(\"[CountDownComponent] The countdown starts now!\");\n\n        this.setCountdownBlockVisibility(\"inprogress\");\n      } else {\n        return; // Still before the countdown start date\n      }\n    }\n\n    if (now > this.countdownto_timestamp) {\n      if (this.debug)\n        console.info(\"[CountDownComponent] The countdown has expired!\");\n\n      this.setCountdownBlockVisibility(\"expired\");\n\n      this.countdownvalue = {\n        days: 0,\n        hours: 0,\n        minutes: 0,\n        seconds: 0,\n        expired: true\n      };\n\n      if (this.options.onexpired)\n        this.options.onexpired();\n\n      return;\n    }\n\n    this.setCountdownBlockVisibility(\"inprogress\"); // Still running / in progress\n\n    const distance = this.countdownto_timestamp - now;\n\n    // Time calculations for days, hours, minutes and seconds\n    const days = Math.floor(distance / (1000 * 60 * 60 * 24));\n    const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\n    const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));\n    const seconds = Math.floor((distance % (1000 * 60)) / 1000);\n\n    this.node_day.classList.toggle(\"leadingzeros\", days === 0);\n    this.node_hours.classList.toggle(\"leadingzeros\", days === 0 && hours === 0);\n    this.node_minutes.classList.toggle(\"leadingzeros\", days === 0 && hours === 0 && minutes === 0);\n    this.node_seconds.classList.toggle(\"leadingzeros\", days === 0 && hours === 0 && minutes === 0 && seconds === 0);\n\n    const digits = [\n      Math.floor(days / 100),      // day X..\n      Math.floor(days / 10) % 10,  // day .X.\n      days % 10,                   // day ..X\n\n      Math.floor(hours / 10),\n      hours % 10,\n\n      Math.floor(minutes / 10),\n      minutes % 10,\n\n      Math.floor(seconds / 10),\n      seconds % 10\n    ];\n\n    let idx = 0;\n    let leadingzero = true;\n    let initially_visible_digits = 0;\n\n    for (const digitnr of digits) {\n      void digitnr; // FIXME: just to stop eslint from complaining - but maybe we should use for with a counter instead?\n      const value = digits[idx];\n      if (value > 0)\n        leadingzero = false;\n\n      if (!leadingzero)\n        initially_visible_digits++;\n\n      const digitnode = this.node_digits[idx];\n\n      // Especially for days we may want to hide the digits which will start at 0\n      if (!this.initialized && leadingzero)\n        this.node_digits[idx].classList.toggle(\"countdown__digit--initiallyleadingzero\", leadingzero);\n\n      // Prevent basing the DOM with unnessecary updates\n      // AND prevent scrolling back from the 2nd zero to the first zero.\n      if (digitnode.firstElementChild!.__countdown_value !== value) {\n        this.setDigit(digitnode, value);\n        this.node_digits[idx].classList.toggle(\"countdown__digit--leadingzero\", leadingzero);\n      }\n\n      idx++;\n    }\n\n    this.node.setAttribute(\"data-initiallyvisibledigits\", initially_visible_digits.toString());\n\n    this.countdownvalue = {\n      days: days,\n      hours: hours,\n      minutes: minutes,\n      seconds: seconds,\n      expired: false\n    };\n\n    if (this.debug)\n      console.info(\"[CountDownComponent]\", this.countdownvalue);\n  }\n\n  setDigit(node: HTMLElement, number: number) {\n    node.firstElementChild!.__countdown_value = number;\n    node.setAttribute(\"data-countvalue\", String(number));\n    this.__shiftTrack(node, number);\n  }\n\n  __shiftTrack(node: HTMLElement, amount: number) {\n    /*\n    We need to go to the wrapping digit if:\n    - we start at 0 (during initialization)\n    - the document/browser-tab isn't visible (because whe're hidden there'll be no transition or transitionend event)\n    */\n    if (amount === 0 && (!this.initialized || document.visibilityState === \"hidden\"))\n      amount = this.__getWrapDigitIDX(node);\n\n    this.setTrackPosition(node, amount);\n  }\n\n  __getWrapDigitIDX(node: HTMLElement) {\n    const digitdesc = node.getAttribute(\"data-digit\");\n    if (digitdesc === \"minutes-ten\" || digitdesc === \"seconds-ten\")\n      return 6;\n    else if (digitdesc === \"hours-ten\")\n      return 3;\n    else\n      return 10;\n  }\n\n  setTrackPositionToWrapDigit(node: HTMLElement) {\n    const position = this.__getWrapDigitIDX(node);\n    this.setTrackPosition(node, position);\n  }\n\n  setTrackPosition(node: HTMLElement, amount: number) {\n    const value = `translateY(calc(-${100 * amount}% - ${amount}px))`;\n    const firstchild = node.firstElementChild as HTMLElement;\n    firstchild.style.transform = value;\n    firstchild.__countdown_digitidx = amount;\n  }\n\n  onTransitionEnd(evt: Event) {\n    // When our transition landed on a 0\n    const tracknode = evt.target as HTMLElement;\n    if (tracknode.__countdown_value === 0) {\n      /* Shift any digit which stopped their transition landing on a zero\n         to the second occurence of zero at the bottom of the track.\n         This ensures we can continue scroll up as if our scroller wraps. */\n      const digitcontainer = tracknode.parentNode as HTMLElement;\n\n      if (document.hidden) {\n        // shift to the 2nd occurence of 0 so we can scroll back up to 9 again\n        this.setTrackPositionToWrapDigit(digitcontainer);\n      } else {\n        tracknode.style.transition = \"none\";\n\n        // shift to the 2nd occurence of 0 so we can scroll back up to 9 again\n        this.setTrackPositionToWrapDigit(digitcontainer);\n\n        setTimeout(() => { tracknode.style.transition = \"\"; });\n      }\n    }\n  }\n\n  enhanceDOM() {\n    const digits = this.node.querySelectorAll(\".countdown__digit\");\n\n    const frag_alldigits = this.getDigitsFragment([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);\n    const frag_lessdigits = this.getDigitsFragment([0, 1, 2, 3, 4, 5, 0]); // seconds and minutes only go up to 59\n    const frag_digits_hourstens = this.getDigitsFragment([0, 1, 2, 0]); // hours only goes up to 23\n\n    for (const digit of digits) {\n      const digitdesc = digit.getAttribute(\"data-digit\");\n\n      let frag;\n      if (digitdesc === \"minutes-ten\" || digitdesc === \"seconds-ten\")\n        frag = frag_lessdigits;\n      else if (digitdesc === \"hours-ten\")\n        frag = frag_digits_hourstens;\n      else\n        frag = frag_alldigits;\n\n      digit.replaceChild(frag.cloneNode(true), digit.firstChild!);\n    }\n  }\n\n  getDigitsFragment(nrs: number[]) {\n    /*\n    Create digits DOM which we can clone/copy into each digit container.\n    These are the numbers we can scroll.\n    By adding an extra 0 we can animate from the last number (9 or 5) to the 0\n    and after the transition finished jump back to the 0 at the top\n    so it seems the counter wraps endlessly.\n    */\n    const frag = document.createDocumentFragment();\n    const paper = document.createElement(\"div\"); // container which we move through the .countdown__digit viewport/track\n    paper.className = \"countdown__digit__track\";\n    frag.appendChild(paper);\n\n    // 0 to 9\n    for (const current_nr of nrs) {\n      const digitnode = document.createElement(\"div\");\n      digitnode.className = \"countdown__digit__number\";\n      digitnode.innerText = current_nr.toString();\n      paper.appendChild(digitnode);\n    }\n\n    return frag;\n  }\n}\n\nexport function parseCountdownToString(str: string) {\n  const parts = str.split(\" \");\n  const dayparts = parts[0].split(\"-\");\n  const timeparts = parts[1].split(\":\");\n  const date = new Date(Number(dayparts[0]), Number(dayparts[1]) - 1, Number(dayparts[2]), Number(timeparts[0]), Number(timeparts[1]));\n\n  return date;\n}\n\ndompack.register(\".component-countdown[data-countdownto]\", node => new CountDownComponent(node as HTMLElement, {}));\n","import * as dompack from \"@webhare/dompack\";\n\nexport class fadeInOutSlides {\n  activeidx: number;\n  slides: HTMLElement[];\n  timer: ReturnType<typeof setTimeout> | undefined;\n  timeout: number;\n  constructor(node: HTMLElement, options: { timeout: number; selector: string }) {\n    this.activeidx = 0;\n    this.slides = dompack.qSA<HTMLElement>(node, options.selector);\n    this.timeout = options.timeout;\n    if (this.slides.length <= 1)\n      return;\n\n    // Start/stop when the user focuses/unfocuses any element in the slideshow\n    node.addEventListener(\"focusin\", () => this.pauseSlides());\n    node.addEventListener(\"focusout\", () => this.resumeSlides());\n\n    this.timer = setTimeout(() => this.nextSlide(), this.timeout);\n  }\n\n  pauseSlides() {\n    clearTimeout(this.timer);\n    this.timer = undefined;\n  }\n\n  resumeSlides() {\n    if (!this.timer)\n      this.timer = setTimeout(() => this.nextSlide(), this.timeout);\n  }\n\n  nextSlide() {\n    this.gotoSlide(this.activeidx + 1);\n  }\n\n  gotoSlide(idx: number) {\n    clearTimeout(this.timer);\n    if (idx < 0)\n      idx = this.slides.length - 1;\n    else if (idx >= this.slides.length)\n      idx = 0;\n\n    this.slides[this.activeidx].hidden = true;\n    this.activeidx = idx;\n    this.slides[this.activeidx].hidden = false;\n\n    this.timer = setTimeout(() => this.nextSlide(), this.timeout);\n  }\n}\n","import \"./notificationbar.css\";\nimport * as dompack from \"@webhare/dompack\";\nimport { debugFlags } from \"@webhare/env\";\n\n/* to reset all hidden CTas:\nlocalStorage[\"ws-notifications\"]=\"\"\n*/\n\nconst notificationDelay = 250;\ntype NotificationNode = HTMLElement & { _wsTmpHeight?: string };\n\nlet notificationNode: NotificationNode;\nlet notificationId: string;\nlet closedNotifications: string[];\n\nfunction onShowNotification(event: CustomEvent) {\n  if (event.target === notificationNode) {\n    // Check if this notification has already been shown\n    const _storedClosedNotifications = localStorage.getItem(\"ws-notifications\");\n    if (_storedClosedNotifications)\n      closedNotifications = _storedClosedNotifications.split(\";\").filter(_ => Boolean(_));\n    else\n      closedNotifications = [];\n    if (debugFlags.umc)\n      console.log(`[umc] Closed notification CTA's`, closedNotifications);\n    notificationId = event.detail.cta.config.id;\n    if (closedNotifications.includes(notificationId)) {\n      // This notification has already been seen and closed by this user\n      if (debugFlags.umc)\n        console.warn(`[umc] Not showing closed notification CTA ${notificationId}`);\n      notificationNode.remove();\n      return;\n    }\n\n    setTimeout(() => {\n      // Force a style recalculation before getting the current height (hopefully fixes #1483)\n      notificationNode._wsTmpHeight = getComputedStyle(notificationNode).height;\n      const rect = notificationNode.getBoundingClientRect();\n      /* For debugging the notification header problem of #1483: set the 'notificationdebug' debug option to reload the page in a\n         loop until the problem occurs, after which some diagnostics are logged to the console\n      */\n      if (debugFlags.notificationdebug) {\n        if (notificationNode._wsTmpHeight !== \"60px\" || rect.height !== 60) {\n          console.info(\"_wsTmpHeight\", notificationNode._wsTmpHeight);\n          console.info(\"rect\", rect);\n          console.info(\"html\", notificationNode.outerHTML);\n\n        } else {\n          setTimeout(() => {\n            const u = new URL(location.href);\n            let c = parseInt(u.search.substring(1)) || 0;\n            ++c;\n            u.search = String(c);\n            location.href = u.toString();\n          }, 1000);\n        }\n        return;\n      }\n      notificationNode.style.height = `0`;\n\n      notificationNode.classList.remove(\"page-notificationbar--init\");\n      document.documentElement.classList.add(\"utwente--notificationvisible\");\n\n      notificationNode.classList.add(\"page-notificationbar--animate\");\n      // Force a style recalculation before setting the new height\n      notificationNode._wsTmpHeight = getComputedStyle(notificationNode).height;\n      notificationNode.style.height = `${rect.height}px`;\n      notificationNode.style.opacity = `1`;\n\n      dompack.dispatchCustomEvent(window, \"wh:notification-change\", { bubbles: false, cancelable: false, detail: { visible: true, height: rect.height } });\n    }, notificationDelay);\n  }\n}\n\nfunction onHideNotification(event: MouseEvent) {\n  event.preventDefault();\n\n  const rect = notificationNode.getBoundingClientRect();\n  notificationNode.style.height = `${rect.height}px`;\n\n  notificationNode.classList.add(\"page-notificationbar--close\");\n  // Force a style recalculation before setting the new height\n  notificationNode._wsTmpHeight = getComputedStyle(notificationNode).height;\n  notificationNode.style.height = `0`;\n  notificationNode.style.opacity = `0`;\n\n  dompack.dispatchCustomEvent(window, \"wh:notification-change\", { bubbles: false, cancelable: false, detail: { visible: false, height: rect.height } });\n\n  closedNotifications.push(notificationId);\n  localStorage.setItem(\"ws-notifications\", closedNotifications.join(\";\"));\n  if (debugFlags.umc)\n    console.info(`[umc] Closed notification CTA ${notificationId}`);\n}\n\nfunction onNotificationTransitionEnd(event: TransitionEvent) {\n  if (!notificationNode.parentNode || event.target !== notificationNode || event.propertyName !== \"height\")\n    return;\n\n  if (notificationNode.classList.contains(\"page-notificationbar--close\")) {\n    notificationNode.remove();\n    document.documentElement.classList.remove(\"utwente--notificationvisible\");\n  } else {\n    notificationNode.style.height = \"\";\n  }\n}\n\n\ndompack.register(\".page-notificationbar\", node => {\n  notificationNode = node;\n\n  document.documentElement.addEventListener(\"ws:managed-cta\", ev => onShowNotification(ev as CustomEvent));\n  //there may be multiple CTAs. we might want to listen at a higer level\n  dompack.qSA(\".notification__close\").forEach(icon => icon.addEventListener(\"click\", onHideNotification));\n  node.addEventListener(\"transitionend\", onNotificationTransitionEnd);\n});\n","import \"./deeplinks.css\";\nimport * as dompack from \"@webhare/dompack\";\nimport SmoothScroll from \"./smoothscroll\";\nimport scrollListener from \"./scrolllistener\";\nimport { getTid } from \"@webhare/gettid\";\nimport { slugify } from \"@webhare/std\";\n\n// Record initial hash\nconst initialhash = location.hash;\n\n/*\nShow the user where they are on the page\n- Update the visible deeplinks to show where you currently are in the page\n- Update the hash on the URL\n*/\nfunction checkHiglightDeeplink() {\n  // Find the deeplink containing our current content\n  let besthref = '', bestdeeplink;\n  const deeplinklist = dompack.qSA(\".main__deeplink\");\n  for (const deeplink of deeplinklist) {\n    const href = deeplink.getAttribute(\"href\") || '';\n    if (!href.startsWith('#'))\n      continue;\n\n    let target = document.getElementById(href.substring(1));\n    if (!target)\n      continue;\n\n    // If this is an <a> anchor link, switch to the parent <h2>\n    // <h2><a class=\"wh-rtd__anchor\" id=\"\"/></h2>\n    if (target.classList.contains(\"wh-rtd__anchor\") || target.classList.contains(\"wh-anchor\"))\n      target = target.closest(\"h2\") || target;\n\n    if (target.getBoundingClientRect().y <= window.innerHeight / 3) { //this one is at top or outside\n\n      bestdeeplink = deeplink;\n      besthref = href;\n    }\n\n  }\n\n  if (bestdeeplink && bestdeeplink.classList.contains(\"isvisible\"))\n    return; //already best one in sight\n\n  const currentvisible = dompack.qS(\".main__deeplink.isvisible\");\n  if (!bestdeeplink && !currentvisible)\n    return; //already no selected link\n\n  if (currentvisible)\n    currentvisible.classList.remove(\"isvisible\");\n\n  if (bestdeeplink) {\n    bestdeeplink.classList.add(\"isvisible\");\n    let isbefore = true;\n    for (const deeplink of deeplinklist) {\n      if (deeplink === bestdeeplink)\n        isbefore = false;\n\n      if (isbefore)\n        deeplink.classList.add(\"isbefore\");\n      else\n        deeplink.classList.remove(\"isbefore\");\n    }\n\n    //set hash on url\n    if (history.replaceState) {\n      //small timeout because some browsers (like safari) jump to anchor directly after loading page\n      setTimeout(function () { history.replaceState(null, \"\", document.location.href.split(\"#\")[0] + besthref); }, 10);\n    }\n  } else {\n    //remove hash from url\n    if (history.replaceState) {\n      //small timeout because some browsers (like safari) jump to anchor directly after loading page\n      setTimeout(function () { history.replaceState(null, \"\", document.location.href.split(\"#\")[0]); }, 10);\n    }\n  }\n}\n\nexport function initDeeplinksNav() {\n  // Add anchors to rtd H2's (replacement for the old serverside contentnavstops)\n  dompack.qSA(\".page-content > h2.heading2\").forEach((h2) => {\n    if (dompack.qS(h2, \"a.wh-anchor\"))\n      return;\n\n    const anchorId = slugify(h2.textContent || '');\n    if( anchorId )\n      h2.prepend(<a class=\"wh-anchor\" id={`${anchorId}`}></a>);\n\n    if( initialhash === `#${anchorId}` ) // initialhash is set on page load, so we can check if the user has opened a deeplink directly\n      h2.scrollIntoView({ behavior: \"auto\", block: \"start\" });\n  });\n\n  if (document.documentElement.classList.contains(\"ws2016--iframed\")) {\n    if ((window.innerWidth >= 483 && window.innerWidth <= 490) || (window.innerWidth >= 530 && window.innerWidth <= 540))\n      return;\n  }\n\n  setupDeepLinksNav();\n}\n\nfunction setupDeepLinksNav() {\n  const headings = [];\n  for (const h2 of dompack.qSA(\"h2:not([data-ut-ignore-deeplink]):not(.wh-form__grouptitle)\")) {\n    if (h2.closest(\".wh-details__container\"))\n      continue; //Ignore if already inside a foldable container, utwente/utwente_base#1962\n\n    const formpage = h2.closest(\".wh-form__page\");\n    if (formpage && formpage.previousElementSibling && formpage.previousElementSibling.classList.contains(\"wh-form__page\"))\n      continue; //Skip if h2 is inside followup page inside forms\n\n    // FIXME: maybe we could add the H2's from the table to the deeplinks, but not fold them.\n    //        To do this we would need to replace the array \"target\" (with all h2's to both add to the list and fold) into two lists.\n    if (h2.closest(\".wh-rtd__tablecell\"))\n      continue; //dont create folds in tables, utwente/utwente_base#1136\n\n    let anchor;\n    if (h2.id)\n      anchor = h2;\n\n    const linkanchor = dompack.qS(h2, \"a[id]\");\n    if (linkanchor)\n      anchor = linkanchor;\n\n    if (!anchor)\n      continue; //skip any h2 without an anchor\n\n    // If a deeplink has the same name as another element on the page (e.g. \"menu\"), rename the id\n    if (dompack.qSA(`*[id='${anchor.id}']`).length > 1) {\n      let i = 1;\n      let newid = anchor.id + \"-\" + i;\n      while (document.getElementById(newid))\n        newid = anchor.id + \"-\" + ++i;\n      anchor.id = newid;\n    }\n\n    const text = h2.textContent.trim();\n\n    headings.push(<li class=\"main__deeplinkitem\"><a class=\"main__deeplink\" title={text} propTarget={h2} href={\"#\" + anchor.id}>{text}</a></li>);\n  }\n\n  if (headings.length <= 1) //no deeplinks if we only have one (utwente/itcwebsite#112)\n    return;\n\n  const deeplinksNode =\n    <nav class=\"main__deeplinks\" aria-label={getTid(\"utwente_base:frontend.ws2016.js.landmark-deeplinks-arialabel\")}>\n      <ul class=\"main__deeplinklist\">{headings}</ul>\n    </nav>;\n\n  dompack.qS('.page-content')?.append(\n    <div class=\"page-deeplinks\">\n      {deeplinksNode}\n    </div>);\n\n  // Initialize smooth scrolling for the deeplinks\n  const deeplinks = dompack.qSA<HTMLAnchorElement>(deeplinksNode, \".main__deeplink\");\n  new SmoothScroll(deeplinks);\n  scrollListener.addNodes(deeplinks);\n\n  //Watch scrolls/resize and check deeplink to highlight after such a change\n  checkHiglightDeeplink();\n  window.addEventListener(\"scroll\", checkHiglightDeeplink);\n  window.addEventListener(\"ws:resize\", checkHiglightDeeplink);\n\n  const targets = [];\n  deeplinks.forEach(deeplink => {\n    const href = deeplink.getAttribute(\"href\") || '';\n    if (!href.startsWith('#'))\n      return;\n\n    let target = document.getElementById(href.substring(1));\n    if (!target)\n      return;\n\n    // If this is an <a> anchor link, switch to the parent <h2>\n    // <h2><a class=\"wh-rtd__anchor\" id=\"\"/></h2>\n    if (target.classList.contains(\"wh-rtd__anchor\") || target.classList.contains(\"wh-anchor\"))\n      target = target.closest(\"h2\") || target;\n\n    // Prepend the target to the list of targets\n    targets.unshift(target);\n  });\n}\n","\n// CSS Smooth scroll based on: http://wibblystuff.blogspot.in/2014/04/in-page-smooth-scroll-using-css3.html\n// With improvements from: http://codepen.io/kayhadrin/pen/KbalA\nexport default class SmoothScroll {\n  constructor(nodes: HTMLAnchorElement[] ) {\n    for (const node of nodes) {\n      const href = node.getAttribute(\"href\");\n      if (href && href.indexOf(\"#\") >= 0) {\n        const target = document.getElementById(href.substring(href.indexOf(\"#\") + 1));\n        if (target) {\n          node.addEventListener(\"click\", event => {\n            event.preventDefault();\n            target.scrollIntoView({ block: \"start\", behavior: \"smooth\" });\n          });\n          target.setAttribute(\"data-scrollevent\", \"0\");\n        }\n      }\n    }\n  }\n}\n","import * as dompack from \"@webhare/dompack\";\n\n/*\n  Scrolllistener is used to trigger loading/animations when selected elements get inside/outside the viewport.\n  Use attribute 'data-scrollevent' to bind event 'wh:visibilitychange' to element\n  With the data-scrollevent an threshold can be set like data-scrollevent=\"100\".\n  Then event will be triggered when at least 100px of element gets visible or is hidden.\n  (On first time 'onload' all thresholds are 0)\n  Extras: data-scrollparallax and data-scrollzoom for parallax/zoom effect while scrolling\n  value of these attributes are the factors of the parallax speed / zoom factor\n*/\n\ntype scrollInfoType = {\n  state: string;\n  node: HTMLElement;\n  treshhold: number;\n  boundingrect: DOMRect | null;\n  actions: string[];\n  data: {\n    innernode: HTMLElement;\n    parallax?: number;\n    limitparallax?: boolean;\n    zoom?: number;\n  } | null;\n  measure: string;\n};\n\nclass ScrollListener {\n  elements: scrollInfoType[];\n  scrollactions: scrollInfoType[];\n  viewport_height: number = 0;\n  isinit: boolean;\n  isscrollup: boolean = false;\n  lastscroll: number = 0;\n  constructor() {\n    this.scrollactions = [];//contains nodes with active functions during scrolling\n    this.elements = [];\n\n    window.addEventListener(\"scroll\", () => this.onScroll());\n    window.addEventListener(\"resize\", () => this.onResize());\n\n    this.isinit = true;\n    this.onResize();\n\n    dompack.onDomReady(() => {\n      this.addNodes(dompack.qSA(\"[data-scrollevent]\"));\n    });\n  }\n\n  // Add nodes to listen to\n  addNodes(selnodes:HTMLElement[]) {\n    if (!selnodes.length)\n      return;\n\n    for (let i = 0; i < selnodes.length; ++i) {\n      const treshhold = selnodes[i].getAttribute(\"data-scrollevent\");\n\n      const nodeinfo: scrollInfoType = {\n        state: \"\",\n        node: selnodes[i],\n        treshhold: !treshhold ? 0 : parseInt(treshhold),\n        boundingrect: null,\n        actions: [],\n        data: null,\n        measure: \"\"\n      };\n\n      const scrollvisibleclass = selnodes[i].getAttribute(\"data-scrollvisibleclass\");\n      if (scrollvisibleclass)\n        selnodes[i].addEventListener(\"wh:visibilitychange\", () => selnodes[i].classList.add(scrollvisibleclass));\n\n      const measuremethod = selnodes[i].getAttribute(\"data-scrolleventmeasure\");\n      if (measuremethod)\n        nodeinfo.measure = measuremethod;\n\n      const parallax = selnodes[i].getAttribute(\"data-scrollparallax\");\n      if (typeof parallax === \"string\") {\n        const free = selnodes[i].hasAttribute(\"data-scrollparallaxfree\"); // if used, we won't limit the amount the element can be shifted based on how much clipped content there is\n\n        const innernode = selnodes[i].firstElementChild as HTMLElement;\n        if (innernode) {\n          const factor = Number(parallax);//movement factor\n          nodeinfo.data = {\n            innernode: innernode,\n            parallax: factor || 0.2,\n            limitparallax: !free\n          };\n          nodeinfo.actions.push(\"parallax\");\n          this.scrollactions.push(nodeinfo);\n        }\n      }\n\n      const zoom = selnodes[i].getAttribute(\"data-scrollzoom\");\n      if (typeof zoom === \"string\") {\n        const innernode = selnodes[i].firstElementChild as HTMLElement;\n        if (innernode) {\n          nodeinfo.data = {\n            innernode: innernode,\n            zoom: zoom ? Math.abs(Number(zoom)) : 1\n          };\n          nodeinfo.actions.push(\"zoom\");\n          this.scrollactions.push(nodeinfo);\n        }\n      }\n      this.elements = this.elements.filter(info => info.node !== selnodes[i]);\n      this.elements.push(nodeinfo);\n    }\n  }\n\n  onScrollActions() {\n    for (let i = 0; i < this.scrollactions.length; i++) {\n      const action = this.scrollactions[i];\n\n      if (action.state !== \"visible\")\n        continue;\n\n      //Parallax\n      if (action.actions.indexOf(\"parallax\") !== -1) {\n        const elementheight = action.data!.innernode.clientHeight;\n        if (action.data!.limitparallax && !elementheight) {\n          // if we cannot measure the content (absolute positioned content within the innernode?)\n          // we cannot limit the parallax.\n          continue;\n        }\n\n        const containerheight = action.node.clientHeight;\n\n        // determine how much larger the element to animate is compared to it's container\n        const overflowsize = elementheight - containerheight;\n\n        const p = 2 * (action.boundingrect!.bottom / (this.viewport_height + containerheight) - 0.5);//range -1 .. 1\n        const center = overflowsize * -0.5;\n\n        let factor = action.data!.parallax as number; // range of the parallax motion (how much it moves up to counter the page scroll)\n\n        // By default prevent the image moving outside of the container (leaving a gap)\n        if (action.data!.limitparallax && Math.abs(factor) > overflowsize) // is the amount of movement (in px) specified on the element larger than the amount the image inside has larger?\n          factor = factor < 0 ? -overflowsize : overflowsize;\n\n\n        if (!action.data!.innernode.style.transform) {\n          //first time: set top/bottom on auto\n          action.data!.innernode.style.top = \"auto\";//(center + p * factor ) + \"px\";\n          action.data!.innernode.style.bottom = \"auto\";\n        }\n\n        action.data!.innernode.style.transform = \"translate(0,\" + (center + p * factor) + \"px)\";\n      }\n\n      //Zoom effect\n      if (action.actions.indexOf(\"zoom\") !== -1) {\n        if (action.boundingrect!.top <= 0) { //start zoom effect if container starts to hide in top\n          const containerheight = action.node.clientHeight;\n          const p = -action.boundingrect!.top / containerheight;\n\n          const factor = 1 + p * (action.data!.zoom as number);\n          action.data!.innernode.style.transform = \"scale(\" + factor + \",\" + factor + \")\";\n          action.data!.innernode.style.opacity = String(1 - p);\n        } else {\n          action.data!.innernode.style.transform = \"scale(1,1)\";\n          action.data!.innernode.style.opacity = \"1\";\n        }\n      }\n\n    }\n  }\n\n  onScroll() {\n    const scrollpos = window.scrollY;\n    this.isscrollup = this.lastscroll ? this.lastscroll > scrollpos : false;\n    this.lastscroll = scrollpos;\n\n    this.checkElementsVisibility();\n\n    this.onScrollActions();\n  }\n\n  checkElementsVisibility() { //check if elements getting visible or hides\n    for (let i = this.elements.length - 1; i >= 0; --i) {\n      let visible = false;\n\n      const treshhold = this.isinit ? 0 : this.elements[i].treshhold;\n      let rect;\n\n      //console.log(\"Check visibility\", this.elements[i]);\n\n      // This was added for elements which itself cannot be measured correctly.\n      // (either because of use display: contents; of childnodes overflowing)\n      if (this.elements[i].measure === \"content\") {\n        let node = this.elements[i].node.firstElementChild;\n        while (node) {\n          rect = node.getBoundingClientRect();\n          if (rect.height > 0) {\n            // FIXME: if we want to support scroll effects we also need to combine the clientrects\n            //        of children and set this.elements[i].boundingrect = rect;\n            visible = (rect.top >= treshhold && this.viewport_height - rect.top >= treshhold) || (rect.bottom > treshhold && this.viewport_height - rect.bottom > treshhold);\n            if (visible)\n              break; // stop checking elements, part of the element is visible anyway\n          }\n\n          node = node.nextElementSibling;\n        }\n      } else {\n        rect = this.elements[i].node.getBoundingClientRect();\n        if (rect.height === 0) // currently not visible\n          continue;\n\n        this.elements[i].boundingrect = rect;\n        visible = (rect.top >= treshhold && this.viewport_height - rect.top >= treshhold) || (rect.bottom > treshhold && this.viewport_height - rect.bottom > treshhold);\n      }\n\n      if (visible) {\n        if (this.elements[i].state !== \"visible\") {\n          this.elements[i].state = \"visible\";\n          dompack.dispatchCustomEvent(this.elements[i].node, \"wh:visibilitychange\", {\n            bubbles: true,\n            cancelable: false,\n            detail: {\n              scrolldirection: this.isinit ? \"\" : (this.isscrollup ? \"up\" : \"down\"),\n              target: this.elements[i],\n              visible: true,\n              nodebounds: rect\n            }\n          });\n        }\n      } else {\n        if (this.elements[i].state === \"visible\") {\n          this.elements[i].state = \"hide\";\n          dompack.dispatchCustomEvent(this.elements[i].node, \"wh:visibilitychange\", {\n            bubbles: true,\n            cancelable: false,\n            detail: {\n              scrolldirection: this.isinit ? \"\" : (this.isscrollup ? \"up\" : \"down\"),\n              target: this.elements[i],\n              visible: false,\n              nodebounds: rect\n            }\n          });\n        }\n      }\n    }\n\n    this.isinit = false;\n  }\n\n  onResize() {\n    const win_height = window.innerHeight;\n    if (this.viewport_height && this.viewport_height === win_height)\n      return;\n\n    this.viewport_height = win_height;\n\n    this.onScroll();\n  }\n}\n\nconst scrollListener = new ScrollListener();\n\nexport default scrollListener;\n","import \"./osiris.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport { getTid } from \"@webhare/gettid\";\nimport { utDialog2, type UTDialog } from \"../forms/dialogs\";\nimport UtwenteService from \"@mod-utwente_base/js/service\";\n\nfunction importHTML(htmlstring: string) {\n  const doc = new DOMParser().parseFromString(htmlstring, 'text/html');\n  return [...dompack.qSA(doc, \"body > *\")];\n}\n\nasync function showOsirisLink2016(id: string) {\n  const language = document.documentElement.lang.startsWith(\"nl\") ? \"nl\" : \"en\";\n  const mainnode = document.querySelector(\".page-content\");\n  if (!mainnode) {\n    console.warn(\"Osiris link found without main contents\");\n    return;\n  }\n\n  //Open popup with loading message\n  const osiriscontentnode = <div class=\"loading\">{getTid(\"utwente_base:frontend.ws2016.js.osiris.loading\")}</div>;\n  const dialog = dialogapi.createDialog({ allowcancel: true }) as UTDialog;\n  if (!dialog.contentnode)\n    throw new Error(\"Dialog content node is not available\");\n\n  dialog.contentnode.appendChild(osiriscontentnode);\n  dialog.contentnode.classList.add(\"osiris\");\n  void dialog.runModal();\n\n  const result = await UtwenteService.GetOsirisCourse(id, language);\n  if (result && result.success) {\n    dialog.utheadernode.append(<h2 class=\"osiris__title\">{result.title}</h2>);\n    if (result.maxpoints)\n      dialog.utheadernode.append(<div class=\"osiris__maxpoints\">{result.maxpoints}</div>);\n\n    dialog.contentnode.replaceChildren(<div class=\"osiris__description\">{importHTML(result.contents)}</div>);\n    if (result.goal)\n      dialog.contentnode.append(<h3>{getTid(\"utwente_base:frontend.ws2016.js.osiris.goal\")}</h3>, ...importHTML(result.goal));\n    dialog.contentnode.append(...importHTML('<p class=\"normal\">' + getTid(\"utwente_base:frontend.ws2016.js.osiris.moredetailslink\", result.link) + '</p>'));\n  } else {\n    osiriscontentnode.textContent = getTid(\"utwente_base:frontend.ws2016.js.osiris.nocoursefound\");\n  }\n}\n\nasync function showOsirisLink2026(id: string) {\n  const language = document.documentElement.lang.startsWith(\"nl\") ? \"nl\" : \"en\";\n  const mainnode = document.querySelector(\".page-content\");\n  if (!mainnode) {\n    console.warn(\"Osiris link found without main contents\");\n    return;\n  }\n\n  //Open popup with loading message\n  const osiriscontentnode = <div class=\"loading\">{getTid(\"utwente_base:frontend.ws2016.js.osiris.loading\")}</div>;\n  const dialog = new utDialog2(osiriscontentnode, \"osiris\");//, { classname: \"dialog--small\" });\n\n  dialog.showModal();\n\n  const result = await UtwenteService.GetOsirisCourse(id, language);\n  if (result && result.success) {\n    // dialog.utheadernode.append();\n    // if (result.maxpoints)\n    //   dialog.utheadernode.append();\n\n    osiriscontentnode.replaceChildren(\n      <h2 class=\"osiris__title\">{result.title}</h2>,\n      <div class=\"osiris__maxpoints\">{result.maxpoints}</div>,\n      <div>{importHTML(result.contents)}</div>);\n    if (result.goal)\n      osiriscontentnode.append(<h3>{getTid(\"utwente_base:frontend.ws2016.js.osiris.goal\")}</h3>, ...importHTML(result.goal));\n\n    osiriscontentnode.append(...importHTML('<p class=\"normal\">' + getTid(\"utwente_base:frontend.ws2016.js.osiris.moredetailslink\", result.link) + '</p>'));\n  } else {\n    osiriscontentnode.textContent = getTid(\"utwente_base:frontend.ws2016.js.osiris.nocoursefound\");\n  }\n}\n\nfunction onOsirisLink(event: MouseEvent) {\n  const utcourselink = event.target instanceof HTMLElement ? event.target.closest<HTMLAnchorElement>(\"a[href^='x-ut-courselink:']\") : null;\n  if (!utcourselink)\n    return true;\n\n  event.preventDefault();\n\n  const id = utcourselink.getAttribute(\"href\")?.split(\":\")[1];\n  if (id)\n    if (document.documentElement.classList.contains(\"utwente--ws2026\"))\n      void showOsirisLink2026(id);\n    else\n      void showOsirisLink2016(id);\n\n  return false;\n}\n\nwindow.addEventListener('click', onOsirisLink);\n","import { createClient } from \"@webhare/jsonrpc-client\";\nimport { PageFiltersContext } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters\";\n\ntype OsirisResultsType = {\n  success: boolean;\n  title: string;\n  goal: string;\n  contents: string;\n  maxpoints: string;\n  year: number;\n  link: string;\n};\n\nexport type NEOResultsType = {\n  totalresults: number;\n  skip: number; // used for pagination, indicates how many items were skipped in the query (e.g. for \"load more\" functionality)\n  archive: boolean; // indicates whether the results are from the archive (only relevant for events)\n  tag: number; // indicates the tag used for filtering news items\n  links: Array<{\n    id: number;\n    link: string;\n  }>;\n  moreitems: boolean;\n  items: Array<{\n    title: string;\n    subtitle?: string;\n    description: string;\n    link: string;\n    dateformatted: string;\n    photolink?: string;\n    photolink_2x?: string;\n    photoalt?: string;\n    summaryphotolink?: string;\n    summaryphotolink_2x?: string;\n    summaryphotoalt?: string;\n    location?: string;\n    tags: Array<{\n      tag: string;\n      filter?: string;\n      id?: number;\n    }>;\n    addthisdata?: {\n      url: string;\n      title: string;\n      startdate: string;\n      enddate: string;\n      location?: string;\n      allday?: boolean;\n      description?: string;\n    };\n  }>;\n};\n\ntype NEOPageOptionsType = {\n  skip: number;\n  addhighlights?: boolean;\n  archive?: boolean;\n  tag?: number;\n};\n\ninterface UtwenteService {\n  GetNEOItems( objid: number, type: string, subtype: string, pagefiltercontext: PageFiltersContext, options: NEOPageOptionsType ): Promise<NEOResultsType>;\n  GetOsirisCourse(id: string, language: string): Promise<OsirisResultsType>;\n  MailContactPerson(formdata: {phone: string; widgetid: number; pageid: number}): Promise<{success: boolean; errors: {tag: string; error: string}[]}>;\n  GetXLSXExport(url: string, idxlist: number[]): Promise<{data: string; filename: string}| null>;\n}\n\nexport default createClient<UtwenteService>(\"utwente_base:rpc\");\n","import * as dompack from \"@webhare/dompack\";\n\nimport { observeNodeResize } from \"@mod-utwente_base/webdesigns/ws2016/src/components/resizeobserver\";\n\nimport SlideShow from \"@mod-utwente_base/webdesigns/ws2016/src/shared/slideshow\";\nimport * as fsslideshow from \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/photoalbum/fullscreen-slideshow\";\n\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/widgetsholder/widgetsholder\";\n\nimport * as layout from '@mod-utwente_base/webfeatures/utwidgets/layout';\nimport UtwenteService from \"@mod-utwente_base/js/service\";\n\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/consentcheck\";\n\n\n// ws2016 widgets that are still used in ws2026 (not yet ported or shared)\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/widgets-general.scss\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/homepage\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/edunumbers/edunumbers.scss\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/ff-innumbers\";\n\nimport '@mod-utwente_base/webfeatures/utwidgets/downloads';\nimport '@mod-utwente_base/webfeatures/utwidgets/imagewithcaption';\n\nimport '@mod-utwente_base/webfeatures/utwidgets/countdown';\nimport \"@mod-utwente_base/webfeatures/utwidgets/countdown/countdown2026.css\"; // aditional ws2026 styling\nimport '@mod-utwente_base/webfeatures/utwidgets/ctawithimage/ctawithimage';\nimport \"@mod-utwente_base/webfeatures/utwidgets/ctawithimage/ctawithimage2026.css\"; // aditional ws2026 styling\nimport '@mod-utwente_base/webfeatures/utwidgets/events';\nimport '@mod-utwente_base/webfeatures/utwidgets/faq';\nimport '@mod-utwente_base/webfeatures/utwidgets/featuredpages';\nimport '@mod-utwente_base/webfeatures/utwidgets/imagevideowithtext';\nimport '@mod-utwente_base/webfeatures/utwidgets/insetblock';\nimport '@mod-utwente_base/webfeatures/utwidgets/news';\nimport '@mod-utwente_base/webfeatures/utwidgets/phonedirectory';\nimport '@mod-utwente_base/webfeatures/utwidgets/programmelist';\nimport '@mod-utwente_base/webfeatures/utwidgets/quote';\nimport '@mod-utwente_base/webfeatures/utwidgets/soundcloud';\nimport '@mod-utwente_base/webfeatures/utwidgets/tablewithtabs';\nimport '@mod-utwente_base/webfeatures/utwidgets/video';\n\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/carrousel\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/photoalbum\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/slideshow\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/progress\";   // progress / admission widget\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/timeline\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/course_overview\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/managed-cta\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/banner\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/pagenavigation\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/richtext-ff\";\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/linksgrid/linksgrid.scss\";\n\nimport \"@mod-utwente_base/webdesigns/ws2016/src/widgets/figures\";\n\n// ws2026:\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/embeddedobjects.scss\";// ToDo: split/cleanup\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/embeddedobjects-cta.css\";// ToDo: split/cleanup\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/widgets.scss\"; // ToDo: split/cleanup\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/linkspercategory_colors/linkspercategory_colors.scss\";\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/linkspercategory_tabs/linkspercategory_tabs\";\nimport \"@mod-utwente_base/webfeatures/utwidgets/linkswithimage/linkswithimage.css\"; // no tsx, only css\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/newsandevents/newsandevents\";\nimport '@mod-utwente_base/webfeatures/utwidgets/sam-chat/sam-chat.ts'; //SAM chat initiator\n\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/persons/contactperson-inline.css\";\nimport \"@mod-utwente_base/webdesigns/ws2026/widgets/photoalbum/photoalbum\";\nimport { initFoldableContent } from \"@mod-utwente_base/webdesigns/ws2026/widgets/embeddedobjects\";\n\n// Extend HTMLElement to allow _wsSlideShow property\ndeclare global {\n  interface HTMLElement {\n    _wsSlideShow?: SlideShow;\n  }\n}\n\n\nclass Tabs {\n  tabIndicator: HTMLElement | null;\n  tabs: { title: HTMLElement | null; page: HTMLElement }[];\n  pageholder: HTMLElement;\n  pulldown: HTMLSelectElement | null;\n  curIdx: number;\n  resizeTimeout: number | null;\n  dir: number = document.documentElement.dir === 'rtl' ? 1 : -1;\n\n  constructor(container: HTMLElement) {\n    this.tabIndicator = dompack.qS(container, \".widget__tabs-currenttitle\");\n    this.tabs = [];\n    this.pageholder = dompack.qR(container, \".widget__tabs-contents\");\n    this.pulldown = null;\n    if (container.classList.contains(\"widget__tabs--pulldown\")) {\n      this.pulldown = dompack.qR<HTMLSelectElement>(container, \"select.widget__tabs-pulldown\");\n      this.pulldown.addEventListener(\"change\", () => this.switchTab(Number(this.pulldown!.value)));\n    }\n\n    const titles = !this.pulldown ? dompack.qSA(container, \".widget__tabs-titletext\") : [];\n    dompack.qSA(container, \".widget__tabs-page\").forEach((page, idx) => {\n      const tab = {\n        title: titles[idx],\n        page: page\n      };\n      this.tabs.push(tab);\n      if (tab.title)\n        tab.title.addEventListener(\"click\", () => this.switchTab(idx));\n      else {\n        // Position each subsequent tab over the first tab (we cannot use position: absolute, because we want our container\n        // to have the height of the highest tab)\n        tab.page.style.marginLeft = idx ? (100 * this.dir) + \"%\" : \"0\";\n      }\n      tab.page.classList.remove(\"widget__tabs-page--init\");\n    });\n\n    this.curIdx = 0;\n    observeNodeResize(container, () => this.resizeTimeout = this.resizeTimeout || requestAnimationFrame(() => this.updateTabIndicator()));\n    this.resizeTimeout = requestAnimationFrame(() => this.updateTabIndicator());\n  }\n\n  switchTab(newIdx: number) {\n    this.curIdx = newIdx;\n\n    if (!this.pulldown) {\n      const pos = this.dir * 100 * this.curIdx;\n      this.pageholder.style.transform = `translateX(${pos}%)`;\n    }\n\n    this.updateTabIndicator();\n  }\n\n  updateTabIndicator() {\n    this.resizeTimeout = null;\n    let firstLeft = 0;\n    this.tabs.forEach((tab, idx) => {\n      if (this.pulldown) {\n        if (idx === this.curIdx) {\n          // Position the next tab on top of the current tab (the new tab is transparent and fades in)\n          tab.page.style.zIndex = \"2\";\n          tab.page.classList.add(\"widget__tabs-page--current\");\n        } else {\n          // Position the current tab beneath the new tab (the new tab is transparent and fades in)\n          tab.page.style.zIndex = \"1\";\n          tab.page.classList.remove(\"widget__tabs-page--current\");\n        }\n        return;\n      }\n      const titleRect = tab.title!.getBoundingClientRect(); //title is .widget__tabs-titletext\n      if (!idx)\n        firstLeft = titleRect[this.dir === 1 ? \"right\" : \"left\"];\n\n      if (idx === this.curIdx && this.tabIndicator) {\n        tab.title!.classList.add(\"widget__tabs-titletext--current\");\n        this.tabIndicator!.style[this.dir === 1 ? \"right\" : \"left\"] = (-this.dir) * (titleRect[this.dir === 1 ? \"right\" : \"left\"] - firstLeft) + \"px\";\n        this.tabIndicator!.style.width = tab.title!.getBoundingClientRect().width + \"px\";\n      } else {\n        tab.title!.classList.remove(\"widget__tabs-titletext--current\");\n      }\n    });\n  }\n}\n\n// Initialize callbackforms (contactperson widgets)\nfunction initializeCallbackForm(node: HTMLElement) {\n  const formNode = dompack.qS<HTMLFormElement>(node, \"form\");\n  if (formNode) {\n    const inputNode = dompack.qR<HTMLInputElement>(formNode, \"input[name='phone']\");\n    inputNode.value = \"\";\n    formNode.addEventListener(\"submit\", event => {\n      dompack.stop(event);\n\n      const phonenr = inputNode.value;\n      if (Number(phonenr.replace(/[^0-9]/g, \"\")) > 999) { // Submit at least 4 digits\n        const formdata = {\n          phone: phonenr,\n          pageid: Number(formNode.getAttribute(\"data-pageid\")),\n          widgetid: Number(formNode.getAttribute(\"data-widgetid\"))\n        };\n        void submitCallbackForm(node, formdata);\n      }\n    });\n  }\n}\n\nasync function submitCallbackForm(node: HTMLElement, formdata: { phone: string; widgetid: number; pageid: number }) {\n  const lock = dompack.flagUIBusy({ modal: true });\n  node.classList.add(\"widget__callbackform--loading\");\n  let result: { success: boolean; errors: { tag: string; error: string }[] };\n  try {\n    result = await UtwenteService.MailContactPerson(formdata);\n  } finally {\n    lock.release();\n    node.classList.remove(\"widget__callbackform--loading\");\n  }\n\n  if (result.success) {\n    node.classList.add(\"widget__callbackform--success\");\n    layout.relayoutWidgets(node);\n  } else if (result.errors.length > 0) {\n    console.error(\"Error submitting callback form:\", result.errors);\n  }\n}\n\ndompack.register(\".widget__callbackform\", callbackform => initializeCallbackForm(callbackform));\n\nfunction initializePhotoslide(widgetphotos: HTMLElement) {\n  const slides = dompack.qSA(widgetphotos, \".widget__photoslide\");\n\n  if (widgetphotos.classList.contains(\"widget__photos--infos\")) {\n    (widgetphotos.closest(\".widget\") as HTMLElement).addEventListener(\"ws:relayoutwidgetcontent\", relayoutPhotoslideByEvent);\n    relayoutPhotoslide(widgetphotos);\n  }\n\n  widgetphotos._wsSlideShow = new SlideShow(slides, {\n    dotNodes: widgetphotos.querySelectorAll(\".widget__photosliderdot\"),\n    pauseNode: widgetphotos\n  });\n}\n\nfunction relayoutPhotoslideByEvent(evt: Event) {\n  const node = dompack.qS(evt.target as HTMLElement, \".widget__photos\");\n  if (node)\n    relayoutPhotoslide(node);\n}\n\nfunction relayoutPhotoslide(widgetphotos: HTMLElement) {\n  const slides = dompack.qSA(widgetphotos, \".widget__photoslide\");\n\n  let infoheight = 0;\n  for (const node of slides) {\n    const info = dompack.qR(node, \".widget__photoinfo\");\n    const height = info.getBoundingClientRect().height;\n    if (height > infoheight)\n      infoheight = height;\n\n    if (node.classList.contains(\"widget__photoslide--infoinit\"))\n      node.classList.remove(\"widget__photoslide--infoinit\");\n  }\n  if (infoheight > 0) {\n    widgetphotos.style.marginBottom = `${infoheight}px`;\n  }\n}\n\n// @ts-ignore FIXME fsslideshow requires update for export functions\nwindow.relayoutPhotoslide = relayoutPhotoslide;\n\n\n// Initialize widget photo slideshows\ndompack.register(\".widget__photos\", widgetphotos => initializePhotoslide(widgetphotos));\n\n\n// Initialize widget info slideshows\ndompack.register(\".widget__infos--slideshow\",\n  widgetinfos => {\n\n    widgetinfos._wsSlideShow = new SlideShow(widgetinfos.querySelectorAll(\".widget__infoslide\"), {\n      dotNodes: widgetinfos.querySelectorAll(\".widget__infosliderdot\"),\n      pauseNode: widgetinfos\n    });\n  }\n);\n\n\ndompack.register(\".widget__image\", imagewidget => {\n  const instanceid = imagewidget.getAttribute(\"data-instanceid\");\n  imagewidget.addEventListener(\"click\", () => {\n    // @ts-ignore FIXME fsslideshow requires update for export functions\n    fsslideshow.doActivateSlideshow(instanceid, 0);\n  });\n});\n\n// Initialize widget tabs\ndompack.register(\".widget__tabs\", widgettabs => new Tabs(widgettabs));\n\n// Initialize widget flips\ndompack.register(\".widget__flip\", widgetflip => {\n  widgetflip.addEventListener(\"click\", event => {\n    const widget = (event.target as HTMLElement).closest(\".widget\");\n    if (widget) {\n      const widgetinfos = dompack.qS(widget, \".widget__infos--slideshow\");\n\n      if (widget.classList.contains(\"widget--rotated\")) {\n        widget.classList.remove(\"widget--rotated\");\n        if (widgetinfos)\n          widgetinfos._wsSlideShow!.resume();\n      } else {\n        widget.classList.add(\"widget--rotated\");\n        if (widgetinfos)\n          widgetinfos._wsSlideShow!.stop();\n      }\n    }\n  });\n});\n\n//Reflow widgets if the form is changed\nwindow.addEventListener('wh:form-validitychange', event => {\n  const widget = (event.target as HTMLElement).closest('.widget');\n  if (widget)\n    layout.relayoutWidgets(widget);\n});\n\ndompack.register(\".foldablecontent:not(.foldablecontent--active)\", node => initFoldableContent(node));\n\n// Use onLoad where we need actual element sizes after rendering (like custom fonts)\n// Also this fixes initial layout issues in Firefox (0px height widgets)\nwindow.addEventListener(\"load\", function () {\n  // Force redoing layouts\n  layout.forceRelayoutWidgets(null);\n});\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n// A wrapper around ResizeObserver with a polyfill for browsers that don't support it\n\nlet observer, resizeListener;\nif (ResizeObserver)\n  observer = new ResizeObserver(entries => onResize(entries));\nelse\n  window.addEventListener(\"resize\", () => resizeListener = resizeListener || requestAnimationFrame(event => onWindowResize(event)));\nconst nodes = new Map();\n\nfunction onResize(entries) {\n  for (const entry of entries) {\n    const callback = nodes.get(entry.target);\n    if (callback)\n      callback(entry);\n  }\n}\n\nfunction onWindowResize() {\n  for (const [node, entry] of nodes.entries()) {\n    const rect = node.getBoundingClientRect();\n    if (rect.height != entry.rect.height || rect.width != entry.rect.width) {\n      entry.rect = rect;\n      entry.callback({ target: node, boundingClientRect: rect });\n    }\n  }\n  resizeListener = null;\n}\n\n/** @short Call the callback if the node is resized\n    @long This registers a callback which is called if the given node is resized. If called multiple times for the same node,\n        only the last callback is called.\n    @param The node to observe\n    @callback The callback that is called if the node is resized, receiving a ResizeObserverEntry object if the browser\n        supports ResizeObserver, or an object containing `target` (the node that was resized) and `boundingClientRect`\n        (the new size of the node) properties\n*/\nexport function observeNodeResize(node, callback) {\n  if (observer)\n    observer.observe(node);\n\n  if (observer)\n    nodes.set(node, callback);\n  else\n    nodes.set(node, { callback, rect: node.getBoundingClientRect() });\n}\n\n/** @short Stop observing this node for resizing\n    @long This unregisters a previously registered callback for the given node. It is not an error to call this function for\n        a node without a registered callback.\n    @param The node that was being observed\n*/\nexport function unobserveNodeResize(node) {\n  if (nodes.has(node)) {\n    nodes.delete(node);\n    if (observer)\n      observer.unobserve(node);\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport utwenteCookies from \"@mod-utwente_design/js/cookiebar\";\nimport * as dompack from \"dompack\";\nimport * as videotools from \"../components/video\";\nimport SwipeDetect from \"../components/swipedetect\";\n\n\nexport default class SlideShow {\n  constructor(nodes, options) {\n    this.nodes = [];\n    this.players = [];\n    this.dotNodes = [];\n    this.curSlide = -1;\n\n    this.options = {\n      timeout: 5000,\n      dotNodes: null,\n      pauseNode: null,\n      enableswipe: true, ...options\n    };\n\n    // Make a list of nodes\n    for (const node of nodes) {\n      node.addEventListener(\"transitionend\", this.onSlide.bind(this));\n      if (this.nodes.length) {\n        // Set z-index of slides not currently visible to 0\n        node.classList.add(\"slideshow--slidein\");\n        node.style.zIndex = 0; // Not visible\n      } else {\n        this.containerNode = node.parentNode;\n        this.containerNode.style.zIndex = 0; // Reset z-index\n        node.style.zIndex = 2; // Currently visible\n      }\n      this.nodes.push(node);\n      // Set visibility to visible (slides are hidden initially)\n      node.style.display = \"block\";\n    }\n\n    // No need to slide\n    if (!this.nodes.length)\n      return;\n    if (this.nodes.length === 1) {\n      // There is one slide, maybe it contains a video?\n      const node = this.nodes[0];\n      if (node.hasAttribute(\"data-video\"))\n        this.initializeVideoSlide(node, 0, false);\n      return;\n    }\n\n    if (this.containerNode && this.options.enableswipe) {\n      new SwipeDetect(this.containerNode);\n      this.containerNode.addEventListener('wh:swipe', function (ev) {\n        if (ev.detail.direction === 'w') {\n          const nextSlide = this.curSlide + 1;\n          this.nextNode(nextSlide >= this.nodes.length ? 0 : nextSlide, false);\n        } else if (ev.detail.direction === 'e') {\n          const nextSlide = this.curSlide - 1;\n          this.nextNode(nextSlide < 0 ? this.nodes.length - 1 : nextSlide, true);\n        }\n      }.bind(this));\n    }\n\n    // Pause on hover, if requested\n    if (this.options.pauseNode) {\n      this.options.pauseNode.addEventListener(\"mouseover\", this.pause.bind(this));\n      this.options.pauseNode.addEventListener(\"mouseout\", this.play.bind(this));\n    }\n\n    // Make a list of dots\n    if (this.options.dotNodes)\n      Array.from(this.options.dotNodes).forEach((dot, idx) => {\n        this.dotNodes.push(dot);\n        dot.addEventListener(\"click\", event => {\n          this.nextNode(idx);\n          // If the slideshow was stopped, resume it\n          this.resume();\n        });\n      });\n\n    // Show the first slide\n    this.nextNode();\n  }\n\n  nextNode(nextindex, moveleft) {\n    // Show the next slide after 'timeout' ms\n    clearTimeout(this.nextTimeout);\n    if (!this.paused)\n      this.nextTimeout = setTimeout(this.nextNode.bind(this), this.options.timeout);\n\n    // Run the actual animation within an animation frame, so the animation only continues if the browser is actually showing\n    // the animation\n    if (this.slideTimeout)\n      cancelAnimationFrame(this.slideTimeout);\n    this.slideTimeout = requestAnimationFrame(() => {\n      if (typeof nextindex !== 'undefined') {\n        if (nextindex === this.curSlide)\n          return;\n\n        this.nextSlide = nextindex;\n\n        if (this.prevNode && this.prevNode.classList.contains(\"slideshow--slideout\")) {\n          this.prevNode.style.zIndex = 0; // Not visible\n          this.prevNode.classList.remove(\"slideshow--slideout\");\n          this.prevNode.classList.add(\"slideshow--slidein\");\n        }\n      }\n\n      // Keep a reference to the previous slide\n      this.prevNode = this.curSlide < 0 ? null : this.nodes[this.curSlide];\n\n      // Select the next slide\n      this.containerNode.classList.remove(\"slideshow--slideleft\");\n      if (typeof this.nextSlide !== 'undefined' && this.nextSlide !== null) {\n        if (this.nextSlide < this.curSlide && typeof moveleft !== 'boolean' || moveleft)\n          this.containerNode.classList.add(\"slideshow--slideleft\");\n\n        this.curSlide = this.nextSlide;\n        this.nextSlide = null;\n      } else\n        ++this.curSlide;\n\n      if (this.curSlide >= this.nodes.length)\n        this.curSlide = 0;\n      const curNode = this.nodes[this.curSlide];\n\n      if (curNode.hasAttribute(\"data-video\")) {\n        curNode.addEventListener(\"click\", event => this.initializeVideoSlide(curNode, this.curSlide, true));\n      }\n\n      this.slideTimeout = null;\n\n      // If there is a previous slide, insert the new slide and start the transition\n      if (this.prevNode) {\n        // Update z-index of current and next slide\n        this.prevNode.style.zIndex = 1; // About to slide out\n        curNode.style.zIndex = 2; // About to slide in\n        // Start the transition\n        this.prevNode.classList.add(\"slideshow--slideout\");\n        curNode.classList.remove(\"slideshow--slidein\");\n      }\n\n      // Update the active slider dot\n      this.dotNodes.forEach((dot, idx) => {\n        // Cannot use classList.toggle with second parameter as it's not supported by IE11\n        if (idx === this.curSlide)\n          dot.classList.add(\"slideshow--activedot\");\n        else\n          dot.classList.remove(\"slideshow--activedot\");\n      });\n\n      dompack.dispatchCustomEvent(window, \"ws:nextslide\", {\n        bubbles: true,\n        cancelable: false,\n        detail: {\n          target: this,\n          idx: this.curSlide\n        }\n      });\n    });\n  }\n\n  initializeVideoSlide(node, idx, startplay) {\n    if (!utwenteCookies.getConsent())\n      return;\n\n    if (!videotools.isVideoNodeInitialized(node)) {\n      videotools.initializeVideoNode(node).then(player => {\n        this.players[idx] = player;\n\n        // Hide poster image and play button\n        node.classList.remove(\"widget__photoslide--poster\");\n\n        // Stop the slideshow when the video starts playing\n        node.addEventListener(\"video:play\", event => this.stop());\n        // Show the slider dots when the video is paused (they're hidden again\n        // when the video resumes which triggers a video:play event)\n        node.addEventListener(\"video:pause\", event => this.toggleDotNodes(true));\n        // If the video has finished playing, resume the slideshow\n        node.addEventListener(\"video:finish\", event => this.resume());\n\n        // If the player is ready, start it\n        if (startplay)\n          node.addEventListener(\"video:ready\", event => player.play());\n      });\n    } else if (this.players[idx]) {\n      // Hide poster image and play button\n      node.classList.remove(\"widget__photoslide--poster\");\n\n      // Resume/replay the video\n      this.players[idx].play();\n    }\n  }\n\n  // Pause the slideshow on hover\n  pause() {\n    this.paused = true;\n    if (this.nextTimeout) {\n      clearTimeout(this.nextTimeout);\n      this.nextTimeout = null;\n      this.dotNodes.forEach((dot, idx) => {\n        if (idx === this.curSlide)\n          dot.classList.add(\"slideshow--paused\");\n      });\n    }\n  }\n\n  // Play the slideshow again after mouseout, unless it's stopped\n  play() {\n    if (this.stopped)\n      return;\n\n    this.paused = false;\n    if (!this.nextTimeout) {\n      this.nextTimeout = setTimeout(this.nextNode.bind(this), this.options.timeout / 2);\n    }\n    this.dotNodes.forEach(dot => dot.classList.remove(\"slideshow--paused\"));\n  }\n\n  // Stop the slideshow until it's resumed\n  stop() {\n    this.pause();\n    this.stopped = true;\n    this.toggleDotNodes(false);\n  }\n\n  // Start playing the slideshow again\n  resume() {\n    this.stopped = false;\n    this.toggleDotNodes(true);\n    for (const node of this.nodes)\n      node.classList.add(\"widget__photoslide--poster\");\n    this.play();\n  }\n\n  toggleDotNodes(show) {\n    this.dotNodes.forEach(dot => dot.style.display = show ? \"\" : \"none\");\n  }\n\n  onSlide(event) {\n    // Check if this is the slide that is no longer active\n    if (event.target === event.currentTarget\n      && event.target.classList.contains(\"slideshow--slideout\")) {\n      // Reset z-index and classes\n      event.target.style.zIndex = 0; // Not visible\n      event.target.classList.remove(\"slideshow--slideout\");\n      event.target.classList.add(\"slideshow--slidein\");\n    }\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\nexport default class SwipeDetect {\n  constructor(node, options) {\n    if (!node)\n      return;\n\n    this.options = {\n      threshold_distance: 15,\n      threshold_speed: 0.3,\n      enablemouseswipe: true, ...options\n    };\n\n    this.swipeinfo = null;\n    this.node = node;\n\n    if (this.options.enablemouseswipe) {\n      node.addEventListener(\"mousedown\", event => this.onTouchStart(event));\n      node.addEventListener(\"mousemove\", event => this.onTouchMove(event));\n      node.addEventListener(\"mouseup\", event => this.onTouchEnd(event));\n    }\n    if (this.touchEnabled()) {\n      node.addEventListener(\"touchstart\", event => this.onTouchStart(event));\n      node.addEventListener(\"touchmove\", event => this.onTouchMove(event));\n      node.addEventListener(\"touchend\", event => this.onTouchEnd(event));\n    }\n  }\n\n  touchEnabled() {\n    return (\"createTouch\" in document);\n  }\n\n  onTouchStart(ev) {\n    this.swipeinfo = {\n      starttime: new Date().getTime(),\n      endtime: -1,\n      start: { x: ev.pageX, y: ev.pageY },\n      end: { x: ev.pageX, y: ev.pageY },\n      target: ev.target,\n      direction: \"\"\n    };\n  }\n\n  onTouchMove(ev) {\n    if (!this.swipeinfo)\n      return;\n    this.swipeinfo.end = { x: ev.pageX, y: ev.pageY };\n  }\n\n  onTouchEnd(ev) {\n    if (!this.swipeinfo)\n      return;\n\n    const dx = this.swipeinfo.end.x - this.swipeinfo.start.x;\n    const dy = this.swipeinfo.end.y - this.swipeinfo.start.y;\n\n    this.swipeinfo.endtime = new Date().getTime();\n\n    const abs_x = Math.abs(dx);\n    const abs_y = Math.abs(dy);\n\n    if (abs_x > this.options.threshold_distance && abs_x / (this.swipeinfo.endtime - this.swipeinfo.starttime) > this.options.threshold_speed)\n      this.swipeinfo.direction += dx > 0 ? \"e\" : \"w\";\n\n    if (abs_y > this.options.threshold_distance && abs_y / (this.swipeinfo.endtime - this.swipeinfo.starttime) > this.options.threshold_speed)\n      this.swipeinfo.direction += dy > 0 ? \"s\" : \"n\";\n\n    if (this.swipeinfo.direction !== \"\") {\n      dompack.dispatchCustomEvent(this.node, \"wh:swipe\", {\n        bubbles: true,\n        cancelable: false,\n        detail: this.swipeinfo\n      });\n\n    }\n\n    this.swipeinfo = null;\n  }\n\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\n// http://masonry.desandro.com/\nimport DesandroMasonry from \"masonry-layout\";\n\n//import DompackMasonry  from \"dompack-masonry\";\nimport DompackMasonry from \"./dompack-masonry\";\n\nimport { getCSSVariable } from \"../../shared/layout-tools\";\n\nimport \"./widgetsholder.scss\";\nimport \"./widgetsholder-eqheight.scss\";\n\n\nconst widgetContainers = []; // all .widgetblock elements\nwindow.widgetContainers = widgetContainers;\n\nlet relayout_throttle; // timer to wait for 250ms without any relayout calls before relayouting\n\nlet windowMode;\n\n\n/*\n\nEvents\n\n\"ws:widgetholders-beforerelayout\n- Fired once on window just before ALL masonries are relayouted\n\n\"ws:relayoutwidgetcontent\"\n- request from dompack-masonry for widgets to relayout content AFTER correct width is set\n- request before running Desonry masonry (width is assumed to be correct due to using a fixed width)\n\n\"ws:relayoutwidgets\"\n- This event SHOULD BE FIRED USING layout.es relayoutWidgets()\n- request to have the widgetsholder relayout all widgets\n  (after widgets have changes size)\n- Example:\n  import * as layout from \"@mod-utwente_base/webfeatures/utwidgets/layout\";\n  layout.relayoutWidgets(this.node);\n\n\n\nWidgetblocks:\n\nDesonry\n  used by:\n    - Footer\n  behaviour:\n    - fullwidth\n    - widgets have a fixed width of 300px (unless mobile mode)\n    - Desonry masonry\n\nDompack-masonry\n  used by:\n    - Pagecontent \"widgetblock\"\n  behaviour:\n    - width is 8 column page layout\n    - normal contentpage: 2 column layout within\n    - toplevel homepage:  2 or 3 columns within depending on the available width\n    - widgets stretch to fill up their column\n\nCSS equal-height\n  used by:\n    - People Page (gridview)\n  behaviour:\n    - CSS uses flex to generate a grid with 2 or 3 columns\n\n*/\n\n\nfunction registerWidgetsContainer(widgetContainer) {\n  widgetContainers.push(widgetContainer);\n\n  /*\n  - Default: white background and widgets have a border\n  - Grey bg: (layout using Desanro)\n  */\n\n  // Determine which layout to use (\"none\" (CSS, for equal-height items), \"desanro\" or \"dompack-carrousel\")\n  if (widgetContainer.classList.contains(\"widgetsblock__contents--equalheight\")\n    || widgetContainer.classList.contains(\"widgetsblock__contents--singlewidget\")\n  )\n    widgetContainer._whMasonryType = \"none\";\n  else\n    widgetContainer._whMasonryType = \"dompack-masonry\";\n}\n\n\n// used on window resize\nfunction throttledRelayoutWidgets() {\n  clearTimeout(relayout_throttle);\n  relayout_throttle = setTimeout(evt => relayoutWidgetsDueToResize(evt), 250);\n}\n\nfunction relayoutWidgetsDueToResize() {\n  sendBeforeRelayoutEvent();\n\n  // In case of a window resize, a widget might have changed in width\n  for (const widgetContainer of widgetContainers)\n    refreshWidgetBlock(widgetContainer);\n}\n\n// a relayout event will trigger a direct relayout of widgets\nfunction onRelayoutWidgets(event) {\n  sendBeforeRelayoutEvent();\n\n  for (const widgetContainer of widgetContainers) {\n    // in case a specific container was passed\n    // we only relayout that container.\n    if (!event.detail.container || widgetContainer == event.detail.container)\n      refreshWidgetBlock(widgetContainer, Boolean(event.detail.force));\n  }\n}\n\nfunction sendBeforeRelayoutEvent() {\n  dompack.dispatchCustomEvent(window, \"ws:widgetholders-beforerelayout\",\n    {\n      bubbles: false,\n      cancelable: false\n    });\n}\n\n\n// The widgets are full width on xsmall and xxsmall devices, but the masonry\n// doesn't play well with switching between fixed column width and full width,\n// it should be activated and deactivated. Because it doesn't support that,\n// we'll just initialize and destroy it when necessary.\nfunction checkWindowSize(mode) {\n  for (const widgetContainer of widgetContainers) {\n    if (widgetContainer._whMasonryType == \"dompack-masonry\")\n      refreshDompackWidgetBlock(widgetContainer);\n    else if (widgetContainer._whMasonryType == \"desandro\")\n      refreshDesandroWidgetBlock(mode, widgetContainer);\n  }\n}\n\nfunction refreshDesandroWidgetBlock(mode, widgetContainer) {\n  if (mode != windowMode) {\n    windowMode = mode;\n    if (windowMode == \"small\") {\n      // When switching to small mode, destroy the widget masonry (if it's still active)\n      if (widgetContainer._wsMasonry) {\n        widgetContainer._wsMasonry.destroy();\n        widgetContainer._wsMasonry = null;\n      }\n\n      const widget = widgetContainer.closest(\".widgetsblock\");\n      widget.classList.remove(\"widgetsblock--defaultlayout\");\n    } else {\n      // When switching to wide mode, initialize the widget masonry (if it isn't already active)\n      const widget = widgetContainer.closest(\".widgetsblock\");\n      widget.classList.add(\"widgetsblock--defaultlayout\");\n\n      if (!widgetContainer._wsMasonry) {\n        // console.log(\"Init Desandro\", widgetContainer);\n        widgetContainer._wsMasonry = new DesandroMasonry(widgetContainer\n          , {\n            itemSelector: \".widget\",\n            columnWidth: \".widgetsblock__contents-sizer\",\n            fitWidth: true,\n            gutter: 15\n          });\n      }\n    }\n  }\n}\n\n\nfunction refreshDompackWidgetBlock(widgetContainer, force) {\n  let options = {};\n\n  widgetContainer.classList.add(\"widgetsblock--dompackmasonry\");\n\n  // Retrieve current settings from CSS /////////////////////////////////////////////////\n  const comp = window.getComputedStyle(widgetContainer, '::before');\n  let layout = comp.content;\n\n  // remove the \" some browsers add (Safari doesn't add quotes)\n  if (layout != \"\" && layout.startsWith('\"'))\n    layout = layout.substring(1, layout.length - 1); // remove the \"'s around the string\n\n  // console.log(\"Masonry CSS hints\", layout, \"for\", widgetContainer);\n\n  if (layout != \"none\") {\n    const parts = layout.split(\":\");\n\n    options = {\n      columns: parseInt(parts[0]),\n      gutter: parseInt(parts[1])\n    };\n  } else // CSS not loaded/parsed yet?\n  {\n    // fallback values\n    options = {\n      columns: 2,\n      gutter: 30\n    };\n  }\n  ////////////////////////////////////////////////////////////////////////////////////////\n\n  //console.info(\"Masonry\", options);\n\n  if (!widgetContainer._wsMasonry) {\n    widgetContainer._wsMasonry = new DompackMasonry(widgetContainer\n      , {\n        ...options,\n        items: \".widget\",\n        breakclass: \".widget__break__title\"\n      });\n  } else {\n    widgetContainer._wsMasonry.setOptions(options);\n    widgetContainer._wsMasonry.refresh(force);\n  }\n}\n\n\nfunction refreshWidgetBlock(widgetContainer, force) {\n  if (widgetContainer._whMasonryType == \"desandro\") {\n    // Give all widgets the ability to do their resize handlers before doing the relayout of the widgetholders.\n    // Because the Desanro masonry layout uses a fixed width we can get away with this.\n    // (ideally we want the refresh trigger events to be send after the masonry determined the width of the widgets)\n    const widgets = widgetContainer.querySelectorAll(\".widget\");\n    for (const widget of widgets) {\n      dompack.dispatchCustomEvent(widget, \"ws:relayoutwidgetcontent\",\n        {\n          bubbles: true,\n          cancelable: false,\n          detail: { force: force } // let our child content also know we want to force relayouting\n        });\n    }\n\n    if (widgetContainer._wsMasonry)\n      widgetContainer._wsMasonry.layout();\n  } else if (widgetContainer._whMasonryType == \"dompack-masonry\")\n    refreshDompackWidgetBlock(widgetContainer, force);\n}\n\n\n// Add new widget blocks to the list of containers to relayout\ndompack.register(\".widgetsblock__contents\", widgetblock => {\n  const initialhash = location.hash;\n  registerWidgetsContainer(widgetblock);\n  setTimeout(() => { // Because of contentshift, check if deeplink is used and scroll it into view\n    if( initialhash != \"\" && initialhash != '#') {\n      const anode = dompack.qS(initialhash);\n      if(anode)\n        anode.scrollIntoView({behavior: \"auto\", block: \"start\"});\n    }\n  },200);\n});\nwindow.addEventListener(\"ws:relayoutwidgets\", onRelayoutWidgets); // listen for trigger to refresh the widgetsholder\nwindow.addEventListener(\"ws:responsivemode\", event => checkWindowSize(event.detail.level <= 1 ? \"small\" : \"wide\")); // ws2016\nwindow.addEventListener(\"resize\", throttledRelayoutWidgets);\n\ngetCSSVariable(\"--breakpoint-phone\").then(breakpoint_phone => {\n  // Read the breakpoint CSS variable and get a MediaQueryList\n  const initMasonryMedia = matchMedia(`(max-width: ${breakpoint_phone})`);\n  // Setup an onchange listener to activate/deactivate the deeplinks\n  initMasonryMedia.addEventListener(\"change\", event => checkWindowSize(event.matches ? \"small\" : \"wide\"));\n  // Directly check the query\n  checkWindowSize(initMasonryMedia.matches ? \"small\" : \"wide\");\n});\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\n/*\nThis is an updated DompackMasonry.\n- Equalheight has been removed\n- force parameter added to refresh()\n- event is fired to all widgets when they need to relayout due to\n  - changed columnwidth\n  - force parameter used (in case of load event or custom fonts or CSS files loaded)\n*/\n\n\nexport default class DompackMasonry {\n  constructor(node, options) {\n    const domoptions = dompack.getJSONAttribute(node, \"data-masonry-options\");\n\n    // NOTE: we don't use Object.assign() here because we have some\n    //       smart rules (convert gutter to gutter_x and gutter_y for example)\n    this.options =\n    {\n      columns: 3,\n      columnwidth: 0,     // if not set the width will be set so the amount of columns will fill up the horizontal space\n\n      // gutter size\n      // gutter:            10 // shorthand for gutter_x and gutter_y\n      gutter_x: 10,\n      gutter_y: 10,\n\n      debug: false,\n\n      // CSS query (for example '.masonry-item' or array of nodes\n      // Pass an array of nodes if you want control over the order visual order of the items (without reordering the dom)\n      items: null,\n\n      // specify a class to ignore in layouting\n      // (can be used for items which you transition to hide/fade)\n      ignoreclass: \"hide\",\n\n      righttoleft: false // FIXME: keep or remove this option?\n    };//, domoptions, options;\n\n    if (domoptions)\n      this.setOptions(domoptions);\n\n    if (options)\n      this.setOptions(options);\n\n    if (typeof (node) === \"string\")\n      this.container = document.getElementById(node);\n    else\n      this.container = node;\n\n    this.__height = 0;\n    this.__columnwidth = 0;    // (also used to detect whether widget width style has to be set)\n    this.__itemdata = [];   // render data\n    this.__visiblewidgetscount = 0;\n    this.__singlerow = true;\n    this.__columncontainers = [];\n\n    this.__items_dirty = true;\n\n    // PRIVATE VARS!!\n    this.__leftoffset = 0;\n    this.__containerwidth = 0;\n    this.__widgetrecs = [];\n    this.ignore_resize_events = false;\n\n    this.refresh();\n  }\n\n  setOptions(options) {\n    if (\"gutter\" in options) {\n      options.gutter_x = options.gutter;\n      options.gutter_y = options.gutter;\n      delete options.gutter;\n    }\n\n    if (\"items\" in options)\n      this.__items_dirty = true; // need to recheck all widgets, there might be new ones\n\n    Object.assign(this.options, options);\n  }\n\n  /** @short full relayout\n      @long find all items, detect width, read data-cols attributes on items and relayout\n  */\n  refresh(force) {\n    if (this.options.debug) {\n      console.log(\"$wh.Masonry.refresh()\");\n      console.trace();\n    }\n\n    const clientwidth = this.container.clientWidth;\n    if (clientwidth == 0) {\n      console.warn(\"Cannot determine size of mansonry container (got 0).\", this.container);\n      return;\n    }\n\n    this.ignore_resize_events = true;\n\n    // FIXME: assuming padding in px\n    // FIXME: assuming correct box-sizing\n    // FIXME: assumption that this container (with the padding) is also the positioning container\n    const cstyle = window.getComputedStyle(this.container);\n    const padtop = parseInt(cstyle.paddingTop, 10);\n    const padbottom = parseInt(cstyle.paddingBottom, 10);\n    const padleft = parseInt(cstyle.paddingLeft, 10);\n    const padright = parseInt(cstyle.paddingRight, 10);\n    this.__padding = {\n      top: padtop,\n      bottom: padbottom,\n      left: padleft,\n      right: padright\n    };\n    //console.log(this.container, this.__padding);\n\n    this.__leftoffset = padleft;\n    this.__containerwidth = clientwidth - padleft - padright;\n\n    let widgets;\n    if (!this.options.items)\n      widgets = this.container.querySelectorAll(\".wh-masonry-item\");\n    else if (typeof (this.options.items) === \"string\")\n      widgets = this.container.querySelectorAll(this.options.items);\n    else\n      widgets = this.options.items;\n\n    this.pvt_relayout(widgets, force);\n\n    this.ignore_resize_events = false;\n  }\n\n  /** @short only update heights and position\n             New items and changed widths aren't detected\n  */\n  refreshHeights() {\n    this.pvt_relayout(null, true);\n  }\n\n  getLastRenderInfo() {\n    return {\n      container: this.container,\n      visiblewidgetscount: this.__visiblewidgetscount,\n      width: this.__containerwidth,\n      height: this.__height,\n      items: this.__itemdata,\n      singlerow: this.__singlerow\n    };\n  }\n\n\n  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  //\n  //  Private functions\n  //\n\n  //, __padding: 0\n\n  // update through on of our components using $wh.fireLayoutChangeEvent\n  onLayoutChange(elem) {\n    //console.log(\"event for\", elem);\n\n    // regardless of the direction we will also receive the event on the element it's fired on\n    if (elem == this.container) {\n      //  console.log(\"ignore\");\n      return;\n    }\n\n    this.refreshHeights();\n  }\n\n  pvt_relayout(widgets, force) {\n    if (this.options.debug)\n      console.group(\"$wh.Masonry.refresh()\", force ? \"FORCE\" : \"\");\n\n    let visiblewidgetscount = 0;\n\n    let columnwidth = this.options.columnwidth;\n    if (!columnwidth)\n      columnwidth = (this.__containerwidth - (this.options.columns - 1) * this.options.gutter_x) / this.options.columns;\n\n    const columncount = this.options.columns;\n    let singlerow = true; // until we have to place a new widget below another one all widgets are still on a single row\n\n    const columns = []; // the last Y position in use per column\n    for (var xcol = 0; xcol < columncount; xcol++)\n      columns.push(0);\n\n    /*\n    console.log({ columns:     this.options.columns\n                , columnwidth: columnwidth\n                });\n    */\n\n    let widgetrecs;\n\n\n\n    // Only change widget width's when needed\n    const dirty = this.__items_dirty || this.__columnwidth != columnwidth;\n    if (dirty) // new items or width for widgets need to change?\n    {\n      widgetrecs = [];\n      // First apply the new width to all widgets, so we can later determine the correct height\n      for (var idx = 0; idx < widgets.length; idx++) {\n        var widget = widgets[idx];\n\n        let widgetcols = widget.getAttribute(\"data-cols\");\n        widgetcols = widgetcols ? parseInt(widgetcols) : 1;\n\n        if (widgetcols > this.options.columns)\n          widgetcols = this.options.columns;\n\n        const width = columnwidth * widgetcols + (widgetcols - 1) * this.options.gutter_x;\n\n        widget.style.position = \"absolute\";\n        widget.style.width = width + \"px\";\n        widget.style.height = \"\"; // clear any inline specified height (we only allow a fixed height if specified in CSS)\n\n        widgetrecs.push(\n          {\n            node: widget,\n            width: width,\n            height: null,\n            cols: widgetcols\n          });\n      }\n    } else {\n      widgetrecs = this.__itemdata;\n    }\n\n    // We force widgets to relayout if we are dirty or force is used\n    // (force is usefull in case a load, custom font load or CSS load event was detected)\n    if (dirty || force) {\n      /*\n      Let our children relayout to match our new width\n      (after which layout of masonry item contents should be done, meaning the height is known and we can start to build up the masonry)\n      */\n      if (this.options.debug)\n        console.log(\"Firing ws:relayoutwidgetcontent event\");\n\n      // Notify any of our components within the Masonry container that layout has changed.\n      // After they have updated their layout we know the final height of each widget and can start to layout our Masonry.\n\n      for (var idx = 0; idx < widgets.length; idx++) {\n        var widget = widgets[idx];\n        // Inform widgets without our masonry grid to relayout\n        // (due to a change in the width)\n        dompack.dispatchCustomEvent(widget, \"ws:relayoutwidgetcontent\",\n          {\n            bubbles: true,\n            cancelable: false,\n            detail: { force: force } // let our child content also know we want to force relayouting\n          });\n      }\n\n      if (this.options.debug)\n        console.log(\"Continue dompack-masonry layouting.\");\n    }\n\n\n\n    // measure all widgets in one go to prevent extreneous reflows by mixing writes and reads\n    for (var idx = 0; idx < widgetrecs.length; idx++)\n      widgetrecs[idx].height = widgetrecs[idx].node.clientHeight;\n\n\n\n    for (var idx = 0; idx < widgetrecs.length; idx++) {\n      const widgetrec = widgetrecs[idx];\n      var widget = widgetrec.node;\n\n      const widgetheight = widgetrec.height;\n\n      if (this.options.debug)\n        console.log(\"#\" + idx, widgetheight + \"px\", widget.className);\n\n      if (widgetheight == 0 || (this.options.ignoreclass != \"\" && widget.classList.contains(this.options.ignoreclass)))\n        continue;\n\n      visiblewidgetscount++;\n\n      let bestcol = -1, ypos = 0;\n\n      // set increase the last used ypos within the columns the current widget will occupy\n      // find the first ypos where the whole block would fit\n      if (this.options.debug)\n        console.info(columns);\n\n      for (var xcol = 0; xcol <= columncount - widgetrec.cols; ++xcol) {\n        var col = this.options.righttoleft ? columncount - widgetrec.cols - xcol : xcol;\n\n        const maxypos = Math.max.apply(null, columns.slice(col, col + widgetrec.cols));\n        //console.log(col, \"has enough room for \", widgetrec.cols, \" columns starting at Y pos\", maxypos);\n\n        // if we cannot find any column in which we can place the block,\n        // move to below where all previous block are\n        if (bestcol == -1 || maxypos < ypos) {\n          //          console.log(widgetrec, maxypos, ypos);\n          bestcol = col;\n          ypos = maxypos;\n        }\n      }\n\n      //console.log(\"We select column\", bestcol);\n\n      if (columns[bestcol] > 0) {\n        if (ypos > 0)\n          singlerow = false;\n\n        ypos += this.options.gutter_y;\n      }\n\n      for (var col = 0; col < widgetrec.cols; ++col) {\n        const nextypos = ypos + widgetheight;\n        columns[bestcol + col] = nextypos;\n      }\n\n      widgetrec.col = bestcol;\n      widgetrec.left = this.__leftoffset + (bestcol * columnwidth + (bestcol) * this.options.gutter_x);\n      widgetrec.top = ypos;\n\n      const styles = {\n        position: \"absolute\",\n        left: widgetrec.left, // 300 width, 10 px leftmargin, 20 inter\n        top: widgetrec.top + this.__padding.top\n        //, width:    columnwidth * widgetrec.cols + (widgetrec.cols-1) * this.options.gutter_x\n      };\n\n      if (this.options.debug)\n        console.log(\"Will be placed into col\", bestcol);\n\n      widget.style.position = styles.position;\n      widget.style.left = styles.left + \"px\";\n      widget.style.top = styles.top + \"px\";\n    }\n\n    const maxheight = Math.max.apply(null, columns) + this.__padding.top + this.__padding.bottom;\n\n    //reorderWidgets(keepcolumnpos);\n    if (this.options.columnwidth)\n      this.container.style.width = (this.options.columnwidth * this.options.columns + (this.options.columns - 1) * this.options.gutter_x) + \"px\";\n\n    this.container.style.height = maxheight + \"px\";\n\n    /*\n        // Now we want our parents to know we have changed in size\n        // FIXME: add a check whether we actually changed in size\n        if (this.options.debug)\n          console.log(\"Firing layout change event\");\n\n        $wh.fireLayoutChangeEvent(this.container, \"up\"); // FIXME\n    */\n\n    if (this.options.debug) {\n      console.log(this.container, \"has\", visiblewidgetscount, \"visible widgets\");\n      console.groupEnd();\n    }\n\n    /*\n    store render information (can be used to add extra behaviour outside this class for example:\n    - to equalize heights of widgets by external code or hide a widgets grid\n    - to hide a widgets container in case it has no visible widgets\n    */\n    this.__itemdata = widgetrecs;\n    this.__columnwidth = columnwidth;\n    this.__height = maxheight;\n    this.__visiblewidgetscount = visiblewidgetscount;\n    this.__singlerow = singlerow;\n  }\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\n/** @short Get the value of a CSS variable\n    @long If the DOM is not fully loaded and the CSS is not fully applied, CSS variables may not have been fully computed.\n        This function returns a promise that resolves with the value of the requested CSS variable once it's available. It\n        rejects after a timeout, if set through the options. This function checks if the value is set (getPropertyValue\n        returns an empty string for unknown variables), so it can only be used for variables that eventually will be set to a\n        non-empty value.\n    @param property The CSS variable (custom property) to read\n    @param options.element The element to query, defaults to document.documentElement\n    @param options.timeout The timeout in ms, defaults to 10000, set to 0 to disable timeout and return only after the\n        variable has received a non-empty (and keep running in the background!)\n*/\nexport function getCSSVariable(property, options?) {\n  options =\n  {\n    element: document.documentElement,\n    timeout: 10000,\n    ...options\n  };\n\n  return new Promise((resolve, reject) => {\n    // Local state\n    const data =\n    {\n      timeout: -1, // Signal to timeout has been set\n      property,\n      element: options.element,\n      resolve\n    };\n\n    // Set a timeout if requested\n    if (options.timeout > 0)\n      data.timeout = setTimeout(() => {\n        // Clear the timeout value, to signal a timeout to the checkCSSVariable function\n        data.timeout = 0;\n        reject(new Error(`Timeout after ${options.timeouts}ms reading CSS variable '${property}'`));\n      }, options.timeout);\n    // Check if the CSS variable is set\n    checkCSSVariable(data);\n  });\n}\n\nfunction checkCSSVariable(data) {\n  // If the request has timed out (i.e. the variable didn't receive a value within the given time), we're done\n  if (data.timeout === 0)\n    return;\n  // Get the CSS variable value\n  const value = getComputedStyle(data.element).getPropertyValue(data.property);\n  if (value) {\n    // Clear the timeout\n    clearTimeout(data.timeout);\n    // Return the value\n    data.resolve(value);\n    return;\n  }\n  // Check again in the next animation frame\n  requestAnimationFrame(() => checkCSSVariable(data));\n}\n\nexport function setCSSVariable(property, value, options) {\n  options =\n  {\n    element: document.documentElement,\n    ...options\n  };\n\n  options.element.style.setProperty(property, value);\n}\n\n/*\n  Function to apply ellipsis on multiple lines with overflow=hidden container\n  Only works properly with childnode for text wrapper (display block or inline-block) to measure text height\n*/\nlet ellipsislines = [];\nlet ellipsislinesInitdone = false;\nexport function setEllipsisLines(forcerefresh, options) {\n  const textsuffix = \"...\";\n  if (!ellipsislinesInitdone || forcerefresh) {\n    let basenode = document;\n    if (options && options.basenode && typeof options.basenode === \"object\")\n      basenode = options.basenode;\n\n    ellipsislines = [];\n    const nodes = basenode.querySelectorAll(\"[data-ellipsislines]\");\n\n    for (const node of nodes) {\n      if (node.clientHeight == 0)\n        continue;//probably not a block element\n\n      const innernode = node.firstElementChild;\n      if (!innernode || innernode.clientHeight == 0)\n        continue;//missing wrapper node or not a block element\n\n      ellipsislines.push({\n        \"text\": innernode.textContent,\n        \"dimensions\": \"\",\n        \"node\": node,\n        \"innernode\": innernode\n      });\n    }\n    ellipsislinesInitdone = true;\n  }\n\n  for (const item of ellipsislines) {\n    const dimensions = item.node.clientWidth + 'x' + item.node.clientHeight;\n    if (dimensions == item.dimensions)\n      continue;//no need to change\n    item.dimensions = dimensions;\n\n    item.innernode.textContent = item.text;//put back orginal text\n    let nodeheight = item.innernode.clientHeight;\n    const maxheight = item.node.clientHeight;\n    if (maxheight >= nodeheight)\n      continue;//no need to fit text\n\n    let hasfitt = false;\n    let testlength = item.text.length;\n    let prevlength = testlength;\n    while (!hasfitt) {\n      testlength = Math.round(testlength / 2);//first a rough fit\n      item.innernode.textContent = item.text.substr(0, testlength) + textsuffix;\n      nodeheight = item.innernode.clientHeight;\n      hasfitt = maxheight >= nodeheight;\n      if (maxheight >= nodeheight) { //now add characters until fit\n        for (let i = testlength + 1; i < prevlength; ++i) {\n          item.innernode.textContent = item.text.substr(0, i) + textsuffix;\n          nodeheight = item.innernode.clientHeight;\n          if (maxheight < nodeheight) { //one step back\n            item.innernode.textContent = item.text.substr(0, i - 1) + textsuffix;\n            break;\n          }\n        }\n      }\n      prevlength = testlength;\n    }\n  }\n}\n\n\n/*\n  Function to scale down font-size / line-height until text fits in container\n  Only works properly with block or inline-block elements\n*/\n\nlet fitfontlist = [];\nlet fitfontlistInitDone = false;\nexport function fitFonts(forcerefresh) {\n  if (!fitfontlistInitDone || forcerefresh) {\n    fitfontlist = [];\n    for (const node of document.querySelectorAll(\"[data-fontfit-height],[data-fontfit-width]\")) {\n      let h_attr = node.getAttribute(\"data-fontfit-height\");\n      let maxheight = h_attr ? 1 * h_attr.replace(/[^0-9.]/g, \"\") : 0;\n      if (maxheight <= 0) {\n        maxheight = 100;\n        h_attr = \"100%\";\n      }\n\n      let w_attr = node.getAttribute(\"data-fontfit-width\");\n      let maxwidth = w_attr ? 1 * w_attr.replace(/[^0-9.]/g, \"\") : 0;\n      if (maxwidth <= 0) {\n        maxwidth = 100;\n        w_attr = \"100%\";\n      }\n\n      let wrappernode = null;\n      const wrapperattr = node.getAttribute(\"data-fontfit-wrapper\");\n      if (wrapperattr)\n        wrappernode = node.closest(wrapperattr);\n      if (!wrappernode)//if no wrappernode, then use parentnode\n        wrappernode = node.parentNode;\n\n      fitfontlist.push({\n        node: node,\n        dimensions: \"\",\n        wrappernode: wrappernode,\n        maxheight: maxheight,\n        maxwidth: maxwidth,\n        width_isperc: w_attr.indexOf(\"%\") != -1,\n        height_isperc: h_attr.indexOf(\"%\") != -1,\n        debug: node.getAttribute(\"data-fontfit-debug\") == \"true\"\n      });\n    }\n    fitfontlistInitDone = true;\n  }\n\n  for (const item of fitfontlist) {\n    if (item.debug)\n      console.groupCollapsed(\"fitFonts\", item);\n\n    const wrappersize = item.wrappernode.getBoundingClientRect();\n    const wrapperheight = wrappersize.height;\n    const wrapperwidth = wrappersize.width;\n\n    const dimensions = wrapperwidth + 'x' + wrapperheight;\n    if (dimensions == item.dimensions) {\n      if (item.debug) {\n        console.warn(\"No need to fit\", { wrapper: dimensions, item: item.dimensions });\n        console.groupEnd();\n      }\n      continue;\n    }\n    item.dimensions = dimensions;\n\n    //reset inline style to get actual css font size\n    item.node.style.fontSize = null;\n    item.node.style.lineHeight = null;\n\n    //get actual css fontsize\n    const fontsize = window.getComputedStyle(item.node, null).getPropertyValue('font-size');\n    const fontunit = fontsize.replace(/[0-9.]/g, \"\");\n    let fontnum = 1 * fontsize.replace(/[^0-9.]/g, \"\");\n    if (fontnum <= 0) {\n      if (item.debug) {\n        console.warn(\"Unable to get fontsize\", { fontsize, fontunit, fontnum });\n        console.groupEnd();\n      }\n      continue;\n    }\n\n    const lineheight = window.getComputedStyle(item.node, null).getPropertyValue('line-height');\n    const lineunit = lineheight.replace(/[0-9.]/g, \"\");\n    let linenum = 1 * lineheight.replace(/[^0-9.]/g, \"\");\n\n    //create temporary inline node for correct measurement of width\n    const contents = item.node.innerHTML;\n    item.node.innerHTML = '<span class=\"wh-measure\" style=\"display:inline;\">' + contents + '</span>';\n    const measurenode = item.node.querySelector(\".wh-measure\");\n\n    let maxheight = item.height_isperc ? item.maxheight * wrapperheight * 0.01 : item.maxheight;\n    if (maxheight > wrapperheight)\n      maxheight = wrapperheight;\n\n    let maxwidth = item.width_isperc ? item.maxwidth * wrapperwidth * 0.01 : item.maxwidth;\n    if (maxwidth > maxwidth)\n      maxwidth = wrapperwidth;\n\n    let measurement = measurenode.getBoundingClientRect();\n    if (measurement.height == 0 || (measurement.height <= maxheight && measurement.width <= maxwidth)) { //fits or not visible\n      item.node.removeChild(measurenode);\n      item.node.innerHTML = contents;\n      if (item.debug) {\n        console.warn(\"Contents fits or isn't visible\", { measurement, maxheight, maxwidth });\n        console.groupEnd();\n      }\n      continue;\n    }\n\n    let hasfitt = false;\n    while (!hasfitt) {\n      item.node.style.fontSize = fontnum + fontunit;\n      item.node.style.lineHeight = linenum + lineunit;\n\n      measurement = measurenode.getBoundingClientRect();\n      hasfitt = (maxheight >= measurement.height && maxwidth >= measurement.width) || fontnum < 3; //makes no sense to go smaller\n\n      --fontnum;\n      --linenum;\n    }\n    item.node.removeChild(measurenode);\n    item.node.innerHTML = contents;//put back original content\n\n    if (item.debug) {\n      console.log(\"done!\", { fontunit, fontnum, lineunit, linenum });\n      console.groupEnd();\n    }\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\n// Relayout the widget masonry if a widget was resized\nexport function relayoutWidgets(widgetnode) {\n  dompack.dispatchCustomEvent(window, \"ws:relayoutwidgets\",\n    {\n      bubbles: true,\n      cancelable: false,\n      detail: { container: widgetnode ? widgetnode.closest(\".widgetsblock__contents\") : null }\n    });\n}\nwindow.__relayoutWidgets = relayoutWidgets;\n\nexport function forceRelayoutWidgets(widgetnode) {\n  dompack.dispatchCustomEvent(window, \"ws:relayoutwidgets\",\n    {\n      bubbles: true,\n      cancelable: false,\n      detail: {\n        container: widgetnode ? widgetnode.closest(\".widgetsblock__contents\") : null,\n        force: true\n      }\n    });\n}\n","import utwenteCookies from \"@mod-utwente_design/js/cookiebar\";\nimport { getTid } from \"@webhare/gettid\";\nimport * as dompack from '@webhare/dompack';\nimport './consentcheck.scss';\n\nfunction setConsentLayers() {\n  for (const node of dompack.qSA(\"*[data-needsconsent],.wh-video.wh-requireconsent\")) {\n    // console.info(\"setConsentLayer\", node.dataset.needsconsent, \"for node\", node);\n\n    let shieldnode = node.querySelector(\".consentblocker\");\n    if (shieldnode)//already added\n      continue;\n\n    if (node.dataset.needsconsent === \"video\" || node.matches('.wh-video')) {\n      let directlink = \"\";\n      let network = \"\";\n\n      const infocode = node.dataset.needsconsent === \"video\" ? dompack.qS(node, \"[data-video]\")?.dataset.video : node.dataset.whVideo;\n\n      if (infocode) {\n        const info = JSON.parse(infocode);\n        network = info.network;\n\n        if (network === \"youtube\") {\n          network = \"YouTube\";\n          directlink = \"https://youtu.be/\" + info.id;\n        } else if (network === \"vimeo\") {\n          network = \"Vimeo\";\n          directlink = \"https://vimeo.com/\" + info.id;\n        } else if (network === \"yuja\") {\n          // Yuja only uses functional cookies (no tracking), so we don't need to block\n          continue;\n        }\n      }\n\n      shieldnode = <div class=\"consentblocker\">\n        <div class=\"consentblocker__title\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-video-title\")}</div>\n        <div class=\"consentblocker__description\">\n          {getTid(\"utwente_base:frontend.ws2016.js.consentblock-video-line1\", network) + \" \"}\n          <a href=\"#accept\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-accept3thpartycookies\")}</a>\n          {' ' + getTid(\"utwente_base:frontend.ws2016.js.consentblock-video-accept3thpartycookies-suffix\")}\n          {directlink\n            ? <span>\n              {\" \" + getTid(\"utwente_base:frontend.ws2016.js.consentblock-video-directlink-prefix\") + \" \"}\n              <a target=\"_blank\" rel=\"noopener noreferrer\" href={directlink}>{getTid(\"utwente_base:frontend.ws2016.js.consentblock-video-directlink\", network)}</a>\n            </span>\n            : null\n          }\n        </div>\n      </div>;\n    } else if (node.dataset.needsconsent === \"soundcloud\") {\n      let playername = \"SoundCloud\";\n      if (node.dataset.provider && node.dataset.provider === \"transistor\")\n        playername = \"Transistor\";\n\n      shieldnode = <div class=\"consentblocker\">\n        <div class=\"consentblocker__title\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-soundcloud-title\")}</div>\n        <div class=\"consentblocker__description\">\n          {getTid(\"utwente_base:frontend.ws2016.js.consentblock-soundcloud-line1\", playername) + ' '}\n          <a href=\"#accept\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-accept3thpartycookies\")}</a>\n          {' ' + getTid(\"utwente_base:frontend.ws2016.js.consentblock-soundcloud-accept3thpartycookies-suffix\")}\n          {node.dataset.directlink\n            ? <span>\n              {\" \" + getTid(\"utwente_base:frontend.ws2016.js.consentblock-soundcloud-directlink-prefix\") + \" \"}\n              <a target=\"_blank\" rel=\"noopener noreferrer\" href={node.dataset.directlink}>{getTid(\"utwente_base:frontend.ws2016.js.consentblock-soundcloud-directlink\")}</a>\n            </span>\n            : null\n          }\n        </div>\n      </div>;\n    } else if (node.dataset.needsconsent === \"facebook\") {\n      node.replaceChildren(); //empty it\n      shieldnode = <div class=\"consentblocker\">\n        <div class=\"consentblocker__title\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-facebook-title\")}</div>\n        <div class=\"consentblocker__description\">\n          {getTid(\"utwente_base:frontend.ws2016.js.consentblock-facebook-line1\") + ' '}\n          <a href=\"#accept\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-accept3thpartycookies\")}</a>\n          {' ' + getTid(\"utwente_base:frontend.ws2016.js.consentblock-facebook-accept3thpartycookies-suffix\")}\n        </div>\n      </div>;\n    } else if (node.dataset.needsconsent === \"twitter-embed\") {\n      shieldnode = getTwitterConsentlayer();\n    }\n\n\n    if (shieldnode) {\n      // console.info(\"Inserting shieldnode\", shieldnode);\n      shieldnode.addEventListener(\"click\", ev => onShieldNodeClick(ev));\n      node.appendChild(shieldnode);\n    }\n  }\n}\n\n\nfunction onShieldNodeClick(ev: Event) {\n  ev.stopPropagation();\n  const link = dompack.isHTMLElement(ev.target) && ev.target.closest(\".consentblocker a\");\n  if (link) {\n    if (link.getAttribute(\"href\") === \"#accept\") {\n      ev.preventDefault();\n      utwenteCookies.acceptMarketingCookies();\n    }\n    return;\n  }\n  ev.preventDefault();\n}\n\n\nfunction getTwitterConsentlayer() {\n  const node =\n    <div class=\"consentblocker\">\n      <div class=\"consentblocker__description\">\n        {getTid(\"utwente_base:frontend.ws2016.js.consentblock-twitterembed-line1\") + ' '}\n        <a href=\"#accept\">{getTid(\"utwente_base:frontend.ws2016.js.consentblock-accept3thpartycookies\")}</a>\n        {' ' + getTid(\"utwente_base:frontend.ws2016.js.consentblock-twitterembed-accept3thpartycookies-suffix\")}\n      </div>\n    </div>;\n\n  return node;\n}\n\n\n\n\n/*\n\nhttps://www.facebook.com/v7.0/plugins/page.php?adapt_container_width=true&app_id=113869198637480&channel=https%3A%2F%2Fstaticxx.facebook.com%2Fx%2Fconnect%2Fxd_arbiter%2F%3Fversion%3D46%23cb%3Df2005fcb13555e8%26domain%3Ddevelopers.facebook.com%26origin%3Dhttps%253A%252F%252Fdevelopers.facebook.com%252Ff1487e3ace22ef8%26relation%3Dparent.parent&container_width=735&hide_cover=false&href=https%3A%2F%2Fwww.facebook.com%2Ffantasyfair%2F&locale=en_US&sdk=joey&show_facepile=true&small_header=false&tabs=timeline%2C%20events%2C%20messages\n*/\nfunction removeConsentLayers() {\n  for (const node of dompack.qSA(\"*[data-needsconsent], .wh-video.wh-requireconsent\")) {\n    //remove overlay with warning text\n    node.querySelector(\".consentblocker\")?.remove();\n  }\n}\n\ndompack.onDomReady(() => {\n  if (!utwenteCookies.getConsent())\n    setConsentLayers();\n  else\n    removeConsentLayers();\n\n  document.addEventListener(\"wh:consent-change\", ev => {\n    if (!utwenteCookies.getConsent())\n      setConsentLayers();\n    else\n      removeConsentLayers();\n  });\n});\n","import { setupCookieWidget } from \"@mod-utwente_design/js/cookiebar\";\nimport \"./widgets-homepage.css\";\nimport \"@mod-utwente_design/js/crm/consenthandler\";\nimport { register } from \"@webhare/dompack\";\n\nregister<HTMLFormElement>(\".ut-cookiewidget\", setupCookieWidget);\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\n/*\n\nCarrouselContent V1.3 dev\nby Mark\n\nV1.1\n- can also act as a slideshow\n\nV1.2\n- improvements backported from utwente_base version\n  (createbullets and small tweaks)\n- options.onchangeslide\n\nV1.3 dev\n- Use of resizeObserver\n- detect scroll position not being in sync (fix debugging purposes)\n\n\nIssues which we havn't been able to reproduce and how\nwe intent to fix or find them:\n\n- Missing a resize (could happen if our container resizes due to changes made in code)\n  This should not happen anymore now we are using resizeObserver.\n\n- Missing a scroll event. This should only happen when our tab is invisible... and even then a browser\n  may fire a new scroll event when we return(??).\n  We've added an interval which checks for this and warns + fixes it - hopefully we can remove this workaround later\n  - Browser thinks tab/document isn't visible and doesn't trigger scroll events?\n  - Something canceling a scroll event?\n- rounding issue in measuring\n  This shouldn't happen...\n- rounding issue in scrollTo\n  We removed the Math.floor we did on the position of each page, so we can scroll to the exact subpixel.\n  This shouldn't have been an issue because the scrollsnap should snap to the exact position of the closest element.\n  Also the active page check checked for this rounded down number. If it went wrong we could expect it to detect a too high page number instead of too low(??).\n\n\n\nFIXME: Chrome 81 and newer resnap while resizing the window... However Firefox doesn't do this yet.\n       Let us force snapping to the current page upon resize?\n\nNOTE: For making an element work as <button> in an accessible way see: https://www.deque.com/blog/accessible-aria-buttons/\n\nUse the smoothscroll-polyfill (for Safari and IE) with this:\n- npm i smoothscroll-polyfill\n- import smoothscroll from 'smoothscroll-polyfill'; // For Safari, IE and Edge (works natively in Chrome, Firefox and iOS)\n- smoothscroll.polyfill();\n\n\n\nADDME: reschedule auto-slide after manual slide (to prevent direct autoslide after manually sliding)\n\nADDME: mutationobserver so we pick up new content (even though viewport_inner wasn't set or size didn't change)\n\n*/\nwindow.__carrouselcontent_instances = [];\n\n\n// Get the first carrousel which is in debug mode\nwindow.getCC = function () {\n  for (const block of window.__carrouselcontent_instances) {\n    if (block.instance.options.debug)\n      return block.instance;\n  }\n};\n\n\n\nclass CarrouselContent {\n  constructor(widgetnode, options) {\n    options =\n    {\n      viewport: \"\", // __itemswrapper - Viewport\n      viewport_inner: \"\", // __items - The container with the items, usually aligned to the content\n      itemsselector: \"\", // __item - Selector to find items to determine how to distribute them into pages\n      item_activeclass: \"\",\n      itemmeasureselector: \"\", // In case the element used in itemsselector has display:contents; or is inline (for example <a>) you might want to target a node within the item to measure\n\n      // Navigation UI\n      bulletscontainer: \"\", // __bullets - To find the container to create bullets into\n      bulletclass: \"\", // __bullet - The class for each bullet / jumpbutton\n      bulletselectedclass: \"\", // __bullet-selected - The class to add to a bullet which indicated a selected page\n      createbullet: null, // function which return a node for the bullet\n      previousbutton: null,\n      nextbutton: null,\n      allowwrap: false, // next on last page will go to the first, previous on the first page will go to the last\n\n      // Autoplay\n      autoplay: false,\n      autoplay_initialdelay: 0,       // delay the first start of autoplay to prevent having a lot of slideshows run in sync\n      autoplay_freezeslideduration: 6000, // how long to keep the slide still (FIXME: should be after the transition) before going to the next\n      transitionDuration: 1500,\n\n      debug: false,\n      debug_determineactivepage: false,\n\n      onchangeslide: null,\n      ...options\n    };\n\n    if (window.location.href.indexOf(\"debugcc\") > -1) {\n      options.debug = true;\n      options.debug_determineactivepage = true;\n    }\n\n    this.options = options;\n\n    if (this.options.debug)\n      console.log(\"[CarrouselContent] Options\", options);\n\n\n    this.prevactivepage = null;\n    this.activepage = 0;\n    this.pagesinfo = [];\n    this.scrollLeft = 0; // for debugging whether we get all scroll events\n\n\n\n    this.initAutoplayVars();\n\n\n    //console.log(\"CarrouselContent options\", options);\n\n    this.widgetnode = widgetnode;\n    //console.log(typeof(this.viewport), typeof(this.viewport) == \"string\");\n    if (typeof (options.viewport) === \"string\") {\n      this.viewport = widgetnode.querySelector(options.viewport);\n      if (!this.viewport)\n        console.error(options.viewport, \"not found in\", widgetnode);\n    }\n\n    if (typeof (options.viewport_inner) === \"string\") {\n      this.viewport_inner = widgetnode.querySelector(options.viewport_inner);\n      if (!this.viewport_inner)\n        console.error(options.viewport_inner, \"not found in\", widgetnode);\n    }\n\n    //this.items = widgetnode.querySelectorAll(options.itemsselector);\n    this.items = [];\n    for (const itemnode of widgetnode.querySelectorAll(options.itemsselector)) {\n      if (this.options.itemmeasureselector) {\n        const measurenode = itemnode.querySelector(this.options.itemmeasureselector);\n        if (!measurenode)\n          console.error(\"Missing measurenode\");\n\n        this.items.push({ node: itemnode, measurenode: measurenode });\n      } else\n        this.items.push({ node: itemnode });\n    }\n\n    if (this.options.debug)\n      console.log(\"[CarrouselContent] Items\", this.items);\n\n    if (!this.viewport) {\n      console.error(\"[CarrouselContent] Missing viewport for\", widgetnode);\n      return;\n    }\n\n    //console.log(this.options.__test + \" - \" + this.options.viewport_inner)\n\n    if (!this.viewport_inner) {\n      console.error(\"[CarrouselContent] Missing viewport_inner for\", widgetnode);\n      return;\n    }\n\n    if (options.bulletscontainer != \"\") {\n      this.bulletscontainer = widgetnode.querySelector(options.bulletscontainer);\n      if (!this.bulletscontainer) {\n        console.error(\"[CarrouselContent] Missing bulletscontainer for\", widgetnode);\n        return;\n      }\n    }\n\n    this.bullets = [];\n\n    this.viewport.addEventListener(\"scroll\", evt => this.onScroll(evt));\n\n    if (this.bulletscontainer) {\n      //this.bulletscontainer.addEventListener(\"click\", evt => this.onBulletClick(evt));\n      this.bulletscontainer.addEventListener(\"mousedown\", evt => this.onBulletClick(evt));\n      this.bulletscontainer.addEventListener(\"touchstart\", evt => this.onBulletClick(evt), { passive: true });\n    }\n\n    if (this.options.previousbutton) {\n      this.options.previousbutton.addEventListener(\"click\", evt => this.previousPage(evt));\n      this.options.previousbutton.addEventListener(\"keypress\", evt => this.maybePreviousPage(evt)); // in case the button isn't made using an <button> element we need to handle keyboard events ourselves\n    }\n\n    if (this.options.nextbutton) {\n      this.options.nextbutton.addEventListener(\"click\", evt => this.nextPage(evt));\n      this.options.nextbutton.addEventListener(\"keypress\", evt => this.maybeNextPage(evt)); // in case the button isn't made using an <button> element we need to handle keyboard events ourselves\n    }\n\n    // this.viewport.scrollTo(0,0); // work around Firefox restoring the scrollposition\n    this.refresh();\n    this.gotoPage(0);\n    this.updateNavigationBar();\n\n    if (this.options.debug) {\n      console.info(\"[CarrouselContent]\"\n        , {\n          widgetnode: this.widgetnode,\n          viewport: this.viewport,\n          viewport_inner: this.viewport_inner,\n          items: this.items,\n          bulletscontainer: this.bulletscontainer,\n          pages: this.pages\n        }\n      );\n    }\n\n    if (this.playing)\n      this.__applyCurrentAutoplay(this.options.autoplay_initialdelay);\n\n\n    if (window.resizeObserver) {\n      // Listen for changes in the viewport size (where we see the animation happen)\n      resizeObserver.observe(this.viewport);\n\n      // Listen for changes in content\n      // (this only works in viewport_inner was explicitly set)\n      if (this.viewport != this.viewport_inner)\n        resizeObserver.observe(this.viewport_inner);\n    }\n\n\n    window.__carrouselcontent_instances.push(\n      {\n        node: widgetnode,\n        instance: this\n      });\n\n    /*\n    This for now is to:\n    - fix the case in which we didn't pick up a scroll due to our tab not being visible\n    - detect/workaround a reported bug which we cannot reproduce\n    */\n    setInterval(this.verifyScrollPosition.bind(this), 1000);\n  }\n\n  verifyScrollPosition() {\n    const scrollLeft = this.viewport.scrollLeft; // for debugging\n\n    if (this.debug)\n      console.log(\"INTERVAL\", document.visibilityState, scrollLeft, this.scrollLeft);\n\n    if (scrollLeft != this.scrollLeft) {\n      console.error(\"scrollLeft checked in interval doesn't match the value from the last received scroll event.\");\n      this.onScroll(null);\n    }\n  }\n\n  maybePreviousPage(evt) {\n    if (evt.keyCode == 13 || evt.keyCode == 32) {\n      this.previousPage();\n      evt.preventDefault(); // we emulate a <button>, so \"space\" must trigger our click action, DON'T let the browser think the user wants to scroll the page\n    }\n  }\n\n  maybeNextPage(evt) {\n    if (evt.keyCode == 13 || evt.keyCode == 32) {\n      this.nextPage();\n      evt.preventDefault();\n    }\n  }\n\n  previousPage() {\n    if (this.options.debug)\n      console.log(\"previousPage\");\n\n    if (this.activepage > 0)\n      this.gotoPage(this.activepage - 1, true);\n    else if (this.options.allowwrap)\n      this.gotoPage(this.pages.length - 1);\n  }\n\n  nextPage() {\n    if (this.options.debug) {\n      console.log(\"nextPage\"\n        , {\n          activepage: this.activepage,\n          pagescount: this.pages.length,\n          nextactivepage: this.activepage + 1\n        });\n    }\n\n    if (this.activepage < this.pages.length - 1)\n      this.gotoPage(this.activepage + 1, true);\n    else if (this.options.allowwrap)\n      this.gotoPage(0);\n  }\n\n  gotoPage(idx, animate) {\n    if (this.options.debug)\n      console.log(\"[CarrouselContent] gotoPage\", idx, this.pages[idx], animate);\n\n    if (this.viewport.scrollTo) // asumming SmoothScroll polyfill has loaded (FIXME: check for scrollBehaviour or polyfill existance)\n      this.viewport.scrollTo({ left: this.pages[idx], behavior: \"smooth\" });\n    else\n      this.viewport.scrollLeft = this.pages[idx]; // SmoothScroll polyfill not loaded yet, IE might not have a scrollTo() function\n\n    //    if (animate && ('scrollBehavior' in document.documentElement.style))\n    //      this.viewport.scrollTo({ left: this.pages[idx], behavior: \"smooth\" });\n    //    else // IE\n    // this.viewport.scrollTo(this.pages[idx], 0);\n    //      this.viewport.scrollLeft = this.pages[idx];\n  }\n\n\n\n  onBulletClick(evt) {\n    if (evt.type == \"click\")\n      evt.preventDefault();\n\n    const bullet = evt.target.closest(\".\" + this.options.bulletclass);\n    const idx = this.bullets.indexOf(bullet);\n    if (!bullet)\n      return;\n\n    if (this.options.debug)\n      console.log(\"[CarrouselContent] onButtonClick\", bullet, idx);\n\n    this.gotoPage(idx, true);\n  }\n\n  onScroll(evt) {\n    this.scrollLeft = this.viewport.scrollLeft; // for debugging\n\n    const activepage = this.determineActivePage();\n    this.activepage = activepage;\n\n    if (this.activepage != this.prevactivepage) {\n      if (this.options.debug)\n        console.log(\"CarrouselContent::onScroll] active page changed to \", this.activepage);\n\n      this.updateNavigationBar();\n      this.prevactivepage = this.activepage;\n\n      if (this.options.onchangeslide) {\n        if (this.options.debug)\n          console.info(\"CarrouselContent::onScroll] using slidechange callback\");\n\n        this.options.onchangeslide({\n          slideidx: this.activepage,\n          slideidx_prev: this.prevactivepage,\n          slidedata: this.pagesinfo[this.activepage]\n        });\n      }\n    }\n  }\n\n  updateNavigationBar() {\n    if (this.options.previousbutton) {\n      if (!this.options.allowwrap && this.activepage == 0)\n        this.options.previousbutton.setAttribute(\"disabled\", \"\");\n      else\n        this.options.previousbutton.removeAttribute(\"disabled\");\n    }\n\n\n    if (this.options.nextbutton) {\n      if (!this.options.allowwrap && this.activepage == this.pages.length - 1)\n        this.options.nextbutton.setAttribute(\"disabled\", \"\");\n      else\n        this.options.nextbutton.removeAttribute(\"disabled\");\n    }\n\n    if (this.bullets.length > 0) {\n      for (let idx = 0; idx < this.pages.length; idx++)\n        this.bullets[idx].classList[idx == this.activepage ? \"add\" : \"remove\"](this.options.bulletselectedclass);\n    }\n\n    // Mark the first item of the page as active\n    if (this.options.item_activeclass != \"\") {\n      if (this.options.debug)\n        console.log(\"Active page\", this.activepage, this.pagesinfo[this.activepage]);\n\n      for (const item of this.items) {\n        //console.log(\"Updating active class for\", itemnode);\n        const in_view = this.pagesinfo[this.activepage].itemnodes.indexOf(item.node) > -1;\n\n        if (this.options.debug)\n          console.log(item, in_view);\n\n        item.node.classList.toggle(this.options.item_activeclass, in_view);\n      }\n    }\n  }\n\n  determineActivePage() {\n    const scrollLeft = this.viewport.scrollLeft;\n    const scrollWidth = this.viewport.scrollWidth;\n\n    const containerbounds = this.viewport_inner.getBoundingClientRect();\n\n    if (this.options.debug_determineactivepage)\n      console.group(\"[CarrouselContent] determineActivePage\");\n\n    let activepage = -1;\n\n    if (this.options.debug_determineactivepage) {\n      console.log(\"Pages\", this.pages);\n      console.info(\"ScrollLeft\", scrollLeft);\n    }\n\n\n    if (scrollLeft + this.viewport.offsetWidth == scrollWidth) {\n      if (this.options.debug) {\n        console.log(\"Reached last scrollLeft position, so last page.\");\n        console.groupEnd();\n      }\n\n      // we reached the end, so it'll always be the last bullet we need to highlight\n      activepage = this.pages.length - 1;\n      return activepage;\n    }\n\n\n    // Find the page we are in\n    for (let idx = 0; idx < this.pages.length - 1; idx++) {\n      const pagex = this.pages[idx];\n\n      if (this.options.debug_determineactivepage) {\n        console.info(\"Page\", idx, \"at\", pagex, \"till\", pagex + containerbounds.width);\n      }\n\n      if (idx == this.pages.length\n        || this.pages[idx + 1] > scrollLeft) //pagex + containerbounds.width > scrollLeft)// + 15 + 1) // FIXME: magic padding number\n      {\n        // Found active page\n        activepage = idx;\n        break;\n      }\n    }\n\n    // If we somehow passed without finding the page, it must be the last page\n    if (activepage == -1)\n      activepage = this.pages.length - 1;\n\n    if (this.options.debug_determineactivepage)\n      console.groupEnd();\n\n    return activepage;\n  }\n\n\n  refresh() {\n    this.recalculatePages();\n    this.createJumpButtons();\n    this.updateNavigationBar();\n  }\n\n  recalculatePages() {\n    if (!this.viewport)\n      return;\n\n    if (this.options.debug) {\n      console.group(\"[CarrouselContent] recalculatePages\", this.options.__test);\n      console.log(\"Items\", this.items);\n    }\n\n    this.pages = [];\n    // this.pageselem = [];\n    this.pagesinfo = [];\n    const viewportbounds_inner = this.viewport_inner.getBoundingClientRect();\n\n    const viewportbounds = this.viewport.getBoundingClientRect();\n    const scrollLeft = this.viewport.scrollLeft;\n\n    let nextpage_xpos = 0; //viewportbounds.width;\n\n\n    //let scrollSnapSupport = true;\n\n    let pagenr = 0;\n    let items_this_page = [];\n    let itemnodes_this_page = [];\n\n    for (const item of this.items) {\n      const measurenode = item.measurenode ?? item.node;\n      //console.log(\"Measurenode\", measurenode);\n      const itembounds = measurenode.getBoundingClientRect();\n      //console.log(itembounds);\n      if (itembounds.width == 0) // skip hidden items\n        continue;\n\n\n      let itemx, itemxend;\n      //if (scrollSnapSupport)\n      //{\n      // itemx = Math.floor(itembounds.left - viewportbounds.left) + scrollLeft;\n      // itemxend = Math.floor(itembounds.right - viewportbounds.left) + scrollLeft;\n      itemx = itembounds.left - viewportbounds.left + scrollLeft;\n      itemxend = itembounds.right - viewportbounds.left + scrollLeft;\n\n      // Get amount to keep from the edge... This is the amount we have to scroll less to get there\n      const comp = window.getComputedStyle(measurenode); //this.pageselem[idx]);\n      let left;\n      if (comp.scrollMarginLeft) {\n        left = parseInt(comp.scrollMarginLeft);\n\n        //if (this.options.debug)\n        //  console.log(\"scrollMarginLeft\", left);\n      } else if (comp.scrollSnapMarginLeft) // older Safari (11 up till 14)\n      {\n        left = parseInt(comp.scrollSnapMarginLeft);\n\n        //if (this.options.debug)\n        //  console.log(\"scrollSnapMarginLeft\", left);\n      } else {\n        // FIXMNE: or use item[0].getBoundingClientRect().left - viewport.getBoundingClientRect().left als scrollMarginLeft ??\n        left = viewportbounds_inner.left - viewportbounds.left; // Don't stoll the first item skipping the whitespace (padding in viewport, margin-left of viewport_iunner)\n\n        if (this.options.debug)\n          console.log(\"Keeping whitespace at start\", left);\n      }\n\n      // Reduce with the amount we have to scroll less\n      // (because the is meant to be whitespace at the left)\n      itemx -= left;\n      itemxend -= left;\n      /*\n      Support for older browsers (such as Internet Explorer)\n\n      }\n      else\n      {\n        // use inner because it's useually within the scroll snap bounds\n        itemx = Math.floor(itembounds.left) - Math.floor(viewportbounds_inner.left);\n        itemxend = Math.floor(itembounds.right) - Math.floor(viewportbounds_inner.left);\n\n        // If the container of the items\n        if (this.viewport == this.viewport_inner)\n        {\n          let scrollLeft = this.viewport.scrollLeft;\n          itemx += scrollLeft;\n          itemxend += scrollLeft;\n        }\n      }\n      */\n\n\n      if (this.options.debug) {\n        console.log({\n          node: item,\n          //  , innerviewport_left: viewportbounds_inner.left\n          item_left: itembounds.left,\n          item_width: itembounds.width,\n\n          xstart: itemx,\n          xend: itemxend\n        });\n      }\n\n      items_this_page.push(item);\n      itemnodes_this_page.push(item.node);\n\n\n      //if (itemx >= nextpage_xpos)\n      if (itemxend > nextpage_xpos) {\n        // console.log(\"Page will start at\", nextpage_xpos);\n        if (this.options.debug)\n          console.log(\"Page #\" + pagenr + \" starts at\", nextpage_xpos, \"and end before\", nextpage_xpos + this.viewport.clientWidth);\n\n        this.pages.push(Math.floor(itemx));\n        // this.pageselem.push(item);\n        this.pagesinfo.push(\n          {\n            x: Math.floor(itemx),\n            items: items_this_page,\n            itemnodes: itemnodes_this_page\n          });\n\n        items_this_page = [];\n        itemnodes_this_page = [];\n        pagenr++;\n\n        nextpage_xpos = itemx + this.viewport.clientWidth; // Math.floor(viewportbounds.width);\n\n        //if (this.options.debug)\n        //  console.log(\"Next page might be at\", nextpage_xpos);\n      }\n\n    }\n\n    if (this.options.debug)\n      console.log(\"pages:\", this.pagesinfo);\n\n    console.groupEnd();\n  }\n\n  createJumpButtons() {\n    if (!this.viewport || !this.bulletscontainer)\n      return;\n\n    const activepage = this.determineActivePage();\n\n    this.bulletscontainer.innerHTML = \"\";\n    this.bullets = [];\n\n    for (let idx = 0; idx < this.pages.length; idx++) {\n      let bullet = null;\n\n      if (this.options.createbullet) {\n        bullet = this.options.createbullet();\n      } else {\n        bullet = document.createElement(\"div\");\n        bullet.className = this.options.bulletclass;\n        bullet.classList[idx == activepage ? \"add\" : \"remove\"](this.options.bulletselectedclass);\n      }\n\n      //console.log(\"New bullet node\", bullet);\n\n      this.bulletscontainer.appendChild(bullet);\n      this.bullets.push(bullet);\n    }\n\n    const multiplepages = this.pages.length > 1;\n    this.bulletscontainer.style.display = multiplepages ? \"\" : \"none\";\n\n    this.widgetnode.classList[multiplepages ? \"add\" : \"remove\"](\"carrouselcontent--multiplepages\");\n  }\n\n  onResize() {\n    this.refresh();\n  }\n\n\n\n  //////////////////////////////////////////////\n  //\n  //  Autoplay support\n  //\n\n  initAutoplayVars() {\n    // autoplay support variables\n    this.autoplaytimer = null;\n    this.lastautoslidetime = null;\n    this.playing = this.options.autoplay;\n  }\n\n  // autoplay support\n  destroy() {\n    clearTimeout(this.autoplaytimer);\n    this.autoplaytimer = null;\n    this.playing = false;\n  }\n\n  // autoplay support\n  pause() {\n    this.playing = false;\n    this.__applyCurrentAutoplay();\n  }\n\n  // autoplay support\n  play() {\n    this.playing = true;\n    this.__applyCurrentAutoplay();\n  }\n\n\n\n  __applyCurrentAutoplay(delay) {\n    if (this.options.debug)\n      console.log(\"[CarrouselContent] __applyCurrentAutoplay\");\n\n    if (!delay)\n      delay = 0;\n\n    //console.log(this.__nextSlideByTimer);\n    if (this.playing)// && !document.hidden && this.inviewport)\n    {\n      if (!this.autoplaytimer) {\n        if (this.options.debug)\n          console.log(\"[CarrouselContent] Setting new timer for auto slide\");\n\n        this.autoplaytimer = setTimeout(this.__nextSlideByTimer.bind(this), this.options.autoplay_freezeslideduration + delay);\n      } else if (this.options.debug)\n        console.log(\"[CarrouselContent] Timer already running...\");\n    } else {\n      if (this.options.debug)\n        console.log(\"[CarrouselContent] No autoplay\");//, { play: this.playing, dochidden: document.hidden, inviewport: this.inviewport });\n\n      if (this.autoplaytimer) {\n        clearTimeout(this.autoplaytimer);\n        this.autoplaytimer = null;\n      }\n    }\n  }\n\n  __nextSlideByTimer() {\n    if (!this.options.autoplay) // did a timer event still get through?\n      return;\n\n    this.lastautoslidetime = new Date().getTime();\n\n    this.nextPage();\n\n    this.autoplaytimer = setTimeout(this.__nextSlideByTimer.bind(this), this.options.autoplay_freezeslideduration);\n  }\n}\n\n\n//module.exports = { CarrouselContent: CarrouselContent };\nexport { CarrouselContent };\n\n\n\n/*\nHaving a single resizeObserver is better for performance.\nSee: https://groups.google.com/a/chromium.org/g/blink-dev/c/z6ienONUb5A/m/F5-VcUZtBAAJ?pli=1\n*/\nlet resizeObserver;\nif (window.ResizeObserver)\n  resizeObserver = new ResizeObserver(entries => onResize(entries));\nelse\n  window.addEventListener(\"resize\", resizeAllContentCarrousels); // handled using the resizeObserver\n\n\n\nfunction onResize(entries) {\n  console.log(\"onResize\", entries);\n\n  for (const entry of entries) {\n    for (const widgetdata of window.__carrouselcontent_instances) {\n      if (entry.target == widgetdata.instance.viewport) {\n        console.info(\"Widget has resized\");\n        widgetdata.instance.onResize();\n      }\n    }\n  }\n}\n\nfunction resizeAllContentCarrousels() {\n  for (const widgetdata of window.__carrouselcontent_instances)\n    widgetdata.instance.onResize();\n}\n\ndompack.onDomReady(resizeAllContentCarrousels);\nwindow.addEventListener(\"load\", resizeAllContentCarrousels);\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./imagewithcaption.scss\";\nimport * as CarrouselContent from \"@mod-utwente_base/webdesigns/ws2016/src/components/carrouselcontent\";\nimport * as dompack from \"dompack\";\n\n\n\nfunction initImagesWithCaptionWidget(widgetnode) {\n  const carrousel = new CarrouselContent.CarrouselContent(widgetnode\n    , {\n      viewport: \".imageswithcaption--multiple .imageswithcaption__images\",\n      viewport_inner: \".imageswithcaption__images\",\n      // , itemsselector:    \".imageswithcaption__item\"\n      itemsselector: \".imageswithcaption__item__image\",\n      bulletscontainer: \".imageswithcaption__jumpbuttons\",\n\n      bulletclass: \"imageswithcaption__jumpbutton\",\n      bulletselectedclass: \"slideshow--activedot\",\n      createbullet: doCreateBullet,\n\n      onchangeslide: onChangeSlide,\n\n      autoplay: true,\n      allowwrap: true,\n\n      // Debug settings\n      __test: \"ImagesWithCaption\"\n      // , debug:                     debug\n      // , debug_determineactivepage: debug\n    });\n\n  // Pause the carrousel while hovering over it\n  widgetnode.addEventListener(\"mouseenter\", () => {\n    widgetnode.classList.add(\"imageswithcaption--paused\");\n    carrousel.pause();\n  });\n  widgetnode.addEventListener(\"mouseleave\", () => {\n    widgetnode.classList.remove(\"imageswithcaption--paused\");\n    carrousel.play();\n  });\n}\n\nfunction onChangeSlide(details) {\n  const firstnodeinslide = details.slidedata.itemnodes[0];\n  const nodeid = firstnodeinslide.getAttribute(\"aria-describedby\");\n  const activemetanode = document.getElementById(nodeid);\n\n\n  const widget = firstnodeinslide.closest(\".embeddedobject--imageswithcaption\");\n  const metaslidescontainer = widget.querySelector(\".imageswithcaption__metaslides\");\n\n  // Update the active state of each information panel\n  let metanode = metaslidescontainer.firstElementChild;\n  while (metanode) {\n    metanode.classList.toggle(\"active\", activemetanode == metanode);\n    metanode = metanode.nextElementSibling;\n  }\n}\n\nfunction doCreateBullet() {\n  return <span class=\"imageswithcaption__jumpbutton UT-icon-UT_icon_77_sliderdot-16px\">\n    <span class=\"imageswithcaption__jumpbutton-active UT-icon-UT_icon_76_slider-dot-active-16px\"></span>\n  </span>;\n}\n\ndompack.register(\".imageswithcaption--multiple\", initImagesWithCaptionWidget);\n","import \"./countdown.css\";\nimport * as dompack from \"@webhare/dompack\";\n\n// Extend Element interface to allow __countdown_value property\ndeclare global {\n  interface Element {\n    __countdown_value?: number;\n    __countdown_digitidx?: number;\n  }\n}\n\ntype onExpiredCallbackFunction = () => void;\n\nexport class CountDownComponent {\n  node: HTMLElement;\n  node_day: HTMLElement;\n  node_daydigits: HTMLElement[];\n  node_hours: HTMLElement;\n  node_hourdigits: HTMLElement[];\n  node_minutes: HTMLElement;\n  node_minutedigits: HTMLElement[];\n  node_seconds: HTMLElement;\n  node_seconddigits: HTMLElement[];\n  node_digits: HTMLElement[];\n  animframetimer: null | number = null;\n  options: {\n    countdownto: string;\n    countdownfrom: string;\n    onexpired: onExpiredCallbackFunction | null; //Function;\n  };\n\n  countdownvalue: {\n    days: number;\n    hours: number;\n    minutes: number;\n    seconds: number;\n    expired: boolean;\n  } | null = null;\n  countdownto: Date | null = null;\n  countdownfrom: Date | null = null;\n  countdownto_timestamp: number = 0; // Timestamp\n  countdownfrom_timestamp: number = 0; // Timestamp\n\n  previousroundedtime: number = 0;\n  /*\n  this.countdownvalue =\n  { days:    0\n  , hours:   0\n  , minutes: 0\n  , seconds: 0\n  , expired: true\n  };\n  */\n\n  debug: boolean;\n  initialized: boolean = false;\n\n\n  constructor(node: HTMLElement, options: { countdownto?: string; countdownfrom?: string; onexpired?: onExpiredCallbackFunction | null }) {\n    this.node = node;\n\n    this.debug = node.hasAttribute(\"data-debugcountdown\");\n\n    this.options = {\n      countdownto: \"\",\n      countdownfrom: \"\",\n      onexpired: null,\n      ...options\n    };\n\n    if (this.debug)\n      console.log(\"[CountDownComponent] initializing\", options);\n\n    this.node_day = node.querySelector(\".countdown__section--days\") as HTMLElement;\n    this.node_daydigits = Array.from(this.node_day.querySelectorAll(\".countdown__digit\"));\n    this.node_hours = node.querySelector(\".countdown__section--hours\") as HTMLElement;\n    this.node_hourdigits = Array.from(this.node_hours.querySelectorAll(\".countdown__digit\"));\n    this.node_minutes = node.querySelector(\".countdown__section--minutes\") as HTMLElement;\n    this.node_minutedigits = Array.from(this.node_minutes.querySelectorAll(\".countdown__digit\"));\n    this.node_seconds = node.querySelector(\".countdown__section--seconds\") as HTMLElement;\n    this.node_seconddigits = Array.from(this.node_seconds.querySelectorAll(\".countdown__digit\"));\n\n    this.node_digits = Array.from(node.querySelectorAll(\".countdown__digit\"));\n\n    if (this.debug)\n      console.info(\"[CountDownComponent] Counting down to %s\", node.dataset.countdownto, this.countdownto_timestamp);\n\n    this.enhanceDOM();\n\n    if (options.countdownfrom)\n      this.setCountdownFrom(options.countdownfrom);\n    else if (node.dataset.countdownfrom)\n      this.setCountdownFrom(node.dataset.countdownfrom);\n\n    if (options.countdownto)\n      this.setCountdownTo(options.countdownto);\n    else if (node.dataset.countdownto)\n      this.setCountdownTo(node.dataset.countdownto);\n    else\n      console.error(\"[CountDownComponent] initialized without setting options.countdownto or a data-countdownto attribute on .component-countdown\");\n\n    this.refreshAndScheduleNextFrame();\n\n    // FIXME: how to handle this with multiple events !!?\n    if (this.countdownvalue && this.countdownvalue.days === 0)\n      this.node_day.classList.add(\"countdown__section--initiallyleadingzero\");\n\n    node.classList.add(\"component-countdown--allowanimation\");\n\n    this.node.addEventListener(\"transitionend\", evt => this.onTransitionEnd(evt));\n    document.addEventListener(\"visibilitychange\", () => this.onPageVisibilityChange());\n\n    this.initialized = true;\n  }\n\n  setCountdownFrom(countdownfrom: string) {\n    this.countdownfrom = parseCountdownToString(countdownfrom);\n    this.countdownfrom_timestamp = this.countdownfrom.getTime();\n\n    if (this.countdownfrom_timestamp && new Date().getTime() < this.countdownfrom_timestamp) {\n      if (this.debug)\n        console.info(\"[CountDownComponent] The countdown has not started yet!\");\n\n      this.node.classList.add(\"component-countdown--before\");\n\n      // Solution for browsers which don't support :has\n      // If all browsers support this we could use .widget-countdown:has(.component-countdown--exired)\n      const specialcontainer = this.node.closest(\"[data-markifbefore]\");\n      if (specialcontainer)\n        specialcontainer.classList.add(\"has-before-countdown\");\n    }\n  }\n\n  setCountdownTo(countdownto: string) {\n    this.countdownto = parseCountdownToString(countdownto);\n    this.countdownto_timestamp = this.countdownto.getTime();\n    this.countdownvalue = null; // the next refresh() (called in onAnimFrame) will set this.countdownvalue again\n    this.previousroundedtime = 0; // timestamp used last time for drawing the countdown\n\n    this.node.classList.remove(\"component-countdown--expired\");\n\n    // refreshing is meant for when external code calls setCountdownTo().\n    // When we call setCountdownTo() during initialization we aren't ready yet for this.\n    if (this.initialized)\n      this.refreshAndScheduleNextFrame();\n  }\n\n  stopCountdown() {\n    if (!this.animframetimer)\n      return;\n\n    cancelAnimationFrame(this.animframetimer);\n    this.animframetimer = null;\n  }\n\n  onPageVisibilityChange() {\n    if (document.visibilityState === \"hidden\") {\n      this.node.classList.remove(\"component-countdown--allowanimation\");\n      return;\n    }\n\n    // When returning to a previous invisible page CSS will be computed again and transitions will\n    // we triggered which were meant to have been finished earlyer.\n    // To prevent this whe'll disable transitions for a moment.\n    if (document.visibilityState === \"visible\") {\n      // Fix any zero's which we haven't moved\n      // (because we useually do this in the transitionend, but transitions aren't done\n      // while the document isn't visible (tab hidden or browser window minimized)\n      for (const digitnode of this.node_digits) {\n        if (digitnode.firstElementChild!.__countdown_value! === 0) {\n          const wrapidx = this.__getWrapDigitIDX(digitnode);\n          this.setTrackPosition(digitnode, wrapidx);\n        }\n      }\n\n      requestAnimationFrame(this.reenableTransitions.bind(this));\n    }\n  }\n\n  reenableTransitions() {\n    // first frame after we became visible.\n    // This animation frame will trigger a transition if we directly enable transitions,\n    // so whe'll delay until the next one.\n    requestAnimationFrame(this.reenableTransitions2.bind(this));\n  }\n\n  reenableTransitions2() {\n    this.node.classList.add(\"component-countdown--allowanimation\");\n  }\n\n  onAnimFrame() {\n    this.animframetimer = null;\n    this.refreshAndScheduleNextFrame();\n  }\n\n  refreshAndScheduleNextFrame() {\n    this.refresh();\n\n    if (!this.animframetimer\n      && (!this.countdownvalue // first frame for the current countdown value (so no value available yet)\n        || !this.countdownvalue.expired)) {\n      this.animframetimer = requestAnimationFrame(this.onAnimFrame.bind(this));\n    }\n  }\n\n  refresh() {\n    const now = new Date();\n    let now_timestamp = now.getTime();\n\n    if (now_timestamp % 1000 > 950)\n      now_timestamp += 1000 - now_timestamp % 1000;\n    else\n      now_timestamp = now_timestamp - now_timestamp % 1000;\n\n    if (now_timestamp === this.previousroundedtime)\n      return;\n\n    this.previousroundedtime = now_timestamp;\n    this.refreshFor(now_timestamp);\n  }\n\n  refreshFor(now: number) {\n    // console.info(\"refreshFor\", now);\n    if (this.node.classList.contains(\"component-countdown--before\")) {\n      if (this.countdownfrom_timestamp && now >= this.countdownfrom_timestamp) {\n        if (this.debug)\n          console.info(\"[CountDownComponent] The countdown starts now!\");\n\n        this.node.classList.remove(\"component-countdown--before\");\n\n        // Solution for browsers which don't support :has\n        // If all browsers support this we could use .widget-countdown:has(.component-countdown--exired)\n        const specialcontainer = this.node.closest(\"[data-markifbefore]\");\n        if (specialcontainer)\n          specialcontainer.classList.remove(\"has-before-countdown\");\n      } else {\n        // Still before the countdown start date\n        return;\n      }\n    }\n\n    if (now > this.countdownto_timestamp) {\n      if (this.debug)\n        console.info(\"[CountDownComponent] The countdown has expired!\");\n\n      this.node.classList.add(\"component-countdown--expired\");\n\n      // Solution for browsers which don't support :has\n      // If all browsers support this we could use .widget-countdown:has(.component-countdown--exired)\n      const specialcontainer = this.node.closest(\"[data-markifexpired]\");\n      if (specialcontainer)\n        specialcontainer.classList.add(\"has-expired-countdown\");\n\n      this.countdownvalue = {\n        days: 0,\n        hours: 0,\n        minutes: 0,\n        seconds: 0,\n        expired: true\n      };\n\n      if (this.options.onexpired)\n        this.options.onexpired();\n\n      return;\n    }\n\n    const distance = this.countdownto_timestamp - now;\n\n    // Time calculations for days, hours, minutes and seconds\n    const days = Math.floor(distance / (1000 * 60 * 60 * 24));\n    const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));\n    const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));\n    const seconds = Math.floor((distance % (1000 * 60)) / 1000);\n\n    this.node_day.classList.toggle(\"leadingzeros\", days === 0);\n    this.node_hours.classList.toggle(\"leadingzeros\", days === 0 && hours === 0);\n    this.node_minutes.classList.toggle(\"leadingzeros\", days === 0 && hours === 0 && minutes === 0);\n    this.node_seconds.classList.toggle(\"leadingzeros\", days === 0 && hours === 0 && minutes === 0 && seconds === 0);\n\n    const digits = [\n      Math.floor(days / 100),      // day X..\n      Math.floor(days / 10) % 10,  // day .X.\n      days % 10,                   // day ..X\n\n      Math.floor(hours / 10),\n      hours % 10,\n\n      Math.floor(minutes / 10),\n      minutes % 10,\n\n      Math.floor(seconds / 10),\n      seconds % 10\n    ];\n\n    let idx = 0;\n    let leadingzero = true;\n    let initially_visible_digits = 0;\n\n    for (const digitnr of digits) {\n      void digitnr; // FIXME: just to stop eslint from complaining - but maybe we should use for with a counter instead?\n      const value = digits[idx];\n      if (value > 0)\n        leadingzero = false;\n\n      if (!leadingzero)\n        initially_visible_digits++;\n\n      const digitnode = this.node_digits[idx];\n\n      // Especially for days we may want to hide the digits which will start at 0\n      if (!this.initialized && leadingzero)\n        this.node_digits[idx].classList.toggle(\"countdown__digit--initiallyleadingzero\", leadingzero);\n\n      // Prevent basing the DOM with unnessecary updates\n      // AND prevent scrolling back from the 2nd zero to the first zero.\n      if (digitnode.firstElementChild!.__countdown_value !== value) {\n        this.setDigit(digitnode, value);\n        this.node_digits[idx].classList.toggle(\"countdown__digit--leadingzero\", leadingzero);\n      }\n\n      idx++;\n    }\n\n    this.node.setAttribute(\"data-initiallyvisibledigits\", initially_visible_digits.toString());\n\n    this.countdownvalue = {\n      days: days,\n      hours: hours,\n      minutes: minutes,\n      seconds: seconds,\n      expired: false\n    };\n\n    if (this.debug)\n      console.info(\"[CountDownComponent]\", this.countdownvalue);\n  }\n\n  setDigit(node: HTMLElement, number: number) {\n    node.firstElementChild!.__countdown_value = number;\n    node.setAttribute(\"data-countvalue\", String(number));\n    this.__shiftTrack(node, number);\n  }\n\n  __shiftTrack(node: HTMLElement, amount: number) {\n    /*\n    We need to go to the wrapping digit if:\n    - we start at 0 (during initialization)\n    - the document/browser-tab isn't visible (because whe're hidden there'll be no transition or transitionend event)\n    */\n    if (amount === 0 && (!this.initialized || document.visibilityState === \"hidden\"))\n      amount = this.__getWrapDigitIDX(node);\n\n    this.setTrackPosition(node, amount);\n  }\n\n  __getWrapDigitIDX(node: HTMLElement) {\n    const digitdesc = node.getAttribute(\"data-digit\");\n    if (digitdesc === \"minutes-ten\" || digitdesc === \"seconds-ten\")\n      return 6;\n    else if (digitdesc === \"hours-ten\")\n      return 3;\n    else\n      return 10;\n  }\n\n  setTrackPositionToWrapDigit(node: HTMLElement) {\n    const position = this.__getWrapDigitIDX(node);\n    this.setTrackPosition(node, position);\n  }\n\n  setTrackPosition(node: HTMLElement, amount: number) {\n    const value = `translateY(calc(-${100 * amount}% - ${amount}px))`;\n    const firstchild = node.firstElementChild as HTMLElement;\n    firstchild.style.transform = value;\n    firstchild.__countdown_digitidx = amount;\n  }\n\n  onTransitionEnd(evt: Event) {\n    // When our transition landed on a 0\n    const tracknode = evt.target as HTMLElement;\n    if (tracknode.__countdown_value === 0) {\n      /* Shift any digit which stopped their transition landing on a zero\n         to the second occurence of zero at the bottom of the track.\n         This ensures we can continue scroll up as if our scroller wraps. */\n      const digitcontainer = tracknode.parentNode as HTMLElement;\n\n      if (document.hidden) {\n        // shift to the 2nd occurence of 0 so we can scroll back up to 9 again\n        this.setTrackPositionToWrapDigit(digitcontainer);\n      } else {\n        tracknode.style.transition = \"none\";\n\n        // shift to the 2nd occurence of 0 so we can scroll back up to 9 again\n        this.setTrackPositionToWrapDigit(digitcontainer);\n\n        setTimeout(() => { tracknode.style.transition = \"\"; });\n      }\n    }\n  }\n\n  enhanceDOM() {\n    const digits = this.node.querySelectorAll(\".countdown__digit\");\n\n    const frag_alldigits = this.getDigitsFragment([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0]);\n    const frag_lessdigits = this.getDigitsFragment([0, 1, 2, 3, 4, 5, 0]); // seconds and minutes only go up to 59\n    const frag_digits_hourstens = this.getDigitsFragment([0, 1, 2, 0]); // hours only goes up to 23\n\n    for (const digit of digits) {\n      const digitdesc = digit.getAttribute(\"data-digit\");\n\n      let frag;\n      if (digitdesc === \"minutes-ten\" || digitdesc === \"seconds-ten\")\n        frag = frag_lessdigits;\n      else if (digitdesc === \"hours-ten\")\n        frag = frag_digits_hourstens;\n      else\n        frag = frag_alldigits;\n\n      digit.replaceChild(frag.cloneNode(true), digit.firstChild!);\n    }\n  }\n\n  getDigitsFragment(nrs: number[]) {\n    /*\n    Create digits DOM which we can clone/copy into each digit container.\n    These are the numbers we can scroll.\n    By adding an extra 0 we can animate from the last number (9 or 5) to the 0\n    and after the transition finished jump back to the 0 at the top\n    so it seems the counter wraps endlessly.\n    */\n    const frag = document.createDocumentFragment();\n    const paper = document.createElement(\"div\"); // container which we move through the .countdown__digit viewport/track\n    paper.className = \"countdown__digit__track\";\n    frag.appendChild(paper);\n\n    // 0 to 9\n    for (const current_nr of nrs) {\n      const digitnode = document.createElement(\"div\");\n      digitnode.className = \"countdown__digit__number\";\n      digitnode.innerText = current_nr.toString();\n      paper.appendChild(digitnode);\n    }\n\n    return frag;\n  }\n}\n\nexport function parseCountdownToString(str: string) {\n  const parts = str.split(\" \");\n  const dayparts = parts[0].split(\"-\");\n  const timeparts = parts[1].split(\":\");\n  const date = new Date(Number(dayparts[0]), Number(dayparts[1]) - 1, Number(dayparts[2]), Number(timeparts[0]), Number(timeparts[1]));\n\n  return date;\n}\n\ndompack.register(\".component-countdown[data-countdownto]\", initCountdownComponent);\n\nfunction initCountdownComponent(node: HTMLElement) {\n  new CountDownComponent(node, {});\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n/*\nFIXME: do we need to use the servertime to ensure the correct countdown (even if the datetime on the computer is messed up) ?\n\nNOTES:\n- countdown components will auto-initialize if they have a data-countdownto attribute\n\n\n[data-markifexpired]\n*/\nimport \"./countdown-widget.css\";\nimport \"./countdown-eventslist.css\";\nimport * as countdown from \"@mod-utwente_base/webfeatures/utcomponents/countdown\";\nimport * as dompack from \"dompack\";\n\n\n\n\n\n\n/*\nGlobal working of the \"Countdown (with events)\" widget\n- The widget will gather the event information attached as JSON to each event (.component-ctalinks__item)\n- We don't specify data-countdownto on .component-countdown so it won't autoinitialize\n  (leaving our CountDownEventsWidget to handle which event we start with)\n- The widget will update all .widget-countdown-expireditem classes\n  (upon initialization and each time after the CountDownComponent used the onexpired callback)\n- The widget will control to which event to count (which is next in time)\n- Only when the enddate of the last event has expired, the expired panel will be shown\n- The \".addeventatc\" class is the triger for AddEvent\n\nWorkin of \"Add to calendar\" functionality\n- The \"Add to calendar\" button will only add the event which we currently count down to\n- Each event in the list contains a <div class=\"addevent-data\" style=\"display:none\">\n  which contains the information for AddEvent.\n  When a countdown is started for an event, the innerHTML of this element will be copied\n  to \".widget-countdown__addtocalendar .addevent-data\"\n*/\nclass CountDownEventsWidget {\n  constructor(node) {\n    console.info(\"[CountDownEventsWidget] Welcome\");\n\n    this.node = node;\n\n    this.events = [];\n    this.currentevent = null;\n\n    this.counter = null;\n    this.countdownnode = node.querySelector(\".component-countdown\");\n\n    const now = new Date();\n\n    this.eventnodes = this.node.querySelectorAll(\".component-ctalinks__item\");\n    for (const eventnode of this.eventnodes) {\n      const eventdata = JSON.parse(eventnode.dataset.event);\n\n      this.events.push(\n        {\n          node: eventnode,\n          ...eventdata,\n          countdownto_start_dt: countdown.parseCountdownToString(eventdata.countdownto_start),\n          countdownto_end_dt: countdown.parseCountdownToString(eventdata.countdownto_end),\n          expired: now > eventdata.countdownto_end_dt\n        });\n    }\n\n    this.refresh();\n  }\n\n  refresh() {\n    const now = new Date();\n\n    let firstupcomingevent = null;\n\n    // The events are sorted by date so we can assume the first event with\n    // the startdate in the future is the \"first upcoming event\"\n    for (const eventdata of this.events) {\n      if (eventdata.expired)\n        continue;\n\n      if (now > eventdata.countdownto_end_dt)\n        eventdata.node.classList.add(\"widget-countdown-expireditem\");\n      else if (!firstupcomingevent)\n        firstupcomingevent = eventdata;\n    }\n\n    // Start countdown for the first upcoming event\n    if (firstupcomingevent) {\n      firstupcomingevent.node.classList.add(\"widget-countdown-countingdownto\");\n\n      this.currentevent = firstupcomingevent; // set before initializing, in case expiry is triggered directly when initializing\n\n\n      // Update the \"Add to calendar\" button\n      // With the DOM addevent.com needs.\n      const addevent_data_container = this.node.querySelector(\".widget-countdown__addtocalendar .addevent-data\");\n      if (addevent_data_container)\n        addevent_data_container.innerHTML = firstupcomingevent.node.querySelector(\".addevent-data\").innerHTML;\n\n\n      if (!this.counter) {\n        console.info(\"Setting event (initializing countdown)\", firstupcomingevent);\n        this.counter = new countdown.CountDownComponent(this.countdownnode, {\n          countdownto: firstupcomingevent.countdownto_start,\n          onexpired: this.onCurrentCountdownExpired.bind(this)\n        });\n      } else {\n        console.info(\"Setting event (update countdown to new countdown target)\", firstupcomingevent);\n        this.counter.setCountdownTo(firstupcomingevent.countdownto_start);\n      }\n    } else {\n      this.node.classList.add(\"has-expired-countdown\");\n    }\n  }\n\n  onCurrentCountdownExpired() {\n    // console.info(\"Current countdown expired\");\n    this.currentevent.expired = true;\n    this.currentevent.node.classList.remove(\"widget-countdown-countingdownto\");\n    this.currentevent.node.classList.add(\"widget-countdown-expireditem\");\n    this.refresh();\n  }\n}\n\n// \"Countdown (with events)\" widget needs to handle multiple events\n// and control which event is count down to.\ndompack.register(\".widget-countdown--withevents\", initCountDownWidget);\n\nfunction initCountDownWidget(node) {\n  new CountDownEventsWidget(node);\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./events.scss\";\nimport * as dompack from \"dompack\";\nimport { relayoutWidgets } from \"../layout\";\n\nfunction renderEvents(node, items) {\n  if (items.length === 0) {\n    dompack.remove(node); //Just remove widget if no events\n    return;\n  }\n\n  const listnode = dompack.qS(node, \".widget__list\");\n  items.forEach(item => {\n    const link = node.dataset.baseurl ? node.dataset.baseurl + item.suburl : item.url;\n    listnode.appendChild(<a href={link} class=\"widget__listitem widget__listitem--link\">\n      <span class=\"widget__listitem-icon widget__listitem-icon--small UT-icon-UT_icon_52_arrow-right-round-16px\" />\n      <span class=\"widget__listitem-text\">{item.title}</span>\n      <span class=\"widget__listitem-subtext\">{item.widgetdate}</span>\n    </a>);\n  });\n\n  //Trigger ut masonry update\n  relayoutWidgets(node);\n}\n\nasync function getEventItems(node) {\n  const response = await fetch(node.dataset.publocfile);\n  if (response && response.status === 200) {\n    const items = await response.json();\n    if (items && items[\"p\" + node.dataset.publoc])\n      renderEvents(node, items[\"p\" + node.dataset.publoc].items);\n    else\n      dompack.remove(node); //Just remove widget if no events\n  }\n}\n\ndompack.register(\".widget-ws2016events\", node => getEventItems(node));\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./faq.scss\";\n\nimport { RPCFormBase, registerHandler } from '@mod-publisher/js/forms';\n\nclass FeedbackForm extends RPCFormBase {\n  constructor(node) {\n    super(node);\n\n    this.container = this.node.closest(\".feedback\");\n\n    for (const inpnode of this.container.querySelectorAll(\"input[name='useful']\")) {\n      inpnode.addEventListener(\"change\", ev => {\n        this.ispositive = ev.target.value === \"yes\";\n        this.container.classList.add(this.ispositive ? \"feedback--ispositive\" : \"feedback--isnegative\");\n        this.reset();//Always first empty form!\n        if (!this.faqquestion) {\n          const faqnode = this.node.closest(\".wh-details\");\n          if (!faqnode)\n            return;\n          this.faqquestion = faqnode.querySelector(\".wh-details__summary\");\n        }\n\n        if (window.dataLayer)\n          window.dataLayer.push({ event: \"faq-\" + (this.ispositive ? \"ja\" : \"nee\"), \"faqcontent\": this.faqquestion.textContent });\n      });\n    }\n  }\n\n  getFormExtraSubmitData() {\n    return {\n      token: this.node.dataset.token,\n      faqquestion: this.faqquestion ? this.faqquestion.textContent : \"\"\n    };\n  }\n\n  onSubmitSuccess(res) {\n    if (res.success)\n      this.container.classList.add(\"feedback--send\");\n  }\n}\n\nregisterHandler(\"utwente_base:faqfeedbackform\", node => new FeedbackForm(node));\n","import \"./imagevideowithtext.scss\";\nimport * as dompack from \"dompack\";\nimport * as modaldialog from \"@mod-utwente_base/webdesigns/ws2016/src/shared/dialog\";\n\ndompack.register(\".embeddedobject-imagevideowithtext__image__fullscreen\", node => {\n  node.addEventListener(\"click\", () => {\n    modaldialog.showModalDialog(\"\",\n      <img src={node.dataset.src} class=\"embeddedobject-imagevideowithtext-dialog__image\" alt=\"\" />, {\n        theme: \"embeddedobject-imagevideowithtext-dialog\"\n      }\n    );\n  });\n});\n","//@ts-nocheck TODO Fix me!\nimport \"./dialog.scss\";\nimport * as dialog from 'dompack/components/dialog';\nimport * as dialogapi from 'dompack/api/dialog';\nimport * as dompack from 'dompack';\nimport { getTid } from \"@webhare/gettid\";\nimport \"./dialog.lang.json\";\nimport PerfectScrollbar from \"@mod-utwente_design/vendor/perfect-scrollbar-wh\";\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// NEW UT DIALOG\n\nexport async function runYesNoMessageBox(question: string) {\n  //support linefeeds\n  const node = <span>{question.split('\\n').map(n => [n, <br />])}</span>;\n  return dialogapi.runMessageBox(node,\n    [\n      { result: \"yes\", title: getTid(\"utwente_base:site-common.texts.yes\") },\n      { result: \"no\", title: getTid(\"utwente_base:site-common.texts.no\") }\n    ], { allowcancel: true });\n}\n\nexport class UTDialog extends dialog.BasicDialog {\n  utheadernode = <div class=\"ut-dialog__header\"></div>;\n  ps;\n\n  constructor(options) {\n    super('ut-dialog', options);\n\n    if (options && options.allowcancel) {\n      const closebtn = <button class=\"ut-dialog--isclose ut-dialog__closeicon UT-icon-UT_icon_47_cross-16px\"\n        onClick={evt => { dompack.stop(evt); this.resolve(\"close\"); }}\n        aria-label={getTid(\"utwente_base:frontend.ws2016.js.dialog-close-arialabel\")}\n        type=\"button\"\n      ></button>;\n      this.holdernode.appendChild(closebtn);\n    }\n\n    this.contentnode!.before(this.utheadernode);\n    this.modalitynode?.addEventListener(\"wheel\", evt => dompack.stop(evt)); //TODO - remove once UT is WH 4.34+\n\n    if (!options || !options.nativescroll)\n      this.ps = new PerfectScrollbar(this.contentnode!, {\n        swipePropagation: false,\n        wheelPropagation: false,\n        suppressScrollX: true\n      });\n\n    const observer = new ResizeObserver(() => this._checkContents());\n    observer.observe(this.contentnode!);\n  }\n\n  afterShow() {\n    //basic animation\n    void (this.holdernode.clientHeight);//force css update\n    this.holdernode.classList.add(\"ut-dialog--aftershow\");\n\n    // We must either set focus to the new content or use aria-live to announce the new content.\n    // Otherwise the screenreader user may not know something has happened at all.\n    this.holdernode.setAttribute(\"tabindex\", \"-1\");\n    this.holdernode.focus();\n\n    dompack.qSA(this.holdernode, '.wh-form__button').forEach(button => button.classList.add('cta__button'));\n    dompack.registerMissed(this.holdernode);\n\n    if (this.ps)\n      setTimeout(() => this.ps.update(), 510); //update scrollbare after animation\n  }\n\n  _checkContents() {\n    // add the bottom 30px if the popup would need to scroll\n    this.holdernode.parentNode/*this.modalitynode*/.classList.toggle(\"ut-dialog--expanded\", this.contentnode.scrollHeight > this.contentnode.offsetHeight);\n\n    if (this.ps) // Update perfect scrollbar\n      this.ps.update();\n  }\n}\n\n\n/////////////////////////////////////////////////////////////////////////////\n//\n// LEGACY UT DIALOG\n\n/*\n  Simple modal dialog\n*/\nfunction showModalDialog(title, contents, options) {\n  if (!options)\n    options = {};\n\n  let modalnode = document.querySelector(\".dialog__modal\");\n  if (modalnode)\n    hideModalDialog();//close previous dialog\n\n  modalnode = document.createElement(\"div\");\n  modalnode.className = \"dialog__modal\" + (options.theme ? \" \" + options.theme : \"\");\n\n  if (options.theme && modalnode.classList.contains(\"withbackground\")) {\n    if (options.background) {\n      modalnode.style.backgroundImage = \"url(\" + options.background + \")\";\n    } else { //get blurred background from header\n      const blurredbg = document.querySelector(\".header__photo-0--background\");\n      if (blurredbg) {\n        const bg = window.getComputedStyle(blurredbg, null).getPropertyValue(\"background-image\");\n        if (bg)\n          modalnode.style.backgroundImage = bg;\n      }\n    }\n  }\n\n  const bodynode = document.createElement(\"div\");\n  bodynode.className = \"dialog__body\";\n  modalnode.appendChild(bodynode);\n\n  if (title !== \"\") {\n    const titlenode = document.createElement(\"div\");\n    titlenode.className = \"title\";\n    titlenode.innerHTML = title;\n    bodynode.appendChild(titlenode);\n  }\n\n  if (!options.disable_close) {\n    const closebtn = document.createElement(\"button\");\n    closebtn.className = \"close UT-icon-UT_icon_47_cross-16px\";\n    closebtn.setAttribute(\"type\", \"button\");\n    closebtn.setAttribute(\"aria-label\", getTid(\"utwente_base:frontend.ws2016.js.dialog-close-arialabel\"));\n    /*\n          let closebtn = <button class=\"ut-dialog--isclose ut-dialog__closeicon UT-icon-UT_icon_47_cross-16px\"\n                                 onClick={ evt => { dompack.stop(evt); this.resolve(\"close\") }}\n                                 aria-label={}></button>;\n    */\n    if (options.position_close && options.position_close === \"outside\")\n      modalnode.appendChild(closebtn);\n    else\n      bodynode.appendChild(closebtn);\n  }\n\n  const contentnode = document.createElement(\"div\");\n  contentnode.className = \"dialog__content\";\n  bodynode.appendChild(contentnode);\n\n  if (typeof contents === \"object\")\n    contentnode.appendChild(contents);\n  else if (typeof contents === \"string\")\n    contentnode.innerHTML = contents;\n\n  if (!options.disable_close) {\n    modalnode.addEventListener('click', hideModalDialog);\n    document.body.addEventListener('keydown', hideModalDialog);\n  }\n\n  document.body.appendChild(modalnode);\n\n  //basic animation\n  // eslint-disable-next-line @typescript-eslint/no-unused-expressions\n  bodynode.clientHeight;//force css update\n  modalnode.classList.add(\"aftershow\");\n\n  return modalnode;\n}\n\nfunction hideModalDialog(ev) {\n  const dialognode = document.querySelector(\".dialog__modal\");\n  if (!dialognode)\n    return;\n\n  if (ev) {\n    if (ev.type === 'keydown' && ev.keyCode !== 27)\n      return;\n    if (ev.type === 'click' && ev.target !== dialognode && !ev.target.classList.contains(\"close\"))\n      return;\n  }\n\n  document.body.removeEventListener('keydown', hideModalDialog);\n  dialognode.removeEventListener('click', hideModalDialog);\n  document.body.removeChild(dialognode);\n}\n\nexport { showModalDialog, hideModalDialog };\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/webdesigns/ws2016/src/shared/dialog/dialog.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_base\",\"nl\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accepteer\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"Om deze functionaliteit te gebruiken:\",\"no\":\"Nee\",\"yes\":\"Ja\"}}});\nregisterTexts(\"utwente_base\",\"en\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\nregisterTexts(\"utwente_base\",\"de\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"akzeptieren\",\"cookies-cookies\":\"Cookies\",\"cookies-touse\":\"Zur Nutzung dieser Funktion:\",\"no\":\"Nein\",\"yes\":\"Ja\"}}});\nregisterTexts(\"utwente_base\",\"es\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\nregisterTexts(\"utwente_base\",\"it\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\nregisterTexts(\"utwente_base\",\"xt\",{\"site-common\":{\"texts\":{\"cookies-accept\":\"Accept\",\"cookies-cookies\":\"cookies\",\"cookies-touse\":\"To use this functionality you first need to:\",\"no\":\"No\",\"yes\":\"Yes\"}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/it.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/xt.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/language/default.xml\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./news.scss\";\nimport * as dompack from \"dompack\";\nimport { relayoutWidgets } from \"../layout\";\n\nfunction renderNews(node, items) {\n  if (items.length === 0) {\n    dompack.remove(node); //Just remove widget if no news\n    return;\n  }\n\n  const photosnode = dompack.qS(node, \".widget-ws2016news__photo\");\n  const listnode = dompack.qS(node, \".widget__list\");\n  items.forEach((item, i) => {\n    const link = node.dataset.baseurl ? node.dataset.baseurl + item.suburl : item.url;\n\n    if (i === 0 && photosnode) {\n      if (item.photolink) {\n        photosnode.setAttribute(\"href\", link);\n        photosnode.style.backgroundImage = \"url(\" + item.photolink + \")\";\n        photosnode.setAttribute(\"role\", item.photoalt ? \"image\" : \"presentation\");\n        if (item.photoalt)\n          photosnode.setAttribute(\"aria-label\", item.photoalt);\n      } else\n        dompack.remove(photosnode);//If no picture, remove photo node\n    }\n\n    listnode.appendChild(<a href={link} class=\"widget__listitem widget__listitem--link\">\n      <span class=\"widget__listitem-icon widget__listitem-icon--small UT-icon-UT_icon_52_arrow-right-round-16px\" />\n      <span class=\"widget__listitem-text\">{item.title}</span>\n    </a>);\n  });\n\n  //Trigger ut masonry update\n  relayoutWidgets(node);\n}\n\nasync function getNewsItems(node) {\n  const response = await fetch(node.dataset.publocfile);\n  if (response && response.status === 200) {\n    const items = await response.json();\n    if (items && items[\"p\" + node.dataset.publoc])\n      renderNews(node, items[\"p\" + node.dataset.publoc].items);\n    else\n      dompack.remove(node); //Just remove widget if no news\n  }\n}\n\ndompack.register(\".widget-ws2016news\", node => {\n  void getNewsItems(node);\n});\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./quote.scss\";\nimport * as dompack from \"dompack\";\nimport { renderPrettyPhoneNumber } from '@mod-utwente_design/js/ut-formatting';\nimport { relayoutWidgets } from \"../layout\";\n\nfunction showDetails(container, timer) {\n  container.style.maxHeight = \"0\";\n  container.classList.add(\"opendetails\");\n  container.style.maxHeight = container.children[0].clientHeight + \"px\";\n  return setTimeout(() => {\n    container.style.maxHeight = \"\";\n  }, 200); //Should be same as duration set in css\n}\n\nfunction hideDetails(container) {\n  container.style.maxHeight = container.children[0].clientHeight + \"px\";\n  void (container.clientHeight);//force css update\n  container.style.maxHeight = \"0\";\n  container.classList.remove(\"opendetails\");\n}\n\nlet __timer = null;\nfunction togglePersonalDetails(node) {\n  node.addEventListener(\"click\", ev => {\n    dompack.stop(ev);\n\n    const quoteswidget = node.closest(\".widget-quotes\");\n    if (quoteswidget) { //If inside multiple quotes widget, 3d - rotate for persondetails\n      ev.preventDefault();\n      quoteswidget.classList.toggle(\"showslidedetails\");\n\n      return;\n    }\n\n    //Inside embedded object, then use foldin/out\n    clearTimeout(__timer);\n    node.classList.toggle(\"opendetails\");\n    const widgetnode = node.closest(\".widget-quote\");\n    const foldcontainer = dompack.qS(widgetnode, \".widget-quote__persondetails\");\n    if (node.classList.contains(\"opendetails\"))\n      __timer = showDetails(foldcontainer, __timer);\n    else\n      hideDetails(foldcontainer);\n  });\n}\n\nclass EmbQuoteSlides {\n  constructor(wrapper) {\n    this.items = dompack.qSA(wrapper, \".widget-quote\");\n    this.idx = 0;\n\n    wrapper.parentNode.appendChild(<div class={\"embeddedobject-quotes__nav\" + (dompack.qS(wrapper, \".widget-quote--withphoto\") ? \" embeddedobject-quotes__nav--spaceleft\" : \"\")}>\n      {this.items.map((_, i) => <button onClick={() => this.gotoSlide(i)} type=\"button\" class=\"embeddedobject-quotes__nav__button\" />)}\n    </div>);\n    this.btns = dompack.qSA(wrapper.parentNode, \".embeddedobject-quotes__nav__button\");\n\n    this.items[this.idx].classList.add(\"active\");\n    this.btns[this.idx].classList.add(\"active\");\n\n    this.timer = setTimeout(() => this.nextSlide(), 7000);\n\n    wrapper.addEventListener(\"mouseover\", () => clearTimeout(this.timer));\n    wrapper.addEventListener(\"mouseout\", () => {\n      clearTimeout(this.timer);\n      this.timer = setTimeout(() => this.nextSlide(), 7000);\n    });\n  }\n\n  nextSlide() {\n    this.gotoSlide(this.idx + 1);\n    this.timer = setTimeout(() => this.nextSlide(), 7000);\n  }\n\n  gotoSlide(idx) {\n    if (idx < 0)\n      idx = this.items.length - 1;\n    else if (idx >= this.items.length)\n      idx = 0;\n\n    if (idx !== this.idx) {\n      clearTimeout(this.timer);\n\n      this.items[this.idx].classList.remove(\"active\");\n      this.btns[this.idx].classList.remove(\"active\");\n      this.idx = idx;\n      this.items[this.idx].classList.add(\"active\");\n      this.btns[this.idx].classList.add(\"active\");\n    }\n  }\n}\n\ndompack.register(\".embeddedobject-quotes__wrapper\", node => new EmbQuoteSlides(node));\n\nclass quotesSlideshow {\n  constructor(node) {\n    this.node = node;\n    this.node.addEventListener(\"click\", ev => this.onClick(ev));\n\n    this.items = dompack.qSA(node, \".widget-quotes__slide\");\n    window.addEventListener(\"load\", ev => this.setQuotesHeight());\n    document.fonts.ready.then(() => this.setQuotesHeight());\n    this.setQuotesHeight();\n\n    const itemcount = this.items.length;\n    if (itemcount <= 1)\n      return;\n\n    this.delay = 7000;//ms. delay between animations\n    this.duration = 1000;//ms. fade animation duration\n    this.idx = 0;\n\n    this.jmpbtns = [];\n    this.items.forEach((item, i) => {\n      item.style.transition = \"opacity \" + this.duration + \"ms\";\n\n      const frontnode = dompack.qS(item, \".widget-quote__front\");\n      const jmpbtns = <div class=\"widget-quotes__jumpbuttons\" />;\n      for (let c = 0; c < itemcount; ++c)\n        jmpbtns.appendChild(<span class={i === c ? \"active\" : \"\"} />);\n      frontnode.appendChild(jmpbtns);\n      this.jmpbtns.push(jmpbtns);\n    });\n\n    this.timer = setTimeout(() => this.nextSlide(), this.delay);\n\n    node.addEventListener(\"mouseover\", ev => {\n      clearTimeout(this.timer);\n    });\n    node.addEventListener(\"mouseout\", ev => {\n      clearTimeout(this.timer);\n      this.timer = setTimeout(() => this.nextSlide(), this.delay);\n    });\n  }\n\n  onClick(ev) {\n    const jmpbtn = ev.target.closest(\".widget-quotes__jumpbuttons > span\");\n    if (jmpbtn) {\n      for (let i = 0; i < this.jmpbtns[this.idx].children.length; ++i) {\n        if (this.jmpbtns[this.idx].children[i] === jmpbtn) {\n          this.gotoSlide(i);\n          break;\n        }\n      }\n    }\n  }\n\n  gotoSlide(idx) {\n    if (this.node.classList.contains(\"showslidedetails\"))\n      return;\n\n    const oldidx = this.idx;\n    this.idx = idx;\n    if (idx < 0)\n      this.idx = this.items.length - 1;\n    this.idx = this.idx % this.items.length;\n\n    if (this.idx === oldidx)\n      return;\n\n    clearTimeout(this.timer);\n\n    this.items.forEach(item => item.classList.remove(\"fadeout\"));//Make sure all other slides are in background\n\n    this.items[oldidx].classList.remove(\"active\");\n    this.items[oldidx].classList.add(\"fadeout\");\n    this.items[this.idx].classList.add(\"active\");\n\n    this.timer = setTimeout(() => this.nextSlide(), this.delay);\n  }\n\n  previousSlide() {\n    this.gotoSlide(this.idx - 1);\n  }\n\n  nextSlide() {\n    if (this.node.classList.contains(\"showslidedetails\")) {//just try next time\n      clearTimeout(this.timer);\n      this.timer = setTimeout(() => this.nextSlide(), this.delay);\n      return;\n    }\n\n    this.gotoSlide(this.idx + 1);\n  }\n\n  setQuotesHeight() { //set all quote widgets to height of largest widget\n    let minh = 0;\n\n    this.items.forEach(item => {\n      dompack.qSA(item, \".widget-quote__front, .widget-quote__persondetails__content\").forEach(panel => {//check front/backside\n        panel.style.minHeight = \"\";\n        const y = panel.clientHeight;\n        if (y > minh)\n          minh = y;\n      });\n    });\n\n    this.items.forEach(item => {\n      dompack.qSA(item, \".widget-quote__front, .widget-quote__persondetails__content\").forEach(panel => {//check front/backside\n        panel.style.minHeight = minh + \"px\";\n      });\n    });\n\n    this.node.style.height = minh + \"px\";\n\n    //Trigger ut masonry update\n    relayoutWidgets(this.node);\n  }\n}\n\ndompack.register(\".widget-quote a[href^='tel:'] > .value\", node => renderPrettyPhoneNumber(node));\ndompack.register(\".widget-quote__togglemore\", node => togglePersonalDetails(node));\ndompack.register(\".widget-quotes\", node => new quotesSlideshow(node));\n","import * as dompack from \"@webhare/dompack\";\n\nexport function renderPrettyPhoneNumber(node: HTMLElement) {\n  if (!node.textContent)\n    return;\n\n  const numbers = node.textContent.replace(/[^0-9]+/g, '');\n  const parts = numbers.split('53487');\n  if (parts.length === 2 && parts[1].length === 4) {\n    node.replaceChildren(<span class=\"prettyphonenumber\">+31 (0)53 487 <b>{parts[1]}</b></span>);\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport utwenteCookies from \"@mod-utwente_design/js/cookiebar\";\nimport * as dompack from \"dompack\";\n\nfunction setupPodcast(node) {\n  let params;\n  try {\n    params = JSON.parse(node.dataset.options);\n  } catch (e) { }\n\n  if (params && params.loadifconsent) {\n    if (utwenteCookies.getConsent()) {\n      startPodcast(node, params);\n    } else {\n      document.addEventListener(\"wh:consent-change\", ev => {\n        if (utwenteCookies.getConsent())\n          startPodcast(node, params);\n      });\n    }\n  }\n\n  node.addEventListener(\"click\", () => startPodcast(node, params));\n}\n\nfunction startPodcast(node, params) {\n  if (dompack.qS(node, \"iframe\"))\n    return;//already loaded\n\n  if (!params)\n    return;\n\n  const podcast_title = node.dataset.title ? node.dataset.title : \"\";\n  if (window.dataLayer)\n    window.dataLayer.push({\n      event: \"podcast_play\",\n      podcast_title\n    });\n\n  node.replaceChildren();\n\n  if (params.url && params.url.indexOf(\".transistor.fm/e/\") > -1)\n    startTransistor(node, params.url);\n  else\n    startSoundCloud(node, params);\n\n  node.parentNode.classList.add(\"widget-soundcloud--loaded\");\n}\n\nfunction startTransistor(node, url) {\n  node.appendChild(<iframe allow=\"autoplay\"\n    src={url}\n    width=\"100%\"\n    height=\"100%\"\n    frameborder=\"0\"\n    scrolling=\"no\"\n    seamless=\"true\"\n    allowtransparency=\"true\" />);\n}\n\nfunction startSoundCloud(node, params) {\n  const urlparts = [];\n  const paramnames = Object.keys(params);\n  for (const name of paramnames)\n    urlparts.push(name + \"=\" + escape(params[name]));\n\n  node.appendChild(<iframe allow=\"autoplay\"\n    src={\"https://w.soundcloud.com/player/?\" + urlparts.join(\"&amp;\")}\n    width=\"100%\"\n    height=\"100%\"\n    frameborder=\"0\"\n    scrolling=\"no\"\n    seamless=\"true\"\n    allowtransparency=\"true\" />);\n}\n\ndompack.register(\".widget-soundcloud__wrapper[data-options]\", node => setupPodcast(node));\n","import \"./tablewithtabs.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { foldableContent } from '@mod-utwente_design/js/foldablecontent';\nimport { pushToDataLayer } from \"@webhare/frontend\";\n\n//NOTE we get attached to both the .wh-details[data-main-item] and .wh-details[data-sub-item]\nclass TimelineTableContent extends foldableContent {\n  override sendToggleEvent(params: { isopen: boolean }): void { //subclasses can override us\n    const table_with_timeline_title = this.node.closest<HTMLElement>('[data-widget-title]')?.dataset.widgetTitle ?? \"\";\n    const table_with_timeline_main_item = this.node.closest<HTMLElement>('[data-main-item]')?.dataset.mainItem ?? \"\";\n    const table_with_timeline_sub_item = this.node.dataset.subItem ?? \"\";\n\n    if (params.isopen)\n      pushToDataLayer({ event: \"table_with_timeline_click\", table_with_timeline_main_item, table_with_timeline_sub_item, table_with_timeline_title });\n  }\n}\n\ndompack.register(\".embeddedobject-tablewithtabs .wh-details\", node => {\n  new TimelineTableContent(node);\n});\n","import \"./foldablecontent.scss\";\nimport * as dompack from '@webhare/dompack';\nimport * as domevents from \"dompack/src/events\";\nimport { pushToDataLayer } from \"@webhare/frontend/src/gtm\";\n\n// Note: custom foldin/out animation not possible with details element\n//  if you want animated foldin/out, details/summary elements should be replace with div's\n\ninterface FoldableContentOptions {\n  duration: number;\n  gtmevent: string;\n}\n\nexport class foldableContent {\n  node;\n  containernode;\n  summarynode;\n  options: FoldableContentOptions;\n  _timer: NodeJS.Timeout | undefined;\n\n  constructor(node: HTMLElement, options?: Partial<FoldableContentOptions>) {\n    this.options = {\n      duration: 200, //Animation duration in ms\n      gtmevent: \"\",\n      ...options\n    };\n\n    this.node = node;\n\n    this.containernode = this.node.querySelector(\".wh-details__container\")! as HTMLElement;\n    this.containernode.style.transition = \"height \" + this.options.duration + \"ms\";\n\n    this.summarynode = this.node.querySelector(\".wh-details__summary\")! as HTMLElement;\n    this.summarynode.addEventListener(\"click\", ev => this.toggleAnimatedDetails(ev));\n  }\n\n  toggleAnimatedDetails(ev: MouseEvent) {\n    if (ev) //prevent double triggering open/close\n      dompack.stop(ev);\n\n    const open = !this.node.classList.contains(\"wh-details--open\");\n\n    clearTimeout(this._timer);\n    this.containernode.style.height = this.containernode.clientHeight + \"px\";\n    void (this.containernode.clientHeight);//force css update\n\n    this.containernode.style.height = (open ? this.containernode.children[0].clientHeight : 0) + \"px\";\n\n    this.node.classList.toggle(\"wh-details--open\", open);\n\n    this.sendToggleEvent({ isopen: open });\n\n    this._timer = setTimeout(() => {\n      this.containernode.style.height = \"\";\n    }, this.options.duration);\n  }\n\n  sendToggleEvent(params: { isopen: boolean }): void { //subclasses can override us\n    if (this.options?.gtmevent && params.isopen) {\n      if (this.options.gtmevent === \"accordion\")\n        pushToDataLayer({ event: \"accordion-klik\", \"accordioncontent\": this.summarynode.textContent || '' });\n      else\n        pushToDataLayer({ event: \"faq-klik\", \"faqcontent\": this.summarynode.textContent || '' });\n    }\n  }\n}\n\nfunction findDetailsHash() {\n  const hash = location.hash.substr(1);\n  if (hash)\n    openCollapsableContainerFor(hash);\n}\n\nfunction openCollapsableContainerFor(hash: string) {\n  // return;\n  const target = document.getElementById(hash);\n  if (target) {\n    let detailsnode = (target.parentNode as HTMLElement)?.closest?.(\"details,.wh-details\");\n    while (detailsnode) { // check of if is subset inside tree. Also open parents\n      if (detailsnode.nodeName === \"DETAILS\")\n        detailsnode.setAttribute(\"open\", \"\");\n      detailsnode.classList.add(\"wh-details--open\");\n      detailsnode = (detailsnode.parentNode as HTMLElement)?.closest(\"details,.wh-details\");\n    }\n  }\n}\n\nexport function setDetailsEvents() {\n  if (location.hash.length > 1)\n    findDetailsHash();\n\n  if (dompack.qS(\"details\") || dompack.qS(\".wh-details\")) {\n    window.addEventListener(\"hashchange\", ev => findDetailsHash());\n\n    //Accessibility for foldablecontent\n    window.addEventListener(\"keydown\", ev => {\n      if (ev.keyCode === 13) {\n        const node = (ev.target as HTMLElement)?.closest(\".wh-details__summary\");\n\n        // If the toggle isn't a button handle the keyboard interaction ourselves\n        if (node && node.tagName !== \"BUTTON\")\n          domevents.fireHTMLEvent(node, 'click');\n      }\n    });\n  }\n}\n\ndompack.register(\"details[data-gtmevent]\", init);\n\nfunction init(node: HTMLDetailsElement) {\n  node.addEventListener(\"toggle\", (e: Event) => onToggleDetails(e as ToggleEvent));\n}\n\nfunction onToggleDetails(evt: ToggleEvent) {\n  const target = evt.target as HTMLDetailsElement;\n\n  const isOpen = target.open;\n  if (!isOpen)\n    return;\n\n  const gtmevent = target.getAttribute(\"data-gtmevent\");\n  const summaryNode = target.querySelector(\"summary\");\n  if (!summaryNode)\n    return;\n\n  const summaryText = summaryNode.textContent;\n  if (gtmevent === \"accordion\")\n    pushToDataLayer({ event: \"accordion-klik\", \"accordioncontent\": summaryText || '' });\n  else\n    pushToDataLayer({ event: \"faq-klik\", \"faqcontent\": summaryText || '' });\n}\n\ndompack.onDomReady(setDetailsEvents);\n","import \"./video.scss\";\nimport * as dompack from \"dompack\";\n\n/*\nPlaybuttons\n\n- Publisher video widget\n  .wh-video .wh-video__playbutton\n\n- Slideshow widget\n  .carrousel__cell__playbutton\n*/\n\ndompack.register(\".wh-video .wh-video__playbutton, .carrousel__cell__playbutton\", node => fixVideoPlayButton(node));\n\nfunction fixVideoPlayButton(playbutton: HTMLElement) {\n  playbutton.classList.add(\"UT-icon-UT_icon_82_play-16px\");\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport Carrousel from \"@webhare/dompack-carrousel\";\nimport * as videotools from \"../../../components/video\";\nimport \"./carrousel-shared.css\";\nimport \"./carrousel.scss\";\n\nlet whitespace;\nconst carrouselwidgets = [];\n\nwindow.carrouselwidgets = carrouselwidgets;\n\n//window.videotools = videotools;\n\nfunction getContentBlank(widgetnode) {\n  let measure_element = widgetnode.previousElementSibling || widgetnode.nextElementSibling;\n  let computed;\n  let measureself;\n\n  // Due to JS reordering/grouping to support anchors in mobile, we might not have any content above or below us.\n  // In this case (ab)use the widget's node to measure paddings.\n  let removedFullwidthClass = false;\n  if (!measure_element) {\n    // use the widget itself to measure by temporary disabling the fullwidth\n    measureself = true;\n    measure_element = widgetnode;\n    removedFullwidthClass = widgetnode.classList.contains(\".main__contents--fullwidth\");\n    widgetnode.classList.remove(\".main__contents--fullwidth\");\n  }\n\n  computed = window.getComputedStyle(measure_element);\n  // NOTE: If this clientWidth isn't requested here, reading the properties of computed sometimes fails on IE11. Requesting\n  //       this clientWidth (the measure_element.offsetWidth may work too) forces the browser to get the proper computed\n  //       styles.\n  const fullwidth = (document.querySelector(\".main__contents,.page-content\") || document.querySelector(\".contentpart__main\")).clientWidth;\n\n  const rec =\n  {\n    spaceLeft: parseInt(computed.marginLeft, 10) + parseInt(computed.paddingLeft, 10),\n    spaceRight: parseInt(computed.marginRight, 10) + parseInt(computed.paddingRight, 10),\n    contentWidth: measure_element.offsetWidth - parseInt(computed.paddingLeft, 10) - parseInt(computed.paddingRight, 10),\n    fullwidth: fullwidth\n  };\n\n  rec.spaceRight = rec.fullwidth - rec.spaceLeft - rec.contentWidth;\n\n  if (measureself && removedFullwidthClass)\n    widgetnode.classList.add(\".main__contents--fullwidth\");\n\n  return rec;\n}\n\nfunction doPauseHeaderAnimation(evt) {\n  if( window.pauseHeaderAnimation )\n    window.pauseHeaderAnimation();\n}\nfunction doUnpauseHeaderAnimation(evt) {\n  if( window.unPauseHeaderAnimation )\n    window.unPauseHeaderAnimation();\n}\n\n\n\nfunction refreshAllCarousels() {\n  // console.info(\"refreshAllCarousels\");\n  //console.log(\"paddingLeft\", paddingLeft);\n\n  for (const widget of carrouselwidgets) {\n    const whitespace = getContentBlank(widget.node);\n\n    fixCarrouselWidgetMinHeight(widget);\n\n    const carrclass = widget.carrousel;\n    carrclass.setOptions({\n      paddingLeft: whitespace.spaceLeft,\n      paddingRight: whitespace.spaceRight\n    });\n    //ADDME: __refreshSlidesLayout doesn't exist? carrclass.__refreshSlidesLayout();\n    carrclass.refresh();\n  }\n}\n\nfunction remeasureSlides() {\n  //console.info(\"Carrousel widget, remeasuring slides, document state is \", document.readyState);\n\n  for (const widget of carrouselwidgets)\n    widget.carrousel.relayoutSlides();\n\n  refreshAllCarousels();\n}\n\n\n/** @short set a minwidth to stretch the carrousel widget to have enough\n           room below the carrousel images to have the navigation buttons\n           not overlap the images.\n*/\nfunction fixCarrouselWidgetMinHeight(widget) {\n  const carrclass = widget.carrousel;\n\n  const nextbutton = widget.node.querySelector(\".carrousel__next\");\n  if (!nextbutton || nextbutton.clientHeight == 0) {\n    widget.node.style.minHeight = \"\"; // no need to make room for the nav buttons\n    return;\n  }\n\n  // Use minheight to make sure there's enough room for the navigation buttons\n  const firstimage = carrclass.nodes.viewport.querySelector(\".carrousel__cell-image\");\n  if (firstimage) {\n    const carrouselrect = widget.node.getBoundingClientRect(); //carrclass.nodes.viewport.getBoundingClientRect();\n    const firstimagerect = firstimage.getBoundingClientRect();\n\n    const minheight = firstimagerect.bottom - carrouselrect.top + 60 + 20 + 20;\n    //console.log(\"Need at least\" + minheight + \"px\");\n    widget.node.style.minHeight = minheight + \"px\";\n  }\n}\n\nfunction doCheckForCarouselVideoTrigger(event) {\n  const widget = event.target.closest(\".carrouselwidget\");\n  if (!widget)\n    return;\n\n  const slidecontainer = event.target.closest(\".carrousel__cell\");\n  if (!slidecontainer)\n    return;\n\n  if (event.target.closest(\".carrousel__cell-playbutton\")) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    const videocontainer = slidecontainer.querySelector(\"[data-video]\");\n    if (videocontainer) {\n      slidecontainer.classList.add(\"active\");\n\n      if (videotools.isVideoNodeInitialized(videocontainer))\n        slidecontainer._wsVideoPlayer.play();\n      else\n        videotools.initializeVideoNode(videocontainer).then(player => slidecontainer._wsVideoPlayer = player);\n    }\n  } else if (event.target.closest(\".video-close\")) {\n    event.preventDefault();\n    event.stopPropagation();\n\n    slidecontainer.classList.remove(\"active\");\n    slidecontainer._wsVideoPlayer.pause();\n  }\n\n  const anchor = event.target.closest(\"a\");\n  if (anchor) {\n    // Get the X translation\n    const style = getComputedStyle(slidecontainer);\n    const transform = style.transform || style.webkitTransform || style.mozTransform;\n    let mat = transform.match(/^matrix3d\\((.+)\\)$/);\n    let xpos = -1;\n    if (mat)\n      xpos = parseFloat(mat[1].split(', ')[12]); // The 'tx' from matrix3d(a, b, 0, 0, c, d, 0, 0, 0, 0, 1, 0, tx, ty, 0, 1)\n    else {\n      mat = transform.match(/^matrix\\((.+)\\)$/);\n      if (mat)\n        xpos = parseFloat(mat[1].split(', ')[4]); // The 'tx' from matrix(a, b, c, d, tx, ty)\n    }\n\n    // Get he current slide width\n    const width = parseInt(style.width);\n\n    // Get the carrousel viewport width\n    let findwidget = carrouselwidgets.filter(carrwidget => carrwidget.node == widget);\n    findwidget = findwidget.length ? findwidget[0] : null;\n    const viewport = findwidget.carrousel.nodes.viewport.getBoundingClientRect();\n\n    // Go to the link if this slide is completely visible (or if it doesn't fit but is currently active)\n    if ((xpos >= 0 && (xpos + width) < viewport.width) || slidecontainer.classList.contains(\"carrousel__cell--aligned\"))\n      location.href = anchor.href;\n\n    event.preventDefault();\n    event.stopPropagation();\n  }\n}\n\nfunction doOnlyAllowSlideImageLinksOnActiveSlides(evt) {\n  // we only want to follow links in active slides... we could either\n  // 1. cancel when the click is fired directly after a drag action\n  // 2. handle the anchor upon a 'iscroll tap event' if needed and cancel normal click events (we chose this route because 'tap' is fired much quicker resulting in a more responsive UI)\n  evt.preventDefault();\n  return;\n  /*\n  let cell = evt.target.closest(\".carrousel__cell\");\n  if (!cell)\n    return;\n\n  // only block links on the slide's image\n  if (!evt.target.closest(\".carrousel__cell-image\"))\n    return;\n\n  if (!cell.classList.contains(\"carrousel__cell--aligned\"))\n    evt.preventDefault();\n  */\n}\n\n\n\ndompack.register(\".carrouselwidget\", (node, idx) => {\n  if (!idx)\n    whitespace = getContentBlank(node);\n\n  const carrousel =\n    new Carrousel(node, {\n      paddingLeft: whitespace.spaceLeft,\n      paddingRight: whitespace.spaceRight\n      //, contentWidth: whitespace.contentWidth\n    });\n\n  const widget =\n  {\n    node: node,\n    carrousel: carrousel,\n    islarge: node.classList.contains(\"carrouselwidget--large\")\n  };\n\n  carrouselwidgets.push(widget);\n\n  fixCarrouselWidgetMinHeight(widget);\n\n  // iScroll replacement for \"click\", for quick response and it won't be triggered during a drag/swipe\n  node.addEventListener(\"tap\", doCheckForCarouselVideoTrigger);\n\n  node.addEventListener(\"click\", doOnlyAllowSlideImageLinksOnActiveSlides);\n\n  //var vpnode = carrousel.nodes.viewport;\n  if (carrousel.iscroll) {\n    carrousel.iscroll.on(\"scrollStart\", () => doPauseHeaderAnimation(\"scrollStart\"));\n    //carrousel.iscroll.on(\"beforeScrollStart\", () => doPauseHeaderAnimation(\"beforeScrollStart\"));\n    //carrousel.iscroll.on(\"scrollCancel\",      () => doUnpauseHeaderAnimation(\"scrollCancel\"));\n    carrousel.iscroll.on(\"flick\", () => doUnpauseHeaderAnimation(\"flick\"));\n    carrousel.iscroll.on(\"scrollEnd\", () => doUnpauseHeaderAnimation(\"scrollEnd\"));\n  }\n\n  if (!idx) {\n    window.addEventListener(\"resize\", refreshAllCarousels);\n    window.__carrouselwidgets = carrouselwidgets;\n\n    document.addEventListener(\"DOMContentLoaded\", remeasureSlides); // may help, but at this time the event might already have fired\n    window.addEventListener(\"load\", remeasureSlides); // Fix/workaround Safari reporting the wrong height for the first slide\n  }\n}, { afterdomready: true });\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport { JustifiedImageGrid } from \"@webhare/dompack-justifiedcontentgrid\";\nimport * as fsslideshow from \"./fullscreen-slideshow\";\n\nimport \"../../../shared/hoversupport\";\nimport \"./photoalbum.css\";\n\n\nconst __photoalbum_grids = [];\n\n\n///////////////////////////////////////////////////////////////////////////////////\n//\n//  Photoalbum overview (justified image grid)\n//\n\nfunction refreshAllPhotoAlbums() {\n  for (const grid of __photoalbum_grids) {\n    const defaultoptions = getDefaultGridOptions(grid.container); // FIXME: is 'container' public?\n    grid.setOptions(defaultoptions);\n    grid.refresh();\n  }\n}\n\nfunction doCheckForImageSelection(evt) {\n  const item = evt.target.closest(\".photoalbumwidget__item\");\n  if (!item)\n    return;\n\n  //console.log(\"Item\", item);\n\n  const grid = evt.target.closest(\".photoalbumwidget\");\n  const instanceid = grid.getAttribute(\"data-instanceid\");\n  //console.log(\"Grid\", grid);\n\n  let items = grid.querySelectorAll(\".photoalbumwidget__item\");\n  //items = Array.prototype.slice.call(items); // convert [Object] to [Array]\n  items = Array.from(items);\n  //console.log(\"All items\", items);\n\n  //console.log(typeof items);\n\n  const itemidx = items.indexOf(item);\n  if (itemidx === -1)\n    return;\n\n  //console.log(\"Opening carrousel slideshow at #\"+itemidx);\n\n  const headeranim = document.querySelector(\".header__universe\");\n  if (headeranim)\n    headeranim.style.display = \"none\";\n\n  fsslideshow.doActivateSlideshow(instanceid, itemidx);\n}\n\nfunction getDefaultGridOptions(node) {\n  //console.log(\"getDefaultGridOptions\", node);\n  let dpr = window.devicePixelRatio;\n  if (!dpr)\n    dpr = 1; // fallback for IE10\n\n  const contentWidth = node.clientWidth;\n\n  // WARNING: setting the row_height higher may cause some rows not to fit two images,\n  //          blowing up a single image to fill a row (which looks blurry)\n  const defaultoptions =\n  {\n    width: Math.round(contentWidth * dpr) / dpr,\n    row_height: Math.round(contentWidth / 2.75 * dpr) / dpr,\n    gutter_x: Math.round(contentWidth * dpr / 50) / dpr,\n    gutter_y: Math.round(contentWidth * dpr / 50) / dpr\n  };\n\n  return defaultoptions;\n}\n\n\n\ndompack.register(\".photoalbumwidget\", (node, idx) => {\n  const gridnode = node.querySelector(\".justifiedmediagrid\");\n\n  const defaultoptions = getDefaultGridOptions(gridnode);\n  const grid = new JustifiedImageGrid(gridnode, defaultoptions);\n\n  __photoalbum_grids.push(grid);\n\n  grid.refresh();\n\n  gridnode.addEventListener(\"click\", doCheckForImageSelection);\n\n  if (!idx) {\n    window.addEventListener(\"resize\", refreshAllPhotoAlbums);\n    window.addEventListener(\"load\", refreshAllPhotoAlbums);\n  }\n}, { afterdomready: true });\n","import * as dompack from \"dompack\";\nimport * as browser from 'dompack/extra/browser';\n\ndompack.onDomReady(() => {\n  const ios = browser.getPlatform() === \"ios\";\n  document.documentElement.classList.add(ios ? \"nohover\" : \"allowhover\");\n});\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./carrousel.scss\";\nimport \"./slideshow.scss\";\nimport * as dompack from \"dompack\";\n//import CarrouselSlideshow from \"@webhare/dompack-carrousel-slideshow\";\nimport CarrouselSlideshow from \"./dompack-carrousel-slideshow\";\nimport * as videotools from \"../../../components/video\";\n\n\nwindow.__widget_slideshow = [];\n\n\nclass SlideshowWidget {\n  constructor(widgetnode) {\n    this.widgetnode = widgetnode;\n\n    if (widgetnode.classList.contains(\"slideshowwidget--multipleslides\")) {\n      this.slideinfonodes = widgetnode.querySelectorAll(\".slideshowwidget__slideinfo\");\n\n      const btn_prev = widgetnode.querySelector(\".slideshowwidget__previousbutton\");\n      const btn_next = widgetnode.querySelector(\".slideshowwidget__nextbutton\");\n\n      // NOTE: Make sure we have a .carrousel__dragarea in the DOM to prevent\n      //       the whole widget triggering dragging of the slideshow.\n      this.slideshow =\n        new CarrouselSlideshow(this.widgetnode\n          , {\n            jumpbuttons: \".slideshowwidget__slidedot\",\n            jumpbutton_selectedclass: \"slideshow--activedot\",\n            autoplay: true,\n            eventPassthrough: true,\n            buttonprevious: btn_prev,\n            buttonnext: btn_next,\n            transitionDuration: 500 // see config.scss for $slideshow-duration\n          });\n\n      // Pause the slideshow when hovering over it, completely stop it when clicking one of the buttons\n      this.widgetnode.addEventListener(\"mouseenter\", () => this.pauseSlideshow());\n      this.widgetnode.addEventListener(\"mouseleave\", () => this.resumeSlideshow());\n      btn_prev.addEventListener(\"click\", () => this.stopSlideshow());\n      btn_next.addEventListener(\"click\", () => this.stopSlideshow());\n\n      window.__widget_slideshow.push(\n        {\n          node: widgetnode,\n          widget: this,\n          slideshow: this.slideshow\n        });\n\n      widgetnode.addEventListener(\"wh:activeslidechange\", evt => this.onSlideChange(evt));\n\n      // iScroll replacement for \"click\", for quick response and it won't be triggered during a drag/swipe\n      widgetnode.addEventListener(\"tap\", evt => this.doCheckForSlideshowVideoTrigger(evt));\n    } else {\n      widgetnode.addEventListener(\"click\", evt => this.doCheckForSlideshowVideoTrigger(evt));\n    }\n  }\n\n  onSlideChange(evt) {\n    //console.log(\"onSlideChange\", evt);\n\n    this.slideinfonodes[evt.detail.previousactiveidx].classList.remove(\"active\");\n    this.slideinfonodes[evt.detail.nextactiveidx].classList.add(\"active\");\n\n    if (evt.detail.previousactivenode)\n      this.deactivateSlide(evt.detail.previousactivenode);\n  }\n\n  pauseSlideshow() {\n    if (!this.deactivated) {\n      this.slideshow.scrolling = false; // FIXME: a tap should cancel scrolling state within the slideshow code itself\n      this.slideshow.pause();\n      this.widgetnode.classList.add(\"slideshow--paused\");\n    }\n  }\n\n  resumeSlideshow() {\n    if (!this.deactivated) {\n      this.slideshow.play();\n      this.widgetnode.classList.remove(\"slideshow--paused\");\n    }\n  }\n\n  stopSlideshow() {\n    this.slideshow.scrolling = false; // FIXME: a tap should cancel scrolling state within the slideshow code itself\n    this.slideshow.pause();\n    this.deactivated = true;\n    this.widgetnode.classList.remove(\"slideshow--paused\");\n  }\n\n  stopVideoSlide(slidecontainer) {\n    console.log(\"stopCarrouselVideo\", slidecontainer);\n\n    this.passBlockPointerEvents(false);\n\n\n    //slidecontainer.classList.remove(\"carrousel__cell--active\");\n    try {\n      if (slidecontainer._wsVideoPlayer)\n        slidecontainer._wsVideoPlayer.pause();\n    } catch (err) // happens if the YouTube API isn't running on https\n    {\n      /*\n      let frame = slidecontainer.querySelector(\"iframe\");\n      if (frame)\n      {\n        slidecontainer._wsVideoFrame = frame;\n        frame.parentNode.removeChild(frame);\n      }\n      */\n    }\n\n    if (this.slideshow)\n      this.slideshow.play();\n  }\n\n\n  deactivateSlide(slidenode) {\n    if (slidenode._wsVideoPlayer)\n      this.stopVideoSlide(slidenode);\n\n    this.widgetnode.classList.remove(\"slideshowwidget--videoplaying\");\n\n    slidenode.classList.remove(\"active\");\n  }\n\n\n  passBlockPointerEvents(pass) {\n    if (this.slideshow)\n      this.slideshow.carrousel.iscroll.options.preventDefault = !pass;\n  }\n\n\n  doCheckForSlideshowVideoTrigger(event) {\n    const widget = event.target.closest(\".slideshowwidget\");\n    if (!widget)\n      return;\n\n    const slidecontainer = event.target.closest(\".carrousel__cell\");\n    if (!slidecontainer)\n      return;\n\n    const videocontainer = slidecontainer.querySelector(\"[data-video]\");\n    if (!videocontainer)\n      return;\n\n    //If playing video, set slideshow over deeplinks\n    this.widgetnode.classList.add(\"main__contents--overdeeplinks\");\n\n    if (event.target.closest(\".video-close\")) {\n      event.preventDefault();\n      event.stopPropagation();\n      this.deactivateSlide(slidecontainer);\n    } else {\n      event.preventDefault();\n      event.stopPropagation();\n\n      slidecontainer.classList.add(\"active\");\n\n      if (videotools.isVideoNodeInitialized(videocontainer)) {\n        this.widgetnode.classList.add(\"slideshowwidget--videoplaying\");\n\n        if (this.slideshow) {\n          this.slideshow.scrolling = false; // FIXME: a tap should cancel scrolling state within the slideshow code itself\n          this.slideshow.pause();\n        }\n\n        this.passBlockPointerEvents(true); // Allow interaction with the video and it's controls\n        slidecontainer._wsVideoPlayer.play();\n      } else\n        videotools.initializeVideoNode(videocontainer).then(player => {\n          this.passBlockPointerEvents(true); // Allow interaction with the video and it's controls\n          this.widgetnode.classList.add(\"slideshowwidget--videoplaying\");\n\n          if (this.slideshow) {\n            this.slideshow.scrolling = false; // FIXME: a tap should cancel scrolling state within the slideshow code itself\n            this.slideshow.pause();\n          }\n\n          slidecontainer._wsVideoPlayer = player;\n        });\n    }\n  }\n}\n\n\ndompack.register(\".slideshowwidget\",\n  widgetnode => new SlideshowWidget(widgetnode)\n);\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport Carrousel from \"@webhare/dompack-carrousel\";\n\n\nwindow.__dompack_cslideshow_idx = 0;\nwindow.__dompack_cslideshows = [];\n\n\n\nlet __observer;\nif (window.IntersectionObserver)\n  __observer = new IntersectionObserver(checkSlideshowVisibility);\n\ndocument.addEventListener(\"visibilitychange\", onDocumentVisibilityChange);\n\n\nfunction onDocumentVisibilityChange() {\n  for (const slideshow of window.__dompack_cslideshows)\n    slideshow.__handleVisibilityChange();\n}\n\nfunction checkSlideshowVisibility(entries, observer) {\n  //console.log(\"checkSlideshowVisibility\");\n  //console.info(entries);\n\n  const visible = [];\n  const invisible = [];\n  for (const entry of entries) {\n    if (entry.isIntersecting)\n      visible.push(entry.target);\n    else\n      invisible.push(entry.target);\n  }\n\n  for (const slideshow of window.__dompack_cslideshows) {\n    const isvisible = visible.indexOf(slideshow.node) > -1;\n    if (!isvisible && invisible.indexOf(slideshow.node) === -1)\n      continue; //node should be at least in one of the lists, else ignore.\n\n    slideshow.inviewport = isvisible;\n    slideshow.__handleVisibilityChange();\n  }\n}\n\n\n\n\nexport default class CarrouselSlideshow {\n  constructor(node, options) {\n    if (!node) {\n      console.error(\"CarrouselSlideshow got null as node.\");\n      return;\n    }\n\n    window.__dompack_cslideshow_idx++; // used for anonymous this.option.name\n    window.__dompack_cslideshows.push(this);\n\n    const domoptions = dompack.getJSONAttribute(node, \"data-carrousel-options\");\n\n    this.node = node;\n    this.inviewport = this.__determineInViewport(node);\n    this.lastautoslidetime = null;\n    this.scrolling = false;\n    this.ignore_scroll = false; // ignore_scroll caused by our own resizes/relayouts\n\n    this.options = {\n      autoplay: true,\n      autoplay_initialdelay: 0,       // delay the first start of autoplay to prevent having a lot of slideshows run in sync\n      autoplay_freezeslideduration: 6000, // how long to keep the slide still (FIXME: should be after the transition) before going to the next\n      //, autoplay_staypausedfor        // amount of time to keep frozen after a mouseover\n      transitionDuration: 1500,\n\n      eventPassthrough: true,    // makes vertical scrolling keep on working (however at the moment it can cause textual selections)\n      updateviewportheight: false,\n\n      jumpbuttons: \".carrousel__jumpbutton\", // FIXME\n      jumpbutton_selectedclass: \"active\", // FIXME\n      buttonprevious: null,\n      buttonnext: null,\n      debug: false,\n      autoresize: true,\n      name: \"slideshow\" + window.__dompack_cslideshow_idx, ...domoptions, ...options\n    };\n\n    if (this.options.debug)\n      console.log(\"CarrouselSlideshow options\", this.options);\n\n    this.autoplaytimer = null;\n    this.playing = this.options.autoplay;\n\n\n    const carrousel_options =\n    {\n      transitionDuration: this.options.transitionDuration,\n      eventPassthrough: this.options.eventPassthrough,\n      gap: 0,\n      updateviewportheight: this.options.updateviewportheight\n    };\n\n    if (\"items\" in this.options)\n      carrousel_options.items = this.options.items;\n\n    if (this.options.debug)\n      console.info(\"Carrousel options\", carrousel_options);\n\n    this.carrousel = new Carrousel(node, carrousel_options);\n\n\n\n    const dragarea = this.carrousel.nodes.dragarea;\n\n    // For Firefox we need to cancel dragstart (otherwise <A> will be draggable)\n    dragarea.addEventListener(\"dragstart\", evt => this.doHandleDragStart(evt));\n\n    // We have cancel clicks and rely on iScroll's tap event,\n    // because clicks can be fired after scrolling.\n    dragarea.addEventListener(\"click\", evt => this.doHandleLinkClick(evt));\n    dragarea.addEventListener(\"tap\", evt => this.doHandleLinkTap(evt));\n\n\n\n    this.jumpbuttonnodes = [];\n    if (typeof this.options.jumpbuttons === \"string\")\n      this.jumpbuttonnodes = this.node.querySelectorAll(this.options.jumpbuttons);\n    else\n      this.jumpbuttonnodes = this.options.jumpbuttons; // assume an array, live nodelist or static nodelist\n\n    // ADDME: use tap if in carrousel viewport or click if outside\n    for (let idx = 0; idx < this.jumpbuttonnodes.length; idx++) {\n      // outside an iScroll container\n      this.jumpbuttonnodes[idx].addEventListener(\"click\", evt => this.__doJumpToSlide(idx, evt));\n\n      // when within an iScroll container\n      this.jumpbuttonnodes[idx].addEventListener(\"tap\", evt => this.__doJumpToSlide(idx, evt));\n    }\n\n    if (this.options.buttonprevious)\n      this.options.buttonprevious.addEventListener(\"click\", this.__handlePrevButton.bind(this));\n\n    if (this.options.buttonnext)\n      this.options.buttonnext.addEventListener(\"click\", this.__handleNextButton.bind(this));\n\n    /*\n    // iScroll replacement for \"click\", for quick response and it won't be triggered during a drag/swipe\n    node.addEventListener(\"tap\", doCheckForCarouselVideoTrigger);\n\n    node.addEventListener(\"click\", doOnlyAllowSlideImageLinksOnActiveSlides)\n    */\n\n    this.node.addEventListener(\"wh:activeslidechange\", this.onSlideChange.bind(this));\n\n    // Prevent autoplay overriding user-actions AND the autoscroll to a new slide\n    // (such as dragging, flicking, keyboard navigation etc...)\n    if (this.carrousel.iscroll) {\n      this.carrousel.iscroll.on(\"scrollStart\", this.__onScrollStart.bind(this));\n      this.carrousel.iscroll.on(\"scrollEnd\", this.__onScrollEnd.bind(this));\n    }\n\n    if (this.options.autoresize) {\n      if (this.options.debug)\n        console.info(\"AUTORESIZE enabled\");\n\n      this.bindedrefresh = this.relayoutSlides.bind(this);\n      window.addEventListener(\"resize\", this.bindedrefresh);\n      document.addEventListener(\"DOMContentLoaded\", this.bindedrefresh); // may help, but at this time the event might already have fired\n      window.addEventListener(\"load\", this.bindedrefresh); // Fix/workaround Safari reporting the wrong height for the first slide\n    }\n\n    if (__observer)\n      __observer.observe(node);\n\n    if (this.playing)\n      this.__applyCurrentAutoplay(this.options.autoplay_initialdelay);\n  }\n\n\n\n  doHandleDragStart(evt) {\n    // dragging stuff from inside a slideshow doesn't seem like a good thing to do\n    evt.preventDefault();\n  }\n\n  // Cancel the default browser click event, because it may fire during or after dragging using iScroll\n  doHandleLinkClick(evt) {\n    const anchor = evt.target.closest(\"a\");\n    if (!anchor)\n      return;\n\n    evt.preventDefault();\n  }\n\n  // When iScroll reports it was a tap (not a drag action) we can safely trigger the anchor\n  doHandleLinkTap(evt) {\n    // Are we in a link?\n    const anchor = evt.target.closest(\"a\");\n    if (!anchor)\n      return;\n\n    window.open(anchor.href, \"_blank\");\n  }\n\n\n  destroy() {\n    clearTimeout(this.autoplaytimer);\n    this.autoplaytimer = null;\n    this.playing = false;\n\n    if (this.bindedrefresh) {\n      window.removeEventListener(\"resize\", this.bindedrefresh);\n      document.removeEventListener(\"DOMContentLoaded\", this.bindedrefresh);\n      window.removeEventListener(\"load\", this.bindedrefresh);\n    }\n\n    this.carrousel.destroy();\n  }\n\n  __determineInViewport(node) {\n    const viewport = document.body.getBoundingClientRect();\n    const viewportheight = viewport.height;\n    const slideshowbounds = node.getBoundingClientRect();\n    return slideshowbounds.bottom >= 0 || slideshowbounds.top <= viewportheight;\n  }\n\n  __handlePrevButton() {\n    this.carrousel.previousSlide();\n  }\n\n  __handleNextButton() {\n    this.carrousel.nextSlide();\n  }\n\n  relayoutSlides() {\n    if (this.options.debug)\n      console.info(\"relayoutSlides\");\n\n    this.ignore_scroll = true;\n    this.carrousel.relayoutSlides();\n    this.carrousel.refresh();\n    this.ignore_scroll = false;\n  }\n\n\n  pause() {\n    this.playing = false;\n    this.__applyCurrentAutoplay();\n  }\n\n  play() {\n    this.playing = true;\n    this.__applyCurrentAutoplay();\n  }\n\n\n  refresh() {\n    this.relayoutSlides();\n    /*\n        console.info(\"refresh\");\n        this.ignore_scroll = true;\n        this.carrousel.refresh();\n        this.ignore_scroll = false;\n    */\n  }\n\n  onSlideChange(evt) {\n    const count = this.jumpbuttonnodes.length;\n\n    if (count > evt.detail.previousactiveidx)\n      this.jumpbuttonnodes[evt.detail.previousactiveidx].classList.remove(this.options.jumpbutton_selectedclass);\n\n    if (count > evt.detail.nextactiveidx)\n      this.jumpbuttonnodes[evt.detail.nextactiveidx].classList.add(this.options.jumpbutton_selectedclass);\n  }\n\n  __handleVisibilityChange() {\n    if (this.options.debug) {\n      console.info(this.options.name,\n        \"Page visible: \", !document.hidden,\n        \"Slideshow in viewport\", this.inviewport\n      );\n    }\n\n    this.__applyCurrentAutoplay();\n  }\n\n  __onScrollStart(evt) {\n    if (this.ignore_scroll)\n      return;\n\n    this.scrolling = true;\n    //this.__pauseAutoplay();\n  }\n\n  __onScrollEnd(evt) {\n    if (this.ignore_scroll)\n      return;\n\n    this.scrolling = false;\n    /*\n        // don't unpause if the document is hidden\n        if (document.hidden)\n          return;\n\n        this.__unpauseAutoplay();\n    */\n  }\n\n  __doJumpToSlide(idx, evt) {\n    evt.preventDefault();\n\n    // FIXME: animation disabled, the carrousel should offer the ability to find the closes path to the image (forward or backwards) or the animation will look like crap\n    //this.carrousel.jumpToSlide(idx, true, true);\n    this.carrousel.jumpToSlide(idx);\n  }\n\n  __applyCurrentAutoplay(delay) {\n    if (this.options.debug)\n      console.log(\"__applyCurrentAutoplay\");\n\n    if (!delay)\n      delay = 0;\n\n    // During scrolling we must finish the scroll.\n    // After the scroll has finished this function will be called again to schedule a slide change if needed.\n    if (this.scrolling) {\n      if (this.options.debug)\n        console.log(\"Not scheduling or cancelling a slide during scrolling.\");\n      return;\n    }\n\n    //console.log(this.__nextSlideByTimer);\n    if (this.playing && !document.hidden && this.inviewport) {\n      if (!this.autoplaytimer) {\n        if (this.options.debug)\n          console.log(\"Setting new timer for auto slide\");\n\n        this.autoplaytimer = setTimeout(this.__nextSlideByTimer.bind(this), this.options.autoplay_freezeslideduration + delay);\n      } else if (this.options.debug)\n        console.log(\"Timer already running...\");\n    } else {\n      if (this.options.debug)\n        console.log(\"No autoplay\", { play: this.playing, dochidden: document.hidden, inviewport: this.inviewport });\n\n      if (this.autoplaytimer) {\n        clearTimeout(this.autoplaytimer);\n        this.autoplaytimer = null;\n      }\n    }\n  }\n\n  __nextSlideByTimer() {\n    if (!this.options.autoplay) // did a timer event still get through?\n      return;\n\n    this.lastautoslidetime = new Date().getTime();\n\n    this.carrousel.nextSlide();\n\n    this.autoplaytimer = setTimeout(this.__nextSlideByTimer.bind(this), this.options.autoplay_freezeslideduration);\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./progress.scss\";\nimport * as dompack from \"dompack\";\n\nlet activestep;\n\ndompack.register(\".embeddedobject--progress\", node => {\n  // don't restore the scroll position from before reloading the page,\n  // we want to explicitly jump to the current progress/step.\n  if (\"scrollRestoration\" in history)\n    history.scrollRestoration = 'manual'; // Chr46+, FF46+, SF. Not IE or Edge yet.\n\n  const builder = new URL(location.href);\n\n  const steptags = builder.searchParams.get(\"step\") || '';\n  const parts = steptags.split(\"/\");\n  const steptag = parts[0];\n  const stepstate = parts.length > 1 ? parts[1] : \"\";\n\n  const activeoptions_str = builder.searchParams.get(\"activesteps\");\n  let activeoptions = [];\n  if (activeoptions_str)\n    activeoptions = activeoptions_str.split(\",\");\n\n  const allsteps = Array.from(node.querySelectorAll(\".progress__item\"));\n\n  activestep = node.querySelector('[data-progresstag=\"' + steptag + '\"]');\n\n  const activestepidx = allsteps.indexOf(activestep);\n\n  // Mark all steps up till the active step as passed\n  for (let idx = 0; idx <= activestepidx; idx++) {\n    const currentstep = allsteps[idx];\n\n    if (idx < activestepidx)\n      currentstep.classList.add(\"progress__item--passed\");\n    else {\n      if (stepstate === \"passed\" || stepstate === \"\")\n        activestep.classList.add(\"progress__item--passed\");\n      else if (stepstate === \"conditional\")\n        activestep.classList.add(\"progress__item--conditional\");\n      else\n        activestep.classList.add(\"progress__item--failed\");\n\n      activestep.classList.add(\"progress__item--currentitem\");\n    }\n\n    const tag = currentstep.getAttribute(\"data-progresstag\");\n\n    if (activeoptions.indexOf(tag) > -1 || currentstep === activestep)\n      currentstep.classList.add(\"progress__item--active\"); // activate an optional step\n  }\n\n  // Expand the active step\n  // foldablecontent is initialized onload (so as the last thing to initialize)\n  // in /src/widgets/embeddedobjects.js ....\n  // This is a hack to open the panel without needing to wait to after onload\n  // (we need to seperate .add because IE doesn't handle adding multiple classes at once)\n  if (activestep) {\n    // !! don't add --active, it's used to indicate that the foldablecontent events have been initialized on the node\n    activestep.classList.add(\"foldablecontent--open\");\n    activestep.querySelector(\".foldablecontent__foldcontainer\").style.cssText = \"height:auto;overflow:inherit;\";\n\n    /*\n    The \"proper\" way of opening the panel.. But it works only after the window load event:\n\n    dompack.dispatchCustomEvent(activestep, \"ws:foldable-set\",\n          { bubbles: true\n          , cancelable: false\n          , detail: { open: true }\n          });\n    */\n  }\n});\n\n\nfunction jumpToActiveStep() {\n  if (activestep) {\n    const node = document.querySelector(\".embeddedobject--progress\");\n\n    // We scroll to the widget because ideally we want to see the whole\n    // progress up to where we are now (activestep).\n    node.scrollIntoView();\n\n    // If the viewport is too small to see both the top of the widget\n    // and the active step, whe'll need to scroll further to the active step.\n    if (activestep.scrollIntoViewIfNeeded) // Chrome & Safari\n      activestep.scrollIntoViewIfNeeded();\n    else\n      activestep.scrollIntoView(); // Firefox\n  }\n}\n\n\nwindow.addEventListener(\"DOMContentLoaded\", jumpToActiveStep);\n\nwindow.addEventListener(\"load\", function () {\n  jumpToActiveStep();\n\n  // For Edge which restores the position, but doesn't support history.scrollRestoration yet\n  if (!(\"scrollRestoration\" in history))\n    setTimeout(jumpToActiveStep, 100);\n});\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./timeline.scss\";\nimport \"./video-playbutton.scss\";\nimport * as dompack from \"dompack\";\nimport FilteredOverview from \"../../../filteredoverview\";\n\n// The updated masonry has some support for defining margins between different\n// types of content (headings, normal items, wide items)\n//import Masonry           from \"dompack-masonry\";\nimport Masonry from \"./dompack-masonry-update\";\n\nimport SmoothScroll from \"../../../components/smoothscroll\";\nimport * as videotools from \"../../../components/video\";\n\nwindow.__timelines = [];\n\nconst bookmark_offsety = document.documentElement.classList.contains(\"utwente--ws2026\") ? -120 : -60;\n\nclass TimelinePageFilter extends FilteredOverview {\n  constructor(options) {\n    super({ ...options, filterpagetype: 'timeline' });\n\n    this.itemscontainer = document.querySelector(\".timeline__items\");\n\n    const items = this.itemscontainer.querySelectorAll(\".timeline__item\");\n\n    // keep an internal list of all items AND\n    // generate the list view based on content of the normal view\n    this.items = [];\n    for (const node of items) {\n      this.items.push({\n        node: node,\n        data: JSON.parse(node.dataset.filterdata)\n      });\n    }\n\n    if (this.isFilterActive())\n      this.doFilter();\n  }\n\n\n  showResults() {\n    //let activefilters = Object.keys(this.filters).length;\n    let totalfound = 0;\n\n    const yearsinresults = []; // In which years are the visible items?\n\n    for (const item of this.items) {\n      let doesnotmatch = false;\n\n      for (const key in this.filters) {\n        if (!(key in item.data)) {\n          if (this.debug_search)\n            console.log(\"Cannot find search key '\" + key + \"'\");\n          continue;\n        }\n\n        const itemvalue = item.data[key];\n        const searchvalue = this.filters[key];\n\n        if (this.debug_search)\n          console.log(\"Looking for\", searchvalue, \"in\", itemvalue);\n\n        if (Array.isArray(searchvalue) && Array.isArray(itemvalue)) // Find multiple values in multiple values\n        {\n          for (let i = 0; i < searchvalue.length; ++i) {\n            let found = false;\n            if (itemvalue.indexOf(this.filters[key][i]) > -1) {\n              found = true;\n              break;\n            }\n\n            if (!found)\n              doesnotmatch = true;\n          }\n        } else if (Array.isArray(itemvalue)) {\n          // lookup single value (pulldown or text) in array\n          if (itemvalue.indexOf(this.filters[key]) === -1)\n            doesnotmatch = true;\n        } else {\n          // lookup single value (pulldown or text) in a non-array (number of string)\n          const matchvalue = (typeof itemvalue === \"number\" ? parseInt(this.filters[key]) : this.filters[key]);\n          if (itemvalue !== matchvalue)\n            doesnotmatch = true;\n        }\n      }\n\n      const ismatch = !doesnotmatch;\n\n      item.node.classList[ismatch ? \"remove\" : \"add\"](\"timeline__item--hide\");\n\n      if (ismatch) {\n        if (yearsinresults.indexOf(item.data.year) === -1)\n          yearsinresults.push(item.data.year);\n\n        ++totalfound;\n      }\n\n      if (this.debug_search)\n        console.groupEnd();\n    }\n\n    this.setFeedback(totalfound);\n\n    for (const tlwidget of window.__timelines) {\n      tlwidget.widgetnode.classList[totalfound === 0 ? \"add\" : \"remove\"](\"embeddedobject--timeline--noresults\");\n\n      tlwidget.yearsinresults = yearsinresults;\n      tlwidget.refreshYearBookmarks(); // content of some years might not be visible anymore\n\n      tlwidget.refresh();\n    }\n  }\n}\n\n\nclass TimelineWidget {\n  constructor(widgetnode) {\n    window.__timelines.push(this);\n\n    this.isFilterPage = widgetnode.classList.contains(\"timeline--timelinepage\"); // ws2026 has slighly different column width\n\n    this.widgetnode = widgetnode;\n    this.masonrynode = widgetnode.querySelector(\".timeline__items\");\n    this.masonry = null; // initialized on demand\n\n    this.preprocessItems();\n\n    window.addEventListener(\"load\", evt => this.refresh(evt));\n    window.addEventListener(\"resize\", evt => this.refresh(evt));\n    window.addEventListener(\"scroll\", evt => this.onScroll());\n\n    this.refresh();\n\n    if( dompack.qS(\".timeline--timelinepage\") ) {\n      this.createYearBookmarks();\n      this.refreshYearBookmarks();\n    }\n\n    widgetnode.addEventListener(\"click\", evt => this.doCheckForVideoTrigger(evt));\n\n    this.scroller = new SmoothScroll([]\n      , {\n        sethash: false,\n        offsety: bookmark_offsety\n      });\n  }\n\n  onScroll() {\n    this.refreshYearBookmarks();\n  }\n\n  preprocessItems() {\n    // keep an internal list of all items AND\n    // generate the list view based on content of the normal view\n    const items = this.widgetnode.querySelectorAll(\".timeline__item,.timeline__header,.timeline__break\");\n\n    this.items = [];\n\n    this.years = [];\n    this.yearsinresults = [];\n\n    for (const node of items) {\n      if (node.classList.contains(\"timeline__break\")) {\n        continue;\n      } else if (node.classList.contains(\"timeline__header\")) {\n        const year = parseInt(node.dataset.year);\n\n        this.years.push({\n          bookmarknode: null,\n          headernode: node,\n          year: year\n        });\n        this.yearsinresults.push(year);\n      } else {\n        this.items.push({\n          node: node,\n          data: JSON.parse(node.dataset.filterdata)\n        });\n      }\n    }\n\n    for (const itemnode of items) {\n      const labelnode = itemnode.nextElementSibling;\n\n      if (labelnode && labelnode.classList.contains(\"timeline__item__label\"))\n        itemnode.labelnode = labelnode;\n    }\n  }\n\n\n  onYearBookmarkClick(evt, year) {\n    evt.preventDefault();\n    evt.stopPropagation();\n\n    // find the first visible item for the given year\n    for (const item of this.items) {\n      if (item.data.year > year)\n        continue; // keep on looking\n\n      if (item.node.classList.contains(\"timeline__item--hide\"))\n        continue;\n\n      if ('scrollBehavior' in document.documentElement.style) {\n        const viewportrect = document.documentElement.getBoundingClientRect(); // document.scrollElement.\n        const itemrect = item.node.getBoundingClientRect();\n        const topy = itemrect.top - viewportrect.top + bookmark_offsety;\n        window.scrollTo({ behavior: \"smooth\", top: topy });\n      } else\n        this.scroller.scrollTo(item.node, evt);\n\n      return;\n    }\n  }\n\n\n  refresh(event) {\n    let options = {};\n\n\n    // Retrieve current settings from CSS /////////////////////////////////////////////////\n    const comp = window.getComputedStyle(this.masonrynode, '::before');\n    let layout = comp.content;\n\n    // remove the \" some browsers add (Safari doesn't add quotes)\n    if (layout !== \"\" && layout.substring(0, 1) === '\"')\n      layout = layout.substring(1, layout.length - 1); // remove the \"'s around the string\n\n    if (layout !== \"none\") {\n      const parts = layout.split(\":\");\n\n      options = {\n        columns: parseInt(parts[0]),\n        gutter_y: parseInt(parts[1]),\n        margin_header_top: parseInt(parts[2]),\n        margin_header_bottom: parseInt(parts[3])\n      };\n\n      if (parts.length > 3) {\n        // don't use masonrynode for measuring, the masonry will set the width when columnwidth is used.\n        if (options.columns > 1) {\n          /* ws2026, isFilterPage: horizontal line length 35px + 20px spacing between line and label */\n          options.columnwidth = this.isFilterPage ? (this.masonrynode.clientWidth * 0.5) - 55 : (this.masonrynode.clientWidth * 0.42);\n          options.gutter_x = this.masonrynode.clientWidth - options.columnwidth * options.columns / (options.columns - 1);\n        } else {\n          options.columnwidth = this.masonrynode.clientWidth;\n          options.gutter_x = 0;\n        }\n      } else\n        options.columnwidth = null;\n    } else {\n      // fallback values\n      options = {\n        columns: 2,\n        gutter_y: 50,\n        gutter_y_header: 35,\n        columnwidth: null\n      };\n    }\n    ////////////////////////////////////////////////////////////////////////////////////////\n\n\n    if (!this.masonry) {\n      this.masonry = new Masonry(this.masonrynode\n        , {\n          ...options,\n          items: \".timeline__item,.timeline__header\",\n          ignoreclass: \"timeline__item--hide\",\n          breakclass: \"timeline__header\"\n        });\n      this.masonry.refresh();\n    } else {\n      this.masonry.setOptions(options);\n      this.masonry.refresh();\n    }\n\n\n    this.repositionLabels();\n  }\n\n  repositionLabels() {\n    // Enhance the masonry rendering with indicator lines\n    const renderinfo = this.masonry.getLastRenderInfo();\n\n    for (let idx = 0; idx < renderinfo.items.length; idx++) {\n      const item = renderinfo.items[idx];\n\n      item.node.classList[item.col === 0 ? \"add\" : \"remove\"](\"timeline__content--leftside\");\n      item.node.classList[item.col !== 0 ? \"add\" : \"remove\"](\"timeline__content--rightside\");\n\n      if (item.node.labelnode) {\n        item.node.labelnode.classList[item.col === 0 ? \"add\" : \"remove\"](\"timeline__item__label--leftside\");\n        item.node.labelnode.classList[item.col !== 0 ? \"add\" : \"remove\"](\"timeline__item__label--rightside\");\n        item.node.labelnode.style.top = item.top + \"px\";\n      }\n    }\n  }\n\n\n  determineVisibleYears() {\n    const viewportrect = document.documentElement.getBoundingClientRect();\n\n    const visibleyears = [];\n\n    for (const item of this.items) {\n      if (visibleyears.indexOf(item.data.year) > -1)\n        continue; // skip we already have this year anyway\n\n      if (item.node.classList.contains(\"timeline__item--hide\"))\n        continue; // animating away or invisible\n\n      const itemrect = item.node.getBoundingClientRect();\n\n      if (itemrect.bottom > 0 && itemrect.top < viewportrect.height)\n        visibleyears.push(item.data.year);\n    }\n\n    return visibleyears;\n  }\n\n  createYearBookmarks() {\n    // The items should be ordered by date\n\n    // The positioning container for bookmarks\n    const bookmarkcontainer = document.createElement(\"div\");\n    bookmarkcontainer.className = \"timeline__bookmarks\";\n    this.bookmarkcontainer = bookmarkcontainer;\n\n    // Container to take content out of the flow\n    // (so it cannot push any content)\n    const bookmarkcontainer2 = document.createElement(\"div\");\n    bookmarkcontainer2.className = \"timeline__bookmarks__inner\";\n    this.bookmarkcontainer2 = bookmarkcontainer2;\n    this.bookmarkcontainer.appendChild(bookmarkcontainer2);\n\n    //let maincontentnode = document.getElementById(\"main\");\n    //maincontentnode.insertBefore(bookmarkcontainer, maincontentnode.firstChild);\n    this.widgetnode.insertBefore(bookmarkcontainer, this.widgetnode.firstChild);\n\n    for (const year of this.years) {\n      const bookmark = document.createElement(\"div\");\n      bookmark.className = \"timeline__bookmarks__item\";\n      bookmark.appendChild(document.createTextNode(year.year));\n      bookmark.addEventListener(\"click\", evt => this.onYearBookmarkClick(evt, year.year));\n      bookmarkcontainer2.appendChild(bookmark);\n\n      year.bookmarknode = bookmark;\n    }\n  }\n\n\n  refreshYearBookmarks() {\n    if (!this.bookmarkcontainer)\n      return;\n\n    const visibleyears = this.determineVisibleYears();\n    for (const year of this.years) {\n      if (this.yearsinresults.indexOf(year.year) === -1) {\n        year.bookmarknode.classList.add(\"timeline__bookmarks__item--hide\");\n        year.bookmarknode.classList.remove(\"timeline__bookmarks__item--inview\");\n        year.headernode.classList.add(\"timeline__item--hide\");\n      } else {\n        year.bookmarknode.classList.remove(\"timeline__bookmarks__item--hide\");\n        year.headernode.classList.remove(\"timeline__item--hide\");\n\n        const inview = visibleyears.indexOf(year.year) > -1;\n        year.bookmarknode.classList[inview ? \"add\" : \"remove\"](\"timeline__bookmarks__item--inview\");\n      }\n    }\n  }\n\n\n  doCheckForVideoTrigger(event) {\n    const itemnode = event.target.closest(\".timeline__item\");\n\n\n    // Did we click on the close video button?\n    if (event.target.closest(\".generic_videocontainer__closevideo\")) {\n      event.preventDefault();\n      event.stopPropagation();\n\n      if (itemnode._wsVideoPlayer) {\n        itemnode._wsVideoPlayer.pause();\n        itemnode.classList.remove(\"genericvideoplayeractive\");\n      }\n\n      return;\n    }\n\n\n    // Did we click on a video play button?\n    if (!event.target.closest(\".timeline__item__playbutton\"))\n      return; // no? nothing to do then.\n\n\n    const videocontainer = itemnode.querySelector(\"[data-video]\");\n    if (!videocontainer)\n      return;\n\n\n    event.preventDefault();\n    event.stopPropagation();\n\n    if (videotools.isVideoNodeInitialized(videocontainer)) {\n      itemnode.classList.add(\"genericvideoplayeractive\");\n      itemnode._wsVideoPlayer.play();\n    } else {\n      videotools.initializeVideoNode(videocontainer).then(player => {\n        itemnode.classList.add(\"genericvideoplayeractive\");\n        itemnode._wsVideoPlayer = player;\n      });\n    }\n  }\n}\n\n\ndompack.register(\".embeddedobject--timeline\", node => new TimelineWidget(node));\n\n\ndompack.onDomReady(() => {\n  // This filterclass is meant for the Timeline Page\n  if (!document.documentElement.classList.contains(\"page--timeline\"))\n    return;\n\n  window.filteredoverview = new TimelinePageFilter({ itemsselector: \".timeline__item\" });\n});\n","/* eslint-disable */\n/// @ts-nocheck -- Rename to enable TypeScript validation\n\nimport * as whintegration from \"@mod-system/js/wh/integration\";\nimport * as dompack from '@webhare/dompack';\nimport UTAutoComplete from '@mod-utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter';\nimport \"../site.lang.json\";\nimport { getTid } from \"@webhare/gettid\";\nimport JSONRPC from \"@mod-system/js/net/jsonrpc\";\nimport { SearchIndex } from \"./searchindex\";\nimport { debugFlags } from \"@webhare/env\";\nimport { pushToDataLayer } from \"@webhare/frontend\";\n\n/// fields for which we don't want to create a tag\nconst filtertags_ignorefields = [\"words\", \"query\"];\nconst filter_lastsettings: Filters = {};\nlet filter_lastseenkeys: string[] = [];\n\ntype ActiveFilterValue = {\n  name: string;\n  value: string | string[];\n  title: string | string[];\n};\n\n//Filters can be an array if they're a checkbox\ntype Filters = Record<string, string | string[]> & {\n  query?: string;\n};\n\ntype FilterItem = {\n  node: HTMLElement;\n  filterdata: Record<string, unknown> | null;\n  title: HTMLElement | null;\n  description: HTMLElement | null;\n};\n\ninterface FilteredOverviewHeaderOptions {\n  getResultsTeaserText?: typeof getResultsFeedbackText;\n  getResultsFeedbackText?: typeof getResultsFeedbackText;\n}\n\ninterface FilteredOverviewOptions extends FilteredOverviewHeaderOptions {\n  filterpagetype: string;\n  additionalform?: HTMLFormElement;\n}\n\n\n/** get default \"X results\" text. Also usefull to for pages with custom filtering\n *         or custom feedback bar to standardize on the same text as the Filtered Overview feedback bar.\n *  @param totalfound - amount of results\n *  @param totalshown - amount of results shown on the page\n *  @param allitemscount - amount of items there are without any filters active\n */\nexport function getResultsFeedbackText(totalfound: number, totalshown?: number) {\n  if (totalshown && totalshown < totalfound)\n    return getTid('utwente_base:frontend.ws2016.js.filteredoverview.feedbackbar-resultslimited', totalfound, totalshown);\n  else if (totalfound === 1)\n    return getTid('utwente_base:frontend.ws2016.js.filteredoverview.feedbackbar-result', totalfound);\n  else if (totalfound > 1)\n    return getTid('utwente_base:frontend.ws2016.js.filteredoverview.feedbackbar-results', totalfound);\n  else\n    return getTid(\"utwente_base:frontend.ws2016.js.filteredoverview.feedbackbar-noresults\");\n}\n\nexport function getResultsTeaserText(totalfound: number) {\n  if (totalfound === 1)\n    return getTid('utwente_base:frontend.ws2016.js.filteredoverview.tease-result', totalfound);\n  else if (totalfound > 1)\n    return getTid('utwente_base:frontend.ws2016.js.filteredoverview.tease-results', totalfound);\n  else\n    return getTid(\"utwente_base:frontend.ws2016.js.filteredoverview.tease-noresults\");\n}\n\n/** Basic filtered overview support for pages which already handle stuff themselves.\n\n    - Header toggle\n    - API for expanding/collapsing the header filters\n    - API to set 'X results' teaser for mobile screens\n*/\nexport class FilteredOverviewHeader {\n  debug = debugFlags[\"ut-filters\"];\n  form: HTMLFormElement;\n  resultscountnode: HTMLElement | null = null;\n  options: FilteredOverviewHeaderOptions;\n  resultscountcontainer: HTMLElement | null = null;\n\n  constructor(options: FilteredOverviewHeaderOptions) {\n    this.options = { ...options };\n    this.form = dompack.qR<HTMLFormElement>(\".filteredoverview__form\");\n\n    this.hideFiltersMaybe();\n\n\n    for (const node of document.body.querySelectorAll<HTMLElement>(\".filteredoverview__toggleaction\")) {\n      // NOTE: We use mouseup to fire before (and be able to prevent) focus\n      //       This way we can prevent the focus ring on mouse events, but keep it for keyboard navigation\n      node.addEventListener(\"mousedown\", evt => evt.preventDefault()); // prevent getting focus\n      node.addEventListener(\"mouseup\", () => this.toggleFiltersExpanded());\n      node.addEventListener(\"keydown\", evt => this.toggleFiltersExpandedIfEnter(evt));\n    }\n  }\n\n  /// Set whether the filters are expanded or collapsed\n  setFiltersExpanded(visible: boolean) {\n    document.documentElement.classList.toggle(\"showfilters\", visible);\n\n    const fieldnodes = this.form.querySelectorAll(\"input[name], select[name]\");\n\n    for (let idx = 0; idx < fieldnodes.length; idx++) {\n      if (visible)\n        fieldnodes[idx].removeAttribute(\"tabindex\");\n      else\n        fieldnodes[idx].setAttribute(\"tabindex\", \"-1\"); // disable ability to focus\n    }\n\n    this.checkNeedToShowTeaserBar();\n  }\n\n  toggleFiltersExpandedIfEnter(evt: KeyboardEvent) {\n    if (evt.key === \"Enter\")\n      this.toggleFiltersExpanded();\n  }\n\n  toggleFiltersExpanded() {\n    this.setFiltersExpanded(!document.documentElement.classList.contains(\"showfilters\"));\n  }\n\n  isFilterBarExpanded() {\n    return document.documentElement.classList.contains(\"showfilters\");\n  }\n\n\n  hideFiltersMaybe() {\n    if (this.debug)\n      console.log(\"[ut-filters] hideFiltersMaybe\");\n\n    // header filters not initialized through the normal route?\n    if (!whintegration.config.obj.filteredoverview) {\n      console.warn(\"No filteredoverview settings found.\");\n      return;\n    }\n\n    const expandwhen = whintegration.config.obj.filteredoverview.expandwhen;\n    if (this.debug)\n      console.log(\"[ut-filters] expandwhen\", expandwhen);\n\n    // NOTE: even though in the template we add the \"showfilters\" to the <html> node,\n    //       we must use setFiltersExpanded to correctly initialize behaviour (and disable/enable tabindex) of elements\n\n    switch (expandwhen) {\n      case \"openfirstvisit\":\n        {\n          if (!(\"whfsid\" in whintegration.config.obj.filteredoverview))\n            console.warn(\"Cannot determine expand state for filteredoverview, no filteredoverview.whfsid specified.\");\n          else {\n            const pagekey = \"pageseen\" + whintegration.config.obj.filteredoverview.whfsid;\n            const firstvisitinsession = !(pagekey in sessionStorage);\n\n            this.setFiltersExpanded(firstvisitinsession);\n\n            sessionStorage[pagekey] = \"true\"; // mark this page as seen for this session\n          }\n          break;\n        }\n      case \"alwaysopen\":\n        {\n          this.setFiltersExpanded(true); // explicitly to also update tabindex of hidden filters\n          break;\n        }\n      case \"defaultclosed\":\n        {\n          this.setFiltersExpanded(false); // explicitly to also update tabindex of hidden filters\n          break;\n        }\n    }\n  }\n\n  setTeaserResultCount(totalfound: number, totalshown: number) {\n    if (!this.resultscountnode)\n      this.__createResultsCountNode();\n\n    const gettextfunc = this.options.getResultsTeaserText ?? getResultsTeaserText;\n    this.resultscountnode!.textContent = gettextfunc(totalfound, totalshown);\n  }\n\n  __createResultsCountNode() {\n    const node = document.createElement(\"a\");\n    node.className = \"filteredoverview__teaser\";\n    node.href = \"#results\";\n\n    const contentnode = document.createElement(\"div\");\n    contentnode.className = \"filteredoverview__teaser__content\";\n    node.appendChild(contentnode);\n\n    //node.addEventListener(\"click\", this.scrollToResults());\n    //contentnode.addEventListener(\"click\", this.scrollToResults());\n\n    //contentnode.addEventListener(\"mousedown\", this.scrollToResults());\n\n    document.body.appendChild(node);\n\n    this.resultscountcontainer = node;\n    this.resultscountnode = contentnode;\n\n    window.addEventListener(\"resize\", () => this.checkNeedToShowTeaserBar());\n    document.addEventListener(\"scroll\", () => this.checkNeedToShowTeaserBar());\n    this.checkNeedToShowTeaserBar();\n  }\n\n  setHoveringFeedbackText(text: string) {\n    if (this.resultscountnode)\n      this.resultscountnode.textContent = text;\n  }\n\n\n  checkNeedToShowTeaserBar() {\n    if (!this.resultscountcontainer)\n      return;\n\n    const viewportheight = document.body.getBoundingClientRect().height;\n\n    const resultsanchor = document.querySelector('#results, a[name=\"results\"]');\n    if (!resultsanchor) {\n      if (this.debug)\n        console.warn(\"Missing results anchor\");\n      return;\n    }\n\n    const feedbackbartop = resultsanchor.getBoundingClientRect().top;\n    const results_out_of_view = feedbackbartop > viewportheight;\n\n    // The feedback bar also tells the amount of results AND it means whe're almost at the results.\n    // So if we reach the top of the feedback bar we can hide the teaser bar.\n    this.resultscountcontainer.classList.toggle(\"filteredoverview__teaser--aboveresults\", results_out_of_view);\n  }\n}\n\n\n\n/** - The class you make MUST use doFilter() or doFilterForce() to trigger a refresh\n    - The class you make may offer a showResults() which uses this.filters to change the content on the page\n*/\nexport default class FilteredOverview extends FilteredOverviewHeader {\n  filters: Filters = {};\n  filters_titles: Record<string, string | string[]> = {};\n  gotfiltersfromurl = false;\n  feedbackcontainer: HTMLElement;\n  feedbacknode: HTMLElement;\n  resultsnode: HTMLElement;\n  declare options: FilteredOverviewOptions;\n  resetnode: HTMLElement | null;\n  oldfilterstr = '';\n\n  constructor(options: FilteredOverviewOptions) {\n    super(options);\n\n    if (!this.options.filterpagetype)\n      console.error(\"Please set the filterpagetype for this page (for tracking)\");\n    else\n      pushToDataLayer({ filterpagetype: this.options.filterpagetype });\n\n\n    this.feedbackcontainer = dompack.qS(\".filteredoverview__feedbackandviewbar\");\n    this.feedbacknode = dompack.qS(\".filteredoverview__feedback\");\n    this.resultsnode = dompack.qS(\".filteredoverview__results\");\n\n    if (this.debug) {\n      this.form.classList.add(\"filteredoverview--debugmode\");\n\n      console.log(\"[ut-filters]\", {\n        fbc: this.feedbackcontainer,\n        fbn: this.feedbacknode,\n        rsn: this.resultsnode\n      });\n    }\n\n\n\n    // Check for removing tags on pages which show selected filters as tags\n    const filtertagscontainer = document.querySelector(\".filtertags__items\");\n    if (filtertagscontainer)\n      filtertagscontainer.addEventListener(\"click\", evt => this.doCheckForTagRemoval(evt));\n\n    this.__attachChangeEvents();\n    this.__initFiltersFromURL();\n\n    this.prefillFormWithFilterValues(this.filters);\n\n    this.resetnode = this.form.querySelector(\".filteredoverview__resetfilters\");\n    if (this.resetnode)\n      this.resetnode.addEventListener(\"click\", evt => this.resetFilters());\n\n\n    // ADDME: setting an onunload(??) event may force the browser to reload the page\n\n\n    // NOTE: only Webkit browsers fire this?\n    // NOTE: Only Safari returns evt.persisted\n    // NOTE: Safari only fires pageshow once\n    // NOTE: ... setting an unload event might force Safari to not use the back-forward cache\n    window.addEventListener(\"pageshow\", evt => this.collapseFilterIfReturned(evt));\n\n\n    if (this.debug)\n      console.log(\"[ut-filters] FilteredOverview clientside mode\", this.form);\n\n    // submit (by enter, 'go' on virtual keyboard or click on a submit button) must force a refilter\n    this.form.addEventListener(\"submit\", evt => {\n      evt.preventDefault();\n      this.doFilter(evt);\n    });\n  }\n\n  filternodes?: Array<HTMLInputElement | HTMLSelectElement>;\n  __attachChangeEvents() {\n    // Apply the settings from the URL to the filters bar\n    this.filternodes = dompack.qSA<HTMLInputElement | HTMLSelectElement>(this.form, \"input[name], select[name]\");\n\n    if (this.options.additionalform) {\n      const additionalfields = dompack.qSA<HTMLInputElement | HTMLSelectElement>(this.options.additionalform, \"input[name], select[name]\");\n      this.filternodes = [...this.filternodes, ...additionalfields];\n    }\n\n    for (const node of this.filternodes)\n      node.addEventListener(\"change\", ev => this.onFilterChange(ev));\n  }\n\n  __initFiltersFromURL() {\n    this.oldfilterstr = \"\";\n    this.filters = this.getFiltersFromURL();\n\n    // The automatically open/closing of the filterbar upon page load\n    // is based on whether an URL to specific filters were used.\n    if (Object.keys(this.filters).length > 0)\n      this.gotfiltersfromurl = true;\n\n    if (this.debug)\n      console.log(\"[ut-filters] Filters from URL\", this.filters);\n\n    //force all languages checked (if option is available and not already set)\n    if (!this.filters.language) {\n      for (const optnode of this.form.querySelectorAll(\"input[name='language']\")) {\n        if (!this.filters.language)\n          this.filters.language = [];\n        this.filters.language.push(optnode.value);\n      }\n    }\n\n    //Set filters from url as oldfilter to detect changes for utwente_courses\n    if (document.documentElement.classList.contains(\"coursefinderpage\"))\n      this.oldfilterstr = JSON.stringify(this.filters);\n  }\n\n\n  collapseFilterIfReturned(evt) {\n    if (evt.persisted)\n      this.setFiltersExpanded(false);\n  }\n\n\n\n  isFilterActive() {\n    return Object.keys(this.filters).length;\n  }\n\n  getFiltersFromURL() {\n    const filters = {};\n\n    //get url params if set\n    const urlparamsdone = [];\n    for (const node of this.filternodes) {\n      const val = urlparamsdone.indexOf(node.name) === -1 ? this.getUrlParam(node.name) : \"\";\n      if (val !== \"\") {\n        // Do we have a mapping?\n        // We can use this to convert the value in field \"tag\" to the value in field \"value\".\n        const inptype = node.nodeName === \"INPUT\" ? node.getAttribute(\"type\") : \"\";\n        if (inptype === \"checkbox\") {\n          const vals = val.split(\",\");\n\n          filters[node.name] = vals;\n        } else if (inptype === \"radio\")\n          filters[node.name] = val;\n        else if (node.nodeName === \"SELECT\")\n          filters[node.name] = val;\n        else\n          filters[node.name] = val;\n\n        urlparamsdone.push(node.name);\n      }\n    }\n\n    this.processFiltersFromURL();\n\n    return filters;\n  }\n\n  prefillFormWithFilterValues(filters) {\n    if (this.debug)\n      console.log(\"[ut-filters] Apply filters to DOM\", filters);\n\n    for (const node of this.filternodes) {\n      const inptype = node.nodeName === \"INPUT\" ? node.getAttribute(\"type\") : \"\";\n      if (inptype === \"checkbox\")\n        node.checked = filters[node.name] && filters[node.name].indexOf(node.value) > -1;\n      else if (inptype === \"radio\")\n        node.checked = filters[node.name] === node.value; // ? true : false;\n      else if (filters[node.name])\n        node.value = filters[node.name];\n    }\n  }\n\n  // Set filter parameters in url\n  applyFiltersToURL() {\n    if (this.debug)\n      console.log(\"[ut-filters] Apply filters to URL\", this.filters);\n\n    if (!history.replaceState)\n      return;\n\n    const url = new URL(location.href);\n    for (const name of Object.keys(this.filters)) {\n      const val = this.filters[name];\n\n      if (typeof val === \"string\") {\n        if (val !== \"\")\n          url.searchParams.set(name, val);\n      } else if (typeof val === \"boolean\") {\n        if (val)\n          url.searchParams.set(name, \"\");\n      } else if (Array.isArray(val)) {\n        if (val.length > 0)\n          url.searchParams.set(name, val.join(\",\"));\n      }\n    }\n\n    // FIXME: workaround for Studyfinder / Coursefinder, find a cleaner way to do this\n    if (typeof this.isdetailsview !== \"undefined\") {\n      if (!this.isdetailsview)\n        url.hash = \"#listview\";\n    }\n\n    history.replaceState(null, \"\", url);\n\n\n    ////////////////////////////////////////////////////////////////////////////////////////////////////\n    // For pages which reload or go to a different URL for another view (such as the PDC services pages)\n    // we need to update the anchor to contain the current filtersettings.\n    // (otherwise the user would loose all filters when switching between views)\n\n    // IE is the only browser not supporting the URL API\n    // (and some very old devices such as iPad1 and iPhone4)\n\n    // using the URL API we update the search query part of the URL\n    // of links to pages which also use the same filters\n    const anchors = document.querySelectorAll<HTMLAnchorElement>(\"a.filteredoverview__updatelinkquery\");\n    for (const anchor of anchors) {\n      // For URL API docs see: https://developer.mozilla.org/en-US/docs/Web/API/URL\n      const url2 = new URL(anchor.href);\n      url2.search = search;\n      anchor.href = url2.href;\n    }\n    ///////////////////////////////////////////////////////////////////////////////////////////////////\n  }\n\n  onFilterChange(evt) {\n    this.doFilter(evt);\n  }\n\n  updateFilters(evt?: Event) {\n    const interactivechange = Boolean(evt);\n    // FIXME: we should change to this.filters = { name: \"\", title: \"\", allselected: true }\n    this.filters = {};\n    this.filters_titles = {};\n\n    for (const node of this.filternodes) {\n      if (node.nodeName === \"SELECT\") { //node.value != \"\") // <select> (pulldown) or <input type=\"text\" />\n\n        if (node.value !== \"\") {\n          this.filters[node.name] = node.value;\n          // FIXME: we could use .selectedOptions, but it might fail on IE11 ?\n          this.filters_titles[node.name] = node.options[node.selectedIndex].text; // node.value;\n        }\n      } else if (node.nodeName === \"INPUT\") {\n        const inptype = node.getAttribute(\"type\");\n\n        if (inptype === \"checkbox\") {\n          if (!node.checked)\n            continue;\n\n          if (!this.filters[node.name]) {\n            this.filters[node.name] = [];\n            this.filters_titles[node.name] = [];\n          }\n\n          this.filters[node.name].push(node.value);\n\n          let title = \"\";\n\n          if (node.id !== \"\") {\n            const labelnode = document.querySelector('label[for=\"' + node.id + '\"]:not(:empty)');\n\n            if (labelnode)\n              title = labelnode.textContent;\n            else\n              title = \"??\"; // no label or there's a typo in the label's for attribute\n          }\n\n          this.filters_titles[node.name].push(title);\n        } else if (inptype === \"radio\") {\n          if (!node.checked)\n            continue;\n\n          if (node.value !== \"\") // ignore invalid (placeholder) or 'show all' settings\n            this.filters[node.name] = node.value; //checked;\n\n          let title = \"\";\n          if (node.id !== \"\") {\n            const labelnode = document.querySelector('label[for=\"' + node.id + '\"]');\n            if (labelnode)\n              title = labelnode.textContent;\n            else\n              title = \"??\"; // no label or there's a typo in the label's for attribute\n          }\n          this.filters_titles[node.name] = title;\n        } else {// assume textual (\"text\", \"search\")\n          if (node.value !== \"\") {\n            this.filters[node.name] = node.value;\n            this.filters_titles[node.name] = node.value;\n          }\n        }\n      }\n    }\n\n    this.sendCurrentFiltersToDataLayer(interactivechange);\n\n    this.onFormFiltersUpdate(this.filters, evt);\n\n    // Exception for language selection in the (Master) studyfinder.\n    // When all languages are selected, treat this as 'filter not used'.\n    if (document.documentElement.classList.contains(\"page--studyfinder\") && this.filters.language) {\n      // All languages selected?\n      if (this.form.language.length === this.filters.language.length)\n        delete this.filters.language;\n    }\n  }\n\n  sendCurrentFiltersToDataLayer(interactivechange) {\n    if (interactivechange) {\n      const dlevent: Record<string, string> = {};\n      Object.keys(this.filters_titles).forEach(key => {\n        let val = this.filters_titles[key];\n        if (Array.isArray(val))\n          val = val.join(', ');\n\n        dlevent['filter_' + key] = val;\n\n        if (!filter_lastsettings[key] || filter_lastsettings[key] !== val) { //also send an explicit event for just this filter\n          filter_lastsettings[key] = val;\n          pushToDataLayer({ event: 'set_filter', filtername: key, filtervalue: val });\n        }\n      });\n      filter_lastseenkeys.filter(key => !(key in this.filters_titles)).forEach(key => { //this key went away\n        pushToDataLayer({ event: 'set_filter', filtername: key, filtervalue: '' });\n      });\n      pushToDataLayer({ event: \"set_filters\", ...dlevent });\n    }\n    filter_lastseenkeys = Object.keys(this.filters_titles);\n  }\n\n  // The study finder resets the other filters when searching for words\n  resetFilters(keepwords) {\n    for (const node of this.filternodes) {\n      if (keepwords && node.name === \"words\")\n        continue;\n      const inptype = node.nodeName === \"INPUT\" ? node.getAttribute(\"type\") : \"\";\n      if (inptype === \"checkbox\" || inptype === \"radio\")\n        node.checked = node.name === \"language\";//check if is language filter else uncheck\n      else\n        node.value = \"\";\n    }\n\n    this.doFilter();\n  }\n\n\n  doFilter(evt?: Event) {\n    this.doFilterInternal(evt);\n  }\n\n  doFilterForced() {\n    this.doFilterInternal(null, true);\n  }\n\n  refreshFilterFeedbackUI() {\n    this.syncFilterTags();\n\n    // Only show reset button if there is an active filter\n    let nrfilters = Object.keys(this.filters).length;\n    if (nrfilters === 1 && this.filters.language && this.filters.language.length === this.languagescount)\n      --nrfilters;//ignore of all languages are selected\n\n    this.form.classList[nrfilters > 0 ? \"add\" : \"remove\"](\"filteredoverview--filteractive\");\n\n    if (this.feedbackcontainer)\n      this.feedbackcontainer.classList[nrfilters > 0 ? \"add\" : \"remove\"](\"filteredoverview--filteractive\");\n  }\n\n\n  //doFilter( forcerefresh )\n  async doFilterInternal(evt, forcerefresh = false) {\n    if (this.debug)\n      console.log(\"[ut-filters] FilteredOverview:doFilter\", { evt: evt });\n\n    this.updateFilters(evt);\n\n    const filterstr = JSON.stringify(this.filters);\n\n    if (filterstr === this.oldfilterstr && !forcerefresh)\n      return;\n\n    this.oldfilterstr = filterstr;\n\n\n    this.refreshFilterFeedbackUI();\n\n    this.applyFiltersToURL();\n\n\n\n\n\n    // Used by Studyfinder / Coursefinder\n    // FIXME: move to StudyfinderFilter class in utwente_education !! HOWEVER only coursefinder actually implements _SearchWords RPC so... this rpc stuff should go to coursefinder ?\n    if (typeof this.filters.words !== \"undefined\" && this.filters.words !== \"\") {\n      if (this.rpccache && this.rpccache.words === this.filters.words) {\n        this.showResults();\n      } else {\n        // this.rpc.request( \"SearchWords\", [ this.filters.words ], this.onRpcResult.bind(this) );\n        const result = await this.doSearchWords(this.filters.words);\n        this.rpccache = result;\n        if (this.debug)\n          console.log(\"rpccache\", result);\n        this.showResults();\n      }\n\n      return;\n    }\n    this.rpccache = null;\n\n    this.showResults();\n  }\n\n  async doSearchWords(words: string) {\n    if (!this.rpc)\n      this.rpc = new JSONRPC();\n    return await this.rpc.async('SearchWords', words);\n  }\n\n  showNoResults(noresults: boolean) {\n    if (noresults)\n      document.documentElement.classList.add(\"filteredoverview--noresults\");\n    else\n      document.documentElement.classList.remove(\"filteredoverview--noresults\");\n  }\n\n\n\n\n\n  // override me\n  // @short after reading the URL and before updating the form field values, this function allows you use or change values in the filters\n  processFiltersFromURL() {\n    if (this.debug)\n      console.log(\"[ut-filters] processFiltersFromURL not used.\");\n  }\n\n  // override me to check/change/delete filters before new results are calculated\n  onFormFiltersUpdate(filters, evt?: Event) {\n  }\n\n\n\n  ////////////////////////////////////////////////////////////////////////////////////////////\n  //\n  //  Tags\n  //\n\n  doCheckForTagRemoval(evt) {\n    const tagnode = evt.target.closest(\".filtertags__item\");\n    if (!tagnode)\n      return;\n\n    evt.preventDefault();\n\n    const fieldname = tagnode.getAttribute(\"data-name\");\n    const fieldvalue = tagnode.getAttribute(\"data-value\");\n\n    /*\n    FIXME: uncomment when there is a need for it again\n    if (this.onRemoveTag)\n      this.onRemoveTag({ name: fieldname, value: fieldvalue });\n    */\n\n    if (!this.form[fieldname]) {\n      console.error(\"Failed to find field/option belonging to the removed tag\", fieldname, fieldvalue);\n      return;\n    }\n    if (this.form[fieldname] instanceof RadioNodeList) { // Both Checkbox and Radiobuttons\n      // In a collection (checkboxes or radiobuttons), lookup the option with the\n      // value we want to remove and remove it's checked state\n      //let field = this.form.querySelector('[name=\"'+fieldname+'\"][value=\"'+fieldvalue+'\"]');\n      //field.checked = false;\n      for (const field of this.form[fieldname] as unknown as HTMLInputElement[]) {\n        if (field.value === fieldvalue)\n          field.checked = false;\n      }\n    } else { // SELECT, input type=\"text\"/\"hidden\"\n      (this.form[fieldname] as HTMLSelectElement).value = \"\";\n    }\n\n    this.doFilter();\n  }\n\n  getFlatActiveFilterValuesList(): ActiveFilterValue {\n    // Compile a list of all selected filter values\n    const tags: ActiveFilterValue[] = [];\n    for (const key in this.filters) {\n      if (filtertags_ignorefields.indexOf(key) > -1)\n        continue; // don't show a free text query as tag\n\n      tags.push({\n        name: key,\n        value: this.filters[key],\n        title: this.filters_titles[key]\n      });\n    }\n    return tags;\n  }\n\n  currenttags: Record<string, {\n    isnew: boolean;\n    isused: boolean;\n    title: string;\n    name: string;\n    value: string;\n    node: HTMLElement | null;\n  }> = {};\n\n  syncFilterTags() {\n    const filtertagscontainer = document.querySelector(\".filtertags__items\");\n    if (!filtertagscontainer)\n      return;\n\n    // FIXME: would have been nicer if updateFilters returned an array\n    //        with { name:, selectedvalues:, selectedvaluetitles: }\n\n    for (const key of Object.keys(this.currenttags)) {\n      this.currenttags[key].isnew = false;\n      this.currenttags[key].isused = false;\n    }\n\n\n    let tags = this.getFlatActiveFilterValuesList();\n\n    // Present the oppertunity to merge tags\n    // For example status=graduated+graduationyear=2018 could be mapped to graduationyear=2018 with title \"Completed in 2018\"\n    if (this.onMapFilterTags) {\n      tags = this.onMapFilterTags(tags, this.filters);\n      //console.info(\"TAGS after mapping\", {...tags});\n    }\n\n    for (const tag of tags) {\n      if (Array.isArray(tag.value)) { // result of a checkbox (or pulldown multiselect??)\n        for (let idx = 0; idx < tag.value.length; idx++) {\n          const rowkey = \"_\" + tag.name + \"=\" + tag.value[idx];\n          if (!this.currenttags[rowkey])\n            this.currenttags[rowkey] = {\n              title: tag.title[idx],\n              name: tag.name,\n              value: tag.value[idx],\n              isnew: true,\n              node: null\n            };\n\n          this.currenttags[rowkey].isused = true;\n        }\n      } else {\n        const rowkey = \"_\" + tag.name + \"=\" + tag.value;\n        if (!this.currenttags[rowkey])\n          this.currenttags[rowkey] =\n          {\n            title: tag.title,\n            name: tag.name,\n            value: tag.value,\n            isnew: true,\n            node: null\n          };\n\n        this.currenttags[rowkey].isused = true;\n      }\n    }\n\n    // Update (create or delete) the list of tags in the DOM\n    for (const key of Object.keys(this.currenttags)) {\n      const tag = this.currenttags[key];\n\n      if (tag.isnew) {\n        const item = document.createElement(\"div\");\n        item.className = \"filtertags__item\";\n        item.setAttribute(\"data-name\", tag.name);\n        item.setAttribute(\"data-value\", tag.value);\n\n        const title = document.createElement(\"div\");\n        title.className = \"filtertags__item__title\";\n        title.textContent = tag.title;\n\n        const remove = document.createElement(\"div\");\n        remove.className = \"filtertags__item__remove UT-icon-UT_icon_47_cross-16px\";\n        //remove.textContent = \"x\";\n\n        item.appendChild(title);\n        item.appendChild(remove);\n        filtertagscontainer.appendChild(item);\n\n        item.__tag = tag;\n\n        this.currenttags[key].node = item;\n      }\n    }\n\n    const feedbacknode = document.querySelector(\".filteredoverview__feedbackandviewbar\");\n    if (feedbacknode)\n      feedbacknode.classList.toggle(\"filteredoverview__filtertags--active\", tags.length > 0);\n\n    document.clientWidth;\n\n    for (const key of Object.keys(this.currenttags)) {\n      const tag = this.currenttags[key];\n      if (tag.isnew) {\n        tag.node.clientWidth;\n        tag.node.classList.add(\"visible\");\n      }\n      if (!tag.isused) {\n        tag.node.classList.remove(\"visible\");\n        setTimeout(() => tag.node?.remove(), 200); //we're not trusting transitionend to fire - it won't fire if the whole filter section is removed\n        delete this.currenttags[key];\n      }\n    }\n  }\n\n\n  ////////////////////////////////////////////////////////////////////////////////////////////\n  //\n  //  Misc helper functions\n  //\n\n  getUrlParam(name) {\n    const urlparamstr = location.search.replace(/\\+/g, \"%20\");\n    if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(urlparamstr))\n      return decodeURIComponent(name[1]);\n    return \"\";\n  }\n\n  setFeedback(totalfound: number, totalshown?: number, allitemscount?: number) {\n    this.showNoResults(totalfound === 0);\n\n    if (this.feedbacknode) {\n      const gettextfunc = this.options.getResultsFeedbackText ?? getResultsFeedbackText;\n      this.feedbacknode.textContent = gettextfunc(totalfound, totalshown);\n    }\n\n    this.setTeaserResultCount(totalfound, totalshown);\n  }\n}\n\n\n\n/** FilteredOverview which automatically handles filtering based on JSON encoded\n    values specified in the data-filterdata attribute of each item\n*/\nexport class ClientSideFilteredOverview extends FilteredOverview {\n  items: FilterItem[] = [];\n  itemscontainer: HTMLElement;\n  searchIndex = new SearchIndex();\n\n  constructor(options) {\n    super(options);\n    const itemsselector = options?.itemsselector || \"\";\n    this.itemscontainer = dompack.qR(\".filteredoverview__items\");\n    if (this.debug)\n      console.log(\"[ut-filters]\", {\n        form: this.form,\n        itemscontainer: this.itemscontainer\n      });\n\n    const items = this.itemscontainer.querySelectorAll(itemsselector);\n    if (items.length === 0)\n      console.error(\"No items in filteredoverview? selector = \");\n    else if (this.debug)\n      console.log(\"[ut-filters] Filteredoverview with \" + items.length + \" items\");\n\n    this.setFeedback(items.length, items.length, items.length);\n\n    // keep an internal list of all items AND\n    // generate the list view based on content of the normal view\n    this.items = [];\n    for (const node of items) {\n      this.items.push({\n        node: node,\n        filterdata: node.dataset.filterdata ? JSON.parse(node.dataset.filterdata) : null,\n        title: node.querySelector(\"[data-autocompletesource-title]\"),\n        description: node.querySelector(\"[data-autocompletesource-description]\")\n        //, \"title\":   node.querySelector(\"h3\").textContent.toLowerCase()\n      });\n    }\n    this._initClientsideAutosuggest();\n\n    if (this.isFilterActive())\n      this.doFilter();\n  }\n\n  _initClientsideAutosuggest() {\n    // A slightly modified version of initSearchSuggestions to highlight matches within suggestions, not just the first x characters\n    const searchnode = this.form.querySelector<HTMLElement>(\"input[data-autocomplete-clientside]\"); //should all switch to -clientside for clarity\n    if (searchnode) {\n      this._initClientsideSearchIndex();\n\n      UTAutoComplete({\n        input: searchnode,\n        className: 'ut-autocomplete',\n        preventSubmit: 1,\n        fetch: async (text, update) => {\n          const suggestions = this.searchIndex.suggest(text).slice(0, 10);\n\n          update(suggestions.map(_ => { return { label: _, value: _ }; }));\n        },\n        onSelect: (item) => {\n          searchnode.value = item.value;\n          this.doFilter();\n        }\n      });\n    }\n  }\n\n  _initClientsideSearchIndex() {\n    this.searchIndex.searchFields = [\"title\", \"description\"];\n    this.searchIndex.completeSuggestFields = [\"title\"];\n\n    for (const item of this.items) {\n      this.searchIndex.indexItem(\n        {\n          node: item.node,\n          title: item.title?.textContent ?? '',\n          description: item.description?.textContent ?? '',\n          titleNode: item.title,\n          descriptionNode: item.description\n        });\n    }\n  }\n\n  isMatch(node) {\n    if (this.searchIndexMatch) { //was the search set ?\n      const matchingentry = this.searchIndexMatch.items.filter(_ => _.node === node)[0];\n      if (!matchingentry)\n        return false;\n    }\n\n    for (const filtername of Object.keys(this.filters)) {\n      if (node.hasAttribute(`data-filter-${filtername}`)) {\n        const filterval = this.filters[filtername];\n\n\n        const matchtype = node.getAttribute(`data-filter-${filtername}-matchtype`);\n        if (matchtype === \"partialtext\") {\n          const findinvalue = node.getAttribute(`data-filter-${filtername}`);\n          if (findinvalue.includes(filterval))\n            return true;\n\n          continue;\n        }\n\n\n        const setvalues = node.getAttribute(`data-filter-${filtername}`).split(' ');\n\n        if (Array.isArray(filterval)) {\n          if (!setvalues.some(val => filterval.includes(val)))\n            return false;\n        } else if (!setvalues.includes(filterval))\n          return false;\n      }\n    }\n    return true;\n  }\n\n  runFilterByDataTags() {\n    if (this.debug)\n      console.log(\"[ut-filters] runFilterByDataTags\", this.filters);\n\n    if (this.searchIndex) {\n      if (this.filters.query)\n        this.searchIndexMatch = this.searchIndex.search(this.filters.query);\n      else\n        this.searchIndexMatch = null;\n    }\n\n    this.items.forEach(item => item.node.hidden = !this.isMatch(item.node));\n\n    const totalfound = this.items.filter(item => !item.node.hidden).length;\n    this.setFeedback(totalfound, totalfound, this.items.length);\n  }\n\n  showResults() {\n    if (this.debug)\n      console.log(\"[ut-filters] showResults\", this.filters);\n\n    //let activefilters = Object.keys(this.filters).length;\n    let totalfound = 0;\n\n    for (let i = 0; i < this.items.length; ++i) {\n      const item = this.items[i].node; //this.items[i].details;\n      const itemdata = this.items[i].filterdata;\n\n      let doesnotmatch = false;\n\n      for (const key of Object.keys(this.filters)) {\n        // FIXME: ITC phd-projects specific hack, find another way to do this\n        if (key === \"status\") {\n          const selectedstatus = this.filters[key]; // 'ongoing', 'graduated'\n\n          if (selectedstatus.indexOf(\"ongoing\") > -1 && itemdata.graduationyear === 0)\n            continue; // OK\n\n          if (selectedstatus.indexOf(\"graduated\") > -1) {\n            if (this.form.graduationyear.value === 0) { // PhD project from any year\n              if (itemdata.graduationyear > 0)\n                continue; // graduated, so OK\n            } else if (this.form.graduationyear.value === itemdata.graduationyear)\n              continue; // OK\n          }\n\n          doesnotmatch = true;\n          continue;\n        } else if (key === \"graduationyear\") // skip this one, we handle it together with the 'status' field\n          continue; // FIXME: ITC phd-projects specific hack, find another way to do this\n        else if (key === \"words\") { // handled by RPC\n          if (this.debug) // if matching cannot be found here which are expected, try rebuilding the Consilio searchcatalog to make sure id's are in sync with the WRD schema\n            console.log(\"[ut-filters] Is\", item.dataset.id, \"IN\", this.rpccache.ids);\n\n          if (this.rpccache && this.rpccache.ids.indexOf(item.dataset.id) === -1)\n            doesnotmatch = true;\n\n          continue;\n        } else if (key === \"query\") { // handled by JS\n          if (!(\"searchtext\" in itemdata)) {\n            console.error(\"searchtext field missing in item's filterdata.\");\n            continue;\n          }\n\n          // FIXME: seperate words\n          if (this.debug)\n            console.log(\"[ut-filters] Got\", itemdata.searchtext, \"\\n\", \"Looking for\", this.filters.query.toLowerCase());\n\n          const parts = this.filters.query.toLowerCase().split(\" \");\n\n          let qmatches = true;\n          for (const findtext of parts) {\n            if (itemdata.searchtext.indexOf(findtext) === -1) {\n              qmatches = false;\n              break;\n            }\n          }\n\n          if (!qmatches)\n            doesnotmatch = true;\n\n          continue;\n        }\n\n        if (!(key in itemdata)) {\n          if (this.debug)\n            console.log(\"Cannot find search key '\" + key + \"'\");\n          continue;\n        }\n\n\n\n        const itemvalue = itemdata[key];\n        const searchvalue = this.filters[key];\n\n        if (this.debug)\n          console.log(\"[ut-filters] Looking for\", searchvalue, \"in\", itemvalue);\n\n\n        if (Array.isArray(searchvalue) && Array.isArray(itemvalue)) { // Find multiple values in multiple values\n          for (let i2 = 0; i2 < searchvalue.length; ++i2) {\n            let found = false;\n            if (itemvalue.indexOf(this.filters[key][i2]) > -1) {\n              found = true;\n              break;\n            }\n\n            if (!found)\n              doesnotmatch = true;\n          }\n        } else if (Array.isArray(itemvalue)) {\n          // lookup single value (pulldown or text) in array\n          if (itemvalue.indexOf(this.filters[key]) === -1)\n            doesnotmatch = true;\n        } else {\n          // lookup single value (pulldown or text) in a non-array (number of string)\n          const matchvalue = (typeof itemvalue === \"number\" ? parseInt(this.filters[key]) : this.filters[key]);\n\n          if (itemvalue !== matchvalue)\n            doesnotmatch = true;\n        }\n      }\n\n      const ismatch = !doesnotmatch;\n\n      item.classList[ismatch ? \"remove\" : \"add\"](\"hidden\");\n\n      if (ismatch) {\n        ++totalfound;\n        /*\n                item.style.opacity = 0;\n                //this.itemscontainer.appendChild( item );\n\n                item.clientHeight;//force css refresh\n                item.style.opacity = 1;\n        */\n      }\n    }\n\n    this.setFeedback(totalfound, totalfound, this.items.length);\n  }\n}\n","import { levenshteinDistance } from \"@webhare/std\";\n\nconst wordRegex = new RegExp(\"\\\\w+\", \"g\");\nconst lastWordRegex = new RegExp(\"(.*[^\\\\w])?(\\\\w+)$\");\n\ntype FieldsMap = Map<string, number>;\ntype Fields = { fields: FieldsMap };\ntype ItemPositions = { positions: number[] };\ntype Entries<ItemType> = Map<ItemType, ItemPositions>;\n\nexport class SearchIndex<ItemType extends object> {\n  // Create a new index mapping\n  index = new Map<string, Entries<ItemType>>;\n  // Global item metadata (e.g. total wordcount per field)\n  items = new Map<ItemType, Fields>;\n\n  // Initialize the search and suggest fields, fill automatically\n  _searchFields: string[] = [];\n  _autoSearchFields = true;\n  _suggestFields: string[] = [];\n  _autoSuggestFields = true;\n  _completeSuggestFields: string[] = [];\n\n  /// The fields that are used for searching, defaults to all of the indexed fields\n  get searchFields() {\n    // Return the search fields\n    return this._searchFields;\n  }\n\n  set searchFields(fields) {\n    // The search fields are set manually\n    this._searchFields = fields;\n    this._autoSearchFields = false;\n  }\n\n  /// The fields that are used for suggestions, defaults to the searchFields\n  get suggestFields() {\n    // If not set manually, return the search fields\n    return this._autoSuggestFields ? this._searchFields : this._suggestFields;\n  }\n\n  set suggestFields(fields) {\n    // The suggest fields are set manually\n    this._suggestFields = fields;\n    this._autoSuggestFields = false;\n  }\n\n  /// If words from this field are suggested, the complete field is returned as a suggestion\n  get completeSuggestFields() {\n    return this._completeSuggestFields;\n  }\n\n  set completeSuggestFields(fields) {\n    this._completeSuggestFields = fields;\n  }\n\n  /** Index an item\n      This function indexes an item. All of the 'string' properties of the item are tokenized and indexed.\n  */\n  indexItem(item: ItemType): void {\n    const fields: FieldsMap = new Map;\n\n    // Index all indexable properties of the incoming item\n    for (const [key, invalue] of Object.entries(item as Record<string, string | unknown>)) {\n      // For now, we'll only index string values\n      if (typeof invalue !== \"string\")\n        continue;\n\n      // If not set manually, search through all indexed fields\n      if (this._autoSearchFields && !this._searchFields.includes(key))\n        this._searchFields.push(key);\n\n      // Normalize the value\n      const value = invalue.toLowerCase();\n\n      // Tokenize into words\n      let match;\n      let count = 0;\n      while ((match = wordRegex.exec(value)) !== null) {\n        const term = key + \":\" + match[0];\n        const pos = match.index;\n\n        // See if this term is already indexed\n        let entry = this.index.get(term);\n        if (!entry) {\n          // Create a new entry for this term\n          entry = new Map();\n          this.index.set(term, entry);\n        }\n\n        // See if this item is already indexed for this term\n        let props = entry.get(item);\n        if (!props) {\n          // Add the item to this term\n          props = { positions: [] } satisfies ItemPositions;\n          entry.set(item, props);\n        }\n\n        // Add the term's position\n        props.positions.push(pos);\n        ++count;\n      }\n      fields.set(key, count);\n\n    }\n    // Store the item's field counts\n    this.items.set(item, { fields });\n  }\n\n  /** Get suggestions for a query\n      @returns A list of suggested queries\n  */\n  suggest(query: string): string[] {\n    const results = new Map<string, number[]>;\n\n    // Split the incoming query into the array [ \"original query\", \"query up until last word\", \"last word of query\" ]\n    const parsedQuery = lastWordRegex.exec(query);\n    if (parsedQuery) {\n      const baseQuery = parsedQuery[1] || \"\";\n      const suggestQuery = parsedQuery[2];\n\n      let baseResults;\n      if (baseQuery)\n        baseResults = this.#searchInternal(baseQuery).results;\n\n      // Iterate over all the terms in the index\n      for (const [term, entry] of this.index) {\n        // Split the term into field and text\n        const termField = term.split(\":\")[0];\n        if (!this.suggestFields.includes(termField))\n          continue; // This is not a suggested field\n\n        const termText = term.substr(termField.length + 1);\n\n        // Check if the text matches the last query word\n        const score = this.#matchesText(suggestQuery, termText, { startsWithScore: .9 });\n        if (score) {\n          // Return the query, completed with the matching term text\n          let suggestion = baseQuery + termText;\n          if (!results.has(suggestion))\n            results.set(suggestion, [score]);\n\n          // If this field should be returned whole, return this field from each of the entry's items\n          if (this.completeSuggestFields.includes(termField)) {\n            for (const item of entry.keys()) {\n              if (baseResults && !baseResults.has(item))\n                continue;\n              const scores = [score];\n              if (baseResults)\n                scores.push(...baseResults.get(item)!); //due to the two 'if's before here, baseResults.get(item) is not null\n\n              suggestion = (item as Record<string, string>)[termField];\n              const result = results.get(suggestion);\n              if (result)\n                result.push(...scores);\n              else\n                results.set(suggestion, scores);\n            }\n          }\n        }\n      }\n    }\n    if (!results)\n      return [];\n\n    // Calcu§late single scores\n    const flatscores = this.#calculateScores(results);\n\n    // Sort by score and return the suggestions as an array\n    return this.#getSortedItems(flatscores);\n  }\n\n  /** Search for items\n      @param query - The query to search for (only words are searched, interpunction is ignored)\n      @returns The matching items, in scoring order\n  */\n  search(query: string): {\n    items: ItemType[];\n    terms: string[];\n  } {\n    const searchResult = this.#searchInternal(query);\n    // Sort by score and return the items as an array\n    const items = this.#getSortedItems(searchResult.results);\n    return { items, terms: searchResult.terms };\n  }\n\n  #searchInternal(query: string) {\n    const results = new Map<ItemType, number[]>();\n    const terms: string[] = [];\n\n    query = query.toLowerCase();\n\n    // Only search through searched fields\n    for (const field of this.searchFields) {\n      let fieldResults;\n      // Iterate over each of the words in the query\n      const matches = query.match(wordRegex);\n      if (matches) {\n        for (const word of matches) {\n          // Search for the word in this field\n          const queryResult = this.#executeQuery(field, word);\n          // If one the words doesn't match anything, return nothing (AND serach)\n          if (!queryResult.results.size)\n            continue;\n\n          for (const term of queryResult.terms)\n            if (!terms.includes(term))\n              terms.push(term);\n\n          // If there are no results yet, add these results\n          if (!fieldResults) {\n            fieldResults = new Map();\n            for (const [item, match] of queryResult.results)\n              fieldResults.set(item, match.scores);\n          } else {\n            // Keep all items that are already there (AND search)\n            for (const [item, match] of queryResult.results) {\n              if (fieldResults.has(item))\n                fieldResults.get(item).push(...match.scores);\n            }\n            // Remove all items that aren't found again (AND search)\n            for (const item of fieldResults.keys())\n              if (!queryResult.results.has(item))\n                fieldResults.delete(item);\n          }\n        }\n      }\n\n      if (fieldResults) {\n        for (const [item, scores] of fieldResults) {\n          const result = results.get(item);\n          if (result)\n            result.push(...scores);\n          else\n            results.set(item, scores);\n        }\n      }\n    }\n\n    // Calculate single scores\n    const flatscores = this.#calculateScores(results);\n    return { results: flatscores, terms };\n  }\n\n  // returns a Map from item to { scores, term, positions }\n  #executeQuery(field: string, text: string) {\n    let results;\n    const terms: string[] = [];\n    // Try a direct match\n    const entry = this.index.get(field + \":\" + text);\n    if (entry) {\n      // The entry's keys are the indexed items\n      results = new Map(Array.from(entry).map(item_positions => {\n        return [item_positions[0], { scores: [1], term: text, positions: item_positions[1].positions }];\n      }));\n      terms.push(text);\n    } else {\n      // Iterate over all the terms in the index\n      results = new Map();\n      for (const [term, indexEntry] of this.index) {\n        // Split the term into field and text\n        const termField = term.split(\":\")[0];\n        if (termField !== field && field !== \"*\")\n          continue; // This is not the field we're looking for\n\n        const termText = term.substr(termField.length + 1);\n\n        // Check if the text matches the query word\n        const score = this.#matchesText(text, termText);\n        if (score) {\n          for (const item_positions of Array.from(indexEntry)) {\n            if (!results.has(item_positions[0]))\n              results.set(item_positions[0], { scores: [score], term: termText, positions: item_positions[1].positions });\n            else\n              results.get(item_positions[0]).scores.push(score);\n          }\n          terms.push(termText);\n        }\n      }\n\n      // Calculate single scores\n      for (const [item, match] of results)\n        results.get(item).scores = [match.scores.reduce((avg: number, cur: number, idx: number) => ((avg * idx) + cur) / (idx + 1))];\n    }\n    return { results, terms };\n  }\n\n  #matchesText(queryWord: string, termWord: string, { limitDistance = 2, startsWithScore = .25 } = {}) {\n    if (queryWord === termWord)\n      return 1;\n    let score = 0;\n    // Require both terms to have a length of at least twice the distance\n    if (Math.min(queryWord.length, termWord.length) >= 2 * limitDistance) {\n      const dist = levenshteinDistance(queryWord, termWord);\n      if (dist <= limitDistance)\n        score = Math.max(score, (limitDistance - dist + 1) / limitDistance);\n    }\n    if (termWord.startsWith(queryWord))\n      score = Math.max(score, startsWithScore);\n    return score;\n  }\n\n  #calculateScores<KeyType>(results: Map<KeyType, number[]>) {\n    const flatscores = new Map<KeyType, number[]>;\n    for (const [key, scores] of results)\n      flatscores.set(key, [scores.reduce((avg, cur, idx) => ((avg * idx) + cur) / (idx + 1))]);\n    return flatscores;\n  }\n\n  #getSortedItems<KeyType>(results: Map<KeyType, number[]>): KeyType[] {\n    return Array.from(results).sort((a, b) => b[1][0] - a[1][0]).map(_ => _[0]);\n  }\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n/*\nThis variation on dompack-masonry has:\n- a breakclass which make the current widget appear on a new line\n- ability to have different gaps/margin for headers en normal items\n- setItems()\n- need to manually call refresh()\n\nTech\n- columnitems - list of which items each column\n- ability to influence rendering by reading/editting masonry.items after initialization, before the first refresh()\n*/\n\nimport * as dompack from \"dompack\";\n\n\nexport default class DompackMasonry {\n  constructor(node, options) {\n    const domoptions = dompack.getJSONAttribute(node, \"data-masonry-options\");\n    this.initialized = false;\n\n    // NOTE: we don't use Object.assign() here because we have some\n    //       smart rules (convert gutter to gutter_x and gutter_y for example)\n    this.options =\n    {\n      columns: 3,\n      columnwidth: 0,     // if not set the width will be set so the amount of columns will fill up the horizontal space\n\n      // gutter size\n      // gutter:            10 // shorthand for gutter_x and gutter_y\n      gutter_x: 10,\n      gutter_y: 10,\n      //            , gutter_y_header:    23\n\n      margin_header_top: 23,\n      margin_header_bottom: 23,\n\n      debug: false,\n\n      // CSS query (for example '.masonry-item' or array of nodes\n      // Pass an array of nodes if you want control over the order visual order of the items (without reordering the dom)\n      items: null,\n\n      // specify a class to ignore in layouting\n      // (can be used for items which you transition to hide/fade)\n      ignoreclass: \"hide\",\n      breakclass: \"\",\n\n      righttoleft: false // FIXME: keep or remove this option?\n    };//, domoptions, options;\n\n    this.items = [];   // render data\n\n    if (typeof (node) === \"string\")\n      this.container = document.getElementById(node);\n    else\n      this.container = node;\n\n    if (domoptions)\n      this.setOptions(domoptions);\n\n    if (options)\n      this.setOptions(options);\n\n    this.__height = 0;\n    this.__columnwidth = 0;    // (also used to detect whether widget width style has to be set)\n    this.__visiblewidgetscount = 0;\n    this.__singlerow = true;\n    this.__columncontainers = [];\n    this.__padding = 0;\n\n    this.__items_dirty = true;\n\n    // PRIVATE VARS!!\n    this.__leftoffset = 0;\n    this.__containerwidth = 0;\n    this.ignore_resize_events = false;\n\n    this.initialized = true;\n\n    //this.refresh();\n  }\n\n  setItems(items) {\n    //console.log(\"setItems\", items);\n\n    this.__items_dirty = true; // need to recheck all widgets, there might be new ones\n\n    // For now only store the existance and some info on the widgets\n    // DON'T do DOM manipulation here!\n    const widgetrecs = [];\n    for (const wnode of items) {\n      let widgetcols = wnode.getAttribute(\"data-cols\");\n      widgetcols = widgetcols ? parseInt(widgetcols) : 1;\n\n      const item =\n      {\n        node: wnode,\n        width: null,\n        height: null,\n        col: null, // explicit column number\n\n        colwanted: null,\n        colswanted: widgetcols,\n        breakbefore: this.options.breakclass != \"\" && wnode.classList.contains(this.options.breakclass)\n      };\n      // console.log(item);\n      widgetrecs.push(item);\n    }\n\n    // console.log(\"Storing \" + widgetrecs.length + \" items\");\n    this.items = widgetrecs;\n  }\n\n  setOptions(options) {\n    if (\"gutter\" in options) {\n      options.gutter_x = options.gutter;\n      options.gutter_y = options.gutter;\n      delete options.gutter;\n    }\n\n    let setitems = false;\n    let widgets;\n    if (\"items\" in options) {\n      setitems = true;\n      if (typeof (options.items) === \"string\") {\n        if (this.options.debug)\n          console.info(\"Finding widgets by query:\", options.items, \"in\", this.container);\n        widgets = this.container.querySelectorAll(options.items);\n      } else\n        widgets = options.items;\n\n      delete options.items;\n    }\n\n    Object.assign(this.options, options);\n\n    if (setitems) // setitems uses this.options so we need it to be set before we call this.setItems\n      this.setItems(widgets);\n  }\n\n  /** @short full relayout\n      @long find all items, detect width, read data-cols attributes on items and relayout\n  */\n  refresh(elem) {\n    if (!this.initialized) {\n      if (this.options.debug)\n        console.info(\"Refresh called before initialization in ready!!\");\n      return;\n    }\n\n    if (this.options.debug) {\n      console.log(\"$wh.Masonry.refresh()\");\n      //console.trace();\n    }\n\n    const clientwidth = this.container.clientWidth;\n    if (clientwidth == 0) {\n      console.warn(\"Cannot determine size of mansonry container (got 0).\", this.container);\n      return;\n    }\n\n    this.ignore_resize_events = true;\n\n    // FIXME: assuming padding in px\n    // FIXME: assuming correct box-sizing\n    // FIXME: assumption that this container (with the padding) is also the positioning container\n    const cstyle = window.getComputedStyle(this.container);\n    const padtop = parseInt(cstyle.paddingTop, 10);\n    const padbottom = parseInt(cstyle.paddingBottom, 10);\n    const padleft = parseInt(cstyle.paddingLeft, 10);\n    const padright = parseInt(cstyle.paddingRight, 10);\n    this.__padding = {\n      top: padtop,\n      bottom: padbottom,\n      left: padleft,\n      right: padright\n    };\n    //console.log(this.container, this.__padding);\n\n    this.__leftoffset = padleft;\n    this.__containerwidth = clientwidth - padleft - padright;\n\n    this.pvt_relayout();\n\n    this.ignore_resize_events = false;\n  }\n\n  /** @short only update heights and position\n             New items and changed widths aren't detected\n  */\n  refreshHeights(elem) {\n    this.pvt_relayout(null, true);\n  }\n\n  getLastRenderInfo() {\n    return {\n      container: this.container,\n      visiblewidgetscount: this.__visiblewidgetscount,\n      width: this.__containerwidth,\n      height: this.__height,\n      items: this.items,\n      singlerow: this.__singlerow\n    };\n  }\n\n\n  ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////\n  //\n  //  Private functions\n  //\n\n  pvt_relayout(widgets) {\n    if (this.options.debug)\n      console.group(\"$wh.Masonry.pvt_relayout()\");\n\n    let visiblewidgetscount = 0;\n\n    let columnwidth = this.options.columnwidth;\n    if (!columnwidth)\n      columnwidth = (this.__containerwidth - (this.options.columns - 1) * this.options.gutter_x) / this.options.columns;\n\n    if (this.options.debug)\n      console.info(\"Colwidth OLD:\", this.__columnwidth, \", NEW:\", columnwidth);\n\n    if (columnwidth == 0) {\n      console.error(\"Cannot render, columnwidth is 0\");\n      return;\n    }\n\n    if (isNaN(this.options.columns)) {\n      console.error(\"options.columns MUST be a number!\");\n      return;\n    }\n\n\n    const columncount = this.options.columns;\n    let singlerow = true; // until we have to place a new widget below another one all widgets are still on a single row\n\n    const columns = []; // the last Y position in use per column\n    for (var xcol = 0; xcol < columncount; xcol++)\n      columns.push(0);\n\n\n    // for each column the items in that column\n    const columnitems = [];\n    for (var xcol = 0; xcol < columncount; xcol++)\n      columnitems.push([]);\n\n    let widgetrecs;\n    if (!widgets) // If we didn't get a list of items to render we must rerender ALL items\n      widgetrecs = this.items;\n\n    if (this.options.debug)\n      console.info(\"$wh.Masonry relayouting \" + widgetrecs.length + \" items\");\n\n    // Only change widget width's when needed\n    if (this.__items_dirty || this.__columnwidth != columnwidth) // new items or width for widgets need to change?\n    {\n      // First apply the new width to all widgets, so we can later determine the correct height\n      //console.info(\"Measuring items\");\n\n      for (const widget of widgetrecs) {\n        const widgetcols = widget.colswanted > this.options.columns ? this.options.columns : widget.colswanted;\n        const width = columnwidth * widgetcols + (widgetcols - 1) * this.options.gutter_x;\n\n        widget.node.style.position = \"absolute\";\n        widget.node.style.width = Math.floor(width) + \"px\"; // round using pixelratio ??\n        widget.node.style.height = \"\"; // clear any inline specified height (we only allow a fixed height if specified in CSS)\n\n        widget.width = width;\n        widget.cols = widgetcols;\n      }\n\n\n      /*\n      Let our children relayout to match our new width\n      (after which layout of masonry item contents should be done, meaning the height is known and we can start to build up the masonry)\n\n      if (this.options.debug)\n        console.log(\"Firing layout change event\");\n\n      // Notify any of our components within the Masonry container that layout has changed.\n      // After they have updated their layout we know the final height of each widget and can start to layout our Masonry.\n      //$wh.fireLayoutChangeEvent(this.container, \"down\"); // FIXME\n      */\n    }\n\n\n    // measure all widgets in one go to prevent extreneous reflows by mixing writes and reads\n    for (const widget of widgetrecs)\n      widget.height = widget.node.clientHeight;\n\n\n\n    if (this.options.debug)\n      console.log(\"relayout mainloop\");\n\n\n    for (let idx = 0; idx < widgetrecs.length; idx++) {\n      const widgetrec = widgetrecs[idx];\n      const wnode = widgetrec.node;\n\n      const widgetheight = widgetrec.height;\n\n      if (this.options.debug)\n        console.log(\"#\" + idx, widgetheight + \"px\", wnode.className);\n\n      if (widgetheight == 0 || (this.options.ignoreclass != \"\" && wnode.classList.contains(this.options.ignoreclass)))\n        continue;\n\n      visiblewidgetscount++;\n\n\n\n      /*\n            if (widgetrec.breakbefore)\n            {\n              ypos = Math.max.apply(null, columns);\n              for (var col = 0; col < columncount; ++col)\n                columns[col] = ypos;\n            }\n      */\n\n\n\n      // Force all columns to continue rendering items below the top position\n      // of all current items\n      if (widgetrec.breakbefore) {\n        // find the widget which starts the lowest\n        let min_ypos = 0;\n        for (var col = 0; col < columncount; ++col) {\n          const itemcount = columnitems[col].length;\n          if (itemcount == 0)\n            continue;\n\n          const lastitemincol = columnitems[col][itemcount - 1];\n          if (lastitemincol.top > ypos)\n            min_ypos = lastitemincol.top;\n        }\n\n        //console.log(\"!! BREAK, lowest widget top\", min_ypos);\n\n        if (min_ypos > 0) {\n          min_ypos += 160;\n\n          // make all column continue at least 60 pixels lower...\n          for (var col = 0; col < columncount; ++col) {\n            if (columns[col] < min_ypos)\n              columns[col] = min_ypos;\n          }\n        }\n      }\n\n\n\n      // set increase the last used ypos within the columns the current widget will occupy\n      // find the first ypos where the whole block would fit\n      if (this.options.debug)\n        console.info(columns);\n\n\n\n      var bestcol = -1, ypos = 0;\n\n\n      // Forced to be in a specific column?\n      if (widgetrec.colwanted !== null && widgetrec.colwanted < columncount) {\n        bestcol = widgetrec.colwanted;\n        ypos = columns[widgetrec.colwanted];\n      } else {\n        // console.log(\"Find column\");\n        for (var xcol = 0; xcol <= columncount - widgetrec.cols; ++xcol) {\n          const col = this.options.righttoleft ? columncount - widgetrec.cols - xcol : xcol;\n          const maxypos = Math.max.apply(null, columns.slice(col, col + widgetrec.cols));\n          //console.log(col, \"has enough room for \", widgetrec.cols, \" columns starting at Y pos\", maxypos);\n\n          if (bestcol == -1 || maxypos < ypos) // no column yet or we can place the item higher at this location than the previous found position\n          {\n            bestcol = col;\n            ypos = maxypos;\n          }\n        }\n      }\n\n\n      if (ypos > 0) {\n        singlerow = false;\n\n\n        // A big hack for some special timeline related layouting\n        if (wnode.classList.contains(\"timeline__header\")) {\n          if (columnitems[bestcol].length > 0 && columnitems[bestcol][columnitems[bestcol].length - 1].breakbefore) {\n            // .header + .header\n            ypos += this.options.margin_header_top; // hack\n            // wnode.style.outline = \"1px solid #F00\";\n          } else {\n            // .normalitem + .header\n            ypos += this.options.gutter_y;\n            // wnode.style.outline = \"1px solid #0F0\";\n          }\n        } else // hack\n        {\n          // Normal item with an header above it?\n          if (columnitems[bestcol].length > 0 && columnitems[bestcol][columnitems[bestcol].length - 1].breakbefore) {\n            ypos += this.options.margin_header_bottom;\n            // wnode.style.outline = \"1px solid #F0F\";\n          } else // Normal item + normal item\n          {\n            ypos += this.options.gutter_y;\n            // wnode.style.outline = \"1px solid #0FF\";\n          }\n        }\n      }\n\n\n      const widgetbottom = ypos + widgetheight;\n      for (var col = 0; col < widgetrec.cols; ++col) {\n        columns[bestcol + col] = widgetbottom;\n        columnitems[bestcol + col].push(widgetrec);\n      }\n\n\n      widgetrec.col = bestcol;\n      widgetrec.left = this.__leftoffset + (bestcol * columnwidth + (bestcol) * this.options.gutter_x);\n      widgetrec.top = ypos;\n\n      const styles = {\n        position: \"absolute\",\n        left: widgetrec.left, // 300 width, 10 px leftmargin, 20 inter\n        top: widgetrec.top + this.__padding.top\n        //, width:    columnwidth * widgetrec.cols + (widgetrec.cols-1) * this.options.gutter_x\n      };\n\n      if (this.options.debug)\n        console.log(\"Will be placed into col\", bestcol);\n\n      wnode.style.position = styles.position;\n      wnode.style.left = styles.left + \"px\";\n      wnode.style.top = styles.top + \"px\";\n    }\n\n    const maxheight = Math.max.apply(null, columns) + this.__padding.top + this.__padding.bottom;\n\n    //reorderWidgets(keepcolumnpos);\n    if (this.options.columnwidth)\n      this.container.style.width = (this.options.columnwidth * this.options.columns + (this.options.columns - 1) * this.options.gutter_x) + \"px\";\n\n    this.container.style.height = maxheight + \"px\";\n\n    /*\n    // Now we want our parents to know we have changed in size\n    // FIXME: add a check whether we actually changed in size\n    if (this.options.debug)\n      console.log(\"Firing layout change event\");\n\n    $wh.fireLayoutChangeEvent(this.container, \"up\"); // FIXME\n    */\n\n    if (this.options.debug) {\n      console.log(this.container, \"has\", visiblewidgetscount, \"visible widgets\");\n      console.groupEnd();\n    }\n\n    /*\n    store render information (can be used to add extra behaviour outside this class for example:\n    - to equalize heights of widgets by external code or hide a widgets grid\n    - to hide a widgets container in case it has no visible widgets\n    */\n    this.__itemdata = widgetrecs;\n    this.__columnwidth = columnwidth;\n    this.__height = maxheight;\n    this.__visiblewidgetscount = visiblewidgetscount;\n    this.__singlerow = singlerow;\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n// CSS Smooth scroll based on: http://wibblystuff.blogspot.in/2014/04/in-page-smooth-scroll-using-css3.html\n// With improvements from: http://codepen.io/kayhadrin/pen/KbalA\nexport default class SmoothScroll {\n  constructor(nodes, options) {\n    this.options = { translateAnchor: null, ...options };\n    for (const node of nodes) {\n      let href = node.getAttribute(\"href\");\n      if (href.indexOf(\"#\") >= 0) {\n        if (this.options.translateAnchor)\n          href = this.options.translateAnchor(href);\n\n        if (href) {\n          const target = document.getElementById(href.substr(href.indexOf(\"#\") + 1));\n          if (target) {\n            node.addEventListener(\"click\", event => {\n              event.preventDefault();\n              target.scrollIntoView({ block: \"start\", behavior: \"smooth\" });\n            });\n            target.setAttribute(\"data-scrollevent\", \"0\");\n          }\n        }\n      }\n    }\n  }\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./banner.scss\";\nimport * as dompack from \"dompack\";\n//import CarrouselSlideshow from \"@webhare/dompack-carrousel-slideshow\";\nimport CarrouselSlideshow from \"../slideshow/dompack-carrousel-slideshow\";\n\nwindow.__slideshows_banner = [];\n\n\nclass BannerSlideshowWidget {\n  constructor(widgetnode) {\n    this.widgetnode = widgetnode;\n\n    this.slides = widgetnode.querySelectorAll(\".carrousel__cell\");\n    if (this.slides.length < 2)\n      return;\n\n    window.__slideshows_banner.push(this);\n\n    this.slideshow =\n      new CarrouselSlideshow(widgetnode, {\n        jumpbuttons: \".banner__slidedot\",\n        jumpbutton_selectedclass: \"banner--activedot\",\n        autoplay: true,\n        eventPassthrough: true,\n        autoplay_freezeslideduration: 5000,\n        transitionDuration: 500,\n        updateviewportheight: true\n      });\n    //this.slideshow.carrousel.options.updateviewportheight = true;\n    //this.slideshow.carrousel.options.debugdimensions = true;\n\n    this.refresh();\n\n    //widgetnode.addEventListener(\"wh:activeslidechange\", this.onSlideChange.bind(this));\n  }\n\n  /*\n  onSlideChange(evt)\n  {\n    this.slides[evt.detail.previousactiveidx].classList.remove(\"active\");\n    this.slides[evt.detail.nextactiveidx].classList.add(\"active\");\n  }\n  */\n\n  refresh() {\n    for (const slide of this.slides)\n      slide.style.minHeight = \"\";\n\n    let largestheight = 0;\n    for (const slide of this.slides) {\n      const slideheight = slide.offsetHeight;\n      if (slideheight > largestheight)\n        largestheight = slideheight;\n    }\n\n    //console.log(\"Largest height\", largestheight);\n\n    for (const slide of this.slides)\n      slide.style.minHeight = largestheight + \"px\";\n\n    this.widgetnode.querySelector(\".banner__viewport\").style.height = largestheight + \"px\";\n  }\n}\n\nfunction refreshBannerSlideshowWidgets() {\n  for (const widget of window.__slideshows_banner)\n    widget.refresh();\n}\n\n\ndompack.register(\".embeddedobject--banner\",\n  widgetnode => new BannerSlideshowWidget(widgetnode)\n);\n\nwindow.addEventListener(\"resize\", refreshBannerSlideshowWidgets);\n\n// the browser (Especially Firefox) may not have loaded the CSS stylesheet yet,\n// so we need to refresh after load to make sure we use the correct height specified in CSS for the viewport width.\nwindow.addEventListener(\"load\", refreshBannerSlideshowWidgets);\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\n\nimport \"./figures-widgets.css\";\nimport \"./figures-widgets.scss\";\n\n\nfunction initProgressCircles(node) {\n  let animationsdone = false;//check of animation is done\n  if (document.documentElement.classList.contains(\"wh-widgetpreview\")) {\n    animationsdone = true;\n\n    const percentage = Math.round(1 * (node.getAttribute('data-percentage')));\n    const contoursize = 2 * Math.PI * 68; //radius 68\n    const circlenode = node.querySelector('.progresscircle__fill');\n    const percentagenode = node.querySelector('.percentage');\n\n    circlenode.style.strokeDashoffset = Math.round(contoursize - (contoursize * 0.01 * percentage) + 6);\n    percentagenode.innerHTML = Math.round(percentage);\n  }\n\n  node.addEventListener(\"wh:visibilitychange\", function (ev) {\n    if (animationsdone || !ev.detail.visible)\n      return;\n\n    const percentage = Math.round(1 * (node.getAttribute('data-percentage')));\n\n    const contoursize = 2 * Math.PI * 68; //radius 68\n    const circlenode = node.querySelector('.progresscircle__fill');\n\n    const duration = 1500;\n\n    const timestep = Math.round(duration / (2 * percentage));\n    let step = 0;\n    const percentagenode = node.querySelector('.percentage');\n    const t = setTimeout(updateDigits, timestep);\n\n    function updateDigits() {\n      step += 0.5;\n\n      circlenode.style.strokeDashoffset = Math.round(contoursize - (contoursize * 0.01 * step) + 6);\n      percentagenode.innerHTML = Math.round(step);\n      if (step < percentage)\n        setTimeout(updateDigits, timestep);\n    }\n\n    animationsdone = true;\n  });\n}\n\nfunction initProgressBars(node) {\n  let animationsdone = false;\n  if (document.documentElement.classList.contains(\"wh-widgetpreview\")) {\n    animationsdone = true;\n\n    const percentage = Math.round(1 * (node.getAttribute('data-percentage')));\n    node.querySelector('.progressbar__progress').style.width = percentage + '%';\n    const percentagenode = node.querySelector('.percentage');\n    percentagenode.innerHTML = percentage;\n  }\n\n  node.addEventListener(\"wh:visibilitychange\", function (ev) {\n    if (animationsdone || !ev.detail.visible)\n      return;\n\n    //animate progressbar percentage from 0 to actual percentage\n    const percentage = Math.round(1 * (node.getAttribute('data-percentage')));\n    node.querySelector('.progressbar__progress').style.width = percentage + '%';\n\n    const duration = 2000;\n\n    const timestep = Math.round(duration / percentage); //steps over 2000 secs\n    let step = 0;\n    const percentagenode = node.querySelector('.percentage');\n    const t = setTimeout(updateDigits, timestep);\n    function updateDigits() {\n      step++;\n      percentagenode.innerHTML = step;\n      if (step < percentage)\n        setTimeout(updateDigits, timestep);\n    }\n\n    animationsdone = true;\n  });\n}\n\nfunction initSegmentedCircle(basenode) {\n  //NOTE: IE does not support css transition animation on svg elements.\n  //      IE bug: classList is undefined on svg elements.\n  for (const node of basenode.querySelectorAll(\".path, .label\")) {\n    node.addEventListener(\"mouseover\", function () {\n      if (node.getAttribute(\"class\").indexOf(\"hover\") != -1)\n        return;\n\n      const sel_idx = 1 * (node.getAttribute(\"data-index\"));\n\n      for (const subnode of basenode.querySelectorAll(\".path, .label\")) {\n        const idx = 1 * (subnode.getAttribute(\"data-index\"));\n        if (idx == sel_idx)\n          subnode.setAttribute(\"class\", subnode.nodeName == \"path\" ? \"path hover\" : \"label hover\");\n        else\n          subnode.setAttribute(\"class\", subnode.nodeName == \"path\" ? \"path\" : \"label\");\n      }\n    });\n\n    node.addEventListener(\"mouseout\", function () {\n      if (node.getAttribute(\"class\").indexOf(\"hover\") == -1)\n        return;\n      const sel_idx = node.getAttribute(\"data-index\");\n      for (const selnode of basenode.querySelectorAll(\".path[data-index='\" + sel_idx + \"'], .label[data-index='\" + sel_idx + \"']\"))\n        selnode.setAttribute(\"class\", selnode.nodeName == \"path\" ? \"path\" : \"label\");\n    });\n  }\n\n  let animationsdone = false;\n  basenode.addEventListener(\"wh:visibilitychange\", function (ev) {\n    if (animationsdone || !ev.detail.visible)\n      return;\n\n    animationsdone = true;\n\n    //animate segments\n    const timeout = 500;\n    const labelnodes = basenode.querySelectorAll(\".label\");\n    for (const node of labelnodes) {\n      const idx = 1 * (node.getAttribute(\"data-index\"));\n\n      setTimeout(function () {\n\n        if (idx > 0) {\n          basenode.querySelector(\".path[data-index='\" + (idx - 1) + \"']\").setAttribute(\"class\", \"path\");\n          basenode.querySelector(\".label[data-index='\" + (idx - 1) + \"']\").classList.remove('hover');\n        }\n\n        node.classList.add('hover');\n        basenode.querySelector(\".path[data-index='\" + idx + \"']\").setAttribute(\"class\", \"path hover\");\n\n        basenode.clientWidth;//force css update\n\n        if (idx == labelnodes.length - 1) {\n          setTimeout(function () {\n            basenode.querySelector(\".path[data-index='\" + idx + \"']\").setAttribute(\"class\", \"path\");\n            basenode.querySelector(\".label[data-index='\" + idx + \"']\").classList.remove('hover');\n          }, timeout);\n        }\n\n      }, timeout * (idx + 1) - timeout * 0.5);\n\n    }\n\n\n  });\n}\n\nfunction initChart(node, chartnr) {\n  const chartdata = JSON.parse(node.getAttribute(\"data-chart\"));\n  if (!chartdata)\n    return;\n\n  const ispreview = document.documentElement.classList.contains(\"wh-widgetpreview\");\n\n  const rgbcolor = ColorStringToRGB(chartdata.color);//darkcolor\n\n  const labels = chartdata.values[0].col;\n  const nrvalues = labels.length - 1;\n  const nrgroups = chartdata.values.length - 1;\n  if (nrgroups <= 0)\n    return;\n\n  const chartnode = node.querySelector(\".chart__area\");\n  const legendanode = node.querySelector(\".chart__legend\");\n  const chartsize = { \"x\": 545, \"y\": 200 };//preview has problems getting correct width/height\n  // let chartsize = { \"x\" : chartnode.clientWidth, \"y\" : chartnode.clientHeight };\n\n  const hintervalwidth = chartsize.x / nrvalues;\n\n  for (let i = 0; i < labels.length; i++) {\n    const labelnode = document.createElement(\"span\");\n    labelnode.innerHTML = labels[i];\n\n    if (i > 0) { //horizontal axis values\n      labelnode.className = \"vlabel\";\n      labelnode.setAttribute(\"style\", \"left:\" + ((i - 1) * hintervalwidth) + \"px;width:\" + hintervalwidth + \"px;\");\n    } else if (labels[i] != \"\") { //horizontal axis label on bottom right\n      labelnode.className = \"htitle\";\n    }\n    chartnode.appendChild(labelnode);\n  }\n\n  //get max value for scale calculations\n  let valuesmax = 0;\n  let valuesmin = 0;\n  for (let c = 1; c < chartdata.values.length; c++) {\n    for (let i = 1; i < chartdata.values[c].col.length; i++) {\n      if (valuesmax < 1 * chartdata.values[c].col[i])\n        valuesmax = 1 * chartdata.values[c].col[i];\n\n      if (valuesmin > 1 * chartdata.values[c].col[i])\n        valuesmin = 1 * chartdata.values[c].col[i];\n    }\n  }\n\n  if (valuesmin < 0)\n    node.classList.add('chart--negativevalues');\n\n  const hlinescount = 5;//nr of horizontal gridlines to display\n\n  //calculate nice factor for dividing values over vertical axis\n  let hspacesteps = (valuesmax - valuesmin) / hlinescount;\n  const precisionfactor = Math.floor(Math.log(hspacesteps) / Math.log(10));\n  hspacesteps = Math.pow(10, precisionfactor);\n\n  valuesmax = hspacesteps * Math.ceil(valuesmax / hspacesteps);\n  valuesmin = hspacesteps * Math.floor(valuesmin / hspacesteps);\n\n  const hvaluestep = (valuesmax - valuesmin) / hlinescount;\n  let labelwidth = 0;\n  let haszeroline;\n  for (let v = 0; v <= hlinescount; v++) { //draw horizontal lines and labels\n    let yvalue = (valuesmax - hvaluestep * v);\n    haszeroline = !haszeroline && yvalue == 0;\n\n    const hnode = document.createElement(\"div\");\n    hnode.className = \"hline\" + (yvalue == 0 ? \" hline--zero\" : \"\");\n    hnode.setAttribute(\"style\", \"top:\" + ((100 / hlinescount) * v) + \"%;\");\n\n    yvalue = parseFloat(yvalue.toFixed(precisionfactor + 1));\n    let vlabelnode;\n    if (yvalue != 0) {\n      vlabelnode = document.createElement(\"span\");\n      vlabelnode.className = \"label\";\n      vlabelnode.innerHTML = yvalue;\n      hnode.appendChild(vlabelnode);\n    }\n\n    chartnode.appendChild(hnode);\n\n    if (vlabelnode && v == 0)\n      labelwidth = vlabelnode.clientWidth + 5;//used for aligning axis title. Add 5px margin\n  }\n\n  if (!haszeroline) {\n    const hnode = document.createElement(\"div\");\n    hnode.className = \"hline hline--zero\";\n    hnode.setAttribute(\"style\", \"top:\" + (valuesmax * 100 / (valuesmax - valuesmin)) + \"%;\");\n    chartnode.appendChild(hnode);\n  }\n\n  if (chartdata.vtitle) { //title vertical axis\n    const vtitlenode = document.createElement(\"span\");\n    vtitlenode.className = \"vtitle\";\n    vtitlenode.innerHTML = chartdata.vtitle;\n    vtitlenode.setAttribute(\"style\", \"margin-left:-\" + labelwidth + \"px;\");\n    chartnode.appendChild(vtitlenode);\n  }\n\n  if (node.classList.contains(\"chart--linechart\")) { //draw svg linechart\n    const svgnode = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n    svgnode.setAttribute(\"width\", \"100%\");\n    svgnode.setAttribute(\"height\", \"100%\");\n\n    const scaley = chartsize.y / (valuesmax - valuesmin);\n    for (let c = 1; c < chartdata.values.length; c++) {\n      const opacity = c * (1 / nrgroups);\n      let svgpath = \"\";\n      const linenode = document.createElementNS(\"http://www.w3.org/2000/svg\", \"path\");\n      for (let i = 0; i < chartdata.values[c].col.length; i++) {\n        const colval = chartdata.values[c].col[i];\n        if (i > 0) {\n          const x = (hintervalwidth * (i - 1)) + (hintervalwidth / 2);\n          const y = chartsize.y - scaley * (1 * colval - valuesmin);\n\n          svgpath += (i == 1 ? \"M\" : \" L\") + RoundValue(x, 2) + \" \" + RoundValue(y, 2);\n          if (i == chartdata.values[c].col.length - 1) {\n            linenode.setAttribute(\"d\", svgpath);\n            linenode.setAttribute(\"stroke\", RGBaToColorString(rgbcolor.r, rgbcolor.g, rgbcolor.b, opacity));\n            linenode.setAttribute(\"stroke-width\", 2);\n            linenode.setAttribute(\"fill\", \"none\");\n            linenode.setAttribute(\"data-id\", \"chart\" + chartnr + \"_\" + c);\n            svgnode.appendChild(linenode);\n\n            if (!ispreview) {\n              linenode.addEventListener(\"mouseover\", function () {\n                const hoverid = this.getAttribute(\"data-id\");\n                if (hoverid == node.getAttribute(\"data-hover\"))\n                  return;\n                this.setAttribute(\"stroke-width\", 3);\n                node.setAttribute(\"data-hover\", hoverid);\n\n                const legendalabel = node.querySelector(\".chart__legend > div:nth-child(\" + c + \")\");\n                if (legendalabel)\n                  legendalabel.classList.add(\"label--hover\");\n              });\n              linenode.addEventListener(\"mouseout\", function () {\n                this.setAttribute(\"stroke-width\", 2);\n                const legendalabel = node.querySelector(\".chart__legend > div:nth-child(\" + c + \")\");\n                if (legendalabel)\n                  legendalabel.classList.remove(\"label--hover\");\n\n                const hoverid = this.getAttribute(\"data-id\");\n                if (hoverid == node.getAttribute(\"data-hover\"))\n                  node.setAttribute(\"data-hover\", \"\");\n              });\n            }\n          }\n\n          const pointnode = document.createElement(\"div\");\n          pointnode.className = \"point\";\n          pointnode.setAttribute(\"style\", \"left:\" + x + \"px;top:\" + y + \"px;border-color:\" + RGBaToColorString(rgbcolor.r, rgbcolor.g, rgbcolor.b, opacity) + \";\");\n          chartnode.appendChild(pointnode);\n\n          if (!ispreview) {\n            const valuenode = document.createElement(\"span\");\n            valuenode.className = \"value\";\n            valuenode.innerHTML = RoundValue(1 * colval, chartdata.decimals);\n            pointnode.appendChild(valuenode);\n            valuenode.setAttribute(\"style\", \"margin-left:\" + (-0.5 * valuenode.clientWidth) + \"px;background-color:\" + chartdata.color + \";border-color:\" + chartdata.color + \";\"); //center valuenode (on top of point)\n\n            pointnode.addEventListener(\"mouseover\", function () {\n              const hoverid = linenode.getAttribute(\"data-id\");\n              if (hoverid == node.getAttribute(\"data-hover\"))\n                return;\n              linenode.setAttribute(\"stroke-width\", 3);\n              node.setAttribute(\"data-hover\", hoverid);\n\n              const legendalabel = node.querySelector(\".chart__legend > div:nth-child(\" + c + \")\");\n              if (legendalabel)\n                legendalabel.classList.add(\"label--hover\");\n            });\n\n            pointnode.addEventListener(\"mouseout\", function () {\n              linenode.setAttribute(\"stroke-width\", 2);\n              const legendalabel = node.querySelector(\".chart__legend > div:nth-child(\" + c + \")\");\n              if (legendalabel)\n                legendalabel.classList.remove(\"label--hover\");\n\n              const hoverid = linenode.getAttribute(\"data-id\");\n              if (hoverid == node.getAttribute(\"data-hover\"))\n                node.setAttribute(\"data-hover\", \"\");\n            });\n          }\n        } else {\n          const infonode = document.createElement(\"div\");\n          infonode.setAttribute(\"data-id\", \"chart\" + chartnr + \"_\" + c);\n          infonode.className = \"label\";\n          infonode.innerHTML = colval;\n\n          const bulletnode = document.createElement(\"span\");\n          bulletnode.className = \"bullet\";\n          bulletnode.setAttribute(\"style\", \"background-color:\" + RGBaToColorString(rgbcolor.r, rgbcolor.g, rgbcolor.b, opacity) + \";\");\n\n          infonode.appendChild(bulletnode);\n          legendanode.appendChild(infonode);\n\n          if (!ispreview) {\n            infonode.addEventListener(\"mouseover\", function () {\n              const hoverid = this.getAttribute(\"data-id\");\n              if (hoverid == node.getAttribute(\"data-hover\"))\n                return;\n              this.classList.add(\"label--hover\");\n              node.setAttribute(\"data-hover\", hoverid);\n\n              const line = node.querySelector(\"svg > path:nth-child(\" + c + \")\");\n              if (line)\n                line.setAttribute(\"stroke-width\", 3);\n\n            });\n\n            infonode.addEventListener(\"mouseout\", function () {\n              this.classList.remove(\"label--hover\");\n\n              const line = node.querySelector(\"svg > path:nth-child(\" + c + \")\");\n              if (line)\n                line.setAttribute(\"stroke-width\", 2);\n\n              const hoverid = this.getAttribute(\"data-id\");\n              if (hoverid == node.getAttribute(\"data-hover\"))\n                node.setAttribute(\"data-hover\", \"\");\n            });\n          }\n\n        }\n      }\n    }\n\n    chartnode.appendChild(svgnode);\n  } else { //barchart, just plain html\n\n    const groupoffset = -0.5 * (12 * nrgroups + 5 * (nrgroups - 1));//width of bars is 12px, 5px margin between grouped bars\n\n    const barnodes = [];\n    for (let c = 1; c < chartdata.values.length; c++) {\n      const opacity = c * (1 / nrgroups);\n\n      for (let i = 0; i < chartdata.values[c].col.length; i++) {\n        const colval = chartdata.values[c].col[i];\n        if (i > 0) {\n          const percentage = Math.abs(100 * colval / (valuesmax - valuesmin));\n          const left = (i - 1) * hintervalwidth + (hintervalwidth / 2);\n\n          const barheight = ispreview ? percentage : 0;\n          let stylstr = \"left:\" + left + \"px;height:\" + barheight + \"%;\"; //height will be animated later\n          stylstr += \"margin-left:\" + (groupoffset + (c - 1) * 17) + \"px;\"; //17 = 12 + 5 (bar-width + margin)\n          stylstr += \"background-color:\" + RGBaToColorString(rgbcolor.r, rgbcolor.g, rgbcolor.b, opacity) + \";\";\n\n          const barnode = document.createElement(\"div\");\n          barnode.setAttribute(\"data-id\", \"chart\" + chartnr + \"_\" + c);\n          barnode.className = \"bar\";\n          barnode.setAttribute(\"style\", stylstr);\n\n          if (valuesmin < 0) {\n            if (colval < 0) {\n              barnode.style.bottom = 'auto';\n              barnode.style.top = 100 * valuesmax / (valuesmax - valuesmin) + '%';\n            } else\n              barnode.style.bottom = -100 * valuesmin / (valuesmax - valuesmin) + '%';\n          }\n\n          chartnode.appendChild(barnode);\n          barnodes.push({ \"node\": barnode, \"percentage\": percentage, \"value\": colval });\n\n\n          if (!ispreview) {\n            const valuenode = document.createElement(\"span\");\n            valuenode.className = \"value\";\n            valuenode.innerHTML = RoundValue(1 * colval, chartdata.decimals);\n            valuenode.setAttribute(\"style\", \"background-color:\" + chartdata.color + \";border-color:\" + chartdata.color + \";\");\n            barnode.appendChild(valuenode);\n\n            //center valuenode (on top of bar)\n            valuenode.style.marginLeft = (-0.5 * valuenode.clientWidth) + \"px\";\n\n            barnode.addEventListener(\"mouseover\", function () {\n              const hoverid = this.getAttribute(\"data-id\");\n              if (hoverid == node.getAttribute(\"data-hover\"))\n                return;\n              this.setAttribute(\"stroke-width\", 3);\n              node.setAttribute(\"data-hover\", hoverid);\n\n              const legendalabel = node.querySelector(\".chart__legend > div:nth-child(\" + c + \")\");\n              if (legendalabel)\n                legendalabel.classList.add(\"label--hover\");\n            });\n            barnode.addEventListener(\"mouseout\", function () {\n              this.setAttribute(\"stroke-width\", 2);\n              const legendalabel = node.querySelector(\".chart__legend > div:nth-child(\" + c + \")\");\n              if (legendalabel)\n                legendalabel.classList.remove(\"label--hover\");\n\n              const hoverid = this.getAttribute(\"data-id\");\n              if (hoverid == node.getAttribute(\"data-hover\"))\n                node.setAttribute(\"data-hover\", \"\");\n            });\n          }\n\n        } else {\n          const infonode = document.createElement(\"div\");\n          infonode.setAttribute(\"data-id\", \"chart\" + chartnr + \"_\" + c);\n          infonode.className = \"label\";\n          infonode.innerHTML = colval;\n\n          const bulletnode = document.createElement(\"span\");\n          bulletnode.className = \"bullet\";\n          bulletnode.setAttribute(\"style\", \"background-color:\" + RGBaToColorString(rgbcolor.r, rgbcolor.g, rgbcolor.b, opacity) + \";\");\n\n          infonode.appendChild(bulletnode);\n          legendanode.appendChild(infonode);\n        }\n      }\n    }\n\n    let animationsdone = false;\n    node.addEventListener(\"wh:visibilitychange\", function (ev) {\n      if (animationsdone || !ev.detail.visible)\n        return;\n\n      //barchart animation\n      for (let i = 0; i < barnodes.length; i++)\n        barnodes[i].node.style.height = barnodes[i].percentage + \"%\";\n\n      animationsdone = true;\n    });\n  }\n}\n\n\n\n\n\n/* Helper functions */\n\nfunction RoundValue(number, decimalplaces) {//round value with given decimals\n  if (decimalplaces > 0) {\n    const multiply1 = Math.pow(10, (decimalplaces + 4));\n    const divide1 = Math.pow(10, decimalplaces);\n    return Math.round(Math.round(number * multiply1) / 10000) / divide1;\n  }\n  if (decimalplaces < 0) {\n    const divide2 = Math.pow(10, Math.abs(decimalplaces));\n    const multiply2 = Math.pow(10, Math.abs(decimalplaces));\n    return Math.round(Math.round(number / divide2) * multiply2);\n  }\n  return Math.round(number);\n}\n\n\nfunction ColorStringToRGB(colorstr) { //convert color hex string to RGB values\n  colorstr = colorstr.toUpperCase().replace(/[^0-9A-F]/g, \"\");\n  const color = {\n    r: parseInt(colorstr.substr(0, 2), 16),\n    g: parseInt(colorstr.substr(2, 2), 16),\n    b: parseInt(colorstr.substr(4, 2), 16)\n  };\n  return color;\n}\n\nfunction RGBaToColorString(r, g, b, a) { //convert rgba to rgb string based on white background\n  // basic calculation: RGB.red = Math.round((RGBA.alpha * (RGBA.red / 255) + (alpha * (bg.red / 255))) * 255);\n  const alpha = 1 - a;\n  r = Math.round((a * (r / 255) + alpha) * 255);\n  g = Math.round((a * (g / 255) + alpha) * 255);\n  b = Math.round((a * (b / 255) + alpha) * 255);\n\n  return \"#\" + (r < 16 ? \"0\" : \"\") + r.toString(16) + (g < 16 ? \"0\" : \"\") + g.toString(16) + (b < 16 ? \"0\" : \"\") + b.toString(16);\n}\n\n\n\n//dompack.register('.embeddedobject__sharelink', initEmbeddedObjectShare);\ndompack.register('.segmentedcircle', initSegmentedCircle);\ndompack.register('.progressbar', initProgressBars);\ndompack.register('.progresscircle', initProgressCircles);\n\n//ADDME: Get rid of load event necessity\nwindow.addEventListener(\"load\", () => {\n  dompack.register('.chart', initChart, { waitEmbedded: true });\n\n  //Force scroll update incase scroll event was triggered before element is initialized\n  dompack.dispatchCustomEvent(window, \"scroll\", { bubbles: true, cancelable: false });\n});\n","import \"./linkspercategory_tabs.css\";\nimport * as dompack from \"@webhare/dompack\";\n\ndeclare global {\n  interface Window {\n    widgets_lpct: Array<LinksPerCategoryWidget>;\n    refreshit?: () => void;\n  }\n}\n\nwindow.widgets_lpct = [];\n\nconst offsety = -60; // scroll a little further up so we keep the tabs in view (for context)\n\nclass LinksPerCategoryWidget {\n  container: HTMLElement;\n  pointer: HTMLElement;\n  categorylist: HTMLElement;\n  contentpanel: HTMLElement;\n  constructor(widget: HTMLElement) {\n    window.widgets_lpct.push(this);\n\n    this.container = widget;\n    this.pointer = dompack.qR(this.container, \".widget-lpct__pointer\");\n    this.categorylist = dompack.qR(this.container, \".widget-lpct__categorylist\"); // tabs\n    this.contentpanel = dompack.qR(this.container, \".widget-lpct__categoriespanel\");\n\n    this.container.addEventListener(\"click\", evt => this.doCheckForTabClick(evt));\n\n    this.refresh();\n    dompack.qR(this.pointer, \"path\").style.display = \"\"; // remove the \"display: none;\" in the template\n  }\n\n  doCheckForTabClick(evt: MouseEvent) {\n    const tab = (evt.target as HTMLElement).closest(\".widget-lpct__categorylist__item\") as HTMLElement;\n    if (!tab)\n      return;\n\n    const tabs = dompack.qSA(this.container, \".widget-lpct__categorylist__item\");\n    const contentpanels = dompack.qSA(this.container, \".widget-lpct__category\");\n\n    for (const tabnode of tabs) {\n      tabnode.setAttribute(\"aria-expanded\", \"false\");\n      tabnode.classList.remove(\"widget-lpct__categorylist__item--active\");\n      tabnode.classList.remove(\"widget-lpct__categorylist__item--activeinitial\");\n    }\n\n    for (const cnode of contentpanels) {\n      cnode.classList.remove(\"widget-lpct__category--active\");\n      cnode.classList.remove(\"widget-lpct__category--activeinitial\");\n      cnode.hidden = true;\n    }\n\n    // Mark the selected tab as active\n    tab.setAttribute(\"aria-expanded\", \"true\");\n    tab.classList.add(\"widget-lpct__categorylist__item--active\");\n\n    // Mark the associated content panel as active\n    const idx = Array.from(tabs).indexOf(tab);\n    contentpanels[idx].classList.add(\"widget-lpct__category--active\");\n    contentpanels[idx].hidden = false;\n\n    const contentpanelbounds = contentpanels[idx].getBoundingClientRect();\n\n    const tabsbounds = this.categorylist.getBoundingClientRect();\n    const bodybounds = document.documentElement.getBoundingClientRect();\n\n    if (tabsbounds.top < 0 || contentpanelbounds.top > bodybounds.height * 0.75) {\n      const scrolltoy = tabsbounds.top - bodybounds.top + offsety;\n      window.scrollTo({ top: scrolltoy, behavior: 'smooth' });\n    }\n\n    pointCurveFromTo(this.pointer, tab, this.contentpanel);\n  }\n\n  refresh() {\n    let activetab = dompack.qS(this.container, \".widget-lpct__categorylist__item--active\");\n    if (!activetab)\n      activetab = dompack.qS(this.container, \".widget-lpct__categorylist__item--activeinitial\");\n    if (activetab)\n      pointCurveFromTo(this.pointer, activetab, this.contentpanel);\n  }\n}\n\n\nfunction pointCurveFromTo(curve: HTMLElement, startnode: HTMLElement, endnode: HTMLElement) {\n  const pointerrect = curve.getBoundingClientRect();\n  const startnoderect = startnode.getBoundingClientRect();\n  const endnoderect = endnode.getBoundingClientRect();\n\n  const topy = startnoderect.top - pointerrect.top + startnoderect.height / 2;\n  const bottomy = endnoderect.top - pointerrect.top + endnoderect.height / 2;\n\n  const pathwidth = pointerrect.width;\n  const pathheight = bottomy - topy;\n  const abspathheight = pathheight < 0 ? -pathheight : pathheight;\n\n  let curveradiusx = 15;\n  const curveradiusy = 15;\n\n  if (curveradiusx * 2 > pathwidth)\n    curveradiusx = curveradiusx / 2;\n\n  // if the item we point to is almost aligned with the category we need\n  // to squeze the radius to fit within the vertical space we have\n  if (curveradiusy * 2 > abspathheight) {\n    /*\n    Option 1: - shrink the curve to fit\n    curveradiusy = curveradiusy / 2;\n    */\n\n    // Draw a simple horizontal line\n    dompack.qR(curve, \"path\").setAttribute(\"d\", `M0,${topy} ${pathwidth},${topy}`);\n    return;\n  }\n\n  const x0 = 0;\n  const x1 = pathwidth / 2 - curveradiusx;\n  const x2 = pathwidth / 2; // middle\n  const x3 = pathwidth / 2 + curveradiusx;\n  const x4 = pathwidth;\n\n  const y0 = topy;\n  const y1 = topy + (pathheight < 0 ? -curveradiusy : curveradiusy);\n  const y2 = bottomy - (pathheight < 0 ? -curveradiusy : curveradiusy);\n  const y3 = bottomy;\n\n  /*\n  let path = `M${x0} ${y0} L${x1} ${y0}\n              L${x2} ${y1}\n              L${x2} ${y2}\n              L${x3} ${y3}\n              L${x4} ${y3}\n             `;\n  */\n\n  const path = `M${x0} ${y0}\n              L${x1} ${y0}\n              C${x2},${y0} ${x2},${y1} ${x2},${y1}\n              L${x2} ${y2}\n              C${x2},${y3} ${x3},${y3} ${x3},${y3}\n              L${x4} ${y3}\n             `;\n  dompack.qR(curve, \"path\").setAttribute(\"d\", path);\n}\n\n\nfunction refreshWidgets() {\n  for (const widget of window.widgets_lpct)\n    widget.refresh();\n}\nwindow.refreshit = refreshWidgets;\n\ndompack.register(\".widget-lpct\", node => new LinksPerCategoryWidget(node));\n\nwindow.addEventListener(\"load\", () => refreshWidgets());\nwindow.addEventListener(\"ws:resize\", () => refreshWidgets());\n","import \"./newsevents.scss\";\nimport * as dompack from \"@webhare/dompack\";\n\ntype NewsStoryItemType = {\n  type: string;\n  title: string;\n  articleintro: string;\n  url: string;\n  embedphotolink: string;\n  embedphotolink_2x: string;\n  photoalt: string;\n  tags: Array<{ bgcolor: string; class: string; data: { link: string }; tag: string }>;\n};\n\ntype EventItemType = {\n  title: string;\n  url: string;\n  embedphotolink: string;\n  embedphotolink_2x: string;\n  photoalt: string;\n  tags: Array<{ bgcolor: string; class: string; data: { link: string }; tag: string }>;\n  category: string;\n  date: string;\n  eventdate: {\n    startdate: { day: string; month: string };\n    enddate: { day: string; month: string };\n  };\n  icon: string;\n  infocusphotolink: string;\n  infocusphotolink_2x: string;\n  location: string;\n  suburl: string;\n  widgetdate: string;\n};\n\ntype NewsEventsResultsType = {\n  [publoc: string]: {\n    items: Array<NewsStoryItemType | EventItemType>;\n  };\n};\n\nclass renderNewsAndEvents {\n  node: HTMLElement;\n  listContainer: HTMLUListElement;\n  options: {\n    type: \"news-stories\" | \"stories\" | \"news\" | \"event\";\n    publoc: number;\n    publocfile: string;\n  };\n  constructor(node: HTMLElement) {\n    this.node = node;\n    this.listContainer = dompack.qR(this.node, \".widget-newsevents__list\");\n    this.options = JSON.parse(this.node.dataset.options as string);\n    void this.getItems();\n  }\n\n  async getItems() {\n    let response;\n    try {\n      response = await fetch(this.options.publocfile, { cache: 'reload' });\n    } catch (e) { }\n\n    if (response && response.status === 200) {\n      const res = await response.json() as NewsEventsResultsType;\n      const items = res && res[\"p\" + this.options.publoc] ? res[\"p\" + this.options.publoc].items : [];\n      if (!items.length) {\n        this.listContainer.remove();\n        this.node.classList.add(\"noresults\");\n        return;\n      }\n\n      this.node.dataset.itemcount = String(items.length);\n      // If widget-newsevents component with 2 or less events, fallback to content area width!\n      if (this.node.classList.contains(\"widget-newsevents--event\") && items.length < 3)\n        this.node.classList.add(\"widget-newsevents--contentwidth\");\n\n      if (this.options.type === \"event\")\n        this.listContainer.append(...this.renderEvent(items as Array<EventItemType>));\n      else\n        this.listContainer.append(...this.renderNewsStories(items as Array<NewsStoryItemType>));\n    }\n  }\n\n  renderEvent(items: Array<EventItemType>) {\n    return items.map(item => <li class=\"widget-newsevents__item\">\n      <a class=\"widget-newsevents__item__link\" href={item.url} target=\"_blank\" rel=\"noreferrer\">\n        <div class=\"widget-newsevents__item__image\">\n          {item.embedphotolink ?\n            <img src={item.embedphotolink} srcset={item.embedphotolink_2x} alt={item.photoalt} loading=\"lazy\" />\n            : null\n          }\n          {item.eventdate.startdate ?\n            <div class=\"widget-newsevents__item__eventdate\">\n              <div class=\"widget-newsevents__item__eventdate__start\" data-day={item.eventdate.startdate.day} data-month={item.eventdate.startdate.month}></div>\n              {item.eventdate.enddate ? <div class=\"widget-newsevents__item__eventdate__end\" data-day={item.eventdate.enddate.day} data-month={item.eventdate.enddate.month}></div> : null}\n            </div>\n            : null\n          }\n        </div>\n        <div class=\"widget-newsevents__item__content\">\n          {item.category ?\n            <div class=\"widget-newsevents__item__category\">\n              {item.icon ? <i class={item.icon} aria-hidden=\"true\"></i> : null}\n              <span>{item.category}</span>\n            </div>\n            : null\n          }\n          <div class=\"widget-newsevents__item__title\">{item.title}</div>\n          {item.location ?\n            <div class=\"widget-newsevents__item__location\">{item.location}</div>\n            : null\n          }\n        </div>\n      </a>\n    </li>);\n  }\n\n  renderNewsStories(items: Array<NewsStoryItemType>): Array<HTMLLIElement> {\n    return items.map(item => <li class=\"widget-newsevents__item\">\n      <a class=\"widget-newsevents__item__link\" href={item.url} target=\"_blank\" rel=\"noreferrer\">\n        <div class=\"widget-newsevents__item__image\">\n          {item.embedphotolink ?\n            <img src={item.embedphotolink} srcset={item.embedphotolink_2x} alt={item.photoalt} loading=\"lazy\" />\n            : null\n          }\n        </div>\n        <div class=\"widget-newsevents__item__content\">\n          <div class=\"widget-newsevents__item__title\">{item.title}</div>\n          <div class=\"widget-newsevents__item__descriptionwrapper\">\n            <div class=\"widget-newsevents__item__description\">{item.articleintro}</div>\n          </div>\n          {item.tags.length ?\n            <div class=\"widget-newsevents__item__tags\">\n              {item.tags.map(tag =>\n                <span class={tag.class} style={{ backgroundColor: tag.bgcolor }} onClick={(ev: Event) => this.onTagClick(ev, tag.data.link)}>{tag.tag}</span>\n              )}\n            </div>\n            : null\n          }\n        </div>\n      </a>\n    </li>);\n  }\n\n  onTagClick(ev: Event, url: string) {\n    ev.preventDefault();\n    window.open(url, \"_blank\", \"noopener\");\n  }\n}\n\ndompack.register(\".widget-newsevents\", node => new renderNewsAndEvents(node));\n","import { addDocEventListener, flagUIBusy, getLang, loadCSS, loadScript, register } from \"@webhare/dompack\";\nimport \"./sam-chat.css\";\n\ndeclare global {\n  interface Window {\n    sam?: {\n      showChat(languageHint: string, programmeIdHint: string): void;\n    };\n    samConfig?: {\n      apiUrl: string;\n    };\n  }\n}\n\nlet loadPromises;\n\nasync function startChat(node: HTMLButtonElement) {\n  //eg. localStorage.samRootUrl = \"https://sites.moe.sf.webhare.dev/repository/utwente-data/psa/v2\";\n  const samRootUrl = localStorage.samRootUrl || \"https://www.utwente.nl/repository/utwente-data/psa/v2\";\n  const langHint = node.dataset.languageHint || (getLang()?.language?.toUpperCase()) || \"EN\";\n  const programHint = node.dataset.programHint || document.documentElement.dataset.programme || \"\";\n  using lock = flagUIBusy({ modal: true });\n  void (lock);\n\n  //we currently have the API installed globally (all URLs). If we need to limit access ensure CORS is set up\n  //ensure configurl is set before loading the script\n  window.samConfig = { apiUrl: `${location.origin}/.utwente_voorlichting/leads/api` };\n  loadPromises ||= [\n    loadScript(`${samRootUrl}/app.js`, { module: true }),\n    loadCSS(`${samRootUrl}/styles.css`)\n  ];\n\n  console.log(`startChat`, { ...window.samConfig, langHint, programHint });\n\n  await Promise.all(loadPromises);\n\n  //sanity check.\n  if (!window.sam)\n    throw new Error(\"'sam' object not found in window\");\n\n  window.sam.showChat(langHint, programHint);\n}\n\nregister<HTMLButtonElement>(\"button.widget-sam-chat__button--chat\", node => addDocEventListener(node, \"click\", () => startChat(node)));\n","import \"./photoalbum.css\";\nimport * as dompack from \"@webhare/dompack\";\nimport { PhotosOverlay, type photoOverlayType } from \"../../shared/photosoverlay/photosoverlay\";\n\nclass PhotoAlbumWidget {\n  node: HTMLElement;\n  items: HTMLElement[] = [];\n  timer: ReturnType<typeof setTimeout> | undefined;\n  overlay?: PhotosOverlay;\n  constructor(node: HTMLElement) {\n    this.node = node;\n    this.node.addEventListener(\"click\", ev => this.onClick(ev));\n    this.items = dompack.qSA(node, \".widget-photoalbum__item\");\n\n    window.addEventListener(\"resize\", () => this.onResize());\n    window.addEventListener(\"load\", () => this.onResize());\n    this.onResize();\n  }\n\n  onResize() {\n    clearTimeout(this.timer);\n    this.timer = setTimeout(() => this.doJustify(), 150); // debounce\n  }\n\n  onClick(ev: MouseEvent) {\n    const item = (ev.target as HTMLElement).closest(\".widget-photoalbum__item\");\n    if( item ) {\n      const data = this.node.getAttribute(\"data-images\");\n      if( data ) {\n        if( !this.overlay )\n          this.overlay = new PhotosOverlay(JSON.parse(data) as photoOverlayType);\n\n        const idx = this.items.findIndex(_ => _ === item);\n        this.overlay.showOverlay(idx);\n      }\n    }\n  }\n\n  doJustify() {\n    this.node.classList.remove(\"widget-photoalbum--justified\");\n    const rows: {item: HTMLElement; w: number}[][] = [];\n    const maxWidth = this.node.clientWidth;\n    let w = 0;\n    rows.push([]);// first row\n    this.items.forEach(item => {\n      item.style.maxWidth = \"\"; // reset max width to get natural width\n      if( w < maxWidth ) { // Add to current row\n        const itemWidth = item.clientWidth;\n        if( itemWidth ) {\n          item.dataset.col = w === 0 ? \"first\" : \"\";\n          rows[rows.length - 1]?.push({item, w: itemWidth});\n        }\n        w += itemWidth;\n      } else { // new row\n        rows.push([]);\n        const itemWidth = item.clientWidth;\n        if( itemWidth ) {\n          item.dataset.col = \"first\";\n          rows[rows.length - 1]?.push({item, w: itemWidth});\n        }\n        w = itemWidth;\n      }\n    });\n\n    rows.forEach((row, rowidx) => {\n      const totalWidth = row.reduce((sum, item) => sum + item.w, 0);\n      row.forEach(item => {\n        item.item.dataset.row = rowidx === 0 ? \"first\" : (rowidx === rows.length - 1 ? \"last\" : \"\");\n        item.item.style.maxWidth = `${item.w*100 / totalWidth}%`;\n      });\n    });\n    this.node.classList.add(\"widget-photoalbum--justified\");\n  }\n}\n\ndompack.register(\".widget-photoalbum\", node => new PhotoAlbumWidget(node));\n","import \"./photosoverlay.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { SwipeDetect, type swipeInfo } from \"../swipedetect\";\nimport { utDialog2 } from '../forms/dialogs';\nimport { getTid } from \"@webhare/gettid\";\n\nexport type photoOverlayType = {\n  title?: string;\n  items: photoType[];\n};\n\nexport type previewPhoto = {\n  mediaMinSize: number; // Used for media queries\n  link: string;\n  width: number;\n  height: number;\n  dominantColor: string | null;\n  objectPosition: string | null;\n};\n\ntype photoType = {\n  link?: string;\n  filename?: string;\n  title: string;\n  video?: { link: string; poster?: string; mediatype?: string } | null;\n  scaledImages: previewPhoto[];\n};\n\nconst _transitionDuration = 500; // This should match the duration of the CSS transition for the fading effect when switching images\n\nexport class PhotosOverlay {\n  data: photoOverlayType;\n  overlay: HTMLElement | null = null;\n\n  constructor(data: photoOverlayType) {\n    this.data = data;\n  }\n\n  onKeyUp(ev: KeyboardEvent) {\n    if (ev.code === \"ArrowLeft\")\n      this.previousImage();\n    else if (ev.code === \"ArrowRight\")\n      this.nextImage();\n  }\n\n  showOverlay(selectedidx: number) {\n    if (!selectedidx || selectedidx < 0)\n      selectedidx = 0;\n    else if (selectedidx >= this.data.items.length)\n      selectedidx = this.data.items.length - 1;\n\n    const totalcount = this.data.items.length;\n\n    this.overlay = <div tabindex=\"0\" class=\"photosoverlay\">\n      {this.data.title ? <div class=\"photosoverlay__title\">{this.data.title}</div> : null}\n\n      <ul class=\"photosoverlay__list\">\n        {this.data.items.map((photo, idx) => {\n          const imagenode =\n            <li class=\"photosoverlay__item\">\n              <div class=\"photosoverlay__item__header\">\n                {photo.title\n                  ? <div class=\"photosoverlay__item__title\" id={\"photooverlay-caption-\" + idx}>{photo.title}</div>\n                  : null\n                }\n                {photo.filename && photo.link ? <a href={photo.link} class=\"photosoverlay__item__download UT-icon-UT_icon_17_download-24px\" download={photo.filename} aria-label={\"Download \" + photo.filename}></a> : null}\n              </div>\n              {photo.video ? this.renderVideo(photo, idx === selectedidx) : this.renderPicture(photo)}\n              <div class=\"photosoverlay__item__footer\">\n                {<div class=\"photosoverlay__item__counter\">{idx + 1 + \"/\" + totalcount}</div>}\n              </div>\n            </li>;\n\n          if (photo.title)\n            imagenode.setAttribute(\"aria-labelledby\", \"photooverlay-caption-\" + idx);\n          imagenode.setAttribute(\"role\", photo.title ? \"figure\" : \"presentation\");\n          imagenode.classList.toggle(\"photosoverlay__item--selected\", idx === selectedidx);\n\n          return imagenode;\n        })}\n      </ul>\n\n      <button type=\"button\" tabindex=\"0\" class=\"photosoverlay__previous\" onClick={() => this.previousImage()}>\n        <i class=\"UT-icon-UT_icon_43_arrow-left-16px\" aria-label={getTid('utwente_base:frontend.ws2026.js.common.previous')} />\n      </button>\n      <button type=\"button\" tabindex=\"0\" class=\"photosoverlay__next\" onClick={() => this.nextImage()}>\n        <i class=\"UT-icon-UT_icon_44_arrow-right-16px\" aria-label={getTid('utwente_base:frontend.ws2026.js.common.next')} />\n      </button>\n    </div>;\n\n    new SwipeDetect(this.overlay!, {});\n    this.overlay!.addEventListener(\"wh:swipe\", (ev: Event) => {\n      const detail = (ev as CustomEvent<swipeInfo>).detail;\n      if (detail.direction === \"w\") {\n        this.nextImage();\n      } else if (detail.direction === \"e\") {\n        this.previousImage();\n      }\n    });\n\n    new utDialog2(this.overlay!, \"photooverlay\", { classname: \"utdialog2-dialog--fullsize\" }).showModal();\n    this.overlay!.focus();\n    this.overlay!.addEventListener(\"keyup\", ev => this.onKeyUp(ev));\n  }\n\n  renderVideo(photo: photoType, selected: boolean) {\n    if (!photo.video)\n      return null;\n\n    const videonode = <video class=\"photosoverlay__item__video\" controls preload={selected ? \"auto\" : \"none\"} defaultMuted=\"true\">\n      <source src={photo.video.link} type={photo.video.mediatype} />\n      Your browser does not support the video tag.\n    </video>;\n\n    videonode.addEventListener(\"loadeddata\", () => {\n      const el = videonode as HTMLVideoElement;\n      el.width = el.videoWidth;\n      el.height = el.videoHeight;\n\n      if (selected)\n        el.play().catch(() => { });// If the video cannot be played automatically, we can ignore the error as the user can still play it manually.\n    });\n\n    return <div class=\"photosoverlay__item__image-wrapper\">{videonode}</div>;\n  }\n\n  renderPicture(photo: photoType) {\n    if (!photo.scaledImages.length)\n      return null;\n\n    const nrOfImages = photo.scaledImages.length;\n\n    return <picture class=\"photosoverlay__item__image-wrapper\">\n      {photo.scaledImages.map((scaledImage, idx) => {\n        if( idx === nrOfImages - 1)\n          return <img src={photo.scaledImages[idx].link} class=\"photosoverlay__item__image\" width={photo.scaledImages[idx].width} style={\"background-color:\" + photo.scaledImages[idx].dominantColor} height={photo.scaledImages[idx].height} loading=\"lazy\" alt={photo.title} />; // The last image (smallest) is used as the default source for the img tag\n        return <source key={idx} srcset={scaledImage.link} media={\"(min-width:\" + scaledImage.mediaMinSize + \"px)\"} />;\n      })}\n\n    </picture>;\n  }\n\n  previousImage() {\n    const curphoto = dompack.qS(this.overlay!, \".photosoverlay__item--selected\");\n    if (!curphoto)\n      return;\n\n    const curvideo = dompack.qS(curphoto, \"video\") as HTMLVideoElement | null;\n    if (curvideo)\n      curvideo.pause(); // Pause the current video if it is playing before switching to the next\n\n    let prevphoto = curphoto.previousElementSibling;\n    if (!prevphoto)\n      prevphoto = dompack.qS(this.overlay!, \".photosoverlay__item:last-child\");\n    if (prevphoto) {\n      curphoto.classList.add(\"photosoverlay__item--hiding\");\n      curphoto.classList.remove(\"photosoverlay__item--selected\");\n      prevphoto.classList.add(\"photosoverlay__item--selected\");\n\n      setTimeout(() => {\n        curphoto.classList.remove(\"photosoverlay__item--hiding\");\n      }, _transitionDuration);\n\n      const video = dompack.qS(prevphoto, \"video\") as HTMLVideoElement | null;\n      if (video)\n        video.play().catch(() => { });// If the video cannot be played automatically, we can ignore the error as the user can still play it manually.\n    }\n  }\n\n  nextImage() {\n    const curphoto = dompack.qS(this.overlay!, \".photosoverlay__item--selected\");\n    if (!curphoto)\n      return;\n\n    const curvideo = dompack.qS(curphoto, \"video\") as HTMLVideoElement | null;\n    if (curvideo)\n      curvideo.pause(); // Pause the current video if it is playing before switching to the next\n\n    let nextphoto = curphoto.nextElementSibling;\n    if (!nextphoto)\n      nextphoto = dompack.qS(this.overlay!, \".photosoverlay__item:first-child\");\n    if (nextphoto) {\n      curphoto.classList.add(\"photosoverlay__item--hiding\");\n      curphoto.classList.remove(\"photosoverlay__item--selected\");\n      nextphoto.classList.add(\"photosoverlay__item--selected\");\n\n      setTimeout(() => {\n        curphoto.classList.remove(\"photosoverlay__item--hiding\");\n      }, _transitionDuration);\n\n      const video = dompack.qS(nextphoto, \"video\") as HTMLVideoElement | null;\n      if (video)\n        video.play().catch(() => { });// If the video cannot be played automatically, we can ignore the error as the user can still play it manually.\n    }\n  }\n}\n","import * as dompack from \"@webhare/dompack\";\n\ntype swipeDetectOptions = {\n  threshold_distance?: number;\n  threshold_speed?: number;\n  enablemouseswipe?: boolean;\n};\n\ntype swipeInfo = {\n  starttime: number;\n  endtime: number;\n  start: { \"x\": number; \"y\": number };\n  end: { \"x\": number; \"y\": number };\n  speed: { \"x\": number; \"y\": number };\n  distance: { \"x\": number; \"y\": number };\n  target: HTMLElement;\n  direction: string;\n  duration: number;\n};\nexport type { swipeInfo };\n\nexport class SwipeDetect {\n  node: HTMLElement;\n  options: swipeDetectOptions;\n  swipeinfo: swipeInfo | null;\n  initdone: boolean;\n  constructor(node: HTMLElement, options: swipeDetectOptions) {\n    this.node = node;\n    this.options = options;\n    this.swipeinfo = null;\n    this.initdone = false;\n\n    if (!node)\n      return;\n\n    if (this.options.enablemouseswipe === undefined)\n      this.options.enablemouseswipe = true;\n\n    //android fix: init after page is loaded\n    window.addEventListener(\"load\", ev => this.init());\n    this.init();\n  }\n\n  init() {\n    if (this.initdone)\n      return;\n\n    this.initdone = true;\n    if (this.options.enablemouseswipe) {\n      this.node.addEventListener(\"mousedown\", event => this.onTouchStart(event));\n      this.node.addEventListener(\"mousemove\", event => this.onTouchMove(event));\n      this.node.addEventListener(\"mouseup\", event => this.onTouchEnd(event));\n    }\n    if (this.touchEnabled()) {\n      this.node.addEventListener(\"touchstart\", event => this.onTouchStart(event));\n      this.node.addEventListener(\"touchmove\", event => this.onTouchMove(event));\n      this.node.addEventListener(\"touchend\", event => this.onTouchEnd(event));\n    }\n  }\n\n  touchEnabled() {\n    return \"ontouchstart\" in this.node || \"createTouch\" in this.node || \"TouchEvent\" in this.node || navigator.maxTouchPoints > 0;\n  }\n\n  onTouchStart(ev: TouchEvent | MouseEvent) {\n    const posx = typeof (ev as MouseEvent).pageX !== \"undefined\" ? (ev as MouseEvent).pageX : (ev as TouchEvent).touches[0].pageX;\n    const posy = typeof (ev as MouseEvent) !== \"undefined\" ? (ev as MouseEvent).pageY : (ev as TouchEvent).touches[0].pageY;\n\n    this.swipeinfo = {\n      starttime: new Date().getTime(),\n      endtime: -1,\n      start: { \"x\": posx, \"y\": posy },\n      end: { \"x\": posx, \"y\": posy },\n      speed: { \"x\": 0, \"y\": 0 },\n      distance: { \"x\": 0, \"y\": 0 },\n      target: ev.target as HTMLElement,\n      direction: \"\",\n      duration: 0\n    };\n  }\n\n  onTouchMove(ev: TouchEvent | MouseEvent) {\n    if (!this.swipeinfo)\n      return;\n\n    const posx = typeof (ev as MouseEvent).pageX !== \"undefined\" ? (ev as MouseEvent).pageX : (ev as TouchEvent).touches[0].pageX;\n    const posy = typeof (ev as MouseEvent).pageY !== \"undefined\" ? (ev as MouseEvent).pageY : (ev as TouchEvent).touches[0].pageY;\n\n    this.swipeinfo.end = { \"x\": posx, \"y\": posy };\n  }\n\n  onTouchEnd(ev: TouchEvent | MouseEvent) {\n    if (!this.swipeinfo)\n      return;\n\n    const dx = this.swipeinfo.end.x - this.swipeinfo.start.x;\n    const dy = this.swipeinfo.end.y - this.swipeinfo.start.y;\n\n    this.swipeinfo.endtime = new Date().getTime();\n\n    this.swipeinfo.duration = this.swipeinfo.endtime - this.swipeinfo.starttime;\n\n    this.swipeinfo.distance.x = Math.abs(dx);\n    this.swipeinfo.distance.y = Math.abs(dy);\n\n    this.swipeinfo.speed.x = this.swipeinfo.distance.x / this.swipeinfo.duration;\n    this.swipeinfo.speed.y = this.swipeinfo.distance.y / this.swipeinfo.duration;\n\n    if (!this.options.threshold_speed)\n      this.options.threshold_speed = 0.3;\n\n    if (!this.options.threshold_distance)\n      this.options.threshold_distance = 15;\n\n    if (this.swipeinfo.distance.x > this.options.threshold_distance && this.swipeinfo.speed.x > this.options.threshold_speed)\n      this.swipeinfo.direction += dx > 0 ? \"e\" : \"w\";\n\n    if (this.swipeinfo.distance.y > this.options.threshold_distance && this.swipeinfo.speed.y > this.options.threshold_speed)\n      this.swipeinfo.direction += dy > 0 ? \"s\" : \"n\";\n\n    if (this.swipeinfo.direction !== \"\") {\n      dompack.dispatchCustomEvent(this.node, \"wh:swipe\", {\n        bubbles: true,\n        cancelable: false,\n        detail: this.swipeinfo,\n      });\n    }\n\n    this.swipeinfo = null;\n  }\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n/* Copied from mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/index.ts\n*/\n\nimport * as dompack from \"@webhare/dompack\";\n\nfunction initWideImage() {\n  window.addEventListener(\"resize\", checkWideImage);\n  checkWideImage();\n}\n\nfunction checkWideImage() { //replace wide image with large (desktop) version if window > 640\n  if (window.innerWidth <= 640)\n    return;\n\n  const wideimages = document.querySelectorAll(\".embeddedobject.imageblock > img[data-wide]\");\n  let imgcount = wideimages.length;\n  for (const node of wideimages) {\n    const widelink = node.getAttribute(\"data-wide\");\n    if (widelink)\n      node.src = widelink;\n    node.removeAttribute(\"data-wide\");\n    imgcount--;\n  }\n  if (imgcount <= 0)\n    window.removeEventListener(\"resize\", checkWideImage);\n}\n\nlet dragging = 0;\nconst dragThreshold = 3;\n\n\n/*\nUsed CSS classes:\n- --disabled\n- --open                  - the foldable content is expanded (not collapsed)\n- __foldcontainer--active - means it's being animated\n*/\n\nexport function openFoldableContent(node, className = \"foldablecontent\") {\n  node.classList.add(className + \"--open\");\n\n  // we are forced to do this because we have custom classnames for all foldable content\n  const foldcontainernode = node.querySelector(\".\" + className + \"__foldcontainer\");\n  foldcontainernode.style.height = \"auto\";\n  foldcontainernode.style.overflow = \"inherit\";\n}\n\nexport function initFoldableContent(node) {\n  const className = \"foldablecontent\";\n\n  node.classList.add(className + \"--active\");\n  // titlenode = the node that toggles the foldable content\n  const titlenode = node.querySelector(\".\" + className + \"__title\");\n  // foldcontainernode = the node that is resized when opening/closing\n  const foldcontainernode = node.querySelector(\".\" + className + \"__foldcontainer\");\n  // textnode = the node that holds the actual content\n  const textnode = node.querySelector(\".\" + className + \"__text\");\n\n  if (!foldcontainernode) {\n    console.warn(\"No expandable content for\", node);\n    return;\n  }\n\n  const setHandler = event => {\n    if (event.detail.open) {\n      openFoldableContent(node, className);\n    } else {\n      node.classList.remove(className + \"--open\");\n      foldcontainernode.style.height = \"\";\n    }\n  };\n\n  const toggleHandler = event => {\n    if (event.type == \"touchend\")\n      event.preventDefault(); // Don't fire click event as well\n    if (dragging >= dragThreshold)\n      return;\n    if (node.classList.contains(className + \"--disabled\"))\n      return;\n\n    // Toggle the open state\n    if (node.classList.toggle(className + \"--open\")) {\n      // Explicitly set height to zero\n      foldcontainernode.style.height = 0;\n\n      // Activate transition\n\n      if (window.matchMedia(\"(prefers-reduced-motion: no-preference)\").matches)\n        foldcontainernode.classList.add(className + \"__foldcontainer--active\");\n\n      // Set height to content height to start the transition\n      foldcontainernode.style.height = textnode.getBoundingClientRect().height + \"px\";\n    } else {\n      // set overflow to css value (overflow=hidden)\n      foldcontainernode.style.overflow = \"\";\n\n      // Explicitly set height to current height\n      foldcontainernode.style.height = textnode.getBoundingClientRect().height + \"px\";\n      foldcontainernode._wsTmpHeight = getComputedStyle(foldcontainernode).height;\n\n      // Activate transition\n      if (window.matchMedia(\"(prefers-reduced-motion: no-preference)\").matches)\n        foldcontainernode.classList.add(className + \"__foldcontainer--active\");\n\n      // Set height to 0 to start the transition\n      foldcontainernode.style.height = \"0\";\n    }\n\n    dompack.dispatchCustomEvent(node, \"ws:foldable-status\",\n      {\n        bubbles: true,\n        cancelable: false,\n        detail: { open: node.classList.contains(className + \"--open\") }\n      });\n  };\n\n  titlenode.addEventListener(\"click\", toggleHandler);\n  node.addEventListener(\"ws:foldable-toggle\", toggleHandler);\n  node.addEventListener(\"ws:foldable-set\", setHandler);\n\n  // Use touch events for mobile, because the first click only activates the hover effect\n  // Only activate toggle and prevent default when a certain number of move events have occurred\n  titlenode.addEventListener(\"touchstart\", () => dragging = 0, { passive: true });\n  titlenode.addEventListener(\"touchmove\", () => ++dragging, { passive: true });\n  titlenode.addEventListener(\"touchend\", toggleHandler);\n\n  foldcontainernode.addEventListener(\"transitionend\", event => {\n    if (event.currentTarget == event.target) {\n      // Deactivate the transition\n      foldcontainernode.classList.remove(className + \"__foldcontainer--active\");\n\n      // reset height and overflow back to what the stylesheet defines\n      //foldcontainernode.style.height = \"\";\n      //foldcontainernode.style.overflow = \"\";\n\n      // Set height to 'auto' when open (natural content height) or clear when closed (css default)\n      // and disable overflow so hover effects on items inside container can get outside container\n      if (node.classList.contains(className + \"--open\")) {\n        // we are forced to do this because we have custom classnames for all foldable content\n        foldcontainernode.style.height = \"auto\";\n        foldcontainernode.style.overflow = \"inherit\";\n      } else {\n        foldcontainernode.style.height = \"\";\n      }\n    }\n  });\n}\n\nfunction toggleStudyFinderSpecializations(ev) {\n  if (ev && !ev.target.closest(\".togglespecializations\"))\n    return;\n\n  if (ev)\n    ev.preventDefault();\n\n  const itemnode = ev.target.closest(\".studyfinder__programme\");\n  if (!itemnode)\n    return;\n\n  const spnode = itemnode.querySelector(\".programme_specializations\");\n  if (!spnode)\n    return;\n\n  if (spnode.classList.contains(\"show\")) {\n    spnode.style.height = spnode.clientHeight + \"px\";\n    void (spnode.clientWidth); //force css update\n    spnode.classList.remove(\"show\");\n    spnode.style.height = \"0px\";\n  } else {\n    spnode.style.height = spnode.children[0].clientHeight + \"px\";\n    void (spnode.clientWidth); //force css update\n    spnode.classList.add(\"show\");\n    setTimeout(function () {\n      if (spnode.classList.contains(\"show\"))\n        spnode.style.height = \"auto\";\n    }, 300);\n  }\n}\n\nfunction activateStudyfinderWidget(widgetnode) {\n  //console.info(\"Initializing StudyFinder widget\", widgetnode);\n\n  // Studyfinder widget 'show all' button\n  const showallnode = widgetnode.querySelector(\".sfwidget__showall\");\n  if (showallnode)\n    showallnode.addEventListener(\"click\", evt => expandStudyfinderWidget(evt));\n\n  widgetnode.addEventListener(\"click\", toggleStudyFinderSpecializations);\n}\n\nfunction expandStudyfinderWidget(evt) {\n  const widget = evt.target.closest(\".embeddedobject, .widget\");\n  widget.classList.add(\"sfwidget--expand\");\n}\n\ndompack.register(\".embeddedobject__studyfinder, .widget-studyfinder\", node => activateStudyfinderWidget(node));\n\n//cleanup empty paragraph between embedded objects\ndompack.register(\".embeddedobject\", node => {\n  const prevnode = node.previousElementSibling;\n  if (prevnode\n    && (prevnode.nodeName == \"P\"\n      || prevnode.nodeName == \"H2\"\n      || prevnode.nodeName == \"H3\"\n      || prevnode.nodeName == \"H4\")\n    && (prevnode.innerHTML == \"\"\n      || prevnode.innerHTML == \"<br>\")) { //empty paragraph or heading\n    //now check if element is between embedded objects\n    const prevembobjectnode = prevnode.previousElementSibling;\n    if (prevembobjectnode && prevembobjectnode.classList.contains(\"embeddedobject\"))\n      node.parentElement.removeChild(prevnode);//delete empty paragraph\n  }\n});\n\n\n//ADDME: Rewrite to picture element with srcset and media queries\ndompack.onDomReady(function () {\n  initWideImage();\n});\n","// @ts-nocheck -- prototyping first\nimport \"./main.scss\";\nimport \"./main-foldable.scss\";\nimport \"./largelists-foldable.scss\";\n\nimport * as dompack from \"dompack\";\n\nlet openedParts: Element[] = [];\nlet initialLayout = true;\nlet prevAutoFold = true;\n\n\nwindow.addEventListener(\"resize\", evt => updateFoldableContentBlocks(evt));\ndompack.onDomReady(initFoldableContentBlocks);\n\n\n\nfunction initFoldableContentBlocks() {\n\n  document.body.addEventListener(\"focusout\", evt => doCheckLostFocus(evt));\n\n  const hash = location.hash.substr(1);\n\n  // If the hash points to an existing element (by id)\n  // ensure all parent accordeons (<details>) are opened.\n  if (hash) {\n    openedParts = [];\n    let block = document.getElementById(hash)?.closest(\".ut-rtd-blocks\");\n    while (block) {\n      openedParts.push(block);\n      block = block.parentElement.closest(\".ut-rtd-blocks\");\n    }\n\n    // console.info(\"BLOCKS to open\", openedParts);\n\n    updateFoldableContentBlocks();\n\n    return;\n  }\n\n  // If there wasn't a target, open the first block\n  const firstBlock = document.querySelector(\".ut-rtd-blocks\");\n  if (firstBlock && firstBlock.tagName === \"DETAILS\")\n    openedParts = [firstBlock];\n\n  updateFoldableContentBlocks();\n\n  // Only after the initial open state of all blocks are set\n  // we enable animation (otherwise whe'll see accordeons\n  // animate closing when loading on mobile)\n  // document.clientWidth;\n  setTimeout(function () {\n    document.documentElement.classList.add(\"ut-rtd-blocks-initialized\");\n  }, 1);\n}\n\n\n/*\nCheck whether we lost focus due to <summary> getting display: contents;\nIn this case we move the focus to a new place we chose, because:\nA) We can restore the focus on the <summary> later when returning to mobile layout\nB) Otherwise Safari will reset the focus position back to the top of the page\n\nNOTE: We first get a focusout and than the window resize event.\n*/\nfunction doCheckLostFocus(evt) {\n  const block = evt.target.closest(\"details.ut-rtd-blocks\");\n  if (!block)\n    return;\n\n  const summary = evt.target.tagName === \"SUMMARY\";\n  if (!summary)\n    return;\n\n  /*\n  - navigating using tab - relatedTarget: (next target node)\n  - losing focus ability due to display: contents; - relatedTarget: null\n  - focus leaving browser - relatedTarget: null\n  */\n\n  // If we havn't lost focus we don't need to do our workaround to keep the focus near the <summary> element.\n  if (evt.relatedTarget !== null)\n    return;\n\n  /*\n  So evt.relatedTarget was null. This happens when:\n  - clicking outside a focused element - reaching the <body>\n  - focused element blurs() - may also be due the element not available anymore (for example due to display: contents;)\n  - the browser window lost focus (user working in another window)\n  */\n  const autoFold = window.getComputedStyle(document.documentElement).getPropertyValue(\"--headingsmode\") === \"autofold\";\n\n  // We have focus on <summary> which is only possible in mobile layout.\n  // So we seem to have moved to the desktop layout, causing the focusout event.\n  // To preserve the focus position for Safari whe'll temporary make the wrapper for out <details> content (.ut-rtd-blocks__body) the focused item.\n  if (!autoFold) {\n    const bodyNode = block.querySelector(\".ut-rtd-blocks__body\");\n    bodyNode.setAttribute(\"tabindex\", \"-1\");\n    bodyNode.focus();\n  }\n}\n\nfunction updateFoldableContentBlocks(evt) {\n  // console.info(\"updateFoldableContentBlocks(evt)\");\n\n  // Get all blocks we can toggle (if the page content doesn't start with a h2, the first block will be a normal div)\n  const blocks = Array.from(document.querySelectorAll(\"details.ut-rtd-blocks\"));\n  if (blocks.length === 0)\n    return;\n\n  const autoFold = window.getComputedStyle(document.documentElement).getPropertyValue(\"--headingsmode\") === \"autofold\";\n\n  if (!initialLayout && prevAutoFold === autoFold)\n    return; // no need to do an update\n\n  // When moving to desktop layout remember which blocks were opened\n  if (prevAutoFold && !autoFold) {\n    openedParts = [];\n    for (const node of blocks) {\n      if (node.hasAttribute(\"open\"))\n        openedParts.push(node);\n    }\n  }\n\n  /*\n  NOTE:\n\n  On Desktop we need the <summary> to act like a normal <h2>:\n\n  - Prevent interaction\n    - We use pointer-events: none; on the summary to prevent mouse interaction\n    - We use tabindex=\"-1\" to prevent focus on the h2's through keyboard navigation (tab)\n    - We use role=\"presentation\" on <summary> to prevent screenreaders from announcing it as an element you can interact with.\n      (screenreaders should still use the headings within)\n    - NOTE: We cannot use \"inert\" - although it would fully prevent interaction and screenreaders\n            This would hide the h2 from readreaders and prevent text selection and browser in-page text searches\n    - NOTE: The detail element's \"toggle\" event cannot be canceled and reopening upon a toggle event may cause a flicker\n\n  - Visually look like a normal heading (h2)\n    - hide the marker and toggle icon\n    - ensure margins mimicing the h2 as being a direct part of the RTD content\n\n  - Tricky\n    - When <summary> (is focused in the mobile layout) and we switch to the desktop layout focus will be lost.\n      Chrome and Firefox will remember the position in the DOM of the last focused element (even though it's not part of the focusable elements anymore due to display: contents;).\n      When tabbing they will look up the next focusable element in the DOM after the <summary>.\n      However Safari won't - so when focus was on a .ut-rtd-blocks <summary> and we switch to desktop layout, Safari will reset the focus to the top of the page/DOM.\n    - Using display: contents; on <summary> not only prevents getting focus, but also makes it blur() (so when it's applied we cannot test for focus on <summary> anymore to prevent it moving to body)\n  */\n  for (const node of blocks) {\n\n    // console.log((!autoFold || openedParts.includes(node)), node);\n\n    node.toggleAttribute(\"open\", !autoFold || openedParts.includes(node));\n\n    const summary = node.querySelector(\"summary\");\n\n    if (autoFold) {\n      summary?.removeAttribute(\"role\");\n      summary?.removeAttribute(\"tabindex\");\n\n      // Check if the focus was set on the contentwrapper as a workaround for Safari to keep the current tabnavigation position.\n      // If this is the case we want to restore this focus back to the <summary> now whe're in the mobile layout again.\n      const bodyNode = node.querySelector(\".ut-rtd-blocks__body\");\n      if (document.activeElement === bodyNode)\n        summary?.focus();\n    } else {\n      // Prevent interaction (without using inert - which kills text selection and in-page search)\n      summary?.setAttribute(\"role\", \"presentation\"); // prevent screenreader from announcing it's special role\n      summary?.setAttribute(\"tabindex\", \"-1\"); // prevent being part of keyboard navigation\n      //summary.style.pointerEvents = \"none\"; // prevent toggling through a pointer/mouse click\n    }\n\n    // FIXME: do we need to listen to toggle to prevent a toggle if the user still someone found a way to toggle it?\n  }\n\n  prevAutoFold = autoFold;\n  initialLayout = false;\n\n  // - height must be updated on .contentpart__navbar-container\n  // NavBarContainerScroller\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport './medical.scss';\nimport * as dompack from 'dompack';\nimport { registerHandler } from '@mod-publisher/js/forms';\nimport { UTRPCFormBase } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts\";\nimport * as dialogapi from \"dompack/api/dialog\";\n\nclass UTMedicalFormHandler extends UTRPCFormBase {\n  constructor(node) {\n    super(node);\n\n    const cancelbutton = this.node.querySelector('.ut-medical__cancel');\n    if (cancelbutton)\n      cancelbutton.addEventListener('click', evt => this.cancelAppointment());\n\n    this.timeoptions = dompack.qSA(this.elements.time, \"option\");\n\n    if (this.elements.date) {\n      this.elements.date.addEventListener('change', evt => this.updateTimes());\n      this.updateTimes();\n    }\n  }\n  updateTimes() {\n    const currentdate = this.elements.date.value;\n    //    let firstallowed;\n\n    //Workaround because ios doesn't hide options:\n    const selection = this.elements.time.options[this.elements.time.selectedIndex];\n    this.elements.time.replaceChildren();\n    this.timeoptions.forEach(opt => {\n      if (JSON.parse(opt.dataset.fordates).includes(currentdate)) {\n        this.elements.time.appendChild(opt);\n        if (selection && selection.textContent === opt.textContent)\n          this.elements.time.value = opt.value;\n      }\n    });\n  }\n  async cancelAppointment() {\n    if (await dialogapi.runMessageBox(\"Weet u zeker dat u uw afspraak wil annuleren ?\", [{ result: \"no\", title: \"Nee\" }, { result: \"yes\", title: \"Ja\" }]) !== 'yes')\n      return;\n    await this.invokeRPC('cancelappointment');\n    document.querySelector('#medical-form-page1').style.display = 'none';\n    document.querySelector('#medical-form-cancelled').style.display = 'block';\n  }\n  onSubmitSuccess(result) {\n    document.querySelector('#medical-form-page1').style.display = 'none';\n    document.querySelector('#medical-form-success').style.display = 'block';\n  }\n}\n\nregisterHandler('utwente_base:medicalsignupform', node => new UTMedicalFormHandler(node));\n","import * as dompack from '@webhare/dompack';\nimport * as frontend from \"@webhare/frontend\";\nimport \"./loginpage.css\"; //eliminate back arrow\n\nif (document.documentElement.classList.contains(\"utwente--loginrouter\")) {\n  dompack.register('#oidc_ut', loginbutton => {\n    loginbutton.addEventListener(\"click\", e => {\n      void frontend.startSSOLogin(\"UTAZURE\");\n    });\n  });\n\n  dompack.register<HTMLFormElement>('form.ut-specialaccount-loginform', form => {\n    form.action += location.hash; //keep the hash while redirecting\n  });\n\n  if (!document.documentElement.classList.contains(\"utwente--ws2026\")) { //TODO remove once ws2016 is gone\n    dompack.register<HTMLFormElement>('.wh-wrdauth-forgotpassword__form', form => { //apply DOM fix:\n      //one day subgrids may fix this and just allow the form to took take full width inside its 2 divs\n      (form.parentNode?.parentNode as HTMLElement).replaceWith(form);\n    });\n  }\n}\n\nfrontend.setupWebHareSSOTrigger();\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport './meetings.scss';\nimport * as dompack from 'dompack';\nimport { getTid } from \"@webhare/gettid\";\nimport * as modaldialog from \"../../shared/dialog\";\nimport { UTRPCFormBase } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts\";\nimport * as textfunctions from \"dompack/types/text\";\nimport * as forms from \"@mod-publisher/js/forms\";\n\nclass cMeetingsForm extends UTRPCFormBase {\n  constructor(formnode) {\n    super(formnode);\n\n    for (const node of this.node.querySelectorAll(\".wh-form__questiongroup__introtext\")) {\n      let html = node.innerHTML;\n      if (html.indexOf(\"[participantscount]\") !== -1 || html.indexOf(\"[bhvcount]\") !== -1) {\n        html = html.replace(\"[participantscount]\", \"<span class=\\\"participantscount\\\"></span>\");\n        html = html.replace(\"[bhvcount]\", \"<span class=\\\"bhvcount\\\"></span>\");\n        node.innerHTML = html;\n      }\n    }\n\n    formnode.querySelector('#meetingsform-step2').addEventListener(\"wh:form-pagechange\", () => this.showbhvcount());\n    formnode.querySelector('#meetingsform-step3').addEventListener(\"wh:form-pagechange\", () => this.generateOverview());\n  }\n\n  showbhvcount() {\n    const participantscount = this.elements.nrparticipants.value;\n    let bhvcount = 0;\n    if (participantscount > 20)\n      bhvcount = Math.ceil(participantscount / 50);\n    for (const node of this.node.querySelectorAll(\".wh-form__questiongroup__introtext .participantscount\"))\n      node.textContent = String(participantscount);\n    for (const node of this.node.querySelectorAll(\".wh-form__questiongroup__introtext .bhvcount\"))\n      node.textContent = String(bhvcount);\n  }\n\n  generateOverview() {\n    const overviewnode = document.getElementById(\"meetingsform-step3-content\");\n    overviewnode.replaceChildren();\n\n    const lines = [];\n    let prevtitle = \"\";\n    for (let i = 0; i < this.elements.length; ++i) {\n      const el = this.elements[i];\n\n      if (el.type !== \"hidden\") {\n        let title = \"\";\n        let value = \"\";\n        const groupnode = el.closest(\".wh-form__fieldgroup\");\n        if (groupnode) {\n          const labelnode = groupnode.querySelector(\"label\");\n          title = labelnode ? groupnode.querySelector(\"label\").textContent : groupnode.dataset.title;\n\n          if (el.nodeName === \"SELECT\")\n            value = el.options[el.selectedIndex].textContent;\n          else\n            value = String(el.value);\n        }\n\n        if (title && value) {\n          if (title === prevtitle && (el.name.indexOf(\"hour\") > -1 || el.name.indexOf(\"minute\") > -1)) { //combine\n            let separator = \" \";\n            if (el.name.indexOf(\"hour\") > -1) {\n              if (value.length === 1)\n                value = \"0\" + value;\n            }\n            if (el.name.indexOf(\"minute\") > -1) {\n              if (value.length === 1)\n                value = \"0\" + value;\n              separator = \":\";\n            }\n\n            lines[lines.length - 1].value += separator + value;\n          } else {\n            lines.push({ \"title\": title, \"value\": value, \"name\": el.name });\n          }\n\n          prevtitle = title;\n        }\n      }\n    }\n\n    let prevbhv_nr = -1;\n    let bhv_active = false;\n    for (let i = 0; i < lines.length; ++i) {\n      const isbhv = lines[i].name.indexOf(\"bhv_\") === 0;\n      if (isbhv) {\n        const bhvnr = Number(lines[i].name.replace(/[^0-9]/g, \"\"));\n        if (prevbhv_nr !== bhvnr) {\n          bhv_active = lines[i].name.indexOf(\"_name\") > 0 && lines[i].value !== \"\";\n          if (bhv_active)\n            overviewnode.appendChild(dompack.create(\"div\", { \"class\": \"line bhv\", \"innerHTML\": \"<strong>BHV'er \" + bhvnr + \"</strong>\" }));\n        }\n        prevbhv_nr = bhvnr;\n\n        if (bhv_active) {\n          const linecontent = '<strong>' + textfunctions.encodeTextNode(lines[i].title) + '</strong><span>' + textfunctions.encodeTextNode(lines[i].value) + '</span>';\n          overviewnode.appendChild(dompack.create(\"div\", { \"class\": \"line\", \"innerHTML\": linecontent }));\n        }\n      } else {\n        bhv_active = false;\n        const linecontent = '<strong>' + textfunctions.encodeTextNode(lines[i].title) + '</strong><span>' + textfunctions.encodeTextNode(lines[i].value) + '</span>';\n        overviewnode.appendChild(dompack.create(\"div\", { \"class\": \"line\", \"innerHTML\": linecontent }));\n      }\n    }\n\n  }\n\n  reset() {\n    super.reset();\n\n    const overviewnode = document.getElementById(\"meetingsform-step3-content\");\n    overviewnode.replaceChildren();\n\n    this.gotoPage(0);\n\n    for (let i = 0; i < this.elements.length; ++i) {\n      const el = this.elements[i];\n      if (el.type !== \"hidden\") {\n        if (el.nodeName === \"SELECT\") {\n          el.selectedIndex = -1;\n          el.value = \"\";\n        } else\n          el.value = \"\";\n      }\n    }\n  }\n\n  onSubmitSuccess(res) {\n    if (res.success) {\n      if (!res.isedit)\n        this.reset();\n\n      this.showSuccessDialog();\n    } else {\n      this.showErrorDialog();\n    }\n  }\n\n  showErrorDialog() {\n    const title = getTid(\"utwente_base:frontend.ws2016.js.meetings.error-title\");\n    const description = getTid(\"utwente_base:frontend.ws2016.js.meetings.error-description\");\n\n    this.dialognode = modaldialog.showModalDialog(title, description, { theme: \"dialog--small\" });\n  }\n\n  showSuccessDialog() {\n    const title = getTid(\"utwente_base:frontend.ws2016.js.meetings.thanks-title\");\n    const description = getTid(\"utwente_base:frontend.ws2016.js.meetings.thanks-description\");\n\n    this.dialognode = modaldialog.showModalDialog(title, description, { theme: \"dialog--small\" });\n  }\n}\n\nforms.registerHandler(\"utwente_base:meetingsform\", node => new cMeetingsForm(node));\n","export function encodeTextNode(str: string) {\n  return str.split('&').join('&amp;')\n    .split('<').join('&lt;')\n    .split('>').join('&gt;');\n}\n\n/** @deprecated You should use encodeString(str, 'attribute') */\nexport function encodeValue(str: string) {\n  return encodeEntities(str, false);\n}\n\n/** @deprecated You should use decodeString(str, 'attribute') */\nexport function decodeValue(str: string) {\n  return str.replace(/<br *\\/?>/g, \"\\n\")\n    .replace(/&#(\\d+);/g, (_, dec) => String.fromCharCode(dec))\n    .replace(/&lt;/g, \"<\")\n    .replace(/&gt;/g, \">\")\n    .replace(/&quot;/g, '\"')\n    .replace(/&apos;/g, \"'\")\n    .replace(/&amp;/g, \"&\");\n}\n\n/** @deprecated You should use encodeString(str, 'html') */\nexport function encodeHTML(str: string) {\n  return encodeEntities(str, true);\n}\n\nfunction encodeEntities(str: string, html: boolean) {\n  let s = \"\";\n  for (const char of str) {\n    const curch = char.codePointAt(0);\n    if (curch === undefined || isHTMLUnrepresentableChar(curch))\n      continue;\n    if (curch >= 32 && curch < 128 && curch !== 38 && curch !== 60 && curch !== 62) {\n      s += String.fromCodePoint(curch);\n      continue;\n    }\n\n    switch (curch) {\n      case 10:\n        {\n          if (html) {\n            s += \"<br />\";\n            continue;\n          }\n          break;\n        }\n      case 13:\n        {\n          if (html)\n            continue;\n          break;\n        }\n      case 34:\n        {\n          s += \"&quot;\";\n          continue;\n        }\n      case 38:\n        {\n          s += \"&amp;\";\n          continue;\n        }\n      case 39:\n        {\n          s += \"&apos;\";\n          continue;\n        }\n      case 60:\n        {\n          s += \"&lt;\";\n          continue;\n        }\n      case 62:\n        {\n          s += \"&gt;\";\n          continue;\n        }\n    }\n\n    s += \"&#\" + curch + \";\";\n  }\n  return s;\n}\n\nfunction isHTMLUnrepresentableChar(curch: number) {\n  return (curch < 32 && curch !== 9 && curch !== 10 && curch !== 13)\n    || (curch >= 128 && curch <= 159);\n}\n","import * as dompack from \"@webhare/dompack\";\nimport type { ImgEditElement } from \"@webhare/forms\";\nimport { getTid } from \"@webhare/gettid\";\nimport { RPCFormBase, registerHandler, setFieldError, setupValidator } from \"@mod-publisher/js/forms\";\nimport \"./neoform.scss\";\n\nconst MIN_HEADERIMAGE_HEIGHT = 640;\nconst MIN_HEADERIMAGE_WIDTH = 1600;\n\n\n//FIXME: Import from @webhare/upload once it's supported\nexport async function getImageDimensions(file: File): Promise<{ width: number; height: number }> {\n  return new Promise((resolve, reject) => {\n    const reader = new FileReader();\n    reader.addEventListener(\"load\", () => {\n      const img = document.createElement(\"img\");\n      img.addEventListener(\"load\", () => {\n        resolve({ width: img.naturalWidth, height: img.naturalHeight });\n      });\n      img.addEventListener(\"error\", error => reject(new Error(error.message)));\n      img.src = reader.result as string;\n    });\n    reader.addEventListener(\"error\", () => reject(new Error(\"readAsDataURL failed\")));\n    reader.readAsDataURL(file);\n  });\n}\n\ntype PublocLanguages = Array<{ id: string; languages: string[] }>;\ntype TypedPublocLanguages = { news: PublocLanguages; event: PublocLanguages };\n\nclass NEOForm extends RPCFormBase {\n  #errorObserver?: MutationObserver;\n  #publocs: TypedPublocLanguages = { news: [], event: [] };\n  #validatedAuthorizationOnce = false;\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n\n    if (this.node.dataset.publocs)\n      this.#publocs = JSON.parse(this.node.dataset.publocs) as TypedPublocLanguages;\n\n    this.#errorObserver = new MutationObserver(mutationList => this.#handleMutations(mutationList));\n\n    // Show the blurry preview when checking the 'blurry background' checkbox\n    for (const fieldGroup of dompack.qSA(node, \".ut-neoform-showblurrybg\")) {\n      const checkbox = dompack.qS<HTMLInputElement>(fieldGroup, \"input[type='checkbox']\");\n      if (checkbox && (fieldGroup.previousSibling as HTMLElement)?.classList.contains(\"ut-neoform-headerphoto\"))\n        checkbox.addEventListener(\"change\", () => (fieldGroup.previousSibling as HTMLElement).classList.toggle(\"ut-neoform-headerphoto--blurrybg\", checkbox.checked));\n    }\n\n    // Implement our own visible/required condition for alt text fields (cannot use FCIsSet on imgedit fields)\n    for (const fieldGroup of dompack.qSA(node, \".ut-neoform-headerphoto\")) {\n      let imgedit = dompack.qS(fieldGroup, \"wh-imgedit\");\n      if (imgedit) {\n        imgedit.addEventListener(\"change\", () => this.#updateAltVisibility(imgedit!));\n        this.node.addEventListener(\"wh:form-pagechange\", () => this.#updateAltVisibility(imgedit!));\n\n        // Add a mutation observer to remove the warning if an error is shown\n        this.#errorObserver.observe(fieldGroup, { childList: true });\n      } else { //FIXME: This legacy support can be removed once UT runs 5.6\n        imgedit = dompack.qS(fieldGroup, \"div.wh-form__imgedit\");\n        if (imgedit) {\n          imgedit.addEventListener(\"change\", () => this.#updateAltVisibility(imgedit!, true));\n          this.node.addEventListener(\"wh:form-pagechange\", () => this.#updateAltVisibility(imgedit!));\n        }\n      }\n    }\n\n    // Hide all alt text fields by default\n    for (const fieldGroup of dompack.qSA(node, \".ut-neoform-headeralt\"))\n      this.#toggleAltEnabled(fieldGroup, false);\n\n    // Move checkboxgroup infotext and errors out of the options wrapper\n    for (const fields of dompack.qSA(node, \".ut-neoform-checkboxgroup .wh-form__fields\")) {\n      const infotextwrapper = dompack.qS(fields, \":scope > .wh-form__infotextwrapper\");\n      if (infotextwrapper)\n        fields.after(infotextwrapper);\n\n      // Add a mutation observer to move errors out of the option wrapper\n      this.#errorObserver.observe(fields, { childList: true });\n    }\n\n    // Link 'UT - all' to other checkboxes\n    for (const fieldGroup of dompack.qSA(node, \".wh-form__fieldgroup[data-wh-form-group-for=mp_receivers]\")) {\n      let changing = false;\n      fieldGroup.addEventListener(\"change\", event => {\n        if (!event.target || changing)\n          return;\n        changing = true;\n\n        if ((event.target as HTMLInputElement).dataset.isemployeesrole === \"true\") {\n          // (De)select all other options\n          for (const input of dompack.qSA(fieldGroup, \"input[type=checkbox][data-isemployeesrole=false]\")) {\n            if ((input as HTMLInputElement).dataset.isemployeesrole !== \"true\")\n              (input as HTMLInputElement).checked = (event.target as HTMLInputElement).checked;\n          }\n        } else {\n          // Set 'UT - all' checked to all other checked\n          const allChecked = dompack.qSA(fieldGroup, \"input[type=checkbox][data-isemployeesrole=false]\").every(input => (input as HTMLInputElement).checked);\n          const allEmployees = dompack.qS(fieldGroup, \"input[type=checkbox][data-isemployeesrole=true]\");\n          if (allEmployees)\n            (allEmployees as HTMLInputElement).checked = allChecked;\n        }\n\n        changing = false;\n      });\n    }\n\n    // Make sure either mp_authorized or mp_persontypes is filled if mp_authorized_public is set\n    // We'll add the validator to mp_authorized and will validate explicitly when mp_persontypes changes (after the validator\n    // has run at least once)\n    const mpAuthorizedField = dompack.qS(node, \".wh-form__fieldgroup[data-wh-form-group-for=mp_authorized]\");\n    if (mpAuthorizedField) {\n      setupValidator(mpAuthorizedField, () => this.#checkRequiredAuthorizedPersonTypes());\n    }\n    const mpPersonTypesField = dompack.qS(node, \".wh-form__fieldgroup[data-wh-form-group-for=mp_persontypes]\");\n    if (mpPersonTypesField && mpAuthorizedField) {\n      mpPersonTypesField.addEventListener(\"change\", () => this.#validatedAuthorizationOnce && this.validate([mpAuthorizedField]));\n    }\n  }\n\n  async getPublocLanguages() {\n    const value = await this.getFormValue() as {\n      newstype: string[];\n      orgpubloc_news: string;\n      publocations_news: string[];\n      orgpubloc_event: string;\n      publocations_event: string[];\n    };\n    const languages = new Set();\n    const newstype = value.newstype[0] as \"news\" | \"event\" | undefined;\n    if (newstype) {\n      const publocids = newstype === \"news\" ? [value.orgpubloc_news, ...value.publocations_news] : [value.orgpubloc_event, ...value.publocations_event];\n      const publocs = this.#publocs[newstype].filter(_ => publocids.includes(_.id));\n      for (const publoc of publocs)\n        for (const lang of publoc.languages)\n          languages.add(lang);\n    }\n    return [...languages.values()];\n  }\n\n  #handleMutations(mutationList: MutationRecord[]) {\n    for (const mutation of mutationList) {\n      const target = mutation.target as HTMLElement;\n      if (target.classList.contains(\"ut-neoform-headerphoto\")) {\n        // If an imgedit error node was added...\n        if ([...mutation.addedNodes].some(_ => (_ as HTMLElement).classList.contains(\"wh-form__error\"))) {\n          const warningNode = target.querySelector(\".ut-neoform__warning\");\n          // ...remove the warning node, if any\n          if (warningNode)\n            warningNode.remove();\n        }\n      } else if (target.matches(\".ut-neoform-checkboxgroup .wh-form__fields\"))\n        // Move the error node out of the options wrapper\n        for (const errorNode of mutation.addedNodes)\n          target.after(errorNode);\n    }\n  }\n\n  async #updateAltVisibility(node: HTMLElement, legacy = false) {\n    let hasImage = false;\n    let name = \"\";\n    if (legacy) { //FIXME: This legacy support can be removed once UT runs 5.6\n      // The imgedit has a value if the 'wh-form__imgedit--hasimage' class is set\n      hasImage = node.classList.contains(\"wh-form__imgedit--hasimage\");\n      name = node.dataset.whFormName ?? \"\";\n    } else {\n      hasImage = (node as ImgEditElement).isSet();\n      name = (node as ImgEditElement).name;\n      this.#checkHeaderPhoto(node as ImgEditElement);\n    }\n    // If name == \"photo2\", we're looking for \"alt_en2\", etc.\n    const languages = await this.getPublocLanguages();\n    const altEN = dompack.qS(`[data-wh-form-group-for=\"${name.replace(/photo/, \"alt_en\")}\"]`);\n    if (altEN)\n      this.#toggleAltEnabled(altEN, hasImage && languages.includes(\"en\"));\n    const altNL = dompack.qS(`[data-wh-form-group-for=\"${name.replace(/photo/, \"alt_nl\")}\"]`);\n    if (altNL)\n      this.#toggleAltEnabled(altNL, hasImage && languages.includes(\"nl\"));\n  }\n\n  async #checkHeaderPhoto(node: ImgEditElement) {\n    // Remove current warning\n    const fieldGroup = node.closest(\".wh-form__fieldgroup\")!;\n    let warningNode = fieldGroup.querySelector(\".ut-neoform__warning\");\n    if (warningNode)\n      warningNode.remove();\n\n    const file = node.value[0]?.file;\n    if (file) {\n      try {\n        const size = await getImageDimensions(file);\n        //FIXME: This height check can be replaced with the 'minheight' attribute on the imgedit field once that's supported on all UT servers\n        if (size.height < MIN_HEADERIMAGE_HEIGHT)\n          setFieldError(node, getTid(\"utwente_base:frontend.ws2016.js.neoform.minheight\", size.height, MIN_HEADERIMAGE_HEIGHT));\n        else if (size.width < MIN_HEADERIMAGE_WIDTH) {\n          // Show a warning if the image is high enough, but not wide enough\n          const warning = <span>{getTid(\"utwente_base:frontend.ws2016.js.neoform.image-invalid-width\", size.width, MIN_HEADERIMAGE_WIDTH)}</span>;\n          warningNode = warningNode || <div class=\"ut-neoform__warning\"></div>;\n          warningNode!.replaceChildren(warning!);\n          fieldGroup.querySelector(\".wh-form__fields\")!.after(warningNode!);\n        }\n      } catch (e) {\n        console.error(e);\n        setFieldError(node, getTid(\"utwente_base:frontend.ws2016.js.neoform.image-read-error\"));\n      }\n    }\n  }\n\n  #toggleAltEnabled(node: HTMLElement, enabled: boolean) {\n    node.classList.toggle(\"wh-form__fieldgroup--disabled\", !enabled);\n    node.classList.toggle(\"wh-form__fieldgroup--required\", enabled);\n    const input = dompack.qS<HTMLInputElement>(node, \"input\");\n    if (input) {\n      input.disabled = !enabled;\n      input.required = enabled;\n    }\n    requestAnimationFrame(() => node.classList.toggle(\"wh-form__fieldgroup--hidden\", !enabled));\n  }\n\n  async #checkRequiredAuthorizedPersonTypes() {\n    this.#validatedAuthorizationOnce = true;\n    const value = await this.getFormValue() as {\n      mp_authorized_public: string[];\n      mp_authorized: string[];\n      mp_persontypes: string[];\n    };\n    if (value.mp_authorized_public?.includes(\"1\") && !value.mp_authorized?.length && !value.mp_persontypes?.length) {\n      return getTid(\"utwente_base:frontend.ws2016.js.neoform.authorizednotset\");\n    }\n  }\n}\n\nregisterHandler(\"utwente_base:neoform\", node => new NEOForm(node));\n","import \"./filteredfolder.scss\";\nimport * as dompack from \"@webhare/dompack\";\n\nclass FilteredFolderPage {\n  container: HTMLElement;\n  sortcol: number = 0; //Default first column\n  sortasc: boolean = true;\n  constructor(container: HTMLElement) {\n    this.container = container;\n\n    const listviewheader = dompack.qS(this.container, \".filteredoverview__listviewheader\");\n    if (listviewheader) {\n      listviewheader.addEventListener(\"click\", ev => this.onSortClick(listviewheader, ev));\n    }\n\n    container.addEventListener(\"pagefilters:viewmodechange\", ev => this.onViewModeChange((ev as CustomEvent).detail.mode));\n  }\n\n  onSortClick(listviewheader: HTMLElement, ev: MouseEvent) {\n    const col = (ev.target as HTMLElement).closest(\".filteredoverview__item__listviewcol\");\n    if (!col)\n      return;\n\n    let idx = this.sortcol;\n    for (let c = 0; c < listviewheader.children.length; ++c) {\n      if (listviewheader.children[c] === col) {\n        idx = c;\n        break;\n      }\n    }\n\n    if (this.sortcol === idx)\n      this.sortasc = !this.sortasc;//reverse ordering if click on same column\n    this.sortcol = idx;\n\n    this.sortList();\n  }\n\n  onViewModeChange(mode: string) {\n    if(mode === \"list\") {\n      this.container.classList.add(\"filteredoverview__items--listview\");\n      this.container.classList.remove(\"filteredoverview__items--detailview\");\n    } else {\n      this.container.classList.add(\"filteredoverview__items--detailview\");\n      this.container.classList.remove(\"filteredoverview__items--listview\");\n    }\n    this.sortList();\n  }\n\n  sortList() {\n    const items = dompack.qSA(this.container, \".filteredoverview__item\");\n    if (this.container.classList.contains(\"filteredoverview__items--listview\")) { //use sort column\n      items.sort((a, b) => {\n        const a_i = Number(a.dataset.ordering); //original ordering\n        const b_i = Number(b.dataset.ordering);\n\n        // + 1 to skip (first) hidden element\n        const colidx = this.sortcol + 1;\n        const a_c = colidx < a.children.length ? a.children[colidx].textContent!.toUpperCase().trim() : \"\";\n        const b_c = colidx < b.children.length ? b.children[colidx].textContent!.toUpperCase().trim() : \"\";\n\n        if (this.sortasc) {\n          if (a_c < b_c)\n            return -1;\n          if (a_c > b_c)\n            return 1;\n          return a_i < b_i ? -1 : 1;//If equal, then check original ordering\n        } else { //sort desc\n          if (a_c > b_c)\n            return -1;\n          if (a_c < b_c)\n            return 1;\n          return a_i > b_i ? -1 : 1;//If equal, then check original ordering\n        }\n      });\n\n      items.forEach(e => this.container.appendChild(e));\n    } else {\n      //Just use original ordering when in detail view\n      items.sort((a, b) => {\n        return Number(a.dataset.ordering) < Number(b.dataset.ordering) ? -1 : 1;//If equal, then check original ordering\n      });\n\n      items.forEach(e => this.container.appendChild(e));\n    }\n  }\n}\n\ndompack.register(\".filteredfolder__results .filteredoverview__items\", node => new FilteredFolderPage(node));\n","import \"./newsevents-overview.css\";\nimport \"./newsevents-details.css\";\nimport \"../../shared/summary.scss\";\nimport * as dompack from '@webhare/dompack';\nimport UtwenteService, { type NEOResultsType } from \"@mod-utwente_base/js/service\";\nimport { type CustomPageFilter, type PageFiltersContext, registerCustomFilter } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters\";\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\nimport { getTid } from \"@webhare/gettid\";\nimport type { SlimSelect } from \"@mod-utwente_design\";\nimport { registerHandler } from '@mod-publisher/js/forms';\nimport { UTRPCFormBase } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts\";\nimport { utDialog2 } from '@mod-utwente_base/webdesigns/ws2026/shared/forms/dialogs';\n\n// render prev/next nav if applicable\ndompack.register(\".page-titlebar\", node => {\n  const settings = getFrontendData(\"utwente_base:neopage\", { allowMissing: true });\n  if (settings && settings.suburl) {\n    const neolinks = dompack.getSession(\"neoLinks-\" + settings.objid) as { suburl: string; link: string }[] | null;\n    if (!neolinks)\n      return;\n\n    const idx = neolinks.findIndex(_ => _.suburl === settings.suburl);\n    if (idx >= 0) {\n      const prevlink = idx > 0 ? neolinks[idx - 1].suburl : \"\";\n      const nextlink = idx < neolinks.length - 1 ? neolinks[idx + 1].suburl : \"\";\n\n      if (prevlink || nextlink) {\n        const nav = <div class=\"neodetailspage-pagenav\">\n          {prevlink ? <a href={settings.baseurl + prevlink} class=\"previous\"><i class=\"UT-icon-UT_icon_43_arrow-left-16px\" aria-hidden=\"true\" /><span>{settings.type === \"news\" ? getTid(\"utwente_base:frontend.ws2016.js.newsevents.previous_article-news\") : getTid(\"utwente_base:frontend.ws2016.js.newsevents.previous_article\")}</span></a> : <span />}\n          {nextlink ? <a href={settings.baseurl + nextlink} class=\"next\"><span>{settings.type === \"news\" ? getTid(\"utwente_base:frontend.ws2016.js.newsevents.next_article-news\") : getTid(\"utwente_base:frontend.ws2016.js.newsevents.next_article\")}</span><i class=\"UT-icon-UT_icon_44_arrow-right-16px\" aria-hidden=\"true\" /></a> : null}\n        </div>;\n\n        node.prepend(nav);\n      }\n    }\n  }\n});\n\nclass NeoPageFilter implements CustomPageFilter {\n  objid: number = 0;\n  type: string = \"\";\n  subtype: string = \"\";\n\n  photoplaceholder: string = \"\";\n  photoplaceholder_2x: string = \"\";\n  summaryplaceholder: string = \"\";\n  summaryplaceholder_2x: string = \"\";\n\n  hasfoldableitems: boolean = false;\n  summarycontainer: HTMLElement;\n  morebutton: HTMLButtonElement;\n\n  currentfilters: PageFiltersContext | null = null;\n\n  constructor() {\n    this.summarycontainer = dompack.qR(\"main .summary\");\n\n    const settings = getFrontendData(\"utwente_base:neopage\");\n    if (settings) {\n      this.objid = settings.objid;\n      this.type = settings.type;\n      this.subtype = settings.subtype;\n\n      this.photoplaceholder = settings.photoplaceholder;\n      this.photoplaceholder_2x = settings.photoplaceholder_2x;\n      this.summaryplaceholder = settings.summaryplaceholder;\n      this.summaryplaceholder_2x = settings.summaryplaceholder_2x;\n    }\n\n    this.hasfoldableitems = this.subtype === \"cultural\";\n\n    if (this.type === \"event\") { // archive, upcoming buttons\n      const buttonsWrapper = dompack.qS(\".page-filters__form__buttons\");\n      if (buttonsWrapper)\n        buttonsWrapper.prepend(<div class=\"neopage-archiveoptions\">\n          <button class=\"neopage-archiveoptions__button\" data-archive=\"no\" onClick={() => this.toggleArchive(false)} hidden>\n            <span>{getTid(\"utwente_base:frontend.ws2016.js.newsevents.upcoming\")}</span>\n          </button>\n          <button class=\"neopage-archiveoptions__button\" data-archive=\"yes\" onClick={() => this.toggleArchive(true)} hidden>\n            <span>{getTid(\"utwente_base:frontend.ws2016.js.newsevents.archive\")}</span>\n          </button>\n        </div>);\n    }\n\n    this.morebutton = dompack.qR(\".neopage-moreresults__button\");\n    this.morebutton.addEventListener(\"click\", () => {\n      const loc = new URL(location.href);\n      const skip = parseInt(loc.searchParams.get(\"skip\")!) || 0;\n      loc.searchParams.set(\"skip\", (skip + 10).toString());\n      history.pushState(null, \"\", loc.toString());\n\n      void this.doFilter();\n    });\n\n    this.summarycontainer.addEventListener(\"click\", e => {\n      const tagEl = (e.target as HTMLElement).closest(\".tag[data-filter]\") as HTMLElement | null;\n      if (tagEl) {\n        const filtername = tagEl.dataset.filter;\n        const id = tagEl.dataset.id;\n        if (filtername && id) {\n          e.preventDefault();\n          if (filtername === \"categories\") {\n            const selEl = dompack.qS<HTMLSelectElement>(\".page-filters__form select[name='categories']\");\n            if (!selEl)\n              return;\n\n            const ss = (selEl as HTMLSelectElement & { slim: SlimSelect }).slim;\n            ss.setSelected(id, true);\n          } else if (filtername === \"tag\") {\n            this.setTag(id);\n          }\n\n        }\n      }\n    });\n  }\n\n  setTag(value: string) {\n    const loc = new URL(location.href);\n    if (value)\n      loc.searchParams.set(\"tag\", value);\n    else\n      loc.searchParams.delete(\"tag\");\n    history.pushState(null, \"\", loc.toString());\n    this.resetPagination();\n    void this.doFilter();\n  }\n\n  toggleArchive(showArchive: boolean) {\n    const loc = new URL(location.href);\n    if (showArchive)\n      loc.searchParams.set(\"archive\", \"yes\");\n    else\n      loc.searchParams.delete(\"archive\");\n    history.pushState(null, \"\", loc.toString());\n    this.resetPagination();\n    void this.doFilter();\n  }\n\n  resetPagination() {\n    const loc = new URL(location.href);\n    loc.searchParams.delete(\"skip\");\n    history.pushState(null, \"\", loc.toString());\n    this.morebutton.hidden = true;\n  }\n\n  async filter(filtercontext: PageFiltersContext): Promise<HTMLElement[] | null> {\n    this.currentfilters = filtercontext;\n    this.resetPagination();\n    return await this.doFilter();\n  }\n\n  async doFilter() {\n    this.morebutton.classList.add(\"neopage-moreresults--loading\");\n    const lock = dompack.flagUIBusy({ modal: true });\n\n    const urlParams = new URLSearchParams(location.search);\n\n    const skip = parseInt(urlParams.get(\"skip\")!) || 0;\n    const archive = this.type === \"event\" && urlParams.get(\"archive\") === \"yes\";\n    const tag = parseInt(urlParams.get(\"tag\")!) || 0;\n\n    let res: NEOResultsType;\n    try {\n      res = await UtwenteService.GetNEOItems(this.objid, this.type, this.subtype, this.currentfilters!, { skip, archive, tag });\n    } finally {\n      lock.release();\n    }\n\n    this.morebutton.classList.remove(\"neopage-moreresults--loading\");\n    this.morebutton.hidden = !res.moreitems;\n    const isMoreResults = res.skip > 0;\n\n    const isAnySet = (this.currentfilters ? this.currentfilters.query.isAnySet : false) || res.archive || res.tag > 0 || res.skip > 0;\n\n    const items = res && res.totalresults > 0 ? this.renderItems(res, isMoreResults, isAnySet) : [] as HTMLElement[];\n\n    dompack.qSA(\".neopage-archiveoptions__button\").forEach(btn => {\n      if (btn.dataset.archive === \"yes\")\n        btn.hidden = archive;\n      else\n        btn.hidden = !archive;\n    });\n\n    // only replace items when not showing more results, otherwise new results are appended to existing items\n    if (!isMoreResults) {\n      dompack.setSession(\"neoLinks-\" + this.objid, res.links);\n      this.summarycontainer.replaceChildren(...items);\n    }\n\n    dompack.qSA(\".page-filterstoolbar__feedback\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.search-xresults\", String(res.totalresults)));\n    dompack.qSA(\".page-filters__mobiletoggle__hidelabel\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-xresults\", String(res.totalresults)));\n\n    document.documentElement.classList.toggle(\"page-filters--noresults\", !res || !res.totalresults);\n    if (!res || !res.totalresults) {\n      if (this.type === \"event\" && res && !res.archive) {\n        this.summarycontainer.append(<div class=\"pagefilters__noresults\">{getTid(\"utwente_base:frontend.ws2016.js.newsevents.noupcoming\")}</div>);\n      } else {\n        this.summarycontainer.append(<div class=\"pagefilters__noresults\">{getTid(\"utwente_base:frontend.ws2016.js.newsevents.noresults\")}</div>);\n      }\n    }\n\n    dompack.registerMissed(this.summarycontainer); // used to pick up add to calendar buttons (.addeventatc) in new results\n\n    return null;\n  }\n\n  renderItems(res: NEOResultsType, isMoreResults: boolean, isAnySet: boolean): HTMLElement[] {\n    const items: HTMLElement[] = [];\n\n    if (!isAnySet && !isMoreResults) {\n      const introItems: HTMLElement[] = [];\n\n      res.items.forEach((item, c) => {\n        if (c >= 2)\n          return;\n\n        if (!item.photolink) {\n          item.photolink = this.photoplaceholder;\n          item.photolink_2x = this.photoplaceholder_2x;\n        }\n\n        introItems.push(<li class=\"summary__introblock\">\n          <a class=\"summary__link\" href={item.link}>\n            {item.photolink ? <img class=\"summary__image\" src={item.photolink} srcset={`${item.photolink} 1x, ${item.photolink_2x} 2x`} alt={item.photoalt || item.title} /> : null}\n            <span class=\"summary__title\">{item.title}</span>\n            {item.description ? <span class=\"summary__description\"><span>{item.description}</span></span> : null}\n            <div class=\"summary__date\">{item.dateformatted}</div>\n            {item.location ? <span class=\"location\">{item.location}</span> : null}\n            {item.tags.length ? <span class=\"tags\">\n              {item.tags.map(tag => tag.filter ? <span class=\"tag\" data-filter={tag.filter} data-id={tag.id}>{tag.tag}</span> : <span class=\"tag\">{tag.tag}</span>)}\n            </span> : null}\n            <span class=\"summary__readmore\">{getTid(\"utwente_base:frontend.ws2016.js.readmore\")}</span>\n          </a>\n        </li>);\n      });\n\n      if (introItems.length > 0)\n        items.push(<ul class=\"summary__introblocks\">{introItems}</ul>);\n    }\n\n    const otherItems: HTMLElement[] = [];\n    res.items.forEach((item, c) => {\n\n      if (!item.summaryphotolink) {\n        item.summaryphotolink = this.summaryplaceholder;\n        item.summaryphotolink_2x = this.summaryplaceholder_2x;\n      }\n\n      otherItems.push(<li class={`summary__item ${!isAnySet && !isMoreResults && c < 2 ? `summary__item--mobileonly` : ``}`}>\n        {this.hasfoldableitems ?\n          <div class=\"summary__link\" onClick={(ev: Event) => this.toggleItemContent(ev)}>\n            {item.summaryphotolink ? <img class=\"summary__image\" src={item.summaryphotolink} srcset={`${item.summaryphotolink} 1x, ${item.summaryphotolink_2x} 2x`} alt={item.summaryphotoalt || item.title} /> : null}\n            <span class=\"summary__meta\">\n              <span class=\"date\">{item.dateformatted}</span>\n              {item.location ? <span class=\"location\">{item.location}</span> : null}\n            </span>\n            <span class=\"summary__title\">{item.title}</span>\n            <div class=\"summary__foldablecontent\">\n              {item.subtitle ? <span class=\"summary__subtitle\">{item.subtitle}</span> : null}\n              {item.description ? <span class=\"summary__description\">{item.description}</span> : null}\n            </div>\n            {item.tags.length ? <span class=\"tags\">\n              {item.tags.map(tag => tag.filter ? <span class=\"tag\" data-filter={tag.filter} data-id={tag.id}>{tag.tag}</span> : <span class=\"tag\">{tag.tag}</span>)}\n            </span> : null}\n            <div class=\"summary__foldablecontent\">\n              {item.addthisdata ? <div class=\"summary__calendar\">\n                <span class=\"icon UT-icon-UT_icon_84_calendar-16px\"></span>\n                <span class=\"addtocalendar addthisevent addeventatc\">\n                  {getTid(\"utwente_base:frontend.ws2016.js.addtocalendar\")}\n                  <span class=\"start\" hidden>{item.addthisdata.startdate}</span>\n                  <span class=\"end\" hidden>{item.addthisdata.enddate}</span>\n                  <span class=\"timezone\" hidden>Europe/Amsterdam</span>\n                  <span class=\"title\" hidden>{item.title}</span>\n                  <span class=\"description\" hidden>{item.addthisdata.description}</span>\n                  {item.location ? <span class=\"location\" hidden>{item.location}</span> : null}\n                  <span class=\"all_day_event\" hidden>{item.addthisdata.allday ? 'true' : 'false'}</span>\n                  <span class=\"date_format\" hidden>DD/MM/YYYY</span>\n                </span>\n              </div> : null}\n              <a href={item.link} class=\"summary__readmore\">{getTid(\"utwente_base:frontend.ws2016.js.readmore\")}</a>\n            </div>\n            <span class=\"summary__arrow\"><span class=\"open UT-icon-UT_icon_54_arrow-down-round-16px\"></span><span class=\"close UT-icon-UT_icon_53_arrow-up-round-16px\"></span></span>\n          </div>\n          : <a class=\"summary__link\" href={item.link}>\n            {item.summaryphotolink ? <img class=\"summary__image\" src={item.summaryphotolink} srcset={`${item.summaryphotolink} 1x, ${item.summaryphotolink_2x} 2x`} alt={item.summaryphotoalt || item.title} /> : null}\n            <span class=\"summary__meta\">\n              <span class=\"date\">{item.dateformatted}</span>\n              {item.location ? <span class=\"location\">{item.location}</span> : null}\n            </span>\n            <span class=\"summary__title\">{item.title}</span>\n            {item.tags.length ? <span class=\"tags\">\n              {item.tags.map(tag => tag.filter ? <span class=\"tag\" data-filter={tag.filter} data-id={tag.id}>{tag.tag}</span> : <span class=\"tag\">{tag.tag}</span>)}\n            </span> : null}\n            <span class=\"summary__arrow UT-icon-UT_icon_52_arrow-right-round-16px\"></span>\n          </a>\n        }\n      </li>);\n    });\n\n    if (otherItems.length > 0) {\n      if (isMoreResults) { // Then just append to existing container (e.g. when loading more results), otherwise create new container\n        const container = dompack.qS<HTMLUListElement>(this.summarycontainer, \".summary__items\");\n        if (container)\n          container.append(...otherItems);\n      } else {\n        items.push(<ul class=\"summary__items\">{otherItems}</ul>);\n      }\n    }\n\n    return items;\n  }\n\n  toggleItemContent(ev: Event) {\n    const itemEl = (ev.target as HTMLElement);\n    if (itemEl.closest(\"a\") || itemEl.closest(\".addthisevent\"))\n      return;// Just follow link or trigger addthisevent, don't toggle content\n\n    itemEl.closest(\".summary__link\")?.classList.toggle(\"foldablecontent--active\");\n  }\n}\n\n\nclass EventsFormHandler extends UTRPCFormBase {\n  wrapper: HTMLDivElement;\n  msgcontainer: HTMLDivElement;\n  requesttype: string;\n  dialog: utDialog2 | null = null;\n\n  constructor(formnode: HTMLFormElement, requesttype: string) {\n    super(formnode);\n\n    this.requesttype = requesttype;\n    this.wrapper = document.createElement(\"div\");\n    this.msgcontainer = document.createElement(\"div\");\n    this.node.style = \"\";\n    this.wrapper.appendChild(this.node);\n    this.wrapper.appendChild(this.msgcontainer);\n\n    for (const node of document.querySelectorAll(\".cta__button[href='#showeventform']\"))\n      node.addEventListener(\"click\", ev => this.show(ev));\n  }\n\n  show(ev: Event) {\n    this.node.hidden = false;\n    this.msgcontainer.textContent = \"\";\n    if (ev)\n      ev.preventDefault();\n    this.reset();\n    this.dialog = new utDialog2(this.wrapper, \"event_registration\", { classname: \"dialog--small\" });\n    this.dialog.showModal();\n  }\n\n  onSubmitSuccess() {\n    this.node.hidden = true;\n    this.msgcontainer.textContent = this.requesttype === 'cultural' ? getTid(\"utwente_base:frontend.ws2016.js.newsevents.thanks-cultural\")\n      : getTid(\"utwente_base:frontend.ws2016.js.newsevents.thanks-event\");\n  }\n}\n\nregisterCustomFilter(\"neoFilter\", () => new NeoPageFilter());\nregisterHandler(\"utwente_base:event_registration\", registrationform => new EventsFormHandler(registrationform, \"event\"));\n","import \"./people.scss\";\nimport * as dompack from '@webhare/dompack';\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\nimport UTAutoComplete from '@mod-utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter';\nimport { SearchIndex } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/searchindex\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_base:peoplepage\": {\n      persons: {\n        category: string;\n        personid: string;\n        textcontent: string; // '\\n' separated text fields, first part is name of person\n      }[];\n    };\n  }\n}\n\ninterface IndexedItem {\n  title: string;\n  description: string;\n  personid: string;\n}\n\nclass peoplePageFilter {\n  node: HTMLFormElement;\n  container: HTMLElement;\n  searchIndex: SearchIndex<IndexedItem> | null = null;\n  filter: {category: string; query: string} = {category: \"\", query: \"\"};\n  constructor(node: HTMLFormElement) {\n    this.node = node;\n\n    const titlebar = dompack.qS(\".page-titlebar\");\n    if( titlebar ) // Move inside titlebar if it exists\n      titlebar.append(this.node);\n\n    this.container = dompack.qR(\".peopleoverview__list\");\n\n    const searchinput = dompack.qR(this.node, \".peopleoverview__filterform__search input\") as HTMLInputElement;\n\n    const queryindex = getFrontendData(\"utwente_base:peoplepage\");\n    if( queryindex && searchinput ) {\n      this.searchIndex = new SearchIndex<IndexedItem>();\n      this.searchIndex.searchFields = [\"title\", \"description\"];\n      this.searchIndex.completeSuggestFields = [\"title\"];\n\n      queryindex.persons.forEach(item => {\n        const parts = item.textcontent.split(\"\\n\");\n        const title = parts.shift() || \"\";\n        const description = parts.join(\"\\n\");\n        this.searchIndex!.indexItem( { personid: item.personid, title, description });\n      });\n\n      UTAutoComplete({\n        input: searchinput,\n        className: 'ut-autocomplete',\n        preventSubmit: 1,\n        fetch: (text, update) => {\n          const suggestions = this.searchIndex!.suggest(text).slice(0, 10);\n          update(suggestions.map(_ => { return { label: _, value: _ }; }));\n        },\n        onSelect: (item) => {\n          searchinput.value = item.label ?? \"\";\n          dompack.dispatchDomEvent(searchinput, \"change\"); // Trigger filtering\n        },\n        customize: (input, inputRect, container, maxHeight) => {\n          // use search form width istead of input width\n          const width = input.parentElement!.offsetWidth;\n          const leftPos = inputRect.left + (inputRect.width - width);\n          container.style.width = width + \"px\";\n          container.style.left = leftPos + \"px\";\n        }\n      });\n    }\n\n    this.node.addEventListener(\"submit\", evt => { evt.preventDefault(); this.onFilter(); });\n    this.node.addEventListener(\"change\", () => this.onFilter());\n    searchinput.addEventListener(\"search\", () => this.onFilter());\n\n    this.onFilter(true);\n  }\n\n  onFilter(isInitial:boolean | undefined = false) {\n    const query = this.node.query.value. trim().toLowerCase();\n    const selectedCategory = dompack.qS<HTMLInputElement>(this.node, \"input[name=category]:checked\");\n    const category = selectedCategory ? selectedCategory.value : \"\";\n\n    if( this.filter.query === query && this.filter.category === category && !isInitial )\n      return;\n\n    this.filter.query = query;\n    this.filter.category = category;\n\n    const matchedPersonIds: string[] = [];\n    if( query && this.searchIndex ) {\n      const result = this.searchIndex.search(query);\n      matchedPersonIds.push(...result.items.map(_ => _.personid));\n    }\n\n    dompack.qSA(\".peopleoverview__person\").forEach(item => {\n      let isMatch = !query || matchedPersonIds.includes(item.dataset.personid || \"\");\n      if( isMatch )\n        isMatch = category === \"\" || item.dataset.category === category;\n\n      item.hidden = !isMatch;\n    });\n\n    // hide category if all its persons are hidden\n    dompack.qSA(\".peopleoverview__category\").forEach(cat => {\n      cat.hidden = dompack.qSA(\".peopleoverview__person[data-category='\"+cat.dataset.category+\"']\").every(_ => _.hidden);\n    });\n\n    this.updateFiltersInUrl();\n  }\n\n  updateFiltersInUrl() {\n    const loc = new URL(location.href);\n\n    // First remove all filter-related params, then add the currently active ones. This ensures the URL doesn't get cluttered with old params when changing filters\n    for( const filtername of Object.keys(this.filter) )\n      loc.searchParams.delete(filtername);\n\n    for (const [filtername, value] of Object.entries(this.filter)) {\n      if( value )\n        loc.searchParams.set(filtername, value);\n    }\n\n    history.replaceState(null, \"\", loc.toString());\n  }\n}\n\ndompack.register<HTMLFormElement>(\".peopleoverview__filterform\", form => new peoplePageFilter(form));\n","import \"./tablewithfilter.scss\";\nimport * as dompack from '@webhare/dompack';\nimport { getTid } from \"@webhare/gettid\";\nimport UtwenteService from \"@mod-utwente_base/js/service\";\n\nclass tableWithFilter {\n  container:HTMLElement;\n  constructor(container:HTMLElement) {\n    this.container = container;\n    const filterbuttons = dompack.qS(\".page-filters__form__buttons\");\n    if( filterbuttons )\n      filterbuttons.prepend(<button tabindex=\"0\" type=\"button\" onClick={() => void this.downloadXLSX()} class=\"ctabutton-with-rightarrow ctabutton-with-rightarrow--download tablewithfilter__downloadbutton\"><span class=\"ctabutton-with-rightarrow__title\">{getTid(\"utwente_base:frontend.ws2016.js.tablewithfilter.downloadxlsx\")}</span></button>);\n\n    window.addEventListener(\"resize\", () => this.onResize());\n    window.addEventListener(\"load\", () => this.onResize());\n    this.container.addEventListener(\"pagefilters:afterfilter\", () => this.onResize());\n    this.onResize();\n  }\n\n  onResize() {\n    this.container.classList.toggle(\"overflow\", this.container.clientWidth < this.container.scrollWidth);\n  }\n\n  async downloadXLSX() {\n    const lock = dompack.flagUIBusy({ modal: true });\n\n    const idxlist: number[] = [];\n    dompack.qSA(this.container, \".pagefilters__item\").forEach(item => idxlist.push(Number(item.dataset.idx)));\n\n    let result: { data: string; filename: string } | null = null;\n    try {\n      result = await UtwenteService.GetXLSXExport(document.location.href, idxlist);\n    } finally {\n      lock.release();\n    }\n\n    if (!result || !result.data)\n      return;\n\n    const filedata = this.dataURLtoBlob(result.data);\n\n    const file = window.URL.createObjectURL(filedata);\n    const link = <a download={result.filename} />;\n    link.href = file;\n    document.body.appendChild(link);\n    link.click();\n\n    window.URL.revokeObjectURL(file);\n    link.remove();\n  }\n\n  dataURLtoBlob(dataurl: string) {\n    const arr = dataurl.split(',');\n    const mime = arr[0].match(/:(.*?);/)?.[1] ?? \"application/octet-stream\";\n    const bstr = atob(arr[1]);\n    let n = bstr.length;\n    const u8arr = new Uint8Array(n);\n    while (n--)\n      u8arr[n] = bstr.charCodeAt(n);\n    return new Blob([u8arr], { type: mime });\n  }\n}\n\ndompack.register(\".tablewithfilter__scrollcontainer\", node => setTimeout(() => new tableWithFilter(node), 200)); // Small delay so filterpanel is already initialized\n","\nimport * as dompack from '@webhare/dompack';\nimport { DefaultFilter, CustomPageFilter, PageFiltersContext, registerCustomFilter } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters\";\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\nimport { getTid } from '@webhare/gettid/src/internal';\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_base:timelinepage\": {\n      addstoryLink: string;\n      addstoryText: string;\n    };\n  }\n}\n\ndeclare global {\n  interface Window {\n    __timelines: Array<{\n      widgetnode: HTMLElement;\n      yearsinresults: number[];\n      refreshYearBookmarks: () => void;\n      refresh: () => void;\n    }>;\n  }\n}\n\n// See mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/timeline/index.ts, used for rending items\nwindow.__timelines = window.__timelines || [];\n\nclass TimelinePageFilter implements CustomPageFilter {\n  node: HTMLElement;\n  myFilter: DefaultFilter; // We use the default filter for the actual filtering, we just rewrite results for specific rendering afterward depending on the view mode\n  constructor() {\n    this.node = dompack.qR(\".timeline__items\");\n    this.myFilter = new DefaultFilter(null);\n\n    const settings = getFrontendData(\"utwente_base:timelinepage\");\n    if( settings && settings.addstoryLink && settings.addstoryText ) {\n      const buttonsWrapper = dompack.qS(\".page-filters__form__buttons\");\n      if( buttonsWrapper)\n        buttonsWrapper.prepend(<div class=\"timeline__addstorylink\">\n          <a href={settings.addstoryLink} rel=\"noopener noreferrer\"><span>{settings.addstoryText}</span></a>\n        </div>);\n    }\n  }\n\n  async filter(filtercontext: PageFiltersContext): Promise<HTMLElement[] | null> {\n    const items = this.myFilter.filter(filtercontext) || [];\n    const idxList = items.map(item => Number(item.dataset.idx || \"\"));\n\n    const visibleYears: number[] = [];\n    dompack.qSA(this.node, \".timeline__item\").forEach(item => {\n      const seqnr = Number(item.dataset.idx || \"\");\n      const isMatch = idxList.includes(seqnr);\n      if( isMatch ) {\n        const year = Number(item.dataset.filterYear || \"\");\n        if( !visibleYears.includes(year) )\n          visibleYears.push(year);\n      }\n\n      item.classList.toggle(\"timeline__item--hide\", !isMatch);\n    });\n\n    // Show/hide year headers based on whether they have visible items\n    dompack.qSA(this.node, \".timeline__header[data-year]\").forEach(item => {\n      const year = Number(item.dataset.year || \"\");\n      item.classList.toggle(\"timeline__item--hide\", !visibleYears.includes(year));\n    });\n\n    dompack.qSA(\".page-filterstoolbar__feedback\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.search-xresults\", String(idxList.length)));\n    dompack.qSA(\".page-filters__mobiletoggle__hidelabel\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-xresults\", String(idxList.length)));\n\n    // See mod::utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/timeline/index.ts\n    for (const tlwidget of window.__timelines) {\n      tlwidget.widgetnode.classList.toggle(\"embeddedobject--timeline--noresults\", idxList.length === 0);\n\n      tlwidget.yearsinresults = visibleYears; // for the year bookmark list\n      tlwidget.refreshYearBookmarks(); // content of some years might not be visible anymore\n      tlwidget.refresh();\n    }\n\n    // We do not want to filter out any items, we just want to update their visibility based on the default filter results.\n    // return null here to indicate that we don't want to change the default filtering result\n    return null;\n  }\n}\n\nregisterCustomFilter(\"TimelinePageFilter\", () => new TimelinePageFilter());\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport './donaties.scss';\nimport * as dompack from 'dompack';\nimport * as whintegration from '@mod-system/js/wh/integration';\nimport { registerHandler } from '@mod-publisher/js/forms';\nimport JSONRPC from \"@mod-system/js/net/jsonrpc\";\nimport { getTid } from \"@webhare/gettid\";\nimport * as modaldialog from \"../../../ws2016/src/shared/dialog\";\nimport { UTRPCFormBase } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts\";\nimport { navigateTo } from '@webhare/env';\n\nclass uFondsForm extends UTRPCFormBase {\n  constructor(formnode) {\n    super(formnode);\n\n    this.amountoptions = this.node.querySelectorAll(\"input[name='amount']\");\n    //Check for other amount\n    for (const chknode of this.amountoptions)\n      chknode.addEventListener(\"change\", this.setAdditionalAmountFields.bind(this));\n\n    this.paymentmethodoptions = this.node.querySelectorAll(\"input[name='payment_method']\");\n    //Check if paymentmethod is 'incasso'\n    for (const chknode of this.paymentmethodoptions)\n      chknode.addEventListener(\"change\", this.setAdditionalPaymentMethodFields.bind(this));\n\n    //Check if donation is from organization\n    this.elements.isorganization.addEventListener(\"change\", this.setAdditionalOrganizationFields.bind(this));\n\n    this.setAdditionalFields();\n\n    if (this.getUrlParam(\"payment\") == \"1\" && whintegration.config.obj.payment)//redirect after payment\n    {\n      if (whintegration.config.obj.payment.status == \"failed\")\n        this.showErrorDialog();\n      else\n        this.showSuccessDialog(whintegration.config.obj.payment.destination);\n    }\n\n    this.elements.amount_other.addEventListener(\"change\", ev => this.sanitizeOtherAmount());\n  }\n\n  sanitizeOtherAmount() {\n    let val = this.elements.amount_other.value;\n    let decsep = val.lastIndexOf(\".\") >= val.lastIndexOf(\",\") ? \".\" : \",\";\n    val = decsep == \".\" ? val.replace(/[^0-9\\.]/g, '') : val.replace(/[^0-9,]/g, '');\n\n    if (val.indexOf(decsep) == -1)\n      val += decsep + \"00\";\n\n    const parts = val.split(decsep);\n    let cents = parts.pop().substr(0, 2);\n    if (cents.length < 2)\n      cents += (cents.length == 0 ? \"00\" : \"0\");\n    const full = parts.join(\"\");\n\n    decsep = document.documentElement.lang.indexOf(\"en\") == -1 ? \",\" : \".\";\n\n    this.elements.amount_other.value = (1 * full + 1 * cents) > 0 ? full + decsep + cents : \"\";\n  }\n\n  setAdditionalFields() {\n    this.setAdditionalAmountFields();\n    this.setAdditionalPaymentMethodFields();\n    this.setAdditionalOrganizationFields();\n  }\n\n  setAdditionalAmountFields() {\n    let selval = this.getValue(\"amount\");\n    if (!selval)\n      selval = \"\";\n\n    if (1 * selval > 0 || selval == \"\") {\n      this.elements.amount_other.closest(\".wh-form__fieldgroup\").style.display = \"none\";\n      this.elements.amount_other.required = false;\n    } else {\n      this.elements.amount_other.closest(\".wh-form__fieldgroup\").style.display = \"\";\n      this.elements.amount_other.required = true;\n    }\n  }\n\n  setAdditionalPaymentMethodFields() {\n    const toggleincassofieldsnames = [\"iban\", \"bankaccount_name\", \"agree\"];\n\n    let selval = this.getValue(\"payment_method\");\n    if (!selval)\n      selval = \"\";\n\n    if (selval == \"incasso\") {\n      for (const fieldname of toggleincassofieldsnames) { //show fields needed for incasso\n        this.elements[fieldname].closest(\".wh-form__fieldgroup\").style.display = \"\";\n        this.elements[fieldname].required = true;\n      }\n    } else {\n      for (const fieldname of toggleincassofieldsnames) { //hide fields needed for incasso\n        this.elements[fieldname].closest(\".wh-form__fieldgroup\").style.display = \"none\";\n        this.elements[fieldname].required = false;\n      }\n    }\n  }\n\n  setAdditionalOrganizationFields() {\n    if (this.elements.isorganization.checked) {\n      this.elements.organization.closest(\".wh-form__fieldgroup\").style.display = \"\";\n      this.elements.organization.required = true;\n    } else {\n      this.elements.organization.closest(\".wh-form__fieldgroup\").style.display = \"none\";\n      this.elements.organization.required = false;\n    }\n  }\n\n  getUrlParam(name) {\n    const urlparamstr = location.search.replace(/\\+/g, \"%20\");\n    if (name = (new RegExp('[?&]' + encodeURIComponent(name) + '=([^&]*)')).exec(urlparamstr))\n      return decodeURIComponent(name[1]);\n    return \"\";\n  }\n\n  onSubmitSuccess(res) {\n    if (res.success) {\n      this.reset();\n      this.setAdditionalFields();\n\n      if (res.redirect) {\n        navigateTo(res.redirect);\n        return;\n      }\n\n      this.showSuccessDialog(res.destination);\n    }\n  }\n\n  showErrorDialog() {\n    const title = getTid(\"utwente_base:frontend.ws2016.js.ufondsdonaties.error-title\");\n    const description = getTid(\"utwente_base:frontend.ws2016.js.ufondsdonaties.error-description\");\n\n    this.dialognode = modaldialog.showModalDialog(title, description, { theme: \"dialog--small\" });\n  }\n\n  showSuccessDialog(destination) {\n    const title = getTid(\"utwente_base:frontend.ws2016.js.ufondsdonaties.thanks-title\");\n    const description = getTid(\"utwente_base:frontend.ws2016.js.ufondsdonaties.thanks-description\");\n    this.dialognode = modaldialog.showModalDialog(title, description, { theme: \"dialog--small\" });\n  }\n}\n\nregisterHandler(\"utwente_base:ufonds_donatie\", node => new uFondsForm(node));\n","/* UT auth library\n\n   This library is shared between utwente_base and serviceportal and implements the UT Global login\n\n   The menu/button in the WS2020 header is implemented in webdesigns/ws2016/src/shared/login/index.es\n\n   Classes\n   .ut-login--clicktologin   convert any element to a login button\n*/\n\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as wrdauth from \"@mod-wrd/js/auth\";\nimport { getLocal, getSession, setLocal, setSession } from '@webhare/dompack';\nimport { getLoginLink, getUTUserInfo } from \"@mod-utwente_design/js/crm/auth\";\nexport { getLoginLink, getUTUserInfo } from \"@mod-utwente_design/js/crm/auth\";\n\nexport function catchServicePortalLoginLink() {\n  /* Any click to x-serviceportal:login is handled by a Just In Time Link Replacement™. This solution should work as long as\n   noone messages with history.pushState & co.*/\n  window.addEventListener(\"click\", ev => {\n    const link = (ev.target as HTMLElement).closest(\"a[href]\") as HTMLAnchorElement;\n    if (!link)\n      return;\n\n    const linktarget = link.href.split('?')[0];\n    if (linktarget === 'x-serviceportal:login') {\n      const user = getUTUserInfo();\n      link.href = getLoginLink({ prompt: (user ? true : false) }); //if you hit a login link while logged in, you probably need to switch accounts\n    }\n  });\n}\n\nexport function utSilentLogin(why: string) {\n  setSession(\"utwente-triedsilentlogin\", why || \"explicit user request\"); //anti-loop flag\n  console.log(\"[ut-login] Attempting silent login because: \" + getSession(\"utwente-triedsilentlogin\"));\n  location.href = getLoginLink({ silent: true });\n}\n\nfunction getReasonforSilentLogin() {\n  const ls = getLocal<string>(\"utwente-lastseenlogin\");\n  if (ls)\n    return \"You were logged in at \" + new Date(parseInt(ls)).toLocaleString();\n\n  const beacons = crm.getUserBeacons();\n  if (beacons && beacons[\"usertype-employee\"])\n    return `You have beacon 'usertype-employee' with value '${beacons[\"usertype-employee\"]}`;\n  if (beacons && beacons[\"usertype-student\"])\n    return `You have beacon 'usertype-student' with value '${beacons[\"usertype-student\"]}`;\n\n  return null;\n}\n\nfunction isFrame() {\n  if (window.top === window)\n    return false; //we're toplevel\n  try {\n    //@ts-ignore only WH5.7 defines this __testframework. TODO @webhare/frontend will have isiNTestFramework once all in WH5.7+\n    if (window.parent.__testframework)\n      return false; //we're inside a testframe, pretend to be the parent\n  } catch (e) {\n\n  }\n  return true;\n}\n\n/** @returns true if we're redirecting awawy from the page */\nfunction handleAutoLogin(): boolean {\n  if (document.documentElement.dataset.noutlogin  //eg. webhare login page uses noutlogin to prevent the 'special account' from becoming unreachable for us\n    || isFrame()  //don't autologin in eg managed cta preview either\n    || location.pathname.startsWith(\"/.publisher/preview/\") //preview redirects are hosted on webhare, not www, and confuse the login system\n    || location.origin === 'alumniportal.utwente.nl') //and although alumniportal lives under utwente.nl - it's not part of the same server and should'n't SSO\n    return false;\n\n  if (!wrdauth.getDefaultAuth()?.isLoggedIn() && !getSession(\"utwente-triedsilentlogin\")) {\n    const reason = getReasonforSilentLogin();\n    if (reason) {\n      utSilentLogin(reason);\n      return true;\n    }\n  }\n  if (getSession(\"utwente-triedsilentlogin\") && getSession(\"utwente-triedsilentlogin\") !== \"done\") {\n    console.log(\"[ut-login] We tried a silent login earlier because: \" + getSession(\"utwente-triedsilentlogin\") + \". It looks like it \" + (wrdauth.getDefaultAuth()?.isLoggedIn() ? \"succeeded\" : \"failed\"));\n    setSession(\"utwente-triedsilentlogin\", \"done\"); //don't retry this session\n  }\n  return false;\n}\n\n/**\n * Handle the UT Global Login process.\n * This function checks if the user is already logged in and handles auto-login if necessary.\n * @returns true if we're redirecting away from the page\n */\nexport function handleUTGLobalLogin(): boolean {\n  //WARNING dom may not yet be ready when we run here\n  const auth = wrdauth.getDefaultAuth();\n  if (!auth)\n    return false;\n\n  if (handleAutoLogin())\n    return true;\n\n  if (wrdauth.getDefaultAuth()?.isLoggedIn())\n    setLocal(\"utwente-lastseenlogin\", Date.now().toString());\n\n  return false;\n}\n","import { register } from \"@webhare/dompack\";\nimport { loadAssetPack } from \"@webhare/frontend\";\n\n/*\n  We replace the original:\n    <addtoassetpack assetpack=\"utwente_base:ws2016\" entrypoint=\"webfeatures/aiexperts/aiexperts.es\" />\n    <addtoassetpack assetpack=\"utwente_base:ws2016\" entrypoint=\"webfeatures/transport/transportexperts.es\" />\n    <addtoassetpack assetpack=\"utwente_base:ws2016\" entrypoint=\"webfeatures/robotics/roboticsexperts.es\" />\n    <addtoassetpack assetpack=\"utwente_base:ws2016\" entrypoint=\"webfeatures/climate/climateexperts.tsx\" />\n    <addtoassetpack assetpack=\"utwente_base:ws2016\" entrypoint=\"webfeatures/chip/chipexperts.tsx\" />\n\n  and load the datacloud bundle async so we can avoid the JS code until the datacloud is actually accessed\n\n  We're split up in two parts:\n  - datacloud-loader - this gets included in the ws2016 bundle and needs to be as compact as possible\n  - datacloud-async - this part is loaded asynchronously and contains all the three Expertfinders, plus the datacloud\n\n  we can't do 'await import(\"./aiexperts/aiexperts\")' etc here, as then we'd get three chunks for all the async imports, and a shared datacloud import=\n*/\n\nlet assetPackPromise: ReturnType<typeof loadAssetPack> | null = null;\n\nregister(\".datacloud-header\", node => {\n  if (!assetPackPromise)\n    assetPackPromise = loadAssetPack(\"datacloud:datacloud\");\n});\n","import \"./course.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { getTid } from \"@mod-tollium/js/gettid\";\nimport { RPCFormBase, registerHandler, type FormSubmitEmbeddedResult } from '@mod-publisher/js/forms';\n\ntype submitResultType = {\n  followupcourselink: string;\n  success: boolean;\n  id: number;\n  parentcourse: number;\n  parentcoursetitle: string;\n  serieid: number;\n  code: string;\n  paymentlink: string;\n  registration_guid: string;\n  onwaitinglist: boolean;\n  name?: string;\n};\n\nclass RegistrationForm extends RPCFormBase {\n  header: { prefixnode: HTMLElement; titlenode: HTMLElement; descriptionnode: HTMLElement };\n  resulttxtnode: HTMLElement;\n  loginbtn: HTMLButtonElement | null;\n  constructor(node: HTMLFormElement) {\n    super(node);\n\n    this.addSignupDeeplink();\n\n    //Get nodes within inlinecta header for altering texts\n    this.header = {\n      prefixnode: dompack.qR(this.node, \".formheader__prefix\"),\n      titlenode: dompack.qR(this.node, \".formheader__title\"),\n      descriptionnode: dompack.qR(this.node, \".formheader__description\")\n    };\n\n    const nextbtn = dompack.qS(this.node, \".wh-form__button--nextlabel, .wh-form__button--submit .wh-form__buttonlabel\");\n    if (nextbtn)\n      nextbtn.textContent = getTid('utwente_courses:webfeatures.frontend.js.nextstep');\n\n    this.resulttxtnode = dompack.qR(this.node, \".resulttext\");\n\n    if (this.node.loggedinuser.value && dompack.qS(this.node, \"input[name=serie]:checked\")) // Logged in and serie preselected, goto second page directly\n      void this.gotoPage(1);\n\n    if (this.node.classList.contains(\"wh-form--disabledsubmit\")) { //If login required and not loggedin, block submit\n      this.node.addEventListener(\"wh:form-beforesubmit\", ev => {\n        ev.preventDefault();\n      });\n    }\n\n    this.node.addEventListener(\"wh:form-pagechange\", ev => this.onPageChange(ev.target as HTMLElement));\n\n    this.loginbtn = dompack.qS(\"#coursefinder-login\");\n    if (this.loginbtn)\n      this.loginbtn.addEventListener(\"click\", ev => this.login(ev));\n\n    setTimeout(() => this.initFoldableSeries(), 200);\n  }\n\n  addSignupDeeplink() {\n    const deeplinklist = dompack.qS(\".main__deeplinklist\");\n    if (deeplinklist) {\n      deeplinklist.appendChild(<li class=\"main__deeplinkitem\">\n        <a class=\"main__deeplink\" href=\"#signup\">{getTid('utwente_courses:webfeatures.frontend.js.signup')}</a>\n      </li>);\n    }\n  }\n\n  login(ev: MouseEvent) {\n    ev.preventDefault();\n    if (this.loginbtn)\n      document.location.href = this.loginbtn.dataset.url + \"?serie=\" + this.node.serie.value + \"#signup\";\n  }\n\n  onPageChange(page: HTMLElement) {\n    if (page.dataset.whFormPagerole === \"thankyou\")\n      return;\n\n    this.header.prefixnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.signupfor');\n    this.header.titlenode.textContent = this.node.dataset.coursetitle as string;\n\n    if (page.classList.contains(\"wh-form__page--series\")) {\n      this.header.descriptionnode.textContent = \"\";\n      this.node.classList.remove(\"hidefootnote\");\n    } else {//Set selected serie into header description\n      const selectedserie = this.getSelectedOption(\"serie\");\n      let description = \"\";\n      if (selectedserie) {\n        this.node.classList.toggle(\"hidefootnote\", !selectedserie.inputnode.dataset.waitinglist);\n\n        dompack.qSA(selectedserie.fieldline!, \".session:first-child > .weekday, .session:first-child > .date, .session:first-child > .time, .note, .duration\").forEach(node => {\n          if (node.textContent !== \"\") {\n            if (node.classList.contains(\"duration\"))\n              description += \" (\" + node.textContent + \")\";\n            else {\n              if (description !== \"\")\n                description += \", \";\n              description += node.textContent;\n            }\n          }\n        });\n      }\n      this.header.descriptionnode.textContent = description;\n    }\n  }\n\n  initFoldableSeries() {\n    dompack.qSA(this.node, \".fieldgroup-serie .fieldgroup-serie__month\").forEach(node => {\n      node.addEventListener(\"click\", ev => this.toggleSerieMonth(node));\n\n      //And foldable serie within:\n      const monthitemswrapper = node.nextElementSibling as HTMLElement;\n      dompack.qSA(monthitemswrapper, \".wh-form__optiondata\").forEach(itemnode => {\n        const togglenode = dompack.qS(itemnode, \".duration\");\n        const sessionswrapper = dompack.qS(itemnode, \".sessions\");\n        if (togglenode && sessionswrapper) {\n          togglenode.addEventListener(\"click\", ev => {\n            sessionswrapper.style.maxHeight = \"\";\n            sessionswrapper.classList.toggle(\"showall\");\n            if (sessionswrapper.classList.contains(\"showall\")) {\n              let h = 0;\n              for (let i = 0; i < sessionswrapper.children.length; ++i)\n                h += sessionswrapper.children[i].clientHeight;\n              sessionswrapper.style.maxHeight = h + \"px\";\n\n              setTimeout(() => {\n                sessionswrapper.style.maxHeight = \"none\";\n              }, 300);\n            }\n          });\n        }\n      });\n    });\n  }\n\n  toggleSerieMonth(titlenode: HTMLElement) {\n    const foldnode = titlenode.nextElementSibling as HTMLElement;\n\n    foldnode.style.overflow = \"\";\n    if (titlenode.classList.contains(\"active\")) {\n      foldnode.style.height = foldnode.clientHeight + \"px\";\n      titlenode.classList.remove(\"active\");\n      void(foldnode.clientHeight);\n      foldnode.style.height = \"\";\n    } else {\n      let h = 0;\n      for (let i = 0; i < foldnode.children.length; ++i)\n        h += foldnode.children[i].clientHeight;\n\n      foldnode.style.height = h + \"px\";\n      titlenode.classList.add(\"active\");\n      void(foldnode.clientHeight);\n\n      setTimeout(function () {\n        foldnode.style.height = \"\";\n        foldnode.style.overflow = \"visible\"; //Needed for duration mouseover popup\n      }, 300);\n    }\n  }\n\n  onSubmitSuccess(result: FormSubmitEmbeddedResult & Partial<submitResultType>) {\n\n    this.resulttxtnode.replaceChildren();\n\n    if (result.success) {\n      this.header.prefixnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submitsuccess-prefix');\n      this.header.titlenode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submitsuccess-title');\n      if (result.onwaitinglist)\n        this.resulttxtnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submitsuccess-waitinglist');\n      else if (result.parentcourse)\n        this.header.descriptionnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submitsuccess-followupdescription', result.parentcoursetitle);\n      else\n        this.header.descriptionnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submitsuccess-description');\n\n      if (result.paymentlink) //Goto payment page\n        document.location.href = result.paymentlink;\n      else if (result.followupcourselink)\n        document.location.href = result.followupcourselink;\n      else\n        this.node.scrollIntoView();\n\n      /*\n      let closebutton = <button class=\"wh-form__button\">{getTid('utwente_courses:webfeatures.frontend.js.closeregistration')}</button>;//\n      closebutton.addEventListener(\"click\", ev => {\n        ev.preventDefault();\n        document.location.reload();\n      });\n      this.resulttxtnode.appendChild(closebutton);\n      */\n    } else {\n      // let title = getTid('utwente_courses:webfeatures.frontend.js.registrationerror_title');\n      let description = '';\n      switch (result.code) {\n        case 'nosuchcourse':\n          description = getTid('utwente_courses:webfeatures.frontend.js.registrationerror_nocourse');\n          break;\n        case 'nosuchserie':\n          description = getTid('utwente_courses:webfeatures.frontend.js.registrationerror_nosession');\n          break;\n        case 'full':\n          description = getTid('utwente_courses:webfeatures.frontend.js.registrationerror_full');\n          break;\n        case 'already_registered':\n          description = getTid('utwente_courses:webfeatures.frontend.js.registrationerror_already_registered');\n          break;\n        case 'fullwaitinglist':\n          description = getTid('utwente_courses:webfeatures.frontend.js.registrationerror_waitinglistfull');\n          break;\n        default:\n          description = result.code + (result.name ? ' : ' + result.name : '');\n      }\n\n      this.header.prefixnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submiterror-prefix');\n      this.header.titlenode.textContent = getTid('utwente_courses:webfeatures.frontend.js.submiterror-failed');\n      this.header.descriptionnode.textContent = description;\n\n      this.resulttxtnode.appendChild(<div class=\"errortitle\">{getTid('utwente_courses:webfeatures.frontend.js.registrationerror_title')}</div>);\n\n      const retrybutton = <button class=\"wh-form__button\">{getTid('utwente_courses:webfeatures.frontend.js.retry')}</button>;\n      retrybutton.addEventListener(\"click\", (ev: MouseEvent) => {\n        ev.preventDefault();\n        document.location.reload();\n      });\n      this.resulttxtnode.appendChild(retrybutton);\n    }\n  }\n}\n\nregisterHandler(\"utwente_courses:registrationform\", node => new RegistrationForm(node));\n","import \"./mycourses.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { cancelCourseDialog, payCourseDialog, showPaymentResult, type CourseDataType } from '../../components/dialogs';\nimport UTCoursesService from \"@mod-utwente_courses/js/site-service\";\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_courses:mycourses\": {token: string};\n  }\n}\n\ndompack.register(\".coursefinder__mycourses__tabs\", node => {\n  const pagecontainer = node.parentNode as HTMLElement;\n\n  if ([\"#history\", \"#coursealert\"].includes(location.hash)) {\n    const activetab = location.hash.substr(1);\n\n    for (let i = 0; i < node.children.length; ++i) {\n      const nodechild = node.children[i] as HTMLElement;\n      if (nodechild.dataset.view === activetab) {\n        nodechild.classList.add(\"active\");\n        pagecontainer.classList.add(\"coursefinder__mycourses--\" + nodechild.dataset.view);\n      } else {\n        nodechild.classList.remove(\"active\");\n        pagecontainer.classList.remove(\"coursefinder__mycourses--\" + nodechild.dataset.view);\n      }\n    }\n  }\n\n  node.addEventListener(\"click\", ev => {\n    for (let i = 0; i < node.children.length; ++i) {\n      const nodechild = node.children[i] as HTMLElement;\n      if (ev.target === nodechild) {\n        nodechild.classList.add(\"active\");\n        pagecontainer.classList.add(\"coursefinder__mycourses--\" + nodechild.dataset.view);\n      } else {\n        nodechild.classList.remove(\"active\");\n        pagecontainer.classList.remove(\"coursefinder__mycourses--\" + nodechild.dataset.view);\n      }\n    }\n  });\n});\n\ndompack.register(\".coursefinder__mycourses__showcanceled\", node => {\n  node.addEventListener(\"click\", () => {\n    const tabcountnode = dompack.qS(\".coursefinder__mycourses__tabs > li[data-view='history'] > .count\");\n    const parentnode = node.parentNode as HTMLElement;\n    if (parentnode.classList.contains(\"coursefinder__mycourses--showcanceled\")) {\n      parentnode.classList.remove(\"coursefinder__mycourses--showcanceled\");\n      if (tabcountnode && node.dataset.count)\n        tabcountnode.textContent = node.dataset.count;\n    } else {\n      parentnode.classList.add(\"coursefinder__mycourses--showcanceled\");\n      if (tabcountnode && node.dataset.totalcount)\n        tabcountnode.textContent = node.dataset.totalcount;\n    }\n  });\n});\n\n//Below is also used by cancel and payment page\ndompack.register(\"#coursefinder-paymentresult\", node => void showPaymentResult(node));\n\ndompack.register(\".coursefinder__registration\", node => {\n  node.addEventListener(\"click\", ev => {\n    const target = ev.target as HTMLElement;\n    if (target.classList.contains(\"cancel-registration\") && target.dataset.id)\n      cancelCourseDialog(target.dataset as CourseDataType);\n    else if (target.classList.contains(\"pay-registration\") && target.dataset.id)\n      payCourseDialog(target.dataset as CourseDataType);\n  });\n});\n\n\nasync function updateCourseAlert(categories: number[], unsubscibecourses: number[]) {\n  const token = getFrontendData(\"utwente_courses:mycourses\").token;\n  const language = document.documentElement.lang ? document.documentElement.lang.split(\"-\")[0] : \"en\";\n  const lock = dompack.flagUIBusy({ modal: true });\n  let result: {success: boolean; coursetitle: string};\n  try {\n    result = await UTCoursesService.UpdateCourseAlert(language, { categories, unsubscibecourses }, token);\n  } finally {\n    lock.release();\n  }\n\n/*\n  try {\n    result = await rpc.async(\"UpdateCourseAlert\", { categories, unsubscibecourses }, token);\n  } finally {\n    lock.release();\n  }\n*/\n  if (!result || !result.success)\n    console.error(\"Error updating course alert\");\n  else if (unsubscibecourses.length) {\n    const coursealertnodes = dompack.qSA(\".coursefinder__mycourses__coursealertform__courseline\");\n    const removenodes = coursealertnodes.filter(_ => unsubscibecourses.includes(Number(_.dataset.id)));\n    if (removenodes.length && coursealertnodes.length === removenodes.length)\n      coursealertnodes[0].closest(\".coursefinder__mycourses__coursealertform__col\")!.remove();\n    else if (removenodes.length)\n      removenodes.forEach(courselinenode => courselinenode.remove());\n  }\n}\n\nasync function unsubscribeCourseAlert() {\n  const token = getFrontendData(\"utwente_courses:mycourses\").token;\n  const language = document.documentElement.lang ? document.documentElement.lang.split(\"-\")[0] : \"en\";\n  const lock = dompack.flagUIBusy({ modal: true });\n  let result: {success: boolean};\n  try {\n    result = await UTCoursesService.UnsubscribeCourseAlert(language, token);\n  } finally {\n    lock.release();\n  }\n\n  if (!result || !result.success)\n    console.error(\"Error while unsubscribe course alert\");\n  else\n    dompack.qR(\".coursefinder__mycourses\").classList.add(\"coursefinder__mycourses--unsubscribedcoursealert\");\n}\n\ndompack.register(\".coursefinder__mycourses__coursealertunsubscribeform\", form => {\n  form.addEventListener(\"submit\", ev => {\n    ev.preventDefault();\n    void unsubscribeCourseAlert();\n  });\n});\n\ndompack.register(\".coursefinder__mycourses__coursealertform\", form => {\n  form.addEventListener(\"submit\", ev => {\n    ev.preventDefault();\n\n    const categories = dompack.qSA<HTMLInputElement>(form, \"input[name='categories']:checked\").map(_ => parseInt(_.value));\n    const unsubscibecourses = dompack.qSA<HTMLInputElement>(form, \"input[name='course']:not(:checked)\").map(_ => parseInt(_.value));\n    void updateCourseAlert(categories, unsubscibecourses);\n  });\n});\n","import \"./dialogs.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { getTid } from \"@mod-tollium/js/gettid\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport type { UTDialog } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/dialogs\";\nimport UTCoursesService from \"@mod-utwente_courses/js/site-service\";\n\nexport type CourseDataType = {\n  hash: string;\n  title: string;\n  date: string;\n  id: string;\n  price?: string;\n};\n\nclass cCancelCourse {\n  data: CourseDataType;\n  constructor(data: CourseDataType) {\n    console.log(data);\n    this.data = data;\n    void this.showDialog();\n  }\n\n  async showDialog() {\n    const dialog = dialogapi.createDialog() as UTDialog;\n    (dialog.contentnode as HTMLElement).appendChild(<div class=\"coursefinder__canceldialog\">\n      <h3>{getTid('utwente_courses:webfeatures.frontend.js.cancel') + \" '\" + this.data.title + \"'?\"}</h3>\n      <div class=\"course_date\">{\"( \" + getTid('utwente_courses:webfeatures.frontend.js.start') + \" \" + this.data.date + \" )\"}</div>\n      <div class=\"buttons\">\n        <button data-action=\"ok\" class=\"wh-form__button\">{getTid('utwente_courses:webfeatures.frontend.js.yes')}</button>\n        <button data-action=\"cancel\" class=\"wh-form__button\">{getTid('utwente_courses:webfeatures.frontend.js.no')}</button>\n      </div>\n    </div>);\n\n    dompack.registerMissed(dialog.contentnode!);\n\n    const id = Number(this.data.id);\n    const hash = this.data.hash;\n\n    (dialog.contentnode as HTMLElement).addEventListener(\"click\", (ev: MouseEvent) => {\n      if ((ev.target as HTMLElement).nodeName === \"BUTTON\") {\n        dialog.resolve(null);\n        if ((ev.target as HTMLElement).dataset.action === \"ok\" && id > 0 && hash)\n          this.doCancel(id, hash).catch(e => console.error(e));\n      }\n    });\n\n    void dialog.runModal();\n  }\n\n  async doCancel(id: number, hash: string) {\n    const language = document.documentElement.lang ? document.documentElement.lang.split(\"-\")[0] : \"en\";\n    const lock = dompack.flagUIBusy({ modal: true });\n    try {\n      await UTCoursesService.CancelCourse(language, id, hash);\n    } finally {\n      lock.release();\n    }\n    document.location.reload();\n  }\n}\n\n\nclass cPayCourse {\n  data: CourseDataType;\n  constructor(data: CourseDataType) {\n    this.data = data;\n    void this.showDialog();\n  }\n\n  async showDialog() {\n    const formnode = document.getElementById(\"coursefinder-paymentform\") as HTMLFormElement;\n    const dialog = dialogapi.createDialog({ borrow: formnode }) as UTDialog;\n\n    dompack.qR<HTMLInputElement>(formnode, \"input[name='id']\").value = this.data.id;\n    dompack.qR<HTMLInputElement>(formnode, \"input[name='pay']\").value = this.data.hash;\n\n    dompack.qR(dialog.contentnode!,\".course_title\").textContent = this.data.title;\n    dompack.qR(dialog.contentnode!,\".course_date\").textContent = this.data.date;\n    dompack.qR(dialog.contentnode!,\".course_price\").textContent = this.data.price || \"\";\n    formnode.style.display = \"\";\n\n    (dialog.contentnode as HTMLElement).addEventListener(\"click\", (ev: MouseEvent) => {\n      if ((ev.target as HTMLElement).nodeName === \"BUTTON\") {\n        dialog.resolve(null);\n        if ((ev.target as HTMLElement).dataset.action === \"pay\" && Number(this.data.id) > 0 && this.data.hash)\n          formnode.submit();\n      }\n    });\n\n    await dialog.runModal();\n  }\n}\n\nexport async function showPaymentResult(node: HTMLElement) {\n  const dialog = dialogapi.createDialog() as UTDialog;\n  dialog.contentnode!.appendChild(node);\n  node.style.display = \"\";\n\n  const btn = node.querySelector(\"button\");\n  if (btn)\n    btn.addEventListener(\"click\", () => dialog.resolve(null));\n\n  void dialog.runModal();\n}\n\nexport function cancelCourseDialog(data: CourseDataType) {\n  new cCancelCourse(data);\n}\n\nexport function payCourseDialog(data: CourseDataType) {\n  new cPayCourse(data);\n}\n","import { createClient } from \"@webhare/jsonrpc-client\";\n\nexport type getSerieOptionsType = {\n  title: string;\n  image: {normal: {link: string; width: number; height: number}; retina: {link: string; width: number; height: number}} | null;\n  subtitle: string;\n  link: string;\n  series: {\n    id: number;\n    time: string;\n    date: string;\n    weekday: string;\n    isfull: boolean;\n    haswaitinglist: boolean;\n    canregister: boolean;\n    sessioncount: number;\n    multiplesessions: boolean;\n    isselected: boolean;\n    link: string;\n    sessions: {\n      time: string;\n      date: string;\n      weekday: string;\n    }[];\n  }[];\n  waitinglistactive: boolean;\n  showmore: boolean;\n  hasselection: boolean;\n};\n\ninterface UTCoursesService {\n  GetSerieOptions(coursefinderid: number, languagecode: string, serieid: number): Promise<getSerieOptionsType>;\n  SearchWords(objid: number, languagecode: string, words: string): Promise<{ids: number[]; words: string}>;\n  CancelCourse(languagecode: string, serieid: number, hash: string): Promise<{success: boolean; code: string}>;\n  UpdateCourseAlert(languagecode: string, data: {categories: number[]; unsubscibecourses: number[]}, token: string): Promise<{success: boolean; coursetitle: string}>;\n  UnsubscribeCourseAlert(languagecode: string, token: string): Promise<{success: boolean}>;\n}\n\nexport default createClient<UTCoursesService>(\"utwente_courses:site_service\");\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./detail.scss\";\nimport * as dompack from \"@webhare/dompack\";\n\nexport class cCourseDetailsList {\n  constructor(node) {\n    this.node = node;\n\n    this.pagenode = node.closest(\".coursefinder__page\");\n\n    //Toggle content\n    for (const footernode of this.node.querySelectorAll(\".coursefinder__detaillist__footer\")) {\n      const itemnode = footernode.closest(\"li\");\n      footernode.addEventListener(\"click\", ev => {\n        let foldnode = null;\n\n        if (ev.target.closest(\".toggle-description\"))\n          foldnode = itemnode.querySelector(\".coursefinder__detaillist__description\");\n        else if (ev.target.closest(\".toggle-courses\"))\n          foldnode = itemnode.querySelector(\".coursefinder__detaillist__courses\");\n\n        if (foldnode)\n          this.toggleContent(foldnode);\n      });\n    }\n\n    for (const headernode of this.node.querySelectorAll(\".coursefinder__detaillist__compacttitle\")) {\n      headernode.addEventListener(\"click\", ev => {\n        const foldnode = headernode.parentNode.querySelector(\".coursefinder__detaillist__courses\");\n        if (foldnode)\n          this.toggleContent(foldnode);\n      });\n    }\n\n    for (const closenode of this.node.querySelectorAll(\".close\")) {\n      closenode.addEventListener(\"click\", ev => {\n        const foldnode = ev.target.closest(\".showfullcontent\");\n        if (foldnode)\n          this.toggleContent(foldnode);\n      });\n    }\n\n    window.addEventListener(\"resize\", ev => this.onRefresh(ev));\n    window.addEventListener(\"load\", ev => this.onRefresh(ev));\n    window.addEventListener(\"wh:refresh\", ev => this.onRefresh(ev));\n\n    this.onRefresh();\n  }\n\n  onRefresh(ev) {\n    if (!this.pagenode.classList.contains(\"coursefinder__page--detail\"))\n      return; //Only needed for detail view\n    this.shortenDescriptions();\n    this.checkDescriptionHeight();\n  }\n\n  shortenDescriptions() {\n    for (const fulldescriptionnode of this.node.querySelectorAll(\".fulldescription\"))\n      this.shortenDescription(fulldescriptionnode);\n  }\n\n  shortenDescription(fulldescriptionnode) {\n    const maxh = 65; //Just check height with 5px margin\n    let h_inner = fulldescriptionnode.clientHeight;\n\n    if (h_inner < maxh) {\n      fulldescriptionnode.parentNode.classList.remove(\"hasshortdescription\");\n      if (fulldescriptionnode.parentNode.children.length > 1)//remove short description\n        fulldescriptionnode.parentNode.removeChild(fulldescriptionnode.parentNode.children[1]);\n\n      return;\n    }\n\n    fulldescriptionnode.parentNode.classList.add(\"hasshortdescription\");\n\n    let shortdescriptionnode = fulldescriptionnode.parentNode.children.length > 1 ? fulldescriptionnode.parentNode.children[1] : null;\n    if (!shortdescriptionnode) {\n      shortdescriptionnode = <span class=\"shortdescription\" />;\n      fulldescriptionnode.parentNode.appendChild(shortdescriptionnode);\n    }\n\n    shortdescriptionnode.textContent = \"\";\n    const words = fulldescriptionnode.textContent.split(\" \");\n\n    h_inner = shortdescriptionnode.clientHeight;\n    let prevcontent = \"\";\n    while (h_inner <= maxh && words.length) {\n      const newcontent = prevcontent + (prevcontent != \"\" ? \" \" : \"\") + words.shift();\n      shortdescriptionnode.textContent = newcontent;\n      h_inner = shortdescriptionnode.clientHeight;\n      if (h_inner > maxh) {\n        shortdescriptionnode.textContent = prevcontent.substr(0, prevcontent.length - 3);//space for ...\n        return;\n      }\n\n      prevcontent = newcontent;\n    }\n  }\n\n  toggleContent(foldnode) {\n    const h_outer = foldnode.clientHeight;\n    const h_inner = foldnode.children[0].clientHeight;\n\n    if (foldnode.classList.contains(\"showfullcontent\")) {\n      foldnode.style.maxHeight = h_outer + \"px\";\n      foldnode.clientHeight;//force css update\n      foldnode.classList.add(\"onhidefullcontent\");\n      foldnode.style.maxHeight = \"\";\n      foldnode.classList.remove(\"showfullcontentready\");\n\n      if (foldnode.classList.contains(\"coursefinder__detaillist__courses\"))\n        foldnode.closest(\"li\").classList.remove(\"showcourses\");\n\n      setTimeout(function () {\n        foldnode.classList.remove(\"showfullcontent\");\n        foldnode.classList.remove(\"onhidefullcontent\");\n      }, 300);\n    } else {\n      foldnode.classList.remove(\"onhidefullcontent\");\n      if (h_inner > h_outer) {\n        foldnode.style.maxHeight = h_outer + \"px\";\n        foldnode.clientHeight;//force css update\n        foldnode.style.maxHeight = h_inner + \"px\";\n\n        if (foldnode.classList.contains(\"coursefinder__detaillist__courses\"))\n          foldnode.closest(\"li\").classList.add(\"showcourses\");\n\n        setTimeout(function () {\n          foldnode.style.maxHeight = \"\";\n        }, 300);\n      }\n\n      foldnode.classList.add(\"showfullcontent\");\n\n      setTimeout(function () {\n        foldnode.classList.add(\"showfullcontentready\");\n      }, 300);\n    }\n  }\n\n  checkDescriptionHeight() {\n    for (const foldnode of this.node.querySelectorAll(\".coursefinder__detaillist__description\"))\n      this.toggleMoreVisibility(foldnode);\n  }\n\n  toggleMoreVisibility(foldnode) {\n    const btnnode = foldnode.parentNode.querySelector(\".toggle-description\");\n    if (!btnnode)\n      return;\n\n    const maxh = 65;//just check height with a bit of margin\n    const h_inner = foldnode.children[0].clientHeight;\n\n    if (h_inner < maxh)\n      btnnode.style.display = \"none\";\n    else\n      btnnode.style.display = \"\";\n  }\n}\n","// ws2026 implementation!\n\nimport \"./calendar.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { getTid } from \"@mod-tollium/js/gettid\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport type { UTDialog } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/dialogs\";\n\nimport UTCoursesService, { getSerieOptionsType } from \"@mod-utwente_courses/js/site-service\";\n\ntype translationsType = {\n  months: string[];\n  months_short: string[];\n  days: string[];\n  days_short: string[];\n};\n\nexport class cCalendar {\n  node: HTMLElement;\n  pagenode: HTMLElement;\n  titlenode: HTMLElement;\n  filterids: string[];\n  language: string;\n  navnode: HTMLElement;\n  tablenode: HTMLElement;\n  calendardata: {node: HTMLElement; timestamp: number}[] = [];\n  popupnode: HTMLElement | null = null;\n  mobileview: boolean;\n  maxmonths: number;\n  monthtable: cMonthTable;\n  listcalendarnode: HTMLElement | null = null;\n  courseids: number[] = [];\n  activemonth: { month: number; year: number; monthname: string } = { month: 0, year: 0, monthname: \"\" };\n  closefn: (ev: MouseEvent) => void = () => {};\n  pageid: number;\n\n  constructor(container: HTMLElement, options: { date?: Date; pageid: number } = { pageid: 0 }) {\n    this.node = container;\n\n    this.pagenode = container.closest(\".coursefinder__page\") as HTMLElement;\n    this.pageid = options.pageid;\n\n    this.titlenode = <div class=\"monthname\"></div>;\n\n    this.filterids = [];\n    this.language = document.documentElement.lang ? document.documentElement.lang.split(\"-\")[0] : \"en\";\n\n    this.navnode = <div class=\"coursefinder__calendar__nav\">\n      {this.titlenode}\n      <div class=\"previousmonth UT-icon-UT_icon_43_arrow-left-16px\"></div>\n      <div class=\"nextmonth UT-icon-UT_icon_44_arrow-right-16px\"></div>\n    </div>;\n    this.node.appendChild(this.navnode);\n\n    const timetable = this.node.dataset ? JSON.parse(this.node.dataset.timetable!) : [];\n\n    //Before we start building calendar first check viewmode\n    this.mobileview = this.checkViewMode(true);\n\n    //let firstdate = null;\n    let lastdate = null;\n    if (timetable.length) {\n      //firstdate = new Date(timetable[0].timestamp * 1000);\n      lastdate = new Date(timetable[timetable.length - 1].timestamp * 1000);\n    }\n\n    this.calendardata = [];\n\n    let daycontent = null;\n    let prevdate = -1;\n    for (let i = 0; i < timetable.length; ++i) {\n      const dt = new Date(timetable[i].timestamp * 1000);\n      //const time = this.getFormattedTime(dt);\n\n      const timestamp = getRoundedDayTimestamp(dt);\n      if (prevdate !== timestamp) {\n        if (daycontent && daycontent.node.children.length > 5)\n          daycontent.node.insertBefore(<li class=\"course course--more\">{(daycontent.node.children.length - 4) + ' more'}</li>, daycontent.node.children[4]);//\n\n        daycontent = { \"node\": <ul class=\"coursefinder__calendar__courses\" />, \"timestamp\": timestamp };\n        this.calendardata.push(daycontent);\n\n        prevdate = timestamp;\n      }\n      if (daycontent)\n        daycontent.node.appendChild(<li title={timetable[i].title} data-tag={timetable[i].tag} data-courseid={timetable[i].courseid} class={'course course--' + timetable[i].type} data-id={timetable[i].id}><span class=\"name\">{timetable[i].title}</span></li>);//\n      //daycontent.node.appendChild(<li title={timetable[i].title} data-courseid={timetable[i].courseid} class={'course course--' + timetable[i].type } data-id={timetable[i].id}><span class=\"time\">{time}</span><span class=\"name\">{timetable[i].title}</span></li>);//\n    }\n    if (daycontent) {\n      if (daycontent.node.children.length > 5)\n        daycontent.node.insertBefore(<li class=\"course course--more\">{getTid('utwente_courses:webfeatures.frontend.js.xmore', daycontent.node.children.length - 4)}</li>, daycontent.node.children[4]);//\n\n      this.calendardata.push(daycontent);\n    }\n\n    const maxdate = lastdate ? { month: lastdate.getMonth(), year: lastdate.getFullYear() } : { month: new Date().getMonth(), year: new Date().getFullYear() };\n    this.maxmonths = (maxdate.year * 12) + maxdate.month; //month starts with 0\n\n    this.tablenode = <div class=\"coursefinder__calendar__tablewrapper\" />;\n    this.node.appendChild(this.tablenode);\n\n    if (options.date) { //Check if initial date is within today/max date\n      const today = new Date();\n      const todaymonths = (today.getFullYear() * 12) + today.getMonth();\n      const setmonths = (options.date.getFullYear() * 12) + options.date.getMonth();\n\n      if (setmonths < todaymonths)\n        options.date = today;\n      else if (setmonths > this.maxmonths)\n        options.date = new Date(maxdate.year, maxdate.month, 1, 0, 0, 0);\n    }\n\n    this.monthtable = new cMonthTable(this.tablenode, {\n      hideweekdays: [0, 6], //hide sunday and saturday\n      agendaitems: this.calendardata,\n      date: options.date || null\n    });\n\n    if (!this.mobileview)\n      this.monthtable.loadTable();\n    else\n      this.loadMobileCalendar();\n\n    this.setMonthName();\n    this.reachedNavLimit(0);\n\n    //Some keyboard handling\n    window.addEventListener(\"keydown\", ev => {\n      if (this.mobileview)\n        return;\n\n      if (ev.key === \"Escape\")\n        this.hideMore(null);\n      else if (ev.key === \"ArrowLeft\")\n        this.previousMonth();\n      else if (ev.key === \"ArrowRight\")\n        this.nextMonth();\n    });\n\n    //handle mouseclick inside calendar day\n    this.tablenode.addEventListener(\"wh:dateclick\", ev => {\n      const dateClickEvent = ev as CustomEvent<{ target: Element }>;\n      const coursenode = dateClickEvent.detail.target.closest(\".course\") as HTMLElement | null;\n      if (!coursenode)\n        return;\n\n      if (dateClickEvent.detail.target.classList.contains(\"course--close\")) {\n        this.hideMore(null);\n        return;\n      }\n\n      if (coursenode.classList.contains(\"course--more\"))\n        this.showMore(dateClickEvent, coursenode.closest(\".day-container\") as HTMLElement);\n      else if (coursenode.dataset.id)\n        void this.showSerieOptions(Number(coursenode.dataset.id), coursenode.title);\n    });\n\n    this.navnode.addEventListener(\"click\", ev => {\n      if ((ev.target as HTMLElement).classList.contains(\"previousmonth\"))\n        this.previousMonth();\n      else if ((ev.target as HTMLElement).classList.contains(\"nextmonth\"))\n        this.nextMonth();\n    });\n\n    window.addEventListener(\"resize\", ev => this.checkViewMode(false));\n  }\n\n  checkViewMode(initial: boolean) {\n    const viewwidth = window.innerWidth || document.documentElement.clientWidth || document.body.clientWidth;\n    const ismobileview = viewwidth < 768;\n    const prevview = this.mobileview;\n\n    this.mobileview = ismobileview;\n\n    this.pagenode.classList.toggle(\"coursefinder__page--mobile\", this.mobileview);\n\n    if (ismobileview !== prevview && !initial)\n      this.switchView();\n\n    return this.mobileview;\n  }\n\n  switchView() {\n    if (this.mobileview) {\n      //remove calendar table from dom\n      this.tablenode.replaceChildren();\n\n      //Add listcalendar\n      this.loadMobileCalendar();\n    } else {\n      //remove listcalendar\n      if (this.listcalendarnode)\n        this.listcalendarnode.remove();\n      this.listcalendarnode = null;\n\n      //reload calendar table\n      this.tablenode.appendChild(this.monthtable.generateTable(this.monthtable.year, this.monthtable.month));\n      this.setMonthName();//update titke above calendar table\n      if (this.courseids)\n        this.filterCourses(this.courseids);\n    }\n  }\n\n  loadMobileCalendar() {\n    this.listcalendarnode = <div class=\"coursefinder__listcalendar\" /> as HTMLElement;\n    this.node.appendChild(this.listcalendarnode);\n    this.listcalendarnode.addEventListener(\"click\", ev => {\n      const coursenode = (ev.target as HTMLElement).closest<HTMLElement>(\"li.course\");\n      if (coursenode) {\n        document.location.href = \"./\" + coursenode.dataset.courseid + \"/\" + coursenode.dataset.tag + \"/?serie=\" + coursenode.dataset.id + \"#signup\";\n        return;\n      }\n      const titlenode = (ev.target as HTMLElement).closest(\".month__title\");\n      if (titlenode)\n        this.toggleListMonth(titlenode.parentNode as HTMLElement);\n    });\n\n    const translations = getCalendarTranslations(this.language);\n\n    const todaytimestamp = getRoundedDayTimestamp(new Date());\n\n    const activeym = this.monthtable.year + 12 * this.monthtable.month;\n\n    let prevym = -1;\n    let monthnode = null;\n    for (let i = 0; i < this.calendardata.length; ++i) {\n      if (todaytimestamp > this.calendardata[i].timestamp)\n        continue;\n\n      //node, timestamp\n      const date = new Date(this.calendardata[i].timestamp);\n      const month = date.getMonth();\n      const year = date.getFullYear();\n      const day = date.getDate();\n      const weekday = date.getDay();\n\n      const ym = year + month * 12;\n      if (ym !== prevym || !monthnode) {\n        monthnode = <div class={\"month\" + (activeym === ym ? \" active\" : \"\")} data-year={year} data-month={month}>\n          <div class=\"month__title\">\n            {translations.months[month] + \" \" + year}\n            <span class=\"month__toggle\">\n              <span class=\"more UT-icon-UT_icon_46_arrow-down-16px\"></span>\n              <span class=\"less UT-icon-UT_icon_45_arrow-up-16px\"></span>\n            </span>\n          </div>\n        </div>;\n        this.listcalendarnode.appendChild(monthnode);\n      }\n\n      const monthdaynode = <div class=\"month__day\">\n        <div class={\"month__day__title\" + (todaytimestamp === this.calendardata[i].timestamp ? \" today\" : \"\")}>\n          {translations.days_short[weekday] + \" \" + day + \" \" + translations.months[month]}\n        </div>\n      </div>;\n      monthdaynode.appendChild(this.calendardata[i].node);\n      monthnode.appendChild(monthdaynode);\n\n      prevym = ym;\n    }\n\n    this.filterCourses(this.courseids);\n  }\n\n  toggleListMonth(monthnode: HTMLElement) {\n    if (monthnode.classList.contains(\"active\")) { //hide\n      monthnode.style.maxHeight = monthnode.clientHeight + \"px\";\n      monthnode.classList.remove(\"active\");\n      void(monthnode.clientHeight);//force css update\n      monthnode.style.maxHeight = \"\";\n    } else { //show\n\n      const year = Number(monthnode.dataset.year);\n      const month = Number(monthnode.dataset.month);\n      if (month > -1 && month < 12 && year > 0) { //set last selected year/month as initial values for calendar table\n        this.monthtable.year = year;\n        this.monthtable.month = month;\n      }\n\n      let h = 0;\n      for (let i = 0; i < monthnode.children.length; ++i)\n        h += monthnode.children[i].clientHeight;\n      monthnode.style.maxHeight = h + \"px\";\n      monthnode.classList.add(\"active\");\n      setTimeout(function () {\n        monthnode.style.maxHeight = \"\";\n      }, 300);\n    }\n  }\n\n  filterCourses(courseids: number[]) { //show only courses with given courseids\n    if (!courseids)\n      courseids = [];\n\n    this.courseids = courseids;\n\n    const filtereditems = [];\n    let monthnode = null;\n    let monthcount = 0;\n    for (let i = 0; i < this.calendardata.length; ++i) {\n      let matchcount = 0;\n      for (let c = 0; c < this.calendardata[i].node.children.length; ++c) {\n        if (this.listcalendarnode && !this.calendardata[i].node.parentNode)\n          continue;//Items before today are not attached to dom if listcalendarnode\n\n        const coursenode = this.calendardata[i].node.children[c] as HTMLElement;\n        if (coursenode.dataset.courseid) {\n          const id = Number(coursenode.dataset.courseid);\n          if (courseids.indexOf(id) > -1) {\n            coursenode.style.display = \"\";\n            ++matchcount;\n          } else\n            coursenode.style.display = \"none\";\n        } else\n          this.calendardata[i].node.removeChild(coursenode);//remove more node (will be added later if needed)\n      }\n\n      if (this.listcalendarnode) {\n        const daynode = this.calendardata[i].node.parentNode as HTMLElement;\n        if (daynode) {\n          const curmonthnode = daynode.parentNode as HTMLElement;\n          if (!monthnode || monthnode !== curmonthnode || i >= this.calendardata.length - 1) {\n            if (monthcount === 0 && monthnode)\n              monthnode.style.display = \"none\";//Hide month of no matches within month\n            else if (monthnode)\n              monthnode.style.display = \"\";\n\n            monthcount = 0;\n            monthnode = curmonthnode;\n          }\n          monthcount += matchcount;\n\n          daynode.style.display = matchcount ? \"\" : \"none\";\n        }\n      } else {\n        if (matchcount > 5)\n          this.calendardata[i].node.insertBefore(<li class=\"course course--more\">{getTid('utwente_courses:webfeatures.frontend.js.xmore', matchcount - 4)}</li>, this.calendardata[i].node.children[4]);//\n\n        if (matchcount > 0)\n          filtereditems.push(this.calendardata[i]);\n      }\n    }\n\n    if (!this.listcalendarnode)\n      this.monthtable.refreshData(filtereditems);\n  }\n\n  createSpinner() { //Spinner for loading indicator courses in dialog\n    const diameter = 50;\n    const strokewidth = 5;\n\n    const svg = document.createElementNS(\"http://www.w3.org/2000/svg\", \"svg\");\n    svg.setAttributeNS(null, \"width\", diameter + \"px\");\n    svg.setAttributeNS(null, \"height\", diameter + \"px\");\n    svg.setAttributeNS(null, \"viewBox\", \"0 0 \" + diameter + \" \" + diameter);\n\n    const symbol = document.createElementNS(\"http://www.w3.org/2000/svg\", \"circle\");\n    symbol.setAttributeNS(null, \"cx\", String(Math.floor(diameter / 2)));\n    symbol.setAttributeNS(null, \"cy\", String(Math.floor(diameter / 2)));\n    symbol.setAttributeNS(null, \"r\", String(Math.floor(diameter / 2 - strokewidth)));\n    symbol.setAttributeNS(null, \"fill\", \"none\");\n    symbol.setAttributeNS(null, \"stroke\", \"#ccc\");\n    symbol.setAttributeNS(null, \"stroke-width\", String(strokewidth));\n    symbol.setAttributeNS(null, \"stroke-dasharray\", \"110,160\");\n    symbol.setAttributeNS(null, \"stroke-linecap\", \"round\");\n\n    svg.appendChild(symbol);\n\n    return svg;\n  }\n\n  async showSerieOptions(serieid: number, title: string) {\n    const dialog = dialogapi.createDialog() as UTDialog;\n    dialog.holdernode.classList.add(\"coursefinder__dialog\");\n    dialog.contentnode!.appendChild(<div class=\"coursefinder__dialog__loading\">\n      <h3 class=\"coursefinder__loadertitle\">{title}</h3>\n      <div class=\"coursefinder__loader\">{this.createSpinner()}</div>\n    </div>\n    );\n    void dialog.runModal();\n\n    const lock = dompack.flagUIBusy();\n    let result: getSerieOptionsType;\n    try {\n      result = await UTCoursesService.GetSerieOptions(this.pageid, this.language, serieid);\n    } finally {\n      lock.release();\n    }\n\n    dialog.contentnode!.replaceChildren();\n\n    let dialogcontent;\n    if (result) {\n      //Note: only items where you can register are shown\n      dialogcontent = <div class=\"coursefinder__dialog__courseoptions\">\n        <div class=\"courseoptions__header\">\n          <div class=\"courseoptions__image\">\n            {result.image ? (\n              <img src={result.image.normal.link} srcset={result.image.normal.link + \" 1x,\" + result.image.retina.link + \" 2x\"} alt=\"\" />\n            )\n              : null\n            }\n          </div>\n          <div class=\"courseoptions__title\">\n            <h3>{result.title}</h3>\n            <div>{result.subtitle}</div>\n            <a href={result.link}>{getTid('utwente_courses:webfeatures.frontend.js.moreinfo')}</a>\n          </div>\n        </div>\n        {result.series.length ? (\n          <form class=\"courseoptions__form wh-styledinput\" action={result.link + \"#signup\"} method=\"get\">\n            <ul>\n              {result.series.map(item => <li class={(item.canregister ? (item.isfull ? \"waitinglist\" : \"open\") : \"isfull\") + (item.multiplesessions ? \" multiplesessions\" : \"\")}>\n                <input id={\"serie-\" + item.id} disabled={!item.canregister} checked={item.canregister && item.isselected} name=\"serie\" type=\"radio\" value={item.id} />\n                <label class=\"radiobtn\" for={\"serie-\" + item.id}></label>\n                <label class=\"wh-form__optionlabel\" for={\"serie-\" + item.id}>\n                  <div class=\"sessions\">\n                    {item.sessions.map(session =>\n                      <div class=\"session\">\n                        <span class=\"weekday\">{session.weekday}</span>\n                        <span class=\"date\">{session.date}</span>\n                        <span class=\"time\">{session.time}</span>\n                      </div>\n                    )}\n                  </div>\n                  <span class=\"note\">\n                    {item.canregister ? (item.isfull ? getTid('utwente_courses:webfeatures.frontend.js.waitinglist') + \"*\" : \"\") : getTid('utwente_courses:webfeatures.frontend.js.isfull')}\n                  </span>\n                  <span class=\"duration\">{getTid('utwente_courses:webfeatures.frontend.js.xdaycourse', item.sessioncount)}</span>\n                </label>\n              </li>\n              )}\n            </ul>\n            {result.showmore ? (<div class=\"courseoptions__more\">\n              <a href={result.link + '#signup'}>View more</a>\n            </div>\n            ) : null}\n            <button class=\"wh-form__button\" type=\"submit\">{getTid('utwente_courses:webfeatures.frontend.js.signup')}</button>\n\n          </form>\n        ) : (\n          <div class=\"courseoptions__nooptions\">{getTid('utwente_courses:webfeatures.frontend.js.nooptionsavailable')}</div>\n        )}\n\n        {result.waitinglistactive ? (\n          <div class=\"courseoptions__footer\">\n            *{getTid('utwente_courses:webfeatures.frontend.js.notewaitinglist')}\n          </div>\n        ) : null\n        }\n      </div>;//\n\n      for (const itemnode of dialogcontent.querySelectorAll(\"li\")) {\n        const togglenode = itemnode.querySelector(\".duration\");\n        const sessionswrapper = itemnode.querySelector(\".sessions\");\n        if (togglenode && sessionswrapper) {\n          togglenode.addEventListener(\"click\", () => {\n            sessionswrapper.style.maxHeight = \"\";\n            sessionswrapper.classList.toggle(\"showall\");\n            if (sessionswrapper.classList.contains(\"showall\")) {\n              let h = 0;\n              for (let i = 0; i < sessionswrapper.children.length; ++i)\n                h += sessionswrapper.children[i].clientHeight;\n              sessionswrapper.style.maxHeight = h + \"px\";\n\n              setTimeout(function () {\n                sessionswrapper.style.maxHeight = \"none\";\n              }, 300);\n            }\n          });\n        }\n      }\n    } else {\n      dialogcontent = <div class=\"coursefinder__dialog__error\">Error: no course dates found.</div>;//\n    }\n\n    //Add close button\n    const closebtn = <div class=\"coursefinder__dialog__close UT-icon-UT_icon_47_cross-16px\" />;\n    closebtn.addEventListener(\"click\", () => dialog.resolve(null));\n    dialog.contentnode!.appendChild(closebtn);\n\n    dialog.contentnode!.appendChild(dialogcontent);\n  }\n\n  getFormattedTime(dt: Date) {\n    const h = dt.getHours();\n    const m = dt.getMinutes();\n    return (h < 10 ? \"0\" : \"\") + h + \":\" + (m < 10 ? \"0\" : \"\") + m;\n  }\n\n  previousMonth() {\n    if (this.reachedNavLimit(-1))\n      return;\n\n    this.monthtable.previousMonth();\n    this.setMonthName();\n  }\n\n  nextMonth() {\n    if (this.reachedNavLimit(1))\n      return;\n\n    this.monthtable.nextMonth();\n    this.setMonthName();\n  }\n\n  showMore(ev: CustomEvent, node: HTMLElement) {\n    const date = ev.detail.date;\n\n    if (this.popupnode)\n      this.hideMore(null);//Hide previous\n\n    this.popupnode = node.cloneNode(true) as HTMLElement;\n\n    //add dayofweek\n    this.popupnode.insertBefore(<span class=\"dayofweek\">{this.monthtable.translations!.days_short[date.getDay()]}</span>, this.popupnode.children[0]);\n\n    this.closefn = this.hideMore.bind(this);\n    document.body.addEventListener(\"click\", this.closefn);\n\n    //add close\n    const closebtn = <span class=\"course--close UT-icon-UT_icon_47_cross-16px\"></span>;\n    closebtn.addEventListener(\"click\", () => this.hideMore(null));\n    this.popupnode.appendChild(closebtn);\n\n    //remove more node\n    const morenode = this.popupnode.querySelector(\"course--more\");\n    if (morenode)\n      (morenode.parentNode as HTMLElement).removeChild(morenode);\n\n    this.popupnode.className = \"coursefinder__calendar__daypopup\";\n    (node.parentNode as HTMLElement).appendChild(this.popupnode);\n    void(this.popupnode.clientWidth); //force css update for animation\n    this.popupnode.classList.add(\"show\");\n  }\n\n  hideMore(ev: MouseEvent | null) {\n    if (ev) {\n      if (this.popupnode && (ev.target as HTMLElement).closest(\".wh-monthtable__day\") === this.popupnode.closest(\".wh-monthtable__day\"))\n        return;//Ignore if click is inside current popup/day element\n    }\n\n    document.body.removeEventListener(\"click\", this.closefn);\n\n    if (!this.popupnode)\n      return;\n\n    (this.popupnode.parentNode as HTMLElement).removeChild(this.popupnode);\n    this.popupnode = null;\n  }\n\n  reachedNavLimit(offset: number) {\n    const today = new Date();\n    const todaymonths = (today.getFullYear() * 12) + today.getMonth();\n    const activemonths = (this.activemonth.year * 12) + this.activemonth.month;\n\n    if (activemonths + offset <= todaymonths)\n      this.navnode.classList.add(\"coursefinder__calendar__nav--minlimit\");\n    else\n      this.navnode.classList.remove(\"coursefinder__calendar__nav--minlimit\");\n\n    if (activemonths + offset >= this.maxmonths)\n      this.navnode.classList.add(\"coursefinder__calendar__nav--maxlimit\");\n    else\n      this.navnode.classList.remove(\"coursefinder__calendar__nav--maxlimit\");\n\n    return activemonths + offset < todaymonths || activemonths + offset > this.maxmonths;\n  }\n\n  setMonthName() {\n    this.activemonth = this.monthtable.getActiveMonth();\n    this.titlenode.textContent = this.activemonth.monthname + \" \" + this.activemonth.year;\n    if (document.location.hash.indexOf(\"#calendarview\") === 0)\n      document.location.hash = \"#calendarview.\" + this.activemonth.year + \".\" + (this.activemonth.month + 1);\n  }\n}\n\n\nfunction getCalendarTranslations(language: string) {\n  if (language.toUpperCase() === \"DE\") {\n    return {\n      months: ['Januar', 'Februar', 'März', 'April', 'Mai', 'Juni', 'Juli', 'August', 'September', 'Oktober', 'November', 'Dezember'],\n      months_short: ['Jan', 'Feb', 'Mär', 'Apr', 'Mai', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dez'],\n      days: ['Sontag', 'Montag', 'Dienstag', 'Mitwoch', 'Donnerstag', 'Freitag', 'Samstag'],\n      days_short: ['So', 'Mo', 'Di', 'Mi', 'Do', 'Fr', 'Sa']\n    };\n  } else if (language.toUpperCase() === \"NL\") {\n    return {\n      months: ['Januari', 'Februari', 'Maart', 'April', 'Mei', 'Juni', 'Juli', 'Augustus', 'September', 'Oktober', 'November', 'December'],\n      months_short: ['Jan', 'Feb', 'Ma', 'Apr', 'Mei', 'Jun', 'Jul', 'Aug', 'Sep', 'Okt', 'Nov', 'Dec'],\n      days: ['Zondag', 'Maandag', 'Dinsdag', 'Woensdag', 'Donderdag', 'Vrijdag', 'Zaterdag'],\n      days_short: ['Zo', 'Ma', 'Di', 'Wo', 'Do', 'Vr', 'Za']\n    };\n  } else { // EN\n    return {\n      months: ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],\n      months_short: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'],\n      days: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'],\n      days_short: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']\n    };\n  }\n}\n\ntype monthOptions = {\n    selecteddate?: Date | null;\n    mindate?: Date | null;\n    maxdate?: Date | null;\n    date: Date | null;\n    showweekdays?: boolean;\n    startweekday?: number;\n    hideweekdays: number[];\n    agendaitems: { timestamp: number; node: HTMLElement }[];\n  };\n\n/*\n      hideweekdays: [0, 6], //hide sunday and saturday\n      agendaitems: this.calendardata,\n      date: options.date\n*/\n\nclass cMonthTable {\n  node: HTMLElement;\n  language: string;\n  year: number;\n  month: number;\n  translations: translationsType | null = null;\n  mindate: { year: number; month: number; day: number; timestamp: number } | null = null;\n  maxdate: { year: number; month: number; day: number; timestamp: number } | null = null;\n  selecteddate: { year: number; month: number; day: number; timestamp: number; date: Date } | null = null;\n  tablenode: HTMLElement | null = null;\n  options: monthOptions;\n  activemonth: { month: number; monthname: string; year: number } = { month: 0, monthname: \"\", year: 0 };\n\n  constructor(node: HTMLElement, options: monthOptions) {\n    this.node = node;//parentNode where month table is appended\n\n    this.options = {\n      selecteddate: options && options.selecteddate ? options.selecteddate : null, //date object\n      mindate: options && options.mindate ? options.mindate : new Date(),     //date object\n      maxdate: options && options.maxdate ? options.maxdate : null,           //date object\n      date: options && options.date ? options.date : new Date(),           //date object\n      showweekdays: options && options.showweekdays ? options.showweekdays : true, //boolean\n      startweekday: options && typeof options.startweekday !== 'undefined' ? options.startweekday : 1, // integer [0-6], 0: Sunday, 1: Monday etc..\n      hideweekdays: options && options.hideweekdays ? options.hideweekdays : [],   //Array with weeknr's to hide, sunday = 0;\n      agendaitems: options && options.agendaitems ? options.agendaitems : []   //Array with objects\n    };\n\n    if (this.options.agendaitems && this.options.agendaitems.length)//set in chronological order\n      this.options.agendaitems.sort(function (a, b) { return a.timestamp - b.timestamp; });\n\n    this.setMinDate(this.options.mindate || null);\n    this.setMaxDate(this.options.maxdate || null);\n    this.setSelectedDate(this.options.selecteddate || null);\n\n    this.language = document.documentElement.lang ? document.documentElement.lang.split(\"-\")[0] : \"en\";\n\n    this.setTranslations(this.language);\n\n    this.year = this.options.date ? this.options.date.getFullYear() : 0;\n    this.month = this.options.date ? this.options.date.getMonth() : 0; //zero based\n  }\n\n  loadTable() {\n    if (this.node)\n      this.node.appendChild(this.generateTable(this.year, this.month));\n  }\n\n  getTranslations() {\n    return this.translations;\n  }\n\n  setTranslations(language: string) {\n    this.translations = getCalendarTranslations(language);\n  }\n\n  refreshData(agendaitems: { timestamp: number; node: HTMLElement }[]) {\n    this.options.agendaitems = agendaitems;\n    this.setMonth(this.year, this.month);\n  }\n\n  setMinDate(mindate: Date | null) {\n\n    if (mindate && typeof mindate === \"object\") {\n      mindate = new Date(mindate.getFullYear(), mindate.getMonth(), mindate.getDate(), 0, 0, 0);//begin of day\n      this.mindate = {\n        \"year\": mindate.getFullYear(),\n        \"month\": mindate.getMonth(), //zero based\n        \"day\": mindate.getDate(),\n        \"timestamp\": mindate.getTime()\n      };\n    } else\n      this.mindate = null;\n  }\n\n  setMaxDate(maxdate: Date | null) {\n    if (maxdate && typeof maxdate === \"object\") {\n      maxdate = new Date(maxdate.getFullYear(), maxdate.getMonth(), maxdate.getDate(), 23, 59, 59);//end of day\n      this.maxdate = {\n        \"year\": maxdate.getFullYear(),\n        \"month\": maxdate.getMonth(), //zero based\n        \"day\": maxdate.getDate(),\n        \"timestamp\": maxdate.getTime()\n      };\n    } else\n      this.maxdate = null;\n  }\n\n  setSelectedDate(seldate: Date | null) {\n    if (seldate && typeof seldate === \"object\") {\n      seldate = new Date(seldate.getFullYear(), seldate.getMonth(), seldate.getDate(), 0, 0, 0);//begin of day\n\n      this.selecteddate = {\n        \"year\": seldate.getFullYear(),\n        \"month\": seldate.getMonth(), //zero based\n        \"day\": seldate.getDate(),\n        \"timestamp\": seldate.getTime(),\n        \"date\": seldate\n      };\n      if (this.mindate && this.selecteddate.timestamp < this.mindate.timestamp)\n        this.selecteddate = null;\n      else if (this.maxdate && this.selecteddate.timestamp > this.maxdate.timestamp)\n        this.selecteddate = null;\n    } else\n      this.selecteddate = null;\n  }\n\n  getSelectedDate() {\n    return this.selecteddate;\n  }\n\n  nextMonth() {\n    if (!this.tablenode)\n      return;\n\n    const d = new Date(this.year, this.month + 1, 1);\n    this.year = d.getFullYear();\n    this.month = d.getMonth();\n\n    this.generateTable(this.year, this.month);\n  }\n\n  previousMonth() {\n    if (!this.tablenode)\n      return;\n\n    const d = new Date(this.year, this.month - 1, 1);\n    this.year = d.getFullYear();\n    this.month = d.getMonth();\n\n    this.generateTable(this.year, this.month);\n  }\n\n  setMonth(year: number, month: number) {\n    if (!this.tablenode)\n      return;\n\n    const d = new Date(year, month, 1);\n    this.year = d.getFullYear();\n    this.month = d.getMonth();\n\n    this.generateTable(this.year, this.month);\n  }\n\n  getActiveMonth() {\n    return {\n      \"month\": this.month,\n      \"monthname\": (this.translations as translationsType).months[this.month],\n      \"year\": this.year\n    };\n  }\n\n  generateTable(year: number, month: number) {\n    //start of week\n    let startweekday = new Date(year, month, 1).getDay();//zero based, 0 = sunday\n\n    let orgstartday = (this.options.startweekday || 0) - startweekday;\n    if (orgstartday > 0)\n      orgstartday = orgstartday - 7;\n\n    // adjust startday if startweekday is in  hideweekdays\n    while (this.options.hideweekdays.indexOf(startweekday) > -1) {\n      ++startweekday;\n      if (startweekday > 6)\n        startweekday = 0;\n    }\n\n    let startday = (this.options.startweekday || 0) - startweekday;\n    if (startday > 0)\n      startday = startday - 7;\n\n    let monthdaycount = new Date(year, month + 1, 0).getDate();\n\n    //Adjust enddaycount if last day of current month are hidden\n    let endweekday = new Date(year, month, monthdaycount).getDay();\n    while (this.options.hideweekdays.indexOf(endweekday) > -1) {\n      --monthdaycount;\n      --endweekday;\n      if (endweekday < 0)\n        endweekday = 6;\n    }\n    const enddaycount = monthdaycount + (7 - (monthdaycount - orgstartday) % 7);\n\n    if (!this.tablenode) {\n      this.tablenode = <table class=\"wh-monthtable\" /> as HTMLElement;\n      this.tablenode.addEventListener(\"click\", ev => this.onDateClick(ev));\n    } else\n      this.tablenode.replaceChildren();\n\n    let rownode;\n    if (this.options.showweekdays){ //The table header with the weekday names\n      rownode = <tr />;\n      for (let i = 0; i < 7; ++i) {\n        let d = i + (this.options.startweekday || 0);\n        if (d >= 7)\n          d -= 7;\n\n        if (this.options.hideweekdays.indexOf(d) === -1)\n          rownode.appendChild(<th class=\"wh-monthtable__weekday\"><div>{(this.translations as translationsType).days_short[d]}</div></th>);\n      }\n      this.tablenode.appendChild(rownode);\n    }\n\n    const todaytimestamp = getRoundedDayTimestamp(new Date());\n    let lastagendaitem_idx = 0;\n    for (let d = startday + (this.options.startweekday || 0); d <= enddaycount; ++d) {\n      const celldate = new Date(year, month, d);\n\n      const cellday = celldate.getDate();\n      const cellmonth = celldate.getMonth(); //zero based\n      const cellyear = celldate.getFullYear();\n      const celltimestamp = celldate.getTime();\n\n      if ((d - (startday + (this.options.startweekday || 0))) % 7 === 0) {\n        rownode = dompack.create('tr');\n        this.tablenode.appendChild(rownode);\n      }\n\n      if (this.options.hideweekdays.indexOf(celldate.getDay()) === -1) {\n        let classstr = \"wh-monthtable__day\";\n        if (cellmonth < month || cellyear < year)\n          classstr += \" wh-monthtable__day--previousmonth\";\n        else if (cellmonth > month || cellyear > year)\n          classstr += \" wh-monthtable__day--nextmonth\";\n\n        if (celltimestamp === todaytimestamp)\n          classstr += \" wh-monthtable__day--today\";\n\n        if (this.maxdate && celltimestamp > this.maxdate.timestamp)\n          classstr += \" wh-monthtable__day--disabled\";\n        else if (this.mindate && celltimestamp < this.mindate.timestamp)\n          classstr += \" wh-monthtable__day--disabled\";\n\n        if (this.selecteddate && cellmonth === this.selecteddate.month && cellday === this.selecteddate.day && cellyear === this.selecteddate.year)\n          classstr += \" wh-monthtable__day--selected\";\n\n        let infonode = null;\n        for (let i = lastagendaitem_idx; i < this.options.agendaitems.length; ++i) {\n          if (celltimestamp === this.options.agendaitems[i].timestamp) {\n            infonode = this.options.agendaitems[i].node;\n            lastagendaitem_idx = i + 1;\n\n            break;\n          }\n        }\n\n\n        const daynode = <td class={classstr} data-date={cellyear + \"-\" + (cellmonth + 1) + \"-\" + cellday}>\n          <div class=\"day-container\">\n            <span class=\"day\">{cellday}</span>\n            {infonode}\n          </div>\n        </td>;//\n\n        rownode.appendChild(daynode);\n\n      }\n    }\n\n    return this.tablenode;\n  }\n\n  onDateClick(ev: MouseEvent) {\n    const datenode = (ev.target as HTMLElement).closest(\".wh-monthtable__day\");\n    if (datenode) {\n      if (ev)\n        ev.preventDefault();\n\n      const parts = (datenode.getAttribute(\"data-date\") || \"\").split(\"-\");\n      const celldate = new Date( Number(parts[0]), Number(parts[1]) - 1, Number(parts[2]));\n\n      dompack.dispatchCustomEvent((this.node ? this.node : this.tablenode) as HTMLElement, \"wh:dateclick\", {\n        bubbles: false,\n        cancelable: true,\n        detail: {\n          date: celldate,\n          day: celldate.getDate(),\n          month: celldate.getMonth(), //zero based\n          year: celldate.getFullYear(),\n          timestamp: celldate.getTime(),\n          target: ev ? ev.target : null,\n          disabled: datenode.classList.contains(\"wh-monthtable__day--disabled\")\n        }\n      });\n    }\n  }\n}\n\n//Helper functions:\nfunction getRoundedDayTimestamp(dateobj: Date) {\n  const roundeddate = new Date(dateobj.getFullYear(), dateobj.getMonth(), dateobj.getDate());\n  return roundeddate.getTime();\n}\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/webfeatures/courses/coursefinder.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_courses\",\"nl\",{\"webfeatures\":{\"frontend\":{\"js\":{\"activefilters\":\"Actieve filters\",\"cancel\":\"Annuleren\",\"closeregistration\":\"Registratie afsluiten\",\"coursealert\":\"Course alert\",\"coursealert-description\":\"Na inschrijving ontvang je regelmatig onze nieuwe cursussen.\",\"coursealert-description-noresults\":\"Op dit moment hebben we geen cursussen beschikbaar voor deze selectie. Vul je gegevens in en je krijgt als eerste een bericht als er één beschikbaar komt.\",\"coursealert-login\":\"Login\",\"coursealert-singlecoursedescription\":[\"Kan je niet wachten om deel te nemen aan deze cursus? We sturen je graag een mail als deze opnieuw ingepland wordt of wanneer er een plek in een reeds geplande cursus vrij komt.\",\"\\n\",\"We zullen je slechts één keer mailen. Als je er dan geen gebruik van maakt, zul je je opnieuw moeten aanmelden voor deze alert.\"],\"coursenotyetopen\":\"Sorry, de registratie voor deze cursus is nog niet geopend.\",\"inxdomains\":[\"in \",1,\"  \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"domein\"],\"subselse\":[\"domeinen\"]}],\"isfull\":\"Vol\",\"moreinfo\":\"Meer info\",\"nextstep\":\"Volgende stap\",\"no\":\"Nee\",\"noavailableoptions\":\"Sorry, er zijn op dit moment  geen opties voor registratie beschikbaar\",\"nooptionsavailable\":\"Sorry, er zijn geen opties beschikbaar.\",\"notewaitinglist\":\"Deze cursus is volgeboekt, als je je nu registreert, word je op de wachtlijst geplaatst en automatisch ingeschreven als er een plek vrijkomt.\",\"ok\":\"Ok\",\"registrationerror_already_registered\":\"U heeft zich al aangemeld voor deze cursus.\",\"registrationerror_full\":\"Geselecteerde datum/tijd is vol\",\"registrationerror_nocourse\":\"Cursus is niet beschikbaar\",\"registrationerror_nosession\":\"Geselecteerde datum/tijd is niet beschikbaar\",\"registrationerror_title\":\"Fout bij verwerken registratie\",\"registrationerror_waitinglistfull\":\"Wachtlijst is vol\",\"results\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"cursus\"],\"subselse\":[\"cursussen\"]},\" gevonden\"],\"retry\":\"Retry\",\"signup\":\"Inschrijven\",\"signupfor\":\"Schrijf in voor:\",\"start\":\"Start\",\"submiterror-failed\":\"Mislukt\",\"submiterror-prefix\":\"Je registratie is:\",\"submitsuccess-description\":\"Je ontvangt een e-mail met verdere informatie.\",\"submitsuccess-followupdescription\":[\"Dit is een begeleidende cursus bij '\",1,\"'\"],\"submitsuccess-prefix\":\"Je registratie is:\",\"submitsuccess-title\":\"Gelukt\",\"submitsuccess-waitinglist\":\"U staat nu op de wachtlijst. U ontvangt een e-mail met verdere informatie.\",\"waitinglist\":\"Wachtlijst\",\"xcourses\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"Cursus\"],\"subselse\":[\"Cursussen\"]}],\"xdaycourse\":[1,\" daagse cursus\"],\"xmore\":[1,\" meer\"],\"yes\":\"Ja\"}}}});\nregisterTexts(\"utwente_courses\",\"en\",{\"webfeatures\":{\"frontend\":{\"js\":{\"activefilters\":\"Active filters\",\"cancel\":\"Cancel\",\"closeregistration\":\"Close registration\",\"coursealert\":\"Course alert\",\"coursealert-description\":\"After registration you will regularly receive our new courses.\",\"coursealert-description-noresults\":\"We currently have no curssen available for this selection. Enter your details and you will be the first to be notified when one becomes available.\",\"coursealert-login\":\"Login\",\"coursealert-singlecoursedescription\":[\"Can’t wait to join this course? Sign up for the waiting list. You will receive an alert as soon as a new course is organised or a seat in one of the current courses becomes available.\",\"\\n\",\"We will only alert you \",{\"t\":\"tag\",\"tag\":\"b\",\"subs\":\"once\"},\". If you do not use this opportunity, you will have to sign up again for this alert.\"],\"coursenotyetopen\":\"Sorry, you cannot register for this course yet.\",\"inxdomains\":[\"in \",1,\"  \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"domain\"],\"subselse\":[\"domains\"]}],\"isfull\":\"Full\",\"moreinfo\":\"More info\",\"nextstep\":\"Next step\",\"no\":\"No\",\"noavailableoptions\":\"Sorry, there are at this time no options for registration available\",\"nooptionsavailable\":\"Sorry, no options available\",\"notewaitinglist\":\"This course is fully booked, if you register now, you will be placed on the waiting list and you will be enrolled if a place becomes available.\",\"ok\":\"Ok\",\"registrationerror_already_registered\":\"You have already registered for this course.\",\"registrationerror_full\":\"Selected date/time is full\",\"registrationerror_nocourse\":\"Course not available\",\"registrationerror_nosession\":\"Selected date/time not available\",\"registrationerror_title\":\"Error while saving registration\",\"registrationerror_waitinglistfull\":\"Waiting list full\",\"results\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"course\"],\"subselse\":[\"courses\"]},\" found\"],\"retry\":\"Retry\",\"signup\":\"Sign up\",\"signupfor\":\"Sign up for:\",\"start\":\"Start\",\"submiterror-failed\":\"Failed\",\"submiterror-prefix\":\"Your registration has:\",\"submitsuccess-description\":\"You will receive an email with further information.\",\"submitsuccess-followupdescription\":[\"This is an accompanying course for '\",1,\"'\"],\"submitsuccess-prefix\":\"Your registration is:\",\"submitsuccess-title\":\"Successful\",\"submitsuccess-waitinglist\":\"You're on the waiting list. You will receive an email with further information.\",\"waitinglist\":\"Waiting list\",\"xcourses\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"Course\"],\"subselse\":[\"Courses\"]}],\"xdaycourse\":[1,\" day course\"],\"xmore\":[1,\" more\"],\"yes\":\"Yes\"}}}});\nregisterTexts(\"utwente_courses\",\"de\",{\"webfeatures\":{\"frontend\":{\"js\":{\"activefilters\":\"Active filters\",\"cancel\":\"Cancel\",\"closeregistration\":\"Close registration\",\"coursealert\":\"Course alert\",\"coursealert-description\":\"After registration you will regularly receive our new courses.\",\"coursealert-description-noresults\":\"We currently have no curssen available for this selection. Enter your details and you will be the first to be notified when one becomes available.\",\"coursealert-login\":\"Login\",\"coursealert-singlecoursedescription\":[\"Can’t wait to join this course? Sign up for the waiting list. You will receive an alert as soon as a new course is organised or a seat in one of the current courses becomes available.\",\"\\n\",\"We will only alert you \",{\"t\":\"tag\",\"tag\":\"b\",\"subs\":\"once\"},\". If you do not use this opportunity, you will have to sign up again for this alert.\"],\"coursenotyetopen\":\"Sorry, you cannot register for this course yet.\",\"inxdomains\":[\"in \",1,\"  \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"domain\"],\"subselse\":[\"domains\"]}],\"isfull\":\"Full\",\"moreinfo\":\"More info\",\"nextstep\":\"Next step\",\"no\":\"No\",\"noavailableoptions\":\"Sorry, there are at this time no options for registration available\",\"nooptionsavailable\":\"Sorry, no options available\",\"notewaitinglist\":\"This course is fully booked, if you register now, you will be placed on the waiting list and you will be enrolled if a place becomes available.\",\"ok\":\"Ok\",\"registrationerror_already_registered\":\"You have already registered for this course.\",\"registrationerror_full\":\"Selected date/time is full\",\"registrationerror_nocourse\":\"Course not available\",\"registrationerror_nosession\":\"Selected date/time not available\",\"registrationerror_title\":\"Error while saving registration\",\"registrationerror_waitinglistfull\":\"Waiting list full\",\"results\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"course\"],\"subselse\":[\"courses\"]},\" found\"],\"retry\":\"Retry\",\"signup\":\"Sign up\",\"signupfor\":\"Sign up for:\",\"start\":\"Start\",\"submiterror-failed\":\"Failed\",\"submiterror-prefix\":\"Your registration has:\",\"submitsuccess-description\":\"You will receive an email with further information.\",\"submitsuccess-followupdescription\":[\"This is an accompanying course for '\",1,\"'\"],\"submitsuccess-prefix\":\"Your registration is:\",\"submitsuccess-title\":\"Successful\",\"submitsuccess-waitinglist\":\"You're on the waiting list. You will receive an email with further information.\",\"waitinglist\":\"Waiting list\",\"xcourses\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"Course\"],\"subselse\":[\"Courses\"]}],\"xdaycourse\":[1,\" day course\"],\"xmore\":[1,\" more\"],\"yes\":\"Yes\"}}}});\nregisterTexts(\"utwente_courses\",\"es\",{\"webfeatures\":{\"frontend\":{\"js\":{\"activefilters\":\"Active filters\",\"cancel\":\"Cancel\",\"closeregistration\":\"Close registration\",\"coursealert\":\"Course alert\",\"coursealert-description\":\"After registration you will regularly receive our new courses.\",\"coursealert-description-noresults\":\"We currently have no curssen available for this selection. Enter your details and you will be the first to be notified when one becomes available.\",\"coursealert-login\":\"Login\",\"coursealert-singlecoursedescription\":[\"Can’t wait to join this course? Sign up for the waiting list. You will receive an alert as soon as a new course is organised or a seat in one of the current courses becomes available.\",\"\\n\",\"We will only alert you \",{\"t\":\"tag\",\"tag\":\"b\",\"subs\":\"once\"},\". If you do not use this opportunity, you will have to sign up again for this alert.\"],\"coursenotyetopen\":\"Sorry, you cannot register for this course yet.\",\"inxdomains\":[\"in \",1,\"  \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"domain\"],\"subselse\":[\"domains\"]}],\"isfull\":\"Full\",\"moreinfo\":\"More info\",\"nextstep\":\"Next step\",\"no\":\"No\",\"noavailableoptions\":\"Sorry, there are at this time no options for registration available\",\"nooptionsavailable\":\"Sorry, no options available\",\"notewaitinglist\":\"This course is fully booked, if you register now, you will be placed on the waiting list and you will be enrolled if a place becomes available.\",\"ok\":\"Ok\",\"registrationerror_already_registered\":\"You have already registered for this course.\",\"registrationerror_full\":\"Selected date/time is full\",\"registrationerror_nocourse\":\"Course not available\",\"registrationerror_nosession\":\"Selected date/time not available\",\"registrationerror_title\":\"Error while saving registration\",\"registrationerror_waitinglistfull\":\"Waiting list full\",\"results\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"course\"],\"subselse\":[\"courses\"]},\" found\"],\"retry\":\"Retry\",\"signup\":\"Sign up\",\"signupfor\":\"Sign up for:\",\"start\":\"Start\",\"submiterror-failed\":\"Failed\",\"submiterror-prefix\":\"Your registration has:\",\"submitsuccess-description\":\"You will receive an email with further information.\",\"submitsuccess-followupdescription\":[\"This is an accompanying course for '\",1,\"'\"],\"submitsuccess-prefix\":\"Your registration is:\",\"submitsuccess-title\":\"Successful\",\"submitsuccess-waitinglist\":\"You're on the waiting list. You will receive an email with further information.\",\"waitinglist\":\"Waiting list\",\"xcourses\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"Course\"],\"subselse\":[\"Courses\"]}],\"xdaycourse\":[1,\" day course\"],\"xmore\":[1,\" more\"],\"yes\":\"Yes\"}}}});\nregisterTexts(\"utwente_courses\",\"it\",{\"webfeatures\":{\"frontend\":{\"js\":{\"activefilters\":\"Active filters\",\"cancel\":\"Cancel\",\"closeregistration\":\"Close registration\",\"coursealert\":\"Course alert\",\"coursealert-description\":\"After registration you will regularly receive our new courses.\",\"coursealert-description-noresults\":\"We currently have no curssen available for this selection. Enter your details and you will be the first to be notified when one becomes available.\",\"coursealert-login\":\"Login\",\"coursealert-singlecoursedescription\":[\"Can’t wait to join this course? Sign up for the waiting list. You will receive an alert as soon as a new course is organised or a seat in one of the current courses becomes available.\",\"\\n\",\"We will only alert you \",{\"t\":\"tag\",\"tag\":\"b\",\"subs\":\"once\"},\". If you do not use this opportunity, you will have to sign up again for this alert.\"],\"coursenotyetopen\":\"Sorry, you cannot register for this course yet.\",\"inxdomains\":[\"in \",1,\"  \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"domain\"],\"subselse\":[\"domains\"]}],\"isfull\":\"Full\",\"moreinfo\":\"More info\",\"nextstep\":\"Next step\",\"no\":\"No\",\"noavailableoptions\":\"Sorry, there are at this time no options for registration available\",\"nooptionsavailable\":\"Sorry, no options available\",\"notewaitinglist\":\"This course is fully booked, if you register now, you will be placed on the waiting list and you will be enrolled if a place becomes available.\",\"ok\":\"Ok\",\"registrationerror_already_registered\":\"You have already registered for this course.\",\"registrationerror_full\":\"Selected date/time is full\",\"registrationerror_nocourse\":\"Course not available\",\"registrationerror_nosession\":\"Selected date/time not available\",\"registrationerror_title\":\"Error while saving registration\",\"registrationerror_waitinglistfull\":\"Waiting list full\",\"results\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"course\"],\"subselse\":[\"courses\"]},\" found\"],\"retry\":\"Retry\",\"signup\":\"Sign up\",\"signupfor\":\"Sign up for:\",\"start\":\"Start\",\"submiterror-failed\":\"Failed\",\"submiterror-prefix\":\"Your registration has:\",\"submitsuccess-description\":\"You will receive an email with further information.\",\"submitsuccess-followupdescription\":[\"This is an accompanying course for '\",1,\"'\"],\"submitsuccess-prefix\":\"Your registration is:\",\"submitsuccess-title\":\"Successful\",\"submitsuccess-waitinglist\":\"You're on the waiting list. You will receive an email with further information.\",\"waitinglist\":\"Waiting list\",\"xcourses\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"Course\"],\"subselse\":[\"Courses\"]}],\"xdaycourse\":[1,\" day course\"],\"xmore\":[1,\" more\"],\"yes\":\"Yes\"}}}});\nregisterTexts(\"utwente_courses\",\"xt\",{\"webfeatures\":{\"frontend\":{\"js\":{\"activefilters\":\"Active filters\",\"cancel\":\"Cancel\",\"closeregistration\":\"Close registration\",\"coursealert\":\"Course alert\",\"coursealert-description\":\"After registration you will regularly receive our new courses.\",\"coursealert-description-noresults\":\"We currently have no curssen available for this selection. Enter your details and you will be the first to be notified when one becomes available.\",\"coursealert-login\":\"Login\",\"coursealert-singlecoursedescription\":[\"Can’t wait to join this course? Sign up for the waiting list. You will receive an alert as soon as a new course is organised or a seat in one of the current courses becomes available.\",\"\\n\",\"We will only alert you \",{\"t\":\"tag\",\"tag\":\"b\",\"subs\":\"once\"},\". If you do not use this opportunity, you will have to sign up again for this alert.\"],\"coursenotyetopen\":\"Sorry, you cannot register for this course yet.\",\"inxdomains\":[\"in \",1,\"  \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"domain\"],\"subselse\":[\"domains\"]}],\"isfull\":\"Full\",\"moreinfo\":\"More info\",\"nextstep\":\"Next step\",\"no\":\"No\",\"noavailableoptions\":\"Sorry, there are at this time no options for registration available\",\"nooptionsavailable\":\"Sorry, no options available\",\"notewaitinglist\":\"This course is fully booked, if you register now, you will be placed on the waiting list and you will be enrolled if a place becomes available.\",\"ok\":\"Ok\",\"registrationerror_already_registered\":\"You have already registered for this course.\",\"registrationerror_full\":\"Selected date/time is full\",\"registrationerror_nocourse\":\"Course not available\",\"registrationerror_nosession\":\"Selected date/time not available\",\"registrationerror_title\":\"Error while saving registration\",\"registrationerror_waitinglistfull\":\"Waiting list full\",\"results\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"course\"],\"subselse\":[\"courses\"]},\" found\"],\"retry\":\"Retry\",\"signup\":\"Sign up\",\"signupfor\":\"Sign up for:\",\"start\":\"Start\",\"submiterror-failed\":\"Failed\",\"submiterror-prefix\":\"Your registration has:\",\"submitsuccess-description\":\"You will receive an email with further information.\",\"submitsuccess-followupdescription\":[\"This is an accompanying course for '\",1,\"'\"],\"submitsuccess-prefix\":\"Your registration is:\",\"submitsuccess-title\":\"Successful\",\"submitsuccess-waitinglist\":\"You're on the waiting list. You will receive an email with further information.\",\"waitinglist\":\"Waiting list\",\"xcourses\":[1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"Course\"],\"subselse\":[\"Courses\"]}],\"xdaycourse\":[1,\" day course\"],\"xmore\":[1,\" more\"],\"yes\":\"Yes\"}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/language/default.xml\n","// ws2026 implementation!\nimport './coursefinder.scss';\nimport \"./pages\";\n\nimport { cCourseDetailsList } from \"./components/detail\";\nimport { cCalendar } from \"./components/calendar/calendar\";\nimport \"./coursefinder.lang.json\";\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\nimport * as dompack from \"@webhare/dompack\";\nimport { type FormSubmitEmbeddedResult, RPCFormBase, registerHandler } from \"@mod-publisher/js/forms\";\nimport * as wrdauth from \"@mod-wrd/js/auth\";\nimport { getTid } from \"@mod-tollium/js/gettid\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport type { UTDialog } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/dialogs\";\nimport * as frontend from \"@webhare/frontend\";\nimport { DefaultFilter, type CustomPageFilter, type PageFiltersContext, registerCustomFilter } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters\";\nimport UTCoursesService from \"@mod-utwente_courses/js/site-service\";\n\ntype FrontendUserInfo = { isemployee: boolean; isstudent: boolean; email?: string };\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_courses:coursefinder\": { pageid: number; catalog: string };\n  }\n}\n\nclass FilterUtwenteCourses implements CustomPageFilter {\n  language: string = \"en\";\n  hashparts: string[] = [];\n  node: HTMLElement;\n  calendar: cCalendar | null = null;\n  frontendData: { pageid: number; catalog: string };\n\n  myFilter: DefaultFilter; // We use the default filter for the actual filtering, we just rewrite results for specific rendering afterward depending on the view mode\n  constructor() {\n    this.node = dompack.qR(\".coursefinder__page\");\n\n    this.myFilter = new DefaultFilter(null, { customTextSearch: true });\n\n    this.frontendData = getFrontendData(\"utwente_courses:coursefinder\");\n\n    this.language = document.documentElement.lang.split(\"-\")[0];\n\n    const detaillistwrapper = dompack.qS(this.node, \".coursefinder__detaillist\");\n    if (detaillistwrapper)\n      new cCourseDetailsList(detaillistwrapper); //Controls animations/effects in detail/list\n\n    const calendarwrapper = dompack.qS(this.node, \".coursefinder__calendar\");\n    if (calendarwrapper) {\n      let initialdate = new Date();//Today\n      if (this.hashparts.length > 2) {\n        const year = Number(this.hashparts[1]);\n        const month = Number(this.hashparts[2]);\n        const curym = (initialdate.getFullYear() * 12) + initialdate.getMonth();\n\n        if (month > 0 && month <= 12 && (year * 12) + (month - 1) >= curym)//should be mininal current month\n          initialdate = new Date(year, month - 1, 1, 0, 0, 0);\n      }\n\n      this.calendar = new cCalendar(calendarwrapper, { \"date\": initialdate, pageid: this.frontendData.pageid });\n    }\n\n    this.node.addEventListener(\"pagefilters:viewmodechange\", ev => this.onViewModeChange((ev as CustomEvent).detail.mode));\n\n    this.node.classList.add(\"coursefinder__page--loaded\");\n  }\n\n  onViewModeChange(mode: string) {\n    const newclass = \"coursefinder__page--\" + mode;\n    if (this.node.classList.contains(newclass))\n      return;//already active\n\n    if (this.calendar && mode === \"calendar\")\n      this.calendar.setMonthName();//update hash with year.month\n\n    this.node.classList.remove(\"coursefinder__page--detail\");\n    this.node.classList.remove(\"coursefinder__page--list\");\n    this.node.classList.remove(\"coursefinder__page--calendar\");\n\n    this.node.classList.add(newclass);\n  }\n\n  async filter(filtercontext: PageFiltersContext): Promise<HTMLElement[] | null> {\n    let items = this.myFilter.filter(filtercontext) || [];\n\n    if (filtercontext.query.searchWords) {\n      // handle word search! Get course ids from consilio results\n      const lock = dompack.flagUIBusy();\n      let result: { ids: number[]; words: string };\n      try {\n        result = await UTCoursesService.SearchWords(this.frontendData.pageid, this.language, filtercontext.query.searchWords);\n      } finally {\n        lock.release();\n      }\n\n      items = items.filter(item => result.ids.includes(Number(item.dataset.id)));\n    }\n\n    const itemids = items.map(_ => _.dataset.id) as string[];\n\n    const itemcount = items.length;\n\n    // handle rendering ourself because items are wrapped per domain, count/domain + different views\n    dompack.qSA(\".page-filterstoolbar__feedback\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.search-xresults\", String(itemcount)));\n    dompack.qSA(\".page-filters__mobiletoggle__hidelabel\").forEach(el => el.textContent = getTid(\"utwente_base:frontend.ws2016.js.pagefilters.show-xresults\", String(itemcount)));\n    document.documentElement.classList.toggle(\"page-filters--noresults\", !itemcount); // used to show no results message\n\n    const coursestxt = getTid('utwente_courses:webfeatures.frontend.js.results', itemcount);\n\n    const domains = items.map(_ => _.dataset.filterDomain).filter((v, i, a) => v && a.indexOf(v) === i) as string[]; // get unique list of domains in results\n\n    dompack.qSA(\".coursefinder__detaillist__domain\").forEach(node => {\n      node.hidden = !domains.includes(node.dataset.domain || \"\"); // show domain if in results, hide otherwise\n\n      if (!node.hidden) {\n        let coursematchcount = 0;\n        dompack.qSA(node, \".pagefilters__item\").forEach(itemnode => {\n          const itemid = itemnode.dataset.id || \"\";\n          itemnode.hidden = !itemids.includes(itemid);\n          if (!itemnode.hidden) coursematchcount++;\n        });\n\n        //Update counters inside domains node\n        dompack.qSA(node, \"span[data-coursecount]\").forEach(countnode => {\n          if (countnode.dataset.coursecount === \"totalcoursecount\")\n            countnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.xcourses', coursematchcount);\n          else if (countnode.dataset.coursecount === \"utcoursecount\") {\n            const utwrapper = countnode.closest(\".coursefinder__detaillist__utcourses\");\n            if (utwrapper) {\n              const utcount = dompack.qSA(utwrapper, \".coursefinder__detaillist__courses__line:not([hidden])\").length;\n              countnode.textContent = getTid('utwente_courses:webfeatures.frontend.js.xcourses', utcount);\n            }\n          } else if (countnode.dataset.coursecount!.startsWith(\"externalcoursecount\")) {\n            const sourcewrapper = countnode.closest(\".coursefinder__detaillist__source\") as HTMLElement | null;\n            if (sourcewrapper) {\n              const sourcecount = dompack.qSA(sourcewrapper, \".coursefinder__detaillist__courses__line:not([hidden])\").length;\n              countnode.textContent = String(sourcecount);\n\n              sourcewrapper.hidden = sourcecount === 0; // hide wrapper if 0 results\n            }\n          }\n        });\n      }\n    });\n\n    if (this.calendar)\n      this.calendar.filterCourses(itemids.map(id => Number(id)));\n\n    const domainstxt = getTid('utwente_courses:webfeatures.frontend.js.inxdomains', domains.length);\n\n    dompack.qSA(\".pagefilters__filteredtags__title\").forEach(resultnode => {\n      resultnode.textContent = `${coursestxt} ${domainstxt}`;\n    });\n\n    return null;// return null so pagefilters don't interferes with rendering!\n  }\n}\n\n\ndompack.register(\".embeddedobject--inlinecta a[href^='#coursealert'], .showcoursealert\", node => {\n  node.addEventListener(\"click\", ev => {\n    ev.preventDefault();\n    node.blur(); // remove focus from clicked element\n\n    let alertoptions;\n\n    let courseid = \"\";\n    let coursetitle = \"\";\n    if (node.nodeName === \"A\") {\n      const parts = node.getAttribute(\"href\")!.split(\":\");\n      if (parts.length === 2) {\n        courseid = parts[1].replace(/[^0-9]+/g, '');\n        const container = node.closest(\".embeddedobject--inlinecta\");\n        if (container)\n          coursetitle = dompack.qR(container, \".formheader__title\").textContent as string;\n      }\n    } else { //probably in course overview page\n      const overviewline = node.closest(\".coursefinder__detaillist__courses__line\") as HTMLElement;\n      if (overviewline) {\n        coursetitle = overviewline.title;\n        courseid = overviewline.dataset.id || \"\";\n      }\n    }\n\n    if (courseid) { // alert for single course\n      alertoptions = {\n        title: coursetitle,\n        id: courseid,\n        singlecourse: true\n      };\n    }\n\n    void showCourseAlertForm(alertoptions);\n  });\n});\n\nasync function showCourseAlertForm(options: { id?: string; categories?: string[]; singlecourse?: boolean; title?: string } = {}) {\n  const formnode = dompack.qS<HTMLFormElement>(\".coursefinder__coursealertdialog__form\");\n  if (!formnode) {\n    console.error(\"Missing Course Alert form\");\n    return;\n  }\n\n  formnode.singlecourse.value = \"0\";\n\n  if (options && options.singlecourse) {\n    formnode.singlecourse.value = options.id;\n    dompack.dispatchDomEvent(formnode.singlecourse, 'change');\n  } else if (options && options.categories && options.categories.length) {\n    dompack.qSA<HTMLInputElement>(formnode, \"input[name='categories']\").forEach(inpnode => {\n      inpnode.checked = options.categories!.indexOf(inpnode.value) > -1;\n    });\n  }\n\n  const dialog = dialogapi.createDialog({ borrow: formnode, allowcancel: true }) as UTDialog;\n\n  dialog.utheadernode.appendChild(<h2>{getTid('utwente_courses:webfeatures.frontend.js.coursealert')}</h2>);\n  if (options && options.title)\n    dialog.utheadernode.appendChild(<h3>{options.title}</h3>);\n\n  if (options && options.singlecourse)\n    dialog.utheadernode.appendChild(<p>{getTid('utwente_courses:webfeatures.frontend.js.coursealert-singlecoursedescription')}</p>);\n  else\n    dialog.utheadernode.appendChild(<p>{getTid('utwente_courses:webfeatures.frontend.js.coursealert-description')}</p>);\n\n  dialog.contentnode!.classList.add(\"courses-dialog--coursealert\");\n  dialog.holdernode.classList.add(\"courses-dialog__holder--coursealert\");\n\n  await dialog.runModal();\n\n  dompack.dispatchCustomEvent(formnode, \"utwente_courses:closedialog\", { bubbles: false, cancelable: true });\n}\n\nasync function showCourseAlertSuccess(node: HTMLElement, options: { title: string; singlecourse?: boolean }) {\n  const dialog = dialogapi.createDialog({ borrow: node, allowcancel: true }) as UTDialog;\n\n  dialog.utheadernode.appendChild(<h2>{getTid('utwente_courses:webfeatures.frontend.js.coursealert')}</h2>);\n  if (options && options.title)\n    dialog.utheadernode.appendChild(<h3>{options.title}</h3>);\n\n  if (options && options.singlecourse)\n    dialog.utheadernode.appendChild(<p>{getTid('utwente_courses:webfeatures.frontend.js.coursealert-singlecoursedescription')}</p>);\n  else\n    dialog.utheadernode.appendChild(<p>{getTid('utwente_courses:webfeatures.frontend.js.coursealert-description')}</p>);\n\n  dialog.contentnode!.classList.add(\"courses-dialog--coursealert\");\n  dialog.holdernode.classList.add(\"courses-dialog__holder--coursealert\");\n\n  await dialog.runModal();\n\n  node.remove();//just remove, just needed once when opening page\n}\n\ndompack.register(\".coursefinder__subscribedcoursealert[data-title]\", node => { //Shown sucess dialog after loggedin when user has registered for course alert\n  void showCourseAlertSuccess(node, { title: node.dataset.title as string, singlecourse: Boolean(node.dataset.singlecourse && node.dataset.singlecourse !== '0') });\n});\n\nclass CourseAlertForm extends RPCFormBase {\n  userinfo: FrontendUserInfo | null = null;\n  constructor(form: HTMLFormElement) {\n    super(form);\n\n    if (wrdauth.getDefaultAuth()?.isLoggedIn())\n      this.userinfo = frontend.getUserInfo<FrontendUserInfo>();\n\n    this.node.addEventListener(\"utwente_courses:closedialog\", ev => {\n      if (ev.target === this.node)\n        this.reset();\n    });\n\n    if (this.getUrlParam(\"showcoursealert\")) //small delay so dialog init script has run before opening dialog\n      setTimeout(() => void showCourseAlertForm(), 500);\n\n    const subscribeasoptoins = dompack.qSA(this.node, \"[name=subscribeas]\");\n    if (subscribeasoptoins.length) {// (not loggedin)\n      subscribeasoptoins.forEach(node => node.addEventListener(\"change\", () => this.updateSubscribeAs()));\n      this.updateSubscribeAs();\n    }\n  }\n\n  async reset() {\n    super.reset();\n    void this.gotoPage(0);\n  }\n\n  onSubmitSuccess(param: FormSubmitEmbeddedResult) {\n    super.onSubmitSuccess(param);\n\n    const dialog = this.node.closest(\".ut-dialog__holder\");\n    if (dialog) // Remove intro tekst from dialog header\n      dompack.qSA(dialog, \".ut-dialog__header p\").forEach(p => p.remove());\n\n    if (!window.dataLayer)\n      window.dataLayer = [];\n\n    const categories: string[] = [];\n    dompack.qSA(this.node, \"input[name='categories']:checked\").forEach(node => {\n      categories.push((node.parentNode as HTMLElement).textContent || \"\");\n    });\n\n    let subscribeas = \"external\";\n    if (this.userinfo) {\n      if (this.userinfo.isemployee)\n        subscribeas = \"employee\";\n      else if (this.userinfo.isstudent)\n        subscribeas = \"student\";\n    }\n\n    window.dataLayer.push({\n      \"event\": \"coursealert-submitted\",\n      \"coursealert-categories\": categories.join(\";\"),\n      \"coursealert-subscribeas\": subscribeas\n    });\n  }\n\n  updateSubscribeAs() {\n    const loginbtngroup = this.node.querySelector(\".wh-form__fieldgroup--loginbtn\");\n    if (!loginbtngroup)\n      return;\n\n    const subscribeas = dompack.qS<HTMLInputElement>(this.node, \"input[name='subscribeas']:checked\");\n    if (subscribeas && subscribeas.value === \"utlogin\") {\n      loginbtngroup.classList.remove(\"wh-form__fieldgroup--hidden\");\n      this.node.classList.remove(\"wh-form--allowsubmit\");\n    } else {\n      loginbtngroup.classList.add(\"wh-form__fieldgroup--hidden\");\n      this.node.classList.add(\"wh-form--allowsubmit\");\n    }\n  }\n\n  getUrlParam(name: string) {\n    const val = new URL(location.href).searchParams.get(name);\n    return val ? decodeURIComponent(val) : \"\";\n  }\n}\n\nregisterCustomFilter(\"utwenteCoursesFilter\", () => new FilterUtwenteCourses());\n\n\nregisterHandler(\"utwente_courses:coursealert\", form => new CourseAlertForm(form));\n","import \"./studyfinder2026.scss\";\nimport \"./studyfinder-widget.scss\";\n\nimport * as dompack from \"@webhare/dompack\";\nimport \"./studyfinder.lang.json\";\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\nimport { navigateTo } from \"@webhare/env\";\nimport { getTid } from \"@mod-tollium/js/gettid\";\nimport UTAutoComplete from '@mod-utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter';\nimport { SearchIndex } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/searchindex\";\nimport { DefaultFilter, type PageFiltersContext, CustomPageFilter, registerCustomFilter } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_education:studyfinder\": {\n      columnsListviewProgramme: string[];\n      columnsListviewSpecialization: string[];\n    };\n  }\n}\n\ninterface IndexedItem {\n  id: string;\n  specid: string;\n  title: string;\n  description: string;\n  titleNode: HTMLElement;\n  descriptionNode: HTMLElement;\n}\n\nclass studyFinderFilter implements CustomPageFilter {\n  programmescontainer: HTMLElement;\n  scorecolumn = <div style=\"display: none;\" />; // Holder for sorting on score\n  tablecellnames_programme: string[] = [];\n  tablecellnames_specialization: string[] = [];\n\n  tableheader = dompack.create(\"li\", { className: \"pagefilters__listview__header studyfinder__listview__header\" });\n  sortcolumn: HTMLElement | null = null;\n\n  myFilter: DefaultFilter; // We use the default filter for the actual filtering, we just rewrite results for specific rendering afterward depending on the view mode\n  searchIndex = new SearchIndex<IndexedItem>();\n\n  constructor() {\n    this.programmescontainer = dompack.qR(\".studyfinderprogrammes.pagefilters__itemcontainer\");\n\n    this.myFilter = new DefaultFilter(null, { customAutocomplete: true }); // We will handle autocomplete ourselves to also include specialization titles/descriptions in suggestions\n\n    this.programmescontainer.parentNode!.append(this.scorecolumn);\n\n    this.programmescontainer.addEventListener(\"pagefilters:viewmodechange\", ev => this.onViewModeChange((ev as CustomEvent).detail.mode));\n\n    const settings = getFrontendData(\"utwente_education:studyfinder\");\n    this.tablecellnames_programme = settings.columnsListviewProgramme;\n    this.tablecellnames_specialization = settings.columnsListviewSpecialization;\n\n    if ( !dompack.qS(this.programmescontainer, \".studyfinder__programme__specializations\") ) {\n      // Incase of listview: If there are no programme's with specializations then remove the column \"specializations\"\n      for (let i = this.tablecellnames_programme.length - 1; i >= 0; --i) {\n        if (this.tablecellnames_programme[i] === \"specializations\") {\n          this.tablecellnames_programme.splice(i, 1);\n          break;\n        }\n      }\n    }\n\n    this.initAutoSuggest();\n    this.programmescontainer.addEventListener(\"click\", ev => this.toggleSpecializations(ev));\n  }\n\n  initAutoSuggest() {\n    // First build suggest index based on all programmes and specializations titles/descriptions\n    this.searchIndex.searchFields = [\"title\", \"description\"];\n    this.searchIndex.completeSuggestFields = [\"title\"];\n\n    this.myFilter.srcItems.forEach(item => {\n      let titleNode = dompack.qS(item, \".studyfinder__programme__title__text\") as HTMLElement;\n      let descriptionNode = dompack.qS(item, \".studyfinder__programme__description\") as HTMLElement;\n      this.searchIndex.indexItem( {\n        id: item.dataset.id!,\n        specid: \"0\",\n        title: titleNode?.textContent || '',\n        description: descriptionNode?.textContent || '',\n        titleNode,\n        descriptionNode\n      });\n\n      dompack.qSA(item, \".studyfinder__programme--specialization\").forEach(specialization => {\n        titleNode = dompack.qS(specialization, \".studyfinder__programme__title__text\") as HTMLElement;\n        descriptionNode = dompack.qS(specialization, \".studyfinder__programme__description\") as HTMLElement;\n        this.searchIndex.indexItem( {\n          id: item.dataset.id!,\n          specid: specialization.dataset.id!,\n          title: titleNode?.textContent || '',\n          description: descriptionNode?.textContent || '',\n          titleNode,\n          descriptionNode\n        });\n      });\n    });\n\n    // A slightly modified version of initSearchSuggestions to highlight matches within suggestions, not just the first x characters\n    const searchnode = dompack.qS<HTMLInputElement>(\".page-titlebar__form input[name=query]\");\n    if (searchnode) {\n      UTAutoComplete({\n        input: searchnode,\n        className: 'ut-autocomplete',\n        preventSubmit: 1,\n        fetch: (text, update) => {\n          const suggestions = this.searchIndex.suggest(text).slice(0, 10);\n          update(suggestions.map(_ => { return { label: _, value: _ }; }));\n        },\n        onSelect: (item) => {\n          searchnode.value = item.label ?? \"\";\n          dompack.dispatchDomEvent(searchnode, \"change\"); // Trigger filtering of pagefilters\n        },\n        customize: (input, inputRect, container, maxHeight) => {\n          // use search form width istead of input width\n          const width = input.parentElement!.offsetWidth;\n          const leftPos = inputRect.left + (inputRect.width - width);\n          container.style.width = width + \"px\";\n          container.style.left = leftPos + \"px\";\n        }\n      });\n    }\n  }\n\n  filter(context: PageFiltersContext): HTMLElement[] | null {\n    let items = this.myFilter.filter(context);\n\n    if( items ) {\n      if( context.query.searchWords ) {\n        const result = this.searchIndex.search(context.query.searchWords);\n        const resultIds =  result.items.map(_ => _.id);\n        items = items.filter(item => resultIds.includes(item.dataset.id!));\n        items.forEach(item => {\n          let titleNode = dompack.qS(item, \".studyfinder__programme__title__text\") as HTMLElement;\n          if( titleNode )\n            this.highlightSearchTerms(result.terms, titleNode.textContent, titleNode);\n          let descriptionNode = dompack.qS(item,\".studyfinder__programme__description\") as HTMLElement;\n          if( descriptionNode )\n            this.highlightSearchTerms(result.terms, descriptionNode.textContent, descriptionNode);\n\n          // also hight specializations and foldout if has searchWords matches\n          const specializationsNode = dompack.qS(item, \".studyfinder__programme__specializations\");\n          if( specializationsNode ) {\n            let specMatchCount = 0;\n            dompack.qSA(specializationsNode, \".studyfinder__programme--specialization\").forEach(specialization => {\n              let hasMatch = false;\n              titleNode = dompack.qS(specialization, \".studyfinder__programme__title__text\") as HTMLElement;\n              if( titleNode && this.highlightSearchTerms(result.terms, titleNode.textContent, titleNode) )\n                hasMatch = true;\n\n              descriptionNode = dompack.qS(specialization,\".studyfinder__programme__description\") as HTMLElement;\n              if( descriptionNode && this.highlightSearchTerms(result.terms, descriptionNode.textContent, descriptionNode))\n                hasMatch = true;\n\n              if (hasMatch)\n                ++specMatchCount;\n            });\n\n            if( specMatchCount ) { // If match in specialization, ensure specializations are visible\n              specializationsNode.classList.add(\"show\");\n              specializationsNode.style.height = \"auto\";\n              specializationsNode.hidden = false;\n            }\n          }\n        });\n      } else {\n        // If no search terms, remove all highlights\n        items.forEach(item => {\n          dompack.qSA(item, \".ut-querymatch\").forEach(match => {\n            const parent = match.parentNode!;\n            parent.replaceChild(document.createTextNode(match.textContent || ''), match);\n            parent.normalize(); // Merge adjacent text nodes to prevent fragmentation\n          });\n        });\n      }\n    }\n\n    if( !items )\n      return null;\n\n    // Rendering depends on viewmode\n    if( this.programmescontainer.classList.contains(\"pagefilters__itemcontainer--detailview\") )\n      return items;\n\n    // list view:\n    return this.itemsToListItems(items);\n  }\n\n  highlightSearchTerms(terms: string[], text: string, node: HTMLElement) {\n    const regex = new RegExp(`\\\\b(${terms.join(\"|\")})\\\\b`, \"ig\");\n    const descriptionNodes = [];\n    let lastIndex = 0;\n    let match;\n    while ((match = regex.exec(text)) !== null) {\n      descriptionNodes.push(text.substring(lastIndex, match.index));\n      descriptionNodes.push(<span class=\"ut-querymatch\" > {match[0]} </span>);\n      lastIndex = match.index + match[0].length;\n    }\n    if (!lastIndex) {\n      node.textContent = text;\n    } else {\n      if (lastIndex < text.length)\n        descriptionNodes.push(text.substr(lastIndex));\n\n      node.replaceChildren();\n      for (const descNode of descriptionNodes)\n        if (typeof descNode === \"string\")\n          node.append(descNode);\n        else\n          node.appendChild(descNode);\n    }\n    return lastIndex > 0;\n  }\n\n  itemsToListItems(items: HTMLElement[]): HTMLLIElement[] {\n    const listItems: HTMLLIElement[] = [];\n\n    items?.forEach((node, idx) => {\n\n      const compactnode = this.buildRow(dompack.qS(node, \".studyfinder__programme__content\") as HTMLElement, node.dataset); // Just pick first\n      compactnode.setAttribute(\"data-idx\", String(idx));\n      if (!node.dataset.specializations)\n        compactnode.classList.add(\"nospecializations\");\n\n      listItems.push(compactnode);\n\n      // Check for expanded specializations, if so add these as well\n      const visibleSpecNode = dompack.qS(node, \".studyfinder__programme__specializations.show\");\n      if (visibleSpecNode) {\n        compactnode.classList.add(\"expanded\");\n        listItems.push(...this.getSpecializationRows(node));\n      }\n    });\n    return listItems;\n  }\n\n  onViewModeChange( mode: \"detail\" | \"list\") {\n    if (mode === \"detail\") {\n      this.tableheader.remove();\n    } else {\n      // Generate the table header row\n      this.tableheader.replaceChildren();\n      for (let i = 0; i < this.tablecellnames_programme.length; ++i) {\n        let coltitle = \"\";\n        switch (this.tablecellnames_programme[i]) {\n          case \"degree\": coltitle = getTid('utwente_education:site.studyfinder.js.degree'); break;\n          case \"title\": coltitle = getTid('utwente_education:site.studyfinder.js.study'); break;\n          case \"duration\": coltitle = getTid('utwente_education:site.studyfinder.js.duration'); break;\n          case \"time\": coltitle = getTid('utwente_education:site.studyfinder.js.workload'); break;\n          case \"languages\": coltitle = getTid('utwente_education:site.studyfinder.js.language'); break;\n          case \"specializations\": coltitle = getTid('utwente_education:site.studyfinder.js.specializations'); break;\n          case \"workload_curiousu\": coltitle = getTid('utwente_education:site.studyfinder.js.workload'); break;\n        }\n\n        const cellnode = dompack.create(\"div\", {\n          className: \"col--\" + this.tablecellnames_programme[i],\n          textContent: coltitle,\n          dataset: { name: this.tablecellnames_programme[i] }\n        });\n\n        cellnode.addEventListener(\"click\", ev => this.sortColumn(cellnode));\n        this.tableheader.appendChild(cellnode);\n      }\n\n      this.programmescontainer.insertBefore(this.tableheader, this.programmescontainer.firstChild);\n    }\n  }\n\n  sortColumn(colnode: HTMLElement) {\n    const isothercolumn = colnode !== this.sortcolumn;\n\n    if (isothercolumn && this.sortcolumn)\n      this.sortcolumn.classList.remove(\"sortactive\");\n\n    this.sortcolumn = colnode;\n    this.sortcolumn.classList.add(\"sortactive\");\n\n    let sortasc = colnode.classList.contains(\"sort-asc\");\n    if (!isothercolumn) { //If same column, invert ordering\n      if (!sortasc) {\n        colnode.classList.add(\"sort-asc\");\n        sortasc = true;\n      } else {\n        colnode.classList.remove(\"sort-asc\");\n        sortasc = false;\n      }\n    }\n\n    const scoresort = this.sortcolumn === this.scorecolumn;\n    let sortedprogrammes = [];\n    for (const node of dompack.qSA(this.programmescontainer, scoresort ? \".studyfinder__programme--mainprogramme[data-sort]\" : \".studyfinder__programme--mainprogramme .cell--\" + colnode.dataset.name)) {\n      // we are a programme, any specializations rows following this row belong to this programme\n      const specializations = [];\n      let snode: HTMLElement | null = (scoresort ? node.nextSibling : (node.parentNode as HTMLElement)!.nextElementSibling) as HTMLElement;\n      while (snode && snode.classList.contains(\"studyfinder__programme--specialization\")) {\n        specializations.push({\n          text: scoresort\n            ? (snode.dataset.sort ? this.getSortText(snode) : (1000 + Number(snode.dataset.specid)))\n            : this.getSortText(dompack.qS<HTMLElement>(snode, \".cell--\" + colnode.dataset.name)),\n          row: snode\n        });\n        snode = snode.nextElementSibling as HTMLElement;\n      }\n\n      sortedprogrammes.push(\n        {\n          text: this.getSortText(node),\n          row: (scoresort ? node : node.parentNode) as HTMLElement,\n          specializations: this.sortList(specializations, sortasc)\n        });\n    }\n\n    sortedprogrammes = this.sortList(sortedprogrammes, sortasc);\n\n    //Now set nodes in correct order\n    for (let i = 0; i < sortedprogrammes.length; ++i) {\n      this.programmescontainer.appendChild(sortedprogrammes[i].row);\n      for (let s = 0; s < sortedprogrammes[i].specializations.length; ++s)\n        this.programmescontainer.appendChild(sortedprogrammes[i].specializations[s].row);\n    }\n  }\n\n  sortDetails(colnode: HTMLElement) {\n    this.sortcolumn = colnode;\n\n    const sortasc = true;\n\n    let sortedprogrammes = [];\n    for (const node of dompack.qSA(this.programmescontainer, \".studyfinder__programme:not(.studyfinder__programme--specialization)\")) {\n      let specializations = [];\n      let specParent;\n      for (const specNode of dompack.qSA(node, \".studyfinder__programme--specialization\")) {\n        if (!specParent)\n          specParent = specNode.parentNode;\n        specializations.push({\n          text: specNode.dataset.sort ? this.getSortText(specNode) : (1000 + Number(specNode.dataset.specid)),\n          node: specNode\n        });\n      }\n\n      if (specializations.length) {\n        // Set specialization nodes in correct order\n        specializations = this.sortList(specializations, sortasc);\n        for (const spec of specializations)\n          specParent!.appendChild(spec.node);\n        // Move all unmatched specializations to the end (skipping the first 'header' row)\n        for (let i = 1; i < specParent!.childNodes.length - specializations.length; ++i)\n          specParent!.appendChild(specParent!.childNodes[1]);\n      }\n\n      sortedprogrammes.push({\n        text: this.getSortText(node),\n        node: node\n      });\n    }\n\n    // Set programme nodes in correct order\n    sortedprogrammes = this.sortList(sortedprogrammes, sortasc);\n    for (const prog of sortedprogrammes)\n      this.programmescontainer.appendChild(prog.node);\n  }\n\n  toggleSpecializations(ev: Event | null, programmenode?: HTMLElement) {\n    if (ev && !(ev.target! as HTMLElement).closest(\".togglespecializations\"))\n      return;\n\n    if (ev)\n      ev.preventDefault();\n\n    const itemnode = programmenode ? programmenode : (ev?.target as HTMLElement).closest<HTMLElement>(\".studyfinder__programme\");\n    if (!itemnode)\n      return;\n\n    const isDetailView = this.programmescontainer.classList.contains(\"pagefilters__itemcontainer--detailview\");\n    if (!isDetailView) {\n      if (itemnode.classList.contains(\"expanded\")) { //remove specialization rows\n        while (itemnode.nextElementSibling?.classList.contains(\"studyfinder__programme--specialization\"))\n          itemnode.nextElementSibling.remove();\n\n        itemnode.classList.remove(\"expanded\");\n        return;\n      }\n\n      //Add specialization rows\n      const programme = this.myFilter.srcItems.find((_ : HTMLElement) => _.dataset.id === itemnode.dataset.id);\n      if( programme ) {\n        const specializations = this.getSpecializationRows(programme);\n\n        let afterNode = itemnode;\n        specializations.forEach(specialization => {\n          afterNode.after(specialization);\n          afterNode = specialization;\n        });\n      }\n\n      itemnode.classList.add(\"expanded\");\n\n      return;\n    }\n\n    toggleSpecializationsFoldout(itemnode);\n  }\n\n  getSpecializationRows(programme: HTMLElement) : Array<HTMLLIElement> {\n    let specializations: Array<{text: string | number; node: HTMLLIElement}> = [];\n    dompack.qSA(programme, \".studyfinder__programme--specialization\").forEach(specialization => {\n      const snode = this.buildRow(specialization, programme.dataset);\n      specializations.push({\n        text: this.sortcolumn ? this.getSortText(dompack.qS<HTMLElement>(snode, \".cell--\" + this.sortcolumn.dataset.name)) : \"\",\n        node: snode\n      });\n    });\n\n    if (this.sortcolumn) //if ordering is set, use this before appending nodes\n      specializations = this.sortList(specializations, this.sortcolumn.classList.contains(\"sort-asc\"));\n\n    return specializations.map(_ => _.node);\n  }\n\n  getSortText(node: HTMLElement | null): string | number {\n    if (!node)\n      return \"\";\n    if (node.dataset.sort)\n      return Number(node.dataset.sort);\n    return node.innerHTML.replace(/<\\/?[^>]+(>|$)/g, \"\").toUpperCase() + \" - \" + (node.parentNode as HTMLElement).dataset.idx;\n  }\n\n  sortList<T extends { text: string | number }>(list: T[], sortasc: boolean): T[] {\n    return [...list].sort((a: { text: string | number }, b: { text: string | number }) => {\n      if (typeof a.text === \"number\" && typeof b.text === \"number\")\n        return (a.text - b.text) * (sortasc ? 1 : -1);\n\n      return String(a.text).localeCompare(String(b.text)) * (sortasc ? 1 : -1);\n    });\n  }\n\n  buildRow(node: HTMLElement, dataset: DOMStringMap) : HTMLLIElement {\n    // The node from which we harvest content knows if this is an specialization\n    const isspecialization = node.classList.contains(\"studyfinder__programme--specialization\");\n    const cellnames = isspecialization ? this.tablecellnames_specialization : this.tablecellnames_programme;\n\n    const rownode = dompack.create(\"li\", { className: \"studyfinder__programme studyfinder__programme--list pagefilters__listview__item pagefilters__item\", \"dataset\": dataset });\n\n    if (isspecialization)\n      rownode.classList.add(\"studyfinder__programme--specialization\");\n    else\n      rownode.classList.add(\"studyfinder__programme--mainprogramme\");\n\n    const linknode = node.closest(\".studyfinder__programme__link\") as HTMLAnchorElement;\n    if (linknode) {\n      rownode.setAttribute(\"data-link\", linknode.href);\n\n      rownode.addEventListener(\"click\", ev => {\n        if (dataset.specializations && (ev.target as HTMLElement).closest(\".togglespecializations\"))\n          return;\n\n        ev.preventDefault();\n        navigateTo(rownode.dataset.link!);\n      });\n    }\n\n    for (let i = 0; i < cellnames.length; ++i) {\n      const currentcellname = cellnames[i];\n\n      const cellnode = dompack.create(\"div\", { className: \"cell--\" + currentcellname });\n\n      const fieldnode = dompack.qS(node, \".\" + currentcellname);\n      if (fieldnode) {\n        if (fieldnode.dataset.sort)\n          cellnode.setAttribute(\"data-sort\", fieldnode.dataset.sort);\n\n        cellnode.appendChild(fieldnode.cloneNode(true));\n      } else if (currentcellname === \"specializations\" || currentcellname === \"duration\")\n        cellnode.setAttribute(\"data-sort\", \"0\");\n\n      if (!fieldnode)\n        cellnode.appendChild(dompack.create(\"span\", { textContent: \"\\u00A0\" }));//IE fix (IE doesn't like empty tablecells)\n\n      if (currentcellname === \"specializations\" && fieldnode)\n        cellnode.classList.add(\"togglespecializations\");\n\n      rownode.appendChild(cellnode);\n    }\n\n    return rownode;\n  }\n}\n\ndompack.register(\".studyfinderprogrammes:not(.pagefilters__itemcontainer)\", programmescontainer => {\n  // Only used outside of pagefilters in widgets\n  programmescontainer.addEventListener(\"click\", ev => {\n    if (ev && !(ev.target! as HTMLElement).closest(\".togglespecializations\"))\n      return;\n    ev.preventDefault();\n    const itemnode = (ev?.target as HTMLElement).closest<HTMLElement>(\".studyfinder__programme\");\n    if( itemnode )\n      toggleSpecializationsFoldout(itemnode);\n  });\n});\n\n/*\n  toggleSpecializationsFoldout is also used in studyfinder widget\n*/\nfunction toggleSpecializationsFoldout(itemnode: HTMLElement) {\n\n  const spnode = dompack.qS(itemnode,\".studyfinder__programme__specializations\");\n  if (!spnode)\n    return;\n\n  if (spnode.classList.contains(\"show\")) {\n    (spnode.parentNode! as HTMLElement).classList.remove(\"studyfinder__programme--specializationsvisible\");\n    spnode.style.height = spnode.clientHeight + \"px\";\n    spnode.classList.add(\"beforehide\");\n    void (spnode.clientWidth); //force css update\n    spnode.classList.remove(\"show\");\n    spnode.style.height = \"0px\";\n\n    setTimeout(() => { spnode.classList.remove(\"beforehide\"); spnode.hidden = true;}, 300);\n  } else {\n    spnode.hidden = false;\n    spnode.style.height = spnode.children[0].clientHeight + \"px\";\n    void (spnode.clientWidth); //force css update\n    spnode.classList.add(\"show\");\n    (spnode.parentNode! as HTMLElement).classList.add(\"studyfinder__programme--specializationsvisible\");\n    setTimeout(function () {\n      if (spnode.classList.contains(\"show\"))\n        spnode.style.height = \"auto\";\n    }, 300);\n  }\n}\n\nregisterCustomFilter(\"studyFinderFilter\", () => new studyFinderFilter());\n\ndompack.register(\".embeddedobject__studylist .summary__morebutton\", morebutton => {\n  const container = morebutton.closest(\".embeddedobject__studylist\") as HTMLElement;\n  const morebuttoncontainer = morebutton.parentElement as HTMLElement;\n  container.addEventListener(\"ws:foldable-status\", (ev: Event) => {\n    const foldableEvent = ev as CustomEvent<{ open: boolean }>;\n    if( !foldableEvent.detail.open ) { // Hide initially hidden items if foldable is closed\n      setTimeout(() => {\n        morebuttoncontainer.hidden = false;\n        dompack.qSA(container, \".summary__item--showing\").forEach(item => {\n          item.classList.remove(\"summary__item--showing\");\n          item.hidden = true;\n        });\n      },200); // Wait for foldable to close before showing morebutton and hide items\n    }\n  });\n\n  morebutton.addEventListener(\"click\", () => {\n    dompack.qSA(container, \".summary__item[hidden]\").forEach(item => {\n      item.classList.add(\"summary__item--showing\");\n      item.hidden = false;\n    });\n    morebuttoncontainer.hidden = true;\n  });\n});\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/webfeatures/studyfinder/studyfinder.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_education\",\"nl\",{\"site\":{\"studyfinder\":{\"js\":{\"degree\":\"Programme\",\"duration\":\"Duur\",\"language\":\"Taal\",\"specializations\":\"Specialisaties\",\"study\":\"Studie\",\"workload\":\"Werkdruk\"}}}});\nregisterTexts(\"utwente_education\",\"en\",{\"site\":{\"studyfinder\":{\"js\":{\"degree\":\"Programme\",\"duration\":\"Duration\",\"language\":\"Language\",\"specializations\":\"Specialisations\",\"study\":\"Study\",\"workload\":\"Workload\"}}}});\nregisterTexts(\"utwente_education\",\"de\",{\"site\":{\"studyfinder\":{\"js\":{\"degree\":\"Programme\",\"duration\":\"Dauer\",\"language\":\"Sprache\",\"specializations\":\"Spezialisierungen\",\"study\":\"Studie\",\"workload\":\"Arbeitsbelastung\"}}}});\nregisterTexts(\"utwente_education\",\"es\",{\"site\":{\"studyfinder\":{\"js\":{\"degree\":\"Programme\",\"duration\":\"Duration\",\"language\":\"Language\",\"specializations\":\"Specialisations\",\"study\":\"Study\",\"workload\":\"Workload\"}}}});\nregisterTexts(\"utwente_education\",\"it\",{\"site\":{\"studyfinder\":{\"js\":{\"degree\":\"Programme\",\"duration\":\"Duration\",\"language\":\"Language\",\"specializations\":\"Specialisations\",\"study\":\"Study\",\"workload\":\"Workload\"}}}});\nregisterTexts(\"utwente_education\",\"xt\",{\"site\":{\"studyfinder\":{\"js\":{\"degree\":\"Programme\",\"duration\":\"Duration\",\"language\":\"Language\",\"specializations\":\"Specialisations\",\"study\":\"Study\",\"workload\":\"Workload\"}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n","/* used by ws2026 */\nimport \"./scholarshipfinder.scss\";\nimport * as dompack from \"@webhare/dompack\";\n\n/*\n  Show intial scholarshipfinder results with a small delay\n*/\ndompack.register(\".scholarshipfinder__items\", node => {\n  setTimeout(() => {\n    node.classList.add(\"scholarshipfinder--show\");\n  }, 200);\n});\n","import * as dompack from '@webhare/dompack';\nimport \"./transfer.scss\";\nimport \"./studyroute.scss\";\n//@ts-expect-error -- FIXME legacy rpc jsoons\nimport services from \"../../shared/services.rpc.json?proxy\";\nimport * as widgets from \"@mod-utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects\";\nimport \"./transfer.lang.json\";\nimport { getTid, getHTMLTid } from \"@mod-tollium/js/gettid\";\nimport cPIR from \"@mod-utwente_base/webdesigns/ws2016/src/shared/peopleimages\";\nimport { SlimSelect } from \"@mod-utwente_design\";\n\nclass transferWidget {\n  node: HTMLElement;\n  targetprogramme: string | undefined;\n  language = document.documentElement.lang.split(\"-\")[0];\n  baseurl: string;\n  instituteselector: HTMLSelectElement | null;\n  programmeselectors: HTMLSelectElement[];\n  resultscontainer;\n  istransferfrom: boolean;\n  activeprogrammes: HTMLSelectElement | null = null;\n  institute = \"\";\n  pir = new cPIR();//get people images\n\n  constructor(node: HTMLElement) {\n    this.node = node;\n    this.targetprogramme = this.node.dataset.targetprogramme;\n    if (!this.targetprogramme)\n      this.targetprogramme = \"\";\n\n    this.baseurl = window.location.href.split('?')[0];\n\n    this.instituteselector = dompack.qS<HTMLSelectElement>(this.node, \"select[name='edutype']\");\n    this.programmeselectors = [...this.node.querySelectorAll<HTMLSelectElement>(\"select[name|='programme']\")];\n    this.resultscontainer = dompack.qR(this.node, \".embeddedobject__transfer__results\");\n\n    this.istransferfrom = this.node.classList.contains(\"embeddedobject__transfer--from\");\n\n    const institute = this.getUrlParam(\"edutype\");\n    if (this.instituteselector) {\n      if (institute && this.instituteselector.querySelector(\"option[value='\" + institute + \"']\")) {\n        this.institute = institute;\n        if (this.instituteselector.utSlimSelect)\n          this.instituteselector.utSlimSelect.setSelected(institute);\n        else\n          this.instituteselector.value = institute; //TODO why didn't this work for slimselect too?\n\n        this.onOrgChange(this.getUrlParam(\"programme\") || '');\n      }\n\n      this.instituteselector.addEventListener(\"change\", ev => this.onOrgChange());\n    } else {\n      this.institute = this.node.dataset.edutype || '';\n\n      if (!this.programmeselectors.length && this.node.dataset.programme)\n        void this.loadResults(this.institute, this.node.dataset.programme);\n    }\n\n    for (const selnode of this.programmeselectors)\n      selnode.addEventListener(\"change\", ev => this.onProgChange(selnode));\n  }\n\n  onProgChange(node: HTMLSelectElement) {\n    this.setUrlParam();\n    if (this.institute && node.value)\n      void this.loadResults(this.institute, node.value);\n  }\n\n  async loadResults(institute: string, programme: string) {\n    const busylock = dompack.flagUIBusy({ modal: false });\n    this.node.classList.add(\"loading\");\n\n    const opt = {\n      targetprogramme: this.istransferfrom ? this.targetprogramme : \"\",\n      language: this.language\n    };\n\n    //let selprogrammetitle = this.activeprogrammes ? this.activeprogrammes.options[this.activeprogrammes.selectedIndex].textContent : \"\";\n\n    const result = await services.GetStudyRoutes(institute, programme, opt);\n\n    this.node.classList.remove(\"loading\");\n    busylock.release();\n\n    this.resultscontainer.replaceChildren();\n    if (result && result.routes) {\n      this.node.classList.add(\"hasresults\");\n      this.showRoutes(result.routes);\n    } else if (result && !result.routes) {\n      this.node.classList.remove(\"hasresults\");\n      this.resultscontainer.appendChild(\n        <div class=\"noresults\">\n          <div class=\"studyroute__route-desc\">\n            <b>{this.setHtmlContent(getHTMLTid('utwente_education:site.transferwidget.js.noroutes'))}</b>\n          </div>\n        </div>);\n    } else {\n      this.node.classList.remove(\"hasresults\");\n      this.resultscontainer.appendChild(\n        <div class=\"noresults\">\n          <div class=\"studyroute__route-header\">\n            <div class=\"studyroute__route-icon\" data-icon=\"no-results\"></div>\n            {this.setHtmlContent(getTid('utwente_education:site.transferwidget.js.noresults_title'))}\n          </div>\n          <div class=\"studyroute__route-desc\">\n            {this.setHtmlContent(result?.destination_title ? getHTMLTid('utwente_education:site.transferwidget.js.noresults_this', result.destination_title)\n              : getHTMLTid('utwente_education:site.transferwidget.js.noresults'))}\n          </div>\n        </div>);\n    }\n  }\n\n  setHtmlContent(content: string, className?: string) {\n    if (!content)\n      return null;\n    const node = <div />;\n    node.innerHTML = content;\n    if (className)\n      node.className = className;\n    return node;\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- FIXME\n  showRoutes(routes: any[]) {\n    for (let c = 0; c < routes.length; ++c) {\n      if (routes[c].programmes.length === 1 && routes[c].programmes[0].destination_programmeid === this.targetprogramme)\n        routes[c].programmes = [];//Don't show programme if one and is targetprogramme\n\n      const node = <div class=\"studyroute__route\">\n        <div class=\"studyroute__route-header\">\n          <div class=\"studyroute__route-icon\" data-icon={routes[c].icon}></div>\n          {this.setHtmlContent(routes[c].title + (this.istransferfrom ? '' : '<span class=\"studyroute__route-count\">(' + routes[c].programmes.length + ')</span>'))}\n        </div>\n        <div class=\"studyroute__route-desc\">{this.setHtmlContent(routes[c].description)}</div>\n        {routes[c].conditions\n          ? <div class=\"studyroute__route__conditions\">{this.setHtmlContent(routes[c].conditions)}</div>\n          : null\n        }\n\n        {routes[c].studyadvisor\n          ? this.setHtmlContent(routes[c].studyadvisor)\n          : null\n        }\n        {routes[c].show_ec && routes[c].programmes.length\n          ? <div class=\"studyroute__route-header-ec\">EC</div>\n          : null\n        }\n        {// eslint-disable-next-line @typescript-eslint/no-explicit-any -- FIXME\n          routes[c].programmes.map((item: any) =>\n            <div class=\"studyroute__route-programme foldableprog\">\n              <div class=\"foldableprog__title\">\n                <div class=\"studyroute__route-icon\" data-icon={item.icon} data-ec={item.deficiencycredits}></div>\n                <div class=\"studyroute__route-title\">{item.title}</div>\n                {routes[c].show_ec\n                  ? <div class=\"studyroute__route-ec\">{item.deficiencycredits}</div>\n                  : null\n                }\n              </div>\n              <div class=\"foldableprog__foldcontainer\">\n                <div class=\"foldableprog__text\">\n                  <div class=\"studyroute__route-intro\">\n                    {item.imagelink\n                      ? <div class=\"studyroute__route-intro__image\"><img src={item.imagelink} alt=\"\" /></div>\n                      : null\n                    }\n                    <div class=\"studyroute__route-intro__text\">\n                      {this.setHtmlContent(item.description)}\n                      {this.setHtmlContent(item.conditions, \"studyroute__route__conditions\")}\n\n                      {this.istransferfrom && item.link && !item.ishbo\n                        ? <a class=\"studyroute__route-link\" href={item.link}>{getTid('utwente_education:site.transferwidget.js.gotomaster')}</a>\n                        : null\n                      }\n                    </div>\n                  </div>\n\n                  {item.studyadvisor\n                    ? this.setHtmlContent(item.studyadvisor)\n                    : null\n                  }\n\n                </div>\n              </div>\n            </div>\n          )}\n      </div>;\n\n      this.resultscontainer.appendChild(node);\n    }\n\n    widgets.initFoldableContent(\"foldableprog\");\n  }\n\n  onOrgChange(setProgramme?: string) {\n    this.institute = this.instituteselector ? this.instituteselector.value : \"\";\n\n    this.activeprogrammes = this.node.querySelector<HTMLSelectElement>(\"select[name='programme-\" + this.institute + \"']\");\n    for (const node of this.programmeselectors) {\n      if (node === this.activeprogrammes || (!this.activeprogrammes && node.name === \"programme\")) {\n        node.classList.add(\"active\");\n        if (setProgramme) {\n          let opt = node.querySelector<HTMLOptionElement>(\"option[value='\" + setProgramme + \"']\");\n          if (!opt) //then try crohocode\n            opt = node.querySelector(\"option[data-crohocode*='_\" + setProgramme + \"_']\");\n\n          if (opt)\n            if (node?.utSlimSelect)\n              node.utSlimSelect.setSelected(opt.value);\n            else\n              node.value = opt.value;\n        }\n      } else\n        node.classList.remove(\"active\");\n    }\n\n    if (this.activeprogrammes && this.activeprogrammes.value)\n      this.onProgChange(this.activeprogrammes);\n    else\n      this.setUrlParam();\n  }\n\n  setUrlParam() {\n    const url = new URL(this.baseurl);\n    if (this.institute)\n      url.searchParams.set(\"edutype\", this.institute);\n\n    if (this.activeprogrammes && this.activeprogrammes.value)\n      url.searchParams.set(\"programme\", this.activeprogrammes.value);\n\n    history.replaceState(undefined, \"\", url.toString());\n  }\n\n  getUrlParam(name: string) {\n    return new URL(location.href).searchParams.get(name);\n  }\n}\n\ndompack.register(\".embeddedobject__transfer\", node => new transferWidget(node));\n\ndompack.register<HTMLFormElement>(\".widget-studyrouteslist\", form => {\n  const program = dompack.qR<HTMLSelectElement>(form, \"select[name=program]\");\n  const filtersource = dompack.qR<HTMLSelectElement>(form, \"select[name=filtersource]\");\n\n  form.addEventListener(\"submit\", ev => {\n    ev.preventDefault();\n    const dlurl = new URL(program.value || \"\", location.href);\n    dlurl.searchParams.set(\"filtersource\", filtersource.value || \"\");\n    location.href = dlurl.toString();\n  });\n\n  new SlimSelect({\n    select: program,\n    settings: {\n      modal: 'off' // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n    }\n  });\n  new SlimSelect({\n    select: filtersource,\n    settings: {\n      modal: 'off' // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n    }\n  });\n});\n","const { createService } = require(\"@mod-system/js/wh/rpc.ts\"); export default createService(\"utwente_education:service\");","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"@webhare/dompack\";\n//import * as consenthandler from '@mod-publisher/js/analytics/consenthandler';\n\n\n/*\n   Note: imports of scss files are moved to widgets/index.ts to prevent them from being included in the ws2026 build using exported functions below.\n   export functions are used by:\n   mod::utwente_education/webfeatures/widgets/transfer/index.tsx which is also used in ws2026\n   mod::utwente_base/webdesigns/ws2016/src/shared/deeplinks.tsx which is also used in ws2026\n*/\n\nfunction initWideImage() {\n  window.addEventListener(\"resize\", checkWideImage);\n  checkWideImage();\n}\n\nfunction checkWideImage() { //replace wide image with large (desktop) version if window > 640\n  if (window.innerWidth <= 640)\n    return;\n\n  const wideimages = document.querySelectorAll(\".embeddedobject.imageblock > img[data-wide]\");\n  let imgcount = wideimages.length;\n  for (const node of wideimages) {\n    const widelink = node.getAttribute(\"data-wide\");\n    if (widelink)\n      node.src = widelink;\n    node.removeAttribute(\"data-wide\");\n    imgcount--;\n  }\n  if (imgcount <= 0)\n    window.removeEventListener(\"resize\", checkWideImage);\n}\n\nlet dragging = 0;\nconst dragThreshold = 3;\n\n\n/*\nUsed CSS classes:\n- --disabled\n- --open                  - the foldable content is expanded (not collapsed)\n- __foldcontainer--active - means it's being animated\n*/\n\nexport function openFoldableContent(node, className = \"foldablecontent\") {\n  node.classList.add(className + \"--open\");\n\n  // we are forced to do this because we have custom classnames for all foldable content\n  const foldcontainernode = node.querySelector(\".\" + className + \"__foldcontainer\");\n  foldcontainernode.style.height = \"auto\";\n  foldcontainernode.style.overflow = \"inherit\";\n}\n\nexport function initFoldableContent(className = \"foldablecontent\") {\n  // Nodes having a \"--active\" class are already initialized\n  for (const node of document.querySelectorAll(\".\" + className + \":not(.\" + className + \"--active)\")) {\n    node.classList.add(className + \"--active\");\n    // titlenode = the node that toggles the foldable content\n    const titlenode = node.querySelector(\".\" + className + \"__title\");\n    // foldcontainernode = the node that is resized when opening/closing\n    const foldcontainernode = node.querySelector(\".\" + className + \"__foldcontainer\");\n    // textnode = the node that holds the actual content\n    const textnode = node.querySelector(\".\" + className + \"__text\");\n\n    if (!foldcontainernode) {\n      console.warn(\"No expandable content for\", node);\n      continue;\n    }\n\n    const setHandler = event => {\n      //console.log(\"setHandler\", event, node.classList);\n\n      if (event.detail.open) {\n        openFoldableContent(node, className);\n      } else {\n        node.classList.remove(className + \"--open\");\n        foldcontainernode.style.height = \"\";\n      }\n    };\n\n\n    const toggleHandler = event => {\n      //console.log(\"toggleHandler\", event, node.classList);\n\n      if (event.type == \"touchend\")\n        event.preventDefault(); // Don't fire click event as well\n      if (dragging >= dragThreshold)\n        return;\n      if (node.classList.contains(className + \"--disabled\"))\n        return;\n\n      // Toggle the open state\n      if (node.classList.toggle(className + \"--open\")) {\n        // Explicitly set height to zero\n        foldcontainernode.style.height = 0;\n\n        // Activate transition\n        foldcontainernode.classList.add(className + \"__foldcontainer--active\");\n\n        // Set height to content height to start the transition\n        foldcontainernode.style.height = textnode.getBoundingClientRect().height + \"px\";\n      } else {\n        // set overflow to css value (overflow=hidden)\n        foldcontainernode.style.overflow = \"\";\n\n        // Explicitly set height to current height\n        foldcontainernode.style.height = textnode.getBoundingClientRect().height + \"px\";\n        foldcontainernode._wsTmpHeight = getComputedStyle(foldcontainernode).height;\n\n        // Activate transition\n        foldcontainernode.classList.add(className + \"__foldcontainer--active\");\n\n        // Set height to 0 to start the transition\n        foldcontainernode.style.height = \"0\";\n      }\n\n      dompack.dispatchCustomEvent(node, \"ws:foldable-status\",\n        {\n          bubbles: true,\n          cancelable: false,\n          detail: { open: node.classList.contains(className + \"--open\") }\n        });\n    };\n\n    titlenode.addEventListener(\"click\", toggleHandler);\n    node.addEventListener(\"ws:foldable-toggle\", toggleHandler);\n    node.addEventListener(\"ws:foldable-set\", setHandler);\n\n    // Use touch events for mobile, because the first click only activates the hover effect\n    // Only activate toggle and prevent default when a certain number of move events have occurred\n    titlenode.addEventListener(\"touchstart\", () => dragging = 0, { passive: true });\n    titlenode.addEventListener(\"touchmove\", () => ++dragging, { passive: true });\n    titlenode.addEventListener(\"touchend\", toggleHandler);\n\n    foldcontainernode.addEventListener(\"transitionend\", event => {\n      if (event.currentTarget == event.target) {\n        // Deactivate the transition\n        foldcontainernode.classList.remove(className + \"__foldcontainer--active\");\n\n        // reset height and overflow back to what the stylesheet defines\n        //foldcontainernode.style.height = \"\";\n        //foldcontainernode.style.overflow = \"\";\n\n        // Set height to 'auto' when open (natural content height) or clear when closed (css default)\n        // and disable overflow so hover effects on items inside container can get outside container\n        if (node.classList.contains(className + \"--open\")) {\n          // we are forced to do this because we have custom classnames for all foldable content\n          foldcontainernode.style.height = \"auto\";\n          foldcontainernode.style.overflow = \"inherit\";\n        } else {\n          foldcontainernode.style.height = \"\";\n        }\n      }\n    });\n  }\n}\n\n\nfunction toggleStudyFinderSpecializations(ev) {\n  if (ev && !ev.target.closest(\".togglespecializations\"))\n    return;\n\n  if (ev)\n    ev.preventDefault();\n\n  const itemnode = ev.target.closest(\".studyfinder__programme\");\n  if (!itemnode)\n    return;\n\n  const spnode = itemnode.querySelector(\".programme_specializations\");\n  if (!spnode)\n    return;\n\n  if (spnode.classList.contains(\"show\")) {\n    spnode.style.height = spnode.clientHeight + \"px\";\n    void (spnode.clientWidth); //force css update\n    spnode.classList.remove(\"show\");\n    spnode.style.height = \"0px\";\n  } else {\n    spnode.style.height = spnode.children[0].clientHeight + \"px\";\n    void (spnode.clientWidth); //force css update\n    spnode.classList.add(\"show\");\n    setTimeout(function () {\n      if (spnode.classList.contains(\"show\"))\n        spnode.style.height = \"auto\";\n    }, 300);\n  }\n}\n\n\n\nfunction activateStudyfinderWidget(widgetnode) {\n  console.info(\"Initializing StudyFinder widget\", widgetnode);\n\n  // Studyfinder widget 'show all' button\n  const showallnode = widgetnode.querySelector(\".sfwidget__showall\");\n  if (showallnode)\n    showallnode.addEventListener(\"click\", evt => expandStudyfinderWidget(evt));\n\n  widgetnode.addEventListener(\"click\", toggleStudyFinderSpecializations);\n}\n\nfunction expandStudyfinderWidget(evt) {\n  console.log(dompack);\n  const widget = evt.target.closest(\".embeddedobject\");\n  widget.classList.add(\"sfwidget--expand\");\n}\n\ndompack.register(\".embeddedobject__studyfinder\", node => activateStudyfinderWidget(node));\n\n//cleanup empty paragraph between embedded objects\ndompack.register(\".embeddedobject\", node => {\n  const prevnode = node.previousElementSibling;\n  if (prevnode\n    && (prevnode.nodeName == \"P\"\n      || prevnode.nodeName == \"H2\"\n      || prevnode.nodeName == \"H3\"\n      || prevnode.nodeName == \"H4\")\n    && (prevnode.innerHTML == \"\"\n      || prevnode.innerHTML == \"<br>\")) { //empty paragraph or heading\n    //now check if element is between embedded objects\n    const prevembobjectnode = prevnode.previousElementSibling;\n    if (prevembobjectnode && prevembobjectnode.classList.contains(\"embeddedobject\"))\n      node.parentElement.removeChild(prevnode);//delete empty paragraph\n  }\n});\n\n\n//ADDME: Rewrite to dompack.register?\ndompack.onDomReady(function () {\n  initWideImage();\n});\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/webfeatures/widgets/transfer/transfer.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_education\",\"nl\",{\"site\":{\"transferwidget\":{\"js\":{\"gotomaster\":\"Ga naar deze masteropleiding\",\"gotopremaster\":\"Lees meer over het pre-masterprogramma\",\"noresults\":[\"Er zijn bij ons geen mogelijkheden bekend om met jouw vooropleiding door te stromen naar een masteropleiding aan de UT. Denk je dat je met jouw bachelor toch toegelaten kunt worden tot een bepaalde master? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/onderwijs/student-services/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Neem dan contact op.\"}],\"noresults_this\":[\"Er zijn bij ons geen mogelijkheden bekend om met jouw vooropleiding door te stromen naar de master \",1,\" aan de UT. Denk je dat je met jouw bachelor toch toegelaten kunt worden? \",{\"t\":\"a\",\"link\":\" https://www.utwente.nl/onderwijs/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Neem dan contact op.\"}],\"noresults_title\":\"Geen doorstroommogelijkheden gevonden\",\"noroutes\":[\"Voor deze opleiding is er op dit moment geen doorstroominformatie bekend. Voor vragen kun je altijd \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/onderwijs/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"contact\"},\" met ons opnemen.\"]}}}});\nregisterTexts(\"utwente_education\",\"en\",{\"site\":{\"transferwidget\":{\"js\":{\"gotomaster\":\"Go to this master\",\"gotopremaster\":\"Read more about the pre-masters’s programme\",\"noresults\":[\"With your previous education, there are no transfer possibilities to UT master’s that we are aware of. Do you think your bachelor’s might still be sufficiently related to one of our master’s or do you have questions about your eligibility? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/student-services/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_this\":[\"We are not aware of any transfer possibilities to the Master’s in \",1,\" at UT with your current programme. Do you think your bachelor’s might still be sufficiently related? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_title\":\"No transfer options found\",\"noroutes\":[\"No transfer information is currently available for this study programme. For questions, you can \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"contact us\"},\".\"]}}}});\nregisterTexts(\"utwente_education\",\"de\",{\"site\":{\"transferwidget\":{\"js\":{\"gotomaster\":\"Go to this master\",\"gotopremaster\":\"Read more about the pre-master's programme\",\"noresults_this\":[\"We are not aware of any transfer possibilities to the Master’s in \",1,\" at UT with your current programme. Do you think your bachelor’s might still be sufficiently related? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_title\":\"No transfer options found\",\"noroutes\":[\"Für diesen Studiengang gibt es derzeit keine Informationen zum Transfer. Du kannst uns jederzeit \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"kontaktieren\"},\".\"],\"noresults\":[\"With your previous education, there are no transfer possibilities to UT master’s that we are aware of. Do you think your bachelor’s might still be sufficiently related to one of our master’s or do you have questions about your eligibility? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/student-services/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}]}}}});\nregisterTexts(\"utwente_education\",\"es\",{\"site\":{\"transferwidget\":{\"js\":{\"gotomaster\":\"Go to this master\",\"gotopremaster\":\"Read more about the pre-masters’s programme\",\"noresults\":[\"With your previous education, there are no transfer possibilities to UT master’s that we are aware of. Do you think your bachelor’s might still be sufficiently related to one of our master’s or do you have questions about your eligibility? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/student-services/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_this\":[\"We are not aware of any transfer possibilities to the Master’s in \",1,\" at UT with your current programme. Do you think your bachelor’s might still be sufficiently related? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_title\":\"No transfer options found\",\"noroutes\":[\"No transfer information is currently available for this study programme. For questions, you can \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"contact us\"},\".\"]}}}});\nregisterTexts(\"utwente_education\",\"it\",{\"site\":{\"transferwidget\":{\"js\":{\"gotomaster\":\"Go to this master\",\"gotopremaster\":\"Read more about the pre-masters’s programme\",\"noresults\":[\"With your previous education, there are no transfer possibilities to UT master’s that we are aware of. Do you think your bachelor’s might still be sufficiently related to one of our master’s or do you have questions about your eligibility? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/student-services/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_this\":[\"We are not aware of any transfer possibilities to the Master’s in \",1,\" at UT with your current programme. Do you think your bachelor’s might still be sufficiently related? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_title\":\"No transfer options found\",\"noroutes\":[\"No transfer information is currently available for this study programme. For questions, you can \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"contact us\"},\".\"]}}}});\nregisterTexts(\"utwente_education\",\"xt\",{\"site\":{\"transferwidget\":{\"js\":{\"gotomaster\":\"Go to this master\",\"gotopremaster\":\"Read more about the pre-masters’s programme\",\"noresults\":[\"With your previous education, there are no transfer possibilities to UT master’s that we are aware of. Do you think your bachelor’s might still be sufficiently related to one of our master’s or do you have questions about your eligibility? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/student-services/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_this\":[\"We are not aware of any transfer possibilities to the Master’s in \",1,\" at UT with your current programme. Do you think your bachelor’s might still be sufficiently related? \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"Contact us!\"}],\"noresults_title\":\"No transfer options found\",\"noroutes\":[\"No transfer information is currently available for this study programme. For questions, you can \",{\"t\":\"a\",\"link\":\"https://www.utwente.nl/en/education/master/contact/\",\"linkparam\":0,\"target\":\"\",\"subs\":\"contact us\"},\".\"]}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/language/default.xml\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport service from \"./pirservice.rpc.json?proxy\";\n\n// People Image Replacement\nexport default class cPIR {\n  constructor() {\n    this.images = [];\n\n    this.matchstr = \"/people-placeholder.png#replace=\";\n\n    this.parseFromImageElements();\n    this.parseFromInlineCss();\n\n    const imagekeys = [];\n    for (let i = 0; i < this.images.length; ++i) {\n      let key = this.images[i].url1.split(\"#replace=\")[1];\n      if (imagekeys.indexOf(key) == -1)\n        imagekeys.push(key);\n\n      if (this.images[i].url2) {\n        key = this.images[i].url2.split(\"#replace=\")[1];\n        if (imagekeys.indexOf(key) == -1)\n          imagekeys.push(key);\n      }\n    }\n\n    if (imagekeys.length)\n      this.getReplacements(imagekeys);\n  }\n\n  getLinkFromResults(oldurl) {\n    if (!this.results)\n      return;\n\n    const key = oldurl.split(\"#replace=\")[1];\n    for (let i = 0; i < this.results.images.length; ++i) {\n      if (key == this.results.images[i].key)\n        return this.results.images[i].url;\n    }\n    return \"\";\n  }\n\n  async getReplacements(imagekeys) {\n    this.results = await service.getPIR(imagekeys);\n\n    if (this.results && this.results.success)\n      this.setReplacements();\n  }\n\n  setReplacements() {\n    for (let i = 0; i < this.images.length; ++i) {\n      const url1 = this.getLinkFromResults(this.images[i].url1);\n      if (!url1)\n        continue;\n\n      if (this.images[i].node) {\n        let url2;\n        if (this.images[i].node.srcset)\n          url2 = this.getLinkFromResults(this.images[i].url2);\n\n        this.images[i].node.src = url1;\n        if (this.images[i].node.srcset)\n          this.images[i].node.srcset = url1 + \" 1x,\" + url2 + \" 2x\";\n      } else if (this.images[i].style) {\n        this.images[i].style.backgroundImage = \"url('\" + url1 + \"')\";\n        if (this.images[i].selector) { //remove class indicating use of placeholder (used in embeddedobject personinfo)\n          for (const node of document.querySelectorAll(\".haspeopleplaceholder \" + this.images[i].selector))\n            node.closest(\".haspeopleplaceholder\").classList.remove(\"haspeopleplaceholder\");\n        }\n      }\n    }\n  }\n\n  parseFromImageElements() {\n    for (const node of document.querySelectorAll(\"img[src*='\" + this.matchstr + \"']\")) {\n      let url1, url2;\n      if (node.srcset) {\n        const parts = node.srcset.split(\",\");\n        for (let i = 0; i < parts.length; ++i) {\n          const part = parts[i].trim();\n          if (part.indexOf(this.matchstr) > -1) {\n            if (part.indexOf(\" 2x\") > -1)\n              url2 = part.split(\" \")[0];\n            else\n              url1 = part.split(\" \")[0];\n          }\n        }\n      } else\n        url1 = node.src;\n\n      this.images.push({\n        \"node\": node,\n        \"url1\": url1,\n        \"url2\": url2,\n        \"style\": null\n      });\n    }\n  }\n\n  parseFromInlineCss() {\n    //check inline styleSheets\n    for (let i = 0; i < window.document.styleSheets.length; ++i) {\n      if (window.document.styleSheets[i].href)\n        continue;//Ignore external stylesheets\n\n      const rules = this.getAllCssRules(window.document.styleSheets[i]);\n      if (!rules)\n        continue;\n\n      const regexp = /(?:\\(['\"]?)(.*?)(?:['\"]?\\))/;\n\n      for (let c = 0; c < rules.length; ++c) {\n        if (rules[c].style.backgroundImage) {\n          const match = regexp.exec(rules[c].style.backgroundImage);\n          if (match && match[1].indexOf(this.matchstr) > -1) {\n            this.images.push({\n              \"node\": null,\n              \"url1\": match[1],\n              \"url2\": \"\",\n              \"style\": rules[c].style,\n              \"selector\": rules[c].selectorText\n            });\n          }\n        }\n      }\n    }\n  }\n\n  getAllCssRules(cssitem) {\n    let items = [];\n    const rules = cssitem.rules || cssitem.cssRules;\n    for (let c = rules.length - 1; rules && c >= 0; --c) {\n      if (rules[c].media) {\n        const mediarules = this.getAllCssRules(rules[c]);\n        if (mediarules)\n          items = items.concat(mediarules);\n      } else if (rules[c].style)\n        items.push(rules[c]);\n    }\n    return items;\n  }\n}\n\ndompack.onDomReady(() => {\n  new cPIR();\n});\n","const { createService } = require(\"@mod-system/js/wh/rpc.ts\"); export default createService(\"utwente_base:pirservice\");","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./programmedetails.scss\";\nimport * as dompack from \"dompack\";\n\nfunction programmeYearFilter(node) {\n  const container = dompack.closest(node, \".embeddedobject__programmedetails\");\n  const dateitems = container.querySelectorAll(\".line__description-text[data-year]\");\n\n  node.addEventListener(\"change\", ev => {\n    const val = node.value;\n    for (const item of dateitems)\n      item.style.display = !val || item.dataset.year === val ? \"\" : \"none\";\n  });\n}\n\ndompack.register(\".programmedetails__yearfilter select\", node => programmeYearFilter(node));\n","import * as dompack from \"@webhare/dompack\";\n\ndompack.register<HTMLButtonElement>(\".programmedetailsheader__items-button\", btn => {\n\n  let timer: NodeJS.Timeout | null;\n  const mediaTwoRows = window.matchMedia(\"(max-width: 900px)\");\n  const mediaMobile = window.matchMedia(\"(max-width: 450px)\");\n\n  const itemslist = dompack.qR(btn.parentNode as HTMLElement, \".programmedetailsheader__items\");\n\n  window.addEventListener(\"resize\", () => {\n    let hidebtn = false;\n    if (mediaMobile.matches) {\n      if (itemslist.children.length <= 2) // 2 rows / 1 column in collapsed mode\n        hidebtn = true;\n    } else if (itemslist.children.length <= 4) // 2 rows / 2 columns in collapsed mode\n      hidebtn = true;\n\n    btn.hidden = hidebtn;\n  });\n\n  let hidebtn = false;\n  if (mediaMobile.matches) {\n    if (itemslist.children.length <= 2) // 2 rows / 1 column in collapsed mode\n      hidebtn = true;\n  } else if (itemslist.children.length <= 4) // 2 rows / 2 columns in collapsed mode\n    hidebtn = true;\n\n  btn.hidden = hidebtn;\n\n  btn.addEventListener(\"click\", () => {\n    clearTimeout(timer!);\n    // Toggle the expanded state\n    if (itemslist.classList.contains(\"programmedetailsheader__items--expanded\")) {\n      itemslist.style.height = `${itemslist.clientHeight}px`;\n      let itemh = itemslist.children[0].clientHeight;\n      if (mediaMobile.matches) {\n        if (itemslist.children.length > 1) // 2 rows / 1 column\n          itemh += itemslist.children[1].clientHeight;\n      } else if (mediaTwoRows.matches && itemslist.children.length > 2) // 2 rows / 2 columns\n        itemh += itemslist.children[3].clientHeight;\n      itemslist.style.height = `${itemh}px`;\n      btn.setAttribute(\"aria-expanded\", \"false\");\n\n      timer = setTimeout(() => {\n        itemslist.style.height = \"\";\n        itemslist.classList.remove(\"programmedetailsheader__items--expanded\");\n        dompack.dispatchCustomEvent(itemslist, \"ws:programmedetailsheader-toggle\", { bubbles: true, cancelable: false });\n      }, 300);\n\n    } else {\n      itemslist.style.height = `${itemslist.clientHeight}px`;\n      itemslist.classList.add(\"programmedetailsheader__items--expanded\");\n      itemslist.style.height = `${itemslist.scrollHeight}px`;\n      btn.setAttribute(\"aria-expanded\", \"true\");\n\n      timer = setTimeout(() => {\n        itemslist.style.height = \"\";\n        dompack.dispatchCustomEvent(itemslist, \"ws:programmedetailsheader-toggle\", { bubbles: true, cancelable: false });\n      }, 300);\n    }\n  });\n});\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./relatedmasterprogrammes.scss\";\nimport * as dompack from \"dompack\";\n\ndompack.register(\".widget-relatedmasterprogrammes\", node => {\n\n  node.addEventListener(\"click\", ev => {\n    const morebtn = ev.target.closest(\".widget-relatedmasterprogrammes__more\");\n    if (morebtn) {\n      dompack.qSA(node, \".widget-relatedmasterprogrammes__programme--hidden\").forEach((item, i) => {\n        setTimeout(() => {\n          item.style.opacity = \"0\";\n          item.classList.remove(\"widget-relatedmasterprogrammes__programme--hidden\");\n          void (item.clientWidth);//force css update\n          item.style.opacity = \"1\";\n        }, 100 * i);\n\n        dompack.remove(morebtn);\n      });\n    }\n  });\n});\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./studyinnumbers.scss\";\nimport * as dompack from \"dompack\";\n\nclass studyInNumbers {\n  constructor(node) {\n    node.addEventListener(\"wh:visibilitychange\", ev => {\n      if (!ev.detail.visible)\n        return;\n\n      if (!ev.target.classList.contains(\"animate--started\")) {\n        ev.target.classList.add(\"animate--started\");\n        setTimeout(() => this.animate(ev.target), 200);\n      }\n    });\n    /*\n        Ps.initialize( dompack.qS(node, \".widget-studyinnumbers__scrollcontainer\")\n                     , { swipePropagation: false\n                       , wheelPropagation: false\n                       , suppressScrollX: true\n                       });\n    */\n  }\n\n  animate(container) {\n    const valuelabels = dompack.qSA(container, \".ratingchart__chart__value, .ratingchart__chart__countryvalue, .widget-studyinnumbers__percentagecircle > div, .widget-studyinnumbers__line__countryvalue\");\n    valuelabels.forEach(node => {\n      const endval = 1 * (node.dataset.percentage ? node.dataset.percentage : node.parentNode.dataset.percentage);\n      const t = Math.round(800 / endval);//animation steps over 800ms\n      setTimeout(() => this.setValue(node, endval, t), t);\n    });\n\n    dompack.qSA(container, \".ratingchart__chart__bars span[data-percentage]\").forEach(el => {\n      el.style.width = el.dataset.percentage + \"%\";\n    });\n\n    const contoursize = 214; // (circumference of circle in px)\n    dompack.qSA(container, \".widget-studyinnumbers__percentagecircle[data-percentage]\").forEach(node => {\n      if (node.dataset.percentage != \"0\")\n        node.querySelector(\"svg\").style.strokeDashoffset = Math.round(contoursize - (0.01 * node.dataset.percentage * contoursize));\n    });\n  }\n\n  setValue(el, endval, t) {\n    let val = 1 * el.textContent;\n    val += 1;\n    el.textContent = val;\n    if (val < endval)\n      setTimeout(() => this.setValue(el, endval, t), t);\n  }\n}\n\ndompack.register(\".widget-studyinnumbers\", node => new studyInNumbers(node));\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./cssstudies.scss\";\nimport * as dompack from \"dompack\";\n\nclass cssStudiesSorter {\n  constructor(node) {\n    this.node = node;\n    this.headnode = node.querySelector(\"thead\");\n    this.headnode.addEventListener(\"click\", ev => this.onSort(ev));\n\n    this.bodynode = node.querySelector(\"tbody\");\n  }\n\n  onSort(ev) {\n    const selcol = dompack.closest(ev.target, \"th\");\n    if (!selcol)\n      return;\n\n    for (const hnode of this.node.querySelectorAll(\"thead th\")) {\n      if (hnode === selcol) {\n        if (hnode.classList.contains(\"sort--down\")) {\n          hnode.classList.remove(\"sort--down\");\n          hnode.classList.add(\"sort--up\");\n        } else {\n          hnode.classList.remove(\"sort--up\");\n          hnode.classList.add(\"sort--down\");\n        }\n      } else {\n        hnode.classList.remove(\"sort--down\");\n        hnode.classList.remove(\"sort--up\");\n      }\n    }\n\n    this.sortTable(selcol);\n  }\n\n  sortTable(selcol) {\n    const colname = selcol.dataset.sort;\n\n    let group;\n    const groupedlines = [];\n    let previdx = -1;\n\n    for (const node of this.node.querySelectorAll(\"tbody > tr\")) {\n      const idx = parseInt(node.dataset.idx); //idx also groups lines\n      let sortval = idx;\n      if (colname !== \"title\") {\n        sortval = node.dataset[colname];\n        if (!sortval)\n          sortval = \"NODATE\";\n      }\n\n      if (idx !== previdx) {\n        if (group)\n          groupedlines.push(group);\n\n        group = {\n          idx: idx,\n          sortval: sortval,\n          lines: []\n        };\n      }\n      group.lines.push(node);\n\n      previdx = idx;\n    }\n    //And finaly add last item\n    groupedlines.push(group);\n\n    if (selcol.classList.contains(\"sort--up\"))\n      groupedlines.sort(this.doSortAsc);\n    else\n      groupedlines.sort(this.doSortDesc);\n\n    //Now rebuild table with sorted lines\n    for (let c = 0; c < groupedlines.length; ++c) {\n      for (let l = 0; l < groupedlines[c].lines.length; ++l) {\n        const row = groupedlines[c].lines[l];\n        if (c % 2)\n          row.classList.add(\"odd\");\n        else\n          row.classList.remove(\"odd\");\n\n        this.bodynode.appendChild(row);\n      }\n    }\n  }\n\n  doSortAsc(a, b) {\n    if (a.sortval > b.sortval)\n      return -1;\n    if (a.sortval < b.sortval)\n      return 1;\n\n    //If same then use idx\n    if (a.idx < b.idx)\n      return -1;\n    if (a.idx > b.idx)\n      return 1;\n\n    return 0;\n  }\n\n  doSortDesc(a, b) {\n    if (a.sortval < b.sortval)\n      return -1;\n    if (a.sortval > b.sortval)\n      return 1;\n\n    //If same then use idx\n    if (a.idx < b.idx)\n      return -1;\n    if (a.idx > b.idx)\n      return 1;\n\n    return 0;\n  }\n}\n\ndompack.register(\".embeddedobject__cssstudies\", node => new cssStudiesSorter(node));\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./specializations.scss\";\nimport * as dompack from \"dompack\";\n\nclass ellipsisFoldout {\n  constructor(node, textcontainer) {\n    this.node = node;\n    this.textcontainer = dompack.qS(this.node, \".embeddedobject__specializations__specialization__ellipsis\");\n\n    this.node.addEventListener(\"click\", ev => {\n      if (!this.node.classList.contains(\"hasellipsis\"))\n        return;\n\n      if (ev.target.closest(\".embeddedobject__specializations__specialization__ellipsistoggle\")) {\n        dompack.stop(ev);\n        this.toggle();\n      } else if (!this.node.classList.contains(\"hasellipsis--open\")) { //click on item with active ellipsis then show full text (else just follow link)\n        dompack.stop(ev);\n        this.open();\n      }\n    });\n\n    window.addEventListener(\"load\", () => this.checkEllipsis());\n    window.addEventListener(\"resize\", () => this.checkEllipsis());\n    document.fonts.ready.then(() => this.checkEllipsis());\n    this.checkEllipsis();\n  }\n\n  checkEllipsis() {\n    // To keep it simple, remove open state when resizing\n    clearTimeout(this.timer);\n    this.node.classList.remove(\"hasellipsis--open\");\n    this.textcontainer.style.maxHeight = \"\";\n\n    //Check for ellipsis\n    this.ellipsisy = this.textcontainer.clientHeight;\n    this.node.classList.toggle(\"hasellipsis\", this.textcontainer.scrollHeight > this.ellipsisy);\n  }\n\n  toggle() {\n    if (this.node.classList.contains(\"hasellipsis--open\"))\n      this.close();\n    else\n      this.open();\n  }\n\n  open() {\n    clearTimeout(this.timer);\n\n    this.textcontainer.style.maxHeight = this.textcontainer.clientHeight + \"px\";\n    this.node.classList.add(\"hasellipsis--open\");\n    this.textcontainer.style.maxHeight = this.textcontainer.scrollHeight + \"px\";\n\n    this.timer = setTimeout(() => this.textcontainer.style.maxHeight = \"\", 300);\n  }\n\n  close() {\n    clearTimeout(this.timer);\n    this.textcontainer.style.maxHeight = this.textcontainer.clientHeight + \"px\";\n    void (this.textcontainer.clientHeight);\n\n    this.textcontainer.style.maxHeight = this.ellipsisy + \"px\";\n\n    this.timer = setTimeout(() => {\n      this.textcontainer.style.maxHeight = \"\";\n      this.node.classList.remove(\"hasellipsis--open\");\n    }, 300);\n  }\n}\n\ndompack.register(\".embeddedobject__specializations__specialization\", node => new ellipsisFoldout(node));\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./vacancies.scss\";\nimport * as dompack from 'dompack';\nimport { relayoutWidgets } from '@mod-utwente_base/webfeatures/utwidgets/layout';\nimport service from \"./vacancies.rpc.json?proxy\";\n\nasync function getVacancies(node) {\n  const options = JSON.parse(node.dataset.options);\n  const res = await service.ZoekVacatures(options.vw);\n\n  if (res && res.vacancies.length) {\n    res.vacancies.map((item) => {\n      node.appendChild(<a href={item.link} class=\"widget__listitem widget__listitem--link\">\n        <span class=\"widget__listitem-text\">{item.title}</span>\n        <span class=\"widget__listitem-subtext\">{item.subtext}</span>\n        <i class=\"widget__listitem-icon widget__listitem-icon--small UT-icon-UT_icon_52_arrow-right-round-16px\"></i>\n      </a>);\n    });\n  } else\n    node.classList.add(\"novacancies\");\n\n  //Trigger ut masonry update\n  relayoutWidgets(node);\n}\n\ndompack.register(\".widget-vacancies__list--afas\", node => getVacancies(node));\n","const { createService } = require(\"@mod-system/js/wh/rpc.ts\"); export default createService(\"utwente_jobs:utvacatures\");","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport './vacancies.scss';\nimport './vacanciesoverview-filters.scss';\nimport './vacancywidget/index';\n\nimport * as dompack from 'dompack';\nimport * as filteredoverview from \"@mod-utwente_base/webdesigns/ws2016/src/filteredoverview\";\n\nclass VacancyOverviewFilter extends filteredoverview.ClientSideFilteredOverview {\n  constructor(options) {\n    super({ ...options, filterpagetype: 'vacancies', itemsselector: \".summary__item\" });\n\n    const vactypenode = this.form.querySelector(\"select[name='offerfamily']\");\n    if (vactypenode) {\n      this.branchenode = this.form.querySelector(\"select[name='offerprofile']\");\n      this.brancheoptions = [];\n      for (const node of this.branchenode.options)\n        this.brancheoptions.push({ value: node.value, title: node.textContent });\n\n      vactypenode.addEventListener(\"change\", ev => this.updateBrancheOptions(ev));\n      this.updateBrancheOptions({ target: vactypenode });\n    }\n\n    // FIXME: updating filters and freshing UI should be part of filteredoverview ?\n    this.updateFilters();\n    this.refreshFilterFeedbackUI();\n  }\n\n  updateBrancheOptions(ev) {\n    const seloption = ev.target.options[ev.target.selectedIndex];\n    const selectedbranchevalue = this.branchenode.value;\n    const branchids = seloption.dataset.branche ? \",\" + seloption.dataset.branche + \",\" : \"\";\n\n    this.branchenode.replaceChildren();\n\n    let selectedidx = -1;\n    for (let i = 0; i < this.brancheoptions.length; ++i) {\n      if (!seloption.dataset.branche || this.brancheoptions[i].value == \"\" || branchids.indexOf(\",\" + this.brancheoptions[i].value + \",\") != -1) {\n        if (selectedbranchevalue == this.brancheoptions[i].value)\n          selectedidx = i;\n        this.branchenode.appendChild(dompack.create(\"option\", {\n          value: this.brancheoptions[i].value,\n          textContent: this.brancheoptions[i].title,\n          selected: this.brancheoptions[i].value == selectedbranchevalue\n        }));\n      }\n    }\n\n    if (selectedidx > -1)\n      this.branchenode.value = selectedbranchevalue;\n  }\n\n  showResults() {\n    this.runFilterByDataTags();\n  }\n\n  isMatch(node) {\n    if (!super.isMatch(node))\n      return false;\n\n    const searchtext = this.form.elements.query.value;\n    if (searchtext\n      && !node.textContent.toUpperCase().includes(searchtext.toUpperCase())\n      && !node.dataset.plaintextsearch.toUpperCase().includes(searchtext.toUpperCase()))\n      return false;\n\n    return true;\n  }\n}\n\nfunction checkTagClick(event) {\n  const tag = event.target.closest(\".ut-vacancies__tag\");\n  if (!tag)\n    return;\n\n  dompack.stop(event);\n  //look for the tag in offerprofile\n  const matchoption = dompack.qSA(\"[name=offerprofile] option\").filter(opt => opt.textContent == tag.textContent)[0];\n  if (matchoption)\n    dompack.changeValue(dompack.qS(\"[name=offerprofile]\"), matchoption.value);\n}\n\ndompack.onDomReady(() => {\n  if (!document.documentElement.classList.contains(\"page--vacanciesoverview\"))\n    return;\n\n  window.addEventListener(\"click\", checkTagClick);\n  window.filteredoverview = new VacancyOverviewFilter(\n    { filterpagetype: \"vacancies\" });\n});\n","import * as dompack from \"@webhare/dompack\";\nimport \"./projectslist.scss\";\n\nclass ProjectsList {\n  listnode: HTMLElement;\n  feedbackbar: HTMLElement;\n\n  constructor(node: HTMLElement) {\n    this.listnode = dompack.qR(node, \".projectslist__items\")!;\n    this.feedbackbar = node.previousElementSibling as HTMLElement; // assumes feedbackbar is always (above) the results container\n\n    const listtoggle = dompack.qR(this.feedbackbar, \".projectslist-viewbar__viewmode__items\");\n    dompack.addDocEventListener(listtoggle, \"click\", ev => {\n      const togglenode = ev.target.closest(\"[data-viewmode]\") as HTMLElement | null;\n      if (!togglenode)\n        return;\n\n      if (togglenode.dataset.viewmode === \"detailview\" && this.feedbackbar.classList.contains(\"projectslist-viewbar--detailview\"))\n        return; // already in detailview\n\n      if (togglenode.dataset.viewmode !== \"detailview\" && !this.feedbackbar.classList.contains(\"projectslist-viewbar--detailview\"))\n        return; // already in listview\n\n      if (togglenode.dataset.viewmode === \"detailview\") {\n        this.feedbackbar.classList.remove(\"projectslist-viewbar--listview\");\n        this.feedbackbar.classList.add(\"projectslist-viewbar--detailview\");\n\n        this.listnode.classList.remove(\"projectslist__items--listview\");\n      } else {\n        this.feedbackbar.classList.add(\"projectslist-viewbar--listview\");\n        this.feedbackbar.classList.remove(\"projectslist-viewbar--detailview\");\n\n        this.listnode.classList.add(\"projectslist__items--listview\");\n      }\n    });\n  }\n}\n\ndompack.register(\".projectslist__results\", node => new ProjectsList(node));\n","//Adds autocomplete for VLS School and our organization database\nimport * as dompack from '@webhare/dompack';\n//@ts-ignore not documented yet\nimport leadsservice from './internal/leads.rpc.json?proxy';\nimport { getMatches } from './shared_search';\nimport { setupValidator, FormBase } from \"@mod-publisher/js/forms\";\n\nimport UTAutoComplete from '@mod-utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter';\nimport { TrigramMatcher } from '@mod-utwente_design';\n\ninterface FoundName {\n  title: string;\n  aliases: string[];\n}\n\nfunction getFlatList(list: FoundName[]) {\n  const names: string[] = [];\n  for (const entry of list)\n    names.push(entry.title, ...entry.aliases);\n  return names;\n}\n\nclass PreppedNameList {\n  prep;\n  //build a reverse alias->name list ... we're supposed to MATCH aliases in the trigram list but not SHOW them\n  aliasunmap = new Map<string, string>;\n\n  constructor(list: FoundName[]) {\n    const flatlist = getFlatList(list);\n    this.prep = new TrigramMatcher(flatlist);\n    for (const entry of list)\n      for (const alias of entry.aliases)\n        this.aliasunmap.set(alias, entry.title);\n  }\n\n  getMatches(searchterm: string): string[] {\n    const finallist: string[] = [];\n\n    /*\n        for (const suggestion of scoreStuff(this.prep, searchterm)\n          .sort((a, b) => (b.score - a.score))//highest score first\n          .map(_ => this.aliasunmap.get(_.str) || _.str)) { //remap to riginal nam\n          //because we remap, we might find the same name multiple times. only keep the first (highest score)\n          if (!finallist.includes(suggestion))\n            finallist.push(suggestion);\n        }\n    */\n    let scoredlist = this.prep.score(searchterm);\n\n    // Only show results which scored at least 66% of max score found\n    const minscore = scoredlist.length ? scoredlist[0].score * 0.66 : 0;\n\n    scoredlist = scoredlist.filter(_ => _.score > minscore);\n\n    for (const suggestion of scoredlist.map(_ => this.aliasunmap.get(_.str) || _.str)) {\n      //because we remap, we might find the same name multiple times. only keep the first (highest score)\n      if (!finallist.includes(suggestion))\n        finallist.push(suggestion);\n    }\n\n    return finallist;\n  }\n}\n\nclass Scope {\n  citylistpromise: Promise<string[]> | null = null;\n  cityprep: TrigramMatcher | null = null;\n  namelistpromises: Record<string, Promise<FoundName[]>> = {};\n  namelistprep: Record<string, PreppedNameList> = {};\n}\n\nconst scopes: Record<string, Scope> = {};\nconst lastsuggestions = new Map<HTMLInputElement, string[]>();\n\nfunction getScope(limittypes: string[]) {\n  let scopename = (limittypes.includes('school') ? 'school' : '');\n  if (!scopename)\n    scopename = 'all';\n\n  if (!scopes[scopename])\n    scopes[scopename] = new Scope;\n\n  return scopes[scopename];\n}\n\nasync function getCities(limittypes: string[], searchterm: string, groupname: string) {\n  const scope = getScope(limittypes);\n  if (searchterm.length <= 0)\n    return;\n\n  if (!scope.citylistpromise) {\n    //@ts-ignore leadsservice missing types\n    scope.citylistpromise = leadsservice.getOrgCities(limittypes);\n  }\n\n  if (searchterm.length <= 1) //we'll wait for you to type 2 chars, but at least we'll have the list!\n    return;\n\n  if (limittypes.length === 1 && limittypes[0] === 'school') {\n    if (!scope.cityprep)\n      scope.cityprep = new TrigramMatcher(await scope.citylistpromise!);\n\n    let scoredlist = scope.cityprep.score(searchterm);\n\n    // Only show results which scored at least 66% of max score found\n    const minscore = scoredlist.length ? scoredlist[0].score * 0.66 : 0;\n    scoredlist = scoredlist.filter(_ => _.score > minscore);\n\n    return scoredlist.map(_ => { return { label: _.str, value: _.str, group: groupname }; });\n  }\n\n  const suggestions = getMatches(await scope.citylistpromise!, searchterm);\n  return suggestions.map(_ => { return { label: _, value: _, group: groupname }; });\n}\n\nasync function getOrgNames(node: HTMLInputElement, limittypes: string[], cityfield: HTMLInputElement, searchterm: string, groupname: string) {\n  const scope = getScope(limittypes);\n  if (searchterm.length < 1 || !cityfield.value)\n    return;\n\n  const key = cityfield.value;\n  if (!scope.namelistpromises[key]) {\n    //@ts-ignore leadsservice missing types\n    scope.namelistpromises[key] = leadsservice.getOrgNames2(limittypes, cityfield.value);\n  }\n\n  if (limittypes.length === 1 && limittypes[0] === 'school') {\n    if (!scope.namelistprep[key])\n      scope.namelistprep[key] = new PreppedNameList(await scope.namelistpromises[key]);\n\n    const suggestions = scope.namelistprep[key].getMatches(searchterm);\n    lastsuggestions.set(node, suggestions);\n\n    return suggestions.map(_ => { return { label: _, value: _, group: groupname }; });\n  }\n\n  const suggestions = getMatches(getFlatList(await scope.namelistpromises[key]), searchterm);\n  return suggestions.map(_ => { return { label: _, value: _, group: groupname }; });\n}\n\nfunction setupSchoolCityField(node: HTMLInputElement) {\n  const limittypes = node.dataset.limittypes ? node.dataset.limittypes.split(' ') : [];\n  const groupname = node.matches(\":lang(nl)\") ? \"Bedoelde je:\" : \"Did you mean:\";\n\n  UTAutoComplete({\n    input: node,\n    className: 'ut-autocomplete',\n    preventSubmit: 1,\n    fetch: async function (text, update) {\n      const suggestions = await getCities(limittypes, text, groupname);\n      update(suggestions || []);\n    },\n    onSelect: function (item) {\n      node.value = item.label ?? \"\";\n    },\n  });\n}\n\nfunction validateSchoolName(field: HTMLInputElement) {\n  const suggestions = lastsuggestions.get(field);\n  ///@ts-ignore we're working around lack of suggestion support in the FormBase\n  field.propWhValidationSuggestion = null;\n\n  if (suggestions?.length && !suggestions.includes(field.value)) {\n    const text = field.matches(\":lang(nl)\") ? \"Bedoelde je\" : \"Did you mean\";\n    ///@ts-ignore we're working around lack of suggestion support in the FormBase\n    field.propWhValidationSuggestion = <span class=\"wh-form__emailcorrection\"> {text} <a href=\"#\" class=\"wh-form__emailcorrected\" on={{\n      pointerdown: (evt: Event) => {\n        field.value = suggestions[0];\n        ///@ts-ignore we're working around lack of suggestion support in the FormBase\n        field.propWhValidationSuggestion = null;\n        dompack.stop(evt);\n        ///@ts-ignore we're working around lack of suggestion support in the FormBase\n        FormBase.getForNode(field.closest(\"form\"))._reportFieldValidity(field);\n      }\n    }} > {suggestions[0]}</a> ? </span>;\n  }\n  return \"\";\n}\n\nfunction setupSchoolNameField(node: HTMLInputElement) {\n  //find our preceding schoolcity field\n  const limittypes = node.dataset.limittypes ? node.dataset.limittypes.split(' ') : [];\n  const relevantfields = dompack.qSA<HTMLInputElement>('.utvoorl--orgselectcity input, .utvoorl--orgselectname input');\n  const mypos = relevantfields.indexOf(node);\n  if (mypos > 0) {\n    const groupname = node.matches(\":lang(nl)\") ? \"Bedoelde je:\" : \"Did you mean:\";\n\n    UTAutoComplete({\n      input: node,\n      className: 'ut-autocomplete',\n      preventSubmit: 1,\n      fetch: async function (text, update) {\n        const suggestions = await getOrgNames(node, limittypes, relevantfields[mypos - 1], text, groupname);\n        update(suggestions || []);\n      },\n      onSelect: function (item) {\n        node.value = item.label ?? \"\";\n      },\n    });\n\n    setupValidator(node, validateSchoolName);\n  }\n}\n\ndompack.register('.utvoorl--orgselectcity input', setupSchoolCityField);\ndompack.register('.utvoorl--orgselectname input', setupSchoolNameField);\n","const { createService } = require(\"@mod-system/js/wh/rpc.ts\"); export default createService(\"utwente_voorlichting:leads\");","export function getMatches(results: string[], searchfor: string): string[] {\n  searchfor = searchfor.toUpperCase();\n  //get matches containing 'searchfor', and their position\n  let matches = results.map(text => ({ text, pos: text.toUpperCase().indexOf(searchfor) }));\n  //filter actual matches\n  matches = matches.filter(item => item.pos >= 0);\n  //sort by distance to start of string\n  matches = matches.sort((lhs, rhs) => lhs.pos < rhs.pos ? -1 : lhs.pos === rhs.pos ? 0 : 1);\n  //and return as text\n  return matches.map(item => item.text);\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n//Adds autocomplete for Institutes\nimport * as dompack from 'dompack';\nimport UTAutoComplete from '@mod-utwente_base/webdesigns/ws2016/src/components/autocompleter2/autocompleter';\n\nimport leadsservice from './internal/leads.rpc.json?proxy';\nimport { getMatches } from './shared_search';\n\nconst citylistpromises = {};\nconst institutelistpromises = {};\n\nasync function getInstitutes(countryfield, searchterm, groupname) {\n  if (searchterm.length <= 0 || !countryfield.value)\n    return;\n\n  const key = countryfield.value;\n  if (!citylistpromises[key])\n    citylistpromises[key] = leadsservice.listInstitutesForCountry(key);\n\n  if (searchterm.length <= 1) //we'll wait for you to type 2 chars, but at least we'll have the list!\n    return;\n\n  return getMatches(await citylistpromises[key], searchterm).slice(0, 5).map(_ => { return { label: _, value: _, group: groupname }; });\n}\n\nasync function getInstituteEducations(countryfield, institutefield, searchterm, groupname) {\n  if (searchterm.length < 1 || !countryfield.value || !institutefield.value)\n    return;\n\n  const key = countryfield.value + '.' + institutefield.value;\n  if (!institutelistpromises[key])\n    institutelistpromises[key] = leadsservice.listEducationsForInstitute(countryfield.value, institutefield.value);\n\n  const results = await institutelistpromises[key];\n\n  return getMatches(results, searchterm).slice(0, 5).map(_ => { return { label: _, value: _, group: groupname }; });\n}\n\nfunction getPrevious(node) {\n  const relevantfields = dompack.qSA('.utvoorl--institutecountry select, .utvoorl--institutename input, .utvoorl--instituteeducation input');\n  const mypos = relevantfields.indexOf(node);\n  if (mypos > 0)\n    return relevantfields[mypos - 1];\n}\n\nfunction setupInstituteNameField(node) {\n  const countryfield = getPrevious(node);\n  if (!countryfield)\n    return console.error(\"Missing countryfield\", node);\n\n  const groupname = node.matches(\":lang(nl)\") ? \"Bedoelde je:\" : \"Did you mean:\";\n  UTAutoComplete({\n    input: node,\n    className: 'ut-autocomplete',\n    preventSubmit: 1,\n    fetch: async function (text, update) {\n      const suggestions = await getInstitutes(countryfield, text, groupname);\n      update(suggestions);\n    },\n    onSelect: function (item) {\n      node.value = item.label ?? \"\";\n    },\n  });\n}\nfunction setupInstituteEducationField(node) {\n  const institutefield = getPrevious(node);\n  if (!institutefield)\n    return console.error(\"Missing institutefield\", node);\n\n  const countryfield = getPrevious(institutefield);\n  if (!countryfield)\n    return console.error(\"Missing countryfield\", institutefield, node);\n\n  const groupname = node.matches(\":lang(nl)\") ? \"Bedoelde je:\" : \"Did you mean:\";\n  UTAutoComplete({\n    input: node,\n    className: 'ut-autocomplete',\n    preventSubmit: 1,\n    fetch: async function (text, update) {\n      const suggestions = await getInstituteEducations(countryfield, institutefield, text, groupname);\n      update(suggestions);\n    },\n    onSelect: function (item) {\n      node.value = item.label ?? \"\";\n    },\n  });\n}\n\ndompack.register('.utvoorl--institutename input', setupInstituteNameField);\ndompack.register('.utvoorl--instituteeducation input', setupInstituteEducationField);\n","import * as dompack from 'dompack';\nimport * as dialogapi from 'dompack/api/dialog';\nimport { qS, qSA } from 'dompack';\n\nimport * as modaldialog from \"@mod-utwente_base/webdesigns/ws2016/src/shared/dialog\";\nimport * as forms from '@mod-publisher/js/forms';\n\nimport './cashpointpage.css';\nimport './cashpointpage.lang.json';\nimport { getTid } from \"@webhare/gettid\";\nimport { UTVoorlichtingRPCForm } from '@mod-utwente_voorlichting/js/shared/forms';\nimport { qR } from '@webhare/dompack';\nimport { setupValidator } from '@mod-publisher/js/forms';\nimport { rpc } from '@webhare/rpc';\nimport { navigateTo } from '@webhare/env';\n\ntype VerifyResult = {\n  status: \"ok\";\n  price: string;\n  diff_amount: string;\n  courses: Array<{\n    course: number;\n    coursetitle: string;\n    invoicetitle: string;\n    ordering: number;\n    price: number;\n    pricepertype: unknown[];\n    round: number;\n    roundtitle: string;\n  }>;\n  housing: string;\n  paymentreq: boolean;\n} | {\n  status: \"emailinuse\";\n  contactaddress: string;\n} | {\n  status: \"invalidcode\" | \"usedcode\" | \"expiredcode\" | \"invalidforcourse\";\n};\n\nclass StayoverEventsSignupForm extends UTVoorlichtingRPCForm {\n  constructor(form: HTMLFormElement) {\n    super(form);\n\n    if (this.elements.namedItem(\"wrd_dateofbirth\"))\n      setupValidator(this.elements.namedItem(\"wrd_dateofbirth\") as HTMLElement, date => this.checkBirthdate(date as HTMLInputElement));\n\n    qR('#previouspagebutton').addEventListener(\"click\", () => void this.onBackButton());\n    qR('#registerbutton').addEventListener(\"click\", () => void this.onRegisterButton());\n    qR('#loginbutton').addEventListener(\"click\", () => void this.onLoginButton());\n    qS('#cancellink')?.addEventListener('click', () => void this.doCancel());\n\n    qSA(this.node, \"select[name^=round]\").forEach(node => node.addEventListener(\"change\", () => this.checkRoundPulldowns()));\n    qSA(this.node, \"input[name=signupusertype]\").forEach(node => node.addEventListener(\"change\", () => this.checkSignupType()));\n\n    //Verify the discount code\n    (this.elements.namedItem(\"discountcode\") as HTMLElement | undefined)?.addEventListener(\"input\", () => this.setFieldError(this.elements.namedItem(\"discountcode\")! as HTMLElement, '')); //FIXME should autoclear on input but that seems broken so this is a quickfix\n  }\n\n  checkRoundPulldowns() {\n    //Disable options in the 'lower' pulldowns if they're selected higher up\n    const selected = [];\n    for (const pulldown of qSA<HTMLSelectElement>(this.node, \"select[name^=round]\")) {\n      for (const option of qSA<HTMLOptionElement>(pulldown, 'option')) {\n        if (!option.value || option.value === '-')\n          continue;\n\n        option.disabled = selected.includes(option.value); //already selected above, so disable here\n        if (option.disabled && pulldown.value === option.value)\n          pulldown.value = \"\"; //reset\n      }\n      selected.push(pulldown.value);\n    }\n  }\n\n  shouldLogin() {\n    const selection = this.node.querySelector<HTMLInputElement>(\"input[name=signupusertype]:checked\");\n    return selection && ['student', 'employee'].includes(selection.value);\n  }\n\n  checkSignupType() {\n    const showloginbutton = this.shouldLogin();\n    qR(\"#registerbutton\").style.display = showloginbutton ? \"none\" : \"\";\n    qR(\"#loginbutton\").style.display = showloginbutton ? \"\" : \"none\";\n  }\n\n  mapError(error: string) {\n    if (error === \"__curiousu_maxdate\")\n      return <span>You need to be at least 18 years old to join CuriousU.</span>;\n    return error;\n  }\n\n  checkBirthdate(date: HTMLInputElement) {\n    if (date.dataset.minimumdate && new Date(date.value) < new Date(date.dataset.minimumdate))\n      return this.mapError(date.dataset.mindateerror!);\n    if (date.dataset.maximumdate && new Date(date.value) > new Date(date.dataset.maximumdate))\n      return this.mapError(date.dataset.maxdateerror!);\n  }\n\n  async onBackButton() {\n    await this.gotoPage(0);\n  }\n\n  async onLoginButton() {\n    this.onRPC(Promise.withResolvers<void>().promise); //trigger the modality layer but abuse a promise that will never resolve\n\n    const link = new URL(location.href);\n    link.searchParams.set(\"login\", \"1\");\n    //fix scroll position, weird things happen otherwise... even in the tests.. it jumps down but unknown why, much farther than the scrollpos before redirect...\n    location.href = link.toString() + \"#registerform-personaldetails-anchor\";\n  }\n\n  async onRegisterButton() {\n    const discountcodefield = this.elements.namedItem(\"discountcode\") as HTMLInputElement | null;\n    if (discountcodefield) //Verify the discount code\n      this.setFieldError(discountcodefield, '');\n\n    const validateresult = await this.validate(qR<HTMLElement>('#formpage_naw'));\n    if (!validateresult.valid)\n      return;\n\n    const verifyresult = await this.invokeRPC('verifyFirstPage') as VerifyResult;\n    if (verifyresult.status === 'emailinuse') {\n      await dialogapi.runMessageBox(\n        <p>{getTid('utwente_voorlichting:webfeatures.stayoverevents.frontend.alreadysignedup')} <a href={\"mailto:\" + verifyresult.contactaddress}>{verifyresult.contactaddress}</a></p>,\n        [{ result: \"ok\", title: getTid(\"utwente_voorlichting:webfeatures.stayoverevents.frontend.alreadysignedup-ok\") }], { allowcancel: true });\n      return;\n    }\n    if (verifyresult.status !== 'ok') {\n      const translations: Record<string, string> = {\n        invalidcode: getTid('utwente_voorlichting:webfeatures.stayoverevents.frontend.status-invalidcode'),\n        usedcode: getTid('utwente_voorlichting:webfeatures.stayoverevents.frontend.status-usedcode'),\n        expiredcode: getTid('utwente_voorlichting:webfeatures.stayoverevents.frontend.status-expiredcode'),\n        invalidforcourse: getTid('utwente_voorlichting:webfeatures.stayoverevents.frontend.status-invalidforcourse')\n      };\n\n      if (discountcodefield && translations[verifyresult.status])\n        this.setFieldError(discountcodefield, translations[verifyresult.status], { reportimmediately: true });\n      return;\n    }\n\n    qR('#verifyname').textContent = qR<HTMLInputElement>(\"#registerform-wrd_firstname\").value + \" \" + qR<HTMLInputElement>(\"#registerform-wrd_lastname\").value;\n    qR('#verifyemail').textContent = qR<HTMLInputElement>(\"#registerform-wrd_contact_email\").value;\n    qR('#verifycourses').replaceChildren(...verifyresult.courses.map(\n      (roundcourse: { roundtitle: string; coursetitle: string }) => <div class=\"verifycourses__courserow\">\n        <span class=\"verifycourses__roundtitle\">{roundcourse.roundtitle}</span>{\": \"}\n        <span class=\"verifycourses__coursetitle\">{roundcourse.coursetitle}</span>\n      </div>));\n\n    if (qS('#verifyhousing'))\n      qS('#verifyhousing')!.textContent = verifyresult.housing;\n    qR('#verifyprice').textContent = verifyresult.price;\n\n    const diff_amount = parseFloat(verifyresult.diff_amount.replace(',', '.')); //we may receive it with ',', correct that\n    const need_payment = diff_amount > 0;\n\n    if (diff_amount < 0) { // refund\n      qR('#verifyrefundtext').style.display = '';\n      qR('#verifyadditionalpaymenttext').style.display = 'none';\n      qR('#verifyrefund').textContent = verifyresult.diff_amount.substr(1);\n    } else { // No payment needed, or additional payment needed\n      qR('#verifyrefundtext').style.display = 'none';\n      qR('#verifyadditionalpaymenttext').style.display = '';\n      qR('#verifyadditionalpayment').textContent = verifyresult.diff_amount;\n    }\n\n    this.node.dataset.whFormVarRequirespayment = need_payment ? \"true\" : \"\";\n    await this.refreshConditions();\n\n    //Go to next page. We shouldn't jump before refreshConditions because it'll break scroll positions if controls get hidden\n    await this.gotoPage(1);\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  onSubmitSuccess(result: any) {\n    this.onRPC(Promise.withResolvers<void>().promise); //trigger the modality layer but abuse a promise that will never resolve\n    navigateTo(result.instr);\n  }\n\n  async doCancel() {\n    const result = await modaldialog.runYesNoMessageBox(getTid('utwente_voorlichting:widgets.openday.confirmcancel'));\n    if (result === 'yes') {\n      const cuguid = new URL(location.href).searchParams.get(\"cuguid\")!;\n      navigateTo((await rpc(\"utwente_voorlichting:cashpoint\").cancelRegistration(cuguid)).instr);\n    }\n  }\n}\n\nfunction setupPaymentZone() {\n  for (const button of qSA('.curiousu__paymentzone input[type=submit]'))\n    button.classList.add('wh-form__button');\n}\n\nforms.registerHandler(\"curiousu-signupform\", node => new StayoverEventsSignupForm(node));\ndompack.register(\".curiousu__paymentzone\", () => setupPaymentZone());\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/webfeatures/cashpoint/cashpointpage.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_voorlichting\",\"nl\",{\"webfeatures\":{\"stayoverevents\":{\"frontend\":{\"additionaloptions\":\"Extra opties registratie\",\"agreementsummary\":[\"U bent ermee akkoord gegaan om te betalen voor \",1,\" \",2,\" plekken voor een totaalbedrag van \",3,\".\"],\"alreadysignedup\":\"Dit e-mailadres is recent al gebruikt voor een registratie, neem contact met ons op via\",\"alreadysignedup-ok\":\"OK\",\"aredetailscorrect\":\"Kloppen deze gegevens?\",\"back\":\"Terug\",\"billingaddress_enable\":\"Factuuradres toevoegen\",\"billingaddress_group\":\"Factuuradres\",\"billingaddress_separate\":\"Apart factuuradres\",\"billingorgname\":\"Organisatie\",\"cancelregistration\":\"Ik wil mijn registratie annuleren\",\"choosecourse\":\"Maak een keuze\",\"choosegroup\":\"- Kies je groep -\",\"choosehousing\":\"Kies accomodatie\",\"choosevwoclass\":\"- Kies je klas -\",\"contactice\":\"Contact in geval van nood (ICE)\",\"courseaccomodation\":\"Programma\",\"courselockedbydiscount\":\"Uw kortingscode is gekoppeld aan uw programmakeuze\",\"dinner\":\"Ben je aanwezig bij het netwerkdiner in het avondprogramma?\",\"dinner-no\":\"Nee\",\"dinner-yes\":\"Ja\",\"diploma\":\"Diploma\",\"discountcode\":\"Kortingscode (optioneel)\",\"education\":\"Gegevens school\",\"housing\":\"Accomodatie\",\"invoiceorgname\":\"Uw instituut / organisatie\",\"login\":\"Login\",\"name\":\"Naam\",\"optin-preu_junior-label\":\"Stuur mij de Pre-U Junior nieuwsbrief\",\"optin_photo\":\"Fotogebruik\",\"optin_photo-label\":\"Ik geef toestemming om mijn foto te gebruiken\",\"optin_preu_junior\":\"Pre-U Junior\",\"parentlegalguardian\":\"Ouder / voogd (contact)\",\"paymentmethod\":\"Betaalmethode\",\"personaldetails\":\"Gegevens deelnemer\",\"personaldetails_child\":\"Gegevens kind\",\"placeorder\":\"Bestelling doorvoeren\",\"preferredlanguage\":\"Voorkeurstaal\",\"programme\":\"Programma\",\"refund\":\"Teruggave\",\"registerbutton\":\"Registreer\",\"registrant_organization\":\"Uw organisatie\",\"registrationstatus\":\"Registratiestatus\",\"remarks\":\"Opmerkingen\",\"school_group\":\"Groep\",\"securepayment\":\"Veilige betaling\",\"signup_login\":\"M/S nummer\",\"signuptype\":\"Type aanmelding\",\"signupusertype\":\"Aanmelden als\",\"signupusertype-employee\":\"UT Medewerker\",\"signupusertype-genootschap\":\"Via Genootschap voor Risicomangement\",\"signupusertype-primo\":\"Via PRIMO\",\"signupusertype-regular_signup\":\"Reguliere aanmelding\",\"signupusertype-sponsor\":\"Via sponsor\",\"signupusertype-student\":\"UT Student\",\"soldout\":\"uitverkocht\",\"specialagreement\":\"Speciale overeenkomst\",\"sponsor_name\":\"Naam sponsor\",\"sponsor_yournumber\":\"Lidmaatschaps nummer\",\"sponsor_yournumber-ifknown\":\"(indien bekend)\",\"status-expiredcode\":\"De kortingscode is verlopen\",\"status-invalidcode\":\"De kortingscode is ongeldig\",\"status-invalidforcourse\":\"De kortingscode is niet beschikbaar voor het gekozen programma\",\"status-usedcode\":\"De kortingscode is al gebruikt\",\"step\":\"Stap\",\"termsandconditions\":\"Voorwaarden\",\"topay\":\"Te betalen\",\"totalprice\":\"Totaalprijs\",\"workstudy\":\"Werk/studie\",\"workstudy-choose\":\"Kies werk/studie\",\"workstudy-other\":\"Overig\",\"workstudy-study\":\"Studie\",\"workstudy-work\":\"Werk\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"en\",{\"webfeatures\":{\"stayoverevents\":{\"frontend\":{\"additionaloptions\":\"Additional options\",\"agreementsummary\":[\"You've agreed to pay for \",1,\" \",2,\" spots with a total amount of \",3,\".\"],\"alreadysignedup\":\"Your email has recently been used for this registration form, please contact us at\",\"alreadysignedup-ok\":\"OK\",\"aredetailscorrect\":\"Are these booking details correct?\",\"back\":\"Back\",\"billingaddress_enable\":\"Add billing address for invoice\",\"billingaddress_group\":\"Billing address\",\"billingaddress_separate\":\"Separate billing address\",\"billingorgname\":\"Organization\",\"cancelregistration\":\"I wish to cancel my registration\",\"choosecourse\":\"Choose a course\",\"choosegroup\":\"- Choose your group -\",\"choosehousing\":\"Choose accomodation\",\"choosevwoclass\":\"- Choose your class -\",\"contactice\":\"Contact in case of emergency (ICE)\",\"courseaccomodation\":\"Course and accommodation\",\"courselockedbydiscount\":\"Your discount code is tied to your course selection\",\"dinner\":\"Will you join the network dinner ?\",\"dinner-no\":\"No\",\"dinner-yes\":\"Yes\",\"diploma\":\"Diploma\",\"discountcode\":\"Discount code (optional)\",\"education\":\"Education\",\"housing\":\"Accommodation\",\"invoiceorgname\":\"Your institution / organization\",\"login\":\"Login\",\"name\":\"Name\",\"optin-preu_junior-label\":\"Send me the Pre-U Junior newsletter\",\"optin_photo\":\"Photo use\",\"optin_photo-label\":\"I give permission to use my photo\",\"optin_preu_junior\":\"Pre-U Junior\",\"parentlegalguardian\":\"Parent / legal guardian\",\"paymentmethod\":\"Payment method\",\"personaldetails\":\"Participant details\",\"personaldetails_child\":\"Child details\",\"placeorder\":\"Place order\",\"preferredlanguage\":\"Preferred language\",\"programme\":\"Programme\",\"refund\":\"Refund\",\"registerbutton\":\"Register\",\"registrant_organization\":\"Your organization\",\"registrationstatus\":\"Registration status\",\"remarks\":\"Remarks\",\"school_group\":\"Group\",\"securepayment\":\"Secure Payment\",\"signup_login\":\"M/S number\",\"signuptype\":\"Signup type\",\"signupusertype\":\"Signup as\",\"signupusertype-employee\":\"UT Employee\",\"signupusertype-genootschap\":\"Through Genootschap voor Risicomangement\",\"signupusertype-primo\":\"Through PRIMO\",\"signupusertype-regular_signup\":\"Regular signup\",\"signupusertype-sponsor\":\"Through sponsor\",\"signupusertype-student\":\"UT Student\",\"soldout\":\"sold out\",\"specialagreement\":\"Special agreement\",\"sponsor_name\":\"Sponsor name\",\"sponsor_yournumber\":\"Membership number\",\"sponsor_yournumber-ifknown\":\"(if known)\",\"status-expiredcode\":\"This code has expired\",\"status-invalidcode\":\"This discount code is invalid\",\"status-invalidforcourse\":\"This discount code is not available for the selected program\",\"status-usedcode\":\"This code has already been used\",\"step\":\"Step\",\"termsandconditions\":\"Terms and conditions\",\"topay\":\"To pay\",\"totalprice\":\"Total price\",\"workstudy\":\"Work/study\",\"workstudy-choose\":\"Choose work/study\",\"workstudy-other\":\"Other\",\"workstudy-study\":\"Study\",\"workstudy-work\":\"Work\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"de\",{\"webfeatures\":{\"stayoverevents\":{\"frontend\":{\"choosevwoclass\":\"- Wähle deinen Schuljahrgang -\",\"additionaloptions\":\"Additional options\",\"agreementsummary\":[\"You've agreed to pay for \",1,\" \",2,\" spots with a total amount of \",3,\".\"],\"alreadysignedup\":\"Your email has recently been used for this registration form, please contact us at\",\"alreadysignedup-ok\":\"OK\",\"aredetailscorrect\":\"Are these booking details correct?\",\"back\":\"Back\",\"billingaddress_enable\":\"Add billing address for invoice\",\"billingaddress_group\":\"Billing address\",\"billingaddress_separate\":\"Separate billing address\",\"billingorgname\":\"Organization\",\"cancelregistration\":\"I wish to cancel my registration\",\"choosecourse\":\"Choose a course\",\"choosegroup\":\"- Choose your group -\",\"choosehousing\":\"Choose accomodation\",\"contactice\":\"Contact in case of emergency (ICE)\",\"courseaccomodation\":\"Course and accommodation\",\"courselockedbydiscount\":\"Your discount code is tied to your course selection\",\"dinner\":\"Will you join the network dinner ?\",\"dinner-no\":\"No\",\"dinner-yes\":\"Yes\",\"diploma\":\"Diploma\",\"discountcode\":\"Discount code (optional)\",\"education\":\"Education\",\"housing\":\"Accommodation\",\"invoiceorgname\":\"Your institution / organization\",\"login\":\"Login\",\"name\":\"Name\",\"optin-preu_junior-label\":\"Send me the Pre-U Junior newsletter\",\"optin_photo\":\"Photo use\",\"optin_photo-label\":\"I give permission to use my photo\",\"optin_preu_junior\":\"Pre-U Junior\",\"parentlegalguardian\":\"Parent / legal guardian\",\"paymentmethod\":\"Payment method\",\"personaldetails\":\"Participant details\",\"personaldetails_child\":\"Child details\",\"placeorder\":\"Place order\",\"preferredlanguage\":\"Preferred language\",\"programme\":\"Programme\",\"refund\":\"Refund\",\"registerbutton\":\"Register\",\"registrant_organization\":\"Your organization\",\"registrationstatus\":\"Registration status\",\"remarks\":\"Remarks\",\"school_group\":\"Group\",\"securepayment\":\"Secure Payment\",\"signup_login\":\"M/S number\",\"signuptype\":\"Signup type\",\"signupusertype\":\"Signup as\",\"signupusertype-employee\":\"UT Employee\",\"signupusertype-genootschap\":\"Through Genootschap voor Risicomangement\",\"signupusertype-primo\":\"Through PRIMO\",\"signupusertype-regular_signup\":\"Regular signup\",\"signupusertype-sponsor\":\"Through sponsor\",\"signupusertype-student\":\"UT Student\",\"soldout\":\"sold out\",\"specialagreement\":\"Special agreement\",\"sponsor_name\":\"Sponsor name\",\"sponsor_yournumber\":\"Membership number\",\"sponsor_yournumber-ifknown\":\"(if known)\",\"status-expiredcode\":\"This code has expired\",\"status-invalidcode\":\"This discount code is invalid\",\"status-invalidforcourse\":\"This discount code is not available for the selected program\",\"status-usedcode\":\"This code has already been used\",\"step\":\"Step\",\"termsandconditions\":\"Terms and conditions\",\"topay\":\"To pay\",\"totalprice\":\"Total price\",\"workstudy\":\"Work/study\",\"workstudy-choose\":\"Choose work/study\",\"workstudy-other\":\"Other\",\"workstudy-study\":\"Study\",\"workstudy-work\":\"Work\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"es\",{\"webfeatures\":{\"stayoverevents\":{\"frontend\":{\"additionaloptions\":\"Additional options\",\"agreementsummary\":[\"You've agreed to pay for \",1,\" \",2,\" spots with a total amount of \",3,\".\"],\"alreadysignedup\":\"Your email has recently been used for this registration form, please contact us at\",\"alreadysignedup-ok\":\"OK\",\"aredetailscorrect\":\"Are these booking details correct?\",\"back\":\"Back\",\"billingaddress_enable\":\"Add billing address for invoice\",\"billingaddress_group\":\"Billing address\",\"billingaddress_separate\":\"Separate billing address\",\"billingorgname\":\"Organization\",\"cancelregistration\":\"I wish to cancel my registration\",\"choosecourse\":\"Choose a course\",\"choosegroup\":\"- Choose your group -\",\"choosehousing\":\"Choose accomodation\",\"choosevwoclass\":\"- Choose your class -\",\"contactice\":\"Contact in case of emergency (ICE)\",\"courseaccomodation\":\"Course and accommodation\",\"courselockedbydiscount\":\"Your discount code is tied to your course selection\",\"dinner\":\"Will you join the network dinner ?\",\"dinner-no\":\"No\",\"dinner-yes\":\"Yes\",\"diploma\":\"Diploma\",\"discountcode\":\"Discount code (optional)\",\"education\":\"Education\",\"housing\":\"Accommodation\",\"invoiceorgname\":\"Your institution / organization\",\"login\":\"Login\",\"name\":\"Name\",\"optin-preu_junior-label\":\"Send me the Pre-U Junior newsletter\",\"optin_photo\":\"Photo use\",\"optin_photo-label\":\"I give permission to use my photo\",\"optin_preu_junior\":\"Pre-U Junior\",\"parentlegalguardian\":\"Parent / legal guardian\",\"paymentmethod\":\"Payment method\",\"personaldetails\":\"Participant details\",\"personaldetails_child\":\"Child details\",\"placeorder\":\"Place order\",\"preferredlanguage\":\"Preferred language\",\"programme\":\"Programme\",\"refund\":\"Refund\",\"registerbutton\":\"Register\",\"registrant_organization\":\"Your organization\",\"registrationstatus\":\"Registration status\",\"remarks\":\"Remarks\",\"school_group\":\"Group\",\"securepayment\":\"Secure Payment\",\"signup_login\":\"M/S number\",\"signuptype\":\"Signup type\",\"signupusertype\":\"Signup as\",\"signupusertype-employee\":\"UT Employee\",\"signupusertype-genootschap\":\"Through Genootschap voor Risicomangement\",\"signupusertype-primo\":\"Through PRIMO\",\"signupusertype-regular_signup\":\"Regular signup\",\"signupusertype-sponsor\":\"Through sponsor\",\"signupusertype-student\":\"UT Student\",\"soldout\":\"sold out\",\"specialagreement\":\"Special agreement\",\"sponsor_name\":\"Sponsor name\",\"sponsor_yournumber\":\"Membership number\",\"sponsor_yournumber-ifknown\":\"(if known)\",\"status-expiredcode\":\"This code has expired\",\"status-invalidcode\":\"This discount code is invalid\",\"status-invalidforcourse\":\"This discount code is not available for the selected program\",\"status-usedcode\":\"This code has already been used\",\"step\":\"Step\",\"termsandconditions\":\"Terms and conditions\",\"topay\":\"To pay\",\"totalprice\":\"Total price\",\"workstudy\":\"Work/study\",\"workstudy-choose\":\"Choose work/study\",\"workstudy-other\":\"Other\",\"workstudy-study\":\"Study\",\"workstudy-work\":\"Work\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"it\",{\"webfeatures\":{\"stayoverevents\":{\"frontend\":{\"additionaloptions\":\"Additional options\",\"agreementsummary\":[\"You've agreed to pay for \",1,\" \",2,\" spots with a total amount of \",3,\".\"],\"alreadysignedup\":\"Your email has recently been used for this registration form, please contact us at\",\"alreadysignedup-ok\":\"OK\",\"aredetailscorrect\":\"Are these booking details correct?\",\"back\":\"Back\",\"billingaddress_enable\":\"Add billing address for invoice\",\"billingaddress_group\":\"Billing address\",\"billingaddress_separate\":\"Separate billing address\",\"billingorgname\":\"Organization\",\"cancelregistration\":\"I wish to cancel my registration\",\"choosecourse\":\"Choose a course\",\"choosegroup\":\"- Choose your group -\",\"choosehousing\":\"Choose accomodation\",\"choosevwoclass\":\"- Choose your class -\",\"contactice\":\"Contact in case of emergency (ICE)\",\"courseaccomodation\":\"Course and accommodation\",\"courselockedbydiscount\":\"Your discount code is tied to your course selection\",\"dinner\":\"Will you join the network dinner ?\",\"dinner-no\":\"No\",\"dinner-yes\":\"Yes\",\"diploma\":\"Diploma\",\"discountcode\":\"Discount code (optional)\",\"education\":\"Education\",\"housing\":\"Accommodation\",\"invoiceorgname\":\"Your institution / organization\",\"login\":\"Login\",\"name\":\"Name\",\"optin-preu_junior-label\":\"Send me the Pre-U Junior newsletter\",\"optin_photo\":\"Photo use\",\"optin_photo-label\":\"I give permission to use my photo\",\"optin_preu_junior\":\"Pre-U Junior\",\"parentlegalguardian\":\"Parent / legal guardian\",\"paymentmethod\":\"Payment method\",\"personaldetails\":\"Participant details\",\"personaldetails_child\":\"Child details\",\"placeorder\":\"Place order\",\"preferredlanguage\":\"Preferred language\",\"programme\":\"Programme\",\"refund\":\"Refund\",\"registerbutton\":\"Register\",\"registrant_organization\":\"Your organization\",\"registrationstatus\":\"Registration status\",\"remarks\":\"Remarks\",\"school_group\":\"Group\",\"securepayment\":\"Secure Payment\",\"signup_login\":\"M/S number\",\"signuptype\":\"Signup type\",\"signupusertype\":\"Signup as\",\"signupusertype-employee\":\"UT Employee\",\"signupusertype-genootschap\":\"Through Genootschap voor Risicomangement\",\"signupusertype-primo\":\"Through PRIMO\",\"signupusertype-regular_signup\":\"Regular signup\",\"signupusertype-sponsor\":\"Through sponsor\",\"signupusertype-student\":\"UT Student\",\"soldout\":\"sold out\",\"specialagreement\":\"Special agreement\",\"sponsor_name\":\"Sponsor name\",\"sponsor_yournumber\":\"Membership number\",\"sponsor_yournumber-ifknown\":\"(if known)\",\"status-expiredcode\":\"This code has expired\",\"status-invalidcode\":\"This discount code is invalid\",\"status-invalidforcourse\":\"This discount code is not available for the selected program\",\"status-usedcode\":\"This code has already been used\",\"step\":\"Step\",\"termsandconditions\":\"Terms and conditions\",\"topay\":\"To pay\",\"totalprice\":\"Total price\",\"workstudy\":\"Work/study\",\"workstudy-choose\":\"Choose work/study\",\"workstudy-other\":\"Other\",\"workstudy-study\":\"Study\",\"workstudy-work\":\"Work\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"xt\",{\"webfeatures\":{\"stayoverevents\":{\"frontend\":{\"additionaloptions\":\"Additional options\",\"agreementsummary\":[\"You've agreed to pay for \",1,\" \",2,\" spots with a total amount of \",3,\".\"],\"alreadysignedup\":\"Your email has recently been used for this registration form, please contact us at\",\"alreadysignedup-ok\":\"OK\",\"aredetailscorrect\":\"Are these booking details correct?\",\"back\":\"Back\",\"billingaddress_enable\":\"Add billing address for invoice\",\"billingaddress_group\":\"Billing address\",\"billingaddress_separate\":\"Separate billing address\",\"billingorgname\":\"Organization\",\"cancelregistration\":\"I wish to cancel my registration\",\"choosecourse\":\"Choose a course\",\"choosegroup\":\"- Choose your group -\",\"choosehousing\":\"Choose accomodation\",\"choosevwoclass\":\"- Choose your class -\",\"contactice\":\"Contact in case of emergency (ICE)\",\"courseaccomodation\":\"Course and accommodation\",\"courselockedbydiscount\":\"Your discount code is tied to your course selection\",\"dinner\":\"Will you join the network dinner ?\",\"dinner-no\":\"No\",\"dinner-yes\":\"Yes\",\"diploma\":\"Diploma\",\"discountcode\":\"Discount code (optional)\",\"education\":\"Education\",\"housing\":\"Accommodation\",\"invoiceorgname\":\"Your institution / organization\",\"login\":\"Login\",\"name\":\"Name\",\"optin-preu_junior-label\":\"Send me the Pre-U Junior newsletter\",\"optin_photo\":\"Photo use\",\"optin_photo-label\":\"I give permission to use my photo\",\"optin_preu_junior\":\"Pre-U Junior\",\"parentlegalguardian\":\"Parent / legal guardian\",\"paymentmethod\":\"Payment method\",\"personaldetails\":\"Participant details\",\"personaldetails_child\":\"Child details\",\"placeorder\":\"Place order\",\"preferredlanguage\":\"Preferred language\",\"programme\":\"Programme\",\"refund\":\"Refund\",\"registerbutton\":\"Register\",\"registrant_organization\":\"Your organization\",\"registrationstatus\":\"Registration status\",\"remarks\":\"Remarks\",\"school_group\":\"Group\",\"securepayment\":\"Secure Payment\",\"signup_login\":\"M/S number\",\"signuptype\":\"Signup type\",\"signupusertype\":\"Signup as\",\"signupusertype-employee\":\"UT Employee\",\"signupusertype-genootschap\":\"Through Genootschap voor Risicomangement\",\"signupusertype-primo\":\"Through PRIMO\",\"signupusertype-regular_signup\":\"Regular signup\",\"signupusertype-sponsor\":\"Through sponsor\",\"signupusertype-student\":\"UT Student\",\"soldout\":\"sold out\",\"specialagreement\":\"Special agreement\",\"sponsor_name\":\"Sponsor name\",\"sponsor_yournumber\":\"Membership number\",\"sponsor_yournumber-ifknown\":\"(if known)\",\"status-expiredcode\":\"This code has expired\",\"status-invalidcode\":\"This discount code is invalid\",\"status-invalidforcourse\":\"This discount code is not available for the selected program\",\"status-usedcode\":\"This code has already been used\",\"step\":\"Step\",\"termsandconditions\":\"Terms and conditions\",\"topay\":\"To pay\",\"totalprice\":\"Total price\",\"workstudy\":\"Work/study\",\"workstudy-choose\":\"Choose work/study\",\"workstudy-other\":\"Other\",\"workstudy-study\":\"Study\",\"workstudy-work\":\"Work\"}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n","export function getPrefills() {\n  return sessionStorage.utFormPrefill ? JSON.parse(sessionStorage.utFormPrefill) : {};\n}\n\nif (location.href.includes('?save') || location.href.includes('&save')) { //might be a prefill\n  const url = new URL(location.href);\n  const prefills: Record<string, string> = {};\n  Array.from(url.searchParams.keys()).filter(key => key.startsWith(\"save.\")).forEach(key => {\n    prefills[key.substring(5)] = url.searchParams.get(key)!;\n    url.searchParams.delete(key);\n  });\n\n  history.replaceState(null, '', url.toString());\n  try {\n    sessionStorage.utFormPrefill = JSON.stringify(prefills);\n  } catch (ignore) {\n  }\n}\n","import { getPrefills } from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm/prefill';\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport { RPCFormBase } from '@mod-publisher/js/forms';\n\nexport class UTVoorlichtingRPCForm<DataShape extends object = Record<string, unknown>> extends RPCFormBase<DataShape> {\n  emailfield: HTMLInputElement | null;\n  diplomafield: HTMLSelectElement | null;\n  firstnamefield: HTMLInputElement | null;\n  startingyearfield: HTMLInputElement | null;\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n\n    this.emailfield = node.elements.namedItem(\"wrd_contact_email\") as HTMLInputElement | null;\n    this.diplomafield = node.elements.namedItem(\"diploma.select\") as HTMLSelectElement | null;\n    this.firstnamefield = node.elements.namedItem(\"wrd_firstname\") as HTMLInputElement | null;\n    this.startingyearfield = (node.elements.namedItem(\"expectedstartingyear.year\") || node.elements.namedItem(\"expectedstartingyear.select\")) as HTMLInputElement | null;\n\n\n    if (this.emailfield && (!this.emailfield.value || this.emailfield!.closest(\".ut-prefill-save-vars\"))) { //new or explicitly prefillable\n      const prefills = getPrefills();\n      if (prefills.diploma && this.diplomafield) {\n        const toselect = [...this.diplomafield.options].find(_ => _.dataset.diplomatag === prefills.diploma);\n        if (toselect)\n          this.setFieldValue(this.diplomafield, toselect.value);\n      }\n      if (prefills.firstname && this.firstnamefield)\n        this.firstnamefield.value = prefills.firstname;\n      if (prefills.email && this.emailfield)\n        this.emailfield.value = prefills.email;\n      if (prefills.expectedstartingyear && this.startingyearfield)\n        this.startingyearfield.value = prefills.expectedstartingyear;\n\n\n      if (prefills.hasoptin === \"true\") {\n        this.node.setAttribute(\"data-wh-form-var-skipoptin\", \"true\");\n        this.refreshConditions(); //TODO Forms should instead make refeshConditions() sync\n      }\n    }\n  }\n\n  onSubmitSuccess(response: unknown) {\n    const r = response as { guid?: string; firstname: string };\n    if (r.guid)\n      crm.learnedAboutUser(r.guid, r.firstname);\n  }\n\n\n  async getFormExtraSubmitData() {\n    const referralinfo = crm.getReferralInfo();\n    const userbeacon = Object.keys(crm.getUserBeacons()).filter(name => name.startsWith('usertype-'))[0];\n    if (userbeacon)\n      referralinfo.beaconusertype = userbeacon.substr(9);\n\n    return {\n      filledoptin: this.node.getAttribute(\"data-wh-form-var-skipoptin\") === \"false\",\n      referralinfo,\n      targetinterest: document.documentElement.dataset.targetinterest || '',\n      targetlanguage: document.documentElement.lang.substr(0, 2)\n    };\n  }\n}\n","import \"./echeck-widget.scss\";\nimport * as dompack from \"@webhare/dompack\";\nimport { SlimSelect } from \"@mod-utwente_design\";\nimport { throwError } from \"@webhare/std\";\nimport { debugFlags } from \"@webhare/env\";\n\ndompack.register(\".widget-eligibilityprogrammes__formcontent\", node => {\n  //we're not embedded in our own <form> if we're part of the echeck form\n  const form = node.closest(\"form.widget-eligibilityprogrammes__formcontent\");\n  const eligibilitycheck = dompack.qR<HTMLSelectElement>(node, \"select[name='eligibilitycheck']\");\n  let idx = -1; // if in programme section AND NOT in an echeck set pulldown option for current programme\n  if (document.documentElement.dataset.programme && node.closest('.echeck2018__form'))\n    idx = [...eligibilitycheck.options].findIndex(_ => _.dataset.hodexcode === document.documentElement.dataset.programme);\n\n  eligibilitycheck.selectedIndex = idx;\n  const onSubmit = (ev: Event) => {\n    ev.preventDefault();\n    if (!eligibilitycheck.selectedOptions.length)\n      return;\n\n    const programs = [...eligibilitycheck.selectedOptions].map(option => option.dataset?.guid).join(',');\n    const firstprog = new URL(eligibilitycheck.selectedOptions[0].dataset.link ?? throwError(\"Missing link\"));\n    firstprog.searchParams.set(\"programs\", programs);\n    location.href = firstprog.toString();\n  };\n\n  if (form)\n    form.addEventListener(\"submit\", onSubmit);\n  else\n    dompack.qR(node, \"button[type=submit]\")?.addEventListener(\"click\", onSubmit);\n\n  if (!debugFlags[\"ut-nocustomselect\"])\n    new SlimSelect({\n      select: eligibilitycheck,\n      settings: {\n        maxSelected: 3,\n        modal: 'off', // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n        placeholderText: \"Select up to 3 programmes\"\n      },\n      events: {\n        afterChange: (newVal) => {\n          node.classList.toggle(\"widget-eligibilityprogrammes--max-selection-reached\", newVal.length >= 3);\n        }\n      }\n    });\n});\n","import \"./echeck.scss\";\nimport \"./widget.ts\";\nimport * as dompack from \"@webhare/dompack\";\nimport { getReferralInfo } from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as forms from \"@mod-publisher/js/forms\";\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\nimport { isTruthy, throwError } from \"@webhare/std\";\nimport { navigateTo } from \"@webhare/frontend\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_voorlichting:echeck\": {\n      firstpage: string;\n      formentryguid: string;\n    };\n  }\n}\n\nconst maxloops = 1000;\nlet echeckreferral = '';\n\nfunction getEcheckReferral() {\n  return echeckreferral || window.localStorage[\"ut:echeck-referral\"] || null;\n}\n\nfunction setEcheckReferral(code: string) {\n  echeckreferral = code;\n  window.localStorage[\"ut:echeck-referral\"] = echeckreferral;\n}\n\nfunction checkEcheckReferral() {\n  //wrapping in try-catch to make sure init doesn't fail because of something here throwing. who knows...\n  try {\n    const url = new URL(location.href);\n    const refrl = url.searchParams.get('echeck-referral');\n    if (refrl) {\n      url.searchParams.delete('echeck-referral');\n      history.replaceState(null, document.title, url.toString());\n      setEcheckReferral(refrl);\n    }\n  } catch (e) {\n    console.error(e);\n  }\n\n  const refrl = getEcheckReferral();\n  if (refrl)\n    window.dataLayer.push({ echeck_referralcode: refrl });\n}\n\nclass EcheckForm extends forms.RPCFormBase<{\n  firstname: string;\n  diploma: string;\n  intent: string;\n  program1?: string;\n  program2?: string;\n  program3?: string;\n}> {\n  history: string[] = [];\n  settings: {\n    firstpage: string;\n    formentryguid: string;\n  };\n  termsnode: HTMLElement | null;\n  pages: HTMLElement[] = [];\n  progressindicator = <div class=\"echeck2018__form__progress__indicator\" />;\n  progressidx = 0; //Initial first position\n  progresssteps: HTMLDivElement[] = [];\n  donepage: HTMLDivElement | null = null;\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n\n    this.settings = getFrontendData(\"utwente_voorlichting:echeck\");\n\n    this.termsnode = dompack.qS(node, \".echeck2018__form__terms\");\n\n    this.rewriteDiplomaLayout(); // First rewrite diploma to 2 columns layout\n\n    dompack.qSA(node, \".wh-form__fieldgroup--radiogroup,.wh-form__fieldgroup--checkboxgroup\").forEach(group => {\n      if (!group.classList.contains(\"echeck2018__form__groupcolumns\")) {\n        const groupoptions = dompack.qSA(group, \".wh-form__fieldline\");\n        if (groupoptions.length > 6) {\n\n          group.classList.add(\"echeck2018__form__groupcolumns\");\n          const col1 = <div class=\"echeck2018__form__groupcolumns__column\" />;\n          const col2 = <div class=\"echeck2018__form__groupcolumns__column\" />;\n\n          const splitidx = Math.ceil(groupoptions.length / 2);\n          groupoptions.forEach((fieldline, i) => {\n            if (i === 0)\n              fieldline.before(col1);\n            else if (i === splitidx)\n              fieldline.before(col2);\n\n            if (i < splitidx)\n              col1.append(fieldline);\n            else\n              col2.append(fieldline);\n          });\n        }\n      }\n    });\n\n    const groupids: string[] = [];\n    dompack.qSA(this.node, \".echeck2018__page\").forEach(page => {\n      if (page.dataset.groupid) {\n        if (!groupids.includes(page.dataset.groupid)) {\n          groupids.push(page.dataset.groupid);\n          this.pages.push(page);\n        }\n      } else if (page.dataset.pageid)\n        this.pages.push(page);\n    });\n\n    this.setupProgressIndicator();\n\n    this.registerHandlers();\n\n    //if we start at diploma but have a selectprogram, push it to the history so you can go back to it\n    if (this.settings.firstpage === \"diploma\" && this.pages.find(_ => _.dataset.pageid === \"selectprogram\"))\n      this.history.push(\"selectprogram\");\n\n    this.selectPage(this.settings.firstpage);\n\n    if (this.node.dataset.referralcode)\n      setEcheckReferral(this.node.dataset.referralcode);\n    else if (window.localStorage[\"ut:echeck-referral\"])\n      setEcheckReferral(window.localStorage[\"ut:echeck-referral\"]);\n  }\n\n  rewriteDiplomaLayout() {\n    const diplomagroup = dompack.qS(this.node, \".echeck2018__form__diploma\");\n    if (!diplomagroup)\n      return;\n\n    diplomagroup.classList.add(\"echeck2018__form__groupcolumns\");\n\n    let eduttypewrapper = <div class=\"echeck2018__form__groupcolumns__column\" />;\n    let colcount = 1;\n    let prevtype = \"\";\n    dompack.qSA(diplomagroup, \".wh-form__fieldline input\").forEach((inp, i) => {\n      const fieldline = inp.closest(\".wh-form__fieldline\");\n      if (!fieldline)\n        throw new Error(\"Fieldline not found\");\n      if (i === 0)\n        fieldline.before(eduttypewrapper);\n      else if (inp.dataset.edutype !== \"secondary\" && colcount === 1) {\n        eduttypewrapper = <div class=\"echeck2018__form__groupcolumns__column\" />;\n        fieldline.before(eduttypewrapper);\n        ++colcount;\n      }\n\n      if (prevtype !== inp.dataset.edutype) {\n        if (inp.dataset.edutype === \"secondary\")\n          eduttypewrapper.append(<h4>Secondary education</h4>);\n        else if (inp.dataset.edutype === \"bachelor\")\n          eduttypewrapper.append(<h4>{\"Bachelor's\"}</h4>);\n        else if (inp.dataset.edutype === \"master\")\n          eduttypewrapper.append(<h4>{\"Master's\"}</h4>);\n      }\n\n      prevtype = inp.dataset.edutype!;\n\n      eduttypewrapper.append(fieldline);\n    });\n  }\n\n  setupProgressIndicator() {\n    const innernode = <div class=\"echeck2018__form__progress__inner\">{this.progressindicator}</div>;\n    dompack.qR(this.node, \".echeck2018__form__progress\").append(innernode);\n\n    this.progresssteps = [];\n    this.pages.forEach((page, i) => {\n      // Don't show indicator for 'sentresumptionlink' page\n      const pageid = page.dataset.pageid ?? throwError(\"Page doesn't have pageid\");\n      if (![\"sentresumptionlink\"].includes(pageid))\n        this.progresssteps.push(this.renderStepNode(pageid, page.dataset.groupid, i));\n    });\n\n    // the finish line\n    this.progresssteps.push(this.renderStepNode(\"finalized\", \"\", 0));\n\n    innernode.append(...this.progresssteps);\n  }\n\n  renderStepNode(pageid: string, groupid: string | undefined, i: number): HTMLDivElement {\n    return <div class={\"echeck2018__form__progress__page \" + (i ? \"echeck2018__form__progress__page--withlabel\" : \"\")} data-pageid={pageid} data-groupid={groupid}>\n      {i > 0 ? <div class=\"echeck2018__form__progress__label\" hidden>\n        <span class=\"echeck2018__form__progress__label__nr\">{i}</span>\n      </div> : null\n      }\n    </div>;\n  }\n\n  updateProgressIndicator(current: HTMLElement, status?: string) {\n    if (!this.progressindicator)\n      return;\n\n    if (!status)\n      status = \"\";\n\n    let idx = -1;\n    if (current.dataset.groupid)\n      idx = this.progresssteps.findIndex(_ => _.dataset.groupid === current.dataset.groupid);\n    else\n      idx = this.progresssteps.findIndex(_ => _.dataset.pageid === current.dataset.pageid);\n\n    if (idx < 0)\n      idx = this.progressidx;\n\n    const finalized = this.node.classList.contains(\"echeck2018__form--success\");\n\n    if (status === \"failed\" && !idx)\n      idx = 1;\n\n    this.progresssteps.forEach((step, i) => {\n      if (this.progresssteps[i].children.length)\n        (this.progresssteps[i].children[0] as HTMLElement).hidden = i > idx;\n\n      if (finalized && i < idx)\n        this.progresssteps[i].classList.remove(\"echeck2018__form__progress__page--checked\");\n      else\n        this.progresssteps[i].classList.toggle(\"echeck2018__form__progress__page--checked\", i < idx || (status === \"success\" && i === idx));\n\n      this.progresssteps[i].classList.toggle(\"echeck2018__form__progress__page--failed\", status === \"failed\" && i === idx);\n    });\n\n    if (status === \"failed\") {\n      this.progressindicator.style.width = (idx * 100 / (this.progresssteps.length - 1)) + \"%\";\n    } else {\n      const stepsize = 100 / (this.progresssteps.length - 1);\n      let progress = idx * stepsize;\n      if (current.dataset.groupid) {\n        const subpages = dompack.qSA(\".echeck2018__page[data-groupid='\" + current.dataset.groupid + \"']\");\n        const subcount = subpages.length;\n        if (subcount > 1) {\n          const subidx = subpages.findIndex(_ => _.classList.contains(\"echeck2018__page--selected\"));\n          if (subidx > 0)\n            progress += (stepsize * subidx / subcount);\n        }\n      }\n\n      if (progress === 0)\n        this.progressindicator.style.width = \"Calc(\" + progress + \"% + 30px)\";\n      else\n        this.progressindicator.style.width = progress + \"%\";\n    }\n\n    this.progressidx = idx;\n  }\n\n  registerHandlers() {\n    dompack.register(\".echeck2018__prevbutton\", node => node.addEventListener(\"click\", () => this.prevPage()));\n    dompack.register(\".echeck2018__nextbutton\", node => node.addEventListener(\"click\", () => this.nextPageLocked()));\n  }\n\n  selectPage(pageid: string, actiontype?: string) {\n    let current = dompack.qS(this.node, \".echeck2018__page--selected\");\n    if (current)\n      current.classList.remove(\"echeck2018__page--selected\");\n\n    const pos = this.history.indexOf(pageid);\n    if (pos === -1)\n      this.history.push(pageid);\n    else\n      this.history = this.history.slice(0, pos + 1);\n\n    current = this.getPageById(pageid);\n    current.classList.add(\"echeck2018__page--selected\");\n\n    const progressstatus = actiontype && actiontype === \"sendresumptionlink\" ? \"success\" : \"\";\n    this.updateProgressIndicator(current, progressstatus);\n\n    if (this.termsnode) // Show terms in footer if on diploma page\n      this.termsnode.hidden = current.dataset.pageid !== \"diploma\";\n\n    dompack.qR(\".echeck2018__prevbutton\").style.display = this.history.length <= 1 || actiontype === \"sendresumptionlink\" ? \"none\" : \"\";\n    dompack.qR<HTMLButtonElement>(\".echeck2018__nextbutton\").disabled = Boolean(current.dataset.disablenextaction);\n  }\n\n  getPageById(pageid: string) {\n    return dompack.qR(this.node, \".echeck2018__page[data-pageid=\\\"\" + pageid + \"\\\"]\");\n  }\n\n  getPageNextAction(page: HTMLElement, ignoreanswers?: boolean) {\n    let nextaction = page.dataset.nextaction;\n    const selectedoption = dompack.qS(page, \"input[type=radio]:checked,option:checked\");\n\n    if (!ignoreanswers && selectedoption && selectedoption.dataset.nextaction)\n      nextaction = selectedoption.dataset.nextaction;\n\n    if (!nextaction)\n      throw new Error(\"Page \" + page.dataset.pageid + \" does not have a nextaction!\");\n\n    return JSON.parse(nextaction);\n  }\n\n  getCurrentSkipGroups() {\n    const retval: string[] = [];\n    this.history.forEach(pageid => {\n      const page = this.getPageById(pageid);\n      const nextaction = this.getPageNextAction(page);\n      if (nextaction.skipgroups)\n        retval.push(...nextaction.skipgroups);\n    });\n    return retval;\n  }\n\n  prevPage() {\n    // First some resets\n    if (this.donepage) {\n      this.donepage.remove();\n      this.donepage = null;\n    }\n    this.node.classList.remove(\"echeck2018__form--failed\");\n\n    if (this.history.length <= 1)\n      return;\n    this.selectPage(this.history[this.history.length - 2]);\n    this.node.scrollIntoView();\n  }\n\n  getNodesFromHTMLContent(htmlstring: string) {\n    const parser = new DOMParser();\n    const contentnode = parser.parseFromString(htmlstring, 'text/html');\n    return dompack.qSA(contentnode, \"body > *\");\n  }\n\n  async nextPageLocked() {\n    const nextpagelock = dompack.flagUIBusy();\n    try {\n      return await this.nextPage();\n    } finally {\n      nextpagelock.release();\n    }\n  }\n\n  async nextPage() {\n    const current = dompack.qR(this.node, \".echeck2018__page--selected\");\n    if (!(await this.validate(current)).valid) {\n      console.log(\"Validation failed\");\n      return;\n    }\n\n    let counter = 0;\n    let nextaction = this.getPageNextAction(current);\n\n    this.node.scrollIntoView();\n\n    const baseforminfo = {\n      guid: this.settings.formentryguid,\n      history: this.history,\n      referralcode: getEcheckReferral(),\n      referralinfo: getReferralInfo()\n    };\n\n\n    for (; ;) {\n      if (++counter === maxloops)\n        throw new Error(\"Infinite loop in form pages path\");\n      if (!nextaction)\n        throw new Error(\"Looped without setting next action!\");\n\n      const action = nextaction;\n      nextaction = null;\n\n      switch (action.type) {\n        case \"sendresumptionlink\":\n          {\n            await this.invokeRPC(\"SendEmailWithLink\");\n            this.selectPage(action.pageid, action.type);\n            return;\n          }\n        case \"done\":\n          {\n            const submitdata =\n            {\n              ...baseforminfo,\n              finished: true,\n              resultcode: action.resultcode\n            };\n\n            const submitresult = await this.submit(submitdata) as {\n              result: {\n                contents: string;\n                notyetquestions: Array<{ question: string; answer: string }>;\n                guid: string;\n              };\n            };\n\n            window.dataLayer.push(\n              {\n                event: 'formulier-submit',\n                form: action.resultcode.toUpperCase() !== 'EL' ? 'eligibilitycheck-failed'\n                  : submitresult.result.notyetquestions.length ? 'eligibilitycheck-notyet'\n                    : 'eligibilitycheck-positive',\n                form_programme: document.documentElement.dataset.programme,\n                form_diploma: this.data.diploma,\n                form_intent: this.data.intent,\n                form_resultcode: action.resultcode,\n                echeck_notyetquestions: submitresult.result.notyetquestions\n              });\n\n            const resultstatus = action.resultcode.toUpperCase() === 'EL' ? \"success\" : \"failed\";\n\n            this.donepage = <div class=\"echeck2018__page echeck2018__page--selected\" data-pageid={\"resultpage-\" + resultstatus} />;\n            this.donepage!.append(...this.getNodesFromHTMLContent(submitresult.result.contents));\n            dompack.registerMissed(this.donepage!);\n            this.history.push(\"resultpage-\" + resultstatus);\n            current.after(this.donepage!);\n            current.classList.remove(\"echeck2018__page--selected\");\n\n            this.node.classList.add(\"echeck2018__form--\" + resultstatus);\n            this.updateProgressIndicator(current, resultstatus);\n\n            crm.learnedAboutUser(submitresult.result.guid, this.data.firstname);\n            return;\n          }\n        case \"nextpage-nostore\":\n        case \"nextpage\":\n        case \"nextpage-modalrpc\":\n          {\n            if (action.informecheckstart) {\n              window.dataLayer.push(\n                {\n                  event: 'formulier-submit',\n                  form: 'eligibilitycheck-enter',\n                  form_programme: document.documentElement.dataset.programme,\n                  form_diploma: this.data.diploma,\n                  form_intent: this.data.intent\n                });\n            }\n            if (action.type !== \"nextpage-nostore\") {\n              const data =\n              {\n                ...baseforminfo,\n                finished: false\n              };\n\n              if (action.type === \"nextpage-modalrpc\") { //this is used straight after entering NAW - blocking reserving an ID ?\n                const res = await this.invokeRPC(\"storeData\", data) as { guid: string };\n                this.settings.formentryguid = res.guid;\n              } else\n                void this.invokeBackgroundRPC(\"storeData\", data).then((res: unknown) => this.settings.formentryguid = (res as { guid: string }).guid);\n            }\n\n            const skipgroups = this.getCurrentSkipGroups();\n            const nextpage = this.getPageById(action.pageid);\n\n            const groupid = nextpage.dataset.groupid;\n            if (!groupid || !skipgroups.includes(groupid)) {\n              this.selectPage(action.pageid);\n              return;\n            }\n\n            nextaction = this.getPageNextAction(nextpage, true);\n            if (counter >= maxloops - 20)\n              console.log(\"skipping to page \" + nextaction.pageid);\n\n          } break;\n        case \"noecheck\":\n          {\n            /* Just fetch page */\n            const gotourl = new URL(location.href);\n            gotourl.searchParams.set('nocheck', action.diploma);\n\n            const res = await this.getNoCheckPage(gotourl.toString());\n            if (res && res.length) {\n              this.donepage = <div class=\"echeck2018__page echeck2018__page--selected\" data-pageid=\"noecheck\" />;\n              this.donepage!.append(...res);\n              current.after(this.donepage!);\n              current.classList.remove(\"echeck2018__page--selected\");\n\n              this.history.push(\"noecheck\");\n              dompack.qR(\".echeck2018__prevbutton\").style.display = \"\";\n\n              this.node.classList.add(\"echeck2018__form--failed\");\n              this.updateProgressIndicator(current, \"failed\");\n            } else\n              location.href = gotourl.toString();\n            return;\n          }\n        case \"selectprogram\":\n          {\n            const programs = [this.data.program1, this.data.program2, this.data.program3].filter(isTruthy).join(\",\");\n            console.log(this.data.program1, this.data.program2, this.data.program3, this.data);\n            const gotourl = new URL(location.href);\n            if (programs !== gotourl.searchParams.get(\"programs\")) {\n              gotourl.searchParams.set(\"programs\", programs);\n              navigateTo(gotourl.toString());\n              return;\n            }\n            nextaction = { type: 'nextpage-nostore', pageid: 'diploma' }; //go to the next page, generally diploma\n            break;\n          }\n        default:\n          {\n            throw new Error(\"unknown action \" + action.type);\n          }\n      }\n    }\n  }\n\n  async getNoCheckPage(url: string) {\n    let response;\n    try {\n      response = await fetch(url, { cache: 'reload' });\n    } catch (e) { }\n\n    if (!response || response.status !== 200) {\n      console.error(\"Error loading page: \" + url);\n      return null;\n    }\n\n    const content = await response.text();\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(content, 'text/html');\n    if( document.documentElement.classList.contains(\"utwente--ws2026\") )\n      return dompack.qSA(doc, \".page-content > *:not(.wh-form__buttongroup):not(.echeck2018__form__progress)\");\n\n    return dompack.qSA(doc, \"main > *:not(.wh-form__buttongroup)\");\n  }\n}\n\nforms.registerHandler(\"utwente_voorlichting:echeck2018\", node => new EcheckForm(node));\n\ncheckEcheckReferral();\n","import * as dompack from 'dompack';\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as dialogapi from 'dompack/api/dialog';\nimport { qS, qSA, qR } from '@webhare/dompack';\nimport * as forms from \"@mod-publisher/js/forms\";\nimport * as whintegration from \"@mod-system/js/wh/integration\";\n\nimport './opendagen.scss';\nimport './opendagen.lang.json';\nimport \"../ws2016_voorlichting/activities/activityform.scss\";\n\nimport { getTid, getHTMLTid } from \"@mod-tollium/js/gettid\";\nimport type { FormSubmitMessage } from '@mod-publisher/js/forms/formbase';\nimport { UTVoorlichtingRPCForm } from '@mod-utwente_voorlichting/js/shared/forms';\nimport { pushToDataLayer } from '@webhare/frontend';\nimport { html } from '@webhare/dompack/src/html';\nimport { throwError } from '@webhare/std';\n\nlet formapitype = '';\n\nfunction toggleClass(el: HTMLElement, classname: string, setTo: boolean) {\n  const current = el.classList.contains(classname);\n  if (current === setTo)\n    return;\n  // console.log(\"toggle\", classname, \"to\", setTo, \"on\", el);\n  el.classList.toggle(classname);\n}\n\nfunction toggleDisabled(el: HTMLInputElement | HTMLOptionElement, setTo: boolean) {\n  if (el.disabled === setTo)\n    return;\n  // console.log(\"toggle disabled to\", setTo, \"on\", el);\n  el.disabled = setTo;\n}\n\nasync function runConfirmResignup() {\n  return dialogapi.runMessageBox(\n    <div>\n      <p>{getTid('utwente_voorlichting:widgets.openday.alreadysignedup-1')}</p>\n      <p><b>{getTid('utwente_voorlichting:widgets.openday.alreadysignedup-2')}</b></p>\n    </div>,\n    [\n      { result: \"yes\", title: getTid(\"utwente_voorlichting:widgets.openday.alreadysignedup-yes\") },\n      { result: \"no\", title: getTid(\"utwente_voorlichting:widgets.openday.alreadysignedup-no\") }\n    ]);\n}\n\ntype EventSelection = {\n  diploma: string | null;\n  rounds: Array<{\n    programme: string;\n    special: string;\n    tag: string | null;\n    select: HTMLSelectElement;\n  }>;\n};\n\n//@ts-expect-error TS doesn't like that our private override\nclass OpenDagenForm extends UTVoorlichtingRPCForm<{\n  programs: number[];\n  themesessions: number[];\n  extrasessions: number[];\n}> {\n  eventselection: EventSelection = { diploma: null, rounds: [] };\n  diplomaselect: HTMLSelectElement;\n  isedit: boolean;\n  origemail: string;\n  isclusterconflict = false;\n  opendaysettings: {\n    questions: string[];\n    apitype: string;\n  };\n  lastselectedcity = '';\n  shortform;\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n    this.shortform = node.hasAttribute(\"data-shortform\");\n    this.diplomaselect = qR<HTMLSelectElement>(node, `select[name=\"diploma.select\"]`);\n    this.opendaysettings = whintegration.config.obj.opendaysettings as typeof this.opendaysettings;\n\n    dompack.qSA(node, '.foldablecontent').forEach(foldablenode => foldablenode.addEventListener(\"click\", evt => {\n      if (foldablenode.classList.contains(\"foldablecontent--open\")) { //just opened one?\n        dompack.qSA(node, '.foldablecontent--open').forEach(currentlyopen => {\n          if (currentlyopen !== foldablenode) {\n            dompack.dispatchCustomEvent(currentlyopen, \"ws:foldable-toggle\",\n              {\n                bubbles: true,\n                cancelable: false\n              });\n          }\n        });\n      }\n    }));\n\n    this.isedit = this.node.classList.contains(\"openday--isedit\");\n\n    this.origemail = (node.elements.namedItem(\"wrd_contact_email\") as HTMLInputElement).value;\n    if (this.node.dataset.guid)\n      crm.learnedAboutUser(this.node.dataset.guid, (node.elements.namedItem(\"wrd_firstname\") as HTMLInputElement).value);\n\n    this.node.addEventListener('change', evt => this.updateFormOptions(), true);\n    qSA(this.node, '.openday--js-cancel').forEach(el => el.addEventListener('click', () => this.onODCancel()));\n\n    this.prefill();\n    (this.elements.namedItem(\"extrainfo_schoolcity_fromlist\") as HTMLElement | null)?.addEventListener(\"change\", () => this.updateSchoolList());\n\n    const firstpagebutton = qS<HTMLButtonElement>('[data-wh-form-action=\"next\"]');\n    if (firstpagebutton) {\n      firstpagebutton.addEventListener('click', () => {\n        if (!firstpagebutton.disabled) {\n          crm.triggerUserBeacon('opendaysignup-' + formapitype + '-firstpage');\n          crm.clearUserBeacon('opendaysignup-' + formapitype + '-cancelled');\n        }\n      });\n    }\n\n    this.updateFormOptions();\n    formapitype = this.node.dataset.apitype!;\n    document.documentElement.classList.add('openday--type-' + formapitype);\n    crm.triggerUserBeacon('opendaysignup-' + formapitype + '-impression');\n  }\n\n  updateSchoolList() {\n    const selectedcity = (this.elements.namedItem(\"extrainfo_schoolcity_fromlist\") as HTMLSelectElement | null)!.value;\n    const schoolname = this.elements.namedItem(\"extrainfo_schoolname_fromlist\") as HTMLSelectElement;\n    if (selectedcity !== this.lastselectedcity) {\n      this.lastselectedcity = selectedcity;\n      schoolname.value = '';\n    }\n    for (const opt of qSA<HTMLOptionElement>(schoolname, 'option')) {\n      const show = !opt.dataset.city || opt.dataset.city === selectedcity;\n      opt.classList[show ? \"remove\" : \"add\"](\"openday--hide\");\n      opt.disabled = !show;\n    }\n  }\n\n  async gotoPage(idx: number) {\n    if (idx === 1 && this.shortform) {\n      await this.invokeRPC(\"prepShortForm\", crm.getReferralInfo());\n      setTimeout(() => pushToDataLayer({ event: \"onlineopendays-shortform\" }), 1); //send AFTER form content is reported to analytics\n    }\n\n    const result = await super.gotoPage(idx);\n    this.node.scrollIntoView(); //scrollfix\n    return result;\n  }\n\n  _getDestinationPage(pagestate: {\n    pages: HTMLElement[];\n    curpage: number;\n  }, direction: number) {\n    if (pagestate.curpage === 0 && pagestate.pages[0].id === \"opendagen-signuppage-typefirst\" && direction === +1) {\n      //going forward from the typefirst page\n      if (this.data.programs.length === 0 && this.data.themesessions.length === 0 && this.data.extrasessions.length === 0)\n        return 2; //skip the programs page\n    }\n    if (pagestate.curpage === 2 && pagestate.pages[0].id === \"opendagen-signuppage-typefirst\" && direction === -1) {\n      if (this.data.programs.length === 0 && this.data.themesessions.length === 0 && this.data.extrasessions.length === 0)\n        return 0; //skip the programs page\n    }\n    //@ts-expect-error TS doesn't lik invoking private funtions\n    return super._getDestinationPage(pagestate, direction);\n  }\n\n  getDatalayerInfo(): Record<string, string> {\n    const programmes = this.eventselection.rounds.map(val => val.programme).filter(val => Boolean(val));\n    const specials = this.eventselection.rounds.map(val => val.special).filter(val => Boolean(val));\n    const rounds = this.eventselection.rounds.map(val => val.tag).filter(val => Boolean(val));\n    const info: Record<string, string> =\n    {\n      origemail: this.node.dataset.origemail || '',\n      ischange: this.node.dataset.origemail ? 'true' : 'false',\n      //compatibility with currently ill-implemented gtm code\n      form_programme1_code: programmes.length > 0 ? programmes[0] : '',\n      form_programme2_code: programmes.length > 1 ? programmes.slice(1).join(',') : '',\n      form_special1_code: specials.join(','),\n      form_rounds1_code: rounds.join(','),\n\n      form_allprogrammes: programmes.join(','),\n      form_allspecials: specials.join(','),\n      form_allrounds: rounds.join(',')\n    };\n    for (const keyname of this.getFormElementNames()) {\n      let toread = this.elements.namedItem(keyname);\n      if (!toread)\n        continue;\n      if (toread instanceof RadioNodeList && toread.length && ((toread[0] as HTMLInputElement).type === 'radio' || (toread[0] as HTMLInputElement).type === 'checkbox')) // it's a radio/checkbox group\n        toread = (Array.from(toread) as HTMLInputElement[]).filter(node => node.checked)[0];\n\n      if (!toread || !(toread instanceof HTMLElement))\n        continue;\n\n      if (toread instanceof HTMLInputElement && (toread.type === 'radio' || toread.type === 'checkbox') && !toread.checked)\n        continue;\n      if (toread.closest('.openday--hide'))\n        continue;\n\n      if (toread instanceof HTMLSelectElement && toread.options && toread.selectedIndex >= 0)\n        toread = toread.options[toread.selectedIndex];\n\n      const setvalue = (toread instanceof HTMLInputElement && toread.dataset && toread.dataset.tag) ? toread.dataset.tag : (toread as HTMLInputElement).value;\n      if (!setvalue)\n        continue;\n\n      info['form_' + keyname] = setvalue;\n    }\n    return info;\n  }\n\n  formToDatalayer(formadd: string) {\n    if (!window.dataLayer)\n      return;\n\n    const layerobj = this.getDatalayerInfo();\n    layerobj.event = \"formulier-submit\";\n    layerobj.form = formapitype + (formadd || '');\n    window.dataLayer.push(layerobj);\n  }\n\n  prefill() {\n    const url = new URL(location.href);\n\n    if (this.diplomaselect.options.length === 1) {\n      //if there's only one diploma option, just select it (eg HBO)\n      dompack.changeValue(this.diplomaselect, this.diplomaselect.options[0].value);\n    } else {\n      if (this.diplomaselect.value || !url.searchParams.get('diploma'))\n        return; //not a prefill\n\n      const toselect = Array.from(this.diplomaselect.options).filter(opt => opt.dataset.diplomatag === url.searchParams.get('diploma'));\n      if (!toselect.length)\n        return;\n\n      dompack.changeValue(this.diplomaselect, toselect[0].value);\n    }\n  }\n\n  getRoundPulldowns() {\n    return qSA<HTMLSelectElement>(this.node, 'select').filter(select => select.name.match(/^roundpulldown/) && !select.closest('.openday--hide'));\n  }\n\n  updateFormOptions() {\n    this.eventselection = { diploma: null, rounds: [] };\n\n    //reset error messages\n    qSA('.openday__clusterwarning').forEach(node => node.style.display = 'none');\n\n    if (this.diplomaselect.options.length <= 0) //no form\n      return;\n\n    document.documentElement.classList.add('openday--formopen');\n\n    //get diploma and remove days by their diplomafilter. gather available days. clear unavailable days checkbox\n    this.eventselection.diploma = this.diplomaselect.selectedOptions[0]?.dataset.diplomatag || null; //it's important for this to be 'null' during initial set or setupVisibleFields will not run at first rendering\n\n    for (const round of qSA(this.node, '.openday__round'))\n      this.updateRoundOptionsVisibility(round);\n    for (const roundgroup of qSA(this.node, '.openday__roundgroup'))\n      toggleClass(roundgroup, \"openday--hide\", !roundgroup.querySelector('.openday__round:not(.openday--hide)'));\n\n    const rounds = qSA('.openday__round:not(.openday--hide)');\n    toggleClass(qR('#opendagen-optionstree'), \"openday--hide\", rounds.length === 0);\n\n    this.eventselection.rounds = [];\n\n    //These are the radio options that match the rounds, if there are alternative options\n    const roundshowupboxes = this.getRoundPulldowns();\n    roundshowupboxes.forEach(select => {\n      const current = select.options[select.selectedIndex];\n      if (current)\n        this.eventselection.rounds.push({\n          programme: parseInt(current.dataset.programmeid || \"\") ? current.dataset.tag ?? '' : '',\n          special: parseInt(current.dataset.special || \"\") ? current.dataset.tag ?? '' : '',\n          tag: current.dataset.tag || '',\n          select: select\n        });\n    });\n  }\n\n  updateRoundOptionsVisibility(round: HTMLElement) {\n    const selectnode = qR<HTMLSelectElement>(round, 'select');\n    const enable = true;\n\n    let anyvisitvisible = false; //any 'visit' visible (eg anything but 'not coming')\n\n    for (const opt of selectnode.querySelectorAll('option')) {\n      const show = enable\n        && !opt.hidden //dompack pulldown is used and doesn't support hidden, so we'll manually consider it\n        && (!opt.dataset.diplomafilter\n          || JSON.parse(opt.dataset.diplomafilter).includes(this.eventselection.diploma)\n        );\n      if (opt.value && show && !anyvisitvisible) {\n        anyvisitvisible = true;\n      }\n\n      toggleClass(opt, \"openday--hide\", !show);\n      toggleDisabled(opt, Boolean(!show || opt.dataset.isfull));\n    }\n\n    for (const optgroup of selectnode.querySelectorAll('optgroup')) {\n      const show = Boolean(optgroup.querySelector('option:not(.openday--hide)'));\n      toggleClass(optgroup, \"openday--hide\", !show);\n    }\n\n    //is current option hidden?\n    if (selectnode.options[selectnode.selectedIndex] && selectnode.options[selectnode.selectedIndex].classList.contains('openday--hide')) {\n      const toselect = selectnode.querySelector<HTMLOptionElement>('option:not(.openday--hide)');\n      if (toselect)\n        selectnode.value = toselect.value;\n    }\n\n    if (this.node.elements.namedItem(\"programs\")) { //type first mode\n      // https://gitlab.webhare.com/utwente/utwente_base/-/work_items/2930#note_277644\n      // rounds should always be visible, even if nothing available\n      const fieldLine = selectnode.closest<HTMLDivElement>('.wh-form__fieldline')!;\n      if (!anyvisitvisible) {\n        if (!fieldLine.parentElement!.querySelector(\".openday__nooptionsmessage\"))\n          fieldLine.parentElement!.prepend( //mimick the pulldown layout as close as possible - https://gitlab.webhare.com/utwente/utwente_base/-/work_items/2930#note_278875\n            html('div', { className: \"openday__nooptionsmessage ss-main ss-disabled\" },\n              [html('div', { className: \"ss-values\" },\n                [html('div', { className: \"ss-single\", textContent: getTid('utwente_voorlichting:widgets.openday.roundpulldown-nooptions') })])]));\n        fieldLine.style.display = \"none\";\n      } else {\n        fieldLine.parentElement!.querySelector(\".openday__nooptionsmessage\")?.remove();\n        fieldLine.style.display = \"\";\n      }\n    } else {\n      toggleClass(round, \"openday--hide\", !anyvisitvisible);\n    }\n  }\n\n  isAnyRoundSelected() {\n    const roundshowupboxes = this.getRoundPulldowns();\n    return roundshowupboxes.length === 0 || roundshowupboxes.filter(select => select.value).length > 0;\n  }\n\n  checkRoundQuestionsClusters(rounds: EventSelection[\"rounds\"]) {\n    const programmes: HTMLOptionElement[] = [];\n\n    rounds.forEach(round => {\n      const selection = round.select.options[round.select.selectedIndex];\n      if (selection && selection.dataset.programmeid)\n        programmes.push(selection);\n    });\n\n    this.verifyClustering(programmes);\n  }\n\n  verifyClustering(programmes: HTMLOptionElement[]) {\n    const checkedprogrammes = [];\n    this.isclusterconflict = false;\n    for (const opt of programmes) {\n      if (opt.dataset.clusteredwith) {\n        const clusteredwith = JSON.parse(opt.dataset.clusteredwith);\n        for (const programme of checkedprogrammes)\n          if (clusteredwith.includes(parseInt(programme.dataset.programmeid || ''))) {\n            const roundNode = opt.closest('.openday__round') ?? throwError(\"round node not found\");\n            let usenode = roundNode.querySelector<HTMLElement>('.openday__clusterwarning');\n            if (!usenode) {\n              usenode = html('div', { className: \"openday__clusterwarning\" });\n              roundNode.appendChild(usenode);\n            }\n\n            if (this.opendaysettings.apitype === 'campusexperience')\n              usenode.textContent = getTid('utwente_voorlichting:widgets.openday.programmeinclusterwith_campusexperience', programme.textContent);\n            else\n              usenode.textContent = getTid('utwente_voorlichting:widgets.openday.programmeinclusterwith', programme.textContent);\n\n            usenode.style.display = 'block';\n            this.isclusterconflict = true;\n            return;\n          }\n      }\n      checkedprogrammes.push(opt);\n    }\n  }\n\n  onSubmitFailed(errors: FormSubmitMessage[], result: unknown) {\n    if (errors.length === 1 && errors[0].name === \"wrd_contact_email\" && (errors[0] as { metadata: { verifyresub: string } }).metadata.verifyresub) {\n      //We're being rejected because the email address is already known\n      void runConfirmResignup().then(res => {\n        if (res === \"yes\")\n          void this.validateAndSubmit({\n            verifyresub: (errors[0] as { metadata: { verifyresub: string } }).metadata.verifyresub\n          });\n      });\n      return;\n    }\n    super.onSubmitFailed(errors, result);\n  }\n\n  onSubmitSuccess(_result: unknown) {\n    const result = _result as {\n      editlink: string;\n      pdflink: string;\n      firstname: string;\n      guid: string;\n      eventname: string;\n      eventdatetext: string;\n      status: string;\n      schedule: Array<{\n        timerange: string;\n        title: string;\n        scheduleprefix: string;\n      }>;\n    };\n    this.formToDatalayer('-submitregistration');\n    crm.triggerUserBeacon('opendaysignup-' + formapitype + '-signedup');\n    crm.clearUserBeacon('opendaysignup-' + formapitype + '-cancelled');\n\n    //hide pagetabs (if any) ??\n    //this.pagenav.tabs.forEach( node => node.style.display = \"none\");\n\n    document.documentElement.classList.add('openday--signupdone');\n    window.opendaySubmitResult = result; //used by CI\n\n    qSA('.opendag_thankyou').forEach(node => node.innerHTML = getHTMLTid(\"utwente_voorlichting:widgets.openday.thankyou\", result.firstname, result.eventname, result.eventdatetext));\n    qSA('.opendag__programma').forEach(node => {\n      node.innerHTML = '';\n      result.schedule.forEach(scheduleitem => {\n        node.appendChild(dompack.create('div',\n          {\n            className: \"opendag__programmaitem\",\n            childNodes: [\n              dompack.create(\"div\", { className: \"opendag__timerange\", textContent: getTid(\"utwente_voorlichting:widgets.openday.timerange\", scheduleitem.timerange) }),\n              dompack.create(\"div\", { className: \"opendag__schedtitle\", textContent: (scheduleitem.scheduleprefix ? scheduleitem.scheduleprefix + \" \" : \"\") + scheduleitem.title })\n            ]\n          }));\n      });\n    });\n\n    if (result.guid)\n      crm.learnedAboutUser(result.guid, result.firstname);\n\n    if (result.editlink)\n      console.log('edit url', result.editlink);\n    if (result.pdflink)\n      console.log('eticket url', result.pdflink);\n  }\n\n  async onODCancel() {\n    if (await dialogapi.runMessageBox(getTid(\"utwente_voorlichting:widgets.openday.confirmcancel\"),\n      [\n        { result: \"yes\", title: getTid(\"utwente_base:site-common.texts.yes\") },\n        { result: \"no\", title: getTid(\"utwente_base:site-common.texts.no\") }\n      ]) !== 'yes')\n      return;\n\n    const lock = dompack.flagUIBusy({ modal: true });\n    this.formToDatalayer('-cancelregistration');\n    await this.invokeRPC('cancelRegistration');\n\n    crm.triggerUserBeacon('opendaysignup-' + formapitype + '-cancelled');\n    crm.clearUserBeacon('opendaysignup-' + formapitype + '-firstpage');\n    crm.clearUserBeacon('opendaysignup-' + formapitype + '-signedup');\n\n    lock.release();\n    dialogapi.runMessageBox(getTid(\"utwente_voorlichting:widgets.openday.cancelled\"), [], { allowcancel: false });\n  }\n}\n\n//@ts-expect-error TS doesn't like that we're registering a handler with a class that has private overrides\nforms.registerHandler(\"utwente_voorlichting:opendays\", node => new OpenDagenForm(node));\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/webfeatures/opendagen/opendagen.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_voorlichting\",\"nl\",{\"widgets\":{\"openday\":{\"alreadysignedup-1\":\"Je bent met dit e-mailadres al aangemeld voor dit evenement. Als je je opnieuw aanmeldt, overschrijven we de bestaande aanmelding.\",\"alreadysignedup-2\":\"Wil je je aanmelding overschrijven?\",\"alreadysignedup-no\":\"Nee, niet overschrijven\",\"alreadysignedup-yes\":\"Ja, overschrijven\",\"btn_confirm\":\"Bevestigen\",\"btn_nextpage\":\"Volgende\",\"btn_previouspage\":\"Vorige\",\"cancelled\":\"Je registratie is verwijderd.\",\"cancellink\":\"Aanmelding verwijderen\",\"chooseaday\":\"Kies een dag\",\"chooseeducation\":\"Kies je opleidingsniveau\",\"choosepresentation\":\"Kies een presentatie\",\"chooseprogrammes\":\"Kies een opleiding\",\"chooseprograms\":\"Van welke opleiding(en) wil je een presentatie volgen?\",\"chooseqasession\":\"Kies een Q&A sessie\",\"choosevwoclass\":\"- Kies je klas -\",\"class\":\"Klas\",\"confirmcancel\":\"Weet je zeker dat je je registratie wil verwijderen?\",\"confirmcancel_no\":\"Nee\",\"confirmcancel_ok\":\"Ok\",\"confirmcancel_yes\":\"Ja\",\"contactme\":\"Neem contact met mij op voor reisinformatie\",\"dayprogramme\":\"Jouw programma voor deze dag\",\"differentprogramlink\":\"Ik wil iets wijzigen\",\"diploma\":\"Huidige (of recent afgeronde) opleiding\",\"extrainfo_resume\":\"Upload hier je cijferlijst. We hebben dit nodig om je opleidingsachtergrond te beoordelen. Vermeld hierbij duidelijk in welke klas je nu zit, op welke school je zit. Vakken en bijbehorende cijfers horen er uiteraard ook op te staan. Zonder je cijferlijst kunnen we je aanmeldverzoek helaas niet in behandeling nemen.\",\"extrainfo_why\":\"Waarom wil je Technology and Liberal Arts & Sciences (ATLAS) studeren aan het University College Twente? Geef ons een korte motivatie.\",\"extras\":[\"Let op: maximaal \",1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"persoon\"],\"subselse\":[\"personen\"]},\".\"],\"extras_title\":\"Hoeveel personen neem je mee?\",\"extrasessions\":\"Kies overige activiteiten\",\"extrasessions_group\":\"Overige activiteiten\",\"full\":\"vol\",\"group-extra\":\"Extra sessies en activiteiten\",\"group-presentation\":\"Opleidingspresentaties\",\"location\":\"| Enschede\",\"maxtwoprogrames\":\"Je kunt maximaal twee voorlichtingsrondes bezoeken\",\"myinterests\":\"Mijn interesses\",\"myprogramme\":\"Mijn programma\",\"nochoiceyet\":\"Ik kies later\",\"personaldata\":\"Mijn gegevens\",\"personaldatatitle\":\"Mijn persoonlijke gegevens\",\"personalinfo\":\"Persoonlijke info\",\"profile\":\"Profiel\",\"program1\":\"Keuze 1\",\"program2\":\"Keuze 2\",\"program_notsureyet\":\"Ik weet het nog niet zeker\",\"programmefull\":\"Door de drukte is het helaas niet mogelijk beide programma's te bezoeken. Wijzig je selectie.\",\"programmeinclusterwith\":[\"De gekozen opleiding heeft een gecombineerde presentatie met \",1,\". Daarom kun je deze opleidingen niet individueel bezoeken.\"],\"programmeinclusterwith_campusexperience\":[\"Deze opleiding heeft een gezamenlijke tour met \",1,\". Kies een andere opleiding.\"],\"programs\":\"Kies opleidingen\",\"programs_group\":\"Opleidingen\",\"register\":\"Aanmelden\",\"registration\":\"Aanmelden\",\"request_visitcampus\":\"Ik wil ook de campus bezoeken.\",\"roundpulldown-nooptions\":\"Niet beschikbaar op basis van je selectie\",\"school\":\"Wat is de naam van je school?\",\"school_city\":\"In welke plaats zit je nu op school?\",\"selectcity\":\"- Kies je stad -\",\"selectpresentation\":\"- Kies presentatie -\",\"selectprogramme\":\"- Kies opleiding -\",\"selectqasession\":\"- Kies een Q&A sessie -\",\"selectroundoption\":\"Maak een keuze (optioneel)\",\"selectroundoption-required\":\"Maak een keuze (verplicht)\",\"selectschool\":\"- Kies je school -\",\"setupday\":\"Stel je dagprogramma samen\",\"specials\":\"Specials\",\"thanks1\":\"Leuk dat je komt\",\"thanks2\":\"! Je hebt je aangemeld voor\",\"thankyou\":[\"Je bent aangemeld. Leuk dat je naar onze campus in Enschede komt, \",1,\"!\"],\"themesessions\":\"Kies themasessies\",\"themesessions_group\":\"Themasessies\",\"timerange\":[1,\" uur\"]}}});\nregisterTexts(\"utwente_voorlichting\",\"en\",{\"widgets\":{\"openday\":{\"alreadysignedup-1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-2\":\"Would you like to overwrite your registration?\",\"alreadysignedup-no\":\"No, do not overwrite\",\"alreadysignedup-yes\":\"Yes, overwrite\",\"btn_confirm\":\"Confirm\",\"btn_nextpage\":\"Next\",\"btn_previouspage\":\"Previous\",\"cancelled\":\"Your registration has been cancelled.\",\"cancellink\":\"Cancel registration\",\"chooseaday\":\"Choose a day\",\"chooseeducation\":\"Choose your level of education\",\"choosepresentation\":\"Choose a presentation\",\"chooseprogrammes\":\"Choose a programme\",\"chooseprograms\":\"Of which programme(s) would you like to attend a presentation?\",\"chooseqasession\":\"Choose a Q&A session\",\"choosevwoclass\":\"- Choose your class -\",\"class\":\"Class\",\"confirmcancel\":\"Are you sure you want to cancel your registration?\",\"confirmcancel_no\":\"No\",\"confirmcancel_ok\":\"Ok\",\"confirmcancel_yes\":\"Yes\",\"contactme\":\"Please contact me about travel information\",\"dayprogramme\":\"Your schedule for this day\",\"differentprogramlink\":\"I want to change something\",\"diploma\":\"Current (or recently completed) education\",\"extrainfo_resume\":\"Upload your grade list or transcript. We need this document to check your educational background. Your transcript should clearly state what your current year is, high school name, courses being taken and of course grades should also be clearly stated on the transcript. Without sending the grade list you cannot be considered for the In_Sight Day.\",\"extrainfo_why\":\"Why are you interested in University College Twente and BSc. Technology and Liberal Arts & Sciences (ATLAS)? Please give us a short motivation.\",\"extras\":[\"Please note: max \",1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"person\"],\"subselse\":[\"persons\"]},\".\"],\"extras_title\":\"How many people will accompany you?\",\"extrasessions\":\"Choose other activities\",\"extrasessions_group\":\"Other activities\",\"full\":\"full\",\"group-extra\":\"Extra sessions and activities\",\"group-presentation\":\"Study presentations\",\"location\":\"| Enschede | The Netherlands\",\"maxtwoprogrames\":\"You can visit a maximum of two programmes.\",\"myinterests\":\"My interests\",\"myprogramme\":\"My programme\",\"nochoiceyet\":\"I want to choose later\",\"personaldata\":\"My information\",\"personaldatatitle\":\"My personal information\",\"personalinfo\":\"Personal info\",\"profile\":\"Profile\",\"program1\":\"First programme\",\"program2\":\"Second programme\",\"program_notsureyet\":\"I'm not sure yet\",\"programmefull\":\"Because of the high number of registrations it's unfortunately not possible to visit both programmes. Please choose another programme.\",\"programmeinclusterwith\":[\"The chosen programme has a combined presentation with \",1,\". Therefore, you cannot visit these programmes seperately.\"],\"programmeinclusterwith_campusexperience\":[\"This programme has a combined tour with \",1,\". Choose another programme.\"],\"programs\":\"Choose programmes\",\"programs_group\":\"Programmes\",\"register\":\"Register\",\"registration\":\"Register\",\"request_visitcampus\":\"I would like to visit the campus in the future. Send me an email when I can sign up for this.\",\"roundpulldown-nooptions\":\"Not available based on your selection\",\"school\":\"What is the name of your current school?\",\"school_city\":\"In what city or town is your school located?\",\"selectcity\":\"- Select your city -\",\"selectpresentation\":\"- Choose presentation -\",\"selectprogramme\":\"- Choose a programme -\",\"selectqasession\":\"- Choose a Q&A session -\",\"selectroundoption\":\"Make a choice (optional)\",\"selectroundoption-required\":\"Make a choice (required)\",\"selectschool\":\"- Select your school -\",\"setupday\":\"Set up your schedule\",\"specials\":\"Specials\",\"thanks1\":\"Great to hear you’ll be coming\",\"thanks2\":\"! You have registered for\",\"thankyou\":[\"You have registered. \",1,\", it's great that you're coming to our campus in Enschede, The Netherlands!\"],\"themesessions\":\"Choose theme sessions\",\"themesessions_group\":\"Theme sessions\",\"timerange\":[1,\" hours\"]}}});\nregisterTexts(\"utwente_voorlichting\",\"de\",{\"widgets\":{\"openday\":{\"alreadysignedup-1\":\"Du bist mit dieser E-Mail Adresse bereits für dieses Event angemeldet. Wenn du dich noch einmal anmeldest, dann wird die erste Registrierung überschrieben.\",\"alreadysignedup-2\":\"Möchtest du deine Registrierung überschreiben?\",\"alreadysignedup-no\":\"Nein, nicht überschreiben\",\"alreadysignedup-yes\":\"Ja, überschreiben\",\"btn_confirm\":\"Bestätigen\",\"btn_nextpage\":\"Weiter\",\"btn_previouspage\":\"Zurück\",\"cancelled\":\"Du hast dich erfolgreich abgemeldet.\",\"cancellink\":\"Abmelden\",\"chooseaday\":\"Wähle einen Tag\",\"chooseeducation\":\"Wähle deine momentane Vorbildung\",\"choosepresentation\":\"Wähle eine Präsentation\",\"chooseprogrammes\":\"Wähle einen Studiengang\",\"chooseprograms\":\"Von welchem/welchen Programm(en) möchten Sie eine Präsentation besuchen?\",\"chooseqasession\":\"Wähle ein Q&A session\",\"choosevwoclass\":\"- Wähle deinen Schuljahrgang -\",\"class\":\"Schuljahrgang\",\"confirmcancel\":\"Möchtest du dich wirklich abmelden?\",\"confirmcancel_no\":\"Nein\",\"confirmcancel_ok\":\"Ok\",\"confirmcancel_yes\":\"Ja\",\"contactme\":\"Ich wünsche eine Kontaktaufnahme der Uni bezüglich Anreiseinformationen\",\"dayprogramme\":\"Dein Programm für diesen Tag\",\"differentprogramlink\":\"Ja, ich möchte etwas anpassen\",\"diploma\":\"Diploma\",\"extrainfo_resume\":[\"Bitte lade deinen Lebenslauf \",{\"t\":\"tag\",\"tag\":\"b\",\"subs\":\"mit deinen letzten Noten\"},\" hoch (alles in einem Dokument). Wir benötigen diese Daten um deine Vorbildung zu beurteilen. Wenn du keinen Lebenslauf abgibst, können wir deine Anmeldung leider nicht beurteilen.\"],\"extrainfo_why\":\"Warum möchtest du Technology and Liberal Arts & Sciences (ATLAS) am University College Twente studieren? Bitte gebe uns eine kurze Begründung.\",\"extras\":[\"Maximum \",1,\".\"],\"extras_title\":\"Wie viele Besucher/Freunde begleiten dich?\",\"extrasessions\":\"Choose other activities\",\"extrasessions_group\":\"Other activities\",\"full\":\"voll\",\"group-extra\":\"Extra Sessions und Aktivitäten\",\"group-presentation\":\"Studiengang Präsentationen\",\"location\":\"| Enschede | The Netherlands\",\"maxtwoprogrames\":\"Du kannst maximal zwei Informationsrunden besuchen\",\"myinterests\":\"My interests\",\"myprogramme\":\"Mein Programm\",\"nochoiceyet\":\"Ich möchte mich später entscheiden\",\"personaldata\":\"Meine Daten\",\"personaldatatitle\":\"Meine persönlichen Daten\",\"personalinfo\":\"Persönlichen Daten\",\"profile\":\"Profil\",\"program1\":\"Option 1\",\"program2\":\"Option 2\",\"program_notsureyet\":\"Ich bin mir noch nicht sicher\",\"programmefull\":\"Aufgrund hoher Anmeldezahlen ist es leider nicht möglich beide Programmteile zu besuchen. Bitte ändere deine Auswahl.\",\"programmeinclusterwith\":[\"Der gewählte Studiengang präsentiert sich zusammen mit \",1,\". Deswegen kannst du diesen Studiengang nur in dieser Kombination besuchen.\"],\"programmeinclusterwith_campusexperience\":[\"This programme has a combined tour with \",1,\". Choose another programme.\"],\"programs\":\"Programme auswählen\",\"programs_group\":\"Programmes\",\"register\":\"Anmelden\",\"registration\":\"Anmelden\",\"request_visitcampus\":\"Ich möchte den Campus in Zukunft besuchen. Schicken Sie mir eine E-Mail, wenn ich mich dafür anmelden kann.\",\"roundpulldown-nooptions\":\"Aufgrund Ihrer Auswahl nicht verfügbar.\",\"school\":\"Wie heisst deine Schule?\",\"school_city\":\"In welcher Stadt gehst du zur Schule?\",\"selectcity\":\"- Select your city -\",\"selectpresentation\":\"- Wähle Präsentation -\",\"selectprogramme\":\"- Wähle einen Studiengang -\",\"selectqasession\":\"- Wähle ein Q&A session -\",\"selectroundoption\":\"Auswahl treffen (optional)\",\"selectroundoption-required\":\"Auswahl treffen (erforderlich)\",\"selectschool\":\"- Select your school -\",\"setupday\":\"Stelle dein Tagesprogramm zusammen\",\"specials\":\"Specials\",\"thanks1\":\"Wir freuen uns auf deinen Besuch\",\"thanks2\":\"! Du hast dich angemeldet für\",\"thankyou\":[\"Sie haben sich angemeldet. \",1,\", es ist toll, dass Sie an unseren Campus in Enschede in den Niederlanden kommen!\"],\"themesessions\":\"Choose theme sessions\",\"themesessions_group\":\"Theme sessions\",\"timerange\":[1,\" hours\"]}}});\nregisterTexts(\"utwente_voorlichting\",\"es\",{\"widgets\":{\"openday\":{\"alreadysignedup-1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-2\":\"Would you like to overwrite your registration?\",\"alreadysignedup-no\":\"No, do not overwrite\",\"alreadysignedup-yes\":\"Yes, overwrite\",\"btn_confirm\":\"Confirm\",\"btn_nextpage\":\"Next\",\"btn_previouspage\":\"Previous\",\"cancelled\":\"Your registration has been cancelled.\",\"cancellink\":\"Cancel registration\",\"chooseaday\":\"Choose a day\",\"chooseeducation\":\"Choose your level of education\",\"choosepresentation\":\"Choose a presentation\",\"chooseprogrammes\":\"Choose a programme\",\"chooseprograms\":\"Of which programme(s) would you like to attend a presentation?\",\"chooseqasession\":\"Choose a Q&A session\",\"choosevwoclass\":\"- Choose your class -\",\"class\":\"Class\",\"confirmcancel\":\"Are you sure you want to cancel your registration?\",\"confirmcancel_no\":\"No\",\"confirmcancel_ok\":\"Ok\",\"confirmcancel_yes\":\"Yes\",\"contactme\":\"Please contact me about travel information\",\"dayprogramme\":\"Your schedule for this day\",\"differentprogramlink\":\"I want to change something\",\"diploma\":\"Current (or recently completed) education\",\"extrainfo_resume\":\"Upload your grade list or transcript. We need this document to check your educational background. Your transcript should clearly state what your current year is, high school name, courses being taken and of course grades should also be clearly stated on the transcript. Without sending the grade list you cannot be considered for the In_Sight Day.\",\"extrainfo_why\":\"Why are you interested in University College Twente and BSc. Technology and Liberal Arts & Sciences (ATLAS)? Please give us a short motivation.\",\"extras\":[\"Please note: max \",1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"person\"],\"subselse\":[\"persons\"]},\".\"],\"extras_title\":\"How many people will accompany you?\",\"extrasessions\":\"Choose other activities\",\"extrasessions_group\":\"Other activities\",\"full\":\"full\",\"group-extra\":\"Extra sessions and activities\",\"group-presentation\":\"Study presentations\",\"location\":\"| Enschede | The Netherlands\",\"maxtwoprogrames\":\"You can visit a maximum of two programmes.\",\"myinterests\":\"My interests\",\"myprogramme\":\"My programme\",\"nochoiceyet\":\"I want to choose later\",\"personaldata\":\"My information\",\"personaldatatitle\":\"My personal information\",\"personalinfo\":\"Personal info\",\"profile\":\"Profile\",\"program1\":\"First programme\",\"program2\":\"Second programme\",\"program_notsureyet\":\"I'm not sure yet\",\"programmefull\":\"Because of the high number of registrations it's unfortunately not possible to visit both programmes. Please choose another programme.\",\"programmeinclusterwith\":[\"The chosen programme has a combined presentation with \",1,\". Therefore, you cannot visit these programmes seperately.\"],\"programmeinclusterwith_campusexperience\":[\"This programme has a combined tour with \",1,\". Choose another programme.\"],\"programs\":\"Choose programmes\",\"programs_group\":\"Programmes\",\"register\":\"Register\",\"registration\":\"Register\",\"request_visitcampus\":\"I would like to visit the campus in the future. Send me an email when I can sign up for this.\",\"roundpulldown-nooptions\":\"Not available based on your selection\",\"school\":\"What is the name of your current school?\",\"school_city\":\"In what city or town is your school located?\",\"selectcity\":\"- Select your city -\",\"selectpresentation\":\"- Choose presentation -\",\"selectprogramme\":\"- Choose a programme -\",\"selectqasession\":\"- Choose a Q&A session -\",\"selectroundoption\":\"Make a choice (optional)\",\"selectroundoption-required\":\"Make a choice (required)\",\"selectschool\":\"- Select your school -\",\"setupday\":\"Set up your schedule\",\"specials\":\"Specials\",\"thanks1\":\"Great to hear you’ll be coming\",\"thanks2\":\"! You have registered for\",\"thankyou\":[\"You have registered. \",1,\", it's great that you're coming to our campus in Enschede, The Netherlands!\"],\"themesessions\":\"Choose theme sessions\",\"themesessions_group\":\"Theme sessions\",\"timerange\":[1,\" hours\"]}}});\nregisterTexts(\"utwente_voorlichting\",\"it\",{\"widgets\":{\"openday\":{\"alreadysignedup-1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-2\":\"Would you like to overwrite your registration?\",\"alreadysignedup-no\":\"No, do not overwrite\",\"alreadysignedup-yes\":\"Yes, overwrite\",\"btn_confirm\":\"Confirm\",\"btn_nextpage\":\"Next\",\"btn_previouspage\":\"Previous\",\"cancelled\":\"Your registration has been cancelled.\",\"cancellink\":\"Cancel registration\",\"chooseaday\":\"Choose a day\",\"chooseeducation\":\"Choose your level of education\",\"choosepresentation\":\"Choose a presentation\",\"chooseprogrammes\":\"Choose a programme\",\"chooseprograms\":\"Of which programme(s) would you like to attend a presentation?\",\"chooseqasession\":\"Choose a Q&A session\",\"choosevwoclass\":\"- Choose your class -\",\"class\":\"Class\",\"confirmcancel\":\"Are you sure you want to cancel your registration?\",\"confirmcancel_no\":\"No\",\"confirmcancel_ok\":\"Ok\",\"confirmcancel_yes\":\"Yes\",\"contactme\":\"Please contact me about travel information\",\"dayprogramme\":\"Your schedule for this day\",\"differentprogramlink\":\"I want to change something\",\"diploma\":\"Current (or recently completed) education\",\"extrainfo_resume\":\"Upload your grade list or transcript. We need this document to check your educational background. Your transcript should clearly state what your current year is, high school name, courses being taken and of course grades should also be clearly stated on the transcript. Without sending the grade list you cannot be considered for the In_Sight Day.\",\"extrainfo_why\":\"Why are you interested in University College Twente and BSc. Technology and Liberal Arts & Sciences (ATLAS)? Please give us a short motivation.\",\"extras\":[\"Please note: max \",1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"person\"],\"subselse\":[\"persons\"]},\".\"],\"extras_title\":\"How many people will accompany you?\",\"extrasessions\":\"Choose other activities\",\"extrasessions_group\":\"Other activities\",\"full\":\"full\",\"group-extra\":\"Extra sessions and activities\",\"group-presentation\":\"Study presentations\",\"location\":\"| Enschede | The Netherlands\",\"maxtwoprogrames\":\"You can visit a maximum of two programmes.\",\"myinterests\":\"My interests\",\"myprogramme\":\"My programme\",\"nochoiceyet\":\"I want to choose later\",\"personaldata\":\"My information\",\"personaldatatitle\":\"My personal information\",\"personalinfo\":\"Personal info\",\"profile\":\"Profile\",\"program1\":\"First programme\",\"program2\":\"Second programme\",\"program_notsureyet\":\"I'm not sure yet\",\"programmefull\":\"Because of the high number of registrations it's unfortunately not possible to visit both programmes. Please choose another programme.\",\"programmeinclusterwith\":[\"The chosen programme has a combined presentation with \",1,\". Therefore, you cannot visit these programmes seperately.\"],\"programmeinclusterwith_campusexperience\":[\"This programme has a combined tour with \",1,\". Choose another programme.\"],\"programs\":\"Choose programmes\",\"programs_group\":\"Programmes\",\"register\":\"Register\",\"registration\":\"Register\",\"request_visitcampus\":\"I would like to visit the campus in the future. Send me an email when I can sign up for this.\",\"roundpulldown-nooptions\":\"Not available based on your selection\",\"school\":\"What is the name of your current school?\",\"school_city\":\"In what city or town is your school located?\",\"selectcity\":\"- Select your city -\",\"selectpresentation\":\"- Choose presentation -\",\"selectprogramme\":\"- Choose a programme -\",\"selectqasession\":\"- Choose a Q&A session -\",\"selectroundoption\":\"Make a choice (optional)\",\"selectroundoption-required\":\"Make a choice (required)\",\"selectschool\":\"- Select your school -\",\"setupday\":\"Set up your schedule\",\"specials\":\"Specials\",\"thanks1\":\"Great to hear you’ll be coming\",\"thanks2\":\"! You have registered for\",\"thankyou\":[\"You have registered. \",1,\", it's great that you're coming to our campus in Enschede, The Netherlands!\"],\"themesessions\":\"Choose theme sessions\",\"themesessions_group\":\"Theme sessions\",\"timerange\":[1,\" hours\"]}}});\nregisterTexts(\"utwente_voorlichting\",\"xt\",{\"widgets\":{\"openday\":{\"alreadysignedup-1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-2\":\"Would you like to overwrite your registration?\",\"alreadysignedup-no\":\"No, do not overwrite\",\"alreadysignedup-yes\":\"Yes, overwrite\",\"btn_confirm\":\"Confirm\",\"btn_nextpage\":\"Next\",\"btn_previouspage\":\"Previous\",\"cancelled\":\"Your registration has been cancelled.\",\"cancellink\":\"Cancel registration\",\"chooseaday\":\"Choose a day\",\"chooseeducation\":\"Choose your level of education\",\"choosepresentation\":\"Choose a presentation\",\"chooseprogrammes\":\"Choose a programme\",\"chooseprograms\":\"Of which programme(s) would you like to attend a presentation?\",\"chooseqasession\":\"Choose a Q&A session\",\"choosevwoclass\":\"- Choose your class -\",\"class\":\"Class\",\"confirmcancel\":\"Are you sure you want to cancel your registration?\",\"confirmcancel_no\":\"No\",\"confirmcancel_ok\":\"Ok\",\"confirmcancel_yes\":\"Yes\",\"contactme\":\"Please contact me about travel information\",\"dayprogramme\":\"Your schedule for this day\",\"differentprogramlink\":\"I want to change something\",\"diploma\":\"Current (or recently completed) education\",\"extrainfo_resume\":\"Upload your grade list or transcript. We need this document to check your educational background. Your transcript should clearly state what your current year is, high school name, courses being taken and of course grades should also be clearly stated on the transcript. Without sending the grade list you cannot be considered for the In_Sight Day.\",\"extrainfo_why\":\"Why are you interested in University College Twente and BSc. Technology and Liberal Arts & Sciences (ATLAS)? Please give us a short motivation.\",\"extras\":[\"Please note: max \",1,\" \",{\"t\":\"ifparam\",\"p\":1,\"value\":\"1\",\"subs\":[\"person\"],\"subselse\":[\"persons\"]},\".\"],\"extras_title\":\"How many people will accompany you?\",\"extrasessions\":\"Choose other activities\",\"extrasessions_group\":\"Other activities\",\"full\":\"full\",\"group-extra\":\"Extra sessions and activities\",\"group-presentation\":\"Study presentations\",\"location\":\"| Enschede | The Netherlands\",\"maxtwoprogrames\":\"You can visit a maximum of two programmes.\",\"myinterests\":\"My interests\",\"myprogramme\":\"My programme\",\"nochoiceyet\":\"I want to choose later\",\"personaldata\":\"My information\",\"personaldatatitle\":\"My personal information\",\"personalinfo\":\"Personal info\",\"profile\":\"Profile\",\"program1\":\"First programme\",\"program2\":\"Second programme\",\"program_notsureyet\":\"I'm not sure yet\",\"programmefull\":\"Because of the high number of registrations it's unfortunately not possible to visit both programmes. Please choose another programme.\",\"programmeinclusterwith\":[\"The chosen programme has a combined presentation with \",1,\". Therefore, you cannot visit these programmes seperately.\"],\"programmeinclusterwith_campusexperience\":[\"This programme has a combined tour with \",1,\". Choose another programme.\"],\"programs\":\"Choose programmes\",\"programs_group\":\"Programmes\",\"register\":\"Register\",\"registration\":\"Register\",\"request_visitcampus\":\"I would like to visit the campus in the future. Send me an email when I can sign up for this.\",\"roundpulldown-nooptions\":\"Not available based on your selection\",\"school\":\"What is the name of your current school?\",\"school_city\":\"In what city or town is your school located?\",\"selectcity\":\"- Select your city -\",\"selectpresentation\":\"- Choose presentation -\",\"selectprogramme\":\"- Choose a programme -\",\"selectqasession\":\"- Choose a Q&A session -\",\"selectroundoption\":\"Make a choice (optional)\",\"selectroundoption-required\":\"Make a choice (required)\",\"selectschool\":\"- Select your school -\",\"setupday\":\"Set up your schedule\",\"specials\":\"Specials\",\"thanks1\":\"Great to hear you’ll be coming\",\"thanks2\":\"! You have registered for\",\"thankyou\":[\"You have registered. \",1,\", it's great that you're coming to our campus in Enschede, The Netherlands!\"],\"themesessions\":\"Choose theme sessions\",\"themesessions_group\":\"Theme sessions\",\"timerange\":[1,\" hours\"]}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n","import { createElement } from \"dompack/src/create\";\n\n\n// Remove 'on' and other unneeded attributes: we want to define onXxxx attributes which will use addEventListener instead of direct binding to the 'on' property\n// Capitalize<string> removes the ATTRIBUTE_NODE etc properties\ntype CleanupAttributes<T> = {\n  [K in keyof T as K extends `on${string}` | \"childNodes\" | \"style\" | Capitalize<string>\n  ? never\n  // eslint-disable-next-line @typescript-eslint/no-unsafe-function-type\n  : T[K] extends Function\n  ? never\n  : K]?: T[K];\n};\n\ntype EventHandlersFor<E extends CustomElementName | keyof HTMLElementTagNameMap> =\n  E extends keyof HTMLElementTagNameMap ? {\n    on?: { [K in keyof HTMLElementEventMap]?: (this: HTMLElementTagNameMap[E], ev: HTMLElementEventMap[K]) => void; };\n  } : {\n    on?: { [K in keyof HTMLElementEventMap]?: (this: HTMLElement, ev: HTMLElementEventMap[K]) => void; };\n  };\n\ntype CreateAttributesFor<K extends CustomElementName | keyof HTMLElementTagNameMap> = CleanupAttributes<K extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[K] : HTMLElement> & EventHandlersFor<K> & {\n  style?: Partial<CSSStyleDeclaration> & object;\n};\n\ntype CustomElementName = `${string}-${string}`;\n\nexport function html<K extends CustomElementName | keyof HTMLElementTagNameMap>(\n  elementname: K,\n  attributes?: CreateAttributesFor<K>, children?: Array<Node | string>):\n  K extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[K] : HTMLElement {\n  //TODO consider making second parameter optional?\n  const el = createElement(elementname, attributes, false);\n  if (children?.length)\n    el.append(...children);\n  return el as K extends keyof HTMLElementTagNameMap ? HTMLElementTagNameMap[K] : HTMLElement;\n}\n","import * as dompack from '@webhare/dompack';\nimport * as dialogapi from 'dompack/api/dialog';\nimport { UTVoorlichtingRPCForm } from '@mod-utwente_voorlichting/js/shared/forms';\nimport * as forms from \"@mod-publisher/js/forms\";\nimport { getTid } from \"@webhare/gettid\";\nimport './opendays_v2.lang.json';\nimport './opendays_v2.scss';\nimport { getReferralInfo } from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport { navigateTo } from '@webhare/env';\nimport { pushToDataLayer } from '@webhare/frontend';\n\nclass OpenDagenFormV2 extends UTVoorlichtingRPCForm {\n  shortform;\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n    this.shortform = node.hasAttribute(\"data-shortform\");\n\n    pushToDataLayer({ onlineopenday_eventtype: this.node.dataset.onlineopenday_eventtype || '' });\n\n    this.diplomafield?.addEventListener(\"change\", () => this._onDiplomaChange());\n    dompack.qS('#cancellink')?.addEventListener('click', evt => this.doCancel(evt));\n\n    if (new URL(location.href).searchParams.get(\"type\") === \"cancel\")\n      this.doCancel();\n  }\n\n  _onDiplomaChange() {\n    const eventoptions = this.node.querySelectorAll<HTMLInputElement>(\"input[name=event]:not([disabled]\");\n    if (eventoptions.length === 1 && !eventoptions[0].checked)\n      eventoptions[0].click(); //autoselect only option\n  }\n\n  async gotoPage(idx: number) {\n    if (idx === 1 && this.shortform) {\n      await this.invokeRPC(\"prepShortForm\", getReferralInfo());\n      setTimeout(() => pushToDataLayer({ event: \"onlineopendays-shortform\" }), 1); //send AFTER form content is reported to analytics\n    }\n\n    const result = await super.gotoPage(idx);\n    this.node.scrollIntoView(); //scrollfix\n    return result;\n  }\n\n  async runConfirmResignup() {\n    return dialogapi.runMessageBox(\n      <div>\n        <p>{getTid('utwente_voorlichting:frontend.opendays_v2.js.alreadysignedup-line1')}</p>\n        <p><b>{getTid('utwente_voorlichting:frontend.opendays_v2.js.alreadysignedup-line2')}</b></p>\n      </div>,\n      [\n        { result: \"yes\", title: getTid(\"utwente_voorlichting:frontend.opendays_v2.js.yes-dontoverwrite\") },\n        { result: \"no\", title: getTid(\"utwente_voorlichting:frontend.opendays_v2.js.no-overwrite\") }\n      ]);\n  }\n\n  onSubmitSuccess(result: unknown) {\n    const r = result as { debughtmlinfo?: string };\n    if (r.debughtmlinfo) {\n      const debuginfoholder = <div class=\"opendaysv2__debuginfo\" />;\n      debuginfoholder.innerHTML = r.debughtmlinfo;\n      dompack.qR(\".opendaysv2__successtext\").after(debuginfoholder);\n    }\n  }\n\n  // eslint-disable-next-line @typescript-eslint/no-explicit-any -- formbase should give us proper Errors type first\n  onSubmitFailed(errors: any, result: unknown) {\n    if (errors.length === 1 && errors[0].name === \"wrd_contact_email\" && errors[0].metadata && errors[0].metadata.verifyresub) { //We're being rejected because the email address is already known\n      this.runConfirmResignup().then(r => {\n        if (r === \"yes\")\n          this.validateAndSubmit({ verifyresub: errors[0].metadata.verifyresub });\n      });\n      return;\n    }\n\n    super.onSubmitFailed(errors, result);\n  }\n\n  doCancel(evt?: Event) {\n    if (evt)\n      dompack.stop(evt);\n    void dialogapi.runMessageBox(\n      <div>\n        <p>{getTid('utwente_voorlichting:frontend.opendays_v2.js.confirm-cancel')}</p>\n      </div>,\n      [\n        { result: \"yes\", title: getTid(\"utwente_voorlichting:frontend.opendays_v2.js.yes-cancel\") },\n        { result: \"no\", title: getTid(\"utwente_voorlichting:frontend.opendays_v2.js.no-dont-cancel\") }\n      ]).then(result => {\n        if (result === \"yes\") {\n          navigateTo({ type: \"form\", form: { action: location.href, vars: [{ name: \"type\", value: \"cancel\" }], method: \"POST\" } });\n        } else {\n          const url = new URL(location.href);\n          if (url.searchParams.get(\"type\") === \"cancel\") { //remove cancel:1 from url\n            url.searchParams.delete(\"type\");\n            history.replaceState({}, document.title, url.toString());\n          }\n        }\n      });\n  }\n}\n\nforms.registerHandler(\"utwente_voorlichting:opendays_v2\", node => new OpenDagenFormV2(node));\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/webfeatures/opendays_v2/opendays_v2.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_voorlichting\",\"nl\",{\"frontend\":{\"opendays_v2\":{\"js\":{\"alreadysignedup-line1\":\"Je bent met dit e-mailadres al aangemeld voor dit evenement. Als je je opnieuw aanmeldt, overschrijven we de bestaande aanmelding.\",\"alreadysignedup-line2\":\"Wil je je aanmelding overschrijven?\",\"confirm-cancel\":\"Weet je zeker dat je je aanmelding wil annuleren?\",\"no-dont-cancel\":\"Nee\",\"no-overwrite\":\"Nee, niet overschrijven\",\"yes-cancel\":\"Ja, annuleren\",\"yes-dontoverwrite\":\"Ja, overschrijven\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"en\",{\"frontend\":{\"opendays_v2\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"de\",{\"frontend\":{\"opendays_v2\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"es\",{\"frontend\":{\"opendays_v2\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"it\",{\"frontend\":{\"opendays_v2\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"xt\",{\"frontend\":{\"opendays_v2\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n","import \"./brochurerequest.scss\";\nimport * as dompack from '@webhare/dompack';\nimport * as widgets from '@mod-utwente_base/webfeatures/utwidgets/layout';\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as forms from \"@mod-publisher/js/forms\";\n//@ts-expect-error -- rpc.jsons are old\nimport services from \"../leadswidgets.rpc.json?proxy\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport { throwError } from \"@webhare/std\";\nimport { UTRPCFormBase } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts\";\n\ntype Brochure = { rowkey: string; brochure?: string; dataset?: { link?: string; htmllink?: string } };\n\ndeclare global {\n  interface Window {\n    brochurelist: Brochure[];\n  }\n}\n\nclass EducationBrochureFormHandler extends UTRPCFormBase {\n  brochurelist: Brochure[];\n  widget: HTMLElement;\n  downloadform: HTMLFormElement;\n  txt_afterlanding: string;\n  deeplinks?: string[];\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n\n    const foldnode = this.node.closest(\".foldablecontent\");\n    if (foldnode) { // Show brochure request form if hash links brochure request widget\n      // https://gitlab.webhare.com/utwente/utwente_base/-/issues/2551\n      window.addEventListener(\"hashchange\", () => this.onHashChange(foldnode, location.hash));\n      if (location.hash.length > 1)\n        this.onHashChange(foldnode, location.hash);\n    }\n\n    if (node.dataset.brochurelist)\n      this.brochurelist = JSON.parse(node.dataset.brochurelist);\n    else\n      this.brochurelist = window.brochurelist; //legacy until end of 2022\n\n    // generic class so both the inline and footer(file)widget version work\n    this.widget = node.closest<HTMLElement>('.brochurerequestform-container') ?? throwError(\"Widget container not found\");\n    this.downloadform = dompack.qR(this.widget, \".downloadpage form\");\n    this.downloadform.addEventListener(\"submit\", this.doDownloadBrochure.bind(this));\n\n    dompack.qR(this.downloadform, \".wh-form__button.email\").addEventListener(\"click\", ev => this.doEmailBrochure(ev));\n\n    const htmllinknode = dompack.qS<HTMLAnchorElement>(this.widget, \"a.brochurerequestform__htmlbrochure__link\");\n    if (htmllinknode) {\n      this.downloadform.programme_dl.addEventListener(\"change\", () => this.updateBrochureHtmlLink(htmllinknode));\n      this.updateBrochureHtmlLink(htmllinknode);\n    }\n\n    dompack.qSA(this.widget, \".imnot\").forEach(\n      link => link.addEventListener(\"click\",\n        evt => {\n          dompack.stop(evt);\n          dompack.dispatchCustomEvent(window, \"ut-brochureform-returntoform\", { bubbles: true, cancelable: false });\n          setTimeout(() => this.node.scrollIntoView({ behavior: \"smooth\" }), 300);\n        }));\n\n    this.txt_afterlanding = dompack.qR(this.widget, \".afterlanding__text\").textContent;\n\n    this.updateBrochureWidget();\n    window.addEventListener(\"ut-brochureform-returntoform\", () => this.doReturnToForm());\n  }\n\n  updateBrochureHtmlLink(htmllinknode: HTMLAnchorElement) {\n    let htmllink = \"\";\n    if (this.downloadform.programme_dl.value !== \"\") {\n      const selected_brochure = this.downloadform.programme_dl.selectedOptions[0];\n      if (selected_brochure?.dataset?.htmllink)\n        htmllink = selected_brochure.dataset.htmllink;\n    }\n\n    htmllinknode.parentElement!.hidden = htmllink === \"\";\n    htmllinknode.href = htmllink ?? \"#\";\n  }\n\n  isBrochureDeeplink(foldnode: Element, hash: string) {\n    if (!this.deeplinks) {\n      const deeplinkcontainer = foldnode.closest(\".foldabledeeplink\");\n      if (deeplinkcontainer)\n        this.deeplinks = dompack.qSA(deeplinkcontainer, \".wh-anchor[id]\").map(_ => \"#\" + _.id);\n    }\n\n    return this.deeplinks ? this.deeplinks.indexOf(hash) : false;\n  }\n\n  onHashChange(foldnode: Element, hash: string | null) {\n    if (!hash || hash === \"#\")\n      return;\n\n    if (!this.isBrochureDeeplink(foldnode, hash))\n      return;\n\n    if (foldnode.classList.contains(\"foldablecontent--open\"))\n      return; // Already open\n\n    /* Check if foldablecontent is initialized (foldablecontent--active)\n       See: utwente_base/webdesigns/ws2016/src/widgets/embeddedobjects/index.es\n       and utwente_base/doc/topics/utwente-random/foldablecontent.md\n    */\n    if (foldnode.classList.contains(\"foldablecontent--active\"))\n      this.showBrochureRequestForm(foldnode);\n    else {\n      new MutationObserver((mutlist, obs) => {\n        if (mutlist.find(_ => (_.target as HTMLElement).classList.contains(\"foldablecontent--active\"))) {\n          obs.disconnect(); // observe just once\n          this.showBrochureRequestForm(foldnode);\n        }\n      }).observe(foldnode, { subtree: false, attributes: true, attributeFilter: [\"class\"] });\n    }\n  }\n\n  showBrochureRequestForm(foldnode: Element) {\n    dompack.dispatchCustomEvent(foldnode, \"ws:foldable-set\", {\n      bubbles: true,\n      cancelable: false,\n      detail: { open: true }\n    });\n    return true;\n  }\n\n  doEmailBrochure(ev: Event) {\n    dompack.stop(ev);\n    void this.sendBrochureMail(this.downloadform.programme_dl.value);\n  }\n\n  async sendBrochureMail(programmeid: string) {\n    if (this.widget.classList.contains(\"rpc--active\"))\n      return;\n\n    const guid = crm.getUserSettings().guid;\n    if (!guid) {\n      dompack.dispatchCustomEvent(window, \"ut-brochureform-returntoform\", { bubbles: true, cancelable: false });\n      return;\n    }\n\n    const data = {\n      programme: programmeid,\n      targetinterest: (await this.getFormExtraSubmitData()).targetinterest,\n      source: document.location.href,\n      targetlanguage: document.documentElement.lang.substr(0, 2)\n    };\n\n    this.widget.classList.add(\"rpc--active\");\n    const res = await services.mailBrochure(guid, data);\n    this.widget.classList.remove(\"rpc--active\");\n\n    if (!res) // when the form fails we return to the first page (... but aren't we still there?)\n      dompack.dispatchCustomEvent(window, \"ut-brochureform-returntoform\", { bubbles: true, cancelable: false });\n    else {\n      const msgnode = this.widget.querySelector(\".emailbrochureform-success\");\n      if (msgnode) {\n        const dialog = dialogapi.createDialog({ allowcancel: true, borrow: msgnode });\n        void dialog.runModal();\n      }\n    }\n  }\n\n  doReturnToForm() {\n    this.reset();\n\n    this.setBrochureState(\"form\", true);\n    widgets.relayoutWidgets(this.widget);\n    crm.setUserSettings({ guid: undefined, firstname: undefined, \"brochure-lastprogramme\": undefined });\n  }\n\n  doDownloadBrochure(evt: Event) {\n    dompack.stop(evt);\n\n    const selected_brochure = this.downloadform.programme_dl.selectedOptions[0];\n    if (selected_brochure?.dataset?.link)\n      window.open(selected_brochure.dataset.link, \"_blank\");\n    else\n      window.open(this.lookupBrochure(selected_brochure.value).brochure, \"_blank\");\n  }\n\n  lookupBrochure(programme: string) {\n    return this.brochurelist.find(_ => _.rowkey === programme) ?? throwError(\"Brochure not found\");\n  }\n\n  onSubmitSuccess(result: forms.FormSubmitEmbeddedResult<{ success: boolean; guid: string }>) {\n    // Note: if no marketing permission, we don't have a guid\n    if (result.guid)\n      crm.learnedAboutUser(result.guid, this.node.firstname.value);\n    crm.setUserSettings({ \"brochure-lastprogramme\": this.node.programme.value });\n\n    //  Replace with download widget\n    this.updateBrochureWidget(true);\n    this.setBrochureState(\"download\", true);\n\n    dompack.changeValue(this.downloadform.programme_dl, this.node.programme.value);\n\n    dompack.qSA(this.widget, \".aftersubmission\").forEach(_ => _.style.display = \"block\");\n    dompack.qSA(this.widget, \".afterlanding\").forEach(_ => _.style.display = \"none\");\n    const node = dompack.qR(this.widget, \".aftersubmission\");\n    this.node.classList.add(\"requestform--aftersubmission\");\n    for (const txtnode of node.querySelectorAll(\".text\"))\n      txtnode.textContent = txtnode.textContent.replace(\"[naam]\", this.node.firstname.value);\n    node.style.display = \"block\";\n  }\n\n  setBrochureState(state: \"form\" | \"download\", also_set_focus?: boolean) {\n    const page1 = state === \"form\";\n    this.node.style.display = page1 ? \"block\" : \"none\";\n    dompack.qR(this.widget, \".downloadpage\").style.display = page1 ? \"none\" : \"block\";\n    requestAnimationFrame(() => widgets.relayoutWidgets(this.widget));\n\n    if (also_set_focus) {\n      if (state === \"form\")\n        dompack.qR(this.widget, \".requestform\").focus();\n      else if (state === \"download\")\n        dompack.qR(this.widget, \".downloadpage\").focus();\n    }\n  }\n\n  updateBrochureWidget(aftersubmit?: boolean) {\n    if (crm.getUserSettings()[\"brochure-lastprogramme\"]) {\n      // Some someone already used the widget\n      // so move to the second page in which\n      // you can download or email additional brochures.\n\n      // dompack.changeValue(this.downloadform.programme_dl, crm.getUserSettings()[\"brochure-lastprogramme\"]); //dont preselect the last ever brochure, might not match when moving to different sites\n\n      dompack.qSA(this.widget, \".firstname\").forEach(el => el.textContent = crm.getUserSettings().firstname || '');\n      // dompack.qS(this.widget, \".imnot\").style.display = \"block\";\n\n      this.setBrochureState(\"download\", aftersubmit); // if we came here through user-interaction (submit) we set the focus\n\n      dompack.qSA(this.widget, \".aftersubmission\").forEach(_ => _.style.display = \"none\");\n\n      dompack.qSA(this.widget, \".firstname\").forEach(_ => _.textContent = crm.getUserSettings().firstname || '');\n\n      const node = dompack.qR(this.widget, \".afterlanding__text\");\n      node.textContent = this.txt_afterlanding.replace(\"[naam]\", crm.getUserSettings().firstname || '');\n      node.parentElement!.style.display = \"block\";\n\n      widgets.relayoutWidgets(this.widget);\n    } else {\n      this.setBrochureState(\"form\");\n    }\n  }\n}\n\nforms.registerHandler(\"utwente_voorlichting:brochurerequest\", node => new EducationBrochureFormHandler(node));\n","const { createService } = require(\"@mod-system/js/wh/rpc.ts\"); export default createService(\"utwente_voorlichting:leads\");","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./stayuptodate.scss\";\nimport * as dompack from 'dompack';\nimport * as forms from \"@mod-publisher/js/forms\";\nimport services from \"../leadswidgets.rpc.json?proxy\";\n\nimport { UTVoorlichtingRPCForm } from '@mod-utwente_voorlichting/js/shared/forms';\n\nclass stayuptodateFormHandler extends UTVoorlichtingRPCForm {\n  constructor(formnode) {\n    super(formnode);\n\n    this.haveprogram = Boolean(this.elements[\"program.select_master\"]?.value || this.elements[\"program.select_bachelor\"]?.value);\n    if (this.haveprogram) //already set?\n    {\n      if (this.elements[\"program.select_master\"])\n        this.elements[\"program.select_master\"].closest(\".wh-form__fieldgroup\").style.display = \"none\";\n      if (this.elements[\"program.select_bachelor\"])\n        this.elements[\"program.select_bachelor\"].closest(\".wh-form__fieldgroup\").style.display = \"none\";\n    }\n\n    this.elements[\"update\"].addEventListener(\"click\", evt => this.onUpdateData(evt));\n  }\n\n  onSubmitSuccess(response) {\n    this.updatetoken = response.updatetoken;\n    super.onSubmitSuccess(response);\n  }\n\n  async onUpdateData() {\n    const lock = dompack.flagUIBusy({ ismodal: true });\n    try {\n      const updatedata = { expectedstartingyear: parseInt(this.elements[\"expectedstartingyear.select\"].value) };\n\n      if (this.elements[\"targetinterest\"]?.value)\n        updatedata.targetinterest = this.elements[\"targetinterest\"].value;\n\n      //check whether either master is explicitly selected or the bachelor select isn't even rendered\n      const ismaster = updatedata.targetinterest == 'MASTER' || !this.elements[\"program_bachelor.select\"];\n      const programnode = this.elements[ismaster ? \"program_master.select\" : \"program_bachelor.select\"];\n      if (programnode?.value)\n        updatedata.program = programnode.value;\n\n      await services.updateProfile(this.updatetoken, updatedata);\n      if (this.getCurrentPageNumber) //WH5.2+ added this\n        this.gotoPage(this.getCurrentPageNumber() + 1); //'next' thank you page\n      else\n        this.gotoPage(2); //for now we know it to be 1, but the above seems clearer in purpose\n    } finally {\n      lock.release();\n    }\n  }\n}\n\nforms.registerHandler(\"utwente_voorlichting:stayuptodate\", node => new stayuptodateFormHandler(node));\n","import { UTRPCFormBase } from \"@mod-utwente_base/webdesigns/ws2026/shared/forms/utformbase.ts\";\nimport './leadswidgets.scss';\nimport * as widgets from '@mod-utwente_base/webfeatures/utwidgets/layout';\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as forms from \"@mod-publisher/js/forms\";\n\nimport \"./brochurerequest/brochurerequest\";\nimport \"./stayuptodate/stayuptodate\";\nimport { throwError } from '@webhare/std';\n\nclass PreRegistrationFormHandler extends UTRPCFormBase {\n  widget: HTMLElement;\n\n  constructor(node: HTMLFormElement) {\n    super(node);\n    this.widget = node.closest<HTMLElement>('.widget-preregistrationwidget') ?? throwError(\"Widget container not found\");\n  }\n\n  async getFormExtraSubmitData() {\n    return {\n      ...await super.getFormExtraSubmitData(),\n      \"hoofdniveau\": document.documentElement.dataset.hoofdniveau || '',\n      \"subniveau\": document.documentElement.dataset.subniveau || '',\n      \"programme\": document.documentElement.dataset.programme || '',\n      \"interesttype\": this.node.dataset.interesttype || '',\n      dontaskpermission: this.node.dataset.dontaskpermission === \"true\"\n    };\n  }\n\n  onSubmitSuccess(response: forms.FormSubmitEmbeddedResult<{ success: boolean; guid: string }>) {\n    if (response.success) {\n      this.reset();\n      const gotourl = this.node.dataset.successRedirect;\n      crm.learnedAboutUser(response.guid, this.node.firstname.value);\n\n      if (gotourl) {\n        setTimeout(() => location.href = gotourl, 150); //give GTM time to learn about the userid\n      } else {\n        this.widget.classList.add('rpc--success');\n        widgets.relayoutWidgets(this.widget);\n      }\n    } else {\n      this.widget.classList.add('rpc--fail');\n      widgets.relayoutWidgets(this.widget);\n    }\n  }\n}\n\nforms.registerHandler(\"utwente_voorlichting:preregistration\", node => new PreRegistrationFormHandler(node));\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n// Don't import the entire utwente_base/webdesigns/ws2016/src/shared/utforms\n//  as it overwrites other webdesign css (ws2026), should only be imported within ws2016 webdesign\n//import '@mod-utwente_base/webdesigns/ws2016/src/shared/utforms';\n\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as dompack from 'dompack';\nimport { registerHandler, RPCFormBase } from '@mod-publisher/js/forms';\n\n\nlet formnode;\nlet formextradata;\n\n\nclass ContactForm extends RPCFormBase {\n  constructor(form) {\n    super(form);\n\n    formnode = form;\n    formextradata = JSON.parse(form.getAttribute(\"data-extraformdata\"));\n\n    if (form.programme) {\n      form.programme.addEventListener(\"change\", updateSpecializations);\n      updateSpecializations();\n    }\n  }\n  onSubmitSuccess(data) {\n    window.dataLayer.push(data.todatalayer);\n    if (data.guid)\n      crm.learnedAboutUser(data.guid, data.firstname);\n  }\n}\n\nregisterHandler(\"utwente_voorlichting:mastercontact\", node => new ContactForm(node));\n\nfunction updateSpecializations() {\n  if (!formextradata || !formextradata.tracks_per_programme)\n    return;\n\n  const programmeid = formnode.programme.value;\n  const programme = formextradata.tracks_per_programme.find(programme => programme.programme == programmeid);\n\n  formnode.specialization.innerHTML = \"\";\n\n  const fieldline = dompack.closest(formnode.specialization, \".wh-form__fieldgroup\");\n\n  if (!(programme && programme.programme)) {\n    fieldline.style.display = \"none\";\n  } else {\n    // placeholder\n    var elem = document.createElement(\"option\");\n    elem.value = 0;\n    elem.innerText = formextradata.nospec;\n    elem.setAttribute(\"selected\", \"selected\");\n    formnode.specialization.appendChild(elem);\n\n    for (const track of programme.tracks) {\n      var elem = document.createElement(\"option\");\n      elem.value = track.trackid;\n      elem.innerText = track.title;\n      formnode.specialization.appendChild(elem);\n      //elem.selected == track.trackid == extradata.specialization;\n    }\n\n    fieldline.style.display = \"\";\n  }\n\n  dompack.dispatchCustomEvent(formnode.specialization\n    , \"refresh\", {\n      bubbles: true,\n    cancelable: false\n  });\n}\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport * as dialogapi from \"dompack/api/dialog\";\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport * as forms from \"@mod-publisher/js/forms\";\nimport getTid from \"@mod-tollium/js/gettid\";\nimport { UTVoorlichtingRPCForm } from '@mod-utwente_voorlichting/js/shared/forms';\n\nimport \"./tasterdays.scss\";\nimport \"./tasterdays.lang.json\";\nimport \"../ws2016_voorlichting/activities/activityform.scss\";\n\nclass TasterDaysForm extends UTVoorlichtingRPCForm {\n  constructor(node) {\n    super(node);\n    const cancelregistration = this.node.querySelector(\".wh-form__fieldgroup[data-wh-form-group-for='cancelregistration'] .wh-form__richtext\");\n    if (cancelregistration)\n      cancelregistration.append(<p class=\"normal\"><a href=\"#\" onClick={event => this.doCancel(event)}>{getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.cancelregistration\")}</a><br /><br /></p>);\n\n    dompack.register('.utwente-tasterdays--hide-infotext-if-nl', node => this.hideInfoTextIfNL(node));\n  }\n\n  hideInfoTextIfNL(node) {\n    node.querySelector(\"select\").addEventListener(\"input\", () => this.checkInfoTextNL(node));\n    this.checkInfoTextNL(node);\n  }\n\n  checkInfoTextNL(node) {\n    node.querySelector('.wh-form__infotextwrapper').hidden = node.querySelector(\"select\").value == 'NL';\n  }\n\n  async doCancel(event) {\n    dompack.stop(event);\n    if (await dialogapi.runMessageBox(\n      <div>\n        <p>{getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.confirm-cancel\")}</p>\n      </div>,\n      [\n        { result: \"yes\", title: getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.yes-cancel\") },\n        { result: \"no\", title: getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.no-dont-cancel\") }\n      ]) == \"yes\") {\n      const gotourl = new URL(location.href);\n      gotourl.searchParams.set(\"cancel\", 1);\n      location.href = gotourl.toString();\n    }\n  }\n\n  async doConfirmResignup() {\n    return dialogapi.runMessageBox(\n      <div>\n        <p>{getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.alreadysignedup-line1\")}</p>\n        <p><b>{getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.alreadysignedup-line2\")}</b></p>\n      </div>,\n      [\n        { result: \"yes\", title: getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.yes-dontoverwrite\") },\n        { result: \"no\", title: getTid(\"utwente_voorlichting:webfeatures.tasterdays.js.no-overwrite\") }\n      ]);\n  }\n\n  onSubmitSuccess(result) {\n    // Show debug info if available\n    if (result && result.debughtmlinfo) {\n      const debuginfoholder = <div class=\"tasterdays__debuginfo\" />;\n      debuginfoholder.innerHTML = result.debughtmlinfo;\n      dompack.qS(this.node, \".wh-form__fieldgroup[data-wh-form-group-for='thankyou']\").after(debuginfoholder);\n    }\n  }\n\n  onSubmitFailed(errors, result) {\n    if (errors.length == 1 && errors[0].name == \"wrd_contact_email\" && errors[0].metadata && errors[0].metadata.verifyresub) {\n      //We're being rejected because the email address is already known\n      this.doConfirmResignup().then(result => {\n        if (result == \"yes\") {\n          this.validateAndSubmit({ verifyresub: errors[0].metadata.verifyresub }).then(() => this.gotoPage(1));\n        }\n      });\n      return;\n    }\n\n    super.onSubmitFailed(errors, result);\n  }\n}\n\nforms.registerHandler(\"utwente_voorlichting:tasterdays\", node => new TasterDaysForm(node));\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/webfeatures/tasterdays/tasterdays.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_voorlichting\",\"nl\",{\"webfeatures\":{\"tasterdays\":{\"js\":{\"alreadysignedup-line1\":\"Je bent met dit e-mailadres al aangemeld voor dit evenement. Als je je opnieuw aanmeldt, overschrijven we de bestaande aanmelding.\",\"alreadysignedup-line2\":\"Wil je je aanmelding overschrijven?\",\"cancelregistration\":\"Ik wil mijn registratie annuleren\",\"confirm-cancel\":\"Weet je zeker dat je je registratie wil verwijderen?\",\"no-dont-cancel\":\"Nee\",\"no-overwrite\":\"Nee, niet overschrijven\",\"yes-cancel\":\"Ja, verwijderen\",\"yes-dontoverwrite\":\"Ja, overschrijven\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"en\",{\"webfeatures\":{\"tasterdays\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"cancelregistration\":\"I wish to cancel my registration\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"de\",{\"webfeatures\":{\"tasterdays\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"cancelregistration\":\"I wish to cancel my registration\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"es\",{\"webfeatures\":{\"tasterdays\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"cancelregistration\":\"I wish to cancel my registration\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"it\",{\"webfeatures\":{\"tasterdays\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"cancelregistration\":\"I wish to cancel my registration\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\nregisterTexts(\"utwente_voorlichting\",\"xt\",{\"webfeatures\":{\"tasterdays\":{\"js\":{\"alreadysignedup-line1\":\"You're already registered for this event with this email address. If you register again, we will overwrite your existing registration.\",\"alreadysignedup-line2\":\"Would you like to overwrite your registration?\",\"cancelregistration\":\"I wish to cancel my registration\",\"confirm-cancel\":\"Are you sure you want to cancel your registration?\",\"no-dont-cancel\":\"No\",\"no-overwrite\":\"No, do not overwrite\",\"yes-cancel\":\"Yes, cancel\",\"yes-dontoverwrite\":\"Yes, overwrite\"}}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n","import \"./registercourse.css\";\nimport * as dompack from '@webhare/dompack';\nimport { FormBase, registerHandler } from \"@webhare/forms\";\n\nclass LifeLongLearningRegistrationForm extends FormBase {\n  language: string = \"en\";\n  tabs: HTMLButtonElement[] = [];\n  constructor(node: HTMLFormElement) {\n    super(node);\n    this.language = document.documentElement.lang || this.language;\n\n    dompack.qSA<HTMLSelectElement>(this.node, \"select[name='ut_productid']\").forEach(select => {\n      select.addEventListener(\"change\", () => this.updatePriceDetails());\n    });\n\n    dompack.qSA(this.node, \".lll_registrationform__discountblock-toggle\").forEach(btn => {\n      btn.addEventListener(\"click\", () => {\n        btn.hidden = true;\n        dompack.qR(this.node,\".lll_registrationform__discountblock\").hidden = false;\n        this.node.discountcode.focus();\n      });\n\n    });\n\n    this.initializeTabs();\n    this.node.addEventListener(\"wh:form-pagechange\", ev => this.onPageChange(ev.target as HTMLElement));\n    this.updatePriceDetails();\n  }\n\n  updatePriceDetails() {\n    const select = this.node.ut_productid as HTMLSelectElement;\n    const price = select.options[select.selectedIndex]?.dataset?.price || \"\";\n    this.node.productprice.value = price;\n    this.node.productprice.closest(\".wh-form__fieldgroup\").hidden = price === \"\";\n  }\n\n  initializeTabs() {\n    const template = dompack.qS<HTMLTemplateElement>(\"#lll_registrationform__tabs-template\");\n    if(template) {\n      const sidebar =  dompack.qR(\".page-sidebar\");\n      sidebar.appendChild(template.content);\n      sidebar.hidden = false;\n\n      this.tabs = dompack.qSA<HTMLButtonElement>(\".lll_registrationform__tab\");\n      this.tabs.forEach((tab, idx) => {\n        tab.addEventListener(\"click\", () => {\n          if( !tab.disabled && tab.getAttribute(\"aria-selected\") !== \"true\" )\n            void this.gotoPage(idx);\n        });\n      });\n    }\n  }\n\n  onPageChange(page: HTMLElement) {\n    const curTabId = page.id + \"-tab\";\n\n    const activIdx = this.tabs.findIndex(tab => tab.id === curTabId);\n    this.tabs.forEach((tab, idx) => {\n      tab.disabled = idx > activIdx; // FIXME: if validated enable (when going back/forward)?\n      tab.setAttribute(\"aria-selected\", idx === activIdx ? \"true\" : \"false\");\n    });\n  }\n}\n\nregisterHandler(\"utwente_voorlichting:lllregistrationform\", node => new LifeLongLearningRegistrationForm(node));\n","\n// FIXME Decide whether it's safe to compile this into te UT Bundle or that it should be a separate bundle\nimport { SlimSelect, TrigramMatcher } from \"@mod-utwente_design\";\nimport { getFrontendData } from \"@webhare/frontend\";\nimport \"./sirform.scss\";\nimport { create, dispatchCustomEvent, dispatchDomEvent, flagUIBusy, getLocal, qR, qSA, qS, setLocal } from \"@webhare/dompack\";\nimport { compareProperties, generateRandomId, parseTyped, pick, wrapSerialized } from \"@webhare/std\";\nimport { LocalFormBase, registerHandler, submitForm, type FormSubmission, type FormSubmitResult } from \"@webhare/forms\";\nimport { rpc } from \"@webhare/rpc\";\nimport type { SirFormConfig, SirFormEvent, SirFormSignup } from \"./sirform.rpc\";\nimport { RPCFormBase, type FormSubmitEmbeddedResult } from \"@mod-publisher/js/forms\";\nimport * as dialogapi from 'dompack/api/dialog';\nimport type { UTDialog } from \"@mod-utwente_base/webdesigns/ws2016/src/shared/dialog\";\nimport * as pwalib from '@mod-publisher/js/pwa';\nimport { getTid, getTidLanguage } from \"@webhare/gettid\";\nimport \"./sirform.lang.json\";\nimport type { UTReferralInfo } from \"@mod-utwente_base/js/types\";\nimport { getHardcodedURLReferralInfo, getReferralInfo } from \"@mod-utwente_base/webdesigns/ws2016/src/shared/crm/referralinfo\";\nimport { html } from \"@webhare/dompack/src/html\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_voorlichting:sirform\": {\n      fairsinfo?: string;\n    };\n  }\n}\n\ntype ExtraSubmitData = {\n  id: string;\n  language: string;\n  date: string;\n  event: string;\n  referralinfo: UTReferralInfo;\n};\n\nlet admin: ConfigFormHandler | null = null;\nlet fairsinfo: SirFormConfig | null = null;\n\nconst isWS2026 = document.documentElement.classList.contains(\"utwente--ws2026\");\n\nfunction setTitle(title: string) {\n  if (isWS2026) {\n    qR(\".page-titlebar\").replaceChildren(html(\"h1\", { className: \"heading1\" }, [title]));\n  } else {\n    qR(\"h1.contentpart__title\").textContent = title;\n  }\n}\n\n\nfunction getSirConfig(): SirFormConfig {\n  return fairsinfo || getLocal<SirFormConfig>(\"utwente_voorlichting:sirform.config\") || {\n    fairTypes: [],\n    fairs: [],\n    programs: [],\n    schools: [],\n    now: \"\"\n  };\n}\nfunction getSelectedEventId(): string | null {\n  return fairsinfo ? fairsinfo.fairs[0].wrdGuid : getLocal<string>(\"utwente_voorlichting:sirform.selectedeventguid\");\n}\nfunction getSelectedEvent(): SirFormEvent | null {\n  const eventid = getSelectedEventId();\n  return eventid && getSirConfig().fairs.find(fair => fair.wrdGuid === eventid) || null;\n}\nfunction getUploadQueue(): FormSubmission[] {\n  return getLocal<FormSubmission[]>(\"utwente_voorlichting:sirform.uploadqueue\") || [];\n}\nfunction getNumUploaded(): number {\n  const eventid = getSelectedEventId();\n  return (eventid && getLocal<Record<string, number>>(\"utwente_voorlichting:sirform.uploadcounts\")?.[eventid]) || 0;\n}\nfunction increaseNumUploaded(eventid: string) {\n  const uploadMap = getLocal<Record<string, number>>(\"utwente_voorlichting:sirform.uploadcounts\") || {};\n  uploadMap[eventid] = (uploadMap[eventid] || 0) + 1;\n  setLocal<Record<string, number>>(\"utwente_voorlichting:sirform.uploadcounts\", uploadMap);\n}\n\nfunction updateOptions(select: HTMLSelectElement, newoptions: HTMLOptionElement[], { setValue = '' } = {}) {\n  const oldvalue = setValue || select.value;\n  if (select.utSlimSelect)\n    select.utSlimSelect.setData(newoptions);\n  else\n    select.replaceChildren(...newoptions);\n\n  if (oldvalue) {\n    if (select.utSlimSelect)\n      select.utSlimSelect.setSelected(oldvalue);\n    else\n      select.value = oldvalue;\n\n    if (select.selectedIndex === -1) //reset if value not found\n      select.selectedIndex = 0;\n  }\n}\n\nfunction setupTrigramSearch(selnode: HTMLSelectElement) {\n  if (!selnode.utSlimSelect)\n    throw new Error(\"SlimSelect not initialized on select element\");\n\n  const seloptions = Array.from(selnode.options).map(opt => ({\n    value: opt.value,\n    text: opt.textContent || \"\",\n    id: opt.value,\n    selected: opt.selected,\n    parent: opt.dataset.parent || \"\",\n    style: opt.getAttribute(\"style\") || \"\",\n    class: opt.className || \"\"\n  }));\n\n  selnode.utSlimSelect.events.search = (search, currentData) => {\n    const selvalues = currentData.map(d => d.id);\n    seloptions.forEach(opt => opt.selected = selvalues.includes(opt.id)); //keep selection state in sync\n\n    if (search.length < 2)\n      return seloptions; // Just return all options if search is less than 2 characters\n\n    const list = seloptions.filter(_ => !_.selected).map(_ => _.text || \"\").filter(s => s.length > 0);\n\n    const prep = new TrigramMatcher(list);\n    const scorelist = prep.score(search);\n\n    // Only show results which scored at least 66% of max score found\n    const minscore = scorelist.length ? scorelist[0].score * 0.66 : 0;\n    const filteredScoreList = scorelist.filter(_ => _.score > minscore).map(_ => _.str);\n\n    const options = seloptions.filter(_ => filteredScoreList.includes(_.text || \"\"));\n    const insertedParents = options.filter(opt => opt.parent === \"\").map(_ => _.value);\n    options.forEach((opt, i) => {\n      if (opt.parent && !insertedParents.includes(opt.parent)) {\n        insertedParents.push(opt.parent);\n        const parentOpt = seloptions.find(o => o.value === opt.parent);\n        if (parentOpt) {// Insert parent option before the first child\n          options.splice(i, 0, parentOpt);\n          if (parentOpt.class.indexOf(\"suboptionvisible\") === -1)\n            parentOpt.class += \" suboptionvisible\";\n        }\n      }\n    });\n\n    return options;\n  };\n}\n\nclass ConfigFormHandler extends LocalFormBase<{\n  eventtype: string;\n  event: string;\n}> {\n  isAdminVisible = false;\n\n  constructor(formnode: HTMLFormElement) {\n    super(formnode);\n    // eslint-disable-next-line @typescript-eslint/no-this-alias\n    admin = this;\n    (this.getElementByName(\"eventtype\") as HTMLSelectElement).addEventListener(\"change\", () => this.updateEvents());\n    pwalib.onReady(() => void this.continuePWASetup(), { reportusage: true });\n\n    this.setupPageForAdminForm();\n    this.setAdminPageVisible(!getSelectedEvent());\n    this.checkUploadQueue();\n\n    //preset the form\n    const curevent = getSelectedEvent();\n    this.updateEventTypes({ setValue: curevent?.fairtype ?? undefined });\n    this.updateEvents({ setValue: curevent?.wrdGuid });\n\n    setInterval(() => this.checkUploadQueue(), 30000);\n  }\n\n  checkUploadQueue() {\n    const queue = getUploadQueue();\n    console.log(\"SIR form upload queue check, entries:\", queue.length);\n    for (const entry of queue) {\n      void this.uploadEntry(entry);\n    }\n  }\n\n  async uploadEntry(entry: FormSubmission): Promise<void> {\n    const result = await submitForm(entry);\n    if (result.success) {\n      const queue = getUploadQueue().filter(e => (e.extrasubmit as ExtraSubmitData).id !== (entry.extrasubmit as ExtraSubmitData).id);\n      setLocal<FormSubmission[]>(\"utwente_voorlichting:sirform.uploadqueue\", queue);\n      increaseNumUploaded((entry.extrasubmit as ExtraSubmitData).event);\n      this.refreshStats();\n    }\n  }\n\n  async continuePWASetup() {\n    void this.checkAppUpdate();\n  }\n\n  setAdminPageVisible(adminVisible: boolean) {\n    qR(\"form[data-wh-form-id=config]\").style.display = adminVisible ? \"\" : \"none\";\n    qR(\"form[data-wh-form-id=signup]\").style.display = adminVisible ? \"none\" : \"\";\n    if (adminVisible)\n      setTitle('Admin');\n    this.isAdminVisible = adminVisible;\n    qR(\"#sirform-status\").hidden = !adminVisible;\n    this.refreshStats();\n\n    const lock = getSirConfig().fairTypes.length ? null : flagUIBusy({ modal: true });\n    void this.checkForEventUpdates().finally(() => {\n      lock?.release();\n    });\n    void this.checkAppUpdate();\n  }\n\n  refreshStats() {\n    qR(\"#sirform-lastupdate\").textContent = getSirConfig().now;\n    qR(\"#sirform-registrationsinqueue\").textContent = String(getUploadQueue().length);\n    qR(\"#sirform-registrationsuploaded\").textContent = String(getNumUploaded());\n  }\n\n  setupPageForAdminForm() {\n    if (isWS2026) {\n      const loginitem = create(\"li\", {\n        className: \"utility-item\",\n        textContent: \"Admin\",\n        on: { click: (evt: Event) => this.openConfig(evt) }\n      });\n\n      qR(\".utility-menu\").appendChild(loginitem);\n    } else {\n      for (const toremove of qSA(\".contentpart__topmenuitem--search\"))\n        toremove.remove();\n\n      const loginitem = create(\"div\", {\n        className: \"contentpart__topmenuitem\",\n        textContent: \"Admin\",\n        on: { click: (evt: Event) => this.openConfig(evt) }\n      });\n\n      qR(\".contentpart__topmenu\").appendChild(loginitem);\n    }\n  }\n\n  openConfig(evt: Event) {\n    evt.preventDefault();\n    if (this.isAdminVisible)\n      return;\n\n    const dialog = dialogapi.createDialog({ allowcancel: true }) as UTDialog;\n\n    const form = create('form', { className: 'wh-styledinput sirform__loginform' });\n    form.addEventListener(\"submit\", ev => this.onAdminLogin(ev, form, dialog));\n\n    form.append(\n      create(\"label\", { for: \"adminpassword\", textContent: \"Enter admin password to open configuration\", className: \"wh-form__label\" }),\n      create(\"input\", { type: \"password\", name: \"password\", id: \"adminpassword\" }),\n      create(\"button\", {\n        type: \"submit\", id: \"adminloginbutton\",\n        textContent: \"Login\",\n        className: \"wh-form__button\",\n      })\n    );\n\n    dialog.contentnode!.append(form);\n\n    void dialog.runModal();\n  }\n\n  onAdminLogin(evt: Event, form: HTMLFormElement, dialog: UTDialog) {\n    evt.preventDefault();\n    if (form.password.value === \"aap\")\n      this.setAdminPageVisible(true);\n    dialog.closeDialog();\n  }\n\n  updateEventTypes(options?: { setValue?: string }) {\n    updateOptions(this.getElementByName(\"eventtype\") as HTMLSelectElement, getSirConfig()\n      .fairTypes.toSorted(compareProperties([\"wrdTitle\", \"wrdGuid\"])).\n      map(ft => create(\"option\", { id: ft.wrdGuid, value: ft.wrdGuid, textContent: ft.wrdTitle })), options);\n  }\n\n  checkForEventUpdates = wrapSerialized(async () => {\n    setLocal<SirFormConfig>(\"utwente_voorlichting:sirform.config\", await rpc(\"utwente_voorlichting:fairs\").getFairs());\n    const curevent = getSelectedEvent();\n    this.updateEventTypes({ setValue: curevent?.fairtype ?? undefined });\n    this.updateEvents({ setValue: curevent?.wrdGuid });\n  }, { coalesce: true });\n\n  checkAppUpdate = wrapSerialized(async () => {\n    const updateres = await pwalib.checkForUpdate() as {\n      needsupdate: boolean;\n      forcerefresh: boolean;\n    }; //'as' required, not typed in WH5.8\n    console.log(\"checkAppUpdate result:\", updateres);\n\n    if (updateres.needsupdate) {\n      await pwalib.downloadUpdate();\n      if (!this.isAdminVisible)\n        return; //don't bother users if we've already exited the admin oage\n\n      await dialogapi.runMessageBox(getTid(\"utwente_voorlichting:frontend.sirform.update_downloaded\"), [{ title: \"Restart\" }]);\n      await pwalib.updateApplication();\n    }\n  });\n\n  updateEvents(options?: { setValue?: string }) {\n    const events = getSirConfig().fairs.filter(\n      fair => !this.data.eventtype || fair.fairtype === this.data.eventtype\n    );\n    const eventSelect = this.getElementByName(\"event\") as HTMLSelectElement;\n    updateOptions(eventSelect, events.\n      toSorted(compareProperties([[\"date\", \"desc\"], \"wrdTitle\", \"wrdGuid\"])).\n      map(ft => create(\"option\", { id: ft.wrdGuid, value: ft.wrdGuid, textContent: ft.title })), options);\n\n    eventSelect.utSlimSelect ||= new SlimSelect({\n      select: eventSelect,\n      settings: {\n        placeholderText: getTid(\"utwente_voorlichting:frontend.sirform.selectvalue\"),\n        modal: 'off', // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n        closeOnSelect: true,\n        keepSearch: true,\n        removeLastSelectedOnBackspace: false\n      }\n    });\n    setupTrigramSearch(eventSelect);\n  }\n\n  async submit(): Promise<{ result?: FormSubmitEmbeddedResult }> {\n    //TODO reconfig parent form based one vent\n    const selectedEvent = getSirConfig().fairs.find(fair => fair.wrdGuid === this.data.event) || null;\n    if (selectedEvent) {\n      setLocal<string>(\"utwente_voorlichting:sirform.selectedeventguid\", selectedEvent.wrdGuid);\n      this.setAdminPageVisible(false);\n      dispatchCustomEvent(window, \"utwente:ut-sirform-selectevent\", { bubbles: true, cancelable: true });\n    }\n\n    return { result: {} };\n  }\n}\n\nfunction getTrackTitle(track: SirFormConfig[\"programs\"][number][\"tracks\"][number]): string {\n  return document.documentElement.lang.startsWith(\"nl\") ? track.nameNl : (document.documentElement.lang.startsWith(\"de\") ? track.nameDe : track.nameEn) || track.nameEn || track.nameNl;\n}\n\nfunction getProgramTitle(prog: SirFormConfig[\"programs\"][number]): string {\n  const basename = document.documentElement.lang.startsWith(\"nl\") ? prog.nameNl : (document.documentElement.lang.startsWith(\"de\") ? prog.nameDe : prog.nameEn) || prog.nameEn || prog.nameNl;\n  if (prog.isBachelor)\n    return `${basename} (BSc)`;\n  if (prog.isMaster)\n    return `${basename} (MSc)`;\n  return basename;\n}\n\nclass SignupFormHandler extends RPCFormBase<SirFormSignup> {\n  constructor(formnode: HTMLFormElement) {\n    super(formnode);\n\n    const config_fairsinfo = getFrontendData(\"utwente_voorlichting:sirform\", { allowMissing: true })?.fairsinfo;\n    if (config_fairsinfo) { //user app!\n      fairsinfo = parseTyped(config_fairsinfo);\n    }\n\n    addEventListener(\"utwente:ut-sirform-selectevent\", (evt: Event) => this.onEventSelected());\n    if (getSelectedEvent())\n      this.onEventSelected();\n\n    const thankyoupage = qR(this.node, \"[data-wh-form-pagerole=thankyou]\");\n    const btnwrapper = create(\"div\", { className: \"sirform__centerbtnwrapper\" });\n    thankyoupage.append(btnwrapper);\n    btnwrapper.append(\n      create(\"button\", {\n        type: \"button\",\n        className: \"wh-form__button\",\n        textContent: getTid(\"utwente_voorlichting:frontend.sirform.resetbutton\"),\n        on: {\n          click: () => {\n            this.reset();\n            qSA<HTMLSelectElement>(this.node, \"select\").forEach(_ => dispatchDomEvent(_, \"change\"));\n          }\n        }\n      })\n    );\n\n    for (const phoneInput of qSA<HTMLInputElement>(this.node, \".webform-utwente--phonefield__input\")) {\n      phoneInput.inputMode = \"tel\";\n      phoneInput.addEventListener(\"input\", evt => {\n        const fixedValue = phoneInput.value.replaceAll(/[^0-9+]/g, '');\n        if (fixedValue !== phoneInput.value)\n          phoneInput.value = fixedValue;\n      });\n    }\n  }\n\n  async getFieldValue(field: HTMLElement) { //FIXME formsapi should support select multiple\n    if (field instanceof HTMLSelectElement && field.multiple) {\n      return Array.from(field.selectedOptions).map(opt => opt.value).join(\",\");\n    }\n    return super.getFieldValue(field);\n  }\n\n  //Read selectedEvent and apply to form\n  onEventSelected() {\n    setTitle(getSelectedEvent()?.title || '');\n\n    //Update schools\n    const schools = getSirConfig().schools.filter(school => getSelectedEvent()?.schools.includes(school.wrdId)).toSorted(compareProperties([\"wrdTitle\"]));\n    updateOptions(qR<HTMLSelectElement>(this.node, \"select[name=school]\"), [\n      create(\"option\", { textContent: \"\", value: \"\" }),\n      ...schools.map(school => create(\"option\", { textContent: school.wrdTitle, value: school.wrdGuid }))\n    ]);\n\n    this.node.dataset.whFormVarSelectschool = schools.length > 1 ? \"1\" : \"\";\n    this.node.dataset.whFormVarSelectprogram = getSelectedEvent()?.allownoprogram ? \"\" : \"1\";\n    this.node.dataset.whFormVarShortform = getSelectedEvent()?.shortform ? \"1\" : \"\";\n    this.node.dataset.whFormVarAskphone = getSelectedEvent()?.askphone ? \"1\" : \"\";\n    void this.refreshConditions(); //TODO can't the form autorespond to data attribute change\n\n    //Update program selector\n    const programOptions = getSirConfig().programs.filter(prog => getSelectedEvent()?.programmes.includes(prog.wrdId));\n    const interestedInSel = qR<HTMLSelectElement>(this.node, \"select[name=interestedin]\");\n\n    const programOptionElements: HTMLOptionElement[] = [];\n    const progopts: Array<{\n      title: string;\n      value: string;\n      isBachelor: boolean;\n      isMaster: boolean;\n      tracks: Array<{ title: string; value: string; style: string; parent: string }>;\n    }> = [];\n\n    // First we build a structured list of programs and tracks, sorted by title. This makes it easier to generate the option elements with correct indentation and sorting.\n    programOptions.forEach(prog => {\n      const tracks: Array<{ title: string; value: string; style: string; parent: string }> = [];\n      if (prog.tracks.length) {\n        tracks.push(...prog.tracks.flatMap(track =>\n          [{ title: getTrackTitle(track), value: track.wrdGuid, parent: prog.wrdGuid, style: \"margin-left:15px;font-size:95%;\" }]\n        ));\n        tracks.sort(compareProperties([\"title\"]));\n      }\n      progopts.push({ title: getProgramTitle(prog), isBachelor: prog.isBachelor, isMaster: prog.isMaster, value: prog.wrdGuid, tracks });\n    });\n    progopts.sort(compareProperties([\"title\"]));\n\n    progopts.forEach((prog) => {\n      programOptionElements.push(create(\"option\", { textContent: prog.title, className: \"mainoption\" + (prog.tracks.length ? \" mainoption--hassuboption suboptionvisible\" : \"\"), value: prog.value, dataset: { parent: \"\" } }));\n      if (prog.tracks.length) {\n        programOptionElements.push(...prog.tracks.flatMap(track =>\n          [create(\"option\", { textContent: track.title, value: track.value, className: \"suboption\", dataset: { parent: track.parent }, style: track.style })]\n        ));\n      }\n    });\n\n    if (programOptions.some(_ => _.isBachelor))\n      programOptionElements.unshift(create(\"option\", { textContent: getTid(\"utwente_voorlichting:frontend.sirform.genericinterest_bsc\"), value: \"BACHELOR\" }));\n    if (programOptions.some(_ => _.isMaster))\n      programOptionElements.unshift(create(\"option\", { textContent: getTid(\"utwente_voorlichting:frontend.sirform.genericinterest_msc\"), value: \"MASTER\" }));\n\n    interestedInSel.replaceChildren(...programOptionElements);\n\n    qSA<HTMLSelectElement>(this.node, \".wh-form__fieldgroup--slimselect select\").forEach(selnode => {\n      selnode.utSlimSelect ||= new SlimSelect({\n        select: selnode,\n        events: { afterChange: () => this.onSelectChange(selnode) },\n        settings: {\n          placeholderText: selnode.name === \"interestedin\" ? getTid(\"utwente_voorlichting:frontend.sirform.selectinterest\") : getTid(\"utwente_voorlichting:frontend.sirform.selectvalue\"),\n          closeOnSelect: selnode.multiple ? false : true,\n          modal: 'off', // prevent slimselect from opening in a modal on mobile (note: required extra styling)\n          hideSelected: selnode.multiple, //hides already selected options from the dropdown in multiple select\n          allowDeselect: true,\n          keepSearch: true,\n          removeLastSelectedOnBackspace: false\n        }\n      });\n      setupTrigramSearch(selnode);\n    });\n\n    this.reset();\n  }\n\n  onSelectChange(node: HTMLSelectElement) {\n    if (node.name === \"interestedin\") {\n      qSA(\".ss-content[data-id='\" + node.dataset.id + \"'] .mainoption--hassuboption.ss-selected\").forEach(mainopt => {\n        let hasSubOptions = false;\n        let subopt = mainopt.nextElementSibling;\n        while (subopt && subopt.classList.contains(\"suboption\")) {\n          if (!subopt.classList.contains(\"ss-selected\"))\n            hasSubOptions = true; // Available suboption found, keep main option visible\n          subopt = subopt.nextElementSibling;\n        }\n\n        mainopt.classList.toggle(\"suboptionvisible\", hasSubOptions); // if selected mainoption has available suboptions keep is visible\n      });\n    }\n  }\n\n  async getFormExtraSubmitData(): Promise<ExtraSubmitData> {\n    return {\n      id: generateRandomId(),\n      language: getTidLanguage(),\n      date: (new Date).toISOString(),\n      event: getSelectedEvent()?.wrdGuid || '',\n      referralinfo: admin ? getHardcodedURLReferralInfo(\"https://www.utwente.nl/sir/adminapp\") : getReferralInfo(),\n    };\n  }\n\n  async submitForm(entry: FormSubmission): Promise<FormSubmitResult> {\n    if (!admin)\n      return super.submitForm(entry);\n\n    const queue = getUploadQueue();\n    setLocal<FormSubmission[]>(\"utwente_voorlichting:sirform.uploadqueue\", [...queue, entry]);\n    admin.refreshStats();\n    void admin.uploadEntry(entry);\n    return {\n      success: true,\n      result: {},\n      errors: [],\n      warnings: [],\n      messages: []\n    };\n  }\n\n  async reset() {\n    await super.reset();\n\n    //manually resync all select fields.  TODO WH6.2 FormBase will handle this itself in reset\n    for (const select of this.node.querySelectorAll(\"select\")) {\n      select.dispatchEvent(new Event(\"change\"));\n    }\n\n    const setNationality = getSelectedEvent()?.noNationalityPrefill ? '' : getSelectedEvent()?.address?.country;\n    if (setNationality) {\n      (this.getElementByName(\"nationality.select\") as HTMLSelectElement).utSlimSelect?.setSelected(setNationality);\n\n      // Prefill phone country if possible\n      const phoneCountryEl = qS(\"select.webform-utwente--phonefield__country\") as HTMLSelectElement;\n      if (phoneCountryEl) {\n        phoneCountryEl.value = setNationality;\n        phoneCountryEl.dispatchEvent(new Event(\"change\"));\n      }\n    }\n  }\n}\n\nregisterHandler(\"utwente_voorlichting:sirform.config\", form => new ConfigFormHandler(form));\nregisterHandler(\"utwente_voorlichting:sirform.signup\", form => {\n  //Unfortunately formsapi doesnt support <select multiple so we'll let it render an input and replace it just before we start regsitering the form\n  const interestedIn = form.elements.namedItem(\"interestedin\") as HTMLInputElement;\n  const interestedInSel = create(\"select\", { multiple: true, ...pick(interestedIn, [\"id\", \"name\"]) });\n  interestedIn.replaceWith(interestedInSel);\n\n  const school = form.elements.namedItem(\"school\") as HTMLInputElement;\n  const schoolSel = create(\"select\", { ...pick(school, [\"id\", \"name\"]) });\n  school.replaceWith(schoolSel);\n\n  return new SignupFormHandler(form);\n});\n","/* eslint-disable no-alert */ //TODO avoid the alert()s though. require dompack dialogs?\n\nimport * as pxl from \"@mod-consilio/js/pxl\";\nimport * as dompack from 'dompack';\nimport * as whintegration from '@mod-system/js/wh/integration';\nimport './internal/debugmenu';\nimport * as settings from './internal/settings';\nimport { getAssetPackBase } from \"@mod-platform/js/concepts/frontend\";\nimport { navigateTo } from \"@webhare/env\";\nimport type { PublishedPWASSettings, PWACheckVersionResponse } from \"@mod-platform/webfeatures/pwaserviceworker/pwaserviceworker\";\nimport { getFrontendData, getSiteRoot } from \"@webhare/frontend\";\n\nconst appbase = location.href.indexOf(\"?\") > -1 ? location.href.split('?')[0] : location.href.split('#')[0];\n//Pre 6.0 WebHares might still have published as whconfig.obj.pwasettings\nconst pwasettings = getFrontendData(\"platform:pwasettings\", { allowMissing: true }) ?? (whintegration.config.obj as { pwasettings: PublishedPWASSettings }).pwasettings;\nlet didinit = false;\n\n//set up a promise we'll use to signal succesful offline mode\nconst offlinedeferred = Promise.withResolvers<void>();\nlet swregistration: ServiceWorkerRegistration | undefined;\n\nfunction getAppName() {\n  if (pwasettings.appname)\n    return pwasettings.appname; //in WH6.0 (and attempting to backport to at least WH5.9.4) the appname should be published directly\n\n  //we'll assume the webdesignname is the appname\n  //TODO clean this up. designroot is undocumented, appname should be in PWASSettings\n  const settings2 = (whintegration.config as unknown as { designroot: string }).designroot.match(/^\\/.publisher\\/sd\\/([^/]*)\\/([^/]*)\\/$/)!;\n  const module = settings2[1];\n  const webdesign = settings2[2];\n  return module + ':' + webdesign;\n}\n\nfunction sendSWRequestTo(sw: ServiceWorker, type: string, data?: object) {\n  return new Promise((resolve, reject) => {\n    const msg_chan = new MessageChannel();\n    msg_chan.port1.onmessage = event => {\n      if (event.data && event.data.__throw)\n        reject(new Error(event.data.__throw));\n      else\n        resolve(event.data);\n    };\n    // console.log(navigator.serviceWorker);\n    // console.log(navigator.serviceWorker.controller);\n    // navigator.serviceWorker.controller.postMessage({ swrequest: type, data }, [msg_chan.port2]);\n    sw.postMessage({ swrequest: type, data }, [msg_chan.port2]);\n  });\n}\n\n//TODO type the SWRequest protocol properly\nasync function sendSWRequest(type: string, data?: object) {\n  //wait for SW to be available. (waiting for ready isn't safe, it may pick up an already installed SW but doesn't mean that onReady is done\n  await offlinedeferred.promise;\n  if (!swregistration?.active)\n    throw new Error(\"ServiceWorker registration failed\");\n  return sendSWRequestTo(swregistration.active, type, data);\n}\n\nexport async function checkForUpdate(): Promise<PWACheckVersionResponse> {\n  return await sendSWRequest(\"checkversion\", {\n    pwauid: document.documentElement.dataset.whPwaUid,\n    pwafileid: document.documentElement.dataset.whPwaFileid\n  }) as PWACheckVersionResponse;\n}\nexport async function downloadUpdate() {\n  return await sendSWRequest(\"downloadupdate\");\n}\n//install downloaded update now\nexport async function updateApplication() {\n  console.log(\"Reloading to update application\");\n  navigateTo({ type: \"reload\" });\n  return new Promise((resolve, reject) => setTimeout(() => reject(new Error(\"The update failed\")), 20000)); //timeout 20 sec...\n}\n\n\nexport function onReady(initfunction: () => void, options?: {\n  reportusage?: boolean;\n  onAvailableOffline?: () => void;\n  onOfflineFailed?: (e: Error) => void;\n}): void {\n  if (didinit)\n    throw new Error(\"pwalib.onReady should be invoked only once\");\n\n  didinit = true;\n\n  //figure out the base of the app we have to work with\n  if (!location.href.startsWith(getSiteRoot())) {\n    alert(\"You cannot access a PWA app using a URL outside its site.\\n\\nThe WebHare 'preview' is not supported by a PWA\");\n    return;\n  }\n  if (!appbase.endsWith('/')) {\n    //we might redirect deeper.. but this shouldn't happen anyway\n    alert(\"The application base URL must end with a /\");\n    return;\n  }\n\n  if (options?.reportusage) {\n    //determinate app name. we should probably get Versioninfo and webhare/other version numbers too\n    pxl.sendPxlEvent(\"publisher:pwastart\", { ds_appname: settings.getAppName() });\n  }\n\n  //wait for dompack to be ready...\n  dompack.onDomReady(async function () {\n    //we can now run initialization which can do some basic UI setup\n    initfunction();\n\n    //bind it to user given clalbacks\n    if (options?.onAvailableOffline)\n      offlinedeferred.promise = offlinedeferred.promise.then(() => options.onAvailableOffline!());\n    if (options?.onOfflineFailed) //we need to chain our catch to the new promise above or we risk a \"unhandled rejection\" - https://stackoverflow.com/questions/52409326/unhandled-promise-rejection-despite-catching-the-promise\n      offlinedeferred.promise = offlinedeferred.promise.catch(e => options.onOfflineFailed!(e));\n\n    //and we can start registration\n    if (!(\"serviceWorker\" in navigator)) {\n      offlinedeferred.reject(new Error(\"This browser does not support serviceWorker\"));\n      return;\n    }\n    if (window.isSecureContext === false) {\n      offlinedeferred.reject(new Error(\"This webpage is not running in a secure context (https or localhost)\"));\n      return;\n    }\n\n    const swurl = `${getAssetPackBase(\"platform:pwaserviceworker\")}ap.mjs?app=${encodeURIComponent(settings.getAppName())}`;\n\n    try {\n      swregistration = await navigator.serviceWorker.register(swurl, { scope: appbase });\n\n      if (swregistration.installing) { //detect an installing worker going straight to redundant\n        swregistration.installing.addEventListener(\"statechange\", () => {\n          if (swregistration?.installing?.state === \"redundant\")\n            offlinedeferred.reject(new Error(\"The serviceWorker failed to install\"));\n        });\n      }\n\n      offlinedeferred.resolve(navigator.serviceWorker.ready.then(() => void undefined));\n    } catch (e) {\n      console.log(\"PWA Registration failed\", (e as Error).message);\n      offlinedeferred.reject(e);\n    }\n  });\n}\n\n//inform any serviceworkers that a pwalib app has connected. gives them a chance to watch for forced version checks\nasync function precheckExistingWorkers() {\n  if (!navigator.serviceWorker)\n    return;\n\n  const registrations = await (navigator.serviceWorker.getRegistrations());\n  for (const sw of registrations)\n    if (sw.active && sw.scope === appbase)\n      await sendSWRequestTo(sw.active, 'loading', {\n        pwasettings: pwasettings,\n        pwauid: document.documentElement.dataset.whPwaUid,\n        pwafileid: document.documentElement.dataset.whPwaFileid\n      });\n}\n\nfunction onServiceWorkerMessage(event: MessageEvent) {\n  if (event.data.type === 'forceRefresh') {\n    console.log(\"Reloading because forced by the serice worker\");\n    navigateTo({ type: \"reload\" });\n    return;\n  }\n  if (event.data.type === \"log\") {\n    //@ts-expect-error TODO ugly, cleanup up\n    console[event.data.loglevel](\"[From ServiceWorker] \" + event.data.message);\n    return;\n  }\n  console.error(\"onServiceWorkerMessage\", event.data);\n}\n\nif (pwasettings) { //only activate if pwasettings are present - avoid sideeffects\n  settings.setAppName(getAppName());\n\n  navigator.serviceWorker.addEventListener(\"message\", onServiceWorkerMessage);\n  void precheckExistingWorkers();\n}\n","import * as dompack from 'dompack';\nimport \"./debugmenu.scss\";\nimport * as settings from './settings';\nimport * as maintenance from './maintenance';\n\nlet debuglayer: HTMLDivElement | undefined;\n\nasync function clearCache() {\n  await maintenance.clearCache(settings.getAppName());\n}\nasync function restartApp() {\n  location.reload();\n}\nasync function unregisterServiceWorkers() {\n  await maintenance.unregisterServiceWorkers();\n}\n\nexport function runPWADebugMenu() {\n  if (debuglayer)\n    debuglayer.remove();\n\n  debuglayer =\n    <div id=\"pwadebugmenu\">\n      <h1>PWA Debugger</h1>\n      <div>\n        <button type=\"button\" onClick={clearCache}>Clear cache</button><br />\n        <button type=\"button\" onClick={unregisterServiceWorkers}>unregisterServiceWorkers</button><br />\n        <button type=\"button\" onClick={restartApp}>Restart application</button><br />\n      </div>\n    </div>;\n\n  document.body.appendChild(debuglayer!);\n}\n\n\nlet activatetouches: number[] = [];\nlet expectnumtouches = Infinity;\nlet expecttaptime = Infinity;\n\nfunction testMenuTap(event: Event) {\n  activatetouches.push(Date.now());\n  activatetouches = activatetouches.slice(-expectnumtouches);\n\n  const totaltime = (activatetouches.at(-1)! - activatetouches[0]);\n  if (totaltime) { // fast enough\n    if (activatetouches.length > 1)\n      dompack.stop(event);\n\n    if (activatetouches.length === expectnumtouches)\n      runPWADebugMenu();\n  }\n}\n\ndompack.register(\"[data-app-activatedebugmenu]\", node => {\n  const settings2 = node.dataset.appActivatedebugmenu?.split(':');\n  if (!settings2)\n    return;\n\n  expectnumtouches = parseInt(settings2[0]);\n  expecttaptime = parseInt(settings2[1]);\n  if (!expecttaptime || !expectnumtouches)\n    return;\n\n  node.addEventListener(\"touchstart\", testMenuTap);\n  node.addEventListener(\"click\", testMenuTap);\n});\n","let appname: string;\n\nexport function setAppName(newappname: string) {\n  appname = newappname;\n}\n\nexport function getAppName() {\n  return appname;\n}\n","const instanceOfAny = (object, constructors) => constructors.some((c) => object instanceof c);\n\nlet idbProxyableTypes;\nlet cursorAdvanceMethods;\n// This is a function to prevent it throwing up in node environments.\nfunction getIdbProxyableTypes() {\n    return (idbProxyableTypes ||\n        (idbProxyableTypes = [\n            IDBDatabase,\n            IDBObjectStore,\n            IDBIndex,\n            IDBCursor,\n            IDBTransaction,\n        ]));\n}\n// This is a function to prevent it throwing up in node environments.\nfunction getCursorAdvanceMethods() {\n    return (cursorAdvanceMethods ||\n        (cursorAdvanceMethods = [\n            IDBCursor.prototype.advance,\n            IDBCursor.prototype.continue,\n            IDBCursor.prototype.continuePrimaryKey,\n        ]));\n}\nconst transactionDoneMap = new WeakMap();\nconst transformCache = new WeakMap();\nconst reverseTransformCache = new WeakMap();\nfunction promisifyRequest(request) {\n    const promise = new Promise((resolve, reject) => {\n        const unlisten = () => {\n            request.removeEventListener('success', success);\n            request.removeEventListener('error', error);\n        };\n        const success = () => {\n            resolve(wrap(request.result));\n            unlisten();\n        };\n        const error = () => {\n            reject(request.error);\n            unlisten();\n        };\n        request.addEventListener('success', success);\n        request.addEventListener('error', error);\n    });\n    // This mapping exists in reverseTransformCache but doesn't exist in transformCache. This\n    // is because we create many promises from a single IDBRequest.\n    reverseTransformCache.set(promise, request);\n    return promise;\n}\nfunction cacheDonePromiseForTransaction(tx) {\n    // Early bail if we've already created a done promise for this transaction.\n    if (transactionDoneMap.has(tx))\n        return;\n    const done = new Promise((resolve, reject) => {\n        const unlisten = () => {\n            tx.removeEventListener('complete', complete);\n            tx.removeEventListener('error', error);\n            tx.removeEventListener('abort', error);\n        };\n        const complete = () => {\n            resolve();\n            unlisten();\n        };\n        const error = () => {\n            reject(tx.error || new DOMException('AbortError', 'AbortError'));\n            unlisten();\n        };\n        tx.addEventListener('complete', complete);\n        tx.addEventListener('error', error);\n        tx.addEventListener('abort', error);\n    });\n    // Cache it for later retrieval.\n    transactionDoneMap.set(tx, done);\n}\nlet idbProxyTraps = {\n    get(target, prop, receiver) {\n        if (target instanceof IDBTransaction) {\n            // Special handling for transaction.done.\n            if (prop === 'done')\n                return transactionDoneMap.get(target);\n            // Make tx.store return the only store in the transaction, or undefined if there are many.\n            if (prop === 'store') {\n                return receiver.objectStoreNames[1]\n                    ? undefined\n                    : receiver.objectStore(receiver.objectStoreNames[0]);\n            }\n        }\n        // Else transform whatever we get back.\n        return wrap(target[prop]);\n    },\n    set(target, prop, value) {\n        target[prop] = value;\n        return true;\n    },\n    has(target, prop) {\n        if (target instanceof IDBTransaction &&\n            (prop === 'done' || prop === 'store')) {\n            return true;\n        }\n        return prop in target;\n    },\n};\nfunction replaceTraps(callback) {\n    idbProxyTraps = callback(idbProxyTraps);\n}\nfunction wrapFunction(func) {\n    // Due to expected object equality (which is enforced by the caching in `wrap`), we\n    // only create one new func per func.\n    // Cursor methods are special, as the behaviour is a little more different to standard IDB. In\n    // IDB, you advance the cursor and wait for a new 'success' on the IDBRequest that gave you the\n    // cursor. It's kinda like a promise that can resolve with many values. That doesn't make sense\n    // with real promises, so each advance methods returns a new promise for the cursor object, or\n    // undefined if the end of the cursor has been reached.\n    if (getCursorAdvanceMethods().includes(func)) {\n        return function (...args) {\n            // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n            // the original object.\n            func.apply(unwrap(this), args);\n            return wrap(this.request);\n        };\n    }\n    return function (...args) {\n        // Calling the original function with the proxy as 'this' causes ILLEGAL INVOCATION, so we use\n        // the original object.\n        return wrap(func.apply(unwrap(this), args));\n    };\n}\nfunction transformCachableValue(value) {\n    if (typeof value === 'function')\n        return wrapFunction(value);\n    // This doesn't return, it just creates a 'done' promise for the transaction,\n    // which is later returned for transaction.done (see idbObjectHandler).\n    if (value instanceof IDBTransaction)\n        cacheDonePromiseForTransaction(value);\n    if (instanceOfAny(value, getIdbProxyableTypes()))\n        return new Proxy(value, idbProxyTraps);\n    // Return the same value back if we're not going to transform it.\n    return value;\n}\nfunction wrap(value) {\n    // We sometimes generate multiple promises from a single IDBRequest (eg when cursoring), because\n    // IDB is weird and a single IDBRequest can yield many responses, so these can't be cached.\n    if (value instanceof IDBRequest)\n        return promisifyRequest(value);\n    // If we've already transformed this value before, reuse the transformed value.\n    // This is faster, but it also provides object equality.\n    if (transformCache.has(value))\n        return transformCache.get(value);\n    const newValue = transformCachableValue(value);\n    // Not all types are transformed.\n    // These may be primitive types, so they can't be WeakMap keys.\n    if (newValue !== value) {\n        transformCache.set(value, newValue);\n        reverseTransformCache.set(newValue, value);\n    }\n    return newValue;\n}\nconst unwrap = (value) => reverseTransformCache.get(value);\n\n/**\n * Open a database.\n *\n * @param name Name of the database.\n * @param version Schema version.\n * @param callbacks Additional callbacks.\n */\nfunction openDB(name, version, { blocked, upgrade, blocking, terminated } = {}) {\n    const request = indexedDB.open(name, version);\n    const openPromise = wrap(request);\n    if (upgrade) {\n        request.addEventListener('upgradeneeded', (event) => {\n            upgrade(wrap(request.result), event.oldVersion, event.newVersion, wrap(request.transaction), event);\n        });\n    }\n    if (blocked) {\n        request.addEventListener('blocked', (event) => blocked(\n        // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n        event.oldVersion, event.newVersion, event));\n    }\n    openPromise\n        .then((db) => {\n        if (terminated)\n            db.addEventListener('close', () => terminated());\n        if (blocking) {\n            db.addEventListener('versionchange', (event) => blocking(event.oldVersion, event.newVersion, event));\n        }\n    })\n        .catch(() => { });\n    return openPromise;\n}\n/**\n * Delete a database.\n *\n * @param name Name of the database.\n */\nfunction deleteDB(name, { blocked } = {}) {\n    const request = indexedDB.deleteDatabase(name);\n    if (blocked) {\n        request.addEventListener('blocked', (event) => blocked(\n        // Casting due to https://github.com/microsoft/TypeScript-DOM-lib-generator/pull/1405\n        event.oldVersion, event));\n    }\n    return wrap(request).then(() => undefined);\n}\n\nconst readMethods = ['get', 'getKey', 'getAll', 'getAllKeys', 'count'];\nconst writeMethods = ['put', 'add', 'delete', 'clear'];\nconst cachedMethods = new Map();\nfunction getMethod(target, prop) {\n    if (!(target instanceof IDBDatabase &&\n        !(prop in target) &&\n        typeof prop === 'string')) {\n        return;\n    }\n    if (cachedMethods.get(prop))\n        return cachedMethods.get(prop);\n    const targetFuncName = prop.replace(/FromIndex$/, '');\n    const useIndex = prop !== targetFuncName;\n    const isWrite = writeMethods.includes(targetFuncName);\n    if (\n    // Bail if the target doesn't exist on the target. Eg, getAll isn't in Edge.\n    !(targetFuncName in (useIndex ? IDBIndex : IDBObjectStore).prototype) ||\n        !(isWrite || readMethods.includes(targetFuncName))) {\n        return;\n    }\n    const method = async function (storeName, ...args) {\n        // isWrite ? 'readwrite' : undefined gzipps better, but fails in Edge :(\n        const tx = this.transaction(storeName, isWrite ? 'readwrite' : 'readonly');\n        let target = tx.store;\n        if (useIndex)\n            target = target.index(args.shift());\n        // Must reject if op rejects.\n        // If it's a write operation, must reject if tx.done rejects.\n        // Must reject with op rejection first.\n        // Must resolve with op value.\n        // Must handle both promises (no unhandled rejections)\n        return (await Promise.all([\n            target[targetFuncName](...args),\n            isWrite && tx.done,\n        ]))[0];\n    };\n    cachedMethods.set(prop, method);\n    return method;\n}\nreplaceTraps((oldTraps) => ({\n    ...oldTraps,\n    get: (target, prop, receiver) => getMethod(target, prop) || oldTraps.get(target, prop, receiver),\n    has: (target, prop) => !!getMethod(target, prop) || oldTraps.has(target, prop),\n}));\n\nconst advanceMethodProps = ['continue', 'continuePrimaryKey', 'advance'];\nconst methodMap = {};\nconst advanceResults = new WeakMap();\nconst ittrProxiedCursorToOriginalProxy = new WeakMap();\nconst cursorIteratorTraps = {\n    get(target, prop) {\n        if (!advanceMethodProps.includes(prop))\n            return target[prop];\n        let cachedFunc = methodMap[prop];\n        if (!cachedFunc) {\n            cachedFunc = methodMap[prop] = function (...args) {\n                advanceResults.set(this, ittrProxiedCursorToOriginalProxy.get(this)[prop](...args));\n            };\n        }\n        return cachedFunc;\n    },\n};\nasync function* iterate(...args) {\n    // tslint:disable-next-line:no-this-assignment\n    let cursor = this;\n    if (!(cursor instanceof IDBCursor)) {\n        cursor = await cursor.openCursor(...args);\n    }\n    if (!cursor)\n        return;\n    cursor = cursor;\n    const proxiedCursor = new Proxy(cursor, cursorIteratorTraps);\n    ittrProxiedCursorToOriginalProxy.set(proxiedCursor, cursor);\n    // Map this double-proxy back to the original, so other cursor methods work.\n    reverseTransformCache.set(proxiedCursor, unwrap(cursor));\n    while (cursor) {\n        yield proxiedCursor;\n        // If one of the advancing methods was not called, call continue().\n        cursor = await (advanceResults.get(proxiedCursor) || cursor.continue());\n        advanceResults.delete(proxiedCursor);\n    }\n}\nfunction isIteratorProp(target, prop) {\n    return ((prop === Symbol.asyncIterator &&\n        instanceOfAny(target, [IDBIndex, IDBObjectStore, IDBCursor])) ||\n        (prop === 'iterate' && instanceOfAny(target, [IDBIndex, IDBObjectStore])));\n}\nreplaceTraps((oldTraps) => ({\n    ...oldTraps,\n    get(target, prop, receiver) {\n        if (isIteratorProp(target, prop))\n            return iterate;\n        return oldTraps.get(target, prop, receiver);\n    },\n    has(target, prop) {\n        return isIteratorProp(target, prop) || oldTraps.has(target, prop);\n    },\n}));\n\nexport { deleteDB, openDB, unwrap, wrap };\n","import * as idb from 'idb';\n\nexport async function deleteDatabase(appname: string) {\n  try {\n    await idb.deleteDB('pwadb-' + appname);\n  } catch (e) {\n    console.log(\"Deletedb failed\", e);\n  }\n}\n\nexport async function clearCache(appname: string) {\n  try {\n    const cache = await window.caches.open(\"pwacache-\" + appname);\n    for (const key of await cache.keys())\n      await cache.delete(key);\n  } catch (e) {\n    console.error(\"Cache cleanup failed\", e);\n    throw e;\n  }\n}\n\nexport async function unregisterServiceWorkers() {\n  const currentregistrations = await navigator.serviceWorker.getRegistrations();\n  for (const reg of currentregistrations)\n    await reg.unregister();\n}\n","// Auto-generated language file from /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/webfeatures/sirform/sirform.lang.json\nvar registerTexts = require(\"@webhare/gettid/src/internal\").registerTexts;\nregisterTexts(\"utwente_voorlichting\",\"nl\",{\"frontend\":{\"sirform\":{\"askquestion\":\"Vraag stellen\",\"event\":\"Evenement\",\"eventtype\":\"Evenementstype\",\"genericinterest_bsc\":\"BSc opleidingen in het algemeen\",\"genericinterest_msc\":\"MSc opleidingen in het algemeen\",\"interestedin\":\"Ik ben geïnteresseerd in\",\"question\":\"Vragen?\",\"question-placeholder\":\"Laat hier een vraag achter en we reageren via email\",\"resetbutton\":\"Volgende gebruiker\",\"school\":\"School\",\"selectinterest\":\"Selecteer interesse\",\"selectvalue\":\"Kies waarde\",\"thankyou_message\":\"Het formulier is verzonden. Dank je voor je interesse in de University of Twente.\",\"thankyou_optin_message\":\"We houden je op de hoogte! Bedankt voor je interesse in Universiteit Twente.\",\"update_downloaded\":\"Er is een update gedownload van SIR, ververs de pagina (F5 / cmd+r) om de nieuwe versie te gebruiken.\"}}});\nregisterTexts(\"utwente_voorlichting\",\"en\",{\"frontend\":{\"sirform\":{\"askquestion\":\"I want to ask a question\",\"event\":\"Event\",\"eventtype\":\"Event type\",\"genericinterest_bsc\":\"BSc programmes in general\",\"genericinterest_msc\":\"MSc programmes in general\",\"interestedin\":\"My interests\",\"question\":\"Questions?\",\"question-placeholder\":\"Leave your question here and we will reply via email\",\"resetbutton\":\"Next user\",\"school\":\"School\",\"selectinterest\":\"Select interest\",\"selectvalue\":\"Select value\",\"thankyou_message\":\"The registration has been submitted successfully. Thank you for your interest in the University of Twente\",\"thankyou_optin_message\":\"We will keep you informed! Thank you for your interest in the University of Twente.\",\"update_downloaded\":\"An update has been downloaded for SIR. Please restart (F5 / cmd+r) to use the new version.\"}}});\nregisterTexts(\"utwente_voorlichting\",\"de\",{\"frontend\":{\"sirform\":{\"askquestion\":\"Frage stellen\",\"event\":\"Event\",\"eventtype\":\"Event type\",\"genericinterest_bsc\":\"BSc-Studiengänge im Allgemeinen\",\"genericinterest_msc\":\"MSc-Studiengänge im Allgemeinen\",\"interestedin\":\"Ich interessiere mich für\",\"question\":\"Fragen?\",\"question-placeholder\":\"Stellen Sie hier Ihre Frage, wir antworten Ihnen per E-Mail.\",\"resetbutton\":\"Nächster Benutzer\",\"school\":\"Schule\",\"selectinterest\":\"Interessen auswählen\",\"selectvalue\":\"Wert auswählen\",\"thankyou_message\":\"Das Formular wurde erfolgreich versendet\",\"thankyou_optin_message\":\"Wir halten Sie auf dem Laufenden! Vielen Dank für Ihr Interesse an der Universität Twente.\",\"update_downloaded\":\"An update has been downloaded for SIR. Please restart (F5 / cmd+r) to use the new version.\"}}});\nregisterTexts(\"utwente_voorlichting\",\"es\",{\"frontend\":{\"sirform\":{\"askquestion\":\"I want to ask a question\",\"event\":\"Event\",\"eventtype\":\"Event type\",\"genericinterest_bsc\":\"BSc programmes in general\",\"genericinterest_msc\":\"MSc programmes in general\",\"interestedin\":\"My interests\",\"question\":\"Questions?\",\"question-placeholder\":\"Leave your question here and we will reply via email\",\"resetbutton\":\"Next user\",\"school\":\"School\",\"selectinterest\":\"Select interest\",\"selectvalue\":\"Select value\",\"thankyou_message\":\"The registration has been submitted successfully. Thank you for your interest in the University of Twente\",\"thankyou_optin_message\":\"We will keep you informed! Thank you for your interest in the University of Twente.\",\"update_downloaded\":\"An update has been downloaded for SIR. Please restart (F5 / cmd+r) to use the new version.\"}}});\nregisterTexts(\"utwente_voorlichting\",\"it\",{\"frontend\":{\"sirform\":{\"askquestion\":\"I want to ask a question\",\"event\":\"Event\",\"eventtype\":\"Event type\",\"genericinterest_bsc\":\"BSc programmes in general\",\"genericinterest_msc\":\"MSc programmes in general\",\"interestedin\":\"My interests\",\"question\":\"Questions?\",\"question-placeholder\":\"Leave your question here and we will reply via email\",\"resetbutton\":\"Next user\",\"school\":\"School\",\"selectinterest\":\"Select interest\",\"selectvalue\":\"Select value\",\"thankyou_message\":\"The registration has been submitted successfully. Thank you for your interest in the University of Twente\",\"thankyou_optin_message\":\"We will keep you informed! Thank you for your interest in the University of Twente.\",\"update_downloaded\":\"An update has been downloaded for SIR. Please restart (F5 / cmd+r) to use the new version.\"}}});\nregisterTexts(\"utwente_voorlichting\",\"xt\",{\"frontend\":{\"sirform\":{\"askquestion\":\"I want to ask a question\",\"event\":\"Event\",\"eventtype\":\"Event type\",\"genericinterest_bsc\":\"BSc programmes in general\",\"genericinterest_msc\":\"MSc programmes in general\",\"interestedin\":\"My interests\",\"question\":\"Questions?\",\"question-placeholder\":\"Leave your question here and we will reply via email\",\"resetbutton\":\"Next user\",\"school\":\"School\",\"selectinterest\":\"Select interest\",\"selectvalue\":\"Select value\",\"thankyou_message\":\"The registration has been submitted successfully. Thank you for your interest in the University of Twente\",\"thankyou_optin_message\":\"We will keep you informed! Thank you for your interest in the University of Twente.\",\"update_downloaded\":\"An update has been downloaded for SIR. Please restart (F5 / cmd+r) to use the new version.\"}}});\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/nl.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/de.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/es.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n// Adding dependency: /opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/language/default.xml\n","\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\n/*\n  Only used for activities page!\n  Obsolete in ws2026 which uses generic filters,\n  after switching to ws2026 this file can be removed\n*/\n\nimport * as dompack from \"dompack\";\n\n// we MUST remove unused blocks from the DOM so the nth-child counting works correct\n// (we need nth child because CSS doesn't have a nth-col/nth-last-col yet)\nlet blocksorder;\nlet bigline;\n\n\nfunction initBlocksPage(switchform) {\n  switchform.addEventListener(\"change\", () => onSwitchCategory(switchform));\n\n  const blocks = document.querySelectorAll(\".blockswidget__item\");\n  blocksorder = Array.from(blocks);\n  bigline = document.querySelector(\".blockswidget__bigline\");\n}\n\nfunction onSwitchCategory(switchform) {\n  const category = switchform.category.value;\n\n  const container = document.querySelector(\".blockswidget__content\");\n  let results = 0;\n\n  if (bigline.parentNode)\n    container.removeChild(bigline);\n\n  const no_filter = category === \"\" || category === \"all\";\n\n  for (const node of blocksorder) {\n    let match = true;\n    if (!no_filter) {\n      const relatedto = node.dataset.relevantto.split(\" \");\n      // node.classList.toggle(\"blockswidget__item--hidden\", relatedto.indexOf(category) == -1);\n      match = relatedto.indexOf(category) > -1;\n    }\n\n    if (match) {\n      container.appendChild(node);\n\n      if (results === 0)\n        container.appendChild(bigline);\n\n      results++;\n    } else if (node.parentNode)  { // still in the DOM ?\n      container.removeChild(node);\n    }\n  }\n}\n\ndompack.register(\".blockswidget__form\", initBlocksPage);\n","import \"./activities.scss\";\nimport \"./my-activities.scss\";\nimport \"./blockspage\";\nimport \"./blockspage.scss\";\n\nimport * as dompack from \"@webhare/dompack\";\nimport { addDocEventListener } from \"@webhare/dompack\";\n\nimport \"./activitieslist\";\nimport { throwError } from \"@webhare/std\";\n\n\n// Upon selecting an event we must update\nfunction initActivitiesList(node: HTMLElement) {\n  const form = dompack.qR(node, \"form\");\n  addDocEventListener(form, \"change\", evt => onChangeEventOption(evt));\n\n  /* These activityiitems may contain options. If so, diasble the button until an option is chosen */\n  if (node.querySelector(\"input[type=radio]\") && !node.querySelector(\"input[type=radio]:checked\")) {\n    const signupbutton = dompack.qS<HTMLAnchorElement>(node, \".activityitem__signupbutton a[href]\");\n    if (signupbutton) {\n      signupbutton.ariaDisabled = \"true\";\n      signupbutton.tabIndex = -1;\n    }\n  }\n}\n\nfunction onChangeEventOption(evt: dompack.DocEvent<Event>) {\n  const form = evt.target.closest<HTMLFormElement>(\"form\")!;\n  const optionnode = evt.target as dompack.FormControlElement;\n  const option = optionnode.value;\n\n  if (optionnode.name === \"option\") { //these are the 'day' selectors, not a timeslot\n    const optionspecificnodes = evt.target.closest(\".activityitem\")!.querySelectorAll<HTMLElement>(\"[data-foroption]\");\n    for (const node of optionspecificnodes) {\n      node.classList.toggle(\"activityitem__ischosenoption\", node.dataset.foroption === option);\n    }\n\n    const myPanel = optionnode.closest<HTMLElement>(\".activityitem__panel\") ?? throwError(\"Could not find the activity item panel\");\n    for (const timeslotheader of dompack.qSA(\".activityitem__options__label--timeslots\")) {\n      timeslotheader.hidden = !option || timeslotheader.closest(\".activityitem__panel\") !== myPanel;\n    }\n\n    for (const timeslot of dompack.qSA(myPanel, \".activityitem__option--timeslot\")) {\n      timeslot.hidden = !option || timeslot.dataset.timeslotForEvent !== option;\n      dompack.qR<HTMLInputElement>(timeslot, \"input\").checked = false;\n    }\n  }\n\n  const signuplink = optionnode.dataset.signuplink;\n  const signupbutton = dompack.qR(form, \".activityitem__signupbutton a[href]\");\n\n  if (signuplink) {\n    signupbutton.setAttribute(\"href\", signuplink);\n    signupbutton.ariaDisabled = null;\n    signupbutton.tabIndex = 0;\n  } else {\n    signupbutton.ariaDisabled = \"true\";\n    signupbutton.tabIndex = -1;\n\n  }\n}\n\ndompack.register(\".activityitem--withdayselect\", initActivitiesList);\n","/* xeslint-disable */\n// x@ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport SmoothScroll from \"../components/smoothscroll\";\nimport scrollListener from \"../components/scrolllistener\";\nimport { openFoldableContent } from \"../widgets/embeddedobjects\";\nimport { getCSSVariable } from \"./layout-tools\";\nimport { getTid } from \"@webhare/gettid\";\n\n// make some widgets stick to eachother or automatically get or lose borders\n// when they are next to each other.\nimport { activateSmartLayout } from \"./smartlayout\";\nimport \"./smartlayout.scss\";\n\n/*\n.ut--notfoldable\n    This element will be left in it's position in the DOM and not folded into an accordion item.\n    (Initial commet from Arnold (ocrt 2016) about this: \"Stop folden bij eerste element met .ut--notfoldable\")\n    - This element isn't allowed to be \"folded\". Instead it will be always be merged into a deeplink container.\n\n.ut--dontfoldcontent\n    This element must be merged into a accordion item in it's entirity. (it's H2's won't be folder).\n\n.hasfoldabledeeplink\n    This element contains content divided into an accordion using the H2's.\n*/\n\nlet windowMode: null | \"small\" | \"wide\" = null;\n\n// Page scroll duration\nconst scrollDuration = 300;\n\n// Record initial hash\nconst initialhash = location.hash;\n\nfunction openFoldableDeepLink(node: HTMLElement) {\n  node.classList.add(\"foldabledeeplink--open\");\n\n  const container = node.querySelector<HTMLElement>(\".foldabledeeplink__foldcontainer\");\n  if (!container) // If there wasn't content between this h2 and the next, no foldercontainer will have been created\n    return;\n\n  container.style.height = \"auto\";\n  container.style.overflow = \"inherit\";\n}\n\nfunction checkWindowMode(mode: \"small\" | \"wide\") {\n  if (mode !== windowMode) {\n    windowMode = mode;\n    if (windowMode === \"small\") {\n      const hash = document.location.hash.replace(\"#\", \"\");\n      // Enable foldable content\n      for (const node of document.querySelectorAll<HTMLElement>(\".foldabledeeplink\")) {\n        if (hash) {\n          //NOTE: This will not work if the id clashes with an id in the design (e.g. \"menu\") as the foldable id will be\n          //      rewritten (e.g. to \"menu-1\")\n          const idnode = node.querySelector(\"[id]\");\n          if (idnode && idnode.id === hash) { //If hash in url is equal to id, show container content\n            openFoldableDeepLink(node);\n          }\n        }\n        node.classList.remove(\"foldabledeeplink--disabled\");\n      }\n    } else {\n      // Disable foldable content\n      for (const node of document.querySelectorAll(\".foldabledeeplink\"))\n        node.classList.add(\"foldabledeeplink--disabled\");\n    }\n  }\n}\n\n/*\nShow the user where they are on the page\n- Update the visible deeplinks to show where you currently are in the page\n- Update the hash on the URL\n*/\nfunction checkHiglightDeeplink() {\n  // Find the deeplink containing our current content\n  let besthref = '', bestdeeplink;\n  const deeplinklist = dompack.qSA(\".main__deeplink\");\n  for (const deeplink of deeplinklist) {\n    const href = deeplink.getAttribute(\"href\") || '';\n    if (!href.startsWith('#'))\n      continue;\n\n    let target = document.getElementById(href.substr(1));\n    if (!target)\n      continue;\n\n    // If this is an <a> anchor link, switch to the parent <h2>\n    // <h2><a class=\"wh-rtd__anchor\" id=\"\"/></h2>\n    if (target.classList.contains(\"wh-rtd__anchor\") || target.classList.contains(\"wh-anchor\"))\n      target = target.closest(\"h2\") || target;\n\n    if (target.getBoundingClientRect().y <= window.innerHeight / 3) { //this one is at top or outside\n\n      bestdeeplink = deeplink;\n      besthref = href;\n    }\n\n  }\n\n  if (bestdeeplink && bestdeeplink.classList.contains(\"isvisible\"))\n    return; //already best one in sight\n\n  const currentvisible = dompack.qS(\".main__deeplink.isvisible\");\n  if (!bestdeeplink && !currentvisible)\n    return; //already no selected link\n\n  if (currentvisible)\n    currentvisible.classList.remove(\"isvisible\");\n\n  if (bestdeeplink) {\n    bestdeeplink.classList.add(\"isvisible\");\n    let isbefore = true;\n    for (const deeplink of deeplinklist) {\n      if (deeplink === bestdeeplink)\n        isbefore = false;\n\n      if (isbefore)\n        deeplink.classList.add(\"isbefore\");\n      else\n        deeplink.classList.remove(\"isbefore\");\n    }\n\n    //set hash on url\n    if (history.replaceState) {\n      //small timeout because some browsers (like safari) jump to anchor directly after loading page\n      setTimeout(function () { history.replaceState(null, \"\", document.location.href.split(\"#\")[0] + besthref); }, 10);\n    }\n  } else {\n    //remove hash from url\n    if (history.replaceState) {\n      //small timeout because some browsers (like safari) jump to anchor directly after loading page\n      setTimeout(function () { history.replaceState(null, \"\", document.location.href.split(\"#\")[0]); }, 10);\n    }\n  }\n}\n\n\n/* In a CSS grid layout, floating elements don't escape their grid line, which in effect causes each paragraph to clear any\n   floating elements. If an empty paragraph contains a floating image, the image is displayed on its own, without the text of\n   the next paragraph floating around it. To get around this limitation, we'll wrap consecutive paragraphs into one node, so\n   images can float within that node, which gets aligned to the CSS grid.\n   To activate this functionality for a container that has a grid layout and paragraph children that might contain floating\n   images, add the 'ut-wrapfloats' class to the container node.\n\n   Containers:\n   - .contentpart__main (wrapper when the page hasn't been rearranged serverside for the mobile accordeon)\n   - .wh-form__richtext (richtext field in form page)\n   - .ut-wrapfloats (opt-in for grids container elements containing RTD content (direct children)\n   - .ut-rtd-blocks__body (blocks of RTD content generated serverside to use as mobile accordeon)\n*/\nfunction combineFloatParagraphs() {\n  // Process the main content node and any node that opts in\n  for (const container of document.querySelectorAll(\".contentpart__main, .wh-form__richtext, .ut-wrapfloats, .ut-rtd-blocks__body\")) {\n    // Skip this container if it doesn't have children containing floating images\n    if (!container.querySelector(\":scope > p > img.wh-rtd__img--floatleft, :scope > p > img.wh-rtd__img--floatright\"))\n      continue;\n\n    let toCombine = [];\n    let child = container.firstElementChild;\n    while (child) {\n      // Keep a reference to the next child node, as we might move the current child to another parent\n      const nextChild = child.nextElementSibling;\n      // If this is a paragraph with a floating image, or if we already have paragraphs to combine, add it to the list\n      if (child.nodeName === \"P\" && (toCombine.length || child.querySelector(\":scope > img.wh-rtd__img--floatleft, :scope > img.wh-rtd__img--floatright\"))) {\n        toCombine.push(child);\n      } else {\n        // If there are multiple paragraphs, wrap them into one section, so floating images can span paragraphs\n        if (toCombine.length > 1) {\n          const section = <section class=\"ut-floatwrapper\" />;\n          section.append(...toCombine);\n          // Insert the section before the current (non-paragraph) child node\n          child.before(section);\n        }\n        toCombine = [];\n      }\n      child = nextChild;\n    }\n    // If there are multiple paragraphs left, wrap them and append to the container\n    if (toCombine.length > 1) {\n      const section = <section class=\"ut-floatwrapper\" />;\n      section.append(...toCombine);\n      container.append(section);\n    }\n  }\n}\n\nfunction convertDetailSummaries() {\n  dompack.qSA(\"details:not(.ut-no-refold) > summary\").forEach(summary => {\n    const details = summary.parentElement as HTMLDetailsElement;\n    details.removeChild(summary); //prevent <summary> from being cloned into the foldcontainer\n    details.replaceWith(<div class=\"foldablecontent\">\n      <div class=\"foldablecontent__title\">{Array.from(summary.childNodes)}</div>\n      <div class=\"foldablecontent__foldcontainer\"><div class=\"foldablecontent__text\">{Array.from(details.childNodes)}</div></div>\n    </div>);\n  });\n}\n\nexport function doChangesToRichtextContent() {\n  // To ensure allowing multiple paragraphs to flow around an floating image we\n  // need to combine these paragraphs. Otherwise a new paragraph won't wrap around the float\n  // due to our richtext nodes being part of a grid.\n  combineFloatParagraphs();\n\n  // before we reorder the DOM into foldabledeeplinks\n  // we want to preserve the information on what type of content (p, widget type)\n  // are next to eachother so we can implement special rules for spacing which require us to know bordering content.\n  activateSmartLayout();\n\n  // Convert <details><summary> elements into our own DOM so we have more control on layout and animation\n  convertDetailSummaries();\n\n  checkJumpIntoDeeplink();\n\n  //don't collapse inside NEO in desktop mode (487 or 535 pixels), https://gitlab.webhare.com/utwente/utwente_base/-/issues/1262\n  if (document.documentElement.dataset.nodeeplinks)\n    return;\n\n  if (document.documentElement.classList.contains(\"ws2016--iframed\")) {\n    if ((window.innerWidth >= 483 && window.innerWidth <= 490) || (window.innerWidth >= 530 && window.innerWidth <= 540))\n      return;\n  }\n\n  setupDeepLinks();\n}\n\nfunction setupDeepLinks() {\n  // Ensure tables aren't devided into deeplinks AND get absorbed into\n  for (const tablenode of dompack.qSA(\".wh-rtd__tablewrap\"))\n    tablenode.classList.add(\"ut--dontfoldcontent\");\n\n  const headings = [];\n  for (const h2 of dompack.qSA(\"h2:not([data-ut-ignore-deeplink]):not(.wh-form__grouptitle)\")) {\n    if (h2.closest(\".wh-details__container\"))\n      continue; //Ignore if already inside a foldable container, utwente/utwente_base#1962\n    // if (h2.closest(\".ut-no-refold\"))\n    //   continue; //Ignore if inside a modernized page\n\n    const formpage = h2.closest(\".wh-form__page\");\n    if (formpage && formpage.previousElementSibling && formpage.previousElementSibling.classList.contains(\"wh-form__page\"))\n      continue; //Skip if h2 is inside followup page inside forms\n\n    // FIXME: maybe we could add the H2's from the table to the deeplinks, but not fold them.\n    //        To do this we would need to replace the array \"target\" (with all h2's to both add to the list and fold) into two lists.\n    if (h2.closest(\".wh-rtd__tablecell\"))\n      continue; //dont create folds in tables, utwente/utwente_base#1136\n\n\n    let anchor;\n    if (h2.id)\n      anchor = h2;\n\n    const linkanchor = h2.querySelector(\"a[id]\");\n    if (linkanchor)\n      anchor = linkanchor;\n\n    if (!anchor)\n      continue; //skip any h2 without an anchor\n\n    // If a deeplink has the same name as another element on the page (e.g. \"menu\"), rename the id\n    if (document.querySelectorAll(`*[id='${anchor.id}']`).length > 1) {\n      let i = 1;\n      let newid = anchor.id + \"-\" + i;\n      while (document.getElementById(newid))\n        newid = anchor.id + \"-\" + ++i;\n      anchor.id = newid;\n    }\n\n    //Note title attribute is also used for ellipsis of link text (fn ellipsisDeeplinks)\n    headings.push(<li class=\"main__deeplinkitem\"><a class=\"main__deeplink\" title={h2.textContent} propTarget={h2} href={\"#\" + anchor.id}>{h2.textContent}</a></li>);\n  }\n  if (headings.length <= 1) //no deeplinks if we only have one (utwente/itcwebsite#112)\n    return;\n\n  const deeplinksNode =\n    <nav class=\"main__deeplinks\" aria-label={getTid(\"utwente_base:frontend.ws2016.js.landmark-deeplinks-arialabel\")}>\n      <ul class=\"main__deeplinklist\">{headings}</ul>\n    </nav>;\n\n  let activateDeeplinksMedia;\n  dompack.qS('main')?.prepend(\n    <div class=\"contentpart__deeplinks\">\n      {deeplinksNode}\n    </div>);\n\n  void getCSSVariable(\"--breakpoint-deeplinks\").then(breakpoint_deeplinks => {\n    // Read the breakpoint CSS variable and get a MediaQueryList\n    activateDeeplinksMedia = matchMedia(`(max-width: ${breakpoint_deeplinks})`);\n    // Directly check the query\n    checkWindowMode(activateDeeplinksMedia.matches ? \"small\" : \"wide\");\n    // Setup an onchange listener to activate/deactivate the deeplinks\n    activateDeeplinksMedia.addEventListener(\"change\", event => checkWindowMode(event.matches ? \"small\" : \"wide\"));\n  });\n\n  // Initialize smooth scrolling for the deeplinks\n  const deeplinks = dompack.qSA(deeplinksNode, \".main__deeplink\");\n  new SmoothScroll(deeplinks, { duration: scrollDuration });\n  scrollListener.addNodes(deeplinks);\n\n  //Watch scrolls/resize and check deeplink to highlight after such a change\n  checkHiglightDeeplink();\n  window.addEventListener(\"scroll\", checkHiglightDeeplink);\n  window.addEventListener(\"ws:resize\", checkHiglightDeeplink);\n\n  const targets = [];\n  deeplinks.forEach(deeplink => {\n    const href = deeplink.getAttribute(\"href\") || '';\n    if (!href.startsWith('#'))\n      return;\n\n    let target = document.getElementById(href.substr(1));\n    if (!target)\n      return;\n\n    // If this is an <a> anchor link, switch to the parent <h2>\n    // <h2><a class=\"wh-rtd__anchor\" id=\"\"/></h2>\n    if (target.classList.contains(\"wh-rtd__anchor\") || target.classList.contains(\"wh-anchor\"))\n      target = target.closest(\"h2\") || target;\n\n    // Prepend the target to the list of targets\n    targets.unshift(target);\n  });\n\n  ellipsisDeeplinks(deeplinks);\n  window.addEventListener(\"load\", () => ellipsisDeeplinks(deeplinks));//font loaded\n  window.addEventListener(\"ws:resize\", () => ellipsisDeeplinks(deeplinks)); //Incase deeplinks where hidden\n}\n\nfunction checkJumpIntoDeeplink() {//Check if the hash is inside a deeplink\n  let target;\n\n  if (initialhash && initialhash.length > 1) {\n    target = document.getElementById(initialhash.substr(1)); //not supporting <a name>, deprecated since html4 anyway\n    if (target)\n      doJumpIntoDeeplink(target);\n  }\n\n  window.addEventListener(\"hashchange\", () => {\n    if (location.hash.length <= 1)\n      return;\n\n    const target2 = document.getElementById(location.hash.substr(1));\n    if (target2)\n      doJumpIntoDeeplink(target2);\n  });\n}\n\n/** @short make sure all containers of the specified target are opened\n    @long This handles opening foldable deeplinks (which are meant for mobile) and foldable content\n*/\nexport function doJumpIntoDeeplink(target: HTMLElement | null) {\n  //console.info(\"doJumpIntoDeeplink\", target);\n\n  //Expand all my parents!\n  let checkexpand = target;\n  const expandlist = [];\n\n  // If the specified target is a foldable\n  if (target?.matches(\".foldablecontent, .foldabledeeplink\"))\n    expandlist.unshift(target);\n\n  while (true) {\n    // checkexpand = checkexpand.parentNode.closest(\".foldablecontent__foldcontainer, .foldabledeeplink__foldcontainer\");\n    checkexpand = checkexpand?.parentElement?.closest(\".foldablecontent, .foldabledeeplink\") || null;\n    if (!checkexpand)\n      break;\n\n    expandlist.unshift(checkexpand);\n  }\n\n  //console.log(\"to reach\",target,\"we must expand\",expandlist);\n\n  // open the \"__foldcontainer\"'s\n  expandlist.forEach(toexpand => {\n    if (toexpand.classList.contains('foldabledeeplink')) {\n      //we can open this by clicking the parent .foldabledeeplink\n      openFoldableDeepLink(toexpand);\n    } else if (toexpand.classList.contains('foldablecontent')) {\n      openFoldableContent(toexpand);\n    } else {\n      console.log(\"don't know how to open \", toexpand);\n    }\n  });\n}\n\nfunction ellipsisDeeplinks(deeplinks: HTMLElement[]) {\n  deeplinks.forEach((deeplink) => {\n    let txt = deeplink.title;\n    let i = txt.length;\n    deeplink.textContent = txt;//Put back original text\n\n    const wrapper_h = deeplink.parentElement?.clientHeight || 0;\n    let txt_h = deeplink.clientHeight;\n    while (txt_h > wrapper_h && i > 0) {\n      txt = txt.substring(0, i - 1);\n      deeplink.textContent = txt;\n      txt_h = deeplink.clientHeight;\n      --i;\n    }\n\n    //Check for max width (in case of long words)\n    const wrapper_w = deeplink.parentElement?.clientWidth || 0;\n    while (deeplink.clientWidth > wrapper_w) {\n      txt = txt.substring(0, i - 1);\n      deeplink.textContent = txt;\n      txt_h = deeplink.clientHeight;\n      --i;\n    }\n\n    if (deeplink.title !== txt) //Ellipsis, then add ... at end\n      deeplink.textContent = txt.substring(0, i - 4) + \"...\";\n  });\n}\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport \"./activitieslist.scss\";\nimport \"./activitieslist-filter.scss\";\nimport * as deeplinks from \"@mod-utwente_base/webdesigns/ws2016/src/shared/deeplinks\";\nimport * as dialogapi from \"dompack/api/dialog\";\nimport PerfectScrollbar from \"@mod-utwente_design/vendor/perfect-scrollbar-wh\";\nimport * as dompack from \"@webhare/dompack\";\nimport setupToggle from \"../components/toggle\";\nimport { getTidLanguage } from \"@webhare/gettid\";\n\ndeclare module \"@webhare/frontend\" {\n  interface FrontendDataTypes {\n    \"utwente_voorlichting:activities\": {\n      addlinks: {link: string; title: string}[];\n    };\n  }\n}\n\nconst defaultshowamount = 5;\nlet showall = false;\nlet items_scroller: PerfectScrollbar | null = null; // PerfectScroll instance\n\n\ndompack.register(\".widget--activitieslist\", initFilters);\ndompack.register(\".blockswidget__item__preregistration\", node => node.addEventListener(\"click\", evt => runPreregistrationWidget(node, evt)));\n\nfunction runPreregistrationWidget(node, event) {\n  dompack.stop(event);\n\n  // TODO this might become a more generic widget popup at some point?\n  const dialogcode = node.querySelector('template');\n  if (!dialogcode)\n    throw new Error(\"<template> with dialog not found\");\n\n  const dialog = dialogapi.createDialog({ allowcancel: true });\n  dialog.contentnode.appendChild(dialogcode.content.cloneNode(true));\n  dompack.registerMissed(dialog.contentnode);\n  void dialog.runModal();\n}\n\nfunction initFilters(node) {\n  const tabstrip = node.querySelector(\".whflattabs\");\n  const form = tabstrip.classList.tagName === \"FORM\" ? tabstrip : tabstrip.closest(\"form\");\n  const toggle = node.querySelector(\".whflattabs__filtertoggle\");\n  const panel = node.querySelector(\".whflattabs__filterpanel\");\n  const closebutton = panel.querySelector(\".whflattabs__filterpanel__closebutton\");\n\n  const itemscontainer = node.querySelector(\".activities__filterpanel__items\");\n\n  itemscontainer.classList.add(\"ps-container--customstyling\");\n\n  items_scroller = new PerfectScrollbar(itemscontainer, {\n    wheelPropagation: false,\n    // , suppressScrollX : true\n    wheelSpeed: 2,\n    minScrollbarLength: 20\n  });\n\n  window.addEventListener(\"resize\", ev => {\n    items_scroller!.update();\n  });\n\n  window.addEventListener(\"load\", ev => {\n    items_scroller!.update();\n  });\n\n  // Preselection through URL\n  const program = new URLSearchParams(location.search).get(\"program\");\n  const category = new URLSearchParams(location.search).get(\"category\");\n  if (program) {\n    // Lookup the programme to see under which tab it lives\n    const item = node.querySelector(`.activityitem[data-programid=\"${CSS.escape(program)}\"]`);\n    if (item)\n      form.category.value = item.dataset.relevantto;\n\n    const checkboxnodes = node.querySelectorAll('.activities__filterpanel__items [type=\"checkbox\"]');\n    for (const cnode of checkboxnodes)\n      cnode.checked = cnode.dataset.urlparam === program;\n  } else if (category) {\n    form.category.value = category;\n  }\n\n  const settings = {\n    togglebutton: toggle,\n    closebutton: closebutton,\n    htmlclass: \"whflattabs__filterpanel--open\"\n  };\n\n  setupToggle(settings);\n\n  const showmorebutton = node.querySelector(\".activitieslist__showmore\");\n  showmorebutton.addEventListener(\"click\", doShowAll);\n\n\n  document.querySelector(\".whflattabs__filterpanel__showresults\").addEventListener(\"click\", doShowResults);\n\n  doFilter({ target: closebutton }); // FIXME: cleaner api to trigger a filter / update of results count\n  form.addEventListener(\"input\", doFilter);\n\n  // Preselection through URL\n  if (program) {\n    const visibleitems = node.querySelectorAll(\".activityitem:not(.activityitem--hidden)\");\n    if (visibleitems.length > 0)\n      deeplinks.doJumpIntoDeeplink(visibleitems[0]);\n  }\n}\n\nfunction doShowAll(evt: { target: HTMLElement }) {\n  document.querySelector(\".widget--activitieslist\").classList.add(\"widget--activitieslist-showall\");\n  showall = true;\n  doFilter(evt); // FIXME: cleaner api to trigger a filter / update of results count\n}\n\n// called when the button in mobile version of the filters panel is clicked\nfunction doShowResults() {\n  document.documentElement.classList.remove(\"whflattabs__filterpanel--open\");\n}\n\n\nfunction doFilter(evt: { target: HTMLElement }) {\n  const widgetnode = evt.target.closest(\".widget--activitieslist\")!;\n  const form = widgetnode.querySelector(\"form\");\n  const query = form.query.value;\n  const category = form.category.value;\n\n  const items = form.querySelectorAll(\".activities__filterpanel__item\");\n\n  const matching = []; // matches due to tabs and query\n  const selecteditems = []; // matching AND checked\n  const selecteditemstitle = [];\n  for (const itemnode of items) {\n    const match = (query === \"\" || itemnode.dataset.title.toLowerCase().indexOf(query) > -1)\n      &&\n      (category === \"\" || itemnode.dataset.relevantto.split(\",\").indexOf(category) > -1);\n\n    itemnode.classList.toggle(\"hidden\", !match);\n\n    const checkbox = itemnode.querySelector(\"input\");\n    checkbox.toggleAttribute(\"disabled\", !match);\n\n    if (match)\n      matching.push(checkbox.value);\n\n    if (match && checkbox.checked) {\n      selecteditems.push(checkbox.value);\n\n      const lookup = `[for=\"${checkbox.id}\"]`;\n      const labelnodes = document.querySelectorAll(lookup);\n\n      // Get the title from the associated label\n      for (const node of labelnodes) {\n        const itext = node.textContent;\n        if (itext) {\n          selecteditemstitle.push(itext);\n          break;\n        }\n      }\n\n    }\n  }\n\n  let visibleprogrammes = 0;\n  let visibleevents = []; // total amount of events within the visible programmes\n\n  for (const item of evt.target.closest(\".widget--activitieslist\").querySelectorAll(\".activityitem\")) {\n    const match = (selecteditems.length > 0 ? selecteditems.indexOf(item.dataset.studyfilterid) > - 1 : true)\n      &&\n      (category === \"\" || item.dataset.relevantto.split(\",\").indexOf(category) > -1);\n\n    item.classList.toggle(\"activityitem--hidden\", !match || (!showall && visibleprogrammes >= defaultshowamount));\n\n    if (match) {\n      visibleprogrammes++;\n      visibleevents = visibleevents.concat(item.dataset.eventids.split(\",\"));\n    }\n  }\n\n\n  const filterpanel = form.querySelector(\".whflattabs__filterpanel\");\n  filterpanel.classList.toggle(\"activities__filterpanel--noresults\", matching.length === 0);\n  widgetnode.classList.toggle(\"widget--activitieslist--noresults\", visibleprogrammes === 0);\n\n  const manually_checked_items = selecteditems.length > 0;\n\n  const unique_visible_events = new Set(visibleevents).size;\n\n\n  let resultstext = \"\";\n  if (manually_checked_items) {\n    const titles = [];\n    for (const title of selecteditemstitle)\n      titles.push(`“${title}”`);\n\n    if (visibleprogrammes === 1)\n      resultstext = getTidLanguage() === \"nl\" ? `<b>${unique_visible_events} resultaat</b> voor ` + titles.join(\", \")\n        : `<b>${unique_visible_events} result</b> for ` + titles.join(\", \");\n    else\n      resultstext = getTidLanguage() === \"nl\" ? `<b>${unique_visible_events} resultaten</b> voor ` + titles.join(\", \")\n        : `<b>${unique_visible_events} results</b> for ` + titles.join(\", \");\n  } else if (category === \"\") {\n    if (visibleprogrammes === 1)\n      resultstext = getTidLanguage() === \"nl\" ? `<b>${unique_visible_events} resultaat</b>`\n        : `<b>${unique_visible_events} result</b>`;\n    else\n      resultstext = getTidLanguage() === \"nl\" ? `<b>${unique_visible_events} resultaten</b>`\n        : `<b>${unique_visible_events} results</b>`;\n  } else if (category !== \"\") {\n    if (visibleprogrammes === 1)\n      resultstext = getTidLanguage() === \"nl\" ? `<b>${unique_visible_events} resultaat</b> voor “${category}”`\n        : `<b>${unique_visible_events} result</b> for “${category}”`;\n    else\n      resultstext = getTidLanguage() === \"nl\" ? `<b>${unique_visible_events} resultaten</b> voor “${category}”`\n        : `<b>${unique_visible_events} results</b> for “${category}”`;\n  }\n\n\n  widgetnode.querySelector(\".activitieslist__resultscount\").innerHTML = resultstext;\n\n  const showmorebutton = widgetnode.querySelector<HTMLElement>(\".activitieslist__showmore\");\n  if (showmorebutton) {\n    showmorebutton.style.display = (!showall && visibleprogrammes > defaultshowamount) ? \"block\" : \"none\";\n    dompack.qR(showmorebutton, \".activitieslist__showmore__category\").textContent = category;\n  }\n\n\n  let showbuttontext = \"\";\n  if (visibleprogrammes === 0)\n    showbuttontext = getTidLanguage() === \"nl\" ? \"Geen resultaten\" : \"No results\";\n  else if (visibleprogrammes === 1)\n    showbuttontext = getTidLanguage() === \"nl\" ? \"Toon 1 resultaat\" : \"Show 1 result\";\n  else if (visibleprogrammes > 1)\n    showbuttontext = getTidLanguage() === \"nl\" ? `Toon ${visibleprogrammes} resultaten` : `Show ${visibleprogrammes} results`;\n\n  filterpanel.querySelector(\".whflattabs__filterpanel__showresults\").innerHTML = showbuttontext;\n\n  items_scroller.update();\n}\n\ndompack.register(\".js-activityitem\",\n  node => node.addEventListener(\"click\", () => {\n    //studychoice calendar events - https://gitlab.webhare.com/utwente/utwente_base/-/issues/2689\n    const form = dompack.qS<HTMLFormElement>(\"form.js-activityoverview__targetgroup\"); // ws2016\n\n    let relevantto;\n    if( !form ) // ws2026\n      relevantto = dompack.qS<HTMLInputElement>(\".page-filterstabs__listitem input:checked\")?.value || '';\n    else\n      relevantto = (form?.elements.namedItem(\"category\") as RadioNodeList)?.value || '';\n\n    const type = node.dataset.tagmanagerType || '';\n    const position = dompack.qSA(\".js-activityitem\").indexOf(node) + 1;\n    window.dataLayer.push({ event: \"scc-click\", type, relevantto, position });\n  })\n);\n","// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nexport default function setupToggle(options) {\n  options = {\n    togglebutton: null,\n    openbutton: null,\n    closebutton: null,\n\n    togglecontainer: null, // element which should receive the toggle class (defaults to document.documentElement aka <html>)\n    htmlclass: \"\",\n\n    panel: null,\n    visibleonfocus: false, // if true the panel closes when focus isn't within the panel anymore\n    visibleonhover: false, // if true, hovering over the togglebutton or panel keeps the panel open\n\n    title: \"\",\n\n    debug: false,\n\n    ...options\n  };\n\n  if (options.debug)\n    console.log(options);\n\n  if (options.togglebutton) {\n    for (const node of makeArray(options.togglebutton))\n      node.addEventListener(\"click\", evt => doToggle(evt, options));\n  }\n\n  if (options.openbutton) {\n    for (const node of makeArray(options.openbutton))\n      node.addEventListener(\"click\", evt => doOpen(evt, options));\n  }\n\n  if (options.closebutton) {\n    for (const node of makeArray(options.closebutton))\n      node.addEventListener(\"click\", evt => doClose(evt, options));\n  }\n\n  if (options.visibleonfocus)\n    options.panel.addEventListener(\"focusout\", evt => onFocusOut(evt, options));\n\n  if (options.visibleonhover) {\n    for (const node of makeArray(options.togglebutton)) {\n      node.addEventListener(\"mouseenter\", evt => onMouseEnter(evt, options));\n      node.addEventListener(\"mouseleave\", evt => onMouseLeave(evt, options));\n    }\n\n    if (options.panel) /* apparently doesn't always exist ? the setupToggle marked with 'Toggle for themes overview menu' doesnt supply this panel */ {\n      options.panel.addEventListener(\"mouseenter\", evt => onMouseEnter(evt, options));\n      options.panel.addEventListener(\"mouseleave\", evt => onMouseLeave(evt, options));\n    }\n  }\n}\n\nfunction makeArray(input) {\n  if (input instanceof NodeList || input instanceof HTMLCollection) {\n    return Array.from(input);\n  } else if (input instanceof HTMLElement)\n    return [input];\n  else {\n    console.error(\"makeArray cannot handle input:\", input);\n    return [];\n  }\n}\n\nfunction onMouseEnter(evt, options) {\n  doOpen(evt, options);\n}\n\nfunction onMouseLeave(evt, options) {\n  doClose(evt, options);\n}\n\n\nfunction onFocusOut(evt, options) {\n  if (evt.relatedTarget && options.panel.contains(evt.relatedTarget))\n    return;\n\n  doClose(evt, options);\n}\n\nfunction doToggle(evt, options) {\n  const open = !document.documentElement.classList.contains(options.htmlclass);\n\n  if (open)\n    doOpen(evt, options);\n  else\n    doClose(evt, options);\n}\n\n\nfunction doOpen(evt, options) {\n  const node = options.togglecontainer ?? document.documentElement;\n  if (options.htmlclass !== \"\")\n    node.classList.add(options.htmlclass);\n\n  if (options.panel)\n    options.panel.focus();\n}\n\nfunction doClose(evt, options) {\n  const node = options.togglecontainer ?? document.documentElement;\n  if (options.htmlclass !== \"\")\n    node.classList.remove(options.htmlclass);\n}\n","import * as dompack from \"@webhare/dompack\";\nimport { DefaultFilter, CustomPageFilter, PageFiltersContext, registerCustomFilter } from \"@mod-utwente_base/webdesigns/ws2026/shared/pagefilters/pagefilters\";\nimport { getFrontendData } from \"@webhare/frontend/src/init\";\n\n/*\n  ws2026: Uses generic pagefilters component\n*/\nclass ActivitiesFilter implements CustomPageFilter {\n  node: HTMLElement;\n  myFilter: DefaultFilter; // We use the default filter for the actual filtering, we just rewrite results for specific for this component (bigline after first item)\n  bigline: HTMLElement | null = null;\n  constructor() {\n    this.node = dompack.qR(\".pagefilters__itemcontainer\");\n    this.bigline = dompack.qS(\".blockswidget__bigline\");\n    this.myFilter = new DefaultFilter(null);\n\n    const settings = getFrontendData(\"utwente_voorlichting:activities\");\n    if( settings?.addlinks && settings?.addlinks.length > 0 ) {\n      const linklist = <ul class=\"page-filterstabs__list\">\n        {settings.addlinks.map(opt => <li class=\"page-filterstabs__listitem\">\n          <a class=\"page-filterstabs__listitem__link\" href={opt.link}>{opt.title}</a>\n        </li>)}\n      </ul>;\n\n      dompack.qS(\".page-filterstabs__inner\")?.appendChild(linklist);\n    }\n  }\n\n  async filter(filtercontext: PageFiltersContext): Promise<HTMLElement[] | null> {\n    const items = this.myFilter.filter(filtercontext) || [];\n\n    if ( this.bigline ) {\n      if (items.length > 0 ) // First item always followed by a bigline, so inject it after the first item\n        items.splice(1, 0, this.bigline);\n      else if (this.bigline.parentNode) // If no items, remove the bigline from the DOM\n        this.bigline.parentNode.removeChild(this.bigline);\n    }\n\n    return items;\n  }\n}\n\nregisterCustomFilter(\"ActivitiesFilter\", () => new ActivitiesFilter());\n","/* eslint-disable */\n// @ts-nocheck -- Bulk rename done by wh devkit:es2ts\n\nimport * as dompack from \"dompack\";\nimport './ctalinks.scss';\nimport * as storage from 'dompack/extra/storage';\n\nfunction setupCTALinksExperiments(node) {\n  const meta = node.previousElementSibling;\n  if (!meta?.matches('meta[name=\"ut-insertactivitiesoverviewwidget-experiment\"'))\n    return; //not running an experiment\n\n  //Lock the experiment for this session\n  const keyname = `ut-ctalinks-${document.documentElement.dataset.id}-experimentgroup`;\n  let abgroup = storage.getLocal(keyname)?.abgroup ?? \"unset\"; //properly differentiate between real 0 and unset\n  if (abgroup === \"unset\") {\n    abgroup = Math.floor(Math.random() * 4); //0-3\n    storage.setLocal(keyname, { abgroup });\n  }\n\n  node.classList.add(\"widget-ctalinks--variant\" + abgroup);\n  document.documentElement.dataset.experimentId = meta.getAttribute(\"content\");\n  document.documentElement.dataset.experimentVariant = abgroup;\n  window.dataLayer.push({\n    experimentId: document.documentElement.dataset.experimentId,\n    experimentVariant: document.documentElement.dataset.experimentVariant\n  });\n\n  dompack.qSA(node, \".widget--ctalinks__item\").forEach(node => node.addEventListener(\"click\", () => {\n    window.dataLayer.push({ event: \"scc_cta_button_click\" });\n  }));\n}\n\ndompack.register(\".widget-ctalinks\", setupCTALinksExperiments);\n\nwindow.__resetCTALinkExperiment = function () {\n  const keyname = `ut-ctalinks-${document.documentElement.dataset.id}-experimentgroup`;\n  storage.setLocal(keyname, null);\n  location.reload();\n};\n","// Our extensions for utwente_base module\nimport * as crm from '@mod-utwente_base/webdesigns/ws2016/src/shared/crm';\nimport '@mod-utwente_voorlichting/js/shared/orgselect';\nimport '@mod-utwente_voorlichting/js/shared/institutes';\nimport '@mod-utwente_voorlichting/webfeatures/cashpoint';\nimport '@mod-utwente_voorlichting/webfeatures/echeck';\nimport '@mod-utwente_voorlichting/webfeatures/opendagen';\nimport '@mod-utwente_voorlichting/webfeatures/opendays_v2';\nimport '@mod-utwente_voorlichting/webfeatures/leadswidgets';\nimport '@mod-utwente_voorlichting/webfeatures/scopemastercontact';\nimport '@mod-utwente_voorlichting/webfeatures/tasterdays';\nimport '@mod-utwente_voorlichting/webfeatures/lifelonglearning/lifelonglearning.ts';\nimport '@mod-utwente_voorlichting/webfeatures/sirform/sirform';\n\nimport './activities/activities';\nimport './activities/activitiespagefilter'; // pagefilter for activities page, uses generic pagefilters component\n\nimport \"./tabstrip/tabstrip.scss\";\n\nimport './widgets/applyforprogrammecta/applyforprogrammecta.scss';\n// import './widgets/blockswidget/blockswidget.scss';\nimport './widgets/ctalinks/ctalinks';\n\nvoid crm.requestGeoIP(); //let country check do its thing/RPC first\n","import \"@webhare/frontend/src/init\";import \"/opt/wh/whtree/modules/publisher/js/internal/polyfills/all\";\nimport \"/opt/whdata/installedmodules/utwente_base.20261103T204827.784Z/webdesigns/ws2026/ws2026-site.tsx\";\nimport \"/opt/whdata/installedmodules/datacloud.20261029T161844.810Z/webfeatures/datacloud-loader\";\nimport \"/opt/whdata/installedmodules/utwente_courses.20261102T164242.529Z/js/internal/ws2026_courses_hook\";\nimport \"/opt/whdata/installedmodules/utwente_education.20261103T172928.036Z/webfeatures/utwente_base2026_hooks\";\nimport \"/opt/whdata/installedmodules/utwente_jobs.20261005T154742.835Z/webfeatures/vacanciespage/index\";\nimport \"/opt/whdata/installedmodules/utwente_ppp.20261026T192316.424Z/webdesigns/shared/ws2016_ppp\";\nimport \"/opt/whdata/installedmodules/utwente_voorlichting.20261103T222858.091Z/webfeatures/ws2016_voorlichting/ws2026_voorlichting\";const aps = globalThis.whAssetPacks ||= {}; aps[\"utwente_base:ws2026\"]=\"2026-11-03T22:29:26.679Z\";"],"mappings":"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","names":["require_searsia","__commonJSMin","exports","module","searsia","SEARSIAVERSION","globalId","globalApiTemplate","globalMother","searsiaAjax","ajaxObject","url","success","error","dataType","options","response","tries","data","decodeError","message","clearLocalStorage","key","setLocalStorage","field","value","deleteLocalStorage","getLocalStorage","existsLocalStorage","setMother","motherObject","getMother","motherJson","setApiTemplate","template","getApiTemplate","getId","setLocalResource","resource","id","getLocalResource","rid","json","existsLocalResource","deleteLocalResource","fillUrlTemplate","query","page","resourceId","resulttype","start","end","ext","addToHits","hits","hit","i","newIndex","TOP","normalizeText","text","noHTMLattribute","noHTMLelement","scoreText","queryTerms","j","len","textTerms","score","restrictStart","someText","size","prefix","postfix","matchingSnippets","k","description","first","second","scoreAllHits","rerank","queryLen","maxscore","tscore","newHits","nrOfTopHits","printableQuery","a","b","correctUrl","absUrl","relUrl","getHost","match","urlParameters","values","params","paramString","parts","formQuery","encodedQuery","inferMissingData","rank","rhost","typeImages","typeSmall","typeFull","typeTitleOnly","count","prior","maxScore","returnResults","sessionid","olddata","callbackSearch","newscore","oldscore","liveResults","queryResources","pending","checkEmpty","getResults","xhr","err","done","generateUUID","c","r","v","searchFederated","connectToServer","callbackConnect","initClient","originalTemplate","resultType","require_searsiaconfig","__commonJSMin","exports","module","SEARSIA_SOURCES","SEARSIA_DUPLICATE_RESOURCES","QUERY_STOPWORDS","require_events","__commonJSMin","exports","module","R","ReflectApply","target","receiver","args","ReflectOwnKeys","ProcessEmitWarning","warning","NumberIsNaN","value","EventEmitter","once","defaultMaxListeners","checkListener","listener","arg","n","_getMaxListeners","that","type","i","doError","events","er","err","handler","len","listeners","arrayClone","_addListener","prepend","m","existing","w","onceWrapper","_onceWrap","state","wrapped","list","position","originalListener","spliceOne","keys","key","_listeners","unwrap","evlistener","unwrapListeners","emitter","listenerCount","arr","copy","index","ret","name","resolve","reject","errorListener","resolver","eventTargetAgnosticAddListener","addErrorHandlerIfEventEmitter","flags","wrapListener","require_requester","__commonJSMin","exports","module","init_dompack","EventEmitter","InternetRequester","options","debugflags","method","url","body","async","key","event","datestr","parseddate","evt","require_jsonrpc","__commonJSMin","exports","module","init_env","InternetRequester","rpcscriptid","JSONRPC","_JSONRPC","options","method","params","deferred","req","errorcode","errormsg","rpcid","promise","result","rejection","onsuccess","onfailure","id","url","timeout","waittimeout","synchronous","errortrace","request","Request","isLive","i","el","event","status","json","trace","line","rec","waiting","nextTimeout","now","waitLength","toGo","parent","require_iscroll_modified","__commonJSMin","exports","module","window","document","Math","rAF","callback","utils","me","_elementStyle","_vendor","vendors","transform","i","l","_prefixStyle","style","target","obj","el","type","fn","capture","pointerEvent","current","start","time","lowerMargin","wrapperSize","deceleration","distance","speed","destination","duration","_transform","appVersion","safariVersion","e","c","re","newclass","left","top","exceptions","k","f","eventName","ev","IScroll","options","button","point","pos","deltaX","deltaY","timestamp","newX","newY","absDistX","absDistY","momentumX","momentumY","distanceX","distanceY","easing","snap","that","x","y","touchAction","rf","index","transitionType","offsetX","offsetY","durationProp","self","remove","eventType","matrix","interactive","customStyle","indicators","indicator","createDefaultScrollbar","Indicator","_indicatorsMap","wheelDeltaX","wheelDeltaY","m","n","cx","cy","stepX","stepY","page","posX","posY","keys","now","prevTime","acceleration","destX","destY","easingFn","startX","startY","startTime","destTime","step","direction","scrollbar","scroller","r","val","hold","delay","import_iscroll","tempid","SpellcoderCarrousel","init_src","__esmMin","init_dompack","node","options","domoptions","getJSONAttribute","nodes","initialx","iscrollsettings","IScroll","idx","classname","timestamp","force","dpr","currentpos","scrollleft","newx","animate","offsetx","forward","xfloor","xceil","virtualidx","renderinfo","item","iteminfo","posx","largestheight","fixedslidewidth","width","height","positionwidth","i","j","tmp","msg","width_content","newheight","evt","dispatchCustomEvent","carrouselcell","closest","viewport_rect","clickpos","contentareawidth","middlex","items","pages","left","wanted_left_within_content","idx_neg","pageX","pageY","repeatedcontent","itemidx","val","x","y","iScroll","activation_x","draw","override_scrollleft","absolute_scrollleft","visible_left","visible_right","new_items_onscreen","items_visible","itemcount","draw_itemidx","offsetleft","newactiveslideidx","newactivenode","newactiveslidevirtualidx","newactiveslide_dist","virtualslideidx","outofview","left_in_viewport","use_node","centerwithinheight","offsety","transform","imagecontainer","leftdist","dist","asset","require_fullscreen_slideshow","__commonJSMin","exports","module","init_dompack","init_src","__active_photoviewer","__active_fsslideshow_container","__old_scrolly","__initialized","refreshFullScreenSlideshow","viewer","resizeImagesToFitInViewport","options","getDefaultSlideshowOptions","resizeActivePhotoviewer","doActivateSlideshowByHash","hash","imageid","cell","slideshow","all_items","itemidx","___doActivateSlideshow","doActivateSlideshow","instanceid","containerid","slideshowcontainer","use_carrousel","carrouselcontainer","onActiveSlideChange","doCloseFullscreenSlideshow","carr","SpellcoderCarrousel","detectButtonTaps","slidenodes","node","fsscontainer","headeranim","evt","buttonnode","titlenode","downloadbutton","carrousel","slidenode","urlhash","viewport_width","viewport_height","rect","maximagewidth","maximageheight","dpr","images","idx","image","orig_w","orig_h","max_w_stretch","max_h_stretch","stretch","img_w","img_h","register","require_ev_emitter","__commonJSMin","exports","module","global","factory","EvEmitter","proto","eventName","listener","events","listeners","onceEvents","onceListeners","index","args","i","isOnce","require_get_size","__commonJSMin","exports","module","window","factory","getStyleSize","value","num","isValid","noop","logError","message","measurements","measurementsLength","getZeroSize","size","i","measurement","getStyle","elem","style","isSetup","isBoxSizeOuter","setup","div","body","getSize","isBorderBox","paddingWidth","paddingHeight","marginWidth","marginHeight","borderWidth","borderHeight","isBorderBoxSizeOuter","styleWidth","styleHeight","require_matches_selector","__commonJSMin","exports","module","window","factory","matchesMethod","ElemProto","prefixes","i","prefix","method","elem","selector","require_utils","__commonJSMin","exports","module","window","factory","matchesSelector","utils","a","b","prop","num","div","arraySlice","obj","isArrayLike","ary","index","elem","selector","event","method","elems","ffElems","childElems","i","_class","methodName","threshold","timeoutName","timeout","args","_this","callback","readyState","str","match","$1","$2","console","WidgetClass","namespace","dashedNamespace","dataAttr","dataAttrElems","jsDashElems","dataOptionsAttr","jQuery","attr","options","error","instance","require_item","__commonJSMin","exports","module","window","factory","EvEmitter","getSize","isEmptyObj","obj","prop","docElemStyle","transitionProperty","transformProperty","transitionEndEvent","vendorProperties","Item","element","layout","proto","event","method","style","elemStyle","supportedProp","isOriginLeft","isOriginTop","xValue","yValue","x","y","layoutSize","xPadding","xProperty","xResetProperty","yPadding","yProperty","yResetProperty","isHorizontal","curX","curY","didNotMove","transX","transY","transitionStyle","args","_transition","h","toDashedAll","str","$1","transitionProps","duration","dashedVendorProperties","propertyName","onTransitionEnd","cleanStyle","cleanTransitionStyle","delay","options","transitionEndProperty","styleProperty","optionStyle","require_outlayer","__commonJSMin","exports","module","window","factory","EvEmitter","getSize","utils","Item","console","jQuery","noop","GUID","instances","Outlayer","element","options","queryElement","id","isInitLayout","proto","opts","option","oldOption","canBindResize","elems","itemElems","items","i","elem","item","layoutInstant","isInstant","measurement","size","queue","position","obj","stagger","getMilliseconds","x","isResizingContainer","measure","isWidth","elemSize","eventName","_this","onComplete","count","doneCount","tick","type","event","args","emitArgs","$event","boundingRect","thisRect","offset","hasSizes","previousItems","removeItems","style","namespace","Layout","subclass","Parent","SubClass","msUnits","time","matches","num","unit","mult","require_masonry","__commonJSMin","exports","module","window","factory","Outlayer","getSize","Masonry","proto","i","firstItem","firstItemElem","columnWidth","containerWidth","cols","excess","mathMethod","isFitWidth","container","size","item","remainder","colSpan","colPosMethod","colPosition","position","setHeight","setMax","colGroup","minimumY","groupCount","col","groupColYs","isOver","hasSize","stamp","stampSize","offset","isOriginLeft","firstX","lastX","firstCol","lastCol","isOriginTop","stampMaxY","unusedCols","previousWidth","rpc_exports","__export","createService","RPCClient","getDebugAppend","urldebugvar","name","service","JSONRPCService","JSONRPCServiceProxy","globalseqnr","ControlledCall","init_rpc","__esmMin","init_dompack","client","method","stack","id","options","callurl","fetchoptions","fetchpromise","resolution","response","retryafter","resolve","exception","jsonresponse","url","debugflags","whservicematch","promise","result","error","trace","rec","line","params","args","target","prop","receiver","init_envbackend","getBrowserDebugFlags","varname","flags","urldebugvar","debugcookie","debugcookievalue","flag","sessionDebug","init_tree","init_std","config","siteroot","dtapStage","whconfigel","parsedConfig","omit","initEnv","flag","getBrowserDebugFlags","debugFlags","frontendConfig","getLang","getFrontendData","dataObject","allowMissing","retval","getSiteRoot","throwError","init_polyfills","IteratorPrototype","ArrayIteratorPrototype","OriginalIteratorPrototype","callback","it","value","next_value","real_value","max_count","values","limit","remaining","index","mapper","mapped","reducer","initial_value","acc","count","string","final","first","iterables","others","it_array","e","finished","partition1","partition2","i","max","min","isObject","t","GetIteratorFlattenable","obj","method","iterator","Iterator","WrappedIterator","#iterator","args","returnMethod","Iterator_from","init_dompack","config","forwardPublisherNavigation","event","isHTMLElement","navaction","desturl","origin","configureForCMS","e","init_dompack","init_dompack","init_env","init_std","lastSeen","showDataLayerUpdates","debugFlags","entry","pushToDataLayer","vars","options","savecallback","newcallback","resolve","collectFormValues","formnode","donefields","outdata","multifields","qSA","multifield","idx","values","labels","checkboxes","node","cbox","keyname","labelsfornode","labelnode","allkeyname","field","val","opt","didinit","setupGTM","setupFormAnalyticsForGTM","key","form","init_dompack","init_dompack","init_env","init_envbackend","consentstatus","cookiename","consentoptions","setup","usecookiename","consentrequester","options","debugFlags","getCookie","storeConsent","onDomReady","updateConsent","hasConsent","consentsetting","details","getConsentDetail","setConsent","newsetting","consent_revoked","tag","navigateTo","onConsent","type","callback","evt","updateConsentOverlays","overlays","qSA","consent","getConsentDetail","debugFlags","overlay","parent","updateConsent","details","dispatchCustomEvent","onDomReady","storeConsent","cookiename","setCookie","consentstatus","consentoptions","deleteCookie","navigateTo","gtmsettings","getFrontendData","didinit","processGTMPluginInstruction","node","topush","init","didinit","gtmsettings","resolve","loadScript","register","processGTMPluginInstruction","gtmsettings","init","setupGTM","init_dompack","init_env","init_dompack","JustifiedContentGrid","container","options","strip_width","strip_height","img_idx","img_count","current_width","current_width_next","row","ypos","maxiterations","maxrows","column","img_this_strip","item","resized_width","compensatex","grow_if_no_extra_image","shrink_if_extra_image","scale_to_fill_width","scale_to_fill_height","scale_to_fill_both","result_width","result_height","add_each_item","add_last_item","xpos","col_idx","expected_height","items","frag","tel","clip_node","JustifiedImageGrid","imgcount","new_items","img","contentnode","imgwidth","imgheight","imgdesc","item_ref","evt","imgnode","init_gettid","init_dompack","init_std","init_env","eventname_regex","datakey_regex","max_sessionid_age","globalOptions","pagesession","useAltRecordURL","seqnr","pxlUserId","pxlSessionId","buildOptions","options","pxlFailed","errormessage","params","isLive","makePxlURL","baseurl","eventname","data","options","globalOptions","eventname_regex","pagesession","generateRandomId","url","seqnr","getPxlSessionId","getPxlId","browser","getBrowser","name","value","test","datakey_regex","type","pxlUserId","timestampvar","debugFlags","sessionExpireDays","max_sessionid_age","expiration","pxlSessionId","sendPxlEvent","event","finaloptions","buildOptions","useAltRecordURL","fetchRes","error","get","element","set","obj","key","let","val","div","className","const","elMatches","matches","query","remove","queryChildren","selector","child","cls","x","scrollingClassTimeout","addScrollingClass","classList","removeScrollingClass","setScrollingClassInstantly","EventElement","eventName","handler","target","this","name","prototypeAccessors","EventManager","ee","onceHandler","evt","createEvent","processScrollDiff","axis","diff","useScrollingClass","forceFireReachEvent","fields","ref","y","scrollTop","contentHeight","containerHeight","up","down","toInt","isEditable","el","DOM.matches","outerWidth","styles","CSS.get","env","updateGeometry","roundedScrollTop","rect","DOM.queryChildren","DOM.remove","getThumbSize","updateCss","thumbSize","i","xRailOffset","CSS.set","yRailOffset","clickRail","e","positionTop","direction","positionLeft","dragThumb","bindMouseScrollHandler","startingScrollTop","startingMousePageY","scrollBy","mouseMoveHandler","pageY","mouseUpHandler","scrollbarYRail","bindMoves","touchMode","railYHeight","scrollbarYHeight","scrollbarY","keyboard","elementHovered","scrollbarFocused","shouldPreventDefault","deltaX","deltaY","scrollLeft","activeElement","wheel","isTop","isBottom","isLeft","isRight","hitsBound","getDeltaFromEvent","shouldBeConsumedByChild","cursor","style","maxScrollTop","maxScrollLeft","mousewheelHandler","shouldPrevent","touch","magnitudeX","magnitudeY","applyTouchMove","differenceX","differenceY","startOffset","startTime","speed","easingLoop","getTouch","shouldHandle","touchStart","touchMove","currentOffset","currentTime","timeGap","touchEnd","defaultSettings","handlers","PerfectScrollbar","userSettings","focus","blur","originalScrollLeft","result","DOM.div","railXStyle","railYStyle","handlerName","import_searsia","import_searsiaconfig","init_dompack","parseManagedCTAConfig","ctaconfig","config","_","regex","idx","r","CTAMatchError","prop","values","params","tryMatchCTAConfig","props","now","debugflags","hitanybeacon","beacon","maxtime","beacondate","matching_regex","only_excludes","cta_regex","e","init_jsonrpc_client","requestbarrier","getIPInfoIntoCache","options","reqoptions","result","createClient","geoinfo","getIPInfo","finaloptions","barrier","curgeoinfotext","e","refetch","retval","init_storage","getLocal","setLocal","getSession","setSession","init_dompack","list","listCookies","read","getCookie","write","setCookie","remove","deleteCookie","init_dompack","init_std","init_dompack","init_jsonrpc_client","init_env","init_dompack","init_env","init_js_api_tools","init_std","isAbsolute","url","getBaseURL","backendBase","ControlledCall","client","method","stack","options","callurl","fetchoptions","fetchpromise","requestStack","response","exception","retryafter","resolve","jsonresponse","parseTyped","logitem","omit","err","prependStackTrace","RPCClient","debugFlags","error","params","stringify","pathName","parseTrace","ServiceProxy","target","prop","receiver","newoptions","rpc","args","service","servicematch","rpcclient","PublicCookieSuffix","init_std","getCookieName","getFrontendData","getAuthLocalData","c","parseTyped","getCookie","PublicCookieSuffix","isLoggedIn","getAuthLocalData","getUserInfo","isLoggedIn","getAuthLocalData","startSSOLogin","tag","options","client","createClient","defer","toSnakeCase","instr","navigateTo","e","setupWebHareSSOTrigger","getAssetPackBase","assetpack","init_dompack","loadAssetPack","apname","options","doc","basepath","getAssetPackBase","loadScript","loadCSS","setupAuthorMode","getLocal","init_env","activeListenPrefixes","sendPxl","eventKey","params","data","options","pxldata","k","v","sendPxlEvent","setupFormAnalytics","prefix","registered","dtapStage","e","formeventdata","key","val","getRemoteIPAddress","_","init_env","postRenderChecks","log","logtext","onDomReady","cookiedomain","getLangCode","lang","UtwenteCookies","deleteCookie","setLocal","utwenteCookies","link","cookielink","privacylink","jsxcreate","reject","d","accept","texts","buttons","prefs","getCookie","ischange","vars","pushToDataLayer","evt","e","newsettings","setting","expires","setCookie","newprefs","curprefs","c","setupCookieWidget","form","thirdparty","throwError","ev","setupConsentHandlerForUtwente","syncConsent","consent","setConsent","setup","register","node","onDomReady","__ignored","cookiebar_default","init_dompack","startedload","setupCobrowser","chtbtn","hasConsent","onChatTouchBlur","event","isHTMLElement","acceptnode","cookiebar_default","openCoBrowser","online","loadCobrowser","qS","create","setupCoBrowserChat","register","onConsent","init_dompack","setupConsentHandlerForUtwente","init_dompack","usersettings","getUserSettings","getUserGuid","setUserSettings","settings","lastguid","write","dispatchCustomEvent","read","init_env","init_dompack","readSessionInfo","getCookie","writeSessionInfo","sessinfo","setCookie","getHardcodedURLReferralInfo","url","getBrowser","getReferralInfo","sessioninfo","usersettings","getUserSettings","referralinfo","cookiebar_default","field","userbeacon","getUserBeacons","name","trackFirstReferrer","referrer","referrerurl","urlparams","varname","sessupdates","debugFlags","urlinfo","grabVar","firstreferage","setUserSettings","init_dompack","auth_exports","__export","WRDAuthenticationProvider","auth_default","getDefaultAuth","init_dompack","init_dompack","init_env","init_keyboard","import_jsonrpc","init_env","init_dompack","defaultauth","getBackVar","backurl","getURLOrigin","url","WRDAuthenticationProvider","options","getUserInfo","JSONRPC","jsstate","read","currentstate","debugflags","logouturl","redirectto","form","KeyboardHandler","evt","event","isHTMLElement","stop","loginfield","passwordfield","persistentfield","persistentlogin","login","password","resolve","reject","opts","response","error","logincontrol","loginlock","flagUIBusy","result","completion","dispatchCustomEvent","navigateTo","code","msg","message","evtdetail","isLoggedIn","type","sp_tag","defer","getDefaultAuth","frontendConfig","register","node","elname","auth_default","getNetworkForIP","ip","init_env","getLoginLink","prompt","silent","redirect","url","gotourl","getUTUserInfo","auth_exports","register","node","event","stop","dtapStage","userinfo","getNetworkForIP","getRemoteIPAddress","init_envbackend","beacons","geoippromise","onMeeloopdagMessage","event","getGTMTracker","analyticsid","tracker","trackClientId","retry","clientid","getUserSettings","setUserSettings","setSession","setupGTMDataLayer","usersettings","base","getUserGuid","getNetworkForIP","getRemoteIPAddress","requestGeoIP","getIPInfo","geoinfo","getUserCountry","learnedAboutUser","newguid","firstname","opts","setUserSettings","getUserGuid","addReferralInfoToForm","evt","getReferralInfo","userbeacon","beacons","name","getUserBeacons","storeBeacons","dispatchCustomEvent","e","triggerUserBeacon","tag","date","debugFlags","clearUserBeacon","tag","beacons","debugFlags","storeBeacons","pickupGlobalBeacons","list","ck","triggerUserBeacon","remove","userinfo","getUTUserInfo","usertype","cookieusertype","read","setbeacon","name","executeANLEvent","node","register","addReferralInfoToForm","setupFormAnalyticsForGTM","evt","pushToDataLayer","setupGTMDataLayer","onMeeloopdagMessage","requestGeoIP","getSession","trackClientId","setupShowAllLinks","node","containerClass","linkClass","target","event","style","links","init_dompack","init_keyboard","import_requester","import_searsia","SearsiaAutoSuggest","inputNode","resultsNode","options","InternetRequester","event","KeyboardHandler","stop","selectitem","_event","flagUIBusy","value","input","values","dispatchCustomEvent","historyhit","entry","url","searsia","createDeferred","lookupresult","suggestions","match","jsxcreate","selectedvalue","changeValue","init_dompack","init_env","init_std","init_gettid","PHONE_UT_REGEX","PHONE_MOB_REGEX","addDebuggingInfo","hit","source","debugFlags","jsxcreate","createGeneralResult","queryWords","titleprefix","icon","getTid","decodeString","highlightQueryWords","formatURL","createNewsResult","extended","createEventResult","createPeopleResult","getMapRouteLink","formatPhone","createVideoResult","createImageResult","createRelatedResults","hits","_source","createFilteredResult","text","words","className","result","match","url","phone","coord","init_dompack","init_env","init_std","init_gettid","shownWidget","locationRequestId","showSearsiaWidgets","hits","ctaslots","ctaprops","eventsurl","node","result","createLocationWidget","createEventsWidget","tryMatchSearsiaCTA","props","ctaslot","cta","tryMatchCTAConfig","debugFlags","createHighlightCTA","createWidgetCTA","e","CTAMatchError","title","description","widgetNode","jsxcreate","getTid","descriptionHTML","retrieveLocation","name","locreqid","response","data","decodeString","formatPhone","getMapRouteLink","eventNode","alleventsurl","resultScoreProp","resultLangProp","resultSourceProp","searsiaClient","defaultSearchType","isSubArray","master","sub","i","j","SearsiaClient","node","qR","event","_","getUserCountry","debugFlags","requestGeoIP","country","getUserBeacons","tabsNode","perfect_scrollbar_esm_default","tabNode","q","t","searchconfigurl","response","searchconfig","apitemplate","searsia","resolve","SearsiaAutoSuggest","ctaslot","cta","parseManagedCTAConfig","tab","jsxcreate","query","words","terms","phrase","word","phrasestart","__","show","searchType","doshow","dispatchCustomEvent","sendPxlEvent","toshow","sheet","nosearch","style","prop","reset","params","result","filter","term","getHTMLTid","registerMissed","source","relatedHits","createRelatedResults","resourceDuplicateScore","hits","hit","manipulated","dupIdx","resultContainer","refNode","resultNode","createNewsResult","createEventResult","createPeopleResult","createVideoResult","createImageResult","createGeneralResult","gridNode","JustifiedImageGrid","defaultoptions","filteredNode","createFilteredResult","getTid","_source","force","html","isstudent","isemployee","loginmsg","showSearsiaWidgets","peopleResult","relatedResult","suggestion","link","widget","initSearchSheet","searchSheetContentNode","resetSearch","section","setupShowAllLinks","stop","toggle","doSearch","register","node","initSearchSheet","init_dompack","init_env","init_dompack","init_env","frontendConfig","initializeTheme","node","colorSchemeNode","colorSchemeCTANode","qS","colorSchemeCTAHoverNode","animateThemeColor","colorScheme","debugFlags","saveStart","getLocal","animDuration","animDelay","setLocal","registered","disableColorAnimation","setAnimation","e","checkThemeColors","animSteps","randomColor","curThemeColor","curThemeColorCTA","curThemeColorCTAHover","setThemeColors","syncTimeout","syncThemeColors","anyChanges","themeColor","props","names","playState","animationStyle","name","observer","curDelay","browser","getBrowser","register","browser","getBrowser","disableColorAnimation","animColorDuration","animDuration","animSteps","animDelay","initTheme","frontendData","getFrontendData","debugFlags","jsxcreate","colorScheme","saveStart","getLocal","setLocal","event","handleAnimationStateEvent","registerTexts","init_dompack","init_gettid","eventscriptloaded","onAddThisClick","eventnode","getTid","addThisScript","qR","register","init_dompack","init_env","samplerate","fetchPredictions","prediction","getFrontendData","logReferrerIfNeeded","alwaysoptin","debugFlags","usesamplerate","requestGeoIP","sendPxl","setupNextPager","onDomReady","init_dompack","init_dompack","init_gettid","init_internal","convertElementTids","scope","node","getTid","args","getTidLanguage","setTidLanguage","getHTMLTid","registerTexts","youtubedomain","videonetworks_preload","registerVideoSource","source","options","createMyFrame","inert","ifrm","initYouTube","node","video","playback","args","youtube_url","initVimeo","vimeo_url","t","minutes","seconds","insertVideoPlayer","opts","use_handler","handler","playback_url","initializeVideoElementV1","initializeVideoElementV2","videonodes","qSA","videonode","activateVideo","playbutton","getTid","evt","onConsent","iFrame","registerVideoSource","getYujaPlaybackURL","register","node","initializeVideoElementV1","initializeVideoElementV2","video","playback","args","params","host","videoid","authorizationkey","playback_url","init_dompack","checkScrollableX","node","create","e","w","sw","register","init_dompack","onDomReady","init_dompack","init_dompack","init_gettid","init_std","autocomplete","settings","doc","container","preventSubmit","uid","containerStyle","debounceWaitMs","disableAutoSelect","customContainerParent","items","inputValue","minLen","showOnFocus","selected","fetchCounter","debounceTimer","destroyed","suppressAutocomplete","input","detach","parent","clearDebounceTimer","attach","containerDisplayed","clear","updatePosition","maxHeight","inputRect","calc","docEl","clientTop","clientLeft","scrollTop","scrollLeft","top","left","update","render","item","_","__","itemElement","renderGroup","groupName","groupDiv","fragment","prevGroup","index","div","ev","empty","updateScroll","updateIfDisplayed","resizeEventHandler","scrollEventHandler","e","inputEventHandler","fetch","elements","element","previous","selectBottom","containerBottom","selectPreviousSuggestion","updateSelectedSuggestion","selectNextSuggestion","unselectSuggestion","selectSuggestion","handleArrowAndEscapeKeys","key","containerIsDisplayed","handleEnterKey","keydownEventHandler","focusEventHandler","trigger","startFetch","inputText","cursorPos","savedFetchCounter","keyupEventHandler","clickEventHandler","blurEventHandler","manualFetch","evt","destroy","UTAutoComplete","settings","autocomplete_es_default","init_std","wordRegex","lastWordRegex","SearchIndex","fields","item","key","invalue","value","match","count","term","pos","entry","props","query","results","parsedQuery","baseQuery","suggestQuery","baseResults","#searchInternal","termField","termText","score","#matchesText","suggestion","scores","result","flatscores","#calculateScores","#getSortedItems","searchResult","terms","field","fieldResults","matches","word","queryResult","#executeQuery","text","item_positions","indexEntry","avg","cur","idx","queryWord","termWord","limitDistance","startsWithScore","dist","levenshteinDistance","a","b","_","factories","desktopMediaQuery","getFlatActiveFilterValuesList","filter","tags","name","entries","items","e","value","title","DefaultFilter","initialItems","options","qSA","item","SearchIndex","idx","titleNode","description","n","searchnode","qS","UTAutoComplete","text","update","suggestions","_","dispatchDomEvent","input","inputRect","container","maxHeight","width","leftPos","context","limitIdx","result","values","itemValue","v","FilteredOverview","settings","qR","ev","factory","throwError","hash","vm","urlParams","startParam","endParam","startInp","endInp","paramValue","loc","inp","option","valuesToSelect","checkbox","radio","searchParam","searchInput","filtertype","selectedOptions","o","jsxcreate","getTid","nrTabs","tablist","opt","selectedViewIdx","filtersToolbar","i","contentWithFilters","sidebar","mobileBtn","registerMissed","node","topMargin","bottomMargin","searchWords","select","mode","dispatchCustomEvent","button","queryform","facets","hiddenFilters","isAnySet","el","lock","flagUIBusy","wrapSerialized","filters","fbtxt","entry","vals","itemsRequest","associatedFilters","txtinput","tagsBar","newtags","tag","setupAutoPageFilter","getFrontendData","onDomReady","registerCustomFilter","TestFilter","context","els","_","jsxcreate","registerCustomFilter","setupNextPager","registerTexts","init_dompack","MenuHandler","menuNode","options","addDocEventListener","event","getBrowser","perfect_scrollbar_esm_default","curItem","stop","dispatchCustomEvent","level","item","testItem","unhandledKey","force","horizontalMain","anyOpened","sibling","wasOpened","opened","node","init_dompack","registerTexts","UtilityMenu","MenuHandler","node","loginNode","qS","addDocEventListener","event","q","foldoutNode","userInfo","getUserInfo","menu","jsxcreate","item","getLoginLink","getTid","dutch","frontendData","getFrontendData","utwenteRoot","peopleRoot","study","dispatchCustomEvent","isHTMLElement","stop","visible","selector","register","init_dompack","init_env","init_std","init_dompack","BreadcrumbList","node","entries","ellipsisNode","jsxcreate","entry","width","childNode","itemWidth","styles","shorten","itemsWidth","item","init_dompack","init_gettid","init_dompack","getCompactMenuBreakpoint","menuWidth","combineFloatParagraphs","container","qSA","qS","child","wrapper","nextChild","floatingImg","jsxcreate","MAX_PAGE_WIDTH","menuPromise","getMenusForFolder","url","res","itemClassName","classNames","item","renderBanner","data","banner","jsxcreate","_","content","createMenu","options","homeLinkCount","getTid","itemIdx","jsxfragment","subItem","subItemIdx","subSubItem","createSecondaryMenu","getMainMenu","menus","getSecondaryMenu","getMenuWidth","mainLeft","mainRight","secondaryLeft","secondaryRight","mobileMenus","MobileMenuHandler","MenuHandler","node","addDocEventListener","event","stop","mutations","menuWidth","mq","getCompactMenuBreakpoint","toggle","opened","currentItems","mq_event","mobile","curItem","menu","mutation","oldClass","newClass","parent","currentSubmenu","lastOpened","register","init_dompack","toNavBarDistance","temporaryFocusedNode","temporaryScrolledToNode","onDomReady","init","checkLeavingTemporaryFocusableElement","button","doSkipLinks","event","main","header","nodeHeaderMessagesArea","nodeHeaderCTA","nodeTitleContainerBG","nodeTitleContainer","scrollToNodeInHeader","focusNode","scrollToNode","navContainer","navPosition","obscuredareaheight","elements","getFrontendData","HeaderUniverse","node","debugFlags","e","element","svgNode","jsxcreate","name","_","prevElement","getLocal","shuffle","setLocal","response","text","svgDoc","frontendData","defs","svgNS","gradient","stop1","stop2","register","lock","flagUIBusy","getMainMenu","menu","registerMissed","error","getSecondaryMenu","BreadcrumbList","init_dompack","register","node","init_dompack","register","node","cssPromise","loadCSS","psaPromise","onDomReady","loadScript","req","loadApp","resolve","i","psa","e","init_dompack","register","node","jsxcreate","init_dompack","getActiveElement","doc","getToplevelWindow","toplevelwindow","asIframe","node","getCurrentlyFocusedElement","limitdoc","focused","frame","canFocusTo","ignoreInertAttribute","getFocusableComponents","startnode","options","focusable","currentnode","currentstyle","iframe","subnodes","formatters","updaters","mergeNode","node","set","data","parts","isNodeFunc","func","exprpath","callparts","funcrest","value","exprpathparts","i","prop","run","mergenode","filter","nodes","sets","init_dompack","init_dompack","getISOLocalDate","date","init_dompack","init_env","init_std","init_formservice","lookupcache","verifyHareScriptAddress","address","options","lookupkey","stringify","emplace","getFormService","init_dompack","init_env","init_gettid","init_dompack","JSFormElement","newname","required","disable","name","oldValue","newValue","init_std","queryFormFieldLike","isInputElement","field","isHTMLElement","isFormFieldLike","control","isFormControl","JSFormElement","isRadioOrCheckbox","isRadioNodeList","el","getFieldName","setFieldName","newname","getFieldDisplayName","downgradeUploadFields","form","uploadfield","qSA","input","attr","getErrorForValidity","validity","getTid","max","reformatDate","min","key","isFieldNativeErrored","getFieldNativeError","parseCondition","conditiontext","getFormElementCandidates","basenode","namePrefix","parentForm","candidates","getFormHandler","node","allowMissing","throwError","setupServerErrorClear","field","group","setFieldError","ComponentValidationState","el","err","getFieldNativeError","validations","getValidationState","state","newstate","error","options","isHTMLElement","debugFlags","getFieldDisplayName","updateFieldError","dispatchCustomEvent","setupValidator","node","checker","init_std","SubField","node","pos","throwError","AddressField","qR","prefixLength","fieldpos","field","qSA","event","fieldname","data","firstfield","key","country","ordering","e","prevgroup","idx","item","fieldgroup","setFieldError","value","visiblefields","anyset","allrequiredset","form","FormBase","curstate","result","lock","flagUIBusy","el","verifyHareScriptAddress","debugFlags","err","anychanges","newvalue","changeValue","init_gettid","init_std","formatDate","dateformat","year","month","day","isValidDate","output","c","parseDate","format","newdate","options","parts","dayoffset","monthoffset","yearoffset","daypos","monthpos","yearpos","day","month","year","isValidDate","parseISODate","newdate","options","parseDate","init_std","validateCheckboxGroup","groupnode","nodes","qSA","min","max","anyenabled","node","numChecked","getTid","validateRadioGroup","reformatDate","datestr","parsed","parseISODate","formatDate","validateDate","date","dateparts","year","month","day","isValidDate","normalizeddate","validateTime","time","timeparts","hours","minutes","seconds","setup","form","datecontrol","field","datematch","propname","thedate","getISOLocalDate","setupValidator","timecontrol","propvalue","checkboxgroup","radiogroup","addresscontrol","AddressField","init_std","init_env","rfSymbol","init_gettid","init_std","init_dompack","fixupConditionRecursive","node","condition","mapping","anychanges","subcondition","newName","ArrayField","handler","items","name","throwError","qS","event","addDocEventListener","rownode","qSA","form","getFormHandler","newrow","addedrow","registerMissed","setup","stop","delNode","row","rowBaseName","rowFields","getFormElementCandidates","_","RecordFieldHandler","rows","n","rowval","valuePromises","rowPromises","field","values","rowValue","value","idx","rowField","firstnode","valueRows","newvalue","fieldnode","rowid","nodeArray","fieldname","getFieldName","cellname","subname","setFieldName","labelnodes","labelnode","type","conditionnode","parseCondition","minRows","maxRows","numRows","getTid","init_std","unmapFieldName","camelCaseName","nameToSnakeCase","mapFieldName","htmlName","nameToCamelCase","mapValue","type","invalue","unmapValue","fieldDescr","isDate","HTMLFormFieldHandler","form","field","selectedrow","newvalue","setvalue","RadioFormFieldHandler","name","rnodes","group","node","_","myname","CheckboxGroupHandler","cboxes","throwError","toset","missing","cbox","RegisteredFieldHandler","ArrayFieldHandler","items","rfSymbol","ArrayField","getFieldName","FormFieldMap","fieldName","nodes","subpos","groups","fullName","arraygroup","AddressFieldHandler","RecordFieldHandler","options","mapName","match","data","ignoreUnknownFields","key","value","baseName","retval","val","prettyName","omit","FieldMapDataProxy","target","p","prop","init_browser","delayvalidation","validationpendingfor","didGlobalHandlers","lineFeedsToBreaks","text","frag","part","getPageIdx","state","page","idx","getErrorFields","validationresult","field","getFieldName","value","index","self","hasEverFailed","doValidation","iffailedbefore","releasePendingValidations","debugFlags","form","doDelayValidation","tovalidate","lastfocusout","handleFocusOutEvent","event","handleFocusInEvent","handleValidateAfterEvent","FormBase","FormFieldMap","generateRandomId","#lastFocused","FieldMapDataProxy","node","getFormElementCandidates","setup","addDocEventListener","evt","#recordLastFocus","pagestate","name","#onUnload","now","eventdata","dispatchCustomEvent","control","qSA","element","target","ourcondition","parseCondition","searchparams","allvalues","shouldbechecked","tocheck","_","type","getError","fieldgroup","field_with_message","error","potentialgroupnode","contextnode","messageid","messagenode","suggestionholder","create","describedby","describedby_fields","failedfield","getValidationState","stop","extradata","submitter","submitselector","tempbutton","beforeResult","isPromise","el","queryFormFieldLike","startingpoint","lock","flagUIBusy","result","containingpage","pagenum","actionnode","pages","curpage","pagelist","currentpage","scrollto","origscrollto","__isSubmit","pageidx","goingforward","run","direction","pagenode","action","navigateTo","validationstatus","isinit","hiddenPages","mergeNodes","anychanges","formpage","visible","hiddengroups","enabledgroups","requiredgroups","formgroup","groupPage","enabled","required","formline","inputtargets","node_enabled","isFormFieldLike","node_required","isFormControl","option","option_enabled","option_hidden","selectnode","wrapSerialized","nodes","formvalue","mergeNode","conditiontext","fieldname","options","matchfield","isRadioNodeList","currentvalue","conditionfield","fields","attrname","selectedvalue","val","selected","qS","extrafields","condition","subcondition","birthdate","age","matchcase","compareagainst","currentValArray","nextpage","morepages","curpagerole","nextpagerole","rawNavigateTo","exitButton","parsedNavTo","redirectdelay","submitButton","submitButtonLabel","richvalues","registerMissed","dtapStage","getFieldDisplayName","rfSymbol","deferred","file","fieldnode","saveInteractive","changeValue","foundfields","skiparraymembers","addto","isRadioOrCheckbox","outdata","fieldpromises","receivedvalue","resolve","reject","e","opts","vals","checker","setupValidator","setFieldError","isFieldNativeErrored","updateFieldError","validator","limitset","defer","item","original","group","subnode","tovalidatelist","validationresults","fld","failed","tofocus","canFocusTo","getFocusableComponents","focus","init_formservice","init_dompack","init_gettid","init_formservice","init_std","init_env","cache","mayValidateField","field","acceptEmailSuggestion","evt","form","suggestion","stop","validateField","setFieldError","checkvalue","isValidEmail","getTid","key","rpcCall","getFormService","getTidLanguage","wrapInTimeout","result","e","debugFlags","jsxcreate","init_dompack","init_keyboard","dialogstack","keyhandler","dialogconstructor","dialogoptions","onEscape","event","stop","onTab","direction","focusable","getFocusableComponents","el","getCurrentlyFocusedElement","tofocusidx","tofocus","focus","DialogBase","options","borrow","KeyboardHandler","evt","myoffset","response","setupDialogs","newdialogconstructor","createDialog","options","dialogconstructor","dialog","runMessageBox","question","choices","choicebuttons","choice","create","dialogoptions","init_env","init_std","init_upload","init_jsonrpc_client","init_dompack","init_gettid","registerTexts","captcharegistry","initializeCaptcha","provider","injectInto","settings","finalsettings","getTid","init_gettid","CaptchaField","JSFormElement","evt","form","setFieldError","getTid","provider","initializeCaptcha","result","stop","setupCaptchaFieldGroup","captchaControl","create","virtualCaptchaPage","buttonarea","qS","init_dompack","init_std","formConfiguration","handlers","configuredRegistrations","firstWarningMs","warningIntervalMs","scheduleFormSetup","form","factory","_stack","lock","__using","flagUIBusy","customEls","qSA","_","initPromise","nextWarning","timeoutPromise","sleep","missing","tag","downgradeUploadFields","_error","_hasError","__callDispose","configureForms","setup","dispatchCustomEvent","registerHandlers","addHandlers","defaultHandler","RPCFormBase","handlername","handler","emplace","current","register","registerHandler","getFormConfiguration","unpackObject","formvalue","_","buildTarget","target","FormSubmitter","cache","offline","file","completed","uploader","SingleFileUploader","uploadinstructions","getTSFormService","uploadedfile","isBlob","result","key","value","buildRPCFormSubmission","target","formValue","options","vals","FormSubmitter","eventdetail","buildTarget","unpackObject","submitRPCForm","submission","createClient","RPCFormBase","FormBase","#hadFocus","#completedUploads","#settingUpCaptcha","formnode","#onFirstFocus","isLive","#getSubmitVals","formvalue","background","methodname","args","waiter","lock","flagUIBusy","rpc","getFormService","result","field","prop","value","key","keyValue","matchpage","dataval","fieldnode","registerMissed","promise","messages","msg","extradata","extraSubmitAwaitable","extraSubmit","dispatchCustomEvent","config","getFormConfiguration","captchaConfig","setupCaptchaFieldGroup","parameters","insubmitrpc","submitparameters","debugFlags","didfirstfocus","globalerrors","error","failednode","serverMetadata","focus","setFieldError","run","failedfields","pick","e","errors","create","runMessageBox","navigateTo","getCurrentlyFocusedElement","validation","validateField","init_dompack","init_gettid","init_dompack","init_upload","init_gettid","registerTexts","isAcceptableType","fileType","masks","basetype","FileEditElement","JSFormElement","csslink","#setValue","evt","error","setFieldError","getTid","value","toset","row","getFieldDisplayName","mimetype","accept","mask","files","_stack","lock","__using","flagUIBusy","file","requestFile","_","_error","_hasError","__callDispose","msg","dispatchCustomEvent","idx","stop","button","init_std","FileUploadFormElement","FileEditElement","#constructFileHolder","fileholder","nodes","idx","file","filename","isFile","filenamefield","jsxcreate","deletebutton","getTid","uploadbutton","init_dompack","init_std","init_gettid","init_upload","revoker","cachedURLs","createFileURL","file","emplace","newurl","oldurl","getImageDimensions","img","loadImage","getFileAsDataURL","ImgEditElement","_ImgEditElement","FileEditElement","name","_oldValue","newValue","value","textupdate","qSA","node","error","size","setFieldError","getTid","nodes","idx","imgholder","create","deletebutton","contentwrapper","uploadicon","explain","init_std","init_dompack","init_keyboard","init_dompack","init_keyboard","init_tree","init_gettid","init_dompack","init_dompack","recaptchaload","recaptchaOptions","makeRecaptchaLoadPromise","jsxcreate","runRecaptcha","provider","injectInto","settings","lock","flagUIBusy","captchanode","recaptchaid","response","setupGoogleRecaptcha","options","captcharegistry","init_dompack","script","endpoint","isLoaded","runFriendlyCaptcha","provider","injectInto","settings","captcha","evt","_stack","lock","__using","flagUIBusy","loadScript","_","_error","_hasError","__callDispose","setupFriendlyCaptcha","options","captcharegistry","setupForms","options","registerHandlers","configureForms","omit","init_dompack","init_env","CssClasses","e","classes","join","t","a","b","name","DEFAULT_DURATION_MS","CONTENT_PANEL_TRANSITION_PROPERTIES","parseAnimationDuration","n","trimmed","cssValue","fallback","ms","seconds","numeric","getAnimationDuration","element","getAnimationTimeout","r","fromCss","userTimeout","prefersReducedMotion","normalizeTransitionProperties","propertyNames","waitForTransitionEnd","i","signal","pending","timer","settled","finish","o","onTransitionEnd","onAbort","resolve","event","timeoutMs","waitForAnimationEnd","onAnimationEnd","animationName","Settings","e","settings","generateID","copyOptionData","data","result","key","value","t","getLabelElementText","clone","label","el","getAssociatedLabelText","select","texts","hasClassInTree","hasClass","n","c","className","parentByClass","element","debounce","timeout","args","context","later","r","immediate","func","callNow","wait","selectedIdsEqual","a","b","sortedA","sortedB","id","i","OPTION_FIELDS","shallowRecordEqual","aKeys","bKeys","normalizedOptionField","field","option","isOptgroupItem","item","optionStructureEqual","optgroupStructureEqual","normalized","optgroup","aNormalized","bNormalized","aOptions","bOptions","dataStructureEqual","aItem","bItem","aIsOptgroup","kebabCase","str","match","shouldUseModalView","modal","viewportWidth","GlobalEvents","handlers","options","Lifecycle","gen","info","resolvers","resolve","settled","finish","idx","controller","phase","Option","Optgroup","o","Store","type","dataObj","validationError","dataFinal","optOptions","candidate","selected","newData","selectedOptionsBeforeUpdate","preserveSelected","missingSelected","selectedOption","allowEmptySelection","selectedIds","addToStart","firstOption","hasSelected","selectedObjects","optionValue","selectedType","selectedValues","search","searchFilter","opt","view","source","dataSearch","filter","includeOptgroup","newOrder","isIn","TYPEAHEAD_RESET_MS","Render","store","classes","callbacks","before","after","beforeIds","afterIds","index","storeOption","classValue","cls","useModal","dirClass","selectedOptions","selectedId","overlay","dialog","title","closeButton","closeSvg","closePath","getAnimationTimeout","waitForTransitionEnd","CONTENT_PANEL_TRANSITION_PROPERTIES","signal","wasModal","listboxId","main","highlighted","values","deselect","shouldDelete","newSelectedIds","min","currentIds","deselectSvg","deselectPath","arrow","arrowPath","eventType","placeholderOption","placeholderText","placeholder","selectedSingle","singleValue","currentNodes","commaOptions","commaValue","maxValuesMessage","removeNodes","node","animationDuration","waitForAnimationEnd","d","shouldAdd","chip","deleteButton","chips","current","dir","onlyHighlighted","target","next","canRemove","deleteButtons","text","deleteDiv","deleteSvg","deletePath","status","list","message","contentHeightChanged","layoutChanged","entry","entries","height","observed","observe","parent","stopAt","depth","input","addable","searchReturn","showGlobalSelectAll","debouncedSearch","highlightedEnter","selectAll","plus","plusPath","inputValue","runFinish","newOption","oo","ids","getAnimationDuration","addableValue","query","notPlaceholder","notDisabled","notHidden","prevOption","prevParent","optgroupLabel","selectOption","selectParent","firstHighlight","char","repeating","highlightedClass","selectedClass","origin","startIndex","s","optionEl","listId","errorDiv","error","searchingDiv","po","noResults","addableMessage","fragment","optgroupEl","optgroupLabelText","optgroupActions","currentSelected","newSelected","optionIds","optgroupClosable","optgroupClosableSvg","optgroupClosableArrow","searchTrim","visibleOptions","optionEls","isPermanentlyHidden","matchesSearch","storeOptions","renderedOptions","storeIds","closable","optgroups","exceptOptgroupEl","hasVisibleOption","visibleCount","lastSelectedEl","isSelected","allSelected","selectAllLabel","selectAllSvg","selectAllBox","selectAllCheck","onClick","selectable","selectableIds","dataClass","elementID","isCurrentlySelected","isCmd","shouldUpdate","lastIndex","currentIndex","endIndex","newSelections","u","isModifierKey","mainClass","contentClass","modalClass","searchTerm","escapedSearch","tempDiv","highlightTextNodes","regex","wrapper","part","mark","child","isAbove","direction","addClass","removeClass","mainHeight","contentHeight","containerRect","top","left","knownWidth","cw","px","contentRight","viewportLeft","width","docLeft","newLeft","overflow","cTop","container","cBottom","eTop","eBottom","mainRect","hasSelectedItems","isMultiple","allowDeselect","atMinSelected","deselectButton","hideClass","classifyMutations","flags","m","mutations","Select","listen","initialSelectionChanged","selectionChanged","classChanged","titleChanged","disabledChanged","optgroupOptionChanged","currentData","nodes","mutation","isHidden","opts","optgroupOptions","nativeValues","style","selectedBefore","pending","optionClass","labels","selectId","labelClickHandler","isSlimSelectElement","handler","shouldSkipStructureUpdate","resolveSelectedIds","valueList","SyncCoordinator","deps","change","batch","hasStructure","changes","hasAddOption","structureChanges","lastStructure","selectionChanges","isSearchResult","err","events","preserveSelection","dataClean","render","searchValue","runAfterChange","isApiSearchOverlay","optionExists","baseline","SlimSelect","config","CssClasses","debounceEvents","disabled","renderCallbacks","selectAriaLabel","selectAriaLabelledBy","labelledByIds","closed","skipRefocus","trimmed","searchResults","generation","searchResp","applyResults","getTrigrams","str","trigrams","i","trigram","TrigramMatcher","strs","s","ut","occ","v","retval","score","t","a","b","init_dompack","init_env","legacyRegisterFormHandler","handlername","handler","registerHandler","form","createdForm","isLive","FormBase","RPCFormBase","setupForms","form","FormBase","setupFormAnalytics","init_gettid","PhoneField","input","fieldgroup","wrapper","jsxcreate","countries","country","select","B","setupValidator","inp","matchcountry","c","phoneNumber","selectedCode","countryCode","countryinfo","phonePrefix","digits","getTid","chknumber","match","setValue","changeValue","requestGeoIP","register","node","init_dompack","RTDEditElement","JSFormElement","_stack","specifiedopts","structure","hidebuttons","style","rtdoptions","lock","__using","flagUIBusy","richeditor","evt","dispatchCustomEvent","_","_error","_hasError","__callDispose","newvalue","url","formhandler","result","disable","nowenabled","node","RTDField","options","init_dompack","init_formservice","EmbedVideoForm","RPCFormBase","node","dialog","rtd","result","insertVideo","formloadlock","flagUIBusy","formhandler","formdata","getFormService","createDialog","qR","init_dompack","registerTexts","init_gettid","init_dompack","BasicDialog","DialogBase","classname","options","create","evt","stop","registerMissed","lang","setupDialogs","options","UTDialog","UTDialog","BasicDialog","jsxcreate","options","closebtn","evt","stop","getTid","perfect_scrollbar_esm_default","registerMissed","contentnode","clickOutsideElement","element","event","rect","utDialog2","name","ev","overlaylayer","lang","init_dompack","shouldOpenInNewWindow","link","page","ourtextnode","node","checkNewWindowLink","setupFormLinkHandling","register","init_dompack","UTRPCFormBase","RPCFormBase","getReferralInfo","getLang","setupFormLinkHandling","lang","FileUploadFormElement","ImgEditElement","register","node","RTDField","setupFriendlyCaptcha","setupGoogleRecaptcha","setupForms","debugFlags","showSearch","qSA","ss","B","rfSymbol","val","setTidLanguage","jsxcreate","getTid","grp","inp","setupValidator","el","dateFormat","getVisualDateFormat","testDate","emailfield","init_dompack","StickyCTAbar","node","e","qS","qSA","btnvisible","btn","sticky","register","template","brochurewidget","form","dialog","createDialog","formwidget","init_dompack","init_dompack","videoNodeInitialized","vimeoFrameLoaded","default_video_playback","generateVideoNode","video","playback","mergedoptions","playernode","args","youtube_url","__getPlayerFrame","getYouTubePlayer","getStaticVideoPlayer","vimeo_url","t","minutes","seconds","event","getVimeoPlayer","params","host","videoid","authorizationkey","playback_url","getYujaPlayer","getHtml5Player","ifrm","isVideoNodeInitialized","node","initializeVideoNode","options","opts","resolve","reject","player","StaticVideoPlayer","loop","volume","dispatchCustomEvent","YouTubeVideoPlayer","VimeoVideoPlayer","Html5VideoPlayer","YuJaVideoPlayer","playerScripts","waiter","script","deferred","createDeferred","init_dompack","init_gettid","init_dompack","ScrollListener","onDomReady","selnodes","i","treshhold","nodeinfo","scrollvisibleclass","measuremethod","parallax","free","innernode","factor","zoom","info","action","elementheight","containerheight","overflowsize","p","center","ev","scrollpos","visible","rect","node","dispatchCustomEvent","win_height","scrollListener","scrolllistener_default","managedCTASlot","userCountry","userBeacons","ctas","setupManagedCTA","node","getUserCountry","getUserBeacons","debugflags","ctadata","subnode","parseManagedCTAConfig","ctatags","cta","updateManagedCTA","requestGeoIP","country","scrolllistener_default","onManagedCTADisplay","onManagedCTAClick","updateAllManagedCTAs","showManagedCTAPreview","haveCTA","forced","displaycta","tryMatchCTAConfig","e","CTAMatchError","dispatchCustomEvent","params","testprops","any_shown","matcherror","explanations","getTid","beacon","positives","_","negatives","jsxcreate","text","event","eventValues","target","pushToDataLayer","register","init_dompack","CountDownComponent","node","options","wrapper","qS","evt","state","countdownfrom","parseCountdownToString","countdownto","digitnode","wrapidx","now_timestamp","now","distance","days","hours","minutes","seconds","digits","idx","leadingzero","initially_visible_digits","digitnr","value","number","amount","digitdesc","position","firstchild","tracknode","digitcontainer","frag_alldigits","frag_lessdigits","frag_digits_hourstens","digit","frag","nrs","paper","current_nr","str","parts","dayparts","timeparts","register","init_dompack","fadeInOutSlides","node","options","qSA","idx","videoSlideTimeout","videoClass","breakpoint_deeplinks","videoSlideShow","node","qSA","videoNode","videoPauseMedia","event","pauseVideo","video","initializeVideoNode","prevVideo","register","contentHeaderWidthAnimation","y","width","fadeInOutSlides","photoInfobtns","qR","ev","elements","el","visiblePhoto","qS","authorinfo","init_dompack","init_env","notificationDelay","notificationNode","notificationId","closedNotifications","onShowNotification","event","_storedClosedNotifications","_","debugFlags","rect","u","c","dispatchCustomEvent","onHideNotification","onNotificationTransitionEnd","register","node","ev","qSA","icon","init_dompack","SmoothScroll","nodes","node","href","target","event","init_dompack","ScrollListener","onDomReady","qSA","selnodes","i","treshhold","nodeinfo","scrollvisibleclass","measuremethod","parallax","free","innernode","factor","zoom","info","action","elementheight","containerheight","overflowsize","p","center","scrollpos","visible","rect","node","dispatchCustomEvent","win_height","scrollListener","scrolllistener_default","init_gettid","init_std","initialhash","checkHiglightDeeplink","besthref","bestdeeplink","deeplinklist","qSA","deeplink","href","target","currentvisible","qS","isbefore","initDeeplinksNav","h2","anchorId","slugify","jsxcreate","setupDeepLinksNav","headings","formpage","anchor","linkanchor","i","newid","text","deeplinksNode","getTid","deeplinks","SmoothScroll","scrolllistener_default","targets","init_dompack","init_gettid","init_jsonrpc_client","service_default","createClient","importHTML","htmlstring","doc","qSA","showOsirisLink2016","id","language","osiriscontentnode","jsxcreate","getTid","dialog","createDialog","result","service_default","showOsirisLink2026","utDialog2","onOsirisLink","event","utcourselink","init_dompack","observer","resizeListener","entries","onResize","event","onWindowResize","nodes","entry","callback","node","rect","observeNodeResize","init_dompack","init_dompack","SwipeDetect","node","options","event","ev","dx","dy","abs_x","abs_y","dispatchCustomEvent","SlideShow","nodes","options","node","SwipeDetect","ev","nextSlide","dot","idx","event","nextindex","moveleft","curNode","dispatchCustomEvent","startplay","cookiebar_default","isVideoNodeInitialized","initializeVideoNode","player","show","fsslideshow","init_dompack","import_masonry_layout","init_dompack","DompackMasonry","node","options","domoptions","getJSONAttribute","force","clientwidth","cstyle","padtop","padbottom","padleft","padright","widgets","elem","visiblewidgetscount","columnwidth","columncount","singlerow","columns","xcol","widgetrecs","dirty","idx","widget","widgetcols","width","dispatchCustomEvent","widgetrec","widgetheight","bestcol","ypos","col","maxypos","nextypos","styles","maxheight","getCSSVariable","property","options","resolve","reject","data","checkCSSVariable","value","widgetContainers","relayout_throttle","windowMode","registerWidgetsContainer","widgetContainer","throttledRelayoutWidgets","evt","relayoutWidgetsDueToResize","sendBeforeRelayoutEvent","refreshWidgetBlock","onRelayoutWidgets","event","dispatchCustomEvent","checkWindowSize","mode","refreshDompackWidgetBlock","refreshDesandroWidgetBlock","DesandroMasonry","force","options","layout","parts","DompackMasonry","widgets","widget","register","widgetblock","initialhash","anode","qS","getCSSVariable","breakpoint_phone","initMasonryMedia","init_dompack","relayoutWidgets","widgetnode","dispatchCustomEvent","forceRelayoutWidgets","init_gettid","init_dompack","setConsentLayers","node","qSA","shieldnode","directlink","network","infocode","qS","info","jsxcreate","getTid","playername","getTwitterConsentlayer","ev","onShieldNodeClick","link","isHTMLElement","cookiebar_default","removeConsentLayers","onDomReady","init_dompack","register","setupCookieWidget","init_dompack","block","CarrouselContent","widgetnode","options","itemnode","measurenode","evt","resizeObserver","scrollLeft","idx","animate","bullet","activepage","item","in_view","scrollWidth","containerbounds","pagex","viewportbounds_inner","viewportbounds","nextpage_xpos","pagenr","items_this_page","itemnodes_this_page","itembounds","itemx","itemxend","comp","left","multiplepages","delay","resizeObserver","entries","onResize","resizeAllContentCarrousels","entry","widgetdata","onDomReady","init_dompack","initImagesWithCaptionWidget","widgetnode","carrousel","CarrouselContent","doCreateBullet","onChangeSlide","details","firstnodeinslide","nodeid","activemetanode","metanode","jsxcreate","register","init_dompack","CountDownComponent","node","options","evt","countdownfrom","parseCountdownToString","specialcontainer","countdownto","digitnode","wrapidx","now_timestamp","now","distance","days","hours","minutes","seconds","digits","idx","leadingzero","initially_visible_digits","digitnr","value","number","amount","digitdesc","position","firstchild","tracknode","digitcontainer","frag_alldigits","frag_lessdigits","frag_digits_hourstens","digit","frag","nrs","paper","current_nr","str","parts","dayparts","timeparts","register","initCountdownComponent","init_dompack","CountDownEventsWidget","node","now","eventnode","eventdata","parseCountdownToString","firstupcomingevent","addevent_data_container","CountDownComponent","register","initCountDownWidget","init_dompack","renderEvents","node","items","remove","listnode","qS","item","link","jsxcreate","relayoutWidgets","getEventItems","response","register","FeedbackForm","RPCFormBase","node","inpnode","ev","faqnode","res","legacyRegisterFormHandler","init_dompack","init_dompack","init_gettid","registerTexts","runYesNoMessageBox","question","node","jsxcreate","n","runMessageBox","getTid","showModalDialog","title","contents","options","modalnode","hideModalDialog","blurredbg","bg","bodynode","titlenode","closebtn","getTid","contentnode","ev","dialognode","register","node","showModalDialog","jsxcreate","init_dompack","renderNews","node","items","remove","photosnode","qS","listnode","item","i","link","jsxcreate","relayoutWidgets","getNewsItems","response","register","init_dompack","init_dompack","renderPrettyPhoneNumber","node","parts","jsxcreate","showDetails","container","timer","hideDetails","__timer","togglePersonalDetails","node","ev","stop","quoteswidget","widgetnode","foldcontainer","qS","EmbQuoteSlides","wrapper","qSA","jsxcreate","_","i","idx","register","quotesSlideshow","itemcount","item","frontnode","jmpbtns","c","jmpbtn","oldidx","minh","panel","y","relayoutWidgets","renderPrettyPhoneNumber","init_dompack","setupPodcast","node","params","cookiebar_default","startPodcast","ev","qS","podcast_title","startTransistor","startSoundCloud","url","jsxcreate","urlparts","paramnames","name","register","init_dompack","init_dompack","init_events","foldableContent","node","options","ev","stop","open","params","pushToDataLayer","findDetailsHash","hash","openCollapsableContainerFor","target","detailsnode","setDetailsEvents","qS","fireHTMLEvent","register","init","onToggleDetails","evt","gtmevent","summaryNode","summaryText","onDomReady","TimelineTableContent","foldableContent","params","table_with_timeline_title","table_with_timeline_main_item","table_with_timeline_sub_item","pushToDataLayer","register","node","init_dompack","register","node","fixVideoPlayButton","playbutton","init_dompack","init_src","whitespace","carrouselwidgets","getContentBlank","widgetnode","measure_element","computed","measureself","removedFullwidthClass","fullwidth","rec","doPauseHeaderAnimation","evt","doUnpauseHeaderAnimation","refreshAllCarousels","widget","fixCarrouselWidgetMinHeight","carrclass","remeasureSlides","nextbutton","firstimage","carrouselrect","minheight","doCheckForCarouselVideoTrigger","event","slidecontainer","videocontainer","isVideoNodeInitialized","initializeVideoNode","player","anchor","style","transform","mat","xpos","width","findwidget","carrwidget","viewport","doOnlyAllowSlideImageLinksOnActiveSlides","register","node","idx","carrousel","SpellcoderCarrousel","init_dompack","fsslideshow","init_dompack","init_browser","onDomReady","ios","getPlatform","__photoalbum_grids","refreshAllPhotoAlbums","grid","defaultoptions","getDefaultGridOptions","doCheckForImageSelection","evt","item","instanceid","items","itemidx","headeranim","node","dpr","contentWidth","register","idx","gridnode","JustifiedImageGrid","init_dompack","init_dompack","init_src","__observer","checkSlideshowVisibility","onDocumentVisibilityChange","slideshow","entries","observer","visible","invisible","entry","isvisible","CarrouselSlideshow","node","options","domoptions","getJSONAttribute","carrousel_options","SpellcoderCarrousel","dragarea","evt","idx","anchor","viewportheight","slideshowbounds","count","delay","SlideshowWidget","widgetnode","btn_prev","btn_next","CarrouselSlideshow","evt","slidecontainer","slidenode","pass","event","videocontainer","isVideoNodeInitialized","initializeVideoNode","player","register","init_dompack","activestep","register","node","builder","parts","steptag","stepstate","activeoptions_str","activeoptions","allsteps","activestepidx","idx","currentstep","tag","jumpToActiveStep","init_dompack","init_dompack","init_gettid","import_jsonrpc","init_std","wordRegex","lastWordRegex","SearchIndex","fields","item","key","invalue","value","match","count","term","pos","entry","props","query","results","parsedQuery","baseQuery","suggestQuery","baseResults","#searchInternal","termField","termText","score","#matchesText","suggestion","scores","result","flatscores","#calculateScores","#getSortedItems","searchResult","terms","field","fieldResults","matches","word","queryResult","#executeQuery","text","item_positions","indexEntry","avg","cur","idx","queryWord","termWord","limitDistance","startsWithScore","dist","levenshteinDistance","a","b","_","init_env","filtertags_ignorefields","filter_lastsettings","filter_lastseenkeys","getResultsFeedbackText","totalfound","totalshown","getTid","getResultsTeaserText","FilteredOverviewHeader","debugFlags","options","qR","node","evt","visible","fieldnodes","idx","frontendConfig","expandwhen","pagekey","firstvisitinsession","gettextfunc","contentnode","text","viewportheight","resultsanchor","results_out_of_view","FilteredOverview","pushToDataLayer","qS","filtertagscontainer","qSA","additionalfields","ev","optnode","filters","urlparamsdone","val","inptype","vals","url","name","anchors","anchor","url2","interactivechange","title","labelnode","dlevent","key","keepwords","nrfilters","forcerefresh","filterstr","result","words","JSONRPC","noresults","tagnode","fieldname","fieldvalue","field","tags","tag","rowkey","item","remove","feedbacknode","urlparamstr","allitemscount","ClientSideFilteredOverview","SearchIndex","itemsselector","items","searchnode","UTAutoComplete","update","suggestions","_","filtername","filterval","setvalues","i","itemdata","doesnotmatch","selectedstatus","parts","qmatches","findtext","itemvalue","searchvalue","i2","found","matchvalue","ismatch","init_dompack","DompackMasonry","node","options","domoptions","getJSONAttribute","items","widgetrecs","wnode","widgetcols","item","setitems","widgets","elem","clientwidth","cstyle","padtop","padbottom","padleft","padright","visiblewidgetscount","columnwidth","columncount","singlerow","columns","xcol","columnitems","widget","width","idx","widgetrec","widgetheight","min_ypos","col","itemcount","lastitemincol","ypos","bestcol","maxypos","widgetbottom","styles","maxheight","SmoothScroll","nodes","options","node","href","target","event","bookmark_offsety","TimelinePageFilter","FilteredOverview","options","items","node","totalfound","yearsinresults","item","doesnotmatch","key","itemvalue","searchvalue","i","found","matchvalue","ismatch","tlwidget","TimelineWidget","widgetnode","evt","qS","SmoothScroll","year","itemnode","labelnode","viewportrect","topy","event","layout","parts","DompackMasonry","renderinfo","idx","visibleyears","itemrect","bookmarkcontainer","bookmarkcontainer2","bookmark","inview","videocontainer","isVideoNodeInitialized","initializeVideoNode","player","register","onDomReady","init_dompack","BannerSlideshowWidget","widgetnode","CarrouselSlideshow","slide","largestheight","slideheight","refreshBannerSlideshowWidgets","widget","register","init_dompack","initProgressCircles","node","animationsdone","percentage","contoursize","circlenode","percentagenode","ev","timestep","step","t","updateDigits","initProgressBars","initSegmentedCircle","basenode","sel_idx","subnode","selnode","timeout","labelnodes","idx","initChart","chartnr","chartdata","ispreview","rgbcolor","ColorStringToRGB","labels","nrvalues","nrgroups","chartnode","legendanode","chartsize","hintervalwidth","i","labelnode","valuesmax","valuesmin","c","hlinescount","hspacesteps","precisionfactor","hvaluestep","labelwidth","haszeroline","v","yvalue","hnode","vlabelnode","vtitlenode","svgnode","scaley","opacity","svgpath","linenode","colval","x","y","RoundValue","RGBaToColorString","hoverid","legendalabel","pointnode","valuenode","infonode","bulletnode","line","groupoffset","barnodes","left","barheight","stylstr","barnode","number","decimalplaces","multiply1","divide1","divide2","multiply2","colorstr","r","g","b","a","alpha","register","dispatchCustomEvent","init_dompack","offsety","LinksPerCategoryWidget","widget","qR","evt","tab","tabs","qSA","contentpanels","tabnode","cnode","idx","contentpanelbounds","tabsbounds","bodybounds","scrolltoy","pointCurveFromTo","activetab","qS","curve","startnode","endnode","pointerrect","startnoderect","endnoderect","topy","bottomy","pathwidth","pathheight","abspathheight","curveradiusx","curveradiusy","x0","x1","x2","x3","x4","y0","y1","y2","y3","path","refreshWidgets","register","node","init_dompack","renderNewsAndEvents","node","qR","response","res","items","item","jsxcreate","tag","ev","url","register","init_dompack","loadPromises","startChat","node","_stack","samRootUrl","langHint","getLang","programHint","lock","__using","flagUIBusy","loadScript","loadCSS","_","_error","_hasError","__callDispose","register","addDocEventListener","init_dompack","init_dompack","init_dompack","SwipeDetect","node","options","ev","event","posx","posy","dx","dy","dispatchCustomEvent","init_gettid","_transitionDuration","PhotosOverlay","data","ev","selectedidx","totalcount","jsxcreate","photo","idx","imagenode","getTid","SwipeDetect","detail","utDialog2","selected","videonode","el","nrOfImages","scaledImage","curphoto","qS","curvideo","prevphoto","video","nextphoto","PhotoAlbumWidget","node","ev","qSA","item","data","PhotosOverlay","idx","_","rows","maxWidth","w","itemWidth","row","rowidx","totalWidth","sum","register","init_dompack","initWideImage","checkWideImage","wideimages","imgcount","node","widelink","dragging","dragThreshold","openFoldableContent","className","foldcontainernode","initFoldableContent","titlenode","textnode","setHandler","event","toggleHandler","dispatchCustomEvent","toggleStudyFinderSpecializations","ev","itemnode","spnode","activateStudyfinderWidget","widgetnode","showallnode","evt","expandStudyfinderWidget","register","prevnode","prevembobjectnode","onDomReady","Tabs","container","qS","qR","titles","qSA","page","idx","tab","observeNodeResize","newIdx","pos","firstLeft","titleRect","initializeCallbackForm","node","formNode","inputNode","event","stop","phonenr","formdata","submitCallbackForm","lock","flagUIBusy","result","service_default","relayoutWidgets","register","callbackform","initializePhotoslide","widgetphotos","slides","relayoutPhotoslideByEvent","relayoutPhotoslide","SlideShow","evt","infoheight","height","widgetinfos","imagewidget","instanceid","widgettabs","widgetflip","widget","initFoldableContent","forceRelayoutWidgets","init_dompack","openedParts","initialLayout","prevAutoFold","evt","updateFoldableContentBlocks","onDomReady","initFoldableContentBlocks","doCheckLostFocus","hash","block","firstBlock","bodyNode","blocks","autoFold","node","summary","init_dompack","UTMedicalFormHandler","UTRPCFormBase","node","cancelbutton","evt","qSA","currentdate","selection","opt","runMessageBox","result","legacyRegisterFormHandler","init_dompack","register","loginbutton","startSSOLogin","form","setupWebHareSSOTrigger","init_dompack","init_gettid","encodeTextNode","str","cMeetingsForm","UTRPCFormBase","formnode","node","html","participantscount","bhvcount","overviewnode","lines","prevtitle","i","el","title","value","groupnode","separator","prevbhv_nr","bhv_active","bhvnr","create","linecontent","encodeTextNode","res","getTid","description","showModalDialog","legacyRegisterFormHandler","init_dompack","init_gettid","MIN_HEADERIMAGE_HEIGHT","MIN_HEADERIMAGE_WIDTH","getImageDimensions","file","resolve","reject","reader","img","error","NEOForm","RPCFormBase","#errorObserver","#publocs","#validatedAuthorizationOnce","node","mutationList","#handleMutations","fieldGroup","qSA","checkbox","qS","imgedit","#updateAltVisibility","#toggleAltEnabled","fields","infotextwrapper","changing","event","input","allChecked","allEmployees","mpAuthorizedField","setupValidator","#checkRequiredAuthorizedPersonTypes","mpPersonTypesField","value","languages","newstype","publocids","publocs","_","publoc","lang","mutation","target","warningNode","errorNode","legacy","hasImage","name","#checkHeaderPhoto","altEN","altNL","size","setFieldError","getTid","warning","jsxcreate","e","enabled","legacyRegisterFormHandler","init_dompack","FilteredFolderPage","container","listviewheader","qS","ev","col","idx","c","mode","items","qSA","a","b","a_i","b_i","colidx","a_c","b_c","e","register","node","init_dompack","init_gettid","register","node","settings","getFrontendData","neolinks","getSession","idx","_","prevlink","nextlink","nav","jsxcreate","getTid","NeoPageFilter","qR","buttonsWrapper","qS","loc","skip","e","tagEl","filtername","id","selEl","value","showArchive","filtercontext","lock","flagUIBusy","urlParams","archive","tag","res","service_default","isMoreResults","isAnySet","items","qSA","btn","setSession","el","registerMissed","introItems","item","c","otherItems","ev","container","itemEl","EventsFormHandler","UTRPCFormBase","formnode","requesttype","utDialog2","registerCustomFilter","legacyRegisterFormHandler","registrationform","init_dompack","peoplePageFilter","node","titlebar","qS","qR","searchinput","queryindex","getFrontendData","SearchIndex","item","parts","title","description","UTAutoComplete","text","update","suggestions","_","dispatchDomEvent","input","inputRect","container","maxHeight","width","leftPos","evt","isInitial","query","selectedCategory","category","matchedPersonIds","result","qSA","isMatch","cat","loc","filtername","value","register","form","init_dompack","init_gettid","tableWithFilter","container","filterbuttons","qS","jsxcreate","getTid","lock","flagUIBusy","idxlist","qSA","item","result","service_default","filedata","file","link","dataurl","arr","mime","bstr","n","u8arr","register","node","init_dompack","init_internal","TimelinePageFilter","qR","DefaultFilter","settings","getFrontendData","buttonsWrapper","qS","jsxcreate","filtercontext","idxList","item","visibleYears","qSA","seqnr","isMatch","year","el","getTid","tlwidget","registerCustomFilter","init_gettid","init_env","uFondsForm","UTRPCFormBase","formnode","chknode","frontendConfig","ev","val","decsep","parts","cents","full","selval","toggleincassofieldsnames","fieldname","name","urlparamstr","res","navigateTo","title","getTid","description","showModalDialog","destination","legacyRegisterFormHandler","node","init_env","init_dompack","catchServicePortalLoginLink","ev","link","user","getUTUserInfo","getLoginLink","utSilentLogin","why","setSession","getSession","getReasonforSilentLogin","ls","getLocal","beacons","getUserBeacons","isFrame","handleAutoLogin","getDefaultAuth","reason","handleUTGLobalLogin","setLocal","init_dompack","isTopLevelHomepage","lang","onDomReady","combineFloatParagraphs","initDeeplinksNav","handleUTGLobalLogin","getLocal","requestGeoIP","country","setupAutoPageFilter","initTheme","dtapStage","setupAuthorMode","event","toggle","doSearch","register","node","showIndicator","scrollHandler","catchServicePortalLoginLink","utSilentLogin","setupCoBrowserChat","init_dompack","assetPackPromise","register","node","loadAssetPack","init_dompack","RegistrationForm","RPCFormBase","node","qR","nextbtn","qS","getTid","ev","deeplinklist","jsxcreate","page","selectedserie","description","qSA","monthitemswrapper","itemnode","togglenode","sessionswrapper","h","i","titlenode","foldnode","result","retrybutton","legacyRegisterFormHandler","init_dompack","init_dompack","init_jsonrpc_client","site_service_default","createClient","cCancelCourse","data","dialog","createDialog","jsxcreate","getTid","registerMissed","id","hash","ev","e","language","lock","flagUIBusy","site_service_default","cPayCourse","formnode","qR","showPaymentResult","node","btn","cancelCourseDialog","payCourseDialog","register","node","pagecontainer","activetab","i","nodechild","ev","tabcountnode","qS","parentnode","showPaymentResult","target","cancelCourseDialog","payCourseDialog","updateCourseAlert","categories","unsubscibecourses","token","getFrontendData","language","lock","flagUIBusy","result","site_service_default","coursealertnodes","qSA","removenodes","_","courselinenode","unsubscribeCourseAlert","qR","form","init_dompack","cCourseDetailsList","node","footernode","itemnode","ev","foldnode","headernode","closenode","fulldescriptionnode","h_inner","shortdescriptionnode","jsxcreate","words","prevcontent","newcontent","h_outer","btnnode","init_dompack","cCalendar","container","options","jsxcreate","timetable","lastdate","daycontent","prevdate","i","dt","timestamp","getRoundedDayTimestamp","getTid","maxdate","today","todaymonths","setmonths","cMonthTable","ev","dateClickEvent","coursenode","initial","ismobileview","prevview","titlenode","translations","getCalendarTranslations","todaytimestamp","activeym","prevym","monthnode","date","month","year","day","weekday","ym","monthdaynode","h","courseids","filtereditems","monthcount","matchcount","c","id","daynode","curmonthnode","svg","symbol","serieid","title","dialog","createDialog","lock","flagUIBusy","result","site_service_default","dialogcontent","item","session","itemnode","togglenode","sessionswrapper","closebtn","m","node","morenode","offset","activemonths","language","a","b","agendaitems","mindate","seldate","d","startweekday","orgstartday","startday","monthdaycount","endweekday","enddaycount","rownode","lastagendaitem_idx","celldate","cellday","cellmonth","cellyear","celltimestamp","create","classstr","infonode","datenode","parts","dispatchCustomEvent","dateobj","registerTexts","init_dompack","FilterUtwenteCourses","qR","DefaultFilter","getFrontendData","detaillistwrapper","qS","cCourseDetailsList","calendarwrapper","initialdate","year","month","curym","cCalendar","ev","mode","newclass","filtercontext","items","lock","flagUIBusy","result","site_service_default","item","itemids","_","itemcount","qSA","el","getTid","coursestxt","domains","v","i","a","node","coursematchcount","itemnode","itemid","countnode","utwrapper","utcount","sourcewrapper","sourcecount","id","domainstxt","resultnode","register","alertoptions","courseid","coursetitle","parts","container","overviewline","showCourseAlertForm","options","formnode","dispatchDomEvent","inpnode","dialog","createDialog","jsxcreate","dispatchCustomEvent","showCourseAlertSuccess","CourseAlertForm","RPCFormBase","form","getDefaultAuth","getUserInfo","subscribeasoptoins","param","p","categories","subscribeas","loginbtngroup","name","val","registerCustomFilter","legacyRegisterFormHandler","init_dompack","registerTexts","init_env","studyFinderFilter","jsxcreate","create","SearchIndex","qR","DefaultFilter","ev","settings","getFrontendData","qS","i","item","titleNode","descriptionNode","qSA","specialization","searchnode","UTAutoComplete","text","update","suggestions","_","dispatchDomEvent","input","inputRect","container","maxHeight","width","leftPos","context","items","result","resultIds","specializationsNode","specMatchCount","hasMatch","match","parent","terms","node","regex","descriptionNodes","lastIndex","descNode","listItems","idx","compactnode","mode","coltitle","getTid","cellnode","colnode","isothercolumn","sortasc","scoresort","sortedprogrammes","specializations","snode","s","specParent","specNode","spec","prog","programmenode","itemnode","programme","afterNode","toggleSpecializationsFoldout","list","a","b","dataset","isspecialization","cellnames","rownode","linknode","navigateTo","currentcellname","fieldnode","register","programmescontainer","spnode","registerCustomFilter","morebutton","morebuttoncontainer","init_dompack","register","node","init_dompack","createService","services_rpc_default","init_dompack","initWideImage","checkWideImage","wideimages","imgcount","node","widelink","dragging","dragThreshold","openFoldableContent","className","foldcontainernode","initFoldableContent","titlenode","textnode","setHandler","event","toggleHandler","dispatchCustomEvent","toggleStudyFinderSpecializations","ev","itemnode","spnode","activateStudyfinderWidget","widgetnode","showallnode","evt","expandStudyfinderWidget","dompack_exports","register","prevnode","prevembobjectnode","onDomReady","registerTexts","init_dompack","createService","pirservice_rpc_default","cPIR","imagekeys","i","key","oldurl","pirservice_rpc_default","url1","url2","node","parts","part","rules","regexp","c","match","cssitem","items","mediarules","onDomReady","transferWidget","cPIR","node","qS","qR","institute","ev","selnode","programme","busylock","flagUIBusy","opt","result","services_rpc_default","jsxcreate","getHTMLTid","getTid","content","className","routes","c","item","initFoldableContent","setProgramme","url","name","register","form","program","filtersource","dlurl","B","init_dompack","programmeYearFilter","node","dateitems","closest","ev","val","item","register","init_dompack","register","btn","timer","mediaTwoRows","mediaMobile","itemslist","qR","hidebtn","itemh","dispatchCustomEvent","init_dompack","register","node","ev","morebtn","qSA","item","i","remove","init_dompack","studyInNumbers","node","ev","container","qSA","endval","t","el","contoursize","val","register","init_dompack","cssStudiesSorter","node","ev","selcol","closest","hnode","colname","group","groupedlines","previdx","idx","sortval","c","row","a","b","register","init_dompack","ellipsisFoldout","node","textcontainer","qS","ev","stop","register","init_dompack","createService","vacancies_rpc_default","getVacancies","node","options","res","vacancies_rpc_default","item","jsxcreate","relayoutWidgets","register","init_dompack","VacancyOverviewFilter","ClientSideFilteredOverview","options","vactypenode","node","ev","seloption","selectedbranchevalue","branchids","selectedidx","i","create","searchtext","checkTagClick","event","tag","stop","matchoption","qSA","opt","changeValue","qS","onDomReady","init_dompack","ProjectsList","node","qR","listtoggle","addDocEventListener","ev","togglenode","register","init_dompack","createService","leads_rpc_default","getMatches","results","searchfor","matches","text","item","lhs","rhs","getFlatList","list","names","entry","PreppedNameList","flatlist","TrigramMatcher","alias","searchterm","finallist","scoredlist","minscore","_","suggestion","Scope","scopes","lastsuggestions","getScope","limittypes","scopename","getCities","groupname","scope","leads_rpc_default","getMatches","getOrgNames","node","cityfield","key","suggestions","setupSchoolCityField","UTAutoComplete","text","update","item","validateSchoolName","field","jsxcreate","evt","stop","FormBase","setupSchoolNameField","relevantfields","qSA","mypos","setupValidator","register","init_dompack","citylistpromises","institutelistpromises","getInstitutes","countryfield","searchterm","groupname","key","leads_rpc_default","getMatches","_","getInstituteEducations","institutefield","results","getPrevious","node","relevantfields","qSA","mypos","setupInstituteNameField","UTAutoComplete","text","update","suggestions","item","setupInstituteEducationField","register","init_dompack","init_dompack","registerTexts","init_gettid","getPrefills","url","prefills","key","UTVoorlichtingRPCForm","RPCFormBase","node","prefills","getPrefills","toselect","_","response","r","learnedAboutUser","referralinfo","getReferralInfo","userbeacon","getUserBeacons","name","init_dompack","init_env","StayoverEventsSignupForm","UTVoorlichtingRPCForm","form","setupValidator","date","qR","qS","qSA","node","selected","pulldown","option","selection","showloginbutton","error","jsxcreate","link","discountcodefield","verifyresult","runMessageBox","getTid","translations","roundcourse","diff_amount","need_payment","result","navigateTo","runYesNoMessageBox","cuguid","rpc","setupPaymentZone","button","legacyRegisterFormHandler","register","init_dompack","init_std","init_env","register","node","form","eligibilitycheck","qR","idx","_","onSubmit","ev","programs","option","firstprog","throwError","debugFlags","B","newVal","init_dompack","init_std","maxloops","echeckreferral","getEcheckReferral","setEcheckReferral","code","checkEcheckReferral","url","refrl","EcheckForm","RPCFormBase","jsxcreate","node","getFrontendData","qS","qSA","group","groupoptions","col1","col2","splitidx","fieldline","i","groupids","page","_","diplomagroup","eduttypewrapper","colcount","prevtype","inp","innernode","qR","pageid","throwError","groupid","current","status","idx","finalized","step","stepsize","progress","subpages","subcount","subidx","register","actiontype","pos","progressstatus","ignoreanswers","nextaction","selectedoption","retval","htmlstring","contentnode","nextpagelock","flagUIBusy","counter","baseforminfo","getReferralInfo","action","submitdata","submitresult","resultstatus","registerMissed","learnedAboutUser","data","res","skipgroups","nextpage","gotourl","programs","isTruthy","navigateTo","response","content","doc","legacyRegisterFormHandler","init_dompack","init_dompack","registerTexts","init_create","html","elementname","attributes","children","el","createElement","init_std","formapitype","toggleClass","el","classname","setTo","toggleDisabled","runConfirmResignup","runMessageBox","jsxcreate","getTid","OpenDagenForm","UTVoorlichtingRPCForm","node","qR","frontendConfig","qSA","foldablenode","evt","currentlyopen","dispatchCustomEvent","learnedAboutUser","firstpagebutton","qS","triggerUserBeacon","clearUserBeacon","selectedcity","schoolname","opt","show","idx","getReferralInfo","pushToDataLayer","result","pagestate","direction","programmes","val","specials","rounds","info","keyname","toread","setvalue","formadd","layerobj","url","changeValue","toselect","select","round","roundgroup","current","selectnode","enable","anyvisitvisible","optgroup","fieldLine","html","roundshowupboxes","selection","checkedprogrammes","clusteredwith","programme","roundNode","throwError","usenode","errors","res","_result","getHTMLTid","scheduleitem","create","lock","flagUIBusy","legacyRegisterFormHandler","init_dompack","init_gettid","registerTexts","init_env","OpenDagenFormV2","UTVoorlichtingRPCForm","node","pushToDataLayer","qS","evt","eventoptions","idx","getReferralInfo","result","runMessageBox","jsxcreate","getTid","r","debuginfoholder","qR","errors","stop","navigateTo","url","legacyRegisterFormHandler","init_dompack","createService","leadswidgets_rpc_default","init_std","EducationBrochureFormHandler","UTRPCFormBase","node","foldnode","throwError","qR","ev","htmllinknode","qS","qSA","link","evt","stop","dispatchCustomEvent","htmllink","selected_brochure","hash","deeplinkcontainer","_","mutlist","obs","programmeid","guid","getUserSettings","data","res","leadswidgets_rpc_default","msgnode","createDialog","relayoutWidgets","setUserSettings","programme","result","learnedAboutUser","changeValue","txtnode","state","also_set_focus","page1","aftersubmit","el","legacyRegisterFormHandler","init_dompack","stayuptodateFormHandler","UTVoorlichtingRPCForm","formnode","evt","response","lock","flagUIBusy","updatedata","ismaster","programnode","leadswidgets_rpc_default","legacyRegisterFormHandler","node","init_std","PreRegistrationFormHandler","UTRPCFormBase","node","throwError","response","gotourl","learnedAboutUser","relayoutWidgets","legacyRegisterFormHandler","init_dompack","formnode","formextradata","ContactForm","RPCFormBase","form","updateSpecializations","data","learnedAboutUser","legacyRegisterFormHandler","node","programmeid","programme","fieldline","closest","elem","track","dispatchCustomEvent","init_dompack","registerTexts","TasterDaysForm","UTVoorlichtingRPCForm","node","cancelregistration","jsxcreate","event","getTid","register","stop","runMessageBox","gotourl","result","debuginfoholder","qS","errors","legacyRegisterFormHandler","init_dompack","LifeLongLearningRegistrationForm","RPCFormBase","node","qSA","select","btn","qR","ev","price","template","qS","sidebar","tab","idx","page","curTabId","activIdx","registerHandler","init_dompack","init_std","init_dompack","init_dompack","appname","setAppName","newappname","getAppName","instanceOfAny","object","constructors","c","idbProxyableTypes","cursorAdvanceMethods","getIdbProxyableTypes","getCursorAdvanceMethods","transactionDoneMap","transformCache","reverseTransformCache","promisifyRequest","request","promise","resolve","reject","unlisten","success","error","wrap","cacheDonePromiseForTransaction","tx","done","complete","idbProxyTraps","target","prop","receiver","value","replaceTraps","callback","wrapFunction","func","args","unwrap","transformCachableValue","newValue","readMethods","writeMethods","cachedMethods","getMethod","target","prop","targetFuncName","useIndex","isWrite","method","storeName","args","tx","replaceTraps","oldTraps","receiver","advanceMethodProps","methodMap","advanceResults","ittrProxiedCursorToOriginalProxy","cursorIteratorTraps","cachedFunc","iterate","cursor","proxiedCursor","reverseTransformCache","unwrap","isIteratorProp","instanceOfAny","clearCache","appname","cache","key","unregisterServiceWorkers","currentregistrations","reg","debuglayer","clearCache","getAppName","restartApp","unregisterServiceWorkers","runPWADebugMenu","jsxcreate","activatetouches","expectnumtouches","expecttaptime","testMenuTap","event","stop","register","node","settings2","init_env","appbase","pwasettings","getFrontendData","frontendConfig","didinit","offlinedeferred","swregistration","getAppName","settings2","module","webdesign","sendSWRequestTo","sw","type","data","resolve","reject","msg_chan","event","sendSWRequest","checkForUpdate","downloadUpdate","updateApplication","navigateTo","onReady","initfunction","options","getSiteRoot","sendPxlEvent","onDomReady","e","swurl","getAssetPackBase","precheckExistingWorkers","registrations","onServiceWorkerMessage","setAppName","init_gettid","registerTexts","admin","fairsinfo","isWS2026","setTitle","title","qR","html","getSirConfig","getLocal","getSelectedEventId","getSelectedEvent","eventid","fair","getUploadQueue","getNumUploaded","increaseNumUploaded","uploadMap","setLocal","updateOptions","select","newoptions","setValue","oldvalue","setupTrigramSearch","selnode","seloptions","opt","search","currentData","selvalues","d","list","_","s","scorelist","TrigramMatcher","minscore","filteredScoreList","options","insertedParents","i","parentOpt","o","ConfigFormHandler","FormBase","formnode","onReady","curevent","queue","entry","submitRPCForm","e","adminVisible","lock","flagUIBusy","loginitem","create","evt","toremove","qSA","dialog","createDialog","form","ev","compareProperties","ft","wrapSerialized","rpc","updateres","checkForUpdate","downloadUpdate","runMessageBox","getTid","updateApplication","events","eventSelect","B","selectedEvent","dispatchCustomEvent","getTrackTitle","track","getProgramTitle","prog","basename","SignupFormHandler","RPCFormBase","config_fairsinfo","getFrontendData","parseTyped","thankyoupage","btnwrapper","dispatchDomEvent","phoneInput","fixedValue","field","schools","school","programOptions","interestedInSel","programOptionElements","progopts","tracks","node","mainopt","hasSubOptions","subopt","generateRandomId","getTidLanguage","getHardcodedURLReferralInfo","getReferralInfo","setNationality","phoneCountryEl","qS","registerHandler","interestedIn","pick","schoolSel","init_dompack","blocksorder","bigline","initBlocksPage","switchform","onSwitchCategory","blocks","category","container","results","no_filter","node","match","register","init_dompack","init_dompack","init_gettid","initialhash","openFoldableDeepLink","node","container","doJumpIntoDeeplink","target","checkexpand","expandlist","toexpand","openFoldableDeepLink","openFoldableContent","init_dompack","setupToggle","options","node","makeArray","evt","doToggle","doOpen","doClose","onFocusOut","onMouseEnter","onMouseLeave","input","init_gettid","defaultshowamount","showall","items_scroller","register","initFilters","node","evt","runPreregistrationWidget","event","stop","dialogcode","dialog","createDialog","registerMissed","tabstrip","form","toggle","closebutton","itemscontainer","perfect_scrollbar_esm_default","ev","program","category","item","checkboxnodes","cnode","setupToggle","doShowAll","doShowResults","doFilter","visibleitems","doJumpIntoDeeplink","widgetnode","query","items","matching","selecteditems","selecteditemstitle","itemnode","match","checkbox","lookup","labelnodes","itext","visibleprogrammes","visibleevents","filterpanel","manually_checked_items","unique_visible_events","resultstext","titles","title","getTidLanguage","showmorebutton","qR","showbuttontext","qS","relevantto","type","position","qSA","init_std","initActivitiesList","node","form","qR","addDocEventListener","evt","onChangeEventOption","signupbutton","qS","optionnode","option","optionspecificnodes","myPanel","throwError","timeslotheader","qSA","timeslot","signuplink","register","init_dompack","ActivitiesFilter","qR","qS","DefaultFilter","settings","getFrontendData","linklist","jsxcreate","opt","filtercontext","items","registerCustomFilter","init_dompack","setupCTALinksExperiments","node","meta","keyname","abgroup","getLocal","setLocal","qSA","register","requestGeoIP","aps"]}