PageSourceSearch

https://torsten-gottschall.de/

html torsten-gottschall.de collected 2026-10-09 23:19:36 UTC 10,290 bytes, 304 lines download raw bytes

1<!doctype html>
2<html lang="de">
3	<head>
4		<meta charset="UTF-8" />
5		<link rel="icon" type="image/svg+xml" href="/favicon.svg" />
6		<meta name="generator" content="Hostinger Horizons" />
7		<meta name="viewport" content="width=device-width, initial-scale=1.0" />
8		<title>Terra-Pie - Therapeutische & Pädagogische Praxis</title>
9		<meta name="description" content="Therapeutische Beratung, Life Coaching und wingwave in Kiel und online. Über 20 Jahre Erfahrung, evidenzbasierte Methoden. Termin bei Torsten Gottschall." />
10		<meta name="keywords" content="therapeutische Beratung Kiel, Life Coaching Kiel, wingwave Coaching, Coaching online, Psychotherapie Beratung, Torsten Gottschall, Terra-Pie, Easy Weight, Supervision, Konfliktberatung, Mobbingberatung, Trauerbegleitung, Paarberatung, Seminare, Mental Health" />
11		<meta name="robots" content="index, follow, max-image-preview:large, max-snippet:-1, max-video-preview:-1" />
12		<link rel="canonical" href="https://torsten-gottschall.de/" />
13		<meta property="og:type" content="website" />
14		<meta property="og:locale" content="de_DE" />
15		<meta property="og:site_name" content="Terra-Pie – Torsten Gottschall" />
16		<meta property="og:title" content="Therapeutische Beratung & Coaching in Kiel | Terra-Pie" />
17		<meta property="og:description" content="Therapeutische Beratung, Life Coaching und wingwave in Kiel und online. Über 20 Jahre Erfahrung, evidenzbasierte Methoden. Termin bei Torsten Gottschall." />
18		<meta property="og:url" content="https://torsten-gottschall.de/" />
19		<meta property="og:image" content="https://horizons-cdn.hostinger.com/5afb7969-abff-4799-b3f5-b7b6f9dda281/2589_2-032full-c-soulpicture-NqBSb.jpg" />
20		<meta name="twitter:card" content="summary_large_image" />
21		<meta name="twitter:title" content="Therapeutische Beratung & Coaching in Kiel | Terra-Pie" />
22		<meta name="twitter:description" content="Therapeutische Beratung, Life Coaching und wingwave in Kiel und online. Über 20 Jahre Erfahrung, evidenzbasierte Methoden. Termin bei Torsten Gottschall." />
23		<meta name="twitter:image" content="https://horizons-cdn.hostinger.com/5afb7969-abff-4799-b3f5-b7b6f9dda281/2589_2-032full-c-soulpicture-NqBSb.jpg" />
24		<link rel="preconnect" href="https://fonts.googleapis.com">
25		<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
26		<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
27		
27<script type="module" crossorigin src="/assets/index-4Y6CaQow.js"></script>
27
28		<link rel="stylesheet" crossorigin href="/assets/index-qP4x9G2Y.css">
29		
29<script type="module">
30window.onerror = (message, source, lineno, colno, errorObj) => {
31	const errorDetails = errorObj ? JSON.stringify({
32		name: errorObj.name,
33		message: errorObj.message,
34		stack: errorObj.stack,
35		source,
36		lineno,
37		colno,
38	}) : null;
39
40	window.parent.postMessage({
41		type: 'horizons-runtime-error',
42		message,
43		error: errorDetails
44	}, '*');
45};
46</script>
46
47		
47<script type="module">
48const observer = new MutationObserver((mutations) => {
49	for (const mutation of mutations) {
50		for (const addedNode of mutation.addedNodes) {
51			if (
52				addedNode.nodeType === Node.ELEMENT_NODE &&
53				(
54					addedNode.tagName?.toLowerCase() === 'vite-error-overlay' ||
55					addedNode.classList?.contains('backdrop')
56				)
57			) {
58				handleViteOverlay(addedNode);
59			}
60		}
61	}
62});
63
64observer.observe(document.documentElement, {
65	childList: true,
66	subtree: true
67});
68
69function handleViteOverlay(node) {
70	if (!node.shadowRoot) {
71		return;
72	}
73
74	const backdrop = node.shadowRoot.querySelector('.backdrop');
75
76	if (backdrop) {
77		const overlayHtml = backdrop.outerHTML;
78		const parser = new DOMParser();
79		const doc = parser.parseFromString(overlayHtml, 'text/html');
80		const messageBodyElement = doc.querySelector('.message-body');
81		const fileElement = doc.querySelector('.file');
82		const messageText = messageBodyElement ? messageBodyElement.textContent.trim() : '';
83		const fileText = fileElement ? fileElement.textContent.trim() : '';
84		const error = messageText + (fileText ? ' File:' + fileText : '');
85
86		window.parent.postMessage({
87			type: 'horizons-vite-error',
88			error,
89		}, '*');
90	}
91}
92</script>
92
93		
93<script type="module">
94const originalConsoleError = console.error;
95const MATCH_LINE_COL_REGEX = /:(\d+):(\d+)\)?\s*$/; // regex to match the :lineNum:colNum
96const MATCH_AT_REGEX = /^\s*at\s+(?:async\s+)?(?:.*?\s+)?\(?/; // regex to remove the 'at' keyword and any 'async' or function name
97const MATCH_PATH_REGEX = /^\//; // regex to remove the leading slash
98
99function parseStackFrameLine(line) {
100	const lineColMatch = line.match(MATCH_LINE_COL_REGEX);
101	if (!lineColMatch) return null;
102	const [, lineNum, colNum] = lineColMatch;
103	const suffix = `:${lineNum}:${colNum}`;
104	const idx = line.lastIndexOf(suffix);
105	if (idx === -1) return null;
106	const before = line.substring(0, idx);
107	const path = before.replace(MATCH_AT_REGEX, '').trim();
108	
109	if (!path) return null;
110
111	try {
112		const pathname = new URL(path).pathname;
113		const filePath = pathname.replace(MATCH_PATH_REGEX, '') || pathname;
114		return `${filePath}:${lineNum}:${colNum}`;
115	} catch (e) {
116		const filePath = path.replace(MATCH_PATH_REGEX, '') || path;
117		return `${filePath}:${lineNum}:${colNum}`;
118	}
119}
120
121function getFilePathFromStack(stack, skipFrames = 0) {
122	if (!stack || typeof stack !== 'string') return null;
123	const lines = stack.split('\n').slice(1);
124
125	const frames = lines.map(line => parseStackFrameLine(line.replace(/\r$/, ''))).filter(Boolean);
126
127	return frames[skipFrames] ?? null;
128}
129
130function formatConsoleMessage(args, skipStackFrames = 1) {
131	let messageString = '';
132	let filePath = null;
133
134	for (let i = 0; i < args.length; i++) {
135		const arg = args[i];
136		if (arg instanceof Error) {
137			filePath = getFilePathFromStack(arg.stack, 0);
138			messageString = `${arg.name}: ${arg.message}`;
139			if (filePath) {
140				messageString = `${messageString} at ${filePath}`;
141			}
142			break;
143		}
144	}
145
146	if (!messageString) {
147		messageString = args.map(arg => typeof arg === 'object' ? JSON.stringify(arg) : String(arg)).join(' ');
148		const stack = new Error().stack;
149		filePath = getFilePathFromStack(stack, skipStackFrames);
150		if (filePath) {
151			messageString = `${messageString} at ${filePath}`;
152		}
153	}
154
155	return messageString;
156}
157
158console.error = function(...args) {
159	originalConsoleError.apply(console, args);
160
161	window.parent.postMessage({
162		type: 'horizons-console-error',
163		error: formatConsoleMessage(args, 1)
164	}, '*');
165};
166
167const originalConsoleWarn = console.warn;
168
169console.warn = function(...args) {
170	originalConsoleWarn.apply(console, args);
171
172	window.parent.postMessage({
173		type: 'horizons-console-warn',
174		warning: formatConsoleMessage(args, 1)
175	}, '*');
176};
177</script>
177
178		
178<script type="module">
179// Prevents authentication failures (PB returns 400) from crashing the app — use console.info, not console.error/PM2.
180// [urlPattern, bodyPattern] tuples; align with sandboxErrorUtils ERROR_BLACKLIST.
181const BENIGN_FETCH_ERRORS = [
182	[/hcgi\/platform\/api\/collections\/.*auth-with-password.*/i, /Failed to authenticate/i],
183	[/hcgi\/api\//i, /Insufficient credits/i],
184	// A user-supplied integration secret (Stripe/PayPal/Twilio/...) is not set yet — an expected setup state, not a bug to fix.
185	[/hcgi\/api\//i, /INTEGRATION_NOT_CONFIGURED/i],
186];
187
188function isBenignFetchError(url, body) {
189	return BENIGN_FETCH_ERRORS.some(([urlPattern, bodyPattern]) =>
190		urlPattern.test(url) && (!bodyPattern || bodyPattern.test(body)));
191}
192
193const PLATFORM_URL_PATTERN = /hcgi\/platform\//i;
194const VALIDATION_CODE_TEXT_PATTERN = /validation_/;
195
196function hasValidationCode(value) {
197	if (value == null) {
198		return false;
199	}
200	if (typeof value === 'string') {
201		return value.startsWith('validation_');
202	}
203	if (Array.isArray(value)) {
204		return value.some(hasValidationCode);
205	}
206	if (typeof value === 'object') {
207		return Object.values(value).some(hasValidationCode);
208	}
209	return false;
210}
211
212function isValidationFetchWarning(url, body) {
213	if (!PLATFORM_URL_PATTERN.test(url)) {
214		return false;
215	}
216	try {
217		return hasValidationCode(JSON.parse(body));
218	} catch {
219		return VALIDATION_CODE_TEXT_PATTERN.test(body);
220	}
221}
222
223const originalFetch = window.fetch;
224
225window.fetch = function(...args) {
226	const url = args[0] instanceof Request ? args[0].url : args[0];
227
228	// Skip WebSocket URLs
229	if (url.startsWith('ws:') || url.startsWith('wss:')) {
230		return originalFetch.apply(this, args);
231	}
232
233	return originalFetch.apply(this, args)
234		.then(async response => {
235			const contentType = response.headers.get('Content-Type') || '';
236
237			// Exclude HTML document responses
238			const isDocumentResponse =
239				contentType.includes('text/html') ||
240				contentType.includes('application/xhtml+xml');
241
242			// no-cors requests (e.g. Google Analytics/Ads beacons) always return an opaque
243			const isOpaqueResponse = response.type === 'opaque';
244
245			if (!response.ok && !isDocumentResponse && !isOpaqueResponse) {
246					const responseClone = response.clone();
247					const errorFromRes = await responseClone.text();
248					const requestUrl = response.url;
249					const errorMessage = `Fetch error from ${requestUrl}: ${errorFromRes}`;
250
251					if (isBenignFetchError(requestUrl, errorFromRes)) {
252						console.info(errorMessage);
253					} else if (isValidationFetchWarning(requestUrl, errorFromRes)) {
254						console.warn(errorMessage);
255					} else {
256						console.error(errorMessage);
257					}
258			}
259
260			return response;
261		})
262		.catch(error => {
263			if (!url.match(/.html?$/i)) {
264				// Cancelled in-flight fetch (e.g. preview reload) — not a server failure.
265				if (error?.name === 'AbortError') {
266					console.info(error);
267				} else {
268					console.error(error);
269				}
270			}
271
272			throw error;
273		});
274};
275</script>
275
276		
276<script type="module">
277if (window.navigation && window.self !== window.top) {
278	window.navigation.addEventListener('navigate', (event) => {
279		const url = event.destination.url;
280
281		try {
282			const destinationUrl = new URL(url);
283			const destinationOrigin = destinationUrl.origin;
284			const currentOrigin = window.location.origin;
285
286			if (destinationOrigin === currentOrigin) {
287				return;
288			}
289		} catch (error) {
290			return;
291		}
292
293		window.parent.postMessage({
294			type: 'horizons-navigation-error',
295			url,
296		}, '*');
297	});
298}
299</script>
299
300	</head>
301	<body>
302		<div id="root"></div>
303	</body>
304</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.