PageSourceSearch

https://theroota.com/

html theroota.com collected 2026-10-09 01:40:00 UTC 6,071 bytes, 213 lines download raw bytes

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.