{"version":3,"file":"components-modal.js","mappings":"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","sources":["webpack://silverstripe-base/./node_modules/a11y-dialog/dist/a11y-dialog.esm.js","webpack://silverstripe-base/./themes/app/src/scripts/components/modal.js"],"sourcesContent":["const not = {\n  inert: ':not([inert]):not([inert] *)',\n  negTabIndex: ':not([tabindex^=\"-\"])',\n  disabled: ':not(:disabled)',\n};\n\nvar focusableSelectors = [\n  `a[href]${not.inert}${not.negTabIndex}`,\n  `area[href]${not.inert}${not.negTabIndex}`,\n  `input:not([type=\"hidden\"]):not([type=\"radio\"])${not.inert}${not.negTabIndex}${not.disabled}`,\n  `input[type=\"radio\"]${not.inert}${not.negTabIndex}${not.disabled}`,\n  `select${not.inert}${not.negTabIndex}${not.disabled}`,\n  `textarea${not.inert}${not.negTabIndex}${not.disabled}`,\n  `button${not.inert}${not.negTabIndex}${not.disabled}`,\n  `details${not.inert} > summary:first-of-type${not.negTabIndex}`,\n  // Discard until Firefox supports `:has()`\n  // See: https://github.com/KittyGiraudel/focusable-selectors/issues/12\n  // `details:not(:has(> summary))${not.inert}${not.negTabIndex}`,\n  `iframe${not.inert}${not.negTabIndex}`,\n  `audio[controls]${not.inert}${not.negTabIndex}`,\n  `video[controls]${not.inert}${not.negTabIndex}`,\n  `[contenteditable]${not.inert}${not.negTabIndex}`,\n  `[tabindex]${not.inert}${not.negTabIndex}`,\n];\n\n/**\n * Set the focus to the first element with `autofocus` with the element or the\n * element itself.\n */\nfunction moveFocusToDialog(el) {\n    const focused = (el.querySelector('[autofocus]') || el);\n    focused.focus();\n}\n/**\n * Get the first and last focusable elements in a given tree.\n */\nfunction getFocusableEdges(el) {\n    // Check for a focusable element within the subtree of `el`.\n    const first = findFocusableElement(el, true);\n    // Only if we find the first element do we need to look for the last one. If\n    // there’s no last element, we set `last` as a reference to `first` so that\n    // the returned array is always of length 2.\n    const last = first ? findFocusableElement(el, false) || first : null;\n    return [first, last];\n}\n/**\n * Find the first focusable element inside the given node if `forward` is truthy\n * or the last focusable element otherwise.\n */\nfunction findFocusableElement(node, forward) {\n    // If we’re walking forward, check if this node is focusable, and return it\n    // immediately if it is.\n    if (forward && isFocusable(node))\n        return node;\n    // We should only search the subtree of this node if it can have focusable\n    // children.\n    if (canHaveFocusableChildren(node)) {\n        // Start walking the DOM tree, looking for focusable elements.\n        // Case 1: If this node has a shadow root, search it recursively.\n        if (node.shadowRoot) {\n            // Descend into this subtree.\n            let next = getNextChildEl(node.shadowRoot, forward);\n            // Traverse siblings, searching the subtree of each one\n            // for focusable elements.\n            while (next) {\n                const focusableEl = findFocusableElement(next, forward);\n                if (focusableEl)\n                    return focusableEl;\n                next = getNextSiblingEl(next, forward);\n            }\n        }\n        // Case 2: If this node is a slot for a Custom Element, search its assigned\n        // nodes recursively.\n        else if (node.localName === 'slot') {\n            const assignedElements = node.assignedElements({\n                flatten: true,\n            });\n            if (!forward)\n                assignedElements.reverse();\n            for (const assignedElement of assignedElements) {\n                const focusableEl = findFocusableElement(assignedElement, forward);\n                if (focusableEl)\n                    return focusableEl;\n            }\n        }\n        // Case 3: this is a regular Light DOM node. Search its subtree.\n        else {\n            // Descend into this subtree.\n            let next = getNextChildEl(node, forward);\n            // Traverse siblings, searching the subtree of each one\n            // for focusable elements.\n            while (next) {\n                const focusableEl = findFocusableElement(next, forward);\n                if (focusableEl)\n                    return focusableEl;\n                next = getNextSiblingEl(next, forward);\n            }\n        }\n    }\n    // If we’re walking backward, we want to check the node’s entire subtree\n    // before checking the node itself. If this node is focusable, return it.\n    if (!forward && isFocusable(node))\n        return node;\n    return null;\n}\nfunction getNextChildEl(node, forward) {\n    return forward ? node.firstElementChild : node.lastElementChild;\n}\nfunction getNextSiblingEl(el, forward) {\n    return forward ? el.nextElementSibling : el.previousElementSibling;\n}\n/**\n * Determine if an element is hidden from the user.\n */\nconst isHidden = (el) => {\n    // Browsers hide all non-<summary> descendants of closed <details> elements\n    // from user interaction, but those non-<summary> elements may still match our\n    // focusable-selectors and may still have dimensions, so we need a special\n    // case to ignore them.\n    if (el.matches('details:not([open]) *') &&\n        !el.matches('details>summary:first-of-type'))\n        return true;\n    // If this element has no painted dimensions, it's hidden.\n    return !(el.offsetWidth || el.offsetHeight || el.getClientRects().length);\n};\n/**\n * Determine if an element is focusable and has user-visible painted dimensions.\n */\nconst isFocusable = (el) => {\n    // A shadow host that delegates focus will never directly receive focus,\n    // even with `tabindex=0`. Consider our <fancy-button> custom element, which\n    // delegates focus to its shadow button:\n    //\n    // <fancy-button tabindex=\"0\">\n    //  #shadow-root\n    //  <button><slot></slot></button>\n    // </fancy-button>\n    //\n    // The browser acts as as if there is only one focusable element – the shadow\n    // button. Our library should behave the same way.\n    if (el.shadowRoot?.delegatesFocus)\n        return false;\n    return el.matches(focusableSelectors.join(',')) && !isHidden(el);\n};\n/**\n * Determine if an element can have focusable children. Useful for bailing out\n * early when walking the DOM tree.\n * @example\n * This div is inert, so none of its children can be focused, even though they\n * meet our criteria for what is focusable. Once we check the div, we can skip\n * the rest of the subtree.\n * ```html\n * <div inert>\n *   <button>Button</button>\n *   <a href=\"#\">Link</a>\n * </div>\n * ```\n */\nfunction canHaveFocusableChildren(el) {\n    // The browser will never send focus into a Shadow DOM if the host element\n    // has a negative tabindex. This applies to both slotted Light DOM Shadow DOM\n    // children\n    if (el.shadowRoot && el.getAttribute('tabindex') === '-1')\n        return false;\n    // Elemments matching this selector are either hidden entirely from the user,\n    // or are visible but unavailable for interaction. Their descentants can never\n    // receive focus.\n    return !el.matches(':disabled,[hidden],[inert]');\n}\n/**\n * Get the active element, accounting for Shadow DOM subtrees.\n * @author Cory LaViska\n * @see: https://www.abeautifulsite.net/posts/finding-the-active-element-in-a-shadow-root/\n */\nfunction getActiveElement(root = document) {\n    const activeEl = root.activeElement;\n    if (!activeEl)\n        return null;\n    // If there’s a shadow root, recursively find the active element within it.\n    // If the recursive call returns null, return the active element\n    // of the top-level Document.\n    if (activeEl.shadowRoot)\n        return getActiveElement(activeEl.shadowRoot) || document.activeElement;\n    // If not, we can just return the active element\n    return activeEl;\n}\n/**\n * Trap the focus inside the given element\n */\nfunction trapTabKey(el, event) {\n    const [firstFocusableChild, lastFocusableChild] = getFocusableEdges(el);\n    // If there are no focusable children in the dialog, prevent the user from\n    // tabbing out of it\n    if (!firstFocusableChild)\n        return event.preventDefault();\n    const activeElement = getActiveElement();\n    // If the SHIFT key is pressed while tabbing (moving backwards) and the\n    // currently focused item is the first one, move the focus to the last\n    // focusable item from the dialog element\n    if (event.shiftKey && activeElement === firstFocusableChild) {\n        // @ts-ignore: we know that `lastFocusableChild` is not null here\n        lastFocusableChild.focus();\n        event.preventDefault();\n    }\n    // If the SHIFT key is not pressed (moving forwards) and the currently focused\n    // item is the last one, move the focus to the first focusable item from the\n    // dialog element\n    else if (!event.shiftKey && activeElement === lastFocusableChild) {\n        firstFocusableChild.focus();\n        event.preventDefault();\n    }\n}\n\nclass A11yDialog {\n    $el;\n    id;\n    previouslyFocused;\n    shown;\n    constructor(element) {\n        this.$el = element;\n        this.id = this.$el.getAttribute('data-a11y-dialog') || this.$el.id;\n        this.previouslyFocused = null;\n        this.shown = false;\n        this.maintainFocus = this.maintainFocus.bind(this);\n        this.bindKeypress = this.bindKeypress.bind(this);\n        this.handleTriggerClicks = this.handleTriggerClicks.bind(this);\n        this.show = this.show.bind(this);\n        this.hide = this.hide.bind(this);\n        this.$el.setAttribute('aria-hidden', 'true');\n        this.$el.setAttribute('aria-modal', 'true');\n        this.$el.setAttribute('tabindex', '-1');\n        if (!this.$el.hasAttribute('role')) {\n            this.$el.setAttribute('role', 'dialog');\n        }\n        document.addEventListener('click', this.handleTriggerClicks, true);\n    }\n    /**\n     * Destroy the current instance (after making sure the dialog has been hidden)\n     * and remove all associated listeners from dialog openers and closers\n     */\n    destroy() {\n        // Hide the dialog to avoid destroying an open instance\n        this.hide();\n        // Remove the click event delegates for our openers and closers\n        document.removeEventListener('click', this.handleTriggerClicks, true);\n        // Clone and replace the dialog element to prevent memory leaks caused by\n        // event listeners that the author might not have cleaned up.\n        this.$el.replaceWith(this.$el.cloneNode(true));\n        // Dispatch a `destroy` event\n        this.fire('destroy');\n        return this;\n    }\n    /**\n     * Show the dialog element, trap the current focus within it, listen for some\n     * specific key presses and fire all registered callbacks for `show` event\n     */\n    show(event) {\n        // If the dialog is already open, abort\n        if (this.shown)\n            return this;\n        // Keep a reference to the currently focused element to be able to restore\n        // it later\n        this.shown = true;\n        this.$el.removeAttribute('aria-hidden');\n        this.previouslyFocused = getActiveElement();\n        // Due to a long lasting bug in Safari, clicking an interactive element\n        // (like a <button>) does *not* move the focus to that element, which means\n        // `document.activeElement` is whatever element is currently focused (like\n        // an <input>), or the <body> element otherwise. We can work around that\n        // problem by checking whether the focused element is the <body>, and if it,\n        // store the click event target.\n        // See: https://bugs.webkit.org/show_bug.cgi?id=22261\n        if (this.previouslyFocused?.tagName === 'BODY' && event?.target) {\n            this.previouslyFocused = event.target;\n        }\n        // Set the focus to the dialog element\n        // See: https://github.com/KittyGiraudel/a11y-dialog/pull/583\n        if (event?.type === 'focus') {\n            this.maintainFocus(event);\n        }\n        else {\n            moveFocusToDialog(this.$el);\n        }\n        // Bind a focus event listener to the body element to make sure the focus\n        // stays trapped inside the dialog while open, and start listening for some\n        // specific key presses (TAB and ESC)\n        document.body.addEventListener('focus', this.maintainFocus, true);\n        this.$el.addEventListener('keydown', this.bindKeypress, true);\n        // Dispatch a `show` event\n        this.fire('show', event);\n        return this;\n    }\n    /**\n     * Hide the dialog element, restore the focus to the previously active\n     * element, stop listening for some specific key presses and fire all\n     * registered callbacks for `hide` event\n     */\n    hide(event) {\n        // If the dialog is already closed, abort\n        if (!this.shown)\n            return this;\n        this.shown = false;\n        this.$el.setAttribute('aria-hidden', 'true');\n        this.previouslyFocused?.focus?.();\n        // Remove the focus event listener to the body element and stop listening\n        // for specific key presses\n        document.body.removeEventListener('focus', this.maintainFocus, true);\n        this.$el.removeEventListener('keydown', this.bindKeypress, true);\n        // Dispatch a `hide` event\n        this.fire('hide', event);\n        return this;\n    }\n    /**\n     * Register a new callback for the given event type\n     */\n    on(type, handler, options) {\n        this.$el.addEventListener(type, handler, options);\n        return this;\n    }\n    /**\n     * Unregister an existing callback for the given event type\n     */\n    off(type, handler, options) {\n        this.$el.removeEventListener(type, handler, options);\n        return this;\n    }\n    /**\n     * Dispatch a custom event from the DOM element associated with this dialog.\n     * This allows authors to listen for and respond to the events in their own\n     * code\n     */\n    fire(type, event) {\n        this.$el.dispatchEvent(new CustomEvent(type, {\n            detail: event,\n            cancelable: true,\n        }));\n    }\n    /**\n     * Add a delegated event listener for when elememts that open or close the\n     * dialog are clicked, and call `show` or `hide`, respectively\n     */\n    handleTriggerClicks(event) {\n        const target = event.target;\n        // We use `.closest(..)` and not `.matches(..)` here so that clicking\n        // an element nested within a dialog opener does cause the dialog to open\n        if (target.closest(`[data-a11y-dialog-show=\"${this.id}\"]`)) {\n            this.show(event);\n        }\n        if (target.closest(`[data-a11y-dialog-hide=\"${this.id}\"]`) ||\n            (target.closest('[data-a11y-dialog-hide]') &&\n                target.closest('[aria-modal=\"true\"]') === this.$el)) {\n            this.hide(event);\n        }\n    }\n    /**\n     * Private event handler used when listening to some specific key presses\n     * (namely ESC and TAB)\n     */\n    bindKeypress(event) {\n        // This is an escape hatch in case there are nested open dialogs, so that\n        // only the top most dialog gets interacted with\n        if (document.activeElement?.closest('[aria-modal=\"true\"]') !== this.$el) {\n            return;\n        }\n        let hasOpenPopover = false;\n        try {\n            hasOpenPopover = !!this.$el.querySelector('[popover]:not([popover=\"manual\"]):popover-open');\n        }\n        catch {\n            // Run that DOM query in a try/catch because not all browsers support the\n            // `:popover-open` selector, which would cause the whole expression to\n            // fail\n            // See: https://caniuse.com/mdn-css_selectors_popover-open\n            // See: https://github.com/KittyGiraudel/a11y-dialog/pull/578#discussion_r1343215149\n        }\n        // If the dialog is shown and the ESC key is pressed, prevent any further\n        // effects from the ESC key and hide the dialog, unless:\n        // - its role is `alertdialog`, which means it should be modal\n        // - or it contains an open popover, in which case ESC should close it\n        if (event.key === 'Escape' &&\n            this.$el.getAttribute('role') !== 'alertdialog' &&\n            !hasOpenPopover) {\n            event.preventDefault();\n            this.hide(event);\n        }\n        // If the dialog is shown and the TAB key is pressed, make sure the focus\n        // stays trapped within the dialog element\n        if (event.key === 'Tab') {\n            trapTabKey(this.$el, event);\n        }\n    }\n    /**\n     * If the dialog is shown and the focus is not within a dialog element (either\n     * this one or another one in case of nested dialogs) or attribute, move it\n     * back to the dialog container\n     * See: https://github.com/KittyGiraudel/a11y-dialog/issues/177\n     */\n    maintainFocus(event) {\n        const target = event.target;\n        if (!target.closest('[aria-modal=\"true\"], [data-a11y-dialog-ignore-focus-trap]')) {\n            moveFocusToDialog(this.$el);\n        }\n    }\n}\n\nfunction instantiateDialogs() {\n    for (const el of document.querySelectorAll('[data-a11y-dialog]')) {\n        new A11yDialog(el);\n    }\n}\nif (typeof document !== 'undefined') {\n    if (document.readyState === 'loading') {\n        document.addEventListener('DOMContentLoaded', instantiateDialogs);\n    }\n    else {\n        instantiateDialogs();\n    }\n}\n\nexport { A11yDialog as default };\n","import \"@styles/components/modal.css\";\nimport ajax from \"@common/ajax\";\nimport { on, off, fire } from \"delegated-events\";\nimport A11yDialog from \"a11y-dialog\";\n\nconst generateTemplate = (id, useDefaultClose = true, useCustomClose = false, title = false) => {\n  const role = useDefaultClose ? \"dialog\" : \"alertdialog\";\n  const labeledBy = title ? 'aria-labelledby=\"modal-title\"' : \"\";\n\n  const html = `\n    <div id=\"${id}\" aria-hidden=\"true\" class=\"modal-wrapper\" ${labeledBy} role=\"${role}\">\n      <div class=\"modal-overlay\" ${useDefaultClose && \"data-a11y-dialog-hide\"}></div>\n\n      ${\n        useCustomClose === false\n          ? '<button type=\"button\" class=\"modal-close\" data-a11y-dialog-hide aria-label=\"Close dialog\"> <svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"> <path fill=\"currentColor\" d=\"M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z\" /> </svg> </button>'\n          : \"\"\n      }\n\n      <div class=\"modal-container\">\n        <svg class=\"site-loader site-loader--centered site-loader--light\" viewBox=\"0 0 50 50\" aria-hidden=\"true\">\n          <circle class=\"path\" cx=\"25\" cy=\"25\" r=\"20\" fill=\"none\" stroke-width=\"5\"></circle>\n        </svg>\n      </div>\n    </div>\n  `;\n\n  return html;\n};\n\nconst populateModal = async (opts = {}, modalEl) => {\n  const type = opts.type;\n  const title = opts.title ?? \"\";\n  const url = opts.url;\n\n  let modalContent = \"\";\n\n  if (type === \"video\") {\n    modalContent = `\n      <div class=\"mx-auto w-full max-w-5xl modal-content\" role=\"document\">\n        <h1 id=\"modal-title\" class=\"sr-only\">Watch ${title}</h1>\n        <div class=\"relative aspect-video modal-body\">\n          <iframe title=\"Watch ${title}\" style=\"border: none\" src=\"${url}?autoplay=1&rel=0&enablejsapi=1\" allowfullscreen class=\"absolute inset-0 w-full h-full\"></iframe>\n        </div>\n      </div>\n    `;\n\n    modalEl.querySelector(\".modal-container\").innerHTML = modalContent;\n  }\n\n  if (type === \"content\") {\n    modalContent = await ajax.get(url).text();\n\n    modalEl.querySelector(\".modal-container\").innerHTML = modalContent;\n  }\n\n  if (type === \"subscribe\") {\n    modalContent = await ajax.get(url).text();\n\n    modalEl.querySelector(\".modal-container\").innerHTML = modalContent;\n  }\n\n  fire(document.documentElement, \"modal:populate\", { modalEl });\n};\n\nconst handleModal = (e) => {\n  e.preventDefault();\n\n  const triggerEl = e.target.closest(\"[data-modal]\");\n\n  openModal({\n    type: triggerEl.dataset.modal,\n    title: triggerEl.dataset.modalTitle,\n    url: triggerEl.href,\n    updateUrl: triggerEl.dataset.modalUpdateUrl ?? false,\n    useDefaultClose: triggerEl.dataset.modalDisableDefaultClose === undefined,\n    useCustomClose: triggerEl.dataset.modalUseCustomClose !== undefined,\n  });\n\n  return false;\n};\n\nconst handleModalReplace = async (e) => {\n  e.preventDefault();\n\n  const triggerEl = e.target.closest(\"[data-modal-replace]\");\n  const url = triggerEl.href;\n\n  const currentModal = document.querySelector(\".modal-wrapper\");\n\n  const modalContent = await ajax.get(url).text();\n\n  currentModal.querySelector(\".modal-container\").innerHTML = modalContent;\n};\n\nconst openModal = (opts = {}) => {\n  const type = opts.type;\n  const title = opts.title ?? false;\n  let useCustomClose = opts.useCustomClose ?? false;\n  let useDefaultClose = opts.useDefaultClose ?? true;\n\n  if (type === \"video\") {\n    useDefaultClose = false;\n  }\n\n  if (type === \"subscribe\") {\n    useDefaultClose = false;\n    useCustomClose = true;\n  }\n\n  const id = `modal-${Math.floor(Math.random() * Date.now())}`;\n  const template = generateTemplate(id, useDefaultClose, useCustomClose, title);\n  const node = document.createRange().createContextualFragment(template);\n\n  document.body.append(node);\n\n  const modalEl = document.getElementById(id);\n  const modal = new A11yDialog(modalEl);\n\n  const hideModal = () => {\n    modal.hide();\n  };\n\n  if (useCustomClose) {\n    on(\"click\", \".modal-custom-close\", hideModal);\n  }\n\n  const currentUrl = opts.defaultUrl ?? window.location.href;\n\n  modal.on(\"show\", () => {\n    document.documentElement.classList.add(\"has-modal-active\");\n\n    if (opts.updateUrl !== false) {\n      window.history.replaceState({}, \"\", opts.updateUrl);\n    }\n  });\n\n  modal.on(\"hide\", () => {\n    document.documentElement.classList.remove(\"has-modal-active\");\n\n    modal.destroy();\n\n    if (opts.updateUrl !== false) {\n      window.history.replaceState({}, \"\", currentUrl);\n    }\n\n    if (useCustomClose) {\n      off(\"click\", \".modal-custom-close\", hideModal);\n    }\n  });\n\n  modal.on(\"destroy\", (e) => {\n    document.querySelector(\".modal-wrapper\").remove();\n    e.target.remove();\n  });\n\n  modal.show();\n\n  populateModal(\n    {\n      type: type,\n      url: opts.url ?? false,\n      updateUrl: opts.updateUrl,\n      defaultUrl: opts.defaultUrl,\n    },\n    modalEl,\n  );\n};\n\nexport default {\n  init: () => {\n    const clickArgs = [\"click\", \"[data-modal]\", handleModal];\n    const replaceClickArgs = [\"click\", \"[data-modal-replace]\", handleModalReplace];\n\n    off(...clickArgs);\n    on(...clickArgs);\n\n    off(...replaceClickArgs);\n    on(...replaceClickArgs);\n\n    // If we have video modals, load the YouTube API\n    if (document.querySelectorAll('[data-modal=\"video\"]').length) {\n      const tag = document.createElement(\"script\");\n      tag.src = \"https://www.youtube.com/iframe_api\";\n\n      const firstScriptTag = document.getElementsByTagName(\"script\")[0];\n\n      firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);\n    }\n  },\n  openModal,\n};\n"],"names":["not","focusableSelectors","moveFocusToDialog","el","querySelector","focus","findFocusableElement","node","forward","isFocusable","shadowRoot","getAttribute","matches","next","getNextChildEl","focusableEl","getNextSiblingEl","localName","assignedElements","flatten","reverse","assignedElement","firstElementChild","lastElementChild","nextElementSibling","previousElementSibling","delegatesFocus","join","offsetWidth","offsetHeight","getClientRects","length","isHidden","getActiveElement","root","document","activeEl","activeElement","A11yDialog","$el","id","previouslyFocused","shown","constructor","element","this","maintainFocus","bind","bindKeypress","handleTriggerClicks","show","hide","setAttribute","hasAttribute","addEventListener","destroy","removeEventListener","replaceWith","cloneNode","fire","event","removeAttribute","tagName","target","type","body","on","handler","options","off","dispatchEvent","CustomEvent","detail","cancelable","closest","hasOpenPopover","key","preventDefault","firstFocusableChild","lastFocusableChild","first","getFocusableEdges","shiftKey","trapTabKey","instantiateDialogs","querySelectorAll","readyState","handleModal","e","triggerEl","openModal","dataset","modal","title","modalTitle","url","href","updateUrl","modalUpdateUrl","useDefaultClose","undefined","modalDisableDefaultClose","useCustomClose","modalUseCustomClose","handleModalReplace","async","currentModal","modalContent","ajax","get","text","innerHTML","opts","Math","floor","random","Date","now","template","generateTemplate","createRange","createContextualFragment","append","modalEl","getElementById","hideModal","currentUrl","defaultUrl","window","location","documentElement","classList","add","history","replaceState","remove","populateModal","init","clickArgs","replaceClickArgs","tag","createElement","src","firstScriptTag","getElementsByTagName","parentNode","insertBefore"],"sourceRoot":""}