1const paginatedFetch = async (url, key, page = 1, previousResponse = []) => { 2 try { 3 const response = await fetch( 4 `${url}?sort_by=position&sort_order=asc&per_page=100&page=${page}`, 5 { 6 method: "GET", 7 headers: { 8 accept: "application/json", 9 }, 10 } 11 ); 12 13 if (!response.ok) throw response; 14 15 const responseJSON = await response.json(); 16 17 const data = [...previousResponse, ...responseJSON[key]]; 18 19 if (!!responseJSON.next_page) { 20 page++; 21 return paginatedFetch(url, key, page, data); 22 } 23 return data; 24 } catch (error) { 25 console.error(`Error fetching ${key} API`, error); 26 27 const eventLabel = 28 error instanceof Response 29 ? `${error.status} - in paginatedFetch request - url: ${error.url}` 30 : `${error.name}: ${error.message} - in paginatedFetch request - url: ${window.location.protocol}//${window.location.hostname}${url}`; 31 32 // Send information about the error to Google Analytics 33 gtag("event", "Zendesk API", { 34 event_category: "Help Center Error", 35 event_label: eventLabel, 36 }); 37 } 38}; 39 40const excludePageFromIndexing = () => { 41 const meta = document.createElement("meta"); 42 meta.name = "robots"; 43 meta.content = "noindex"; 44 document.querySelector("head").append(meta); 45}; 46 47function standardizeLocale(locale, useBackendDict) { 48 if (useBackendDict) { 49 return guideToGCPLocaleBackendDict[locale]; 50 } 51 return guideToGCPLocale[locale]; 52} 53 54// Execute reCAPTCHA v3 Invisible Enterprise for algorithm training 55function executeRecaptchaTraining( 56 // The action name for reCAPTCHA (e.g., 'page_view', 'article_view', etc.) 57 action = "page_view", 58 siteKey 59) { 60 if (!siteKey) { 61 console.warn("reCAPTCHA site key not provided "); 62 return; 63 } 64 65 if (typeof grecaptcha !== "undefined" && grecaptcha.enterprise) { 66 grecaptcha.enterprise.ready(() => { 67 grecaptcha.enterprise 68 .execute(siteKey, { action }) 69 .then(() => { 70 console.log(`reCAPTCHA v3 executed for action ${action}`); 71 gtag("event", "reCAPTCHA", { 72 event_category: "reCAPTCHA Success", 73 event_label: `reCAPTCHA v3 executed for action ${action}`, 74 }); 75 }) 76 .catch((error) => { 77 gtag("event", "reCAPTCHA", { 78 event_category: "reCAPTCHA Error", 79 event_label: `reCAPTCHA v3 training execution failed for action ${action}: ${error}`, 80 }); 81 }); 82 }); 83 } else { 84 gtag("event", "reCAPTCHA", { 85 event_category: "reCAPTCHA Error", 86 event_label: "reCAPTCHA v3 is not available for page monitoring", 87 }); 88 } 89} 90 91// Initialize reCAPTCHA training on page load 92function initRecaptchaTraining(action, siteKey) { 93 const disclaimerEligibleActions = [ 94 "cuf_cant_access_account_page_view", 95 "cuf_found_a_bug_page_view", 96 "cuf_feedback_page_view", 97 "cuf_delete_account_page_view", 98 "cuf_snapstreak_page_view", 99 "cuf_safety_reporting_page_view", 100 "cuf_privacy_questions_page_view", 101 "cuf_infringement_page_view", 102 "article_page_view", 103 "category_page_view", 104 "home_page_view", 105 "search_results_page_view", 106 "section_page_view", 107 ]; 108 109 function executeOnLoad() { 110 executeRecaptchaTraining(action, siteKey); 111 112 // Show reCAPTCHA disclaimer if this page is eligible 113 if (disclaimerEligibleActions.includes(action)) { 114 const disclaimer = document.querySelector(".recaptcha-disclaimer"); 115 if (disclaimer) { 116 disclaimer.classList.add("recaptcha-disclaimer-visible"); 117 } 118 } 119 } 120 121 if (document.readyState === "loading") { 122 document.addEventListener("DOMContentLoaded", executeOnLoad); 123 } else { 124 executeOnLoad(); 125 } 126} 127 128function decodeJwt(token) { 129 const payload = token.split(".")[1]; 130 return payload 131 ? JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/"))) 132 : null; 133} 134 135function startJwtExpiryTimer( 136 token, 137 targetElement, 138 textNonExpired, 139 onExpire, 140 onError 141) { 142 if (!token) { 143 if (onError) onError(); 144 return null; 145 } 146 147 let decoded = null; 148 149 try { 150 decoded = decodeJwt(token); 151 } catch (error) { 152 if (onError) onError(); 153 return null; 154 } 155 156 const exp = decoded ? decoded.exp : null; 157 158 if (!exp) { 159 if (onError) onError(); 160 return null; 161 } 162 163 let timerContainer = document.getElementById("jwt-expiry-timer"); 164 165 if (!timerContainer) { 166 timerContainer = document.createElement("div"); 167 timerContainer.id = "jwt-expiry-timer"; 168 timerContainer.classList.add("jwt-expiry-timer-container"); 169 170 if (targetElement) { 171 targetElement.appendChild(timerContainer); 172 } 173 } 174 175 let intervalId; 176 177 const updateTimer = () => { 178 const now = Math.floor(Date.now() / 1000); 179 const remaining = exp - now; 180 181 if (remaining <= 0) { 182 timerContainer.textContent = ""; 183 if (intervalId) clearInterval(intervalId); 184 if (onExpire) onExpire(); 185 return true; 186 } 187 188 const minutes = Math.floor(remaining / 60); 189 const seconds = remaining % 60; 190 timerContainer.textContent = `â ï¸ ${textNonExpired} ${minutes}:${seconds 191 .toString() 192 .padStart(2, "0")}`; 193 return false;
194 }; 195 196 if (!updateTimer()) { 197 if (timerContainer.dataset.intervalId) { 198 clearInterval(Number(timerContainer.dataset.intervalId)); 199 } 200 intervalId = setInterval(updateTimer, 1000); 201 timerContainer.dataset.intervalId = intervalId; 202 } 203 204 return { stop: () => clearInterval(intervalId), container: timerContainer }; 205}
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.