{"version":3,"sources":["jsdelivr-header.js","/gh/flitsdigital/flits-digital@main/src/script.js"],"names":[],"mappings":"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","file":"/gh/flitsdigital/flits-digital@main/src/script.js","sourceRoot":"","sourcesContent":["/**\n * Minified by jsDelivr using Terser v5.39.0.\n * Original file: /gh/flitsdigital/flits-digital@main/src/script.js\n *\n * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files\n */\n","console.log(\"test\");\n\n// Initialize a new Lenis instance for smooth scrolling\nconst lenis = new Lenis();\n\n// Synchronize Lenis scrolling with GSAP's ScrollTrigger plugin\nlenis.on(\"scroll\", ScrollTrigger.update);\n\n// Add Lenis's requestAnimationFrame (raf) method to GSAP's ticker\n// This ensures Lenis's smooth scroll animation updates on each GSAP tick\ngsap.ticker.add((time) => {\n  lenis.raf(time * 1000); // Convert time from seconds to milliseconds\n});\n\n// Disable lag smoothing in GSAP to prevent any delay in scroll animations\ngsap.ticker.lagSmoothing(0);\n\nUnicornStudio.init()\n  .then((scenes) => {\n    // Scenes are ready\n  })\n  .catch((err) => {\n    console.error(err);\n  });\n\n$(\"section[data-theme]\").each(function () {\n  let theme = 1;\n  if ($(this).attr(\"data-theme\") === \"dark\") theme = 2;\n\n  ScrollTrigger.create({\n    trigger: $(this),\n    start: \"top 2%\",\n    end: \"bottom top\",\n    onToggle: ({ self, isActive }) => {\n      if (isActive)\n        gsap.to(\".navigatie\", { ...colorThemes[theme], duration: 0.3 });\n    },\n  });\n});\n\ngsap.registerPlugin(CustomEase, ScrollTrigger);\n\nCustomEase.create(\"main\", \"0.65, 0.01, 0.05, 0.99\");\n\ngsap.defaults({\n  ease: \"main\",\n  duration: 0.7,\n});\n\ninitMenu();\ninitModalBasic();\ninitScrollTriggerAnimations();\ninitAdvancedFormValidation();\ninitMarqueeScrollDirection();\n\n\nfunction initMenu() {\n  let navWrap = document.querySelector(\".navigatie_menu\");\n  let state = navWrap.getAttribute(\"data-nav\");\n  let overlay = navWrap.querySelector(\".overlay\");\n  let menu = navWrap.querySelector(\".menu\");\n  let bg = navWrap.querySelector(\".menu_bg\");\n  let menuLinks = navWrap.querySelectorAll(\".menu_link\");\n  let fadeTargets = navWrap.querySelector(\".menu_details\");\n\n  let menuToggles = document.querySelectorAll(\"[data-menu-toggle]\");\n  let menuButton = document.querySelector(\".navigatie_button-wrap\");\n  let firstMenuIcon = menuButton.querySelector(\".navigatie_button-icon-1\");\n  let secondMenuIcon = menuButton.querySelector(\".navigatie_button-icon-2\");\n\n  let navLinks = document.querySelectorAll(\".nav_link\");\n\n  let tl = gsap.timeline();\n\n  const openNav = () => {\n    navWrap.setAttribute(\"data-nav\", \"open\");\n\n    tl.clear()\n      .set(navWrap, { display: \"block\" })\n      .set(menu, { xPercent: 0 }, \"<\")\n      .fromTo(firstMenuIcon, { y: \"0rem\" }, { y: \"-2rem\", duration: 0.4 })\n      .fromTo(secondMenuIcon, { y: \"2rem\" }, { y: \"0rem\", duration: 0.5 }, \"<\")\n      .fromTo(\n        navLinks,\n        { y: \"0rem\" },\n        { y: \"-1.5rem\", stagger: 0.1, duration: 0.3 },\n        \"<\"\n      )\n      .fromTo(overlay, { autoAlpha: 0 }, { autoAlpha: 1 }, \"<\")\n      .fromTo(\n        bg,\n        { xPercent: -120 },\n        { xPercent: 0, stagger: 0.12, duration: 0.575 },\n        \"<\"\n      )\n      .fromTo(menuLinks, { yPercent: 140 }, { yPercent: 0, stagger: 0.1 }, \"<\")\n      .fromTo(\n        fadeTargets,\n        { autoAlpha: 0, yPercent: 50 },\n        {\n          autoAlpha: 1,\n          yPercent: 0,\n          duration: 0.5,\n        },\n        \"<+=0.2\"\n      );\n  };\n\n  const closeNav = () => {\n    navWrap.setAttribute(\"data-nav\", \"closed\");\n\n    tl.clear()\n      .to(overlay, { autoAlpha: 0 })\n      .to(menu, { xPercent: -120 }, \"<\")\n      .to(firstMenuIcon, { y: \"0rem\" }, \"<\")\n      .to(secondMenuIcon, { y: \"2rem\" }, \"<\")\n      .to(navLinks, { y: \"0rem\", stagger: 0.1, duration: 0.5 }, \"<\")\n      .set(navWrap, { display: \"none\" });\n  };\n\n  // Toggle menu open / close depending on its current state\n  menuToggles.forEach((toggle) => {\n    toggle.addEventListener(\"click\", () => {\n      state = navWrap.getAttribute(\"data-nav\");\n      if (state === \"open\") {\n        closeNav();\n      } else {\n        openNav();\n      }\n    });\n  });\n\n  menuLinks.forEach((link) => {\n    link.addEventListener(\"click\", () => {\n      closeNav();\n    });\n  });\n\n  // If menu is open, you can close it using the \"escape\" key\n  document.addEventListener(\"keydown\", (e) => {\n    if (e.key === \"Escape\" && navWrap.getAttribute(\"data-nav\") === \"open\") {\n      closeNav();\n    }\n  });\n}\n\nfunction initModalBasic() {\n  const modalGroup = document.querySelector(\"[data-modal-group-status]\");\n  const modals = document.querySelectorAll(\"[data-modal-name]\");\n  const modalTargets = document.querySelectorAll(\"[data-modal-target]\");\n  const isMobile = window.innerWidth <= 768;\n\n  // Open modal\n  modalTargets.forEach((modalTarget) => {\n    modalTarget.addEventListener(\"click\", function () {\n      if (!isMobile) lenis.stop();\n      const modalTargetName = this.getAttribute(\"data-modal-target\");\n\n      // Close all modals\n      modalTargets.forEach((target) =>\n        target.setAttribute(\"data-modal-status\", \"not-active\")\n      );\n      modals.forEach((modal) =>\n        modal.setAttribute(\"data-modal-status\", \"not-active\")\n      );\n\n      // Activate clicked modal\n      document\n        .querySelector(`[data-modal-target=\"${modalTargetName}\"]`)\n        .setAttribute(\"data-modal-status\", \"active\");\n      document\n        .querySelector(`[data-modal-name=\"${modalTargetName}\"]`)\n        .setAttribute(\"data-modal-status\", \"active\");\n\n      // Set group to active\n      if (modalGroup) {\n        modalGroup.setAttribute(\"data-modal-group-status\", \"active\");\n      }\n    });\n  });\n\n  // Close modal\n  document.querySelectorAll(\"[data-modal-close]\").forEach((closeBtn) => {\n    closeBtn.addEventListener(\"click\", closeAllModals);\n  });\n\n  // Close modal on `Escape` key\n  document.addEventListener(\"keydown\", function (event) {\n    if (event.key === \"Escape\") {\n      closeAllModals();\n    }\n  });\n\n  // Function to close all modals\n  function closeAllModals() {\n    modalTargets.forEach((target) =>\n      target.setAttribute(\"data-modal-status\", \"not-active\")\n    );\n\n    if (modalGroup) {\n      modalGroup.setAttribute(\"data-modal-group-status\", \"not-active\");\n    }\n    if (!isMobile) lenis.start();\n  }\n}\n\nfunction initAdvancedFormValidation() {\n  const forms = document.querySelectorAll(\"[data-form-validate]\");\n\n  forms.forEach((formContainer) => {\n    const startTime = new Date().getTime();\n\n    const form = formContainer.querySelector(\"form\");\n    if (!form) {\n      console.log(\"no form\");\n      return;\n    }\n\n    const validateFields = form.querySelectorAll(\"[data-validate]\");\n    const dataSubmit = form.querySelector(\"[data-submit]\");\n    if (!dataSubmit) return;\n\n    const realSubmitInput = dataSubmit.querySelector('input[type=\"submit\"]');\n    if (!realSubmitInput) return;\n\n    function isSpam() {\n      const currentTime = new Date().getTime();\n      return currentTime - startTime < 5000;\n    }\n\n    // Disable select options with invalid values on page load\n    validateFields.forEach(function (fieldGroup) {\n      const select = fieldGroup.querySelector(\"select\");\n      if (select) {\n        const options = select.querySelectorAll(\"option\");\n        options.forEach(function (option) {\n          if (\n            option.value === \"\" ||\n            option.value === \"disabled\" ||\n            option.value === \"null\" ||\n            option.value === \"false\"\n          ) {\n            option.setAttribute(\"disabled\", \"disabled\");\n          }\n        });\n      }\n    });\n\n    function validateAndStartLiveValidationForAll() {\n      let allValid = true;\n      let firstInvalidField = null;\n\n      validateFields.forEach(function (fieldGroup) {\n        const input = fieldGroup.querySelector(\"input, textarea, select\");\n        const radioCheckGroup = fieldGroup.querySelector(\n          \"[data-radiocheck-group]\"\n        );\n        if (!input && !radioCheckGroup) return;\n\n        if (input) input.__validationStarted = true;\n        if (radioCheckGroup) {\n          radioCheckGroup.__validationStarted = true;\n          const inputs = radioCheckGroup.querySelectorAll(\n            'input[type=\"radio\"], input[type=\"checkbox\"]'\n          );\n          inputs.forEach(function (input) {\n            input.__validationStarted = true;\n          });\n        }\n\n        updateFieldStatus(fieldGroup);\n\n        if (!isValid(fieldGroup)) {\n          allValid = false;\n          if (!firstInvalidField) {\n            firstInvalidField = input || radioCheckGroup.querySelector(\"input\");\n          }\n        }\n      });\n\n      if (!allValid && firstInvalidField) {\n        firstInvalidField.focus();\n      }\n\n      return allValid;\n    }\n\n    function isValid(fieldGroup) {\n      const radioCheckGroup = fieldGroup.querySelector(\n        \"[data-radiocheck-group]\"\n      );\n      if (radioCheckGroup) {\n        const inputs = radioCheckGroup.querySelectorAll(\n          'input[type=\"radio\"], input[type=\"checkbox\"]'\n        );\n        const checkedInputs = radioCheckGroup.querySelectorAll(\"input:checked\");\n        const min = parseInt(radioCheckGroup.getAttribute(\"min\")) || 1;\n        const max =\n          parseInt(radioCheckGroup.getAttribute(\"max\")) || inputs.length;\n        const checkedCount = checkedInputs.length;\n\n        if (inputs[0].type === \"radio\") {\n          return checkedCount >= 1;\n        } else {\n          if (inputs.length === 1) {\n            return inputs[0].checked;\n          } else {\n            return checkedCount >= min && checkedCount <= max;\n          }\n        }\n      } else {\n        const input = fieldGroup.querySelector(\"input, textarea, select\");\n        if (!input) return false;\n\n        let valid = true;\n        const min = parseInt(input.getAttribute(\"min\")) || 0;\n        const max = parseInt(input.getAttribute(\"max\")) || Infinity;\n        const value = input.value.trim();\n        const length = value.length;\n\n        if (input.tagName.toLowerCase() === \"select\") {\n          if (\n            value === \"\" ||\n            value === \"disabled\" ||\n            value === \"null\" ||\n            value === \"false\"\n          ) {\n            valid = false;\n          }\n        } else if (input.type === \"email\") {\n          const emailPattern = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n          valid = emailPattern.test(value);\n        } else {\n          if (input.hasAttribute(\"min\") && length < min) valid = false;\n          if (input.hasAttribute(\"max\") && length > max) valid = false;\n        }\n\n        return valid;\n      }\n    }\n\n    function updateFieldStatus(fieldGroup) {\n      const radioCheckGroup = fieldGroup.querySelector(\n        \"[data-radiocheck-group]\"\n      );\n      if (radioCheckGroup) {\n        const inputs = radioCheckGroup.querySelectorAll(\n          'input[type=\"radio\"], input[type=\"checkbox\"]'\n        );\n        const checkedInputs = radioCheckGroup.querySelectorAll(\"input:checked\");\n\n        if (checkedInputs.length > 0) {\n          fieldGroup.classList.add(\"is--filled\");\n        } else {\n          fieldGroup.classList.remove(\"is--filled\");\n        }\n\n        const valid = isValid(fieldGroup);\n\n        if (valid) {\n          fieldGroup.classList.add(\"is--success\");\n          fieldGroup.classList.remove(\"is--error\");\n        } else {\n          fieldGroup.classList.remove(\"is--success\");\n          const anyInputValidationStarted = Array.from(inputs).some(\n            (input) => input.__validationStarted\n          );\n          if (anyInputValidationStarted) {\n            fieldGroup.classList.add(\"is--error\");\n          } else {\n            fieldGroup.classList.remove(\"is--error\");\n          }\n        }\n      } else {\n        const input = fieldGroup.querySelector(\"input, textarea, select\");\n        if (!input) return;\n\n        const value = input.value.trim();\n\n        if (value) {\n          fieldGroup.classList.add(\"is--filled\");\n        } else {\n          fieldGroup.classList.remove(\"is--filled\");\n        }\n\n        const valid = isValid(fieldGroup);\n\n        if (valid) {\n          fieldGroup.classList.add(\"is--success\");\n          fieldGroup.classList.remove(\"is--error\");\n        } else {\n          fieldGroup.classList.remove(\"is--success\");\n          if (input.__validationStarted) {\n            fieldGroup.classList.add(\"is--error\");\n          } else {\n            fieldGroup.classList.remove(\"is--error\");\n          }\n        }\n      }\n    }\n\n    validateFields.forEach(function (fieldGroup) {\n      const input = fieldGroup.querySelector(\"input, textarea, select\");\n      const radioCheckGroup = fieldGroup.querySelector(\n        \"[data-radiocheck-group]\"\n      );\n\n      if (radioCheckGroup) {\n        const inputs = radioCheckGroup.querySelectorAll(\n          'input[type=\"radio\"], input[type=\"checkbox\"]'\n        );\n        inputs.forEach(function (input) {\n          input.__validationStarted = false;\n\n          input.addEventListener(\"change\", function () {\n            requestAnimationFrame(function () {\n              if (!input.__validationStarted) {\n                const checkedCount =\n                  radioCheckGroup.querySelectorAll(\"input:checked\").length;\n                const min = parseInt(radioCheckGroup.getAttribute(\"min\")) || 1;\n\n                if (checkedCount >= min) {\n                  input.__validationStarted = true;\n                }\n              }\n\n              if (input.__validationStarted) {\n                updateFieldStatus(fieldGroup);\n              }\n            });\n          });\n\n          input.addEventListener(\"blur\", function () {\n            input.__validationStarted = true;\n            updateFieldStatus(fieldGroup);\n          });\n        });\n      } else if (input) {\n        input.__validationStarted = false;\n\n        if (input.tagName.toLowerCase() === \"select\") {\n          input.addEventListener(\"change\", function () {\n            input.__validationStarted = true;\n            updateFieldStatus(fieldGroup);\n          });\n        } else {\n          input.addEventListener(\"input\", function () {\n            const value = input.value.trim();\n            const length = value.length;\n            const min = parseInt(input.getAttribute(\"min\")) || 0;\n            const max = parseInt(input.getAttribute(\"max\")) || Infinity;\n\n            if (!input.__validationStarted) {\n              if (input.type === \"email\") {\n                if (isValid(fieldGroup)) input.__validationStarted = true;\n              } else {\n                if (\n                  (input.hasAttribute(\"min\") && length >= min) ||\n                  (input.hasAttribute(\"max\") && length <= max)\n                ) {\n                  input.__validationStarted = true;\n                }\n              }\n            }\n\n            if (input.__validationStarted) {\n              updateFieldStatus(fieldGroup);\n            }\n          });\n\n          input.addEventListener(\"blur\", function () {\n            input.__validationStarted = true;\n            updateFieldStatus(fieldGroup);\n          });\n        }\n      }\n    });\n\n    dataSubmit.addEventListener(\"click\", function () {\n      if (validateAndStartLiveValidationForAll()) {\n        if (isSpam()) {\n          alert(\"Form submitted too quickly. Please try again.\");\n          return;\n        }\n        realSubmitInput.click();\n      }\n    });\n\n    form.addEventListener(\"keydown\", function (event) {\n      if (event.key === \"Enter\" && event.target.tagName !== \"TEXTAREA\") {\n        event.preventDefault();\n        if (validateAndStartLiveValidationForAll()) {\n          if (isSpam()) {\n            alert(\"Form submitted too quickly. Please try again.\");\n            return;\n          }\n          realSubmitInput.click();\n        }\n      }\n    });\n  });\n}\n\nfunction initScrollTriggerAnimations() {\n  // Home Hero\n  if (document.querySelector(\".hero\")) {\n    $(\".hero\").each(function (index) {\n      let triggerElement = $(this);\n      let targetElement = $(this).find(\".hero_header\");\n\n      let tl = gsap.timeline({\n        scrollTrigger: {\n          trigger: triggerElement,\n          start: \"0% 0%\",\n          end: \"100% 0%\",\n          scrub: 1,\n          markers: false,\n        },\n      });\n\n      tl.to(targetElement, {\n        ease: \"none\",\n        yPercent: -50,\n      });\n    });\n  }\n\n  // Cases Horizontal scroll\n\n  $(\".cases_3image-slider\").each(function () {\n    console.log(\"test\");\n    let triggerElement = $(this);\n    let targetElement = $(this).find(\"._3image-slider_wrap\");\n\n    let tl = gsap.timeline({\n      scrollTrigger: {\n        trigger: triggerElement,\n        start: \"top bottom\",\n        end: \"bottom top\",\n        scrub: 1,\n        markers: false,\n      },\n    });\n\n    tl.fromTo(\n      targetElement,\n      {\n        x: \"-20%\",\n      },\n      {\n        x: \"20%\",\n        ease: \"none\",\n      }\n    );\n  });\n}\n\nlet flitsPath = $(\".footer_svg\").find(\"path\");\nconsole.log(flitsPath);\n\ngsap.from(flitsPath, {\n  scrollTrigger: {\n    trigger: \".footer\",\n    start: \"top 50%\",\n    end: \"bottom bottom\",\n  },\n  yPercent: 100,\n  stagger: 0.2,\n  ease: \"main\",\n  duration: 0.7,\n});\n\nfunction updateTime() {\n  // Maak een nieuwe datum gebaseerd op de Nederlandse tijd\n  const now = new Date().toLocaleTimeString(\"nl-NL\", {\n    hour: \"2-digit\",\n    minute: \"2-digit\",\n    second: \"2-digit\",\n    timeZone: \"Europe/Amsterdam\",\n  });\n\n  // Pak het element met ID 'currentTime'\n  const currentTimeElement = document.getElementById(\"currentTime\");\n  if (currentTimeElement) {\n    // Update de inhoud van het element met de huidige tijd\n    currentTimeElement.textContent = now;\n  }\n}\n\nfunction initMarqueeScrollDirection() {\n  document\n    .querySelectorAll(\"[data-marquee-scroll-direction-target]\")\n    .forEach((marquee) => {\n      // Query marquee elements\n      const marqueeContent = marquee.querySelector(\n        \"[data-marquee-collection-target]\"\n      );\n      const marqueeScroll = marquee.querySelector(\n        \"[data-marquee-scroll-target]\"\n      );\n      if (!marqueeContent || !marqueeScroll) return;\n\n      // Get data attributes\n      const {\n        marqueeSpeed: speed,\n        marqueeDirection: direction,\n        marqueeDuplicate: duplicate,\n        marqueeScrollSpeed: scrollSpeed,\n      } = marquee.dataset;\n\n      // Convert data attributes to usable types\n      const marqueeSpeedAttr = parseFloat(speed);\n      const marqueeDirectionAttr = direction === \"right\" ? 1 : -1; // 1 for right, -1 for left\n      const duplicateAmount = parseInt(duplicate || 0);\n      const scrollSpeedAttr = parseFloat(scrollSpeed);\n      const speedMultiplier =\n        window.innerWidth < 479 ? 0.25 : window.innerWidth < 991 ? 0.5 : 1;\n\n      let marqueeSpeed =\n        marqueeSpeedAttr *\n        (marqueeContent.offsetWidth / window.innerWidth) *\n        speedMultiplier;\n\n      // Precompute styles for the scroll container\n      marqueeScroll.style.marginLeft = `${scrollSpeedAttr * -1}%`;\n      marqueeScroll.style.width = `${scrollSpeedAttr * 2 + 100}%`;\n\n      // Duplicate marquee content\n      if (duplicateAmount > 0) {\n        const fragment = document.createDocumentFragment();\n        for (let i = 0; i < duplicateAmount; i++) {\n          fragment.appendChild(marqueeContent.cloneNode(true));\n        }\n        marqueeScroll.appendChild(fragment);\n      }\n\n      // GSAP animation for marquee content\n      const marqueeItems = marquee.querySelectorAll(\n        \"[data-marquee-collection-target]\"\n      );\n      const animation = gsap\n        .to(marqueeItems, {\n          xPercent: -100, // Move completely out of view\n          repeat: -1,\n          duration: marqueeSpeed,\n          ease: \"linear\",\n        })\n        .totalProgress(0.5);\n\n      // Initialize marquee in the correct direction\n      gsap.set(marqueeItems, {\n        xPercent: marqueeDirectionAttr === 1 ? 100 : -100,\n      });\n      animation.timeScale(marqueeDirectionAttr); // Set correct direction\n      animation.play(); // Start animation immediately\n\n      // Set initial marquee status\n      marquee.setAttribute(\"data-marquee-status\", \"normal\");\n\n      // ScrollTrigger logic for direction inversion\n      ScrollTrigger.create({\n        trigger: marquee,\n        start: \"top bottom\",\n        end: \"bottom top\",\n        onUpdate: (self) => {\n          const isInverted = self.direction === 1; // Scrolling down\n          const currentDirection = isInverted\n            ? -marqueeDirectionAttr\n            : marqueeDirectionAttr;\n\n          // Update animation direction and marquee status\n          animation.timeScale(currentDirection);\n          marquee.setAttribute(\n            \"data-marquee-status\",\n            isInverted ? \"normal\" : \"inverted\"\n          );\n        },\n      });\n\n      // Extra speed effect on scroll\n      const tl = gsap.timeline({\n        scrollTrigger: {\n          trigger: marquee,\n          start: \"0% 100%\",\n          end: \"100% 0%\",\n          scrub: 0,\n        },\n      });\n\n      const scrollStart =\n        marqueeDirectionAttr === -1 ? scrollSpeedAttr : -scrollSpeedAttr;\n      const scrollEnd = -scrollStart;\n\n      tl.fromTo(\n        marqueeScroll,\n        { x: `${scrollStart}vw` },\n        { x: `${scrollEnd}vw`, ease: \"none\" }\n      );\n    });\n}\n\n// Roep de functie meteen aan om de tijd direct te tonen\nupdateTime();\n\n// Update de tijd elke seconde\nsetInterval(updateTime, 1000);\n\n// ------------------- DIENSTEN PAGINA ------------------- //\n\nconst casesSwiper = new Swiper(\".swiper.is-cases\", {\n  // Optional parameters\n  direction: \"horizontal\",\n  grabCursor: true,\n  slidesPerView: 2,\n  spaceBetween: 8,\n  // breakpoints: {\n  //   // when window width is >= 320px\n  //   320: {\n  //     slidesPerView: 1,\n  //     spaceBetween: 8\n  //   },\n  //   // when window width is >= 480px\n  //   480: {\n  //     slidesPerView: 1,\n  //     spaceBetween: 8\n  //   },\n  //   // when window width is >= 640px\n  //   640: {\n  //     slidesPerView: 2,\n  //     spaceBetween: 16\n  //   }\n  // },\n});\n\nconst reviewsSwiper = new Swiper(\".swiper.is-reviews\", {\n  direction: \"horizontal\",\n  grabCursor: true,\n  loop: true,\n\n  autoplay: {\n    delay: 5000,\n  },\n  breakpoints: {\n    768: {\n      slidesPerView: 1,\n      spaceBetween: 16,\n    },\n    1024: {\n      slidesPerView: 3,\n      spaceBetween: 16,\n    },\n  },\n});\n"]}