1 2<!doctype html> 3<html lang="en"> 4 <head> 5 <meta charset="UTF-8" /> 6 <link rel="icon" type="image/png" href="https://horizons-cdn.hostinger.com/175f2c8b-ed30-40e8-988f-e1aa4f663d07/d6c4990ea8eff2dea553942bc7ae069.png" /> 7 <meta name="generator" content="Hostinger Horizons" /> 8 <meta name="viewport" content="width=device-width, initial-scale=1.0" /> 9 <meta name="description" content="Roota Hair Growth - Trusted hair growth solution with natural ingredients. Shop the official product page for proven results." /> 10 <title>Roota Hair Growth - Trusted Purchase Page Official</title> 11
11<script type="module" crossorigin src="/assets/index-Dg3nbRXn.js"></script>
11 12 <link rel="stylesheet" crossorigin href="/assets/index-BH_1MMSj.css"> 13
13<script type="module"> 14window.onerror = (message, source, lineno, colno, errorObj) => { 15 const errorDetails = errorObj ? JSON.stringify({ 16 name: errorObj.name, 17 message: errorObj.message, 18 stack: errorObj.stack, 19 source, 20 lineno, 21 colno, 22 }) : null; 23 24 window.parent.postMessage({ 25 type: 'horizons-runtime-error', 26 message, 27 error: errorDetails 28 }, '*'); 29}; 30</script>
30 31
31<script type="module"> 32const observer = new MutationObserver((mutations) => { 33 for (const mutation of mutations) { 34 for (const addedNode of mutation.addedNodes) { 35 if ( 36 addedNode.nodeType === Node.ELEMENT_NODE && 37 ( 38 addedNode.tagName?.toLowerCase() === 'vite-error-overlay' || 39 addedNode.classList?.contains('backdrop') 40 ) 41 ) { 42 handleViteOverlay(addedNode); 43 } 44 } 45 } 46}); 47 48observer.observe(document.documentElement, { 49 childList: true, 50 subtree: true 51}); 52 53function handleViteOverlay(node) { 54 if (!node.shadowRoot) { 55 return; 56 } 57 58 const backdrop = node.shadowRoot.querySelector('.backdrop'); 59 60 if (backdrop) { 61 const overlayHtml = backdrop.outerHTML; 62 const parser = new DOMParser(); 63 const doc = parser.parseFromString(overlayHtml, 'text/html'); 64 const messageBodyElement = doc.querySelector('.message-body'); 65 const fileElement = doc.querySelector('.file'); 66 const messageText = messageBodyElement ? messageBodyElement.textContent.trim() : ''; 67 const fileText = fileElement ? fileElement.textContent.trim() : ''; 68 const error = messageText + (fileText ? ' File:' + fileText : ''); 69 70 window.parent.postMessage({ 71 type: 'horizons-vite-error', 72 error, 73 }, '*'); 74 } 75} 76</script>
76 77
77<script type="module"> 78const originalConsoleError = console.error; 79const MATCH_LINE_COL_REGEX = /:(\d+):(\d+)\)?\s*$/; // regex to match the :lineNum:colNum 80const MATCH_AT_REGEX = /^\s*at\s+(?:async\s+)?(?:.*?\s+)?\(?/; // regex to remove the 'at' keyword and any 'async' or function name 81const MATCH_PATH_REGEX = /^\//; // regex to remove the leading slash 82 83function parseStackFrameLine(line) { 84 const lineColMatch = line.match(MATCH_LINE_COL_REGEX); 85 if (!lineColMatch) return null; 86 const [, lineNum, colNum] = lineColMatch; 87 const suffix = `:${lineNum}:${colNum}`; 88 const idx = line.lastIndexOf(suffix); 89 if (idx === -1) return null; 90 const before = line.substring(0, idx); 91 const path = before.replace(MATCH_AT_REGEX, '').trim(); 92 93 if (!path) return null; 94 95 try { 96 const pathname = new URL(path).pathname; 97 const filePath = pathname.replace(MATCH_PATH_REGEX, '') || pathname; 98 return `${filePath}:${lineNum}:${colNum}`; 99 } catch (e) { 100 const filePath = path.replace(MATCH_PATH_REGEX, '') || path; 101 return `${filePath}:${lineNum}:${colNum}`; 102 } 103} 104 105function getFilePathFromStack(stack, skipFrames = 0) { 106 if (!stack || typeof stack !== 'string') return null; 107 const lines = stack.split('\n').slice(1); 108 109 const frames = lines.map(line => parseStackFrameLine(line.replace(/\r$/, ''))).filter(Boolean); 110 111 return frames[skipFrames] ?? null; 112} 113 114console.error = function(...args) { 115 originalConsoleError.apply(console, args); 116 117 let errorString = ''; 118 let filePath = null; 119 120 for (let i = 0; i < args.length; i++) { 121 const arg = args[i]; 122 if (arg instanceof Error) { 123 filePath = getFilePathFromStack(arg.stack, 0); 124 errorString = `${arg.name}: ${arg.message}`; 125 if (filePath) { 126 errorString = `${errorString} at ${filePath}`; 127 } 128 break; 129 } 130 } 131 132 if (!errorString) { 133 errorString = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' '); 134 const stack = new Error().stack; 135 filePath = getFilePathFromStack(stack, 1); 136 if (filePath) { 137 errorString = `${errorString} at ${filePath}`; 138 } 139 } 140 141 window.parent.postMessage({ 142 type: 'horizons-console-error', 143 error: errorString 144 }, '*'); 145}; 146</script>
146 147
147<script type="module"> 148const originalFetch = window.fetch; 149 150window.fetch = function(...args) { 151 const url = args[0] instanceof Request ? args[0].url : args[0]; 152 153 // Skip WebSocket URLs 154 if (url.startsWith('ws:') || url.startsWith('wss:')) { 155 return originalFetch.apply(this, args); 156 } 157 158 return originalFetch.apply(this, args) 159 .then(async response => { 160 const contentType = response.headers.get('Content-Type') || ''; 161 162 // Exclude HTML document responses 163 const isDocumentResponse = 164 contentType.includes('text/html') || 165 contentType.includes('application/xhtml+xml'); 166 167 if (!response.ok && !isDocumentResponse) { 168 const responseClone = response.clone(); 169 const errorFromRes = await responseClone.text(); 170 const requestUrl = response.url; 171 console.error(`Fetch error from ${requestUrl}: ${errorFromRes}`); 172 } 173 174 return response; 175 }) 176 .catch(error => { 177 if (!url.match(/.html?$/i)) { 178 console.error(error); 179 } 180 181 throw error; 182 }); 183}; 184</script>
184 185
185<script type="module"> 186if (window.navigation && window.self !== window.top) { 187 window.navigation.addEventListener('navigate', (event) => { 188 const url = event.destination.url; 189 190 try { 191 const destinationUrl = new URL(url); 192 const destinationOrigin = destinationUrl.origin; 193 const currentOrigin = window.location.origin; 194 195 if (destinationOrigin === currentOrigin) { 196 return; 197 } 198 } catch (error) { 199 return; 200 } 201 202 window.parent.postMessage({ 203 type: 'horizons-navigation-error', 204 url, 205 }, '*'); 206 }); 207} 208</script>
208 209 </head> 210 <body> 211 <div id="root"></div> 212 </body> 213</html>
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.