PageSourceSearch

https://www.ricekrispies.us/scripts/aem.js

js ricekrispies.us collected 2026-09-25 02:42:56 UTC 48,628 bytes, 1,258 lines download raw bytes

1/*
2 * Copyright 2024 Adobe. All rights reserved.
3 * This file is licensed to you under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License. You may obtain a copy
5 * of the License at http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software distributed under
8 * the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
9 * OF ANY KIND, either express or implied. See the License for the specific language
10 * governing permissions and limitations under the License.
11 */
12
13/* eslint-env browser */
14
15/**
16 * log RUM if part of the sample.
17 * @param {string} checkpoint identifies the checkpoint in funnel
18 * @param {Object} data additional data for RUM sample
19 * @param {string} data.source DOM node that is the source of a checkpoint event,
20 * identified by #id or .classname
21 * @param {string} data.target subject of the checkpoint event,
22 * for instance the href of a link, or a search term
23 */
24function sampleRUM(checkpoint, data = {}) {
25  const SESSION_STORAGE_KEY = 'aem-rum';
26  sampleRUM.baseURL = sampleRUM.baseURL
27    || new URL(window.RUM_BASE == null ? 'https://rum.hlx.page' : window.RUM_BASE, window.location);
28  sampleRUM.defer = sampleRUM.defer || [];
29  const defer = (fnname) => {
30    sampleRUM[fnname] = sampleRUM[fnname] || ((...args) => sampleRUM.defer.push({ fnname, args }));
31  };
32  sampleRUM.drain = sampleRUM.drain
33    || ((dfnname, fn) => {
34      sampleRUM[dfnname] = fn;
35      sampleRUM.defer
36        .filter(({ fnname }) => dfnname === fnname)
37        .forEach(({ fnname, args }) => sampleRUM[fnname](...args));
38    });
39  sampleRUM.always = sampleRUM.always || [];
40  sampleRUM.always.on = (chkpnt, fn) => {
41    sampleRUM.always[chkpnt] = fn;
42  };
43  sampleRUM.on = (chkpnt, fn) => {
44    sampleRUM.cases[chkpnt] = fn;
45  };
46  defer('observe');
47  defer('cwv');
48  try {
49    window.hlx = window.hlx || {};
50    if (!window.hlx.rum) {
51      const usp = new URLSearchParams(window.location.search);
52      const weight = usp.get('rum') === 'on' ? 1 : 100; // with parameter, weight is 1. Defaults to 100.
53      const id = Array.from({ length: 75 }, (_, i) => String.fromCharCode(48 + i))
54        .filter((a) => /\d|[A-Z]/i.test(a))
55        .filter(() => Math.random() * 75 > 70)
56        .join('');
57      const random = Math.random();
58      const isSelected = random * weight < 1;
59      const firstReadTime = window.performance ? window.performance.timeOrigin : Date.now();
60      const urlSanitizers = {
61        full: () => window.location.href,
62        origin: () => window.location.origin,
63        path: () => window.location.href.replace(/\?.*$/, ''),
64      };
65      // eslint-disable-next-line max-len
66      const rumSessionStorage = sessionStorage.getItem(SESSION_STORAGE_KEY)
67        ? JSON.parse(sessionStorage.getItem(SESSION_STORAGE_KEY))
68        : {};
69      // eslint-disable-next-line max-len
70      rumSessionStorage.pages = (rumSessionStorage.pages ? rumSessionStorage.pages : 0)
71        + 1
72        /* noise */ + (Math.floor(Math.random() * 20) - 10);
73      sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(rumSessionStorage));
74      // eslint-disable-next-line object-curly-newline, max-len
75      window.hlx.rum = {
76        weight,
77        id,
78        random,
79        isSelected,
80        firstReadTime,
81        sampleRUM,
82        sanitizeURL: urlSanitizers[window.hlx.RUM_MASK_URL || 'path'],
83        rumSessionStorage,
84      };
85    }
86
87    const { weight, id, firstReadTime } = window.hlx.rum;
88    if (window.hlx && window.hlx.rum && window.hlx.rum.isSelected) {
89      const knownProperties = [
90        'weight',
91        'id',
92        'referer',
93        'checkpoint',
94        't',
95        'source',
96        'target',
97        'cwv',
98        'CLS',
99        'FID',
100        'LCP',
101        'INP',
102        'TTFB',
103      ];
104      const sendPing = (pdata = data) => {
105        // eslint-disable-next-line max-len
106        const t = Math.round(
107          window.performance ? window.performance.now() : Date.now() - firstReadTime,
108        );
109        // eslint-disable-next-line object-curly-newline, max-len, no-u
109se-before-define
110        const body = JSON.stringify(
111          {
112            weight, id, referer: window.hlx.rum.sanitizeURL(), checkpoint, t, ...data,
113          },
114          knownProperties,
115        );
116        const url = new URL(`.rum/${weight}`, sampleRUM.baseURL).href;
117        navigator.sendBeacon(url, body);
118        // eslint-disable-next-line no-console
119        console.debug(`ping:${checkpoint}`, pdata);
120      };
121      sampleRUM.cases = sampleRUM.cases || {
122        load: () => sampleRUM('pagesviewed', { source: window.hlx.rum.rumSessionStorage.pages }) || true,
123        cwv: () => sampleRUM.cwv(data) || true,
124        lazy: () => {
125          // use classic script to avoid CORS issues
126          const script = document.createElement('script');
127          script.src = new URL(
128            '.rum/@adobe/helix-rum-enhancer@^1/src/index.js',
129            sampleRUM.baseURL,
130          ).href;
131          document.head.appendChild(script);
132          return true;
133        },
134      };
135      sendPing(data);
136      if (sampleRUM.cases[checkpoint]) {
137        sampleRUM.cases[checkpoint]();
138      }
139    }
140    if (sampleRUM.always[checkpoint]) {
141      sampleRUM.always[checkpoint](data);
142    }
143  } catch (error) {
144    // something went wrong
145  }
146}
147
148/**
149 * Setup block utils.
150 */
151function setup() {
152  window.hlx = window.hlx || {};
153  window.hlx.RUM_MASK_URL = 'full';
154  window.hlx.codeBasePath = '';
155  window.hlx.lighthouse = new URLSearchParams(window.location.search).get('lighthouse') === 'on';
156
157  const scriptEl = document.querySelector('script[src$="/scripts/scripts.js"]');
158  if (scriptEl) {
159    try {
160      const scriptURL = new URL(scriptEl.src, window.location);
161      if (scriptURL.host === window.location.host) {
162        [window.hlx.codeBasePath] = scriptURL.pathname.split('/scripts/scripts.js');
163      } else {
164        [window.hlx.codeBasePath] = scriptURL.href.split('/scripts/scripts.js');
165      }
166    } catch (error) {
167      // eslint-disable-next-line no-console
168      console.log(error);
169    }
170  }
171}
172
173/**
174 * Sets attributes for created document elements
175 * @param {HTMLElement} el element that needs attributes
176 * @param {object} attrs attributes to set on element
177 */
178function setAttributes(el, attrs) {
179  Object.keys(attrs).forEach((attr) => {
180    el.setAttribute(attr, attrs[attr]);
181  });
182}
183
184/**
185 * Helper function to create multiple elements
186 * @param {string} el element type to be created
187 * @param {object} props attributes to set on element
188 * @param {string} text innerHTML text to add to new element
189 */
190const generateElement = (type, props, text) => {
191  const el = document.createElement(type);
192  setAttributes(el, props);
193  el.innerHTML = text;
194  return el;
195};
196
197/**
198  * Helper functions for creating Schema on product detail and recipe detail blocks
199*/
200const stripHtmlTags = (value) => {
201  if (!value) {
202    return '';
203  }
204  const container = document.createElement('div');
205  container.innerHTML = String(value);
206  return container.textContent || container.innerText || '';
207};
208const normalizeText = (value) => stripHtmlTags(value).replace(/\s+/g, ' ').trim();
209
210/**
211  * Gets site locale on page load
212*/
213const getLocale = () => {
214  let locale = '';
215  const { pathname } = window.location;
216  const { hostname } = window.location;
217  const pathSplit = pathname.split('/').filter((path) => path);
218  if (hostname.includes('localhost')) {
219    locale = 'en_US';
220    return locale;
221  }
222  if (hostname.includes('live')) {
223    if (hostname.includes('-ca-') && pathSplit[0].includes('en')) {
224      locale = 'en_CA';
225      return locale;
226    }
227    if (hostname.includes('-ca-') && pathSplit.includes('fr')) {
228      locale = 'fr_CA';
229      return locale;
230    }
231    if (pathSplit.includes('es')) {
232      locale = 'es_US';
233      return locale;
234    }
235    locale = 'en_US';
236    return locale;
237  }
238  if (hostname.includes('.ca') && pathSplit.includes('en')) {
239    locale = 'en_CA';
240    return locale;
241  }
242  if (pathSplit.includes('fr')) {
243    locale = 'fr_CA';
244    return locale;
245  }
246  if (pathSplit.includes('es')) {
247    locale = 'es_US';
248    return locale;
249  }
250  locale = 'en_US';
251  return locale;
252};
253
254/**
255  * Get brand from window.location.origin on page load
256*/
257const getBrand = () => {
258  let brand = '';
259  const { hostname } = window.location;
260  if (hostname.includes('localhost')) {
261    brand = 'wkkc';
262    return brand;
263  }
264  if (hostname.includes('ricekrispies')) {
265    brand = 'Rice Krispies';
266    return brand;
267  }
268  if (hostname.includes('frostedflakes')) {
269    brand = 'Frosted Flakes';
270    return brand;
271  }
272  if (hostname.includes('specialk')) {
273    brand = 'special-k';
274    return brand;
275  }
276  if (hostname.includes('kashi')) {
277    brand = 'kashi';
278    return brand;
279  }
280  if (hostname.includes('wkkelloggawayfromhome') || hostname.includes('away-from-home')) {
281    brand = 'away-from-home';
282    return brand;
283  }
284  if (hostname.includes('bear-naked') || hostname.includes('bearnaked')) {
285    brand = 'bear-naked';
286    return brand;
287  }
288  brand = 'wkkc';
289  return brand;
290};
291
292/**
293 * Removes all non-alphanumeric characters
294 * @param {string} alphaInput the string to strip
295 */
296function removeNonAlphabetChars(alphaInput) {
297  const cleanString = alphaInput?.replace(/[^A-Za-züé -]/g, '').toLowerCase();
298  return cleanString;
299}
300
301function removeNonAlphabetCharsEpsilon(alphaInput) {
302  const cleanString = alphaInput?.replace(/[^A-Za-züé -]/g, '');
303  return cleanString;
304}
305
306/**
307 * Removes 'Kelloggs' and 'cereal' from string
308 * @param {string} removeInput the string that needs removal
309 */
310function removeKelloggs(removeInput) {
311  const cleanName = removeInput.replace('kelloggs', '').replace('cereal', '').toLowerCase().trim();
312  return cleanName;
313}
314
315function removeKelloggsEpsilon(removeInput) {
316  const cleanName = removeInput.replace('Kelloggs', '').replace('cereal', '').trim();
317  return cleanName;
318}
319
320/**
321 * Gets wkkellogg home url for Schema.org breadcrumbList.
322 */
323const getWkkcHomeUrl = () => {
324  const { hostname } = window.location;
325  const locale = getLocale();
326
327  if (hostname.includes('localhost') || hostname.includes('wkkellogg')) {
328    if (locale === 'fr_CA') {
329      return 'https://www.wkkellogg.ca/fr/';
330    }
331    if (locale === 'en_CA') {
332      return 'https://www.wkkellogg.ca/en/';
333    }
334    return 'https://www.wkkellogg.com';
335  }
336
337  return '';
338};
339
340/**
341 * Chooses the locale-specific path segment for Schema breadcrumbList.
342 */
343const getLocalizedPathByLocale = (enPath, frPath, inputLocale = getLocale()) => {
344  if (inputLocale === 'fr_CA') {
345    return frPath;
346  }
347  return enPath;
348};
349
350/**
351 * Appends a path segment to a base URL while normalizing slashes for Schema breadcrumbList.
352 */
353const appendPathToUrl = (baseUrl, path) => {
354  if (!baseUrl || !path) {
355    return baseUrl || '';
356  }
357
358  const normalizedBaseUrl = baseUrl.endsWith('/') ? baseUrl.slice(0, -1) : baseUrl;
359  const normalizedPath = String(path).replace(/^\/+/, '');
360  return `${normalizedBaseUrl}/${normalizedPath}`;
361};
362
363/**
364 * Converts text into a URL-safe slug for Schema breadcrumb/category links.
365 */
366const toUrlSlug = (value) => stripHtmlTags(value)
367  .toLowerCase()
368  .replace(/[^a-z0-9\s-]/g, '')
369  .trim()
370  .replace(/\s+/g, '-')
371  .replace(/-+/g, '-');
372
373/**
374 * Builds a Schema BreadcrumbList from ordered breadcrumb items.
375 */
376function buildBreadcrumbListSchema(id, items = []) {
377  return {
378    '@type': 'BreadcrumbList',
379    '@id': id,
380    itemListElement: items
381      .filter((item) => item?.id && item?.name)
382      .map((item, index) => ({
383        '@type': 'ListItem',
384        position: index + 1,
385        item: {
386          '@id': item.id,
387          name: item.name,
388        },
389      })),
390  };
391}
392
393// updating a seo title in product/recipe detail pages
394
395function updateSeoTitle(title) {
396  if (!title) return;
397  const Brand = getBrand();
398  let locale = getLocale();
399  let upDatedBrand = '';
400  switch (Brand) {
401    case 'rice-krispies':
402      upDatedBrand = 'Rice Krispies®';
403      break;
404    case 'kashi':
405      upDatedBrand = 'Kashi®';
406      break;
407    case 'wkkc':
408      upDatedBrand = 'WK Kellogg Co';
409      break;
410    case 'bear-naked':
411      upDatedBrand = 'Bear Naked®';
412      break;
413    default:
414      upDatedBrand = '';
415  }
416  if (!upDatedBrand) return;
417  if (locale === 'en_CA' || locale === 'fr_CA') {
418    if (upDatedBrand === 'Kashi®' && locale === 'fr_CA') return;
419    locale = 'Canada';
420    document.title = `${title} - ${upDatedBrand} ${locale}`;
421  }
422}
423// redirection
424function redirection() {
425  const Locale = getLocale();
426  let locale = '';
427
428  switch (Locale) {
429    case 'en_CA':
430      locale = '/en';
431      break;
432    case 'fr_CA':
433      locale = '/fr';
434      break;
435    default:
436      locale = '';
437  }
438
439  /**
440  * redirection from www.wkkellogg.com/who-we-are/board-management to
441  investor.wkkellogg.com/governance/board-of-directors/default.aspx
442*/
443
444  if (window.location.href === `${window.location.origin}${locale}/who-we-are/board-management`) {
445    window.location.href = 'https://investor.wkkellogg.com/governance/board-of-directors/default.aspx';
446  }
447}
448redirection();
449
450/**
451 * Auto initializiation.
452 */
453
454function init() {
455  setup();
456  sampleRUM('top');
457
458  window.addEventListener('load', () => sampleRUM('load'));
459
460  window.addEventListener('unhandledrejection', (event) => {
461    sampleRUM('error', { source: event.reason.sourceURL, target: event.reason.line });
462  });
463
464  window.addEventListener('error', (event) => {
465    sampleRUM('error', { source: event.filename, target: event.lineno });
466  });
467}
468
469/**
470 * Sanitizes a string for use as class name.
471 * @param {string} name The unsanitized string
472 * @returns {string} The class name
473 */
474function toClassName(name) {
475  return typeof name === 'string'
476    ? name
477      .toLowerCase()
478      .replace(/[^0-9a-z]/gi, '-')
479      .replace(/-+/g, '-')
480      .replace(/^-|-$/g, '')
481    : '';
482}
483
484/**
485 * Sanitizes a string for use as a js property name.
486 * @param {string} name The unsanitized string
487 * @returns {string} The camelCased name
488 */
489function toCamelCase(name) {
490  return toClassName(name).replace(/-([a-z])/g, (g) => g[1].toUpperCase());
491}
492
493/**
494 * Extracts the config from a block.
495 * @param {Element} block The block element
496 * @returns {object} The block config
497 */
498// eslint-disable-next-line import/prefer-default-export
499function readBlockConfig(block) {
500  const config = {};
501  block.querySelectorAll(':scope > div').forEach((row) => {
502    if (row.children) {
503      const cols = [...row.children];
504      if (cols[1]) {
505        const col = cols[1];
506        const name = toClassName(cols[0].textContent);
507        let value = '';
508        if (col.querySelector('a')) {
509          const as = [...col.querySelectorAll('a')];
510          if (as.length === 1) {
511            value = as[0].href;
512          } else {
513            value = as.map((a) => a.href);
514          }
515        } else if (col.querySelector('img')) {
516          const imgs = [...col.querySelectorAll('img')];
517          if (imgs.length === 1) {
518            value = imgs[0].src;
519          } else {
520            value = imgs.map((img) => img.src);
521          }
522        } else if (col.querySelector('p')) {
523          const ps = [...col.querySelectorAll('p')];
524          if (ps.length === 1) {
525            value = ps[0].textContent;
526          } else {
527            value = ps.map((p) => p.textContent);
528          }
529        } else value = row.children[1].textContent;
530        config[name] = value;
531      }
532    }
533  });
534  return config;
535}
536
537/**
538 * Loads a CSS file.
539 * @param {string} href URL to the CSS file
540 */
541async function loadCSS(href) {
542  return new Promise((resolve, reject) => {
543    if (!document.querySelector(`head > link[href="${href}"]`)) {
544      const link = document.createElement('link');
545      link.rel = 'stylesheet';
546      link.href = href;
547      link.onload = resolve;
548      link.onerror = reject;
549      document.head.append(link);
550    } else {
551      resolve();
552    }
553  });
554}
555
556/**
557 * Loads a non module JS file.
558 * @param {string} src URL to the JS file
559 * @param {Object} attrs additional optional attributes
560 */
561async function loadScript(src, attrs) {
562  return new Promise((resolve, reject) => {
563    if (!document.querySelector(`head > script[src="${src}"]`)) {
564      const script = document.createElement('script');
565      script.src = src;
566      if (attrs) {
567        // eslint-disable-next-line no-restricted-syntax, guard-for-in
568        for (const attr in attrs) {
569          script.setAttribute(attr, attrs[attr]);
570        }
571      }
572      script.onload = resolve;
573      script.onerror = reject;
574      document.head.append(script);
575    } else {
576      resolve();
577    }
578  });
579}
580
581/**
582 * Extracts an image URL from a CSS background-image declaration.
583 * Accepts either css url(...) values or direct URLs.
584 * @param {string} value CSS background-image value or direct URL
585 * @returns {string} Resolved image URL or empty string
586 */
587function getBackgroundImageUrl(url) {
588  const input = String(url).trim();
589  const match = input.match(/^url\(([^)]+)\)$/i);
590  const rawUrl = (match ? match[1] : input).trim().replace(/^['"]|['"]$/g, '');
591  try {
592    return new URL(rawUrl, window.location.href).href;
593  } catch (error) {
594    return '';
595  }
596}
597
598/**
599 * Adds a high-priority preload link for an image when not already present.
600 * @param {string} imageUrl Image URL to preload
601 */
602function preloadSectionBackgroundImage(imageUrl) {
603  if (!imageUrl) return;
604
605  const normalizedImageUrl = getBackgroundImageUrl(imageUrl);
606  const existingPreloadLinks = [...document.head.querySelectorAll('link[rel="preload"][as="image"]')];
607  const hasMatchingPreloadLink = existingPreloadLinks.some((link) => {
608    const href = link.getAttribute('href');
609    if (!href) return false;
610    return getBackgroundImageUrl(href) === normalizedImageUrl;
611  });
612  if (hasMatchingPreloadLink) {
613    return;
614  }
615
616  const preloadLink = document.createElement('link');
617  preloadLink.setAttribute('rel', 'preload');
618  preloadLink.setAttribute('as', 'image');
619  preloadLink.setAttribute('href', normalizedImageUrl);
620  preloadLink.setAttribute('fetchpriority', 'high');
621  document.head.append(preloadLink);
622}
623
624/**
625 * Retrieves the content of metadata tags.
626 * @param {string} name The metadata name (or property)
627 * @param {Document} doc Document object to query for metadata. Defaults to the window's document
628 * @returns {string} The metadata value(s)
629 */
630function getMetadata(name, doc = document) {
631  const attr = name && name.includes(':') ? 'property' : 'name';
632  const meta = [...doc.head.querySelectorAll(`meta[${attr}="${name}"]`)]
633    .map((m) => m.content)
634    .join(', ');
635  return meta || '';
636}
637
638/**
639 * Collects all anchor tags
640 * If the link address contains a host that does not match the current location,
641 * the `target="_blank"` attribute is assigned to the anchor tag
642 */
643function updateLinkTags() {
644  const aTags = document.querySelectorAll('a');
645  const theme = getMetadata('theme');
646  aTags.forEach((item) => {
647    if (item.href) {
648      const url = new URL(item.href);
649      if (url && url.host !== window.location.host) {
650        item.setAttribute('target', '_blank');
651      }
652
653      if (theme === 'theme-frosted-flakes' && item.href.indexOf('mission-tiger') !== -1) {
654        item.setAttribute('target', '_blank');
655      }
656    }
657  });
658}
659
660/**
661 * Returns a picture element with webp and fallbacks
662 * @param {string} src The image URL
663 * @param {string} [alt] The image alternative text
664 * @param {boolean} [eager] Set loading attribute to eager
665 * @param {Array} [breakpoints] Breakpoints and corresponding params (eg. width)
666 * @returns {Element} The picture element
667 */
668function createOptimizedPicture(
669  src,
670  alt = '',
671  eager = false,
672  breakpoints = [{ media: '(min-width: 600px)', width: '2000' }, { width: '750' }],
673) {
674  const url = new URL(src, window.location.href);
675  const picture = document.createElement('picture');
676  const { pathname } = url;
677  const ext = pathname.substring(pathname.lastIndexOf('.') + 1);
678
679  // webp
680  breakpoints.forEach((br) => {
681    const source = document.createElement('source');
682    if (br.media) source.setAttribute('media', br.media);
683    source.setAttribute('type', 'image/webp');
684    source.setAttribute('srcset', `${pathname}?width=${br.width}&format=webply&optimize=medium`);
685    picture.appendChild(source);
686  });
687
688  // fallback
689  breakpoints.forEach((br, i) => {
690    if (i < breakpoints.length - 1) {
691      const source = document.createElement('source');
692      if (br.media) source.setAttribute('media', br.media);
693      source.setAttribute('srcset', `${pathname}?width=${br.width}&format=${ext}&optimize=medium`);
694      picture.appendChild(source);
695    } else {
696      const img = document.createElement('img');
697      img.setAttribute('loading', eager ? 'eager' : 'lazy');
698      img.setAttribute('alt', alt);
699      picture.appendChild(img);
700      img.setAttribute('src', `${pathname}?width=${br.width}&format=${ext}&optimize=medium`);
701    }
702  });
703
704  return picture;
705}
706
707/**
708 * Set template (page structure) and theme (page styles).
709 */
710function decorateTemplateAndTheme() {
711  const addClasses = (element, classes) => {
712    classes.split(',').forEach((c) => {
713      element.classList.add(toClassName(c.trim()));
714    });
715  };
716  const template = getMetadata('template');
717  if (template) addClasses(document.body, template);
718  const theme = getMetadata('theme');
719  if (theme) addClasses(document.body, theme);
720}
721
722/**
723 * Wrap inline text content of block cells within a <p> tag.
724 * @param {Element} block the block element
725 */
726function wrapTextNodes(block) {
727  const validWrappers = [
728    'P',
729    'PRE',
730    'UL',
731    'OL',
732    'PICTURE',
733    'TABLE',
734    'H1',
735    'H2',
736    'H3',
737    'H4',
738    'H5',
739    'H6',
740  ];
741
742  const wrap = (el) => {
743    const wrapper = document.createElement('p');
744    wrapper.append(...el.childNodes);
745    [...el.attributes]
746      // move the instrumentation from the cell to the new paragraph, also keep the class
747      // in case the content is a buttton and the cell the button-container
748      .filter(({ nodeName }) => nodeName === 'class'
749        || nodeName.startsWith('data-aue')
750        || nodeName.startsWith('data-richtext'))
751      .forEach(({ nodeName, nodeValue }) => {
752        wrapper.setAttribute(nodeName, nodeValue);
753        el.removeAttribute(nodeName);
754      });
755    el.append(wrapper);
756  };
757
758  block.querySelectorAll(':scope > div > div').forEach((blockColumn) => {
759    if (blockColumn.hasChildNodes()) {
760      const hasWrapper = !!blockColumn.firstElementChild
761        && validWrappers.some((tagName) => blockColumn.firstElementChild.tagName === tagName);
762      if (!hasWrapper) {
763        wrap(blockColumn);
764      } else if (
765        blockColumn.firstElementChild.tagName === 'PICTURE'
766        && (blockColumn.children.length > 1 || !!blockColumn.textContent.trim())
767      ) {
768        wrap(blockColumn);
769      }
770    }
771  });
772}
773
774/**
775 * Decorates paragraphs containing a single link as buttons.
776 * @param {Element} element container element
777 */
778function decorateButtons(element) {
779  element.querySelectorAll('a').forEach((a) => {
780    a.title = a.title || a.textContent;
781    if (a.href !== a.textContent) {
782      const up = a.parentElement;
783      const twoup = a.parentElement.parentElement;
784      if (!a.querySelector('img')) {
785        if (up.childNodes.length === 1 && (up.tagName === 'P' || up.tagName === 'DIV')) {
786          a.className = 'button default'; // default
787          up.classList.add('button-container');
788        }
789        if (
790          up.childNodes.length === 1
791          && up.tagName === 'STRONG'
792          && twoup.childNodes.length === 1
793          && (twoup.tagName === 'P' || twoup.tagName === 'DIV')
794        ) {
795          a.className = 'button primary';
796          twoup.classList.add('button-container');
797        }
798        if (
799          up.childNodes.length === 1
800          && up.tagName === 'EM'
801          && twoup.childNodes.length === 1
802          && (twoup.tagName === 'P' || twoup.tagName === 'DIV')
803        ) {
804          a.className = 'button secondary';
805          twoup.classList.add('button-container');
806        }
807      }
808    }
809  });
810}
811
812/**
813 * Add <img> for icon, prefixed with codeBasePath and optional prefix.
814 * @param {Element} [span] span element with icon classes
815 * @param {string} [prefix] prefix to be added to icon src
816 * @param {string} [alt] alt text to be added to icon
817 */
818function decorateIcon(span, prefix = '', alt = '') {
819  const iconName = Array.from(span.classList)
820    .find((c) => c.startsWith('icon-'))
821    .substring(5);
822  const img = document.createElement('img');
823  img.dataset.iconName = iconName;
824  img.src = `${window.hlx.codeBasePath}${prefix}/icons/${iconName}.svg`;
825  img.alt = alt || iconName;
826  img.loading = 'lazy';
827  span.append(img);
828}
829
830/**
831 * Add <img> for icons, prefixed with codeBasePath and optional prefix.
832 * @param {Element} [element] Element containing icons
833 * @param {string} [prefix] prefix to be added to icon the src
834 */
835function decorateIcons(element, prefix = '') {
836  const icons = [...element.querySelectorAll('span.icon')];
837  icons.forEach((span) => {
838    decorateIcon(span, prefix);
839  });
840}
841
842/**
843 * Decorates all sections in a container element.
844 * @param {Element} main The container element
845 */
846function decorateSections(main) {
847  main.querySelectorAll(':scope > div:not([data-section-status])').forEach((section) => {
848    const wrappers = [];
849    let defaultContent = false;
850    [...section.children].forEach((e) => {
851      if (e.tagName === 'DIV' || !defaultContent) {
852        const wrapper = document.createElement('div');
853        wrappers.push(wrapper);
854        defaultContent = e.tagName !== 'DIV';
855        if (defaultContent) wrapper.classList.add('default-content-wrapper');
856      }
857      wrappers[wrappers.length - 1].append(e);
858    });
859    wrappers.forEach((wrapper) => section.append(wrapper));
860    section.classList.add('section');
861    section.dataset.sectionStatus = 'initialized';
862    section.style.display = 'none';
863
864    // Process section metadata
865    const sectionMeta = section.querySelector('div.section-metadata');
866    if (sectionMeta) {
867      const meta = readBlockConfig(sectionMeta);
868      Object.keys(meta).forEach((key) => {
869        if (key === 'style') {
870          const styles = meta.style
871            .split(',')
872            .filter((style) => style)
873            .map((style) => toClassName(style.trim()));
874          styles.forEach((style) => section.classList.add(style));
875        } else if (key === 'background') {
876          const bg = meta.background;
877          section.classList.add('has-background-image');
878          section.style.backgroundImage = `url(${bg})`;
879          preloadSectionBackgroundImage(bg);
880        } else {
881          section.dataset[toCamelCase(key)] = meta[key];
882        }
883      });
884      sectionMeta.parentNode.remove();
885    }
886    let dataBg = section.getAttribute('data-background') || section.dataset.background;
887    if (dataBg) {
888      if (/^https?:\/\//i.test(dataBg)) {
889        try {
890          const u = new URL(dataBg);
891          if (u.host !== window.location.host && (u.host.includes('bearnaked') || getBrand() === 'bear-naked')) {
892            dataBg = `${u.pathname}${u.search || ''}${u.hash || ''}`;
893            section.classList.add('has-background-image');
894            section.style.backgroundImage = `url(${dataBg})`;
895            section.removeAttribute('data-background');
896          }
897        } catch (e) {
898        }
899      }
900    }
901  });
902}
903
904/**
905 * Gets placeholders object.
906 * @param {string} [prefix] Location of placeholders
907 * @returns {object} Window placeholders object
908 */
909// eslint-disable-next-line import/prefer-default-export
910async function fetchPlaceholders(prefix = 'default') {
911  window.placeholders = window.placeholders || {};
912  if (!window.placeholders[prefix]) {
913    window.placeholders[prefix] = new Promise((resolve) => {
914      fetch(`${prefix === 'default' ? '' : prefix}/placeholders.json`)
915        .then((resp) => {
916          if (resp.ok) {
917            return resp.json();
918          }
919          return {};
920        })
921        .then((json) => {
922          const placeholders = {};
923          json.data
924            .filter((placeholder) => placeholder.Key)
925            .forEach((placeholder) => {
926              placeholders[toCamelCase(placeholder.Key)] = placeholder.Text;
927            });
928          window.placeholders[prefix] = placeholders;
929          resolve(window.placeholders[prefix]);
930        })
931        .catch(() => {
932          // error loading placeholders
933          window.placeholders[prefix] = {};
934          resolve(window.placeholders[prefix]);
935        });
936    });
937  }
938  return window.placeholders[`${prefix}`];
939}
940
941/**
942 * Updates all section status in a container element.
943 * @param {Element} main The container element
944 */
945function updateSectionsStatus(main) {
946  const sections = [...main.querySelectorAll(':scope > div.section')];
947  for (let i = 0; i < sections.length; i += 1) {
948    const section = sections[i];
949    const status = section.dataset.sectionStatus;
950    if (status !== 'loaded') {
951      const loadingBlock = section.querySelector(
952        '.block[data-block-status="initialized"], .block[data-block-status="loading"]',
953      );
954      if (loadingBlock) {
955        section.dataset.sectionStatus = 'loading';
956        break;
957      } else {
958        section.dataset.sectionStatus = 'loaded';
959        section.style.display = null;
960      }
961    }
962  }
963}
964
965/**
966 * Builds a block DOM Element from a two dimensional array, string, or object
967 * @param {string} blockName name of the block
968 * @param {*} content two dimensional array or string or object of content
969 */
970function buildBlock(blockName, content) {
971  const table = Array.isArray(content) ? content : [[content]];
972  const blockEl = document.createElement('div');
973  // build image block nested div structure
974  blockEl.classList.add(blockName);
975  table.forEach((row) => {
976    const rowEl = document.createElement('div');
977    row.forEach((col) => {
978      const colEl = document.createElement('div');
979      const vals = col.elems ? col.elems : [col];
980      vals.forEach((val) => {
981        if (val) {
982          if (typeof val === 'string') {
983            colEl.innerHTML += val;
984          } else {
985            colEl.appendChild(val);
986          }
987        }
988      });
989      rowEl.appendChild(colEl);
990    });
991    blockEl.appendChild(rowEl);
992  });
993  return blockEl;
994}
995
996/**
997 * Loads JS and CSS for a block.
998 * @param {Element} block The block element
999 */
1000async function loadBlock(block) {
1001  const status = block.dataset.blockStatus;
1002  if (status !== 'loading' && status !== 'loaded') {
1003    block.dataset.blockStatus = 'loading';
1004    const { blockName } = block.dataset;
1005    try {
1006      const cssLoaded = loadCSS(`${window.hlx.codeBasePath}/blocks/${blockName}/${blockName}.css`);
1007      const decorationComplete = new Promise((resolve) => {
1008        (async () => {
1009          try {
1010            const mod = await import(
1011              `${window.hlx.codeBasePath}/blocks/${blockName}/${blockName}.js`
1012            );
1013            if (mod.default) {
1014              await mod.default(block);
1015            }
1016          } catch (error) {
1017            // eslint-disable-next-line no-console
1018            console.log(`failed to load module for ${blockName}`, error);
1019          }
1020          resolve();
1021        })();
1022      });
1023      await Promise.all([cssLoaded, decorationComplete]);
1024    } catch (error) {
1025      // eslint-disable-next-line no-console
1026      console.log(`failed to load block ${blockName}`, error);
1027    }
1028    block.dataset.blockStatus = 'loaded';
1029  }
1030  return block;
1031}
1032
1033/**
1034 * Loads JS and CSS for all blocks in a container element.
1035 * @param {Element} main The container element
1036 */
1037async function loadBlocks(main) {
1038  updateSectionsStatus(main);
1039  const blocks = [...main.querySelectorAll('div.block')];
1040  for (let i = 0; i < blocks.length; i += 1) {
1041    // eslint-disable-next-line no-await-in-loop
1042    await loadBlock(blocks[i]);
1043    updateSectionsStatus(main);
1044  }
1045}
1046
1047/**
1048 * Decorates a block.
1049 * @param {Element} block The block element
1050 */
1051function decorateBlock(block) {
1052  const shortBlockName = block.classList[0];
1053  if (shortBlockName && !block.dataset.blockStatus) {
1054    block.classList.add('block');
1055    block.dataset.blockName = shortBlockName;
1056    block.dataset.blockStatus = 'initialized';
1057    const blockWrapper = block.parentElement;
1058    blockWrapper.classList.add(`${shortBlockName}-wrapper`);
1059    const section = block.closest('.section');
1060    if (section) section.classList.add(`${shortBlockName}-container`);
1061    block.querySelectorAll(':scope > div > div').forEach((cell) => {
1062      const firstChild = cell.firstElementChild;
1063      const cellText = cell.textContent.trim();
1064      if ((!firstChild && cellText)
1065        || (firstChild && !firstChild.tagName.match(/^(P(RE)?|H[1-6]|(U|O)L|TABLE)$/))) {
1066        const paragraph = document.createElement('p');
1067        [...cell.attributes]
1068          // move the instrumentation from the cell to the new paragraph, also keep the class
1069          // in case the content is a buttton and the cell the button-container
1070          .filter(({ nodeName }) => nodeName === 'class'
1071            || nodeName.startsWith('data-aue')
1072            || nodeName.startsWith('data-richtext'))
1073          .forEach(({ nodeName, nodeValue }) => {
1074            paragraph.setAttribute(nodeName, nodeValue);
1075            cell.removeAttribute(nodeName);
1076          });
1077        paragraph.append(...cell.childNodes);
1078        cell.replaceChildren(paragraph);
1079      }
1080    });
1081    // eslint-disable-next-line no-use-before-define
1082    decorateButtons(block);
1083  }
1084}
1085
1086/**
1087 * Decorates all blocks in a container element.
1088 * @param {Element} main The container element
1089 */
1090function decorateBlocks(main) {
1091  main.querySelectorAll('div.section > div > div').forEach(decorateBlock);
1092}
1093
1094/**
1095 * Loads a block named 'header' into header
1096 * @param {Element} header header element
1097 * @returns {Promise}
1098 */
1099async function loadHeader(header) {
1100  const headerBlock = buildBlock('header', '');
1101  header.append(headerBlock);
1102  decorateBlock(headerBlock);
1103  return loadBlock(headerBlock);
1104}
1105
1106/**
1107 * Loads a block named 'footer' into footer
1108 * @param footer footer element
1109 * @returns {Promise}
1110 */
1111async function loadFooter(footer) {
1112  const footerBlock = buildBlock('footer', '');
1113  footer.append(footerBlock);
1114  decorateBlock(footerBlock);
1115  return loadBlock(footerBlock);
1116}
1117
1118/**
1119 * Loads a block named '404' into main section of 404.html
1120 * @param footer footer element
1121 * @returns {Promise}
1122 */
1123async function loadErrorPage(errorPage) {
1124  const errorBlock = buildBlock('404', '');
1125  errorPage.append(errorBlock);
1126  decorateBlock(errorBlock);
1127  return loadBlock(errorBlock);
1128}
1129
1130/**
1131 * Load LCP block and/or wait for LCP in default content.
1132 * @param {Array} lcpBlocks Array of blocks
1133 */
1134async function waitForLCP(lcpBlocks) {
1135  const block = document.querySelector('.block');
1136  const hasLCPBlock = block && lcpBlocks.includes(block.dataset.blockName);
1137  if (hasLCPBlock) await loadBlock(block);
1138
1139  document.body.style.display = null;
1140  const lcpCandidate = document.querySelector('main img');
1141
1142  await new Promise((resolve) => {
1143    if (lcpCandidate && !lcpCandidate.complete) {
1144      lcpCandidate.setAttribute('loading', 'eager');
1145      lcpCandidate.addEventListener('load', resolve);
1146      lcpCandidate.addEventListener('error', resolve);
1147    } else {
1148      resolve();
1149    }
1150  });
1151}
1152
1153/**
1154 * Creates an SVG sparkle icon with brand color
1155 * @param {string} color - Hex color for the sparkle (default: #0061af)
1156 * @param {boolean} isRight - Whether to use right-oriented sparkle (default: false for left)
1157 * @returns {SVGElement} SVG element with sparkle paths
1158 */
1159function createSparkleIcon(color = '#0061af', isRight = false) {
1160  const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
1161  svg.setAttribute('viewBox', isRight ? '0 0 37 61' : '0 0 36 61');
1162  svg.setAttribute('fill', 'none');
1163  svg.setAttribute('class', 'sparkle-icon');
1164
1165  // Left sparkle paths (default)
1166  const leftPaths = [
1167    'M15.2768 19.5249C15.4078 19.526 15.5414 19.5105 15.6598 19.458C15.7781 19.4055 15.8713 19.3207 15.9235 19.2125C15.9758 19.1042 15.9842 18.9786 15.9517 18.8533C15.9192 18.7279 15.8483 18.6136 15.7659 18.5118C15.5786 18.2825 15.3859 18.0646 15.1877 17.8578C14.3949 17.0309 13.5152 16.3842 12.5485 15.9175C9.16521 14.2842 5.66353 12.896 2.0435 11.753C1.78493 11.6713 1.52575 11.5909 1.26597 11.5118C1.13224 11.4712 0.985844 11.4699 0.853046 11.5205C0.720292 11.5709 0.612751 11.6676 0.552663 11.792C0.492575 11.9165 0.483807 12.0608 0.526872 12.1961C0.569893 12.3316 0.661954 12.4454 0.776875 12.5249C1.00043 12.6791 1.22458 12.832 1.44934 12.9837C4.59598 15.1073 7.86097 16.9858 11.2443 18.6192C12.2109 19.0858 13.2645 19.3724 14.4051 19.4788C14.6903 19.5054 14.9808 19.5208 15.2768 19.5249Z',
1168    'M18.9842 15.6851C19.0747 15.7793 19.1777 15.8646 19.2961 15.9144C19.4146 15.9641 19.5385 15.9742 19.6519 15.939C19.7653 15.9038 19.8618 15.8253 19.9313 15.7172C20.0007 15.6092 20.0373 15.4805 20.0586 15.3516C20.103 15.0729 20.1354 14.7979 20.1559 14.5266C20.238 13.4413 20.129 12.4154 19.829 11.4487C18.779 8.06544 17.469 4.76279 15.899 1.54083C15.7869 1.3107 15.6734 1.08097 15.5586 0.851651C15.4961 0.727186 15.3971 0.619923 15.2698 0.55769C15.1427 0.495426 14.9992 0.482781 14.8678 0.523565C14.7364 0.56435 14.6254 0.655968 14.5558 0.779294C14.4861 0.902651 14.4652 1.0471 14.4842 1.1851C14.5194 1.43912 14.5559 1.69272 14.5938 1.94591C15.1238 5.49062 15.9138 8.95464 16.9638 12.3379C17.2638 13.3046 17.7548 14.212 18.4368 15.0601C18.6073 15.2721 18.7898 15.4804 18.9842 15.6851Z',
1169    'M23.5848 15.6636C23.5789 15.7935 23.5792 15.9227 23.6068 16.0404C23.6347 16.1582 23.6895 16.2562 23.773 16.3241C23.8565 16.3919 23.9636 16.4255 24.0846 16.4286C24.2055 16.4316 24.3321 16.4054 24.4579 16.373C24.6633 16.3185 24.8589 16.2561 25.0449 16.1859C25.7887 15.9048 26.3772 15.4976 26.8106 14.9642C28.3272 13.0976 29.6326 11.0592 30.7267 8.84928C30.8049 8.69142 30.882 8.53269 30.9579 8.37308C31.0162 8.25006 31.0458 8.11077 31.0256 7.97395C31.0055 7.8372 30.9387 7.71524 30.8357 7.63155C30.7327 7.54787 30.5996 7.50741 30.4617 7.51575C30.3236 7.52401 30.1933 7.5815 30.0848 7.66366C29.9441 7.77072 29.8046 7.87866 29.666 7.98747C27.7268 9.51081 25.9989 11.2058 24.4822 13.0724C24.0489 13.6058 23.7708 14.2652 23.6479 15.0508C23.6172 15.2472 23.5961 15.4515 23.5848 15.6636Z',
1170    'M27.0588 20.9571C26.9605 21.0446 26.8661 21.1302 26.7947 21.2191C26.7234 21.3086 26.6806 21.399 26.6742 21.4952C26.6678 21.5913 26.6981 21.6867 26.757 21.7848C26.8159 21.8824 26.8981 21.9798 26.984 22.0796C27.1007 22.2126 27.2182 22.3332 27.3365 22.4413C27.8099 22.8738 28.2966 23.1067 28.7966 23.14C30.5466 23.2567 32.3147 23.1017 34.1009 22.6752C34.2285 22.6447 34.3562 22.6128 34.484 22.5796C34.6129 22.5455 34.7384 22.4861 34.8343 22.3917C34.9302 22.2974 34.9885 22.1772 34.997 22.05C35.0055 21.9229 34.9636 21.796 34.8811 21.6898C34.7986 21.5835 34.6821 21.508 34.5588 21.4571C34.4366 21.4072 34.3143 21.3586 34.1918 21.3115C32.4781 20.6516 30.7462 20.2633 28.9962 20.1467C28.4962 20.1133 27.9829 20.2795 27.4563 20.6453C27.3246 20.7368 27.1921 20.8407 27.0588 20.9571Z',
1171    'M24.4347 25.6368C24.305 25.622 24.1774 25.6109 24.0606 25.6237C23.9434 25.6368 23.844 25.6752 23.7687 25.7446C23.6935 25.8141 23.6473 25.9
1171101 23.6249 26.0259C23.6028 26.1413 23.6037 26.2694 23.6081 26.3999C23.6162 26.593 23.6335 26.7776 23.6601 26.9538C23.7661 27.6584 24.0192 28.2274 24.4192 28.6608C25.8192 30.1774 27.4192 31.5094 29.2193 32.6568C29.3478 32.7388 29.4774 32.8198 29.6081 32.8999C29.7232 32.97 29.856 33.0165 29.9926 33.0151C30.1291 33.0138 30.257 32.9657 30.3528 32.8774C30.4485 32.789 30.5066 32.6653 30.5188 32.5293C30.5312 32.3933 30.4954 32.2571 30.4347 32.1368C30.3653 32.0002 30.2949 31.8646 30.2235 31.7298C29.2236 29.8439 28.0236 28.1426 26.6236 26.6259C26.2236 26.1926 25.6766 25.8949 24.9827 25.7329C24.8092 25.6924 24.6266 25.6603 24.4347 25.6368Z',
1172    'M19.5464 26.7203C19.5291 26.5911 19.4988 26.462 19.4365 26.3514C19.3742 26.2408 19.2849 26.1578 19.1761 26.116C19.0674 26.0742 18.9454 26.0759 18.8251 26.1162C18.7048 26.1566 18.5957 26.2321 18.4964 26.3164C18.2964 26.4882 18.108 26.6645 17.9314 26.8453C17.2247 27.5683 16.7047 28.3632 16.3714 29.2299C15.2047 32.2632 14.2921 35.3943 13.6336 38.623C13.5866 38.8537 13.5408 39.0848 13.4964 39.3164C13.4705 39.4526 13.4824 39.5973 13.5438 39.7243C13.6051 39.8512 13.7092 39.9493 13.8368 39.9983C13.9643 40.0474 14.1073 40.0443 14.2378 39.9912C14.3685 39.9381 14.4744 39.8387 14.5464 39.7203C14.6686 39.5186 14.7895 39.3163 14.9092 39.1136C16.584 36.2757 18.0047 33.3401 19.1714 30.3068C19.5047 29.4401 19.6514 28.5017 19.6114 27.4914C19.6014 27.2388 19.5797 26.9818 19.5464 26.7203Z',
1173    'M14.344 24.9792C14.3948 24.8596 14.437 24.7355 14.4453 24.6114C14.4535 24.4872 14.4266 24.3724 14.3619 24.28C14.2972 24.1876 14.1985 24.1229 14.079 24.0882C13.9596 24.0535 13.8286 24.0507 13.6988 24.0575C13.4605 24.0718 13.2293 24.0963 13.0053 24.131C12.1092 24.27 11.3279 24.5728 10.6612 25.0395C8.3279 26.6728 6.15067 28.5292 4.12956 30.6085C3.98519 30.7571 3.84163 30.9067 3.69885 31.0575C3.60449 31.1576 3.53525 31.2839 3.51601 31.4225C3.49671 31.561 3.52795 31.6989 3.60539 31.8096C3.68283 31.9202 3.80173 31.9968 3.93847 32.026C4.07528 32.0554 4.21768 32.0336 4.344 31.9792C4.53456 31.8966 4.72432 31.8129 4.91329 31.7281C7.55884 30.5408 10.0483 29.1305 12.3816 27.4972C13.0482 27.0305 13.6002 26.4 14.0375 25.6056C14.1468 25.4071 14.249 25.1982 14.344 24.9792Z',
1174  ];
1175
1176  // Right sparkle paths (inverted)
1177  const rightPaths = [
1178    'M19.6138 40.5453C19.5474 40.6582 19.494 40.7816 19.4803 40.9104C19.4666 41.0391 19.4934 41.1622 19.561 41.2615C19.6287 41.361 19.7332 41.431 19.858 41.4655C19.9829 41.5001 20.1173 41.4959 20.2467 41.4754C20.5389 41.4278 20.8239 41.3699 21.1021 41.3017C22.2147 41.0285 23.2146 40.59 24.1021 39.9862C27.2082 37.8728 30.1613 35.5343 32.9612 32.9708C33.1612 32.7877 33.3604 32.6035 33.5588 32.4181C33.6608 32.3225 33.7352 32.1964 33.7577 32.0561C33.7805 31.9159 33.7505 31.7744 33.6728 31.6602C33.595 31.5459 33.4745 31.4662 33.3357 31.4358C33.1969 31.4053 33.0523 31.4282 32.926 31.4879C32.6807 31.6044 32.4362 31.7221 32.1924 31.8409C28.78 33.5042 25.5207 35.3925 22.4144 37.5059C21.5271 38.1097 20.7521 38.8788 20.0896 39.8134C19.924 40.0471 19.7654 40.291 19.6138 40.5453Z',
1179    'M21.0855 45.6759C20.9587 45.7071 20.8333 45.7537 20.731 45.8313C20.6287 45.9091 20.558 46.0114 20.5318 46.1272C20.5056 46.243 20.5253 46.3658 20.5842 46.48C20.643 46.5941 20.7361 46.6902 20.8371 46.7731C21.0563 46.9509 21.2782 47.1164 21.5029 47.2698C22.4018 47.8836 23.3447 48.3021 24.3319 48.5257C27.787 49.308 31.3021 49.8248 34.8774 50.0762C35.1328 50.0942 35.3885 50.1107 35.6445 50.126C35.7835 50.1341 35.9259 50.102 36.0435 50.0228C36.1609 49.9439 36.2436 49.8259 36.274 49.6918C36.3044 49.5576 36.2805 49.4156 36.2085 49.2937C36.1366 49.1716 36.0219 49.0813 35.8929 49.0288C35.6553 48.9323 35.4174 48.8371 35.1792 48.7433C31.8444 47.4299 28.4495 46.3821 24.9945 45.5998C24.0073 45.3762 22.9759 45.3477 21.9005 45.5143C21.6316 45.556 21.36 45.6099 21.0855 45.6759Z',
1180    'M18.8038 49.6709C18.6943 49.6008 18.5822 49.5365 18.4665 49.5015C18.3505 49.4668 18.2383 49.4652 18.1377 49.5036C18.0372 49.542 17.9546 49.618 17.8914 49.7212C17.8284 49.8244 17.7878 49.9471 17.7529 50.0723C17.6974 50.2774 17.6537 50.478 17.6214 50.6742C17.493 51.4589 17.5514 52.1721 17.7966 52.8142C18.6548 55.0609 19.7674 57.2106 21.1343 59.2631C21.2319 59.4098 21.3308 59.5559 21.4311 59.7014C21.5085 59.8134 21.6143 59.9087 21.7429 59.9596C21.8714 60.0106 22.0104 60.0137 22.1344 59.9664C22.2583 59.919 22.3599 59.824 22.4216 59.7004C22.4835 59.5766 22.4989 59.4351 22.482 59.3C22.4596 59.1246 22.4359 58.9499 22.411 58.7754C22.0613 56.3344 21.4573 53.9904 20.5992 51.7436C20.3539 51.1017 19.9219 50.5311 19.303 50.0319C19.1482 49.9071 18.9819 49.7867 18.8038 49.6709Z',
1181    'M12.4825 50.0327C12.4559 49.9038 12.429 49.7792 12.3877 49.673C12.3458 49.5665 12.2889 49.4842 12.2088 49.4306C12.1288 49.377 12.031 49.3555 11.9166 49.3575C11.8026 49.3597 11.6772 49.3822 11.5478 49.4067C11.3743 49.4412 11.2111 49.4827 11.0583 49.5311C10.4471 49.7248 10.002 50.0298 9.72317 50.4462C8.7471 51.9034 7.99729 53.5121 7.47355 55.2723C7.43616 55.398 7.39994 55.5246 7.36479 55.6518C7.32987 55.7805 7.31856 55.9189 7.35237 56.0492C7.38608 56.1794 7.46103 56.29 7.56694 56.3609C7.67276 56.4318 7.80361 56.459 7.93683 56.4406C8.07014 56.4223 8.19377 56.3592 8.2995 56.2779C8.40382 56.197 8.50706 56.1154 8.6091 56.0328C10.0374 54.8787 11.2397 53.573 12.2156 52.1157C12.4946 51.6994 12.6073 51.1718 12.5538 50.5328C12.5404 50.373 12.5167 50.2063 12.4825 50.0327Z',
1182    'M9.74183 45.4203C9.81949 45.3154 9.89291 45.2104 9.94022 45.1029C9.98748 44.9948 10.0039 44.8895 9.98147 44.7896C9.95888 44.6897 9.89884 44.6017 9.80976 44.5244C9.72087 44.4476 9.60948 44.3843 9.49426 44.3229C9.32298 44.2334 9.15447 44.156 8.98857 44.091C8.32537 43.8305 7.70605 43.7652 7.13072 43.8949C5.1173 44.349 3.16376 45.0686 1.27003 46.0539C1.13477 46.1242 0.999815 46.1959 0.865096 46.269C0.746838 46.3337 0.640167 46.4254 0.57308 46.5444C0.505956 46.6633 0.483664 46.7981 0.512234 46.9252C0.540941 47.0523 0.619017 47.1645 0.730697 47.243C0.842276 47.3218 0.978129 47.3589 1.11266 47.3664C1.26566 47.3746 1.41829 47.3815 1.57073 47.387C3.70392 47.4641 5.77729 47.2755 7.79079 46.8214C8.36604 46.6916 8.89736 46.3668 9.3846 45.8468C9.50643 45.7168 9.62553 45.5747 9.74183 45.4203Z',
1183    'M11.2476 40.6451C11.3682 40.6948 11.4951 40.7331 11.6221 40.7344C11.749 40.7358 11.8655 40.6999 11.9561 40.6266C12.0467 40.5534 12.1062 40.4469 12.1315 40.3225C12.1566 40.1982 12.1458 40.0659 12.1224 39.9378C12.0736 39.6787 12.0152 39.4274 11.9469 39.184C11.6741 38.2105 11.2457 37.3627 10.6618 36.6407C8.6182 34.1137 6.36288 31.7578 3.896 29.5732C3.71971 29.4171 3.54247 29.2619 3.3641 29.1076C3.25909 29.0171 3.12783 28.9551 2.98715 28.9447C2.8466 28.9344 2.70959 28.9755 2.60335 29.0615C2.49708 29.1474 2.42827 29.2728 2.409 29.4123C2.38964 29.5521 2.42277 29.6935 2.48931 29.815C2.60288 30.0217 2.71763 30.2276 2.83333 30.4326C4.45362 33.3019 6.28557 36.0001 8.32914 38.5271C8.91307 39.2491 9.6524 39.8454 10.5473 40.3159C10.7711 40.4335 11.0045 40.5432 11.2476 40.6451Z',
1184    'M15.3567 37.0103C15.4349 37.1141 15.5212 37.2127 15.6245 37.2819C15.728 37.3511 15.8409 37.3852 15.9533 37.3754C16.0656 37.3656 16.
1184171 37.3124 16.2608 37.2263C16.3506 37.1402 16.4185 37.0282 16.4775 36.9124C16.5843 36.6989 16.6786 36.4864 16.7606 36.275C17.0883 35.4295 17.2167 34.6015 17.1459 33.7907C16.898 30.9534 16.379 28.1396 15.5888 25.3496C15.5323 25.1503 15.4745 24.9512 15.4153 24.7521C15.3758 24.6204 15.301 24.4973 15.1906 24.4113C15.0803 24.3253 14.9453 24.2834 14.8107 24.2951C14.6762 24.3069 14.5504 24.3716 14.4568 24.4754C14.3629 24.5792 14.3106 24.7134 14.2945 24.85C14.2708 25.0563 14.2484 25.2625 14.2273 25.4686C13.9328 28.3533 13.9094 31.2144 14.1572 34.0518C14.2281 34.8624 14.4981 35.6557 14.9674 36.4317C15.0847 36.6256 15.2145 36.8185 15.3567 37.0103Z',
1185  ];
1186
1187  const pathsToUse = isRight ? rightPaths : leftPaths;
1188  pathsToUse.forEach((pathData) => {
1189    const path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
1190    path.setAttribute('d', pathData);
1191    path.setAttribute('fill', color);
1192    svg.appendChild(path);
1193  });
1194
1195  return svg;
1196}
1197
1198/**
1199 * Exports isIframe global variable and inIframeFunc function
1200 * in order to prevent JS from interfering with the
1201 * Universal Editor authoring experience
1202 */
1203// eslint-disable-next-line import/no-mutable-exports
1204export let isIframe = false;
1205export function inIframeFunc() {
1206  if (window.location !== window.parent.location) {
1207    // The page is in an iFrames
1208    isIframe = true;
1209  }
1210}
1211
1212init();
1213updateLinkTags();
1214
1215export {
1216  buildBlock,
1217  createOptimizedPicture,
1218  decorateBlock,
1219  decorateBlocks,
1220  decorateButtons,
1221  decorateIcons,
1222  decorateSections,
1223  decorateTemplateAndTheme,
1224  fetchPlaceholders,
1225  getMetadata,
1226  loadBlock,
1227  loadBlocks,
1228  loadCSS,
1229  loadFooter,
1230  loadHeader,
1231  loadErrorPage,
1232  loadScript,
1233  readBlockConfig,
1234  sampleRUM,
1235  setup,
1236  toCamelCase,
1237  toClassName,
1238  stripHtmlTags,
1239  normalizeText,
1240  updateSectionsStatus,
1241  waitForLCP,
1242  wrapTextNodes,
1243  updateLinkTags,
1244  generateElement,
1245  getLocale,
1246  getBrand,
1247  removeNonAlphabetChars,
1248  removeKelloggs,
1249  removeKelloggsEpsilon,
1250  removeNonAlphabetCharsEpsilon,
1251  updateSeoTitle,
1252  getWkkcHomeUrl,
1253  getLocalizedPathByLocale,
1254  appendPathToUrl,
1255  toUrlSlug,
1256  buildBreadcrumbListSchema,
1257  createSparkleIcon,
1258};

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.