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