commit 33a8b18147e0878e30926f85cdc6ea73f15a5e0c Author: oliver Date: Sat Sep 19 07:28:18 2026 -0300 hallo knut diff --git a/README.md b/README.md new file mode 100644 index 0000000..da399ce --- /dev/null +++ b/README.md @@ -0,0 +1,93 @@ +# Interval Timer + +A mobile-first interval training timer that installs as a Progressive Web App. +No build step, no dependencies, no network calls — just static files. + +## The cycle + +For every set, each exercise gets a **pause** followed by a **training** block: + +``` +for each set: + for each exercise: + pause (default 15s) text is grey + training (default 45s) text turns red +``` + +- **Start** rings a bell, shows the first exercise in grey and runs the pause. +- When the pause ends a beep plays and the text turns **red** for the training block. +- When training ends another beep plays, the next exercise appears and its pause begins. +- After the last exercise of the last set, a triple bell rings and the screen shows *Workout complete*. + +`Pause` / `Resume` freezes the clock; `Reset` returns to the start. The screen is kept +awake during a session via the Screen Wake Lock API. + +## Files + +| Path | Purpose | +| --- | --- | +| `index.html` | Markup: stage, controls, settings | +| `styles.css` | Dark theme; grey/red phase colours | +| `app.js` | Timer state machine, Web Audio bell/beep, exercise list | +| `manifest.webmanifest` | PWA metadata and icons | +| `sw.js` | Service worker — app shell cached for offline use | +| `icons/` | Generated app icons | +| `tools/make_icons.py` | Regenerates the icons (needs Pillow) | +| `tools/smoke_test.mjs` | Headless-Chrome test of the whole cycle | +| `start` | Your local live-server launcher (port 8080) | + +Settings and the exercise list are stored in `localStorage`, so they survive a reload. + +## Running it on your phone + +PWA installation and offline caching require a **secure context** (HTTPS, or +`localhost`). A plain `http://:8080` URL works as a normal web page but +will not be installable and will not cache offline. + +### 1. Serve the files + +```sh +cd timer +python3 -m http.server 8080 +# or, using the ./start script (Node + live-server, auto-reload) +./start +``` + +### 2. Give your phone an HTTPS URL + +Either expose the local server through a tunnel, for example: + +```sh +cloudflared tunnel --url http://localhost:8080 +# or: npx localtunnel --port 8080 +``` + +or upload the folder as-is to any static host (GitHub Pages, Netlify, Cloudflare +Pages, Vercel). There is nothing to compile. + +### 3. Install + +Open the HTTPS URL on the phone and use **Add to Home Screen** (Safari: Share +menu; Chrome: banner or the ⋮ menu → *Install app*). It then launches fullscreen +and works offline. + +### Audio notes + +- The bell and beeps are synthesised with the Web Audio API, so there are no sound + files to download and they work offline. +- Audio is unlocked by the first tap on **Start**, as mobile browsers require. +- On iOS the ringer/silent switch still mutes Web Audio playback — turn silent mode + off for a workout. + +## Tests + +With a server on `127.0.0.1:8765` and Chrome running with `--remote-debugging-port=9222`: + +```sh +cd timer +node tools/smoke_test.mjs +``` + +The test drives the real page and asserts the exact pause/training sequence for +2 sets × 3 exercises, the grey→red colour switch, phase durations, the frozen clock +while paused, reset/restart behaviour and settings persistence. \ No newline at end of file diff --git a/app.js b/app.js new file mode 100644 index 0000000..f592531 --- /dev/null +++ b/app.js @@ -0,0 +1,519 @@ +(() => { + 'use strict'; + + const STORAGE_KEY = 'interval-timer/v1'; + const TICK_MS = 100; + + const els = { + body: document.body, + stage: document.getElementById('stage'), + progress: document.getElementById('progress'), + phaseLabel: document.getElementById('phaseLabel'), + exerciseName: document.getElementById('exerciseName'), + clock: document.getElementById('clock'), + nextUp: document.getElementById('nextUp'), + startBtn: document.getElementById('startBtn'), + pauseBtn: document.getElementById('pauseBtn'), + resetBtn: document.getElementById('resetBtn'), + settingsToggle: document.getElementById('settingsToggle'), + settings: document.getElementById('settings'), + pauseInput: document.getElementById('pauseInput'), + workInput: document.getElementById('workInput'), + setsInput: document.getElementById('setsInput'), + exerciseList: document.getElementById('exerciseList'), + emptyHint: document.getElementById('emptyHint'), + exerciseInput: document.getElementById('exerciseInput'), + addBtn: document.getElementById('addBtn'), + installHint: document.getElementById('installHint'), + }; + + const DEFAULTS = { pauseSec: 15, workSec: 45, sets: 5, exercises: [] }; + + /* ------------------------------------------------------------------ * + * settings persistence + * ------------------------------------------------------------------ */ + + function loadSettings() { + try { + const raw = localStorage.getItem(STORAGE_KEY); + if (!raw) return { ...DEFAULTS }; + const parsed = JSON.parse(raw); + return { + pauseSec: clampInt(parsed.pauseSec, 0, 3600, DEFAULTS.pauseSec), + workSec: clampInt(parsed.workSec, 1, 3600, DEFAULTS.workSec), + sets: clampInt(parsed.sets, 1, 999, DEFAULTS.sets), + exercises: Array.isArray(parsed.exercises) + ? parsed.exercises.filter((e) => typeof e === 'string' && e.trim()).map((e) => e.trim()) + : [], + }; + } catch { + return { ...DEFAULTS }; + } + } + + function saveSettings() { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); + } catch { + /* storage unavailable (private mode) — the app still works in memory */ + } + } + + function clampInt(value, min, max, fallback) { + const n = Math.round(Number(value)); + if (!Number.isFinite(n)) return fallback; + return Math.min(max, Math.max(min, n)); + } + + const settings = loadSettings(); + + /* ------------------------------------------------------------------ * + * runtime state + * ------------------------------------------------------------------ */ + + const run = { + phase: 'idle', // idle | pause | work | done + setIndex: 0, + exIndex: 0, + remaining: 0, + deadline: 0, + paused: false, + pausedRemaining: 0, + timerId: null, + }; + + const isActive = () => run.phase === 'pause' || run.phase === 'work'; + + /* ------------------------------------------------------------------ * + * audio — synthesised, so the app needs no sound files and works offline + * ------------------------------------------------------------------ */ + + let audioCtx = null; + + function ensureAudio() { + try { + const Ctx = window.AudioContext || window.webkitAudioContext; + if (!Ctx) return null; + if (!audioCtx) audioCtx = new Ctx(); + if (audioCtx.state === 'suspended') audioCtx.resume().catch(() => {}); + return audioCtx; + } catch { + return null; // audio unavailable — the timer must still run + } + } + + function tone(freq, delay, duration, peak, type) { + if (!ensureAudio()) return; + const ctx = audioCtx; + const t0 = ctx.currentTime + delay; + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.type = type || 'sine'; + osc.frequency.setValueAtTime(freq, t0); + gain.gain.setValueAtTime(0.0001, t0); + gain.gain.exponentialRampToValueAtTime(peak, t0 + 0.012); + gain.gain.exponentialRampToValueAtTime(0.0001, t0 + duration); + osc.connect(gain).connect(ctx.destination); + osc.start(t0); + osc.stop(t0 + duration + 0.05); + } + + /** Bell: a few inharmonic partials with long decay. */ + function bell(count) { + if (!ensureAudio()) return; + const rings = count || 1; + for (let i = 0; i < rings; i++) { + const at = i * 0.55; + tone(880, at, 1.6, 0.32, 'sine'); + tone(1320, at, 1.1, 0.16, 'sine'); + tone(1760, at, 0.7, 0.09, 'sine'); + tone(587, at, 1.9, 0.12, 'sine'); + } + } + + /** Short beep marking a phase change. Higher = training, lower = pause. */ + function beep(freq) { + if (!ensureAudio()) return; + tone(freq, 0, 0.16, 0.3, 'square'); + tone(freq * 2, 0, 0.1, 0.08, 'sine'); + } + + function vibrate(pattern) { + if (navigator.vibrate) { + try { navigator.vibrate(pattern); } catch { /* ignore */ } + } + } + + /* ------------------------------------------------------------------ * + * screen wake lock — keeps the phone display on during a session + * ------------------------------------------------------------------ */ + + let wakeLock = null; + + async function requestWakeLock() { + if (!('wakeLock' in navigator)) return; + try { + wakeLock = await navigator.wakeLock.request('screen'); + wakeLock.addEventListener('release', () => { wakeLock = null; }); + } catch { + /* denied or unsupported — not fatal */ + } + } + + function releaseWakeLock() { + if (wakeLock) { + wakeLock.release().catch(() => {}); + wakeLock = null; + } + } + + /* ------------------------------------------------------------------ * + * timer engine — phases chain off their own deadline, so a throttled or + * suspended page catches up to real elapsed time instead of drifting + * ------------------------------------------------------------------ */ + + const MAX_CATCHUP = 5000; + + function startTimer() { + if (run.timerId !== null) return; + run.timerId = window.setInterval(tick, TICK_MS); + } + + function stopTimer() { + if (run.timerId !== null) { + window.clearInterval(run.timerId); + run.timerId = null; + } + } + + function tick() { + if (!isActive() || run.paused) return; + + const now = performance.now(); + const late = now - run.deadline; + + if (late < 0) { + run.remaining = -late / 1000; + render(); + return; + } + + // One or more phases ended while we were not ticking (timer throttling). + // Play the cue only for a prompt transition, not for a bulk catch-up. + let steps = 0; + while (isActive() && !run.paused && run.deadline <= now && steps < MAX_CATCHUP) { + advance(steps === 0 && late < 1500); + steps++; + } + + if (!isActive()) return; + run.remaining = Math.max(0, (run.deadline - now) / 1000); + render(); + } + + /** `from` anchors the new phase to the previous phase's deadline. */ + function beginPhase(phase, from) { + run.phase = phase; + const duration = phase === 'pause' ? settings.pauseSec : settings.workSec; + run.remaining = duration; + run.deadline = (from === undefined ? performance.now() : from) + duration * 1000; + render(); + } + + function advance(playSound) { + if (run.phase === 'pause') { + // pause finished -> training starts, text turns red + if (playSound) { beep(1180); vibrate(140); } + beginPhase('work', run.deadline); + return; + } + + if (run.phase === 'work') { + // training finished -> line up the next exercise + const from = run.deadline; + run.exIndex += 1; + if (run.exIndex >= settings.exercises.length) { + run.exIndex = 0; + run.setIndex += 1; + } + if (run.setIndex >= settings.sets) { + finish(); + return; + } + if (playSound) { beep(720); vibrate(140); } + beginPhase('pause', from); + } + } + + function start() { + if (settings.exercises.length === 0) { + openSettings(); + els.exerciseInput.focus(); + return; + } + ensureAudio(); // must happen inside the user gesture + run.setIndex = 0; + run.exIndex = 0; + run.paused = false; + run.pausedRemaining = 0; + bell(1); + vibrate(300); + requestWakeLock(); + startTimer(); + beginPhase('pause'); + } + + function togglePause() { + if (!isActive()) return; + if (run.paused) { + run.paused = false; + run.deadline = performance.now() + run.pausedRemaining * 1000; + } else { + run.paused = true; + run.pausedRemaining = Math.max(0, (run.deadline - performance.now()) / 1000); + } + render(); + } + + function finish() { + run.phase = 'done'; + run.remaining = 0; + run.paused = false; + stopTimer(); + releaseWakeLock(); + bell(3); + vibrate([250, 120, 250, 120, 500]); + render(); + } + + function reset() { + run.phase = 'idle'; + run.setIndex = 0; + run.exIndex = 0; + run.remaining = 0; + run.paused = false; + run.pausedRemaining = 0; + stopTimer(); + releaseWakeLock(); + render(); + } + + /* ------------------------------------------------------------------ * + * rendering + * ------------------------------------------------------------------ */ + + function formatTime(seconds) { + const total = Math.max(0, Math.ceil(seconds)); + const m = Math.floor(total / 60); + const s = total % 60; + return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; + } + + function nextExerciseAfterWork() { + let ex = run.exIndex + 1; + let set = run.setIndex; + if (ex >= settings.exercises.length) { + ex = 0; + set += 1; + } + if (set >= settings.sets) return null; + return settings.exercises[ex]; + } + + function render() { + const total = settings.exercises.length; + const current = total ? settings.exercises[run.exIndex] : null; + + els.body.classList.toggle('phase-work', run.phase === 'work'); + els.body.classList.toggle('phase-done', run.phase === 'done'); + els.body.classList.toggle('phase-paused', run.paused); + + if (run.phase === 'idle') { + els.progress.textContent = total + ? `${settings.sets} set${settings.sets === 1 ? '' : 's'} · ${total} exercise${total === 1 ? '' : 's'}` + : ''; + els.phaseLabel.textContent = 'Ready'; + els.exerciseName.textContent = current || 'Add your exercises'; + els.clock.textContent = formatTime(settings.pauseSec); + els.nextUp.textContent = total + ? `Pause ${settings.pauseSec}s, then ${settings.workSec}s training` + : ''; + } else if (run.phase === 'done') { + els.progress.textContent = 'Complete'; + els.phaseLabel.textContent = 'Done'; + els.exerciseName.textContent = 'Workout complete'; + els.clock.textContent = '00:00'; + els.nextUp.textContent = `${settings.sets} set${settings.sets === 1 ? '' : 's'} finished`; + } else { + els.progress.textContent = + `Set ${run.setIndex + 1} / ${settings.sets} · Exercise ${run.exIndex + 1} / ${total}`; + els.phaseLabel.textContent = run.paused + ? 'Paused' + : run.phase === 'work' ? 'Training' : 'Pause'; + els.exerciseName.textContent = current || ''; + els.clock.textContent = formatTime(run.remaining); + + if (run.phase === 'pause') { + els.nextUp.textContent = `Next: ${settings.workSec}s training`; + } else { + const next = nextExerciseAfterWork(); + els.nextUp.textContent = next ? `Next: ${next}` : 'Last one — finish strong'; + } + } + + renderControls(); + } + + function renderControls() { + const active = isActive(); + els.startBtn.hidden = active; + els.startBtn.textContent = run.phase === 'done' ? 'Restart' : 'Start'; + els.pauseBtn.hidden = !active; + els.pauseBtn.textContent = run.paused ? 'Resume' : 'Pause'; + els.resetBtn.hidden = !active && run.phase !== 'done'; + + const lock = active; + els.pauseInput.disabled = lock; + els.workInput.disabled = lock; + els.setsInput.disabled = lock; + els.exerciseInput.disabled = lock; + els.addBtn.disabled = lock; + els.exerciseList.querySelectorAll('button').forEach((b) => { b.disabled = lock; }); + } + + function renderExerciseList() { + els.exerciseList.textContent = ''; + settings.exercises.forEach((name, i) => { + const li = document.createElement('li'); + + const idx = document.createElement('span'); + idx.className = 'idx'; + idx.textContent = `${i + 1}.`; + + const label = document.createElement('span'); + label.className = 'name'; + label.textContent = name; + + const remove = document.createElement('button'); + remove.type = 'button'; + remove.className = 'remove-btn'; + remove.textContent = '\u00d7'; + remove.setAttribute('aria-label', `Remove ${name}`); + remove.addEventListener('click', () => { + settings.exercises.splice(i, 1); + saveSettings(); + renderExerciseList(); + render(); + }); + + li.append(idx, label, remove); + els.exerciseList.append(li); + }); + + els.emptyHint.hidden = settings.exercises.length > 0; + renderControls(); + } + + /* ------------------------------------------------------------------ * + * settings UI + * ------------------------------------------------------------------ */ + + function openSettings() { + els.settings.hidden = false; + els.settingsToggle.setAttribute('aria-expanded', 'true'); + } + + function toggleSettings() { + const open = els.settings.hidden; + els.settings.hidden = !open; + els.settingsToggle.setAttribute('aria-expanded', String(open)); + } + + function addExercise() { + const name = els.exerciseInput.value.trim(); + if (!name) return; + settings.exercises.push(name); + saveSettings(); + els.exerciseInput.value = ''; + renderExerciseList(); + render(); + els.exerciseInput.focus(); + } + + function bindNumberInput(input, key, min, max) { + input.value = String(settings[key]); + input.addEventListener('change', () => { + settings[key] = clampInt(input.value, min, max, DEFAULTS[key]); + input.value = String(settings[key]); + saveSettings(); + render(); + }); + } + + /* ------------------------------------------------------------------ * + * wiring + * ------------------------------------------------------------------ */ + + bindNumberInput(els.pauseInput, 'pauseSec', 0, 3600); + bindNumberInput(els.workInput, 'workSec', 1, 3600); + bindNumberInput(els.setsInput, 'sets', 1, 999); + + els.startBtn.addEventListener('click', start); + els.pauseBtn.addEventListener('click', togglePause); + els.resetBtn.addEventListener('click', reset); + els.settingsToggle.addEventListener('click', toggleSettings); + els.addBtn.addEventListener('click', addExercise); + els.exerciseInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + addExercise(); + } + }); + + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + if (isActive() && !run.paused) tick(); + if (isActive() && !wakeLock) requestWakeLock(); + } + }); + + // space bar toggles pause on desktop + document.addEventListener('keydown', (e) => { + if (e.code === 'Space' && isActive() && e.target.tagName !== 'INPUT') { + e.preventDefault(); + togglePause(); + } + }); + + renderExerciseList(); + render(); + + /* ------------------------------------------------------------------ * + * PWA: service worker + install prompt + * ------------------------------------------------------------------ */ + + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('./sw.js').catch(() => {}); + }); + } + + let deferredPrompt = null; + window.addEventListener('beforeinstallprompt', (e) => { + e.preventDefault(); + deferredPrompt = e; + const btn = document.createElement('button'); + btn.type = 'button'; + btn.className = 'btn'; + btn.textContent = 'Install app'; + btn.addEventListener('click', async () => { + if (!deferredPrompt) return; + deferredPrompt.prompt(); + await deferredPrompt.userChoice; + deferredPrompt = null; + els.installHint.textContent = ''; + }); + els.installHint.textContent = ''; + els.installHint.append(btn); + }); +})(); diff --git a/icons/icon-192.png b/icons/icon-192.png new file mode 100644 index 0000000..b64e463 Binary files /dev/null and b/icons/icon-192.png differ diff --git a/icons/icon-512.png b/icons/icon-512.png new file mode 100644 index 0000000..2c24f2a Binary files /dev/null and b/icons/icon-512.png differ diff --git a/icons/icon-maskable-512.png b/icons/icon-maskable-512.png new file mode 100644 index 0000000..e8ade1b Binary files /dev/null and b/icons/icon-maskable-512.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..4a6717b --- /dev/null +++ b/index.html @@ -0,0 +1,81 @@ + + + + + + + + + + + + + + +Interval Timer + + + +
+

Interval Timer

+ +
+ +
+
+ +
Ready
+ +
Add your exercises
+ +
00:00
+ + +
+ +
+ + + +
+ + + +
+ +
+ + + + diff --git a/manifest.webmanifest b/manifest.webmanifest new file mode 100644 index 0000000..6bb6444 --- /dev/null +++ b/manifest.webmanifest @@ -0,0 +1,32 @@ +{ + "name": "Interval Timer", + "short_name": "Timer", + "description": "Interval training timer: pause, training, sets and exercises.", + "start_url": "./", + "scope": "./", + "display": "standalone", + "orientation": "portrait", + "background_color": "#0e0e11", + "theme_color": "#0e0e11", + "categories": ["health", "fitness", "sports"], + "icons": [ + { + "src": "./icons/icon-192.png", + "sizes": "192x192", + "type": "image/png", + "purpose": "any" + }, + { + "src": "./icons/icon-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "any" + }, + { + "src": "./icons/icon-maskable-512.png", + "sizes": "512x512", + "type": "image/png", + "purpose": "maskable" + } + ] +} diff --git a/start b/start new file mode 100755 index 0000000..a1db1d4 --- /dev/null +++ b/start @@ -0,0 +1,21 @@ +#!/bin/bash + + +#!/bin/bash + +# Simple static file server with live reload +# Requires Node.js and live-server + +# Check if live-server is installed +if ! command -v live-server &> /dev/null +then + echo "Installing live-server..." + npm install -g live-server +fi + +# Serve the current directory with auto-reload +echo "Starting live-server on http://localhost:8080 ..." +live-server . + + + diff --git a/styles.css b/styles.css new file mode 100644 index 0000000..b9e460e --- /dev/null +++ b/styles.css @@ -0,0 +1,330 @@ +:root { + --bg: #0e0e11; + --bg-soft: #17171c; + --bg-input: #202027; + --line: #2c2c35; + --text: #f2f2f5; + --muted: #8b8b96; + --pause: #8b8b96; + --work: #ff3b30; + --accent: #4c8dff; + --radius: 14px; +} + +* { box-sizing: border-box; } + +html, body { + margin: 0; + padding: 0; + height: 100%; +} + +body { + background: var(--bg); + color: var(--text); + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif; + display: flex; + flex-direction: column; + min-height: 100dvh; + padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left); + -webkit-tap-highlight-color: transparent; + overscroll-behavior: none; +} + +/* ---------- top bar ---------- */ + +.topbar { + display: flex; + align-items: center; + justify-content: space-between; + gap: 12px; + padding: 14px 18px 6px; +} + +.topbar h1 { + font-size: 1rem; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--muted); + margin: 0; +} + +.icon-btn { + background: none; + border: 0; + color: var(--muted); + padding: 8px; + border-radius: 10px; + display: grid; + place-items: center; + cursor: pointer; +} + +.icon-btn:active { background: var(--bg-soft); } +.icon-btn[aria-expanded="true"] { color: var(--text); } + +/* ---------- stage ---------- */ + +.stage { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + text-align: center; + padding: 8px 20px; + gap: 6px; + min-height: 0; +} + +.progress { + font-size: 0.85rem; + letter-spacing: 0.08em; + text-transform: uppercase; + color: var(--muted); + min-height: 1.2em; +} + +.phase-label { + font-size: 0.95rem; + letter-spacing: 0.14em; + text-transform: uppercase; + font-weight: 700; + color: var(--muted); + transition: color 0.2s ease; +} + +.exercise { + font-size: clamp(1.8rem, 9vw, 3.2rem); + font-weight: 700; + line-height: 1.15; + color: var(--pause); + transition: color 0.2s ease; + overflow-wrap: anywhere; + max-width: 100%; +} + +.clock { + font-size: clamp(3.4rem, 22vw, 7rem); + font-weight: 700; + font-variant-numeric: tabular-nums; + line-height: 1; + letter-spacing: -0.02em; + color: var(--pause); + transition: color 0.2s ease; +} + +.next { + font-size: 0.9rem; + color: var(--muted); + min-height: 1.3em; +} + +/* phase colours: grey while pausing, red while training */ + +body.phase-work .exercise, +body.phase-work .clock, +body.phase-work .phase-label { + color: var(--work); +} + +body.phase-done .exercise, +body.phase-done .clock, +body.phase-done .phase-label { + color: var(--accent); +} + +body.phase-paused .clock { opacity: 0.45; } + +/* ---------- controls ---------- */ + +.controls { + display: flex; + gap: 12px; + padding: 10px 18px 18px; +} + +.btn { + flex: 1; + appearance: none; + border: 1px solid var(--line); + background: var(--bg-soft); + color: var(--text); + font-size: 1.05rem; + font-weight: 600; + padding: 16px 18px; + border-radius: var(--radius); + cursor: pointer; + touch-action: manipulation; +} + +.btn:active { transform: scale(0.985); } + +.btn-primary { + background: var(--accent); + border-color: var(--accent); + color: #fff; +} + +.btn-primary:disabled { + opacity: 0.4; + cursor: not-allowed; +} + +/* ---------- settings ---------- */ + +.settings { + background: var(--bg-soft); + border-top: 1px solid var(--line); + padding: 18px; + max-height: 62dvh; + overflow-y: auto; + -webkit-overflow-scrolling: touch; +} + +.field-row { + display: flex; + gap: 10px; +} + +.field { + flex: 1; + display: flex; + flex-direction: column; + gap: 6px; + min-width: 0; +} + +.field span { + font-size: 0.75rem; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--muted); +} + +input[type="number"], +input[type="text"] { + width: 100%; + background: var(--bg-input); + border: 1px solid var(--line); + border-radius: 10px; + color: var(--text); + font-size: 1.05rem; + padding: 12px; + font-family: inherit; +} + +input:focus { + outline: none; + border-color: var(--accent); +} + +.section-title { + font-size: 0.75rem; + letter-spacing: 0.05em; + text-transform: uppercase; + color: var(--muted); + margin: 22px 0 8px; +} + +.exercise-list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 8px; +} + +.exercise-list li { + display: flex; + align-items: center; + gap: 10px; + background: var(--bg-input); + border: 1px solid var(--line); + border-radius: 10px; + padding: 10px 10px 10px 14px; +} + +.exercise-list .idx { + color: var(--muted); + font-size: 0.85rem; + font-variant-numeric: tabular-nums; + min-width: 1.4em; +} + +.exercise-list .name { + flex: 1; + overflow-wrap: anywhere; +} + +.remove-btn { + background: none; + border: 0; + color: var(--muted); + font-size: 1.3rem; + line-height: 1; + padding: 6px 10px; + border-radius: 8px; + cursor: pointer; +} + +.remove-btn:active { background: #2c2c35; color: var(--work); } + +.empty-hint { + color: var(--muted); + font-size: 0.9rem; + margin: 4px 0 12px; +} + +.add-row { + display: flex; + gap: 10px; + margin-top: 12px; +} + +.add-row input { flex: 1; } + +.btn-add { + flex: 0 0 auto; + width: 56px; + font-size: 1.6rem; + line-height: 1; + padding: 8px; + background: var(--accent); + border-color: var(--accent); + color: #fff; +} + +.hint { + color: var(--muted); + font-size: 0.8rem; + line-height: 1.5; + margin: 16px 0 0; +} + +/* ---------- footer ---------- */ + +.footer { + padding: 0 18px 10px; + font-size: 0.75rem; + color: var(--muted); + text-align: center; + min-height: 1em; +} + +.footer .btn { + flex: none; + width: auto; + display: inline-block; + padding: 10px 18px; + font-size: 0.85rem; +} + +/* keep the clock readable on short landscape screens */ +@media (max-height: 520px) { + .clock { font-size: clamp(2.4rem, 14vh, 4rem); } + .exercise { font-size: clamp(1.3rem, 5vh, 2rem); } + .stage { gap: 2px; } +} diff --git a/sw.js b/sw.js new file mode 100644 index 0000000..7fda59c --- /dev/null +++ b/sw.js @@ -0,0 +1,65 @@ +/* Offline app shell for the Interval Timer PWA. */ + +const CACHE = 'interval-timer-v1'; + +const ASSETS = [ + './', + './index.html', + './styles.css', + './app.js', + './manifest.webmanifest', + './icons/icon-192.png', + './icons/icon-512.png', + './icons/icon-maskable-512.png', +]; + +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE) + .then((cache) => cache.addAll(ASSETS)) + .then(() => self.skipWaiting()) + ); +}); + +self.addEventListener('activate', (event) => { + event.waitUntil( + caches.keys() + .then((keys) => Promise.all(keys.filter((k) => k !== CACHE).map((k) => caches.delete(k)))) + .then(() => self.clients.claim()) + ); +}); + +self.addEventListener('fetch', (event) => { + const { request } = event; + if (request.method !== 'GET' || new URL(request.url).origin !== self.location.origin) return; + + // Navigations: try the network, fall back to the cached shell when offline. + if (request.mode === 'navigate') { + event.respondWith( + fetch(request) + .then((response) => { + const copy = response.clone(); + caches.open(CACHE).then((cache) => cache.put('./index.html', copy)); + return response; + }) + .catch(() => caches.match('./index.html')) + ); + return; + } + + // Everything else: cache first, refresh in the background. + event.respondWith( + caches.match(request).then((cached) => { + const network = fetch(request) + .then((response) => { + if (response && response.status === 200 && response.type === 'basic') { + const copy = response.clone(); + caches.open(CACHE).then((cache) => cache.put(request, copy)); + } + return response; + }) + .catch(() => cached); + return cached || network; + }) + ); +}); diff --git a/tmp-ff-app.png b/tmp-ff-app.png new file mode 100644 index 0000000..11338e8 Binary files /dev/null and b/tmp-ff-app.png differ diff --git a/tmp-ffprof/.parentlock b/tmp-ffprof/.parentlock new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/SiteSecurityServiceState.bin b/tmp-ffprof/SiteSecurityServiceState.bin new file mode 100644 index 0000000..833ede2 Binary files /dev/null and b/tmp-ffprof/SiteSecurityServiceState.bin differ diff --git a/tmp-ffprof/addonStartup.json.lz4 b/tmp-ffprof/addonStartup.json.lz4 new file mode 100644 index 0000000..9b8264f Binary files /dev/null and b/tmp-ffprof/addonStartup.json.lz4 differ diff --git a/tmp-ffprof/addons.json b/tmp-ffprof/addons.json new file mode 100644 index 0000000..bec320e --- /dev/null +++ b/tmp-ffprof/addons.json @@ -0,0 +1 @@ +{"schema":6,"addons":[{"id":"langpack-de@firefox.mozilla.org","icons":{"32":"https://addons.mozilla.org/static-server/img/addon-icons/default-32.png","64":"https://addons.mozilla.org/static-server/img/addon-icons/default-64.png","128":"https://addons.mozilla.org/static-server/img/addon-icons/default-128.png"},"name":"Deutsch (DE) Language Pack","version":"157.0.20260918.91356","sourceURI":"https://addons.mozilla.org/firefox/downloads/file/5039501/deutsch_de_language_pack-157.0.20260918.91356.xpi","homepageURL":null,"supportURL":null,"amoListingURL":"https://addons.mozilla.org/de/firefox/addon/deutsch-de-language-pack/","description":"Deutsch (DE) Language Pack","fullDescription":null,"weeklyDownloads":1045,"type":"locale","creator":{"name":"Firefox","url":"https://addons.mozilla.org/de/firefox/user/4757633/"},"developers":[],"screenshots":[],"contributionURL":"","averageRating":4.1419,"reviewCount":280,"reviewURL":"https://addons.mozilla.org/de/firefox/addon/deutsch-de-language-pack/reviews/","updateDate":1789737511000}]} \ No newline at end of file diff --git a/tmp-ffprof/bounce-tracking-protection.sqlite b/tmp-ffprof/bounce-tracking-protection.sqlite new file mode 100644 index 0000000..33faebe Binary files /dev/null and b/tmp-ffprof/bounce-tracking-protection.sqlite differ diff --git a/tmp-ffprof/cache2/entries/2E3BB6BC391F71592ABB479526FC18EF6BFAED2C b/tmp-ffprof/cache2/entries/2E3BB6BC391F71592ABB479526FC18EF6BFAED2C new file mode 100644 index 0000000..2a7e140 Binary files /dev/null and b/tmp-ffprof/cache2/entries/2E3BB6BC391F71592ABB479526FC18EF6BFAED2C differ diff --git a/tmp-ffprof/cache2/entries/31B882D8B33FAF0FE8062511BABE3B31700FD00D b/tmp-ffprof/cache2/entries/31B882D8B33FAF0FE8062511BABE3B31700FD00D new file mode 100644 index 0000000..e343306 --- /dev/null +++ b/tmp-ffprof/cache2/entries/31B882D8B33FAF0FE8062511BABE3B31700FD00D @@ -0,0 +1,532 @@ +(() => { + 'use strict'; + + const STORAGE_KEY = 'interval-timer/v1'; + const TICK_MS = 100; + + const els = { + body: document.body, + stage: document.getElementById('stage'), + progress: document.getElementById('progress'), + phaseLabel: document.getElementById('phaseLabel'), + exerciseName: document.getElementById('exerciseName'), + clock: document.getElementById('clock'), + nextUp: document.getElementById('nextUp'), + startBtn: document.getElementById('startBtn'), + pauseBtn: document.getElementById('pauseBtn'), + resetBtn: document.getElementById('resetBtn'), + settingsToggle: document.getElementById('settingsToggle'), + settings: document.getElementById('settings'), + pauseInput: document.getElementById('pauseInput'), + workInput: document.getElementById('workInput'), + setsInput: document.getElementById('setsInput'), + exerciseList: document.getElementById('exerciseList'), + emptyHint: document.getElementById('emptyHint'), + exerciseInput: document.getElementById('exerciseInput'), + addBtn: document.getElementById('addBtn'), + installHint: document.getElementById('installHint'), + }; + + const DEFAULTS = { pauseSec: 15, workSec: 45, sets: 5, exercises: [] }; + + /* ------------------------------------------------------------------ * + * settings persistence + * ------------------------------------------------------------------ */ + + function loadSettings() { + try { + const raw = localStorage.getItem(STORAGE_KEY); + if (!raw) return { ...DEFAULTS }; + const parsed = JSON.parse(raw); + return { + pauseSec: clampInt(parsed.pauseSec, 0, 3600, DEFAULTS.pauseSec), + workSec: clampInt(parsed.workSec, 1, 3600, DEFAULTS.workSec), + sets: clampInt(parsed.sets, 1, 999, DEFAULTS.sets), + exercises: Array.isArray(parsed.exercises) + ? parsed.exercises.filter((e) => typeof e === 'string' && e.trim()).map((e) => e.trim()) + : [], + }; + } catch { + return { ...DEFAULTS }; + } + } + + function saveSettings() { + try { + localStorage.setItem(STORAGE_KEY, JSON.stringify(settings)); + } catch { + /* storage unavailable (private mode) — the app still works in memory */ + } + } + + function clampInt(value, min, max, fallback) { + const n = Math.round(Number(value)); + if (!Number.isFinite(n)) return fallback; + return Math.min(max, Math.max(min, n)); + } + + const settings = loadSettings(); + + /* ------------------------------------------------------------------ * + * runtime state + * ------------------------------------------------------------------ */ + + const run = { + phase: 'idle', // idle | pause | work | done + setIndex: 0, + exIndex: 0, + remaining: 0, + deadline: 0, + paused: false, + pausedRemaining: 0, + timerId: null, + }; + + const isActive = () => run.phase === 'pause' || run.phase === 'work'; + + /* ------------------------------------------------------------------ * + * audio — synthesised, so the app needs no sound files and works offline + * ------------------------------------------------------------------ */ + + let audioCtx = null; + + function ensureAudio() { + try { + const Ctx = window.AudioContext || window.webkitAudioContext; + if (!Ctx) return null; + if (!audioCtx) audioCtx = new Ctx(); + if (audioCtx.state === 'suspended') audioCtx.resume().catch(() => {}); + return audioCtx; + } catch { + return null; // audio unavailable — the timer must still run + } + } + + function tone(freq, delay, duration, peak, type) { + if (!ensureAudio()) return; + const ctx = audioCtx; + const t0 = ctx.currentTime + delay; + const osc = ctx.createOscillator(); + const gain = ctx.createGain(); + osc.type = type || 'sine'; + osc.frequency.setValueAtTime(freq, t0); + gain.gain.setValueAtTime(0.0001, t0); + gain.gain.exponentialRampToValueAtTime(peak, t0 + 0.012); + gain.gain.exponentialRampToValueAtTime(0.0001, t0 + duration); + osc.connect(gain).connect(ctx.destination); + osc.start(t0); + osc.stop(t0 + duration + 0.05); + } + + /** Bell: a few inharmonic partials with long decay. */ + function bell(count) { + if (!ensureAudio()) return; + const rings = count || 1; + for (let i = 0; i < rings; i++) { + const at = i * 0.55; + tone(880, at, 1.6, 0.32, 'sine'); + tone(1320, at, 1.1, 0.16, 'sine'); + tone(1760, at, 0.7, 0.09, 'sine'); + tone(587, at, 1.9, 0.12, 'sine'); + } + } + + /** Short beep marking a phase change. Higher = training, lower = pause. */ + function beep(freq) { + if (!ensureAudio()) return; + tone(freq, 0, 0.16, 0.3, 'square'); + tone(freq * 2, 0, 0.1, 0.08, 'sine'); + } + + function vibrate(pattern) { + if (navigator.vibrate) { + try { navigator.vibrate(pattern); } catch { /* ignore */ } + } + } + + /* ------------------------------------------------------------------ * + * screen wake lock — keeps the phone display on during a session + * ------------------------------------------------------------------ */ + + let wakeLock = null; + + async function requestWakeLock() { + if (!('wakeLock' in navigator)) return; + try { + wakeLock = await navigator.wakeLock.request('screen'); + wakeLock.addEventListener('release', () => { wakeLock = null; }); + } catch { + /* denied or unsupported — not fatal */ + } + } + + function releaseWakeLock() { + if (wakeLock) { + wakeLock.release().catch(() => {}); + wakeLock = null; + } + } + + /* ------------------------------------------------------------------ * + * timer engine — phases chain off their own deadline, so a throttled or + * suspended page catches up to real elapsed time instead of drifting + * ------------------------------------------------------------------ */ + + const MAX_CATCHUP = 5000; + + function startTimer() { + if (run.timerId !== null) return; + run.timerId = window.setInterval(tick, TICK_MS); + } + + function stopTimer() { + if (run.timerId !== null) { + window.clearInterval(run.timerId); + run.timerId = null; + } + } + + function tick() { + if (!isActive() || run.paused) return; + + const now = performance.now(); + const late = now - run.deadline; + + if (late < 0) { + run.remaining = -late / 1000; + render(); + return; + } + + // One or more phases ended while we were not ticking (timer throttling). + // Play the cue only for a prompt transition, not for a bulk catch-up. + let steps = 0; + while (isActive() && !run.paused && run.deadline <= now && steps < MAX_CATCHUP) { + advance(steps === 0 && late < 1500); + steps++; + } + + if (!isActive()) return; + run.remaining = Math.max(0, (run.deadline - now) / 1000); + render(); + } + + /** `from` anchors the new phase to the previous phase's deadline. */ + function beginPhase(phase, from) { + run.phase = phase; + const duration = phase === 'pause' ? settings.pauseSec : settings.workSec; + run.remaining = duration; + run.deadline = (from === undefined ? performance.now() : from) + duration * 1000; + render(); + } + + function advance(playSound) { + if (run.phase === 'pause') { + // pause finished -> training starts, text turns red + if (playSound) { beep(1180); vibrate(140); } + beginPhase('work', run.deadline); + return; + } + + if (run.phase === 'work') { + // training finished -> line up the next exercise + const from = run.deadline; + run.exIndex += 1; + if (run.exIndex >= settings.exercises.length) { + run.exIndex = 0; + run.setIndex += 1; + } + if (run.setIndex >= settings.sets) { + finish(); + return; + } + if (playSound) { beep(720); vibrate(140); } + beginPhase('pause', from); + } + } + + function start() { + if (settings.exercises.length === 0) { + openSettings(); + els.exerciseInput.focus(); + return; + } + ensureAudio(); // must happen inside the user gesture + run.setIndex = 0; + run.exIndex = 0; + run.paused = false; + run.pausedRemaining = 0; + bell(1); + vibrate(300); + requestWakeLock(); + startTimer(); + beginPhase('pause'); + } + + function togglePause() { + if (!isActive()) return; + if (run.paused) { + run.paused = false; + run.deadline = performance.now() + run.pausedRemaining * 1000; + } else { + run.paused = true; + run.pausedRemaining = Math.max(0, (run.deadline - performance.now()) / 1000); + } + render(); + } + + function finish() { + run.phase = 'done'; + run.remaining = 0; + run.paused = false; + stopTimer(); + releaseWakeLock(); + bell(3); + vibrate([250, 120, 250, 120, 500]); + render(); + } + + function reset() { + run.phase = 'idle'; + run.setIndex = 0; + run.exIndex = 0; + run.remaining = 0; + run.paused = false; + run.pausedRemaining = 0; + stopTimer(); + releaseWakeLock(); + render(); + } + + /* ------------------------------------------------------------------ * + * rendering + * ------------------------------------------------------------------ */ + + function formatTime(seconds) { + const total = Math.max(0, Math.ceil(seconds)); + const m = Math.floor(total / 60); + const s = total % 60; + return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`; + } + + function nextExerciseAfterWork() { + let ex = run.exIndex + 1; + let set = run.setIndex; + if (ex >= settings.exercises.length) { + ex = 0; + set += 1; + } + if (set >= settings.sets) return null; + return settings.exercises[ex]; + } + + function render() { + const total = settings.exercises.length; + const current = total ? settings.exercises[run.exIndex] : null; + + els.body.classList.toggle('phase-work', run.phase === 'work'); + els.body.classList.toggle('phase-done', run.phase === 'done'); + els.body.classList.toggle('phase-paused', run.paused); + + if (run.phase === 'idle') { + els.progress.textContent = total + ? `${settings.sets} set${settings.sets === 1 ? '' : 's'} · ${total} exercise${total === 1 ? '' : 's'}` + : ''; + els.phaseLabel.textContent = 'Ready'; + els.exerciseName.textContent = current || 'Add your exercises'; + els.clock.textContent = formatTime(settings.pauseSec); + els.nextUp.textContent = total + ? `Pause ${settings.pauseSec}s, then ${settings.workSec}s training` + : ''; + } else if (run.phase === 'done') { + els.progress.textContent = 'Complete'; + els.phaseLabel.textContent = 'Done'; + els.exerciseName.textContent = 'Workout complete'; + els.clock.textContent = '00:00'; + els.nextUp.textContent = `${settings.sets} set${settings.sets === 1 ? '' : 's'} finished`; + } else { + els.progress.textContent = + `Set ${run.setIndex + 1} / ${settings.sets} · Exercise ${run.exIndex + 1} / ${total}`; + els.phaseLabel.textContent = run.paused + ? 'Paused' + : run.phase === 'work' ? 'Training' : 'Pause'; + els.exerciseName.textContent = current || ''; + els.clock.textContent = formatTime(run.remaining); + + if (run.phase === 'pause') { + els.nextUp.textContent = `Next: ${settings.workSec}s training`; + } else { + const next = nextExerciseAfterWork(); + els.nextUp.textContent = next ? `Next: ${next}` : 'Last one — finish strong'; + } + } + + renderControls(); + } + + function renderControls() { + const active = isActive(); + els.startBtn.hidden = active; + els.startBtn.textContent = run.phase === 'done' ? 'Restart' : 'Start'; + els.pauseBtn.hidden = !active; + els.pauseBtn.textContent = run.paused ? 'Resume' : 'Pause'; + els.resetBtn.hidden = !active && run.phase !== 'done'; + + const lock = active; + els.pauseInput.disabled = lock; + els.workInput.disabled = lock; + els.setsInput.disabled = lock; + els.exerciseInput.disabled = lock; + els.addBtn.disabled = lock; + els.exerciseList.querySelectorAll('button').forEach((b) => { b.disabled = lock; }); + } + + function renderExerciseList() { + els.exerciseList.textContent = ''; + settings.exercises.forEach((name, i) => { + const li = document.createElement('li'); + + const idx = document.createElement('span'); + idx.className = 'idx'; + idx.textContent = `${i + 1}.`; + + const label = document.createElement('span'); + label.className = 'name'; + label.textContent = name; + + const remove = document.createElement('button'); + remove.type = 'button'; + remove.className = 'remove-btn'; + remove.textContent = '\u00d7'; + remove.setAttribute('aria-label', `Remove ${name}`); + remove.addEventListener('click', () => { + settings.exercises.splice(i, 1); + saveSettings(); + renderExerciseList(); + render(); + }); + + li.append(idx, label, remove); + els.exerciseList.append(li); + }); + + els.emptyHint.hidden = settings.exercises.length > 0; + renderControls(); + } + + /* ------------------------------------------------------------------ * + * settings UI + * ------------------------------------------------------------------ */ + + function openSettings() { + els.settings.hidden = false; + els.settingsToggle.setAttribute('aria-expanded', 'true'); + } + + function toggleSettings() { + const open = els.settings.hidden; + els.settings.hidden = !open; + els.settingsToggle.setAttribute('aria-expanded', String(open)); + } + + function addExercise() { + const name = els.exerciseInput.value.trim(); + if (!name) return; + settings.exercises.push(name); + saveSettings(); + els.exerciseInput.value = ''; + renderExerciseList(); + render(); + els.exerciseInput.focus(); + } + + function bindNumberInput(input, key, min, max) { + input.value = String(settings[key]); + input.addEventListener('change', () => { + settings[key] = clampInt(input.value, min, max, DEFAULTS[key]); + input.value = String(settings[key]); + saveSettings(); + render(); + }); + } + + /* ------------------------------------------------------------------ * + * wiring + * ------------------------------------------------------------------ */ + + bindNumberInput(els.pauseInput, 'pauseSec', 0, 3600); + bindNumberInput(els.workInput, 'workSec', 1, 3600); + bindNumberInput(els.setsInput, 'sets', 1, 999); + + els.startBtn.addEventListener('click', start); + els.pauseBtn.addEventListener('click', togglePause); + els.resetBtn.addEventListener('click', reset); + els.settingsToggle.addEventListener('click', toggleSettings); + els.addBtn.addEventListener('click', addExercise); + els.exerciseInput.addEventListener('keydown', (e) => { + if (e.key === 'Enter') { + e.preventDefault(); + addExercise(); + } + }); + + document.addEventListener('visibilitychange', () => { + if (document.visibilityState === 'visible') { + if (isActive() && !run.paused) tick(); + if (isActive() && !wakeLock) requestWakeLock(); + } + }); + + // space bar toggles pause on desktop + document.addEventListener('keydown', (e) => { + if (e.code === 'Space' && isActive() && e.target.tagName !== 'INPUT') { + e.preventDefault(); + togglePause(); + } + }); + + renderExerciseList(); + render(); + + /* ------------------------------------------------------------------ * + * PWA: service worker + install prompt + * ------------------------------------------------------------------ */ + + if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('./sw.js').catch(() => {}); + }); + } + + let deferredPrompt = null; + window.addEventListener('beforeinstallprompt', (e) => { + e.preventDefault(); + deferredPrompt = e; + const btn = document.createElement('button'); + btn.type = 'button'; + btn.className = 'btn'; + btn.textContent = 'Install app'; + btn.addEventListener('click', async () => { + if (!deferredPrompt) return; + deferredPrompt.prompt(); + await deferredPrompt.userChoice; + deferredPrompt = null; + els.installHint.textContent = ''; + }); + els.installHint.textContent = ''; + els.installHint.append(btn); + }); +})(); +3Ì +ekQj®bÅj®bÅIòïj®cCO^partitionKey=%28http%2C127.0.0.1%29,:http://127.0.0.1:8765/app.jsstrongly-framed1request-methodGETresponse-headHTTP/1.0 200 OK +Server: SimpleHTTP/0.6 Python/3.14.4 +Date: Sat, 19 Sep 2026 10:24:05 GMT +Content-type: text/javascript +Content-Length: 16154 +Last-Modified: Sat, 19 Sep 2026 10:13:36 GMT +original-response-headersServer: SimpleHTTP/0.6 Python/3.14.4 +Date: Sat, 19 Sep 2026 10:24:05 GMT +Content-type: text/javascript +Content-Length: 16154 +Last-Modified: Sat, 19 Sep 2026 10:13:36 GMT +ctid2net-response-time-onstart4net-response-time-onstop5? \ No newline at end of file diff --git a/tmp-ffprof/cache2/entries/360DE1F3E174E84794C36651DD126686164A2F9A b/tmp-ffprof/cache2/entries/360DE1F3E174E84794C36651DD126686164A2F9A new file mode 100644 index 0000000..a60fff0 Binary files /dev/null and b/tmp-ffprof/cache2/entries/360DE1F3E174E84794C36651DD126686164A2F9A differ diff --git a/tmp-ffprof/cache2/entries/6BF512B7CD3F2753FABE3D20A75FCC07E2DCD473 b/tmp-ffprof/cache2/entries/6BF512B7CD3F2753FABE3D20A75FCC07E2DCD473 new file mode 100644 index 0000000..d50cfb9 Binary files /dev/null and b/tmp-ffprof/cache2/entries/6BF512B7CD3F2753FABE3D20A75FCC07E2DCD473 differ diff --git a/tmp-ffprof/cache2/entries/76A7C8DE6ACCD5C67DA0E2BE76566EBDF96402F1 b/tmp-ffprof/cache2/entries/76A7C8DE6ACCD5C67DA0E2BE76566EBDF96402F1 new file mode 100644 index 0000000..4cdc4ca Binary files /dev/null and b/tmp-ffprof/cache2/entries/76A7C8DE6ACCD5C67DA0E2BE76566EBDF96402F1 differ diff --git a/tmp-ffprof/cache2/entries/9085CF9B24AE65C77BD081772230413CCEE1184A b/tmp-ffprof/cache2/entries/9085CF9B24AE65C77BD081772230413CCEE1184A new file mode 100644 index 0000000..9c4d349 Binary files /dev/null and b/tmp-ffprof/cache2/entries/9085CF9B24AE65C77BD081772230413CCEE1184A differ diff --git a/tmp-ffprof/cache2/entries/A03CE2818598B535678ED3CDB1A376FD46FB5FF2 b/tmp-ffprof/cache2/entries/A03CE2818598B535678ED3CDB1A376FD46FB5FF2 new file mode 100644 index 0000000..43784f0 Binary files /dev/null and b/tmp-ffprof/cache2/entries/A03CE2818598B535678ED3CDB1A376FD46FB5FF2 differ diff --git a/tmp-ffprof/cache2/entries/E482BE33A6F82D22EF970CF4950D6CDAE376EBC4 b/tmp-ffprof/cache2/entries/E482BE33A6F82D22EF970CF4950D6CDAE376EBC4 new file mode 100644 index 0000000..6afeec4 Binary files /dev/null and b/tmp-ffprof/cache2/entries/E482BE33A6F82D22EF970CF4950D6CDAE376EBC4 differ diff --git a/tmp-ffprof/cert9.db b/tmp-ffprof/cert9.db new file mode 100644 index 0000000..b7b53c2 Binary files /dev/null and b/tmp-ffprof/cert9.db differ diff --git a/tmp-ffprof/compatibility.ini b/tmp-ffprof/compatibility.ini new file mode 100644 index 0000000..e70f811 --- /dev/null +++ b/tmp-ffprof/compatibility.ini @@ -0,0 +1,5 @@ +[Compatibility] +LastVersion=155.0.1_20260904071051/20260904071051 +LastOSABI=Linux_x86_64-gcc3 +LastPlatformDir=/snap/firefox/8863/usr/lib/firefox +LastAppDir=/snap/firefox/8863/usr/lib/firefox/browser diff --git a/tmp-ffprof/cookies.sqlite b/tmp-ffprof/cookies.sqlite new file mode 100644 index 0000000..f50aa69 Binary files /dev/null and b/tmp-ffprof/cookies.sqlite differ diff --git a/tmp-ffprof/datareporting/archived/2026-09/1789813445838.adfba4ed-07a6-45c7-81b8-dad6b639df68.new-profile.jsonlz4 b/tmp-ffprof/datareporting/archived/2026-09/1789813445838.adfba4ed-07a6-45c7-81b8-dad6b639df68.new-profile.jsonlz4 new file mode 100644 index 0000000..9fd67ab Binary files /dev/null and b/tmp-ffprof/datareporting/archived/2026-09/1789813445838.adfba4ed-07a6-45c7-81b8-dad6b639df68.new-profile.jsonlz4 differ diff --git a/tmp-ffprof/datareporting/archived/2026-09/1789813445845.36dada9b-7991-49d0-8ba8-f67c8e1c5427.event.jsonlz4 b/tmp-ffprof/datareporting/archived/2026-09/1789813445845.36dada9b-7991-49d0-8ba8-f67c8e1c5427.event.jsonlz4 new file mode 100644 index 0000000..5ea78b8 Binary files /dev/null and b/tmp-ffprof/datareporting/archived/2026-09/1789813445845.36dada9b-7991-49d0-8ba8-f67c8e1c5427.event.jsonlz4 differ diff --git a/tmp-ffprof/datareporting/archived/2026-09/1789813445852.f7af7a4c-b941-4403-8289-19b458caa23e.main.jsonlz4 b/tmp-ffprof/datareporting/archived/2026-09/1789813445852.f7af7a4c-b941-4403-8289-19b458caa23e.main.jsonlz4 new file mode 100644 index 0000000..9cb10a5 Binary files /dev/null and b/tmp-ffprof/datareporting/archived/2026-09/1789813445852.f7af7a4c-b941-4403-8289-19b458caa23e.main.jsonlz4 differ diff --git a/tmp-ffprof/datareporting/archived/2026-09/1789813445853.5be2fcab-6c50-4108-99e3-a968ab37ae56.first-shutdown.jsonlz4 b/tmp-ffprof/datareporting/archived/2026-09/1789813445853.5be2fcab-6c50-4108-99e3-a968ab37ae56.first-shutdown.jsonlz4 new file mode 100644 index 0000000..fbfe1ac Binary files /dev/null and b/tmp-ffprof/datareporting/archived/2026-09/1789813445853.5be2fcab-6c50-4108-99e3-a968ab37ae56.first-shutdown.jsonlz4 differ diff --git a/tmp-ffprof/datareporting/glean/client_id.txt b/tmp-ffprof/datareporting/glean/client_id.txt new file mode 100644 index 0000000..db97c60 --- /dev/null +++ b/tmp-ffprof/datareporting/glean/client_id.txt @@ -0,0 +1 @@ +282c8a0b-de08-4073-83e2-6349be31c557 \ No newline at end of file diff --git a/tmp-ffprof/datareporting/glean/db/data.safe.bin b/tmp-ffprof/datareporting/glean/db/data.safe.bin new file mode 100644 index 0000000..fbfc807 Binary files /dev/null and b/tmp-ffprof/datareporting/glean/db/data.safe.bin differ diff --git a/tmp-ffprof/datareporting/glean/events/events b/tmp-ffprof/datareporting/glean/events/events new file mode 100644 index 0000000..bf7a75a --- /dev/null +++ b/tmp-ffprof/datareporting/glean/events/events @@ -0,0 +1,9 @@ +{"timestamp":439193142,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"loadfail_reason":"File doesn't exist.","path_key":"clean","can_load":"false","glean_timestamp":"1789813444852"}} +{"timestamp":439193151,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"loadfail_reason":"File doesn't exist.","can_load":"false","path_key":"recovery","glean_timestamp":"1789813444861"}} +{"timestamp":439193193,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"can_load":"false","path_key":"recoveryBackup","glean_timestamp":"1789813444903","loadfail_reason":"File doesn't exist."}} +{"timestamp":439193211,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"glean_timestamp":"1789813444921","loadfail_reason":"File doesn't exist.","path_key":"cleanBackup","can_load":"false"}} +{"timestamp":439193216,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"loadfail_reason":"File doesn't exist.","glean_timestamp":"1789813444927","path_key":"clean","can_load":"false"}} +{"timestamp":439193228,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"path_key":"recovery","can_load":"false","loadfail_reason":"File doesn't exist.","glean_timestamp":"1789813444939"}} +{"timestamp":439193293,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"can_load":"false","glean_timestamp":"1789813445003","loadfail_reason":"File doesn't exist.","path_key":"recoveryBackup"}} +{"timestamp":439193322,"category":"session_restore","name":"backup_can_be_loaded_session_file","extra":{"glean_timestamp":"1789813445033","path_key":"cleanBackup","can_load":"false","loadfail_reason":"File doesn't exist."}} +{"timestamp":439194211,"category":"glean","name":"session_start","extra":{"session_start_time":"2026-09-19T07:24:05.921-03:00","glean_timestamp":"439194211","sampled_in":"true","session_id":"11f4d217-12a6-4446-8cc0-07068fb4f43e","session_seq":"1"}} diff --git a/tmp-ffprof/datareporting/glean/events/pageload b/tmp-ffprof/datareporting/glean/events/pageload new file mode 100644 index 0000000..b9e913c --- /dev/null +++ b/tmp-ffprof/datareporting/glean/events/pageload @@ -0,0 +1 @@ +{"timestamp":439193704,"category":"perf","name":"page_load","extra":{"http_ver":"1","using_webdriver":"false","time_to_request_start":"17","load_time":"242","cache_disposition":"4","interaction_count":"0","script_memory_cache_revived":"0","script_memory_cache_use":"0","script_from_necko_serialized":"0","script_from_necko_text":"1","load_type":"NORMAL","dns_lookup_time":"0","script_memory_cache_evicted_dirty":"0","js_exec_time":"4","response_time":"23","glean_timestamp":"1789813445414"}} diff --git a/tmp-ffprof/datareporting/glean/pending_pings/04c02fd7-1a9f-4565-8897-de4e3ce8a32f b/tmp-ffprof/datareporting/glean/pending_pings/04c02fd7-1a9f-4565-8897-de4e3ce8a32f new file mode 100644 index 0000000..3d7e0f3 --- /dev/null +++ b/tmp-ffprof/datareporting/glean/pending_pings/04c02fd7-1a9f-4565-8897-de4e3ce8a32f @@ -0,0 +1,3 @@ +/submit/firefox-desktop/baseline/1/04c02fd7-1a9f-4565-8897-de4e3ce8a32f +{"ping_info":{"seq":0,"start_time":"2026-09-19T07:24:05.866-03:00","end_time":"2026-09-19T07:24:05.922-03:00","reason":"active"},"client_info":{"telemetry_sdk_build":"68.0.1","build_date":"1970-01-01T00:00:00+00:00","first_run_date":"2026-09-19-03:00","client_id":"282c8a0b-de08-4073-83e2-6349be31c557","app_channel":"release","os_version":"7.0","architecture":"x86_64","app_display_version":"155.0.1","os":"Linux","app_build":"20260904071051","locale":"de","distribution":{"name":"canonical-002"}},"metrics":{"uuid":{"legacy.telemetry.client_id":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","legacy.telemetry.profile_group_id":"dd6a2853-9d81-4edd-b920-ae094d7305ee"},"object":{"glean.distribution.ext":{"distributionVersion":"1.0","partnerId":"ubuntu","distributor":"canonical","distributorChannel":"","partnerNames":["ubuntu"]}},"string":{"startup.profile_selection_reason":"argument-profile"},"boolean":{"policies.is_enterprise":false}}} +{"headers":{},"body_has_info_sections":true,"ping_name":"baseline","uploader_capabilities":[]} \ No newline at end of file diff --git a/tmp-ffprof/datareporting/glean/pending_pings/3b8fea54-ce26-4592-aefe-4ef35a912ce6 b/tmp-ffprof/datareporting/glean/pending_pings/3b8fea54-ce26-4592-aefe-4ef35a912ce6 new file mode 100644 index 0000000..a2b3d99 --- /dev/null +++ b/tmp-ffprof/datareporting/glean/pending_pings/3b8fea54-ce26-4592-aefe-4ef35a912ce6 @@ -0,0 +1,3 @@ +/submit/firefox-desktop/health/1/3b8fea54-ce26-4592-aefe-4ef35a912ce6 +{"ping_info":{"seq":0,"start_time":"2026-09-19T07:24:05.866-03:00","end_time":"2026-09-19T07:24:05.924-03:00","reason":"pre_init"},"client_info":{"telemetry_sdk_build":"68.0.1","app_display_version":"155.0.1","app_build":"20260904071051","os_version":"7.0","architecture":"x86_64","app_channel":"release","locale":"de","os":"Linux","first_run_date":"2026-09-19-03:00","build_date":"1970-01-01T00:00:00+00:00","client_id":"282c8a0b-de08-4073-83e2-6349be31c557","distribution":{"name":"canonical-002"}},"metrics":{"counter":{"glean.health.init_count":1,"fog.inits_during_shutdown":1},"object":{"glean.health.data_directory_info":[{"dir_name":"db","dir_exists":false},{"dir_name":"events","dir_exists":false},{"dir_name":"pending_pings","dir_exists":false}]},"labeled_counter":{"glean.health.file_read_error":{"file-not-found":1},"glean.validation.pings_submitted":{"baseline":1}},"timing_distribution":{"glean.validation.shutdown_dispatcher_wait":{"values":{"961548":1},"sum":1000000}},"uuid":{"legacy.telemetry.client_id":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","legacy.telemetry.profile_group_id":"dd6a2853-9d81-4edd-b920-ae094d7305ee"}}} +{"headers":{},"body_has_info_sections":true,"ping_name":"health","uploader_capabilities":[]} \ No newline at end of file diff --git a/tmp-ffprof/datareporting/glean/pending_pings/74c1afc4-3f96-497a-b8f9-83e3580d4f80 b/tmp-ffprof/datareporting/glean/pending_pings/74c1afc4-3f96-497a-b8f9-83e3580d4f80 new file mode 100644 index 0000000..6514837 --- /dev/null +++ b/tmp-ffprof/datareporting/glean/pending_pings/74c1afc4-3f96-497a-b8f9-83e3580d4f80 @@ -0,0 +1,3 @@ +/submit/firefox-desktop/new-profile/1/74c1afc4-3f96-497a-b8f9-83e3580d4f80 +{"ping_info":{"seq":0,"start_time":"2026-09-19T07:24:05.866-03:00","end_time":"2026-09-19T07:24:05.904-03:00"},"client_info":{"telemetry_sdk_build":"68.0.1","client_id":"282c8a0b-de08-4073-83e2-6349be31c557","app_display_version":"155.0.1","os_version":"7.0","app_build":"20260904071051","app_channel":"release","architecture":"x86_64","os":"Linux","locale":"de","build_date":"1970-01-01T00:00:00+00:00","first_run_date":"2026-09-19-03:00","distribution":{"name":"canonical-002"}},"metrics":{"string":{"startup.profile_selection_reason":"argument-profile","startup.profile_database_version":"2"},"quantity":{"startup.profile_count":1}}} +{"headers":{},"body_has_info_sections":true,"ping_name":"new-profile","uploader_capabilities":[]} \ No newline at end of file diff --git a/tmp-ffprof/datareporting/glean/pending_pings/83ef7c73-727e-4aa1-b87c-92ec69a613bf b/tmp-ffprof/datareporting/glean/pending_pings/83ef7c73-727e-4aa1-b87c-92ec69a613bf new file mode 100644 index 0000000..7d3123e --- /dev/null +++ b/tmp-ffprof/datareporting/glean/pending_pings/83ef7c73-727e-4aa1-b87c-92ec69a613bf @@ -0,0 +1,3 @@ +/submit/firefox-desktop/addons/1/83ef7c73-727e-4aa1-b87c-92ec69a613bf +{"ping_info":{"seq":0,"start_time":"2026-09-19T07:24:05.866-03:00","end_time":"2026-09-19T07:24:05.889-03:00","reason":"startup"},"client_info":{"telemetry_sdk_build":"68.0.1","client_id":"282c8a0b-de08-4073-83e2-6349be31c557","build_date":"1970-01-01T00:00:00+00:00","first_run_date":"2026-09-19-03:00","app_display_version":"155.0.1","app_build":"20260904071051","os":"Linux","architecture":"x86_64","os_version":"7.0","app_channel":"release","locale":"de","distribution":{"name":"canonical-002"}},"metrics":{"object":{"addons.theme":{},"addons.active_addons":[{"id":"langpack-de@firefox.mozilla.org","blocklisted":false,"description":"Firefox Language Pack for Deutsch (de) – German","name":"Language: Deutsch (German)","userDisabled":false,"appDisabled":false,"version":"155.0.20260903.215306","scope":1,"addonType":"locale","foreignInstall":false,"hasBinaryComponents":false,"installDay":20715,"updateDay":20715,"signedState":2,"signedTypes":"[2,1]","isSystem":false,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":false,"quarantineIgnoredByUser":false},{"id":"formautofill@mozilla.org","blocklisted":false,"name":"Form Autofill","userDisabled":false,"appDisabled":false,"version":"1.0.1","scope":4,"addonType":"extension","foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},{"id":"ipp-activator@mozilla.com","blocklisted":false,"description":"A system add-on to activate IPP in 143","name":"IPP Activator","userDisabled":false,"appDisabled":false,"version":"0.3","scope":4,"addonType":"extension","foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},{"id":"newtab@mozilla.org","blocklisted":false,"description":"","name":"New Tab","userDisabled":false,"appDisabled":false,"version":"155.2.0","scope":4,"addonType":"extension","foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},{"id":"pictureinpicture@mozilla.org","blocklisted":false,"description":"Fixes for web compatibility with Picture-in-Picture","name":"Picture-In-Picture","userDisabled":false,"appDisabled":false,"version":"1.0.0","scope":4,"addonType":"extension","foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},{"id":"addons-search-detection@mozilla.com","blocklisted":false,"description":"","name":"Add-ons Search Detection","userDisabled":false,"appDisabled":false,"version":"3.0.0","scope":4,"addonType":"extension","foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},{"id":"webcompat@mozilla.org","blocklisted":false,"description":"Urgent post-release fixes for web compatibility.","name":"Web Compatibility Interventions","userDisabled":false,"appDisabled":false,"version":"155.5.0","scope":4,"addonType":"extension","foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false}],"addons.active_g_m_plugins":[{"id":"dummy-gmp","version":"0.1","userDisabled":false,"applyBackgroundUpdates":1}]}}} +{"headers":{},"body_has_info_sections":true,"ping_name":"addons","uploader_capabilities":[]} \ No newline at end of file diff --git a/tmp-ffprof/datareporting/session-state.json b/tmp-ffprof/datareporting/session-state.json new file mode 100644 index 0000000..14beb3c --- /dev/null +++ b/tmp-ffprof/datareporting/session-state.json @@ -0,0 +1 @@ +{"sessionId":"682852a1-6419-4b1a-b8f0-b7fd58a5bc74","subsessionId":"c848b5d1-24ee-40b0-9de4-7830ea54cf2a","profileSubsessionCounter":1,"newProfilePingSent":true} \ No newline at end of file diff --git a/tmp-ffprof/datareporting/state.json b/tmp-ffprof/datareporting/state.json new file mode 100644 index 0000000..30bfc01 --- /dev/null +++ b/tmp-ffprof/datareporting/state.json @@ -0,0 +1 @@ +{"version":2,"clientID":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","profileGroupID":"dd6a2853-9d81-4edd-b920-ae094d7305ee","usageProfileID":"eb394fcc-3869-4c41-8c12-862763534118","usageProfileGroupID":"4002bf00-9fad-44e1-8bb1-e48f748dc4d1"} \ No newline at end of file diff --git a/tmp-ffprof/extension-preferences.json b/tmp-ffprof/extension-preferences.json new file mode 100644 index 0000000..f5f9118 --- /dev/null +++ b/tmp-ffprof/extension-preferences.json @@ -0,0 +1 @@ +{"newtab@mozilla.org":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]},"addons-search-detection@mozilla.com":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]},"formautofill@mozilla.org":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]},"ipp-activator@mozilla.com":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]},"pictureinpicture@mozilla.org":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]},"webcompat@mozilla.org":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]},"default-theme@mozilla.org":{"permissions":["internal:privateBrowsingAllowed","internal:svgContextPropertiesAllowed"],"origins":[],"data_collection":[]}} \ No newline at end of file diff --git a/tmp-ffprof/extensions.json b/tmp-ffprof/extensions.json new file mode 100644 index 0000000..63bc915 --- /dev/null +++ b/tmp-ffprof/extensions.json @@ -0,0 +1 @@ +{"schemaVersion":37,"addons":[{"id":"langpack-de@firefox.mozilla.org","syncGUID":"{ca3b6f48-15f7-4bf6-a4e7-daa7375f654e}","version":"155.0.20260903.215306","type":"locale","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"Language: Deutsch (German)","description":"Firefox Language Pack for Deutsch (de) – German","creator":"Sebastian Hengst (contributors: Robert Kaiser, Abdulkadir Topal)","developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"installDate":1789813444124,"updateDate":1789813444124,"applyBackgroundUpdates":1,"path":"/home/oliver/timer/tmp-ffprof/extensions/langpack-de@firefox.mozilla.org.xpi","skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":"155.0","maxVersion":"155.*"}],"targetPlatforms":[],"signedState":2,"signedTypes":[2,1],"signedDate":1788479390000,"seen":true,"dependencies":[],"userPermissions":null,"optionalPermissions":null,"requestedPermissions":null,"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":{"chromeEntries":[["locale","app-marketplace-icons","de","browser/chrome/browser/locale/de/app-marketplace-icons/"],["locale","branding","de","browser/chrome/de/locale/branding/"],["locale","browser","de","browser/chrome/de/locale/browser/"],["locale","browser-region","de","browser/chrome/de/locale/browser-region/"],["locale","devtools","de","browser/chrome/de/locale/de/devtools/client/"],["locale","devtools-shared","de","browser/chrome/de/locale/de/devtools/shared/"],["locale","alerts","de","chrome/de/locale/de/alerts/"],["locale","autoconfig","de","chrome/de/locale/de/autoconfig/"],["locale","global","de","chrome/de/locale/de/global/"],["locale","global-platform","de","chrome/de/locale/de/global-platform/unix/"],["locale","mozapps","de","chrome/de/locale/de/mozapps/"],["locale","necko","de","chrome/de/locale/de/necko/"],["locale","passwordmgr","de","chrome/de/locale/de/passwordmgr/"],["locale","pipnss","de","chrome/de/locale/de/pipnss/"],["locale","pippki","de","chrome/de/locale/de/pippki/"],["locale","places","de","chrome/de/locale/de/places/"]],"langpackId":"langpack-de-browser","l10nRegistrySources":{"toolkit":"","browser":"browser/"},"languages":["de"]},"hidden":false,"installTelemetryInfo":{"source":"distribution"},"recommendationState":null,"rootURI":"jar:file:///home/oliver/timer/tmp-ffprof/extensions/langpack-de@firefox.mozilla.org.xpi!/","location":"app-profile"},{"id":"formautofill@mozilla.org","syncGUID":"{bcca9762-a5cf-4d4d-90ff-99bd0e73760f}","version":"1.0.1","type":"extension","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"Form Autofill","creator":null,"developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"applyBackgroundUpdates":1,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":null,"maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"incognito":"spanning","userPermissions":{"permissions":[],"origins":[],"data_collection":[]},"optionalPermissions":{"permissions":[],"origins":[],"data_collection":[]},"requestedPermissions":{"permissions":[],"origins":[],"data_collection":[]},"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":true,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://builtin-addons/formautofill/","location":"app-builtin-addons"},{"id":"ipp-activator@mozilla.com","syncGUID":"{be6f0602-c196-4318-98ca-a757d1c10dde}","version":"0.3","type":"extension","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"IPP Activator","description":"A system add-on to activate IPP in 143","creator":null,"developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"applyBackgroundUpdates":1,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":"143.0","maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"incognito":"spanning","userPermissions":{"permissions":["tabs","cookies","webRequest"],"origins":[""],"data_collection":[]},"optionalPermissions":{"permissions":[],"origins":[],"data_collection":[]},"requestedPermissions":{"permissions":[],"origins":[],"data_collection":[]},"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":true,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://builtin-addons/ipp-activator/","location":"app-builtin-addons"},{"id":"newtab@mozilla.org","syncGUID":"{88e1a439-28ba-4667-b183-1ecbfaa3dd72}","version":"155.2.0","type":"extension","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"New Tab","description":"","creator":null,"developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"applyBackgroundUpdates":1,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":"142.0a1","maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"incognito":"spanning","userPermissions":{"permissions":[],"origins":[],"data_collection":[]},"optionalPermissions":{"permissions":[],"origins":[],"data_collection":[]},"requestedPermissions":{"permissions":[],"origins":[],"data_collection":[]},"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":true,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://builtin-addons/newtab/","location":"app-builtin-addons"},{"id":"pictureinpicture@mozilla.org","syncGUID":"{703f037a-ee19-4c30-ace4-aecca051a88a}","version":"1.0.0","type":"extension","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"Picture-In-Picture","description":"Fixes for web compatibility with Picture-in-Picture","creator":null,"developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"applyBackgroundUpdates":1,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":"88.0a1","maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"incognito":"spanning","userPermissions":{"permissions":[],"origins":[],"data_collection":[]},"optionalPermissions":{"permissions":[],"origins":[],"data_collection":[]},"requestedPermissions":{"permissions":[],"origins":[],"data_collection":[]},"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":true,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://builtin-addons/pictureinpicture/","location":"app-builtin-addons"},{"id":"addons-search-detection@mozilla.com","syncGUID":"{0ece4a7f-06f9-4548-aa10-d221dc898825}","version":"3.0.0","type":"extension","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"Add-ons Search Detection","description":"","creator":null,"developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"applyBackgroundUpdates":1,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":null,"maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"incognito":"spanning","userPermissions":{"permissions":["telemetry","webRequest","webRequestBlocking"],"origins":[""],"data_collection":[]},"optionalPermissions":{"permissions":[],"origins":[],"data_collection":[]},"requestedPermissions":{"permissions":[],"origins":[],"data_collection":[]},"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":true,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://builtin-addons/search-detection/","location":"app-builtin-addons"},{"id":"webcompat@mozilla.org","syncGUID":"{3e8dc0e3-6d21-417a-842c-6b74c57639bf}","version":"155.5.0","type":"extension","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"Web Compatibility Interventions","description":"Urgent post-release fixes for web compatibility.","creator":null,"developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"applyBackgroundUpdates":1,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":"102.0","maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"incognito":"spanning","userPermissions":{"permissions":["cookies","mozillaAddons","scripting","tabs","webNavigation","webRequest","webRequestBlocking"],"origins":[""],"data_collection":[]},"optionalPermissions":{"permissions":[],"origins":[],"data_collection":[]},"requestedPermissions":{"permissions":[],"origins":[],"data_collection":[]},"icons":{},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":true,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://builtin-addons/webcompat/","location":"app-builtin-addons"},{"id":"default-theme@mozilla.org","syncGUID":"{1c74a813-ff4e-432b-9695-40af2eebaa0f}","version":"1.4.2","type":"theme","loader":null,"updateURL":null,"installOrigins":null,"manifestVersion":2,"optionsURL":null,"optionsType":null,"optionsBrowserStyle":true,"aboutURL":null,"defaultLocale":{"name":"System theme — auto","description":"Follow the operating system setting for buttons, menus, and windows.","creator":"Mozilla","developers":null,"translators":null,"contributors":null},"visible":true,"active":true,"userDisabled":false,"appDisabled":false,"embedderDisabled":false,"installDate":1789813444859,"applyBackgroundUpdates":1,"path":null,"skinnable":false,"sourceURI":null,"releaseNotesURI":null,"softDisabled":false,"foreignInstall":false,"strictCompatibility":true,"locales":[],"targetApplications":[{"id":"toolkit@mozilla.org","minVersion":null,"maxVersion":null}],"targetPlatforms":[],"signedDate":null,"seen":true,"dependencies":[],"userPermissions":null,"optionalPermissions":null,"requestedPermissions":null,"icons":{"32":"icon.svg"},"iconURL":null,"blocklistAttentionDismissed":false,"blocklistState":0,"blocklistURL":null,"startupData":null,"hidden":false,"installTelemetryInfo":null,"recommendationState":null,"rootURI":"resource://default-theme/","location":"app-builtin"}]} \ No newline at end of file diff --git a/tmp-ffprof/extensions/langpack-de@firefox.mozilla.org.xpi b/tmp-ffprof/extensions/langpack-de@firefox.mozilla.org.xpi new file mode 100644 index 0000000..7095d31 Binary files /dev/null and b/tmp-ffprof/extensions/langpack-de@firefox.mozilla.org.xpi differ diff --git a/tmp-ffprof/favicons.sqlite b/tmp-ffprof/favicons.sqlite new file mode 100644 index 0000000..e0b6183 Binary files /dev/null and b/tmp-ffprof/favicons.sqlite differ diff --git a/tmp-ffprof/favicons.sqlite-wal b/tmp-ffprof/favicons.sqlite-wal new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/key4.db b/tmp-ffprof/key4.db new file mode 100644 index 0000000..9e619e4 Binary files /dev/null and b/tmp-ffprof/key4.db differ diff --git a/tmp-ffprof/lock b/tmp-ffprof/lock new file mode 120000 index 0000000..dd8fe58 --- /dev/null +++ b/tmp-ffprof/lock @@ -0,0 +1 @@ +127.0.1.1:+789420 \ No newline at end of file diff --git a/tmp-ffprof/permissions.sqlite b/tmp-ffprof/permissions.sqlite new file mode 100644 index 0000000..c6c883e Binary files /dev/null and b/tmp-ffprof/permissions.sqlite differ diff --git a/tmp-ffprof/pkcs11.txt b/tmp-ffprof/pkcs11.txt new file mode 100644 index 0000000..6029a96 --- /dev/null +++ b/tmp-ffprof/pkcs11.txt @@ -0,0 +1,5 @@ +library= +name=NSS Internal PKCS #11 Module +parameters=configdir='sql:/home/oliver/timer/tmp-ffprof' certPrefix='' keyPrefix='' secmod='secmod.db' flags=optimizeSpace updatedir='' updateCertPrefix='' updateKeyPrefix='' updateid='' updateTokenDescription='' +NSS=Flags=internal,critical trustOrder=75 cipherOrder=100 slotParams=(1={slotFlags=[ECC,RSA,DSA,DH,RC2,RC4,DES,RANDOM,SHA1,MD5,MD2,SSL,TLS,AES,Camellia,SEED,SHA256,SHA512] askpw=any timeout=30}) + diff --git a/tmp-ffprof/places.sqlite b/tmp-ffprof/places.sqlite new file mode 100644 index 0000000..99d2c92 Binary files /dev/null and b/tmp-ffprof/places.sqlite differ diff --git a/tmp-ffprof/places.sqlite-wal b/tmp-ffprof/places.sqlite-wal new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/prefs.js b/tmp-ffprof/prefs.js new file mode 100644 index 0000000..021f780 --- /dev/null +++ b/tmp-ffprof/prefs.js @@ -0,0 +1,53 @@ +// Mozilla User Preferences + +// DO NOT EDIT THIS FILE. +// +// If you make changes to this file while the application is running, +// the changes will be overwritten when the application exits. +// +// To change a preference value, you can either: +// - modify it via the UI (e.g. via about:config in the browser); or +// - set it within a user.js file in your profile. + +user_pref("app.normandy.migrationsApplied", 12); +user_pref("app.update.auto", false); +user_pref("app.update.lastUpdateTime.region-update-timer", 0); +user_pref("app.update.lastUpdateTime.xpi-signature-verification", 0); +user_pref("browser.bookmarks.restore_default_bookmarks", false); +user_pref("browser.migration.version", 179); +user_pref("browser.proton.toolbar.version", 3); +user_pref("browser.startup.homepage_override.mstone", "ignore"); +user_pref("browser.uiCustomization.state", "{\"placements\":{\"widget-overflow-fixed-list\":[],\"unified-extensions-area\":[]},\"seen\":[\"reset-pbm-toolbar-button\"],\"dirtyAreaCache\":[],\"currentVersion\":26,\"newElementCount\":0}"); +user_pref("datareporting.dau.cachedUsageProfileGroupID", "4002bf00-9fad-44e1-8bb1-e48f748dc4d1"); +user_pref("datareporting.dau.cachedUsageProfileID", "eb394fcc-3869-4c41-8c12-862763534118"); +user_pref("datareporting.policy.dataSubmissionEnabled", false); +user_pref("distribution.canonical-002.bookmarksProcessed", true); +user_pref("distribution.iniFile.exists.appversion", "155.0.1"); +user_pref("distribution.iniFile.exists.value", true); +user_pref("dom.forms.autocomplete.formautofill", true); +user_pref("extensions.activeThemeID", "default-theme@mozilla.org"); +user_pref("extensions.blocklist.pingCountVersion", 0); +user_pref("extensions.databaseSchema", 37); +user_pref("extensions.getAddons.cache.lastUpdate", 1789813445); +user_pref("extensions.getAddons.databaseSchema", 6); +user_pref("extensions.installedDistroAddon.langpack-de@firefox.mozilla.org", true); +user_pref("extensions.lastAppBuildId", "20260904071051"); +user_pref("extensions.lastAppVersion", "155.0.1"); +user_pref("extensions.lastPlatformVersion", "155.0.1"); +user_pref("extensions.pendingOperations", false); +user_pref("extensions.signatureCheckpoint", 1); +user_pref("extensions.webextensions.uuids", "{\"formautofill@mozilla.org\":\"7e19ba0d-6161-4150-8264-3ef692ed4336\",\"ipp-activator@mozilla.com\":\"d4eabf67-a127-49a4-9993-3df65d6163d2\",\"pictureinpicture@mozilla.org\":\"72c1fd14-b9ca-434b-9844-90735da55834\",\"addons-search-detection@mozilla.com\":\"fa9171f1-0d58-40e0-bb84-3a3b414d4781\",\"webcompat@mozilla.org\":\"9a310967-e580-48bf-b3e8-4eafebbc122d\",\"newtab@mozilla.org\":\"55649e03-6360-49d9-8568-c6c3e3ec209c\",\"default-theme@mozilla.org\":\"5e67a4c0-6eb3-44f3-9f25-052367bcf1e5\"}"); +user_pref("media.gmp.storage.version.observed", 1); +user_pref("network.cookie.CHIPS.lastMigrateDatabase", 2); +user_pref("network.cookie.validation.lastEpoch", 1); +user_pref("nimbus.profileId", "9a5a9153-e9ac-4a73-8a3b-836e8eec5dc1"); +user_pref("pdfjs.enabledCache.state", true); +user_pref("privacy.bounceTrackingProtection.hasMigratedUserActivationData", true); +user_pref("privacy.trackingprotection.allow_list.hasMigratedCategoryPrefs", true); +user_pref("services.settings.base_attachments_url", "https://firefox.settings.services.mozilla.com/v2|https://firefox-settings-attachments.cdn.mozilla.net/"); +user_pref("services.sync.engine.addresses.available", true); +user_pref("toolkit.profiles.newProfileSubmitted", true); +user_pref("toolkit.startup.last_success", 1789813443); +user_pref("toolkit.telemetry.cachedClientID", "f8fb24d3-61c2-4342-b9fb-cb5679e729fc"); +user_pref("toolkit.telemetry.cachedProfileGroupID", "dd6a2853-9d81-4edd-b920-ae094d7305ee"); +user_pref("toolkit.telemetry.previousBuildID", "20260904071051"); diff --git a/tmp-ffprof/saved-telemetry-pings/36dada9b-7991-49d0-8ba8-f67c8e1c5427 b/tmp-ffprof/saved-telemetry-pings/36dada9b-7991-49d0-8ba8-f67c8e1c5427 new file mode 100644 index 0000000..4a8cebb --- /dev/null +++ b/tmp-ffprof/saved-telemetry-pings/36dada9b-7991-49d0-8ba8-f67c8e1c5427 @@ -0,0 +1 @@ +{"type":"event","id":"36dada9b-7991-49d0-8ba8-f67c8e1c5427","creationDate":"2026-09-19T10:24:05.845Z","version":4,"application":{"architecture":"x86-64","buildId":"20260904071051","name":"Firefox","version":"155.0.1","displayVersion":"155.0.1","vendor":"Mozilla","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","channel":"release"},"payload":{"reason":"shutdown","processStartTimestamp":1789813440000,"sessionId":"682852a1-6419-4b1a-b8f0-b7fd58a5bc74","subsessionId":"c848b5d1-24ee-40b0-9de4-7830ea54cf2a","lostEventsCount":0,"events":{"parent":[[1638,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"clean","loadfail_reason":"File doesn't exist."}],[1647,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"recovery","loadfail_reason":"File doesn't exist."}],[1689,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"recoveryBackup","loadfail_reason":"File doesn't exist."}],[1707,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"cleanBackup","loadfail_reason":"File doesn't exist."}],[1712,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"clean","loadfail_reason":"File doesn't exist."}],[1724,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"recovery","loadfail_reason":"File doesn't exist."}],[1789,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"recoveryBackup","loadfail_reason":"File doesn't exist."}],[1818,"session_restore","backup_can_be_loaded","session_file",null,{"can_load":"false","path_key":"cleanBackup","loadfail_reason":"File doesn't exist."}]]}},"clientId":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","profileGroupId":"dd6a2853-9d81-4edd-b920-ae094d7305ee","environment":{"build":{"applicationId":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","applicationName":"Firefox","architecture":"x86-64","buildId":"20260904071051","version":"155.0.1","vendor":"Mozilla","displayVersion":"155.0.1","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","updaterAvailable":false},"partner":{"distributionId":"canonical-002","distributionVersion":"1.0","partnerId":"ubuntu","distributor":"canonical","distributorChannel":"","partnerNames":["ubuntu"]},"system":{"memoryMB":15712,"virtualMaxMB":null,"cpu":{"count":12,"cores":8,"pcount":8,"mcount":0,"ecount":0,"vendor":"GenuineIntel","name":"12th Gen Intel(R) Core(TM) i5-12450H","family":6,"model":154,"stepping":3,"l2cacheKB":1280,"l3cacheKB":12288,"speedMHz":4400,"extensions":["hasMMX","hasSSE","hasSSE2","hasSSE3","hasSSSE3","hasSSE4_1","hasSSE4_2","hasAVX","hasAVX2","hasAES"]},"os":{"name":"Linux","version":"7.0.0-31-generic","locale":"de-DE","distro":"Ubuntu-core","distroVersion":"24"},"hdd":{"profile":{"model":null,"revision":null,"type":null},"binary":{"model":null,"revision":null,"type":null},"system":{"model":null,"revision":null,"type":null}},"gfx":{"DWriteEnabled":null,"ContentBackend":"Skia","Headless":true,"TargetFrameRate":60,"textScaleFactor":1,"adapters":[{"description":"Mesa Intel(R) Graphics (ADL GT2)","vendorID":"0x8086","deviceID":"0x46a3","subsysID":null,"RAM":0,"driver":null,"driverVendor":"mesa/iris","driverVersion":"25.2.8.0","driverDate":null,"GPUActive":true}],"monitors":[{"screenWidth":1366,"screenHeight":768,"defaultCSSScaleFactor":1,"contentsScaleFactor":1}],"features":{"compositor":"none","hwCompositing":{"status":"blocked:FEATURE_FAILURE_COMP_HEADLESSMODE"},"gpuProcess":{"status":"unused"},"webrender":{"status":"unavailable-no-hw-compositing"},"wrCompositor":{"status":"blocklisted:FEATURE_FAILURE_WEBRENDER_COMPOSITOR_DISABLED"},"openglCompositing":{"status":"unavailable:FEATURE_FAILURE_OPENGL_NEED_HWCOMP"}}},"appleModelId":null,"hasWinPackageId":null},"settings":{"blocklistEnabled":true,"e10sEnabled":true,"e10sMultiProcesses":8,"fissionEnabled":true,"locale":"de","intl":{},"update":{"channel":"release","enabled":false,"autoDownload":false,"background":false},"userPrefs":{"browser.shell.checkDefaultBrowser":false,"browser.urlbar.autoFill":true,"browser.urlbar.autoFill.adaptiveHistory.enabled":false,"browser.urlbar.dnsResolveSingleWordsAfterSearch":0,"browser.urlbar.suggest.quicksuggest.sponsored":false,"network.http.microsoft-entra-sso.enabled":false,"network.trr.strict_native_fallback":false,"widget.content.gtk-high-contrast.enabled":true},"sandbox":{"effectiveContentProcessLevel":6,"contentWin32kLockdownState":3},"addonCompatibilityCheckEnabled":true,"isDefaultBrowser":null},"profile":{"creationDate":20715,"firstUseDate":20715},"addons":{"activeAddons":{"langpack-de@firefox.mozilla.org":{"version":"155.0.20260903.215306","scope":1,"type":"locale","updateDay":20715,"isSystem":false,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Firefox Language Pack for Deutsch (de) – German","name":"Language: Deutsch (German)","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":20715,"signedState":2,"signedTypes":"[2,1]","quarantineIgnoredByApp":false,"quarantineIgnoredByUser":false},"formautofill@mozilla.org":{"version":"1.0.1","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":null,"name":"Form Autofill","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"ipp-activator@mozilla.com":{"version":"0.3","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"A system add-on to activate IPP in 143","name":"IPP Activator","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"newtab@mozilla.org":{"version":"155.2.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"New Tab","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"pictureinpicture@mozilla.org":{"version":"1.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Fixes for web compatibility with Picture-in-Picture","name":"Picture-In-Picture","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"addons-search-detection@mozilla.com":{"version":"3.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"Add-ons Search Detection","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"webcompat@mozilla.org":{"version":"155.5.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Urgent post-release fixes for web compatibility.","name":"Web Compatibility Interventions","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false}},"theme":{},"activeGMPlugins":{"gmp-gmpopenh264":{"version":null,"userDisabled":false,"applyBackgroundUpdates":1}}}}} \ No newline at end of file diff --git a/tmp-ffprof/saved-telemetry-pings/5be2fcab-6c50-4108-99e3-a968ab37ae56 b/tmp-ffprof/saved-telemetry-pings/5be2fcab-6c50-4108-99e3-a968ab37ae56 new file mode 100644 index 0000000..17c5ea6 --- /dev/null +++ b/tmp-ffprof/saved-telemetry-pings/5be2fcab-6c50-4108-99e3-a968ab37ae56 @@ -0,0 +1 @@ +{"type":"first-shutdown","id":"5be2fcab-6c50-4108-99e3-a968ab37ae56","creationDate":"2026-09-19T10:24:05.853Z","version":4,"application":{"architecture":"x86-64","buildId":"20260904071051","name":"Firefox","version":"155.0.1","displayVersion":"155.0.1","vendor":"Mozilla","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","channel":"release"},"payload":{"ver":4,"simpleMeasurements":{"totalTime":3,"main":413,"activeTicks":0},"processes":{"parent":{"scalars":{"browser.engagement.session_time_including_suspend":2267,"gfx.supports_hdr":false,"browser.engagement.session_time_excluding_suspend":2267,"gfx.os_compositor":false,"startup.profile_selection_reason":"argument-profile","gfx.linux_window_protocol":"xwayland","startup.profile_database_version":"2","policies.is_enterprise":false,"startup.profile_count":1,"dom.contentprocess.os_priority_lowered":2,"policies.count":0,"dom.contentprocess.os_priority_change_considered":23},"keyedScalars":{"media.device_hardware_decoding_support":{"av1":true,"hevc":true,"vp8":true,"h264":true,"vp9":true},"networking.data_transferred_v3_kb":{"Y1_N1":48,"Y0_N1Sys":900}}},"content":{"histograms":{"HTTP_PAGE_DNS_LOOKUP_TIME":{"bucket_count":50,"histogram_type":0,"sum":0,"range":[1,30000],"values":{"0":1,"1":0}},"HTTP_PAGE_TCP_CONNECTION_2":{"bucket_count":50,"histogram_type":0,"sum":0,"range":[1,30000],"values":{"0":1,"1":0}},"APZ_ZOOM_ACTIVITY":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":1,"1":0}}},"keyedHistograms":{},"scalars":{},"keyedScalars":{}},"dynamic":{"scalars":{},"keyedScalars":{}},"gpu":{"histograms":{},"keyedHistograms":{},"scalars":{},"keyedScalars":{}},"socket":{"histograms":{},"keyedHistograms":{},"scalars":{},"keyedScalars":{}}},"histograms":{"CHILD_PROCESS_LAUNCH_MS":{"bucket_count":100,"histogram_type":0,"sum":19,"range":[1,64000],"values":{"1":0,"2":2,"3":2,"4":1,"5":1,"6":0}},"CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS":{"bucket_count":100,"histogram_type":0,"sum":3,"range":[1,64000],"values":{"2":0,"3":1,"4":0}},"CONTENT_PROCESS_LAUNCH_TOTAL_MS":{"bucket_count":100,"histogram_type":0,"sum":8,"range":[1,64000],"values":{"7":0,"8":1,"9":0}},"CONTENT_PROCESS_SYNC_LAUNCH_MS":{"bucket_count":100,"histogram_type":0,"sum":13,"range":[1,64000],"values":{"4":0,"5":1,"8":1,"9":0}},"CONTENT_PROCESS_LAUNCH_IS_SYNC":{"bucket_count":3,"histogram_type":2,"sum":2,"range":[1,2],"values":{"0":1,"1":2,"2":0}},"HTTP_TRANSACTION_IS_SSL":{"bucket_count":3,"histogram_type":2,"sum":4,"range":[1,2],"values":{"0":4,"1":4,"2":0}},"HTTP_PAGELOAD_IS_SSL":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":1,"1":0}},"HTTP_CHANNEL_ONSTART_SUCCESS":{"bucket_count":3,"histogram_type":2,"sum":8,"range":[1,2],"values":{"0":1,"1":8,"2":0}},"STARTUP_CACHE_REQUESTS":{"bucket_count":51,"histogram_type":5,"sum":560,"range":[1,50],"values":{"0":1,"2":280,"3":0}},"URLCLASSIFIER_LOOKUP_TIME_2":{"bucket_count":30,"histogram_type":0,"sum":0,"range":[1,5000],"values":{"0":1,"1":0}},"URLCLASSIFIER_SHUTDOWN_TIME":{"bucket_count":50,"histogram_type":0,"sum":0,"range":[1,60000],"values":{"0":1,"1":0}},"URLCLASSIFIER_CL_CHECK_TIME":{"bucket_count":10,"histogram_type":0,"sum":0,"range":[1,500],"values":{"0":1,"1":0}},"FX_SESSION_RESTORE_ALL_FILES_CORRUPT":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":1,"1":0}},"QUERY_STRIPPING_COUNT":{"bucket_count":51,"histogram_type":5,"sum":0,"range":[1,50],"values":{"0":1,"1":0}},"SERVICE_WORKER_ISOLATED_LAUNCH_TIME":{"bucket_count":25,"histogram_type":0,"sum":11,"range":[1,30000],"values":{"5":0,"8":1,"12":0}},"ORB_DID_EVER_BLOCK_RESPONSE":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":15,"1":0}}},"keyedHistograms":{"EMAIL_TRACKER_EMBEDDED_PER_TAB":{"content_normal":{"bucket_count":100,"histogram_type":0,"sum":0,"range":[1,1000],"values":{"0":1,"1":0}},"base_normal":{"bucket_count":100,"histogram_type":0,"sum":0,"range":[1,1000],"values":{"0":1,"1":0}},"all_normal":{"bucket_count":100,"histogram_type":0,"sum":0,"range":[1,1000],"values":{"0":1,"1":0}}},"QM_QUOTA_INFO_LOAD_TIME_V0":{"Normal":{"bucket_count":60,"histogram_type":0,"sum":0,"range":[1,180000],"values":{"0":1,"1":0}}},"QM_FIRST_INITIALIZATION_ATTEMPT":{"PersistentOrigin":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryStorage":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryRepository":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"DefaultRepository":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryOrigin":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"Storage":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryGroup":{"bucket_count":3,"histogram_type":2,"sum":7,"range":[1,2],"values":{"0":0,"1":7,"2":0}}},"QM_SHUTDOWN_TIME_V0":{"Normal":{"bucket_count":60,"histogram_type":0,"sum":11,"range":[1,60000],"values":{"8":0,"10":1,"12":0}}},"HTTP_TRAFFIC_ANALYSIS_3":{"Connection":{"bucket_count":51,"histogram_type":5,"sum":4,"range":[1,50],"values":{"0":4,"1":4,"2":0}},"Transaction":{"bucket_count":51,"histogram_type":5,"sum":4,"range":[1,50],"values":{"0":4,"1":4,"2":0}}}},"info":{"reason":"shutdown","revision":"https://hg.mozilla.org/releases/mozilla-release/rev/5fdfd0092780e85643e2cddc0e1b590c8b9ef860","timezoneOffset":-180,"previousBuildId":null,"sessionId":"682852a1-6419-4b1a-b8f0-b7fd58a5bc74","subsessionId":"c848b5d1-24ee-40b0-9de4-7830ea54cf2a","previousSessionId":null,"previousSubsessionId":null,"subsessionCounter":1,"profileSubsessionCounter":1,"sessionStartDate":"2026-09-19T07:00:00.0-03:00","subsessionStartDate":"2026-09-19T07:00:00.0-03:00","sessionLength":2,"subsessionLength":1,"addons":"langpack-de%40firefox.mozilla.org:155.0.20260903.215306,formautofill%40mozilla.org:1.0.1,ipp-activator%40mozilla.com:0.3,newtab%40mozilla.org:155.2.0,pictureinpicture%40mozilla.org:1.0.0,addons-search-detection%40mozilla.com:3.0.0,webcompat%40mozilla.org:155.5.0,default-theme%40mozilla.org:1.4.2"}},"clientId":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","profileGroupId":"dd6a2853-9d81-4edd-b920-ae094d7305ee","environment":{"build":{"applicationId":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","applicationName":"Firefox","architecture":"x86-64","buildId":"20260904071051","version":"155.0.1","vendor":"Mozilla","displayVersion":"155.0.1","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","updaterAvailable":false},"partner":{"distributionId":"canonical-002","distributionVersion":"1.0","partnerId":"ubuntu","distributor":"canonical","distributorChannel":"","partnerNames":["ubuntu"]},"system":{"memoryMB":15712,"virtualMaxMB":null,"cpu":{"count":12,"cores":8,"pcount":8,"mcount":0,"ecount":0,"vendor":"GenuineIntel","name":"12th Gen Intel(R) Core(TM) i5-12450H","family":6,"model":154,"stepping":3,"l2cacheKB":1280,"l3cacheKB":12288,"speedMHz":4400,"extensions":["hasMMX","hasSSE","hasSSE2","hasSSE3","hasSSSE3","hasSSE4_1","hasSSE4_2","hasAVX","hasAVX2","hasAES"]},"os":{"name":"Linux","version":"7.0.0-31-generic","locale":"de-DE","distro":"Ubuntu-core","distroVersion":"24"},"hdd":{"profile":{"model":null,"revision":null,"type":null},"binary":{"model":null,"revision":null,"type":null},"system":{"model":null,"revision":null,"type":null}},"gfx":{"DWriteEnabled":null,"ContentBackend":"Skia","Headless":true,"TargetFrameRate":60,"textScaleFactor":1,"adapters":[{"description":"Mesa Intel(R) Graphics (ADL GT2)","vendorID":"0x8086","deviceID":"0x46a3","subsysID":null,"RAM":0,"driver":null,"driverVendor":"mesa/iris","driverVersion":"25.2.8.0","driverDate":null,"GPUActive":true}],"monitors":[{"screenWidth":1366,"screenHeight":768,"defaultCSSScaleFactor":1,"contentsScaleFactor":1}],"features":{"compositor":"none","hwCompositing":{"status":"blocked:FEATURE_FAILURE_COMP_HEADLESSMODE"},"gpuProcess":{"status":"unused"},"webrender":{"status":"unavailable-no-hw-compositing"},"wrCompositor":{"status":"blocklisted:FEATURE_FAILURE_WEBRENDER_COMPOSITOR_DISABLED"},"openglCompositing":{"status":"unavailable:FEATURE_FAILURE_OPENGL_NEED_HWCOMP"}}},"appleModelId":null,"hasWinPackageId":null},"settings":{"blocklistEnabled":true,"e10sEnabled":true,"e10sMultiProcesses":8,"fissionEnabled":true,"locale":"de","intl":{},"update":{"channel":"release","enabled":false,"autoDownload":false,"background":false},"userPrefs":{"browser.shell.checkDefaultBrowser":false,"browser.urlbar.autoFill":true,"browser.urlbar.autoFill.adaptiveHistory.enabled":false,"browser.urlbar.dnsResolveSingleWordsAfterSearch":0,"browser.urlbar.suggest.quicksuggest.sponsored":false,"network.http.microsoft-entra-sso.enabled":false,"network.trr.strict_native_fallback":false,"widget.content.gtk-high-contrast.enabled":true},"sandbox":{"effectiveContentProcessLevel":6,"contentWin32kLockdownState":3},"addonCompatibilityCheckEnabled":true,"isDefaultBrowser":null},"profile":{"creationDate":20715,"firstUseDate":20715},"addons":{"activeAddons":{"langpack-de@firefox.mozilla.org":{"version":"155.0.20260903.215306","scope":1,"type":"locale","updateDay":20715,"isSystem":false,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Firefox Language Pack for Deutsch (de) – German","name":"Language: Deutsch (German)","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":20715,"signedState":2,"signedTypes":"[2,1]","quarantineIgnoredByApp":false,"quarantineIgnoredByUser":false},"formautofill@mozilla.org":{"version":"1.0.1","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":null,"name":"Form Autofill","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"ipp-activator@mozilla.com":{"version":"0.3","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"A system add-on to activate IPP in 143","name":"IPP Activator","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"newtab@mozilla.org":{"version":"155.2.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"New Tab","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"pictureinpicture@mozilla.org":{"version":"1.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Fixes for web compatibility with Picture-in-Picture","name":"Picture-In-Picture","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"addons-search-detection@mozilla.com":{"version":"3.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"Add-ons Search Detection","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"webcompat@mozilla.org":{"version":"155.5.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Urgent post-release fixes for web compatibility.","name":"Web Compatibility Interventions","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false}},"theme":{},"activeGMPlugins":{"gmp-gmpopenh264":{"version":null,"userDisabled":false,"applyBackgroundUpdates":1}}}}} \ No newline at end of file diff --git a/tmp-ffprof/saved-telemetry-pings/adfba4ed-07a6-45c7-81b8-dad6b639df68 b/tmp-ffprof/saved-telemetry-pings/adfba4ed-07a6-45c7-81b8-dad6b639df68 new file mode 100644 index 0000000..d052a2a --- /dev/null +++ b/tmp-ffprof/saved-telemetry-pings/adfba4ed-07a6-45c7-81b8-dad6b639df68 @@ -0,0 +1 @@ +{"type":"new-profile","id":"adfba4ed-07a6-45c7-81b8-dad6b639df68","creationDate":"2026-09-19T10:24:05.838Z","version":4,"application":{"architecture":"x86-64","buildId":"20260904071051","name":"Firefox","version":"155.0.1","displayVersion":"155.0.1","vendor":"Mozilla","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","channel":"release"},"payload":{"reason":"shutdown","processes":{"parent":{"scalars":{"startup.profile_selection_reason":"argument-profile","startup.profile_database_version":"2","startup.profile_count":1}}}},"clientId":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","profileGroupId":"dd6a2853-9d81-4edd-b920-ae094d7305ee","environment":{"build":{"applicationId":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","applicationName":"Firefox","architecture":"x86-64","buildId":"20260904071051","version":"155.0.1","vendor":"Mozilla","displayVersion":"155.0.1","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","updaterAvailable":false},"partner":{"distributionId":"canonical-002","distributionVersion":"1.0","partnerId":"ubuntu","distributor":"canonical","distributorChannel":"","partnerNames":["ubuntu"]},"system":{"memoryMB":15712,"virtualMaxMB":null,"cpu":{"count":12,"cores":8,"pcount":8,"mcount":0,"ecount":0,"vendor":"GenuineIntel","name":"12th Gen Intel(R) Core(TM) i5-12450H","family":6,"model":154,"stepping":3,"l2cacheKB":1280,"l3cacheKB":12288,"speedMHz":4400,"extensions":["hasMMX","hasSSE","hasSSE2","hasSSE3","hasSSSE3","hasSSE4_1","hasSSE4_2","hasAVX","hasAVX2","hasAES"]},"os":{"name":"Linux","version":"7.0.0-31-generic","locale":"de-DE","distro":"Ubuntu-core","distroVersion":"24"},"hdd":{"profile":{"model":null,"revision":null,"type":null},"binary":{"model":null,"revision":null,"type":null},"system":{"model":null,"revision":null,"type":null}},"gfx":{"DWriteEnabled":null,"ContentBackend":"Skia","Headless":true,"TargetFrameRate":60,"textScaleFactor":1,"adapters":[{"description":"Mesa Intel(R) Graphics (ADL GT2)","vendorID":"0x8086","deviceID":"0x46a3","subsysID":null,"RAM":0,"driver":null,"driverVendor":"mesa/iris","driverVersion":"25.2.8.0","driverDate":null,"GPUActive":true}],"monitors":[{"screenWidth":1366,"screenHeight":768,"defaultCSSScaleFactor":1,"contentsScaleFactor":1}],"features":{"compositor":"none","hwCompositing":{"status":"blocked:FEATURE_FAILURE_COMP_HEADLESSMODE"},"gpuProcess":{"status":"unused"},"webrender":{"status":"unavailable-no-hw-compositing"},"wrCompositor":{"status":"blocklisted:FEATURE_FAILURE_WEBRENDER_COMPOSITOR_DISABLED"},"openglCompositing":{"status":"unavailable:FEATURE_FAILURE_OPENGL_NEED_HWCOMP"}}},"appleModelId":null,"hasWinPackageId":null},"settings":{"blocklistEnabled":true,"e10sEnabled":true,"e10sMultiProcesses":8,"fissionEnabled":true,"locale":"de","intl":{},"update":{"channel":"release","enabled":false,"autoDownload":false,"background":false},"userPrefs":{"browser.shell.checkDefaultBrowser":false,"browser.urlbar.autoFill":true,"browser.urlbar.autoFill.adaptiveHistory.enabled":false,"browser.urlbar.dnsResolveSingleWordsAfterSearch":0,"browser.urlbar.suggest.quicksuggest.sponsored":false,"network.http.microsoft-entra-sso.enabled":false,"network.trr.strict_native_fallback":false,"widget.content.gtk-high-contrast.enabled":true},"sandbox":{"effectiveContentProcessLevel":6,"contentWin32kLockdownState":3},"addonCompatibilityCheckEnabled":true,"isDefaultBrowser":null},"profile":{"creationDate":20715,"firstUseDate":20715},"addons":{"activeAddons":{"langpack-de@firefox.mozilla.org":{"version":"155.0.20260903.215306","scope":1,"type":"locale","updateDay":20715,"isSystem":false,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Firefox Language Pack for Deutsch (de) – German","name":"Language: Deutsch (German)","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":20715,"signedState":2,"signedTypes":"[2,1]","quarantineIgnoredByApp":false,"quarantineIgnoredByUser":false},"formautofill@mozilla.org":{"version":"1.0.1","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":null,"name":"Form Autofill","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"ipp-activator@mozilla.com":{"version":"0.3","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"A system add-on to activate IPP in 143","name":"IPP Activator","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"newtab@mozilla.org":{"version":"155.2.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"New Tab","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"pictureinpicture@mozilla.org":{"version":"1.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Fixes for web compatibility with Picture-in-Picture","name":"Picture-In-Picture","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"addons-search-detection@mozilla.com":{"version":"3.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"Add-ons Search Detection","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"webcompat@mozilla.org":{"version":"155.5.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Urgent post-release fixes for web compatibility.","name":"Web Compatibility Interventions","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false}},"theme":{},"activeGMPlugins":{"gmp-gmpopenh264":{"version":null,"userDisabled":false,"applyBackgroundUpdates":1}}}}} \ No newline at end of file diff --git a/tmp-ffprof/saved-telemetry-pings/f7af7a4c-b941-4403-8289-19b458caa23e b/tmp-ffprof/saved-telemetry-pings/f7af7a4c-b941-4403-8289-19b458caa23e new file mode 100644 index 0000000..4ab70a0 --- /dev/null +++ b/tmp-ffprof/saved-telemetry-pings/f7af7a4c-b941-4403-8289-19b458caa23e @@ -0,0 +1 @@ +{"type":"main","id":"f7af7a4c-b941-4403-8289-19b458caa23e","creationDate":"2026-09-19T10:24:05.852Z","version":4,"application":{"architecture":"x86-64","buildId":"20260904071051","name":"Firefox","version":"155.0.1","displayVersion":"155.0.1","vendor":"Mozilla","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","channel":"release"},"payload":{"ver":4,"simpleMeasurements":{"totalTime":3,"main":413,"activeTicks":0},"processes":{"parent":{"scalars":{"browser.engagement.session_time_including_suspend":2267,"gfx.supports_hdr":false,"browser.engagement.session_time_excluding_suspend":2267,"gfx.os_compositor":false,"startup.profile_selection_reason":"argument-profile","gfx.linux_window_protocol":"xwayland","startup.profile_database_version":"2","policies.is_enterprise":false,"startup.profile_count":1,"dom.contentprocess.os_priority_lowered":2,"policies.count":0,"dom.contentprocess.os_priority_change_considered":23},"keyedScalars":{"media.device_hardware_decoding_support":{"av1":true,"hevc":true,"vp8":true,"h264":true,"vp9":true},"networking.data_transferred_v3_kb":{"Y1_N1":48,"Y0_N1Sys":900}}},"content":{"histograms":{"HTTP_PAGE_DNS_LOOKUP_TIME":{"bucket_count":50,"histogram_type":0,"sum":0,"range":[1,30000],"values":{"0":1,"1":0}},"HTTP_PAGE_TCP_CONNECTION_2":{"bucket_count":50,"histogram_type":0,"sum":0,"range":[1,30000],"values":{"0":1,"1":0}},"APZ_ZOOM_ACTIVITY":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":1,"1":0}}},"keyedHistograms":{},"scalars":{},"keyedScalars":{}},"dynamic":{"scalars":{},"keyedScalars":{}},"gpu":{"histograms":{},"keyedHistograms":{},"scalars":{},"keyedScalars":{}},"socket":{"histograms":{},"keyedHistograms":{},"scalars":{},"keyedScalars":{}}},"histograms":{"CHILD_PROCESS_LAUNCH_MS":{"bucket_count":100,"histogram_type":0,"sum":19,"range":[1,64000],"values":{"1":0,"2":2,"3":2,"4":1,"5":1,"6":0}},"CONTENT_PROCESS_LAUNCH_MAINTHREAD_MS":{"bucket_count":100,"histogram_type":0,"sum":3,"range":[1,64000],"values":{"2":0,"3":1,"4":0}},"CONTENT_PROCESS_LAUNCH_TOTAL_MS":{"bucket_count":100,"histogram_type":0,"sum":8,"range":[1,64000],"values":{"7":0,"8":1,"9":0}},"CONTENT_PROCESS_SYNC_LAUNCH_MS":{"bucket_count":100,"histogram_type":0,"sum":13,"range":[1,64000],"values":{"4":0,"5":1,"8":1,"9":0}},"CONTENT_PROCESS_LAUNCH_IS_SYNC":{"bucket_count":3,"histogram_type":2,"sum":2,"range":[1,2],"values":{"0":1,"1":2,"2":0}},"HTTP_TRANSACTION_IS_SSL":{"bucket_count":3,"histogram_type":2,"sum":4,"range":[1,2],"values":{"0":4,"1":4,"2":0}},"HTTP_PAGELOAD_IS_SSL":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":1,"1":0}},"HTTP_CHANNEL_ONSTART_SUCCESS":{"bucket_count":3,"histogram_type":2,"sum":8,"range":[1,2],"values":{"0":1,"1":8,"2":0}},"STARTUP_CACHE_REQUESTS":{"bucket_count":51,"histogram_type":5,"sum":560,"range":[1,50],"values":{"0":1,"2":280,"3":0}},"URLCLASSIFIER_LOOKUP_TIME_2":{"bucket_count":30,"histogram_type":0,"sum":0,"range":[1,5000],"values":{"0":1,"1":0}},"URLCLASSIFIER_SHUTDOWN_TIME":{"bucket_count":50,"histogram_type":0,"sum":0,"range":[1,60000],"values":{"0":1,"1":0}},"URLCLASSIFIER_CL_CHECK_TIME":{"bucket_count":10,"histogram_type":0,"sum":0,"range":[1,500],"values":{"0":1,"1":0}},"FX_SESSION_RESTORE_ALL_FILES_CORRUPT":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":1,"1":0}},"QUERY_STRIPPING_COUNT":{"bucket_count":51,"histogram_type":5,"sum":0,"range":[1,50],"values":{"0":1,"1":0}},"SERVICE_WORKER_ISOLATED_LAUNCH_TIME":{"bucket_count":25,"histogram_type":0,"sum":11,"range":[1,30000],"values":{"5":0,"8":1,"12":0}},"ORB_DID_EVER_BLOCK_RESPONSE":{"bucket_count":3,"histogram_type":2,"sum":0,"range":[1,2],"values":{"0":15,"1":0}}},"keyedHistograms":{"EMAIL_TRACKER_EMBEDDED_PER_TAB":{"content_normal":{"bucket_count":100,"histogram_type":0,"sum":0,"range":[1,1000],"values":{"0":1,"1":0}},"base_normal":{"bucket_count":100,"histogram_type":0,"sum":0,"range":[1,1000],"values":{"0":1,"1":0}},"all_normal":{"bucket_count":100,"histogram_type":0,"sum":0,"range":[1,1000],"values":{"0":1,"1":0}}},"QM_QUOTA_INFO_LOAD_TIME_V0":{"Normal":{"bucket_count":60,"histogram_type":0,"sum":0,"range":[1,180000],"values":{"0":1,"1":0}}},"QM_FIRST_INITIALIZATION_ATTEMPT":{"PersistentOrigin":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryStorage":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryRepository":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"DefaultRepository":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryOrigin":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"Storage":{"bucket_count":3,"histogram_type":2,"sum":1,"range":[1,2],"values":{"0":0,"1":1,"2":0}},"TemporaryGroup":{"bucket_count":3,"histogram_type":2,"sum":7,"range":[1,2],"values":{"0":0,"1":7,"2":0}}},"QM_SHUTDOWN_TIME_V0":{"Normal":{"bucket_count":60,"histogram_type":0,"sum":11,"range":[1,60000],"values":{"8":0,"10":1,"12":0}}},"HTTP_TRAFFIC_ANALYSIS_3":{"Connection":{"bucket_count":51,"histogram_type":5,"sum":4,"range":[1,50],"values":{"0":4,"1":4,"2":0}},"Transaction":{"bucket_count":51,"histogram_type":5,"sum":4,"range":[1,50],"values":{"0":4,"1":4,"2":0}}}},"info":{"reason":"shutdown","revision":"https://hg.mozilla.org/releases/mozilla-release/rev/5fdfd0092780e85643e2cddc0e1b590c8b9ef860","timezoneOffset":-180,"previousBuildId":null,"sessionId":"682852a1-6419-4b1a-b8f0-b7fd58a5bc74","subsessionId":"c848b5d1-24ee-40b0-9de4-7830ea54cf2a","previousSessionId":null,"previousSubsessionId":null,"subsessionCounter":1,"profileSubsessionCounter":1,"sessionStartDate":"2026-09-19T07:00:00.0-03:00","subsessionStartDate":"2026-09-19T07:00:00.0-03:00","sessionLength":2,"subsessionLength":1,"addons":"langpack-de%40firefox.mozilla.org:155.0.20260903.215306,formautofill%40mozilla.org:1.0.1,ipp-activator%40mozilla.com:0.3,newtab%40mozilla.org:155.2.0,pictureinpicture%40mozilla.org:1.0.0,addons-search-detection%40mozilla.com:3.0.0,webcompat%40mozilla.org:155.5.0,default-theme%40mozilla.org:1.4.2"}},"clientId":"f8fb24d3-61c2-4342-b9fb-cb5679e729fc","profileGroupId":"dd6a2853-9d81-4edd-b920-ae094d7305ee","environment":{"build":{"applicationId":"{ec8030f7-c20a-464f-9b0e-13a3a9e97384}","applicationName":"Firefox","architecture":"x86-64","buildId":"20260904071051","version":"155.0.1","vendor":"Mozilla","displayVersion":"155.0.1","platformVersion":"155.0.1","xpcomAbi":"x86_64-gcc3","updaterAvailable":false},"partner":{"distributionId":"canonical-002","distributionVersion":"1.0","partnerId":"ubuntu","distributor":"canonical","distributorChannel":"","partnerNames":["ubuntu"]},"system":{"memoryMB":15712,"virtualMaxMB":null,"cpu":{"count":12,"cores":8,"pcount":8,"mcount":0,"ecount":0,"vendor":"GenuineIntel","name":"12th Gen Intel(R) Core(TM) i5-12450H","family":6,"model":154,"stepping":3,"l2cacheKB":1280,"l3cacheKB":12288,"speedMHz":4400,"extensions":["hasMMX","hasSSE","hasSSE2","hasSSE3","hasSSSE3","hasSSE4_1","hasSSE4_2","hasAVX","hasAVX2","hasAES"]},"os":{"name":"Linux","version":"7.0.0-31-generic","locale":"de-DE","distro":"Ubuntu-core","distroVersion":"24"},"hdd":{"profile":{"model":null,"revision":null,"type":null},"binary":{"model":null,"revision":null,"type":null},"system":{"model":null,"revision":null,"type":null}},"gfx":{"DWriteEnabled":null,"ContentBackend":"Skia","Headless":true,"TargetFrameRate":60,"textScaleFactor":1,"adapters":[{"description":"Mesa Intel(R) Graphics (ADL GT2)","vendorID":"0x8086","deviceID":"0x46a3","subsysID":null,"RAM":0,"driver":null,"driverVendor":"mesa/iris","driverVersion":"25.2.8.0","driverDate":null,"GPUActive":true}],"monitors":[{"screenWidth":1366,"screenHeight":768,"defaultCSSScaleFactor":1,"contentsScaleFactor":1}],"features":{"compositor":"none","hwCompositing":{"status":"blocked:FEATURE_FAILURE_COMP_HEADLESSMODE"},"gpuProcess":{"status":"unused"},"webrender":{"status":"unavailable-no-hw-compositing"},"wrCompositor":{"status":"blocklisted:FEATURE_FAILURE_WEBRENDER_COMPOSITOR_DISABLED"},"openglCompositing":{"status":"unavailable:FEATURE_FAILURE_OPENGL_NEED_HWCOMP"}}},"appleModelId":null,"hasWinPackageId":null},"settings":{"blocklistEnabled":true,"e10sEnabled":true,"e10sMultiProcesses":8,"fissionEnabled":true,"locale":"de","intl":{},"update":{"channel":"release","enabled":false,"autoDownload":false,"background":false},"userPrefs":{"browser.shell.checkDefaultBrowser":false,"browser.urlbar.autoFill":true,"browser.urlbar.autoFill.adaptiveHistory.enabled":false,"browser.urlbar.dnsResolveSingleWordsAfterSearch":0,"browser.urlbar.suggest.quicksuggest.sponsored":false,"network.http.microsoft-entra-sso.enabled":false,"network.trr.strict_native_fallback":false,"widget.content.gtk-high-contrast.enabled":true},"sandbox":{"effectiveContentProcessLevel":6,"contentWin32kLockdownState":3},"addonCompatibilityCheckEnabled":true,"isDefaultBrowser":null},"profile":{"creationDate":20715,"firstUseDate":20715},"addons":{"activeAddons":{"langpack-de@firefox.mozilla.org":{"version":"155.0.20260903.215306","scope":1,"type":"locale","updateDay":20715,"isSystem":false,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Firefox Language Pack for Deutsch (de) – German","name":"Language: Deutsch (German)","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":20715,"signedState":2,"signedTypes":"[2,1]","quarantineIgnoredByApp":false,"quarantineIgnoredByUser":false},"formautofill@mozilla.org":{"version":"1.0.1","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":null,"name":"Form Autofill","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"ipp-activator@mozilla.com":{"version":"0.3","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"A system add-on to activate IPP in 143","name":"IPP Activator","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"newtab@mozilla.org":{"version":"155.2.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"New Tab","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"pictureinpicture@mozilla.org":{"version":"1.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Fixes for web compatibility with Picture-in-Picture","name":"Picture-In-Picture","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"addons-search-detection@mozilla.com":{"version":"3.0.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"","name":"Add-ons Search Detection","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false},"webcompat@mozilla.org":{"version":"155.5.0","scope":4,"type":"extension","updateDay":0,"isSystem":true,"isWebExtension":true,"multiprocessCompatible":true,"blocklisted":false,"description":"Urgent post-release fixes for web compatibility.","name":"Web Compatibility Interventions","userDisabled":false,"appDisabled":false,"foreignInstall":false,"hasBinaryComponents":false,"installDay":0,"quarantineIgnoredByApp":true,"quarantineIgnoredByUser":false}},"theme":{},"activeGMPlugins":{"gmp-gmpopenh264":{"version":null,"userDisabled":false,"applyBackgroundUpdates":1}}}}} \ No newline at end of file diff --git a/tmp-ffprof/sessionCheckpoints.json b/tmp-ffprof/sessionCheckpoints.json new file mode 100644 index 0000000..5d0282f --- /dev/null +++ b/tmp-ffprof/sessionCheckpoints.json @@ -0,0 +1 @@ +{"profile-after-change":true,"final-ui-startup":true,"quit-application-granted":true,"quit-application":true,"profile-change-net-teardown":true,"profile-change-teardown":true,"profile-before-change":true} \ No newline at end of file diff --git a/tmp-ffprof/shield-preference-experiments.json b/tmp-ffprof/shield-preference-experiments.json new file mode 100644 index 0000000..3759a90 --- /dev/null +++ b/tmp-ffprof/shield-preference-experiments.json @@ -0,0 +1 @@ +{"experiments":{}} \ No newline at end of file diff --git a/tmp-ffprof/startupCache/startupCache.8.little b/tmp-ffprof/startupCache/startupCache.8.little new file mode 100644 index 0000000..f601a34 Binary files /dev/null and b/tmp-ffprof/startupCache/startupCache.8.little differ diff --git a/tmp-ffprof/startupCache/webext.sc.lz4 b/tmp-ffprof/startupCache/webext.sc.lz4 new file mode 100644 index 0000000..dfb39c9 Binary files /dev/null and b/tmp-ffprof/startupCache/webext.sc.lz4 differ diff --git a/tmp-ffprof/storage.sqlite b/tmp-ffprof/storage.sqlite new file mode 100644 index 0000000..6abd7d6 Binary files /dev/null and b/tmp-ffprof/storage.sqlite differ diff --git a/tmp-ffprof/storage/default/http+++127.0.0.1+8765/.metadata-v2 b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/.metadata-v2 new file mode 100644 index 0000000..7114578 Binary files /dev/null and b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/.metadata-v2 differ diff --git a/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/.padding b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/.padding new file mode 100644 index 0000000..1b1cb4d Binary files /dev/null and b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/.padding differ diff --git a/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/caches.sqlite b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/caches.sqlite new file mode 100644 index 0000000..9c15401 Binary files /dev/null and b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/caches.sqlite differ diff --git a/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/caches.sqlite-wal b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/caches.sqlite-wal new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/context_open.marker b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/context_open.marker new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/morgue/153/{d59877df-3bc7-48dd-8ad7-60fbe1bbcc99}.final b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/morgue/153/{d59877df-3bc7-48dd-8ad7-60fbe1bbcc99}.final new file mode 100644 index 0000000..d1ce41e Binary files /dev/null and b/tmp-ffprof/storage/default/http+++127.0.0.1+8765/cache/morgue/153/{d59877df-3bc7-48dd-8ad7-60fbe1bbcc99}.final differ diff --git a/tmp-ffprof/storage/ls-archive.sqlite b/tmp-ffprof/storage/ls-archive.sqlite new file mode 100644 index 0000000..6734946 Binary files /dev/null and b/tmp-ffprof/storage/ls-archive.sqlite differ diff --git a/tmp-ffprof/storage/permanent/chrome/.metadata-v2 b/tmp-ffprof/storage/permanent/chrome/.metadata-v2 new file mode 100644 index 0000000..99c708c Binary files /dev/null and b/tmp-ffprof/storage/permanent/chrome/.metadata-v2 differ diff --git a/tmp-ffprof/storage/permanent/chrome/idb/3561288849sdhlie.sqlite b/tmp-ffprof/storage/permanent/chrome/idb/3561288849sdhlie.sqlite new file mode 100644 index 0000000..0a1aa26 Binary files /dev/null and b/tmp-ffprof/storage/permanent/chrome/idb/3561288849sdhlie.sqlite differ diff --git a/tmp-ffprof/storage/permanent/chrome/idb/3561288849sdhlie.sqlite-wal b/tmp-ffprof/storage/permanent/chrome/idb/3561288849sdhlie.sqlite-wal new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/storage/permanent/chrome/idb/3870112724rsegmnoittet-es.sqlite b/tmp-ffprof/storage/permanent/chrome/idb/3870112724rsegmnoittet-es.sqlite new file mode 100644 index 0000000..420ec85 Binary files /dev/null and b/tmp-ffprof/storage/permanent/chrome/idb/3870112724rsegmnoittet-es.sqlite differ diff --git a/tmp-ffprof/storage/permanent/chrome/idb/3870112724rsegmnoittet-es.sqlite-wal b/tmp-ffprof/storage/permanent/chrome/idb/3870112724rsegmnoittet-es.sqlite-wal new file mode 100644 index 0000000..e69de29 diff --git a/tmp-ffprof/times.json b/tmp-ffprof/times.json new file mode 100644 index 0000000..495da20 --- /dev/null +++ b/tmp-ffprof/times.json @@ -0,0 +1 @@ +{"firstUse":1789813444852,"created":1789813442191} \ No newline at end of file diff --git a/tmp-ffprof/user.js b/tmp-ffprof/user.js new file mode 100644 index 0000000..38b8135 --- /dev/null +++ b/tmp-ffprof/user.js @@ -0,0 +1,5 @@ +user_pref("browser.shell.checkDefaultBrowser", false); +user_pref("browser.startup.homepage_override.mstone", "ignore"); +user_pref("datareporting.policy.dataSubmissionEnabled", false); +user_pref("toolkit.telemetry.enabled", false); +user_pref("app.update.auto", false); diff --git a/tools/make_icons.py b/tools/make_icons.py new file mode 100644 index 0000000..7d04d1b --- /dev/null +++ b/tools/make_icons.py @@ -0,0 +1,53 @@ +"""Generates the PWA icons. Run: python3 tools/make_icons.py""" + +import os + +from PIL import Image, ImageDraw + +BG = (14, 14, 17, 255) +GREY = (139, 139, 150, 255) +RED = (255, 59, 48, 255) +WHITE = (242, 242, 245, 255) + +OUT_DIR = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "icons") +SS = 4 # supersampling factor for smooth edges + + +def make_icon(size, content_scale): + s = size * SS + img = Image.new("RGBA", (s, s), BG) + d = ImageDraw.Draw(img) + + cx = cy = s / 2 + r = s * content_scale / 2 + width = int(s * 0.072) + box = [cx - r, cy - r, cx + r, cy + r] + + # grey arc = pause (270 deg), red arc = training (90 deg) + d.arc(box, start=-90, end=180, fill=GREY, width=width) + d.arc(box, start=180, end=270, fill=RED, width=width) + + # clock hand pointing up + hand_w = int(s * 0.05) + d.line([(cx, cy), (cx, cy - r * 0.58)], fill=WHITE, width=hand_w) + dot = hand_w * 0.9 + d.ellipse([cx - dot, cy - dot, cx + dot, cy + dot], fill=WHITE) + + return img.resize((size, size), Image.Resampling.LANCZOS) + + +def main(): + os.makedirs(OUT_DIR, exist_ok=True) + targets = [ + ("icon-192.png", 192, 0.78), + ("icon-512.png", 512, 0.78), + ("icon-maskable-512.png", 512, 0.60), + ] + for name, size, scale in targets: + path = os.path.join(OUT_DIR, name) + make_icon(size, scale).save(path, "PNG") + print("wrote", path) + + +if __name__ == "__main__": + main() diff --git a/tools/probe_firefox.py b/tools/probe_firefox.py new file mode 100644 index 0000000..0ab0628 --- /dev/null +++ b/tools/probe_firefox.py @@ -0,0 +1,117 @@ +"""Probes Firefox's web-platform support by loading a page that reports back. + +Usage: python3 tools/probe_firefox.py +Launches headless Firefox against a local page whose script POSTs its feature +detection results back to this server, then prints them. +""" + +import http.server +import json +import os +import shutil +import subprocess +import threading + +PORT = 8766 + +# Snap-confined Firefox cannot see /tmp, so the profile lives next to the repo. +ROOT = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) +PROFILE = os.path.join(ROOT, 'tmp-ffprof-probe') + +USER_JS = ''' +user_pref("browser.shell.checkDefaultBrowser", false); +user_pref("browser.startup.homepage_override.mstone", "ignore"); +user_pref("datareporting.policy.dataSubmissionEnabled", false); +user_pref("toolkit.telemetry.enabled", false); +user_pref("app.update.auto", false); +''' + +PAGE = """ + +""" + +report = {} +done = threading.Event() + + +class Handler(http.server.BaseHTTPRequestHandler): + def do_GET(self): + if self.path == '/manifest.webmanifest': + body = json.dumps({ + "name": "Probe", "short_name": "Probe", "start_url": "./", + "display": "standalone", + "icons": [{"src": "/icon.png", "sizes": "192x192", "type": "image/png"}], + }).encode() + self.send_response(200) + self.send_header('Content-Type', 'application/manifest+json') + self.send_header('Content-Length', str(len(body))) + self.end_headers() + self.wfile.write(body) + return + body = PAGE.encode() + self.send_response(200) + self.send_header('Content-Type', 'text/html') + self.send_header('Content-Length', str(len(body))) + self.end_headers() + self.wfile.write(body) + + def do_POST(self): + length = int(self.headers.get('Content-Length', 0)) + report.update(json.loads(self.rfile.read(length) or b'{}')) + self.send_response(204) + self.end_headers() + done.set() + + def log_message(self, *args): + pass + + +def main(): + server = http.server.ThreadingHTTPServer(('127.0.0.1', PORT), Handler) + threading.Thread(target=server.serve_forever, daemon=True).start() + + shutil.rmtree(PROFILE, ignore_errors=True) + os.makedirs(PROFILE, exist_ok=True) + with open(os.path.join(PROFILE, 'user.js'), 'w') as fh: + fh.write(USER_JS) + + proc = subprocess.Popen( + ['firefox', '--headless', '--no-remote', '--new-instance', + '--profile', PROFILE, f'http://127.0.0.1:{PORT}/'], + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, + ) + + ok = done.wait(timeout=30) + proc.terminate() + try: + proc.wait(timeout=10) + except subprocess.TimeoutExpired: + proc.kill() + server.shutdown() + shutil.rmtree(PROFILE, ignore_errors=True) + + if not ok: + print('probe: no report received (Firefox did not run the page)') + return + print(json.dumps(report, indent=2, sort_keys=True)) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/tools/smoke_test.mjs b/tools/smoke_test.mjs new file mode 100644 index 0000000..224695c --- /dev/null +++ b/tools/smoke_test.mjs @@ -0,0 +1,320 @@ +/** + * Functional smoke test: drives the real page in headless Chrome over CDP. + * Assumes a server on 127.0.0.1:8765 and Chrome with --remote-debugging-port=9222. + */ + +const PORT = 9222; +const ORIGIN = '127.0.0.1:8765'; + +const GREY = 'rgb(139, 139, 150)'; +const RED = 'rgb(255, 59, 48)'; + +function fail(msg) { + console.error('FAIL: ' + msg); + process.exit(1); +} + +async function connect() { + const res = await fetch(`http://127.0.0.1:${PORT}/json/list`); + const targets = await res.json(); + const page = targets.find((t) => t.type === 'page' && t.url.includes(ORIGIN)); + if (!page) fail('page target not found: ' + JSON.stringify(targets.map((t) => t.url))); + + const ws = new WebSocket(page.webSocketDebuggerUrl); + await new Promise((resolve, reject) => { + ws.addEventListener('open', resolve, { once: true }); + ws.addEventListener('error', reject, { once: true }); + }); + + let nextId = 0; + const pending = new Map(); + ws.addEventListener('message', (ev) => { + const msg = JSON.parse(ev.data); + const resolve = pending.get(msg.id); + if (resolve) { + pending.delete(msg.id); + resolve(msg); + } + }); + + const send = (method, params) => + new Promise((resolve) => { + const id = ++nextId; + pending.set(id, resolve); + ws.send(JSON.stringify({ id, method, params })); + }); + + const evaluate = async (expression) => { + const msg = await send('Runtime.evaluate', { + expression, + returnByValue: true, + awaitPromise: true, + }); + if (msg.result?.exceptionDetails) { + throw new Error('page exception: ' + JSON.stringify(msg.result.exceptionDetails)); + } + return msg.result.result.value; + }; + + return { evaluate, send, close: () => ws.close() }; +} + +const SNAPSHOT = `(() => { + const clock = document.getElementById('clock'); + const exName = document.getElementById('exerciseName'); + return { + phase: document.getElementById('phaseLabel').textContent, + exercise: exName.textContent, + clock: clock.textContent, + progress: document.getElementById('progress').textContent, + next: document.getElementById('nextUp').textContent, + bodyClass: document.body.className, + exColor: getComputedStyle(exName).color, + clockColor: getComputedStyle(clock).color, + }; +})()`; + +const SETUP = `(() => { + // measure target colours, not the in-flight transition + const style = document.createElement('style'); + style.textContent = '* { transition: none !important; animation: none !important; }'; + document.head.append(style); + + const setVal = (id, v) => { + const el = document.getElementById(id); + el.value = String(v); + el.dispatchEvent(new Event('change', { bubbles: true })); + }; + setVal('pauseInput', 2); + setVal('workInput', 1); + setVal('setsInput', 2); + const add = (name) => { + const input = document.getElementById('exerciseInput'); + input.value = name; + document.getElementById('addBtn').click(); + }; + add(' '); // blank input must be ignored + add('Push-ups'); + add('Squats'); + add('Plank'); + document.getElementById('exerciseInput').value = 'Deadlift'; + document.getElementById('addBtn').click(); + document.querySelectorAll('#exerciseList li')[3].querySelector('button').click(); // remove Deadlift + return { + listed: Array.from(document.querySelectorAll('#exerciseList li .name')).map(n => n.textContent), + clockBeforeStart: document.getElementById('clock').textContent, + startLabel: document.getElementById('startBtn').textContent, + }; +})()`; + +const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); + +function expect(cond, msg) { + if (!cond) fail(msg); +} + +/** Evaluate, tolerating the brief window where a reload has no execution context yet. */ +async function evaluateRetry(evaluate, expression, attempts = 15) { + for (let i = 0; i < attempts; i++) { + try { + return await evaluate(expression); + } catch { + await sleep(300); + } + } + return fail(`page never became responsive: ${expression}`); +} + +/** "00:07" -> 7 */ +function toSecs(text) { + const [m, s] = text.split(':').map(Number); + return m * 60 + s; +} + +async function main() { + const { evaluate, send, close } = await connect(); + + // the settings panel must be reachable before anything can be configured + await evaluate(`document.getElementById('settingsToggle').click()`); + const panel = await evaluate(`({ + hidden: document.getElementById('settings').hidden, + expanded: document.getElementById('settingsToggle').getAttribute('aria-expanded'), + })`); + expect(!panel.hidden && panel.expanded === 'true', 'settings toggle should open the panel'); + + const setup = await evaluate(SETUP); + console.log('setup:', JSON.stringify(setup)); + + if (JSON.stringify(setup.listed) !== JSON.stringify(['Push-ups', 'Squats', 'Plank'])) { + fail('exercise list should hold exactly the three added names'); + } + if (setup.startLabel !== 'Start') fail('start button should read "Start" before starting'); + + await evaluate(`document.getElementById('startBtn').click()`); + + const seen = []; + const colors = { grey: 0, red: 0 }; + const deadline = Date.now() + 30000; + + while (Date.now() < deadline) { + const s = await evaluate(SNAPSHOT); + const key = `${s.phase}|${s.exercise}|${s.progress}`; + if (!seen.length || seen[seen.length - 1].key !== key) { + seen.push({ key, at: Date.now(), clockSecs: toSecs(s.clock), ...s }); + } else { + const last = seen[seen.length - 1]; + if (toSecs(s.clock) > last.clockSecs) fail(`clock went up during ${s.phase}: ${last.clock} -> ${s.clock}`); + last.clockSecs = toSecs(s.clock); + } + if (s.phase === 'Done') break; + await sleep(150); + } + + console.log('\nobserved sequence:'); + for (const s of seen) { + console.log(` ${s.phase.padEnd(8)} | ${s.exercise.padEnd(16)} | ${s.clock} | ${s.progress} | ${s.next}`); + if (s.exercise === 'Workout complete') continue; + if (s.phase === 'Pause') { + if (s.exColor !== GREY || s.clockColor !== GREY) fail(`pause should be grey, got ${s.exColor}`); + colors.grey++; + } else if (s.phase === 'Training') { + if (s.exColor !== RED || s.clockColor !== RED) fail(`training should be red, got ${s.exColor}`); + colors.red++; + } + } + + const expected = [ + 'Pause|Push-ups', + 'Training|Push-ups', + 'Pause|Squats', + 'Training|Squats', + 'Pause|Plank', + 'Training|Plank', + 'Pause|Push-ups', + 'Training|Push-ups', + 'Pause|Squats', + 'Training|Squats', + 'Pause|Plank', + 'Training|Plank', + 'Done|Workout complete', + ]; + + const actual = seen.map((s) => `${s.phase}|${s.exercise}`); + console.log('\nexpected:', expected.join(' -> ')); + console.log('actual: ', actual.join(' -> ')); + + if (actual.join('|') !== expected.join('|')) { + fail('phase sequence mismatch'); + } + + // each pause should last ~2s and each training block ~1s (poll lag allowed for). + // phases chain off their deadline, so error must not accumulate from one to the next. + for (let i = 0; i < seen.length - 1; i++) { + const expectedMs = seen[i].phase === 'Pause' ? 2000 : 1000; + const actualMs = seen[i + 1].at - seen[i].at; + console.log(` ${seen[i].phase.padEnd(8)} ${String(actualMs).padStart(5)}ms (expected ~${expectedMs}ms)`); + if (Math.abs(actualMs - expectedMs) > 350) { + fail(`${seen[i].phase} of ${seen[i].exercise} lasted ${actualMs}ms, expected ~${expectedMs}ms`); + } + } + + /* ---- restart / pause / resume / reset / persistence ---- */ + + await evaluate(`document.getElementById('startBtn').click()`); + await sleep(200); + let s = await evaluate(SNAPSHOT); + expect(s.phase === 'Pause' && s.progress.includes('Set 1 / 2'), `restart should begin a fresh session, got ${s.phase} / ${s.progress}`); + expect(s.exercise === 'Push-ups', `restart should show the first exercise, got ${s.exercise}`); + + let ui = await evaluate(`({ + startHidden: document.getElementById('startBtn').hidden, + resetHidden: document.getElementById('resetBtn').hidden, + inputsDisabled: document.getElementById('pauseInput').disabled && document.getElementById('addBtn').disabled, + })`); + expect(ui.startHidden && !ui.resetHidden, 'while running: Start hidden, Reset visible'); + expect(ui.inputsDisabled, 'settings inputs should be locked while running'); + + await evaluate(`document.getElementById('pauseBtn').click()`); + await sleep(150); + const before = await evaluate(SNAPSHOT); + await sleep(700); + const after = await evaluate(SNAPSHOT); + expect(before.phase === 'Paused', `expected Paused label, got ${before.phase}`); + expect(before.clock === after.clock, `clock must freeze while paused: ${before.clock} -> ${after.clock}`); + expect(await evaluate(`document.getElementById('pauseBtn').textContent`) === 'Resume', 'pause button should offer Resume'); + + await evaluate(`document.getElementById('pauseBtn').click()`); + await sleep(150); + s = await evaluate(SNAPSHOT); + expect(s.phase === 'Pause', `resume should continue the paused phase, got ${s.phase}`); + + await evaluate(`document.getElementById('resetBtn').click()`); + await sleep(200); + s = await evaluate(SNAPSHOT); + expect(s.phase === 'Ready' && s.clock === '00:02', `reset should return to Ready / 00:02, got ${s.phase} / ${s.clock}`); + ui = await evaluate(`({ + startLabel: document.getElementById('startBtn').textContent, + startHidden: document.getElementById('startBtn').hidden, + pauseHidden: document.getElementById('pauseBtn').hidden, + resetHidden: document.getElementById('resetBtn').hidden, + inputsDisabled: document.getElementById('pauseInput').disabled, + listed: Array.from(document.querySelectorAll('#exerciseList li .name')).map((n) => n.textContent), + })`); + expect(ui.startLabel === 'Start' && !ui.startHidden, 'reset should restore the Start button'); + expect(ui.pauseHidden && ui.resetHidden, 'reset should hide Pause and Reset'); + expect(!ui.inputsDisabled, 'settings inputs should be editable again after reset'); + expect(JSON.stringify(ui.listed) === JSON.stringify(['Push-ups', 'Squats', 'Plank']), 'exercises should survive a reset'); + + const stored = await evaluate(`localStorage.getItem('interval-timer/v1')`); + const parsed = JSON.parse(stored); + expect( + parsed.pauseSec === 2 && parsed.workSec === 1 && parsed.sets === 2 && parsed.exercises.length === 3, + 'settings should be persisted: ' + stored + ); + console.log('\nrestart/pause/resume/reset/persistence: ok'); + + /* ---- PWA: service worker, cached shell, offline boot ---- */ + + const sw = await evaluate(`(async () => { + if (!('serviceWorker' in navigator)) return { supported: false }; + const reg = await navigator.serviceWorker.ready; + const keys = await caches.keys(); + const cached = []; + for (const key of keys) { + for (const req of await (await caches.open(key)).keys()) { + cached.push(new URL(req.url).pathname); + } + } + return { supported: true, active: !!reg.active, scope: reg.scope, cached: cached.sort() }; + })()`); + console.log('service worker:', JSON.stringify(sw)); + expect(sw.supported, 'service workers should be supported in a secure context'); + expect(sw.active, 'service worker should be installed and active'); + + for (const asset of ['/', '/index.html', '/styles.css', '/app.js', '/manifest.webmanifest', + '/icons/icon-192.png', '/icons/icon-512.png', '/icons/icon-maskable-512.png']) { + expect(sw.cached.includes(asset), `app shell should be cached: ${asset} (have ${sw.cached.join(', ')})`); + } + + await send('Network.enable'); + await send('Page.enable'); + await send('Network.emulateNetworkConditions', { + offline: true, latency: 0, downloadThroughput: 0, uploadThroughput: 0, + }); + await send('Page.reload', {}); + + const offlinePhase = await evaluateRetry(evaluate, `document.getElementById('phaseLabel').textContent`); + const offlineEx = await evaluateRetry(evaluate, `document.getElementById('exerciseName').textContent`); + expect(offlinePhase === 'Ready', `app should boot from cache while offline, got "${offlinePhase}"`); + expect(offlineEx === 'Push-ups', `offline boot should restore saved exercises, got "${offlineEx}"`); + console.log('offline reload: ok (Phase="' + offlinePhase + '", Exercise="' + offlineEx + '")'); + + await send('Network.emulateNetworkConditions', { + offline: false, latency: 0, downloadThroughput: -1, uploadThroughput: -1, + }); + + close(); + console.log(`\nPASS — pause/training sequence, grey->red colours, timing, controls, PWA offline all verified`); +} + +main().catch((err) => fail(err.stack || String(err))); \ No newline at end of file