diff --git a/APPS_README.md b/APPS_README.md index c835ab7..813cc68 100644 --- a/APPS_README.md +++ b/APPS_README.md @@ -204,6 +204,100 @@ Use these keys to synchronize related fields: } ``` +## Optional: Localization & Shared Helpers + +`fetch()` can opt into runtime-injected helpers by **declaring extra parameters**. +The runtime inspects your signature and only passes a helper if you name it, so the +classic four-argument `fetch(settings, format_lines, get_rows, get_cols)` keeps +working unchanged — every helper below is purely opt-in and backward compatible. + +### Localization (`i18n`) + +If your app shows words (day/month names, status labels), add an `i18n=None` +parameter. The runtime binds it to the global **Language** setting; on a host +without it (or with `babel` not installed) `i18n` is `None` and you fall back to +English. + +```python +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + from datetime import datetime + now = datetime.now() + weekday = i18n.weekday(now) if i18n else now.strftime("%A").upper() + label = i18n.t("SUNRISE") if i18n else "SUNRISE" + return [format_lines(weekday, label)] +``` + +- `i18n.weekday(dt, short=False)` / `i18n.month(dt, short=False)` — CLDR-correct, + UPPERCASE day/month names for every language. +- `i18n.date(dt, short=False, year=False)` — day + month (and optional year) in the + locale's **own order and wording**: `JULY 9` in English but `9 JUILLET` (fr), + `9. JULI` (de). Don't hand-assemble `month + " " + day` — order is language-specific. +- `i18n.time(dt, seconds=False)` — wall-clock time: `3:48 PM` in English, `15:48` + elsewhere. `i18n.is_24h` exposes the same decision if you branch yourself. +- `i18n.unit("D")` — localized compact duration suffix for `D`/`H`/`M`/`S`, so `175D` + becomes `175J` in French (jour), `175T` in German (Tag). +- `i18n.number(value, decimals=2, grouping=True)` — a number with the locale's own + separators: `1,234.50` (en) vs `1.234,50` (de) vs `1 234,50` (fr). Use it for any + price/rate/percent — never hardcode `f"{v:,.2f}"`. +- `i18n.base_currency()` / `i18n.country()` — the currency / country a language-region + implies (a sensible default; prefer `get_location` below for geography). +- `i18n.t("ENGLISH LABEL")` — a translated UI word; with no translation it returns the + English key, so nothing ever breaks. All data lives in `server/i18n_data.json` (the + language list, translations, and per-language default currency/country). Add keys or + languages there rather than in your app, keep them short (modules are narrow), and + give each key a generic `context` note so translators know what the word means. A + regional variant like `pt-BR` automatically inherits every `pt` translation. + +Once your app adapts to the language, add `"i18n": true` to its `manifest.json`. When +internationalization is enabled the Apps grid shows a 🌐 badge on those cards, and the +app automatically gets a per-app **Language** override in its settings (blank = follow +the global Language). Only Western-European (Windows-1252) languages are offered — the +modules can't display Greek, Cyrillic, CJK, etc. + +Internationalization is **off by default**: unless the user turns on *Enable +internationalization* in Settings, `i18n` is not injected and your app runs its +English `i18n=None` fallback — so always keep that fallback correct. The toggle exists +because accented glyphs only render on modules whose firmware/character map supports +them. + +### Shared current weather (`get_weather`) + +If your app shows the weather, don't hardcode a provider — add a `get_weather=None` +parameter and call it: + +```python +def fetch(settings, format_lines, get_rows, get_cols, get_weather=None): + if get_weather is None: # host without the helper + return [format_lines("NO WEATHER")] + w = get_weather() # uses the *global* provider + key + location + if not w["ok"]: + return [format_lines("WEATHER", "UNAVAILABLE")] + return [format_lines(w["city"], f'{w["temp_f"]}F {w["desc"]}')] +``` + +`get_weather()` returns a dict: `ok`, `city`, `temp_f`, `feels_like_f`, `hi_f`, +`lo_f`, `desc`, `humidity`, `wind_mph`, `cloud_cover`, `provider`, `lat`, `lon` +(temps in °F; `ok` is `False` with an `error` key on failure). The default provider +is keyless Open-Meteo, so weather works with **no API key**. + +### Location → country / currency (`get_location`) + +Anything tied to *geography* — which currency, which country's holidays — should key +off the configured **Location**, not the language. Declare a `get_location` +parameter for the shared resolver: + +```python +def fetch(settings, format_lines, get_rows, get_cols, get_location=None): + loc = get_location() if get_location else {} + country = loc.get("country") # ISO 3166-1 alpha-2, e.g. "CA" + subdivision = loc.get("subdivision") # ISO 3166-2, e.g. "CA-QC"; may be None + currency = loc.get("currency") # ISO 4217, e.g. "CAD" (None if unknown) +``` + +It reverse-geocodes the global Location once (cached) and is keyless. Declaring +`get_location` also gives the app an automatic per-app **Location** override in its +settings. Helpers compose: `def fetch(..., get_weather=None, get_location=None, i18n=None)`. + ## Final Checklist - Confirm your app directory contains `manifest.json` and `app.py`. diff --git a/apps/advice/app.py b/apps/advice/app.py new file mode 100644 index 0000000..1213959 --- /dev/null +++ b/apps/advice/app.py @@ -0,0 +1,105 @@ +"""A random piece of advice (keyless: Advice Slip).""" + + +def _need_lines(lens, cols): + need, cur = 1, 0 + for wl in lens: + add = wl if cur == 0 else cur + 1 + wl + if add <= cols: + cur = add + else: + need += 1 + cur = wl + return need + + +def _balance(words, lens, cols, k): + """Split words into exactly k lines (each <= cols) minimizing raggedness, so + lines fill evenly instead of orphaning the last word; prefers ending a line at + sentence punctuation. A tiny DP.""" + n = len(words) + pre = [0] + for wl in lens: + pre.append(pre[-1] + wl) + + def linelen(i, j): + return pre[j + 1] - pre[i] + (j - i) + + INF = float("inf") + dp = [[INF] * (n + 1) for _ in range(k + 1)] + nxt = [[0] * (n + 1) for _ in range(k + 1)] + dp[0][n] = 0.0 + for kk in range(1, k + 1): + for i in range(n - 1, -1, -1): + j = i + while j < n: + ll = linelen(i, j) + if ll > cols and j > i: + break + rest = dp[kk - 1][j + 1] + if rest < INF: + slack = cols - ll + cost = slack * slack + rest + if words[j][-1:] in ".!?": + cost -= cols + if cost < dp[kk][i]: + dp[kk][i] = cost + nxt[kk][i] = j + 1 + j += 1 + if dp[k][0] >= INF: + return None + out, i, kk = [], 0, k + while kk > 0: + j = nxt[kk][i] + out.append(" ".join(words[i:j])) + i, kk = j, kk - 1 + return out + + +def _greedy(words, cols): + lines, cur = [], '' + for w in words: + w = w if len(w) <= cols else w[:cols] + if len(cur) + len(w) + (1 if cur else 0) <= cols: + cur = f'{cur} {w}'.strip() + else: + lines.append(cur) + cur = w + if cur: + lines.append(cur) + return lines or [''] + + +def _pages(format_lines, title, text, rows, cols): + """Lay the text out under a title. When it fits on one page the words are + balanced evenly across the lines it needs; longer text word-wraps and + paginates.""" + words = text.split() or [''] + lens = [len(w) for w in words] + if rows == 1: + return [ln.center(cols)[:cols] for ln in _greedy(words, cols)] + body = rows - 1 if title else rows + if max(lens) <= cols: + need = _need_lines(lens, cols) + if need <= body: + bal = _balance(words, lens, cols, need) + if bal is not None: + return [format_lines(title, *bal)] if title else [format_lines(*bal)] + lines = _greedy(words, cols) + pages, i = ([format_lines(title, *lines[:body])], body) if title else ([], 0) + while i < len(lines): + pages.append(format_lines(*lines[i:i + rows])) + i += rows + return pages + +def fetch(settings, format_lines, get_rows, get_cols): + import requests + rows, cols = get_rows(), get_cols() + try: + d = requests.get('https://api.adviceslip.com/advice', timeout=8).json() + text = str((d.get('slip') or {}).get('advice', '') or '').strip().upper() + if not text: + return [format_lines('ADVICE', 'NO DATA', '')] + return _pages(format_lines, '', f'ADVICE: {text}', rows, cols) + except Exception: + return [format_lines('ADVICE', 'OFFLINE', '')] diff --git a/apps/advice/manifest.json b/apps/advice/manifest.json new file mode 100644 index 0000000..5dc2114 --- /dev/null +++ b/apps/advice/manifest.json @@ -0,0 +1,34 @@ +{ + "id": "advice", + "name": "Advice", + "icon": "🧭", + "description": "A random piece of advice", + "type": "functional", + "refresh_interval": 1800, + "loop_delay": 7, + "category": "entertainment", + "min_rows": 2, + "min_cols": 15, + "settings": [ + { + "key": "refresh_minutes", + "label": "Fetch new advice every (minutes)", + "type": "number", + "default": "30", + "min": "1", + "max": "1440", + "step": "1", + "stepper": true + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "7", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/aurora/app.py b/apps/aurora/app.py new file mode 100644 index 0000000..f5efa8f --- /dev/null +++ b/apps/aurora/app.py @@ -0,0 +1,49 @@ +"""Aurora / geomagnetic activity — planetary K-index (NOAA SWPC, keyless).""" + + +def _label(kp): + if kp < 3: + return 'QUIET' + if kp < 5: + return 'UNSETTLED' + if kp < 6: + return 'MINOR STORM' + if kp < 7: + return 'MODERATE' + if kp < 8: + return 'STRONG STORM' + if kp < 9: + return 'SEVERE STORM' + return 'EXTREME' + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + import requests + rows = get_rows() + + def t(s): + return i18n.t(s, "aurora") if i18n is not None else s + + def num(kp): # integer Kp shows no decimal + whole = (kp == int(kp)) + if i18n is not None: + return i18n.number(kp, decimals=0 if whole else 1, grouping=False) + return f'{kp:.0f}' if whole else f'{kp:.1f}' + + try: + data = requests.get('https://services.swpc.noaa.gov/products/noaa-planetary-k-index.json', + timeout=8).json() + if not isinstance(data, list) or not data: + return [format_lines(t('AURORA'), t('NO DATA'), '')] + latest = data[-1] + # The feed is a list of {time_tag, Kp, ...} records (newest last). + kp = float(latest.get('Kp') if isinstance(latest, dict) else latest[1]) + kps = num(kp) + label = t(_label(kp)) + if rows == 1: + return [format_lines(f'{t("AURORA")} KP {kps}')] + if rows == 2: + return [format_lines(f'{t("AURORA")} KP {kps}', label)] + return [format_lines(t('AURORA'), f'KP INDEX {kps}', label)] + except Exception: + return [format_lines(t('AURORA'), t('OFFLINE'), '')] diff --git a/apps/aurora/manifest.json b/apps/aurora/manifest.json new file mode 100644 index 0000000..a2ec3b1 --- /dev/null +++ b/apps/aurora/manifest.json @@ -0,0 +1,25 @@ +{ + "id": "aurora", + "name": "Aurora Watch", + "icon": "🌌", + "description": "Geomagnetic activity (Kp index)", + "type": "functional", + "i18n": true, + "refresh_interval": 900, + "loop_delay": 6, + "category": "data", + "min_rows": 1, + "min_cols": 12, + "settings": [ + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/bitcoin-fear-greed/app.py b/apps/bitcoin-fear-greed/app.py index 1f3a88f..88f2b5c 100644 --- a/apps/bitcoin-fear-greed/app.py +++ b/apps/bitcoin-fear-greed/app.py @@ -1,8 +1,12 @@ """Bitcoin Fear & Greed Index plugin for Split-Flap Display.""" -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): import urllib.request import json + + def t(s): + return i18n.t(s, "sentiment") if i18n is not None else s + try: url = "https://api.alternative.me/fng/?limit=1" req = urllib.request.Request(url, headers={"User-Agent": "SplitFlap/1.0"}) @@ -10,10 +14,11 @@ def fetch(settings, format_lines, get_rows, get_cols): data = json.loads(resp.read().decode()) entry = data["data"][0] value = entry["value"] - label = entry["value_classification"].upper() + # "Extreme Fear" / "Fear" / "Neutral" / "Greed" / "Extreme Greed" -> localized. + label = t(entry["value_classification"].upper()) return [format_lines("BTC FEAR&GREED", f"INDEX: {value}/100", label)] except Exception: - return [format_lines("FEAR & GREED", "FETCH ERROR", "")] + return [format_lines("BTC FEAR&GREED", t("OFFLINE"), "")] def trigger(settings, conditions): diff --git a/apps/bitcoin-fear-greed/manifest.json b/apps/bitcoin-fear-greed/manifest.json index 7e539fd..9bd5bf4 100644 --- a/apps/bitcoin-fear-greed/manifest.json +++ b/apps/bitcoin-fear-greed/manifest.json @@ -5,6 +5,7 @@ "description": "Bitcoin Fear and Greed Index", "category": "finance", "type": "functional", + "i18n": true, "version": "1.0", "refresh_interval": 300, "loop_delay": 10, diff --git a/apps/cat-facts/app.py b/apps/cat-facts/app.py new file mode 100644 index 0000000..054f18b --- /dev/null +++ b/apps/cat-facts/app.py @@ -0,0 +1,115 @@ +"""A random cat fact (keyless: catfact.ninja).""" + + +def _need_lines(lens, cols): + need, cur = 1, 0 + for wl in lens: + add = wl if cur == 0 else cur + 1 + wl + if add <= cols: + cur = add + else: + need += 1 + cur = wl + return need + + +def _balance(words, lens, cols, k): + """Split words into exactly k lines (each <= cols) minimizing raggedness, so + lines fill evenly instead of orphaning the last word; prefers ending a line at + sentence punctuation. A tiny DP.""" + n = len(words) + pre = [0] + for wl in lens: + pre.append(pre[-1] + wl) + + def linelen(i, j): + return pre[j + 1] - pre[i] + (j - i) + + INF = float("inf") + dp = [[INF] * (n + 1) for _ in range(k + 1)] + nxt = [[0] * (n + 1) for _ in range(k + 1)] + dp[0][n] = 0.0 + for kk in range(1, k + 1): + for i in range(n - 1, -1, -1): + j = i + while j < n: + ll = linelen(i, j) + if ll > cols and j > i: + break + rest = dp[kk - 1][j + 1] + if rest < INF: + slack = cols - ll + cost = slack * slack + rest + if words[j][-1:] in ".!?": + cost -= cols + if cost < dp[kk][i]: + dp[kk][i] = cost + nxt[kk][i] = j + 1 + j += 1 + if dp[k][0] >= INF: + return None + out, i, kk = [], 0, k + while kk > 0: + j = nxt[kk][i] + out.append(" ".join(words[i:j])) + i, kk = j, kk - 1 + return out + + +def _greedy(words, cols): + lines, cur = [], '' + for w in words: + w = w if len(w) <= cols else w[:cols] + if len(cur) + len(w) + (1 if cur else 0) <= cols: + cur = f'{cur} {w}'.strip() + else: + lines.append(cur) + cur = w + if cur: + lines.append(cur) + return lines or [''] + + +def _pages(format_lines, title, text, rows, cols): + """Lay the text out (optionally under a title). When it fits on one page the + words are balanced evenly across the lines; longer text word-wraps and + paginates. With no title the text uses every row and is vertically centered.""" + words = text.split() or [''] + lens = [len(w) for w in words] + if rows == 1: + return [ln.center(cols)[:cols] for ln in _greedy(words, cols)] + body = rows - 1 if title else rows + if max(lens) <= cols: + need = _need_lines(lens, cols) + if need <= body: + bal = _balance(words, lens, cols, need) + if bal is not None: + if title: + return [format_lines(title, *bal)] + top = (rows - len(bal)) // 2 + return [format_lines(*([''] * top + bal))] + lines = _greedy(words, cols) + pages, i = ([format_lines(title, *lines[:body])], body) if title else ([], 0) + while i < len(lines): + pages.append(format_lines(*lines[i:i + rows])) + i += rows + return pages + +def fetch(settings, format_lines, get_rows, get_cols): + import requests + rows, cols = get_rows(), get_cols() + try: + max_len = int(float(settings.get('max_length', '120') or 120)) + except (TypeError, ValueError): + max_len = 120 + max_len = max(40, min(250, max_len)) + try: + # catfact.ninja honors max_length, so we can ask for a display-friendly fact. + d = requests.get('https://catfact.ninja/fact', + params={'max_length': max_len}, timeout=8).json() + text = str(d.get('fact', '') or '').strip().upper() + if not text: + return [format_lines('CAT FACT', 'NO DATA', '')] + return _pages(format_lines, '', text, rows, cols) # no title — just the fact + except Exception: + return [format_lines('CAT FACT', 'OFFLINE', '')] diff --git a/apps/cat-facts/manifest.json b/apps/cat-facts/manifest.json new file mode 100644 index 0000000..d6cad1f --- /dev/null +++ b/apps/cat-facts/manifest.json @@ -0,0 +1,44 @@ +{ + "id": "cat-facts", + "name": "Cat Facts", + "icon": "🐱", + "description": "A concise cat fact", + "type": "functional", + "refresh_interval": 1800, + "loop_delay": 7, + "category": "entertainment", + "min_rows": 3, + "min_cols": 15, + "settings": [ + { + "key": "max_length", + "label": "Max fact length (characters)", + "type": "number", + "default": "120", + "min": "40", + "max": "250", + "step": "10", + "stepper": true + }, + { + "key": "refresh_minutes", + "label": "Fetch a new fact every (minutes)", + "type": "number", + "default": "30", + "min": "1", + "max": "1440", + "step": "1", + "stepper": true + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "7", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/countdown/app.py b/apps/countdown/app.py index 0d91dfa..8bbdbdc 100644 --- a/apps/countdown/app.py +++ b/apps/countdown/app.py @@ -1,7 +1,13 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): from datetime import datetime import pytz + def t(s): + return i18n.t(s, "time") if i18n is not None else s + + def u(k): # localized D/H/M/S suffix (French J for jour, etc.) + return i18n.unit(k) if i18n is not None else k + def get_allowed_chars(): default_chars = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$&()-+=;:%'.,/?*" @@ -36,11 +42,12 @@ def build_compact_countdown(total_seconds, cols): mins, secs = divmod(rem, 60) # Keep the most useful leading units that still fit on the sign. + day_u = u('D') sections = [ - f'{days}D', - f'{hrs}H', - f'{mins}M', - f'{secs}S', + f'{days}{day_u}', + f'{hrs}{u("H")}', + f'{mins}{u("M")}', + f'{secs}{u("S")}', ] text = '' @@ -55,33 +62,23 @@ def build_compact_countdown(total_seconds, cols): return text # At the narrowest widths, preserve the day suffix so the value still has context. if cols <= 1: - return 'D'[:cols] - return f"{str(days)[:cols - 1]}D" + return day_u[:cols] + return f"{str(days)[:cols - len(day_u)]}{day_u}" + + def _pick(cols, *words): + for w in words: + if w and cols >= len(w): + return w + return (words[-1] or '')[:cols] def build_arrived_text(cols): - if cols >= len('ARRIVED!'): - return 'ARRIVED!' - if cols >= len('HERE!'): - return 'HERE!' - if cols >= len('NOW!'): - return 'NOW!' - return 'GO'[:cols] + return _pick(cols, t('ARRIVED') + '!', t('HERE') + '!', t('NOW') + '!', 'GO') def build_celebration_text(cols): - if cols >= len('CELEBRATE!'): - return 'CELEBRATE!' - if cols >= len('PARTY!'): - return 'PARTY!' - if cols >= len('YAY!'): - return 'YAY!' - return '' + return _pick(cols, t('CELEBRATE') + '!', t('PARTY') + '!', '') def build_remaining_text(cols): - if cols >= len('REMAINING'): - return 'REMAINING' - if cols >= len('LEFT'): - return 'LEFT' - return '' + return _pick(cols, t('REMAINING'), t('LEFT'), '') def build_slot_pages(event, target, now, rows, cols): diff = target - now diff --git a/apps/countdown/manifest.json b/apps/countdown/manifest.json index e7ec470..73f11ef 100644 --- a/apps/countdown/manifest.json +++ b/apps/countdown/manifest.json @@ -1,5 +1,6 @@ { "id": "countdown", + "i18n": true, "name": "Countdown", "icon": "⏳", "description": "Timer to event", diff --git a/apps/crypto/app.py b/apps/crypto/app.py index f5fa7e1..a3a1c3b 100644 --- a/apps/crypto/app.py +++ b/apps/crypto/app.py @@ -1,38 +1,80 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None, get_location=None): import requests + + def t(s): + return i18n.t(s, "crypto") if i18n is not None else s + coins = [s.strip() for s in settings.get('crypto_list', '').split(',') if s.strip()] if not coins: - return [format_lines('CRYPTO', 'NO COINS', 'CONFIGURE')] - currency = settings.get('currency_symbol', '$').strip() or '$' + return [format_lines('CRYPTO', t('NO COINS'), t('CONFIGURE'))] + + # Price in the local currency: where you are (Location) -> your Language -> USD. + # CoinGecko quotes natively in the target currency, so no FX conversion is needed. + loc = get_location() if get_location is not None else None + ccy = loc.get('currency') if isinstance(loc, dict) and loc.get('ok') else None + if not ccy and i18n is not None: + ccy = i18n.base_currency() + ccy = (ccy or 'USD').upper() + vs = ccy.lower() + # With i18n the display can render € £ ¥ (Windows-1252); without it the modules + # are the basic charset, so use '$' for USD and the ASCII ISO code otherwise. + cur_sym = i18n.currency_symbol(ccy) if i18n is not None else ('$' if ccy == 'USD' else ccy) + sep = '' if cur_sym != ccy else ' ' # 3-letter-code fallback reads better spaced + try: r = requests.get( 'https://api.coingecko.com/api/v3/simple/price', - params={'ids': ','.join(coins), 'vs_currencies': 'usd', 'include_24hr_change': 'true'}, + params={'ids': ','.join(coins), 'vs_currencies': vs, 'include_24hr_change': 'true'}, timeout=10 ).json() except Exception: - return [format_lines('CRYPTO', 'ERROR', 'API FAIL')] - rows = get_rows() + return [format_lines('CRYPTO', t('ERROR'), t('API FAIL'))] + rows, cols = get_rows(), get_cols() + no_color = settings.get('disable_colors', 'no') == 'yes' + + # Numbers follow the global Language (1,234.50 vs 1.234,50 vs 1 234,50). + def n(v, d=2, grouping=True): + if i18n is not None: + return i18n.number(v, d, grouping) + return f'{v:,.{d}f}' if grouping else f'{v:.{d}f}' + + def pct(v): + return f"{'+' if v >= 0 else '-'}{n(abs(v), 1, grouping=False)}%" + + def price_str(price): + body = n(price, 0) if price >= 1 else n(price, 4, grouping=False) + return f'{cur_sym}{sep}{body}' + + def block(c): + """The lines for one coin, sized to the display: price+change together on + 2+ row displays (with the name too when there are 3+ rows).""" + d = r.get(c, {}) + price, chg = d.get(vs), d.get(f'{vs}_24h_change') + sym = c[:6].upper() + if price is None: + return [f'{sym} ERR'] + if chg is None: + chg_str = 'N/A' + elif no_color: + chg_str = pct(chg) + else: + chg_str = ('🟩' if chg >= 0 else '🟥') + f' {pct(chg)}' + if rows == 1: + return [f'{sym} {price_str(price)}'] + if rows == 2: + return [f'{sym} {price_str(price)}', chg_str] + return [c.upper()[:cols], price_str(price), chg_str] # name / price / change + + lines_per = 1 if rows == 1 else (2 if rows == 2 else 3) + per_page = max(1, rows // lines_per) # how many coins fit on one page pages = [] - for i in range(0, len(coins), rows): - chunk = coins[i:i+rows] - price_lines, change_lines = [], [] - for c in chunk: - d = r.get(c, {}) - price = d.get('usd') - chg = d.get('usd_24h_change') - sym = c[:5].upper() - if price is not None: - price_lines.append(f'{sym} {currency}{price:,.0f}' if price >= 1 else f'{sym} {currency}{price:.4f}') - icon = '🟩' if (chg or 0) >= 0 else '🟥' - change_lines.append(f'{sym} {icon}{chg:+.1f}%' if chg is not None else f'{sym} N/A') - else: - price_lines.append(f'{sym} ERR') - change_lines.append(f'{sym} ERR') - pad = [''] * (rows - len(chunk)) - pages.append(format_lines(*(price_lines + pad))) - pages.append(format_lines(*(change_lines + pad))) - return pages or [format_lines('CRYPTO', 'NO DATA', '')] + for i in range(0, len(coins), per_page): + lines = [] + for c in coins[i:i + per_page]: + b = block(c) + lines += b + [''] * (lines_per - len(b)) # pad each block so coins align + pages.append(format_lines(*lines)) + return pages or [format_lines('CRYPTO', t('NO DATA'), '')] def trigger(settings, conditions): diff --git a/apps/crypto/manifest.json b/apps/crypto/manifest.json index 392e3ba..db1e5ba 100644 --- a/apps/crypto/manifest.json +++ b/apps/crypto/manifest.json @@ -1,5 +1,6 @@ { "id": "crypto", + "i18n": true, "name": "Crypto", "icon": "₿", "description": "Coin prices", diff --git a/apps/dashboard/app.py b/apps/dashboard/app.py index c557b96..41ae0fa 100644 --- a/apps/dashboard/app.py +++ b/apps/dashboard/app.py @@ -1,40 +1,44 @@ -"""Dashboard plugin: time + weather combined.""" +"""Dashboard plugin: time + current weather (via the shared weather helper).""" -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, get_weather=None, i18n=None): from datetime import datetime import pytz - tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) - dt = datetime.now(tz) - time_page = format_lines(dt.strftime("%A").upper(), - dt.strftime("%b %d %Y").upper(), - dt.strftime("%I:%M %p").upper()) - # Weather try: - import requests - api_key = settings.get('weather_api_key', '').strip() - if not api_key: - return [time_page, format_lines("NO WEATHER DATA", "", "CHECK API KEY")] - loc_lat = settings.get('location_lat', '') - loc_lon = settings.get('location_lon', '') - if loc_lat and loc_lon: - url = f"http://api.openweathermap.org/data/2.5/weather?lat={loc_lat}&lon={loc_lon}&appid={api_key}&units=imperial" - else: - zip_code = settings.get('zip_code', '02118').strip() - url = f"http://api.openweathermap.org/data/2.5/weather?zip={zip_code},us&appid={api_key}&units=imperial" - res = requests.get(url, timeout=5).json() - c = get_cols() - city = res['name'].upper() - temp = round(res['main']['temp']) - feels = round(res['main']['feels_like']) - desc = res['weather'][0]['main'].upper() - high = round(res['main']['temp_max']) - low = round(res['main']['temp_min']) - now_t = dt.strftime("%I:%M%p").lstrip("0") - mcl = c - 1 - len(now_t) - l1 = f"{city[:mcl]} {now_t}".center(c) - pfx = f"{temp}F ({feels}F) " - l2 = (pfx + desc[:c - len(pfx)]).center(c) - l3 = f"H:{high}F L:{low}F".center(c) - return [time_page, format_lines(l1, l2, l3)] - except Exception: - return [time_page, format_lines("WEATHER ERROR", "", "")] + tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + except pytz.UnknownTimeZoneError: + tz = pytz.timezone('US/Eastern') + dt = datetime.now(tz) + if i18n is not None: # localized names, locale date order, 24h outside English + weekday = i18n.weekday(dt) + date_line = i18n.date(dt, short=True, year=True) + time_str = i18n.time(dt) + else: + weekday = dt.strftime("%A").upper() + date_line = dt.strftime("%b %d %Y").upper() + time_str = dt.strftime("%I:%M %p").lstrip("0") + time_page = format_lines(weekday, date_line, time_str) + + # Weather comes from the companion's shared helper (global provider + key + + # location). With no helper (e.g. a bare host), just show the time. + if get_weather is None: + return [time_page] + w = get_weather() + if not w or not w.get('ok'): + return [time_page, format_lines("NO WEATHER", "DATA", "TRY LATER")] + + c = get_cols() + city = str(w.get('city') or 'LOCATION').upper() + temp = w.get('temp_f') + feels = w.get('feels_like_f') + desc = str(w.get('desc') or '').upper() + if i18n is not None: # translate shared-helper condition text where we can + desc = i18n.t(desc, "weather") + high = w.get('hi_f') + low = w.get('lo_f') + now_t = i18n.time(dt, ampm_space=False) if i18n is not None else dt.strftime("%I:%M%p").lstrip("0") + mcl = max(1, c - 1 - len(now_t)) + l1 = f"{city[:mcl]} {now_t}".center(c) + pfx = f"{temp}F ({feels}F) " + l2 = (pfx + desc[:max(0, c - len(pfx))]).center(c) + l3 = f"H:{high}F L:{low}F".center(c) + return [time_page, format_lines(l1, l2, l3)] diff --git a/apps/dashboard/manifest.json b/apps/dashboard/manifest.json index 3c199f6..c805925 100644 --- a/apps/dashboard/manifest.json +++ b/apps/dashboard/manifest.json @@ -1,5 +1,6 @@ { "id": "dashboard", + "i18n": true, "name": "Dashboard", "icon": "🏠", "description": "Time + weather", diff --git a/apps/date/app.py b/apps/date/app.py index 6a5e2d0..399f82f 100644 --- a/apps/date/app.py +++ b/apps/date/app.py @@ -1,11 +1,21 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): from datetime import datetime import pytz - tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + try: + tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + except pytz.UnknownTimeZoneError: + tz = pytz.timezone('US/Eastern') now = datetime.now(tz) - time_str = now.strftime('%I:%M %p') - month_day = now.strftime('%B %d') - weekday = now.strftime('%A') + # When the companion injects i18n, honor the global Language: localized weekday, + # locale-ordered date (9 JUILLET, not JUILLET 9), and 24h time outside English. + if i18n is not None: + time_str = i18n.time(now) + weekday = i18n.weekday(now) + month_day = i18n.date(now) + else: + time_str = now.strftime('%I:%M %p').lstrip('0') + weekday = now.strftime('%A').upper() + month_day = f"{now.strftime('%B').upper()} {now.day}" rows = get_rows() if rows == 2: return [format_lines(month_day, weekday)] diff --git a/apps/date/manifest.json b/apps/date/manifest.json index 1c16b09..d26f7f3 100644 --- a/apps/date/manifest.json +++ b/apps/date/manifest.json @@ -1,5 +1,6 @@ { "id": "date", + "i18n": true, "name": "Date", "icon": "📅", "description": "Full date view", diff --git a/apps/earthquakes/app.py b/apps/earthquakes/app.py new file mode 100644 index 0000000..9e35903 --- /dev/null +++ b/apps/earthquakes/app.py @@ -0,0 +1,57 @@ +"""Recent significant earthquakes worldwide (USGS FDSN, keyless).""" + + +def _wrap(text, cols, maxlines): + words, lines, cur = text.split(), [], '' + for w in words: + if len(cur) + len(w) + (1 if cur else 0) <= cols: + cur = f'{cur} {w}'.strip() + else: + lines.append(cur) + cur = w[:cols] + if len(lines) >= maxlines: + break + if cur and len(lines) < maxlines: + lines.append(cur) + return lines[:maxlines] or [''] + + +def fetch(settings, format_lines, get_rows, get_cols): + import requests + from datetime import datetime, timezone + rows, cols = get_rows(), get_cols() + try: + minmag = str(settings.get('min_magnitude', '4.5') or '4.5') + data = requests.get('https://earthquake.usgs.gov/fdsnws/event/1/query', + params={'format': 'geojson', 'orderby': 'time', 'limit': 5, + 'minmagnitude': minmag}, timeout=8).json() + feats = data.get('features', []) or [] + now = datetime.now(timezone.utc).timestamp() + pages = [] + for ft in feats[:5]: + p = ft.get('properties', {}) or {} + mag = p.get('mag') + place = str(p.get('place', '') or 'UNKNOWN').upper() + mags = f'M{mag:.1f}' if isinstance(mag, (int, float)) else 'M?' + ago = '' + ms = p.get('time') + if isinstance(ms, (int, float)): + mins = int((now - ms / 1000) / 60) + ago = f'{mins}M AGO' if mins < 120 else f'{mins // 60}H AGO' + # USGS place is like "134 KM E OF BITUNG, INDONESIA": show the distance + # on the header line and give the location name the remaining rows so + # it isn't cut off. + if ' OF ' in place: + dist, loc = place.split(' OF ', 1) + head = f'{mags} {dist.strip()}' + else: + loc, head = place, f'{mags} {ago}'.strip() + if rows == 1: + pages.append(f'{mags} {loc}'[:cols].center(cols)) + elif rows == 2: + pages.append(format_lines(head, *_wrap(loc, cols, 1))) + else: + pages.append(format_lines(head, *_wrap(loc, cols, rows - 1))) + return pages or [format_lines('EARTHQUAKES', 'NONE RECENT', '')] + except Exception: + return [format_lines('EARTHQUAKES', 'OFFLINE', '')] diff --git a/apps/earthquakes/manifest.json b/apps/earthquakes/manifest.json new file mode 100644 index 0000000..2c85559 --- /dev/null +++ b/apps/earthquakes/manifest.json @@ -0,0 +1,34 @@ +{ + "id": "earthquakes", + "name": "Earthquakes", + "icon": "🌎", + "description": "Recent significant earthquakes (USGS)", + "type": "functional", + "refresh_interval": 600, + "loop_delay": 6, + "category": "news", + "min_rows": 2, + "min_cols": 12, + "settings": [ + { + "key": "min_magnitude", + "label": "Minimum magnitude", + "type": "number", + "default": "4.5", + "min": "1", + "max": "8", + "step": "0.5", + "stepper": true + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/exchange-rates/app.py b/apps/exchange-rates/app.py new file mode 100644 index 0000000..830d9e2 --- /dev/null +++ b/apps/exchange-rates/app.py @@ -0,0 +1,39 @@ +"""Currency exchange rates via Frankfurter (European Central Bank data, keyless).""" + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None, get_location=None): + import requests + rows, cols = get_rows(), get_cols() + + # Base currency: an explicit setting wins; otherwise the configured LOCATION + # decides (a French speaker in Canada wants CAD, in Switzerland CHF — the + # language can't tell), falling back to the Language only if no location is set. + base = str(settings.get('base', '') or '').strip().upper()[:3] + if not base and get_location is not None: + base = str((get_location() or {}).get('currency') or '') + if not base: + base = i18n.base_currency() if i18n is not None else 'USD' + targets = [t.strip().upper()[:3] for t in str(settings.get('targets', 'EUR,GBP,JPY')).split(',') if t.strip()] + targets = targets[:8] or ['EUR', 'GBP', 'JPY'] + + # Rates use the locale's decimal/grouping (150,25 vs 150.25; 1.350 vs 1,350). + def n(v, d): + return i18n.number(v, d) if i18n is not None else f'{v:,.{d}f}' + + def fmt(v): + return n(v, 3) if v < 10 else (n(v, 2) if v < 1000 else n(v, 0)) + + try: + data = requests.get('https://api.frankfurter.app/latest', + params={'from': base, 'to': ','.join(targets)}, timeout=8).json() + rates = data.get('rates', {}) + if not rates: + return [format_lines('FX RATES', 'NO DATA', 'CHECK CODES')] + + pairs = [(t, rates[t]) for t in targets if t in rates] + if rows == 1: + return [f'1{base}={fmt(v)}{t}'.center(cols)[:cols] for t, v in pairs] + lines = [f'1 {base} ='] + [f'{t} {fmt(v)}' for t, v in pairs] + return [format_lines(*lines[i:i + rows]) for i in range(0, len(lines), rows)] + except Exception: + return [format_lines('FX RATES', 'OFFLINE', '')] diff --git a/apps/exchange-rates/manifest.json b/apps/exchange-rates/manifest.json new file mode 100644 index 0000000..3a5a410 --- /dev/null +++ b/apps/exchange-rates/manifest.json @@ -0,0 +1,41 @@ +{ + "id": "exchange-rates", + "i18n": true, + "name": "Exchange Rates", + "icon": "💱", + "description": "Live currency rates (ECB)", + "type": "functional", + "refresh_interval": 3600, + "loop_delay": 5, + "category": "finance", + "min_rows": 1, + "min_cols": 12, + "settings": [ + { + "key": "base", + "label": "Base currency (3-letter code)", + "type": "text", + "default": "", + "ph": "blank = follow Location", + "note": "Blank uses your Location's currency (then Language).", + "size": "sm" + }, + { + "key": "targets", + "label": "Show these currencies", + "type": "text", + "default": "EUR,GBP,JPY", + "ph": "comma-separated codes" + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "5", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/formula1/app.py b/apps/formula1/app.py new file mode 100644 index 0000000..52b26d9 --- /dev/null +++ b/apps/formula1/app.py @@ -0,0 +1,63 @@ +"""Formula 1 — next Grand Prix & championship leader (keyless: Jolpica / Ergast).""" + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + import requests + from datetime import datetime, timezone + rows, cols = get_rows(), get_cols() + + def t(s, ctx="sports"): + return i18n.t(s, ctx) if i18n is not None else s + + def u(k): # localized D/H duration suffix + return i18n.unit(k) if i18n is not None else k + + pages = [] + try: + nxt = requests.get('https://api.jolpi.ca/ergast/f1/current/next.json', timeout=10).json() + races = nxt.get('MRData', {}).get('RaceTable', {}).get('Races', []) + if races: + r = races[0] + name = str(r.get('raceName', '')).upper().replace('GRAND PRIX', 'GP') + cd = '' + try: + dt = datetime.fromisoformat( + f"{r.get('date', '')}T{r.get('time', '00:00:00Z')}".replace('Z', '+00:00')) + secs = int((dt - datetime.now(timezone.utc)).total_seconds()) + if secs > 0: + d, h = secs // 86400, (secs % 86400) // 3600 + in_ = t('IN', 'time') + cd = f'{in_} {d}{u("D")} {h}{u("H")}' if d else f'{in_} {h}{u("H")}' + else: + cd = t('RACE WEEKEND') + except ValueError: + pass + if rows == 1: + pages.append(f'{name} {cd}'[:cols].center(cols)) + elif rows == 2: + pages.append(format_lines(t('NEXT GP'), name)) + pages.append(format_lines(name, cd)) + else: + pages.append(format_lines(t('NEXT GRAND PRIX'), name, cd)) + else: + pages.append(format_lines('FORMULA 1', t('SEASON'), t('OVER'))) + except Exception: + return [format_lines('FORMULA 1', t('OFFLINE'), '')] + + try: + st = requests.get('https://api.jolpi.ca/ergast/f1/current/driverStandings.json', timeout=10).json() + lists = st.get('MRData', {}).get('StandingsTable', {}).get('StandingsLists', []) + ds = lists[0].get('DriverStandings', []) if lists else [] + if ds: + top = ds[0] + nm = str(top.get('Driver', {}).get('familyName', '')).upper() + pts = top.get('points', '') + if rows == 1: + pages.append(f'{t("LEADER")} {nm} {pts}'[:cols].center(cols)) + elif rows == 2: + pages.append(format_lines(t('CHAMPIONSHIP'), f'{nm} {pts}{t("PTS")}')) + else: + pages.append(format_lines(t('LEADER'), nm, f'{pts} {t("POINTS")}')) + except Exception: + pass + return pages or [format_lines('FORMULA 1', t('NO DATA'), '')] diff --git a/apps/formula1/manifest.json b/apps/formula1/manifest.json new file mode 100644 index 0000000..beb74be --- /dev/null +++ b/apps/formula1/manifest.json @@ -0,0 +1,25 @@ +{ + "id": "formula1", + "name": "Formula 1", + "icon": "🏎️", + "description": "Next Grand Prix & championship leader", + "type": "functional", + "i18n": true, + "refresh_interval": 3600, + "loop_delay": 6, + "category": "sports", + "min_rows": 2, + "min_cols": 12, + "settings": [ + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/holidays/app.py b/apps/holidays/app.py new file mode 100644 index 0000000..55bd666 --- /dev/null +++ b/apps/holidays/app.py @@ -0,0 +1,58 @@ +"""Upcoming public holidays for your location (keyless: Nager.Date). + +Which calendar to show is driven by the configured LOCATION (the language can't tell +France from Canada from Switzerland), down to the province/state: in Quebec you get +Quebec's holidays, not the other provinces'. Names use the source's native localName, +or a localized translation for the common holidays (so a French speaker in Quebec — +where the source only has English — still reads Fête du Travail, Action de grâce…). +An explicit Country setting overrides the location; the Language is the last resort. +""" + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None, get_location=None): + import requests + from datetime import datetime, date + rows, cols = get_rows(), get_cols() + + def t(s, ctx="time"): + return i18n.t(s, ctx) if i18n is not None else s + + loc = (get_location() or {}) if get_location is not None else {} + country = str(settings.get('country', '') or '').strip().upper()[:2] + if not country: + country = str(loc.get('country') or '') or (i18n.country() if i18n is not None else 'US') + # Province/state (e.g. CA-QC) — only trusted when it belongs to the country we're + # actually showing (an explicit Country setting can differ from the location). + subdivision = str(loc.get('subdivision') or '') + if subdivision and not subdivision.startswith(country): + subdivision = '' + try: + data = requests.get(f'https://date.nager.at/api/v3/NextPublicHolidays/{country}', timeout=8).json() + if not isinstance(data, list) or not data: + return [format_lines('HOLIDAYS', 'NONE FOUND', country)] + # Keep nationwide holidays + the ones for our own province/state; drop other + # regions' (so Quebec doesn't list British Columbia Day). + if subdivision: + data = [h for h in data if h.get('global') or subdivision in (h.get('counties') or [])] + pages, today = [], date.today() + for h in data[:4]: + localized = i18n.holiday(h.get('name')) if i18n is not None else None + name = str(localized or h.get('localName') or h.get('name') or '').upper() + cd = '' + try: + days = (datetime.strptime(h.get('date', ''), '%Y-%m-%d').date() - today).days + if days == 0: + cd = t('TODAY') + elif days > 0: + cd = f'{t("IN")} {days} {t("DAYS")}' + except ValueError: + pass + if rows == 1: + pages.append(f'{name} {cd}'[:cols].center(cols)) + elif rows == 2: + pages.append(format_lines(name, cd)) + else: + pages.append(format_lines(t('NEXT HOLIDAY', 'holidays'), name, cd)) + return pages or [format_lines('HOLIDAYS', 'NONE', '')] + except Exception: + return [format_lines('HOLIDAYS', 'OFFLINE', '')] diff --git a/apps/holidays/manifest.json b/apps/holidays/manifest.json new file mode 100644 index 0000000..b5d5c2a --- /dev/null +++ b/apps/holidays/manifest.json @@ -0,0 +1,34 @@ +{ + "id": "holidays", + "i18n": true, + "name": "Public Holidays", + "icon": "📅", + "description": "Upcoming public holidays", + "type": "functional", + "refresh_interval": 21600, + "loop_delay": 6, + "category": "data", + "min_rows": 2, + "min_cols": 12, + "settings": [ + { + "key": "country", + "label": "Country (2-letter code)", + "type": "text", + "default": "", + "size": "sm", + "ph": "blank = follow Location", + "note": "ISO country code, e.g. US, GB, DE, FR, CA. Blank follows your Location (then Language)." + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/iss/app.py b/apps/iss/app.py index 5fe9be9..0a03449 100644 --- a/apps/iss/app.py +++ b/apps/iss/app.py @@ -1,5 +1,9 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): import requests + + def t(s): + return i18n.t(s, "space") if i18n is not None else s + try: pos = requests.get('http://api.open-notify.org/iss-now.json', timeout=10).json() ppl = requests.get('http://api.open-notify.org/astros.json', timeout=10).json() @@ -11,9 +15,9 @@ def fetch(settings, format_lines, get_rows, get_cols): return [format_lines(f'ISS LAT{lat} LON{lon}')] if rows == 2: return [format_lines('ISS TRACKER', f'LAT{lat} LON{lon}')] - return [format_lines('ISS TRACKER', f'LAT {lat} LON {lon}', f'{num} IN SPACE')] + return [format_lines('ISS TRACKER', f'LAT {lat} LON {lon}', f'{num} ' + t('IN SPACE'))] except Exception: - return [format_lines('ISS TRACKER', 'ERROR', 'API FAIL')] + return [format_lines('ISS TRACKER', t('ERROR'), t('API FAIL'))] def trigger(settings, conditions): diff --git a/apps/iss/manifest.json b/apps/iss/manifest.json index beca0ad..6095585 100644 --- a/apps/iss/manifest.json +++ b/apps/iss/manifest.json @@ -1,5 +1,6 @@ { "id": "iss", + "i18n": true, "name": "ISS Tracker", "icon": "🛸", "description": "Space station", diff --git a/apps/metals/app.py b/apps/metals/app.py new file mode 100644 index 0000000..86bb714 --- /dev/null +++ b/apps/metals/app.py @@ -0,0 +1,64 @@ +"""Precious metal spot prices, USD per troy ounce (keyless: gold-api.com).""" + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None, get_location=None): + import requests + rows, cols = get_rows(), get_cols() + + def t(s): + return i18n.t(s, "metals") if i18n is not None else s + + def n(v, d): # locale decimal/grouping (2,345 vs 2.345 vs 2 345) + return i18n.number(v, d) if i18n is not None else f'{v:,.{d}f}' + + # gold-api.com quotes in USD/oz; show the local currency (Location -> Language -> + # USD) by converting through a keyless ECB rate. Falls back to USD if no rate. + loc = get_location() if get_location is not None else None + ccy = loc.get('currency') if isinstance(loc, dict) and loc.get('ok') else None + if not ccy and i18n is not None: + ccy = i18n.base_currency() + ccy = (ccy or 'USD').upper() + rate = 1.0 + if ccy != 'USD': + try: + rate = float(requests.get('https://api.frankfurter.app/latest', + params={'from': 'USD', 'to': ccy}, timeout=8).json()['rates'][ccy]) + except Exception: + ccy, rate = 'USD', 1.0 + # With i18n the display can render € £ ¥ (Windows-1252); without it the modules + # are the basic charset, so use '$' for USD and the ASCII ISO code otherwise. + cur_sym = i18n.currency_symbol(ccy) if i18n is not None else ('$' if ccy == 'USD' else ccy) + sep = '' if cur_sym != ccy else ' ' + + def price(sym): + try: + return requests.get(f'https://api.gold-api.com/price/{sym}', timeout=8).json().get('price') + except Exception: + return None + + def fmt(p): + if not isinstance(p, (int, float)): + return '--' + p = p * rate + body = n(p, 0) if p >= 100 else n(p, 2) + return f'{cur_sym}{sep}{body}' + + try: + gold, silver = price('XAU'), price('XAG') + if gold is None and silver is None: + return [format_lines('METALS', t('OFFLINE'), '')] + # Localized names vary in length — pad both to the same width so they align. + g, s = t('GOLD'), t('SILVER') + w = max(len(g), len(s)) + if rows == 1: + pages = [] + if gold is not None: + pages.append(f'{g} {fmt(gold)}/OZ'[:cols].center(cols)) + if silver is not None: + pages.append(f'{s} {fmt(silver)}/OZ'[:cols].center(cols)) + return pages + if rows == 2: + return [format_lines(f'{g:<{w}} {fmt(gold)}', f'{s:<{w}} {fmt(silver)}')] + return [format_lines(f'{t("SPOT PRICE")} /OZ', f'{g:<{w}} {fmt(gold)}', f'{s:<{w}} {fmt(silver)}')] + except Exception: + return [format_lines('METALS', t('OFFLINE'), '')] diff --git a/apps/metals/manifest.json b/apps/metals/manifest.json new file mode 100644 index 0000000..920c9fb --- /dev/null +++ b/apps/metals/manifest.json @@ -0,0 +1,25 @@ +{ + "id": "metals", + "i18n": true, + "name": "Precious Metals", + "icon": "🥇", + "description": "Gold & silver spot prices", + "type": "functional", + "refresh_interval": 900, + "loop_delay": 5, + "category": "finance", + "min_rows": 1, + "min_cols": 12, + "settings": [ + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "5", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/moon-phase/app.py b/apps/moon-phase/app.py index 1fed80d..49d1d16 100644 --- a/apps/moon-phase/app.py +++ b/apps/moon-phase/app.py @@ -1,9 +1,18 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): from datetime import datetime import pytz import math - tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + def t(s): + return i18n.t(s, "moon") if i18n is not None else s + + def u(k): # localized D/H/M/S suffix (French J for jour, etc.) + return i18n.unit(k) if i18n is not None else k + + try: + tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + except pytz.UnknownTimeZoneError: + tz = pytz.timezone('US/Eastern') now = datetime.now(tz) # Known new moon: January 6, 2000 18:14 UTC @@ -38,9 +47,10 @@ def fetch(settings, format_lines, get_rows, get_cols): filled = int(illumination * cols) bar = 'w' * filled + ' ' * (cols - filled) + name = t(phase_name) pages = [ - format_lines(phase_name, f'{illum_pct}% LIT', f'FULL IN {int(days_to_full)}D'), - format_lines(phase_name, bar, f'NEW IN {int(days_to_new)}D'), + format_lines(name, f'{illum_pct}% {t("LIT")}', f'{t("FULL IN")} {int(days_to_full)}{u("D")}'), + format_lines(name, bar, f'{t("NEW IN")} {int(days_to_new)}{u("D")}'), ] return pages diff --git a/apps/moon-phase/manifest.json b/apps/moon-phase/manifest.json index 39c6ae2..2a5fcac 100644 --- a/apps/moon-phase/manifest.json +++ b/apps/moon-phase/manifest.json @@ -1,5 +1,6 @@ { "id": "moon-phase", + "i18n": true, "name": "Moon Phase", "icon": "🌙", "description": "Current moon phase", diff --git a/apps/quote/app.py b/apps/quote/app.py new file mode 100644 index 0000000..1dd272d --- /dev/null +++ b/apps/quote/app.py @@ -0,0 +1,127 @@ +"""An inspirational quote (keyless: DummyJSON quotes).""" + + +def _need_lines(lens, cols): + need, cur = 1, 0 + for wl in lens: + add = wl if cur == 0 else cur + 1 + wl + if add <= cols: + cur = add + else: + need += 1 + cur = wl + return need + + +def _balance(words, lens, cols, k): + """Split words into exactly k lines (each <= cols) minimizing raggedness, so + lines fill evenly instead of orphaning the last word; prefers ending a line at + sentence punctuation. A tiny DP.""" + n = len(words) + pre = [0] + for wl in lens: + pre.append(pre[-1] + wl) + + def linelen(i, j): + return pre[j + 1] - pre[i] + (j - i) + + INF = float("inf") + dp = [[INF] * (n + 1) for _ in range(k + 1)] + nxt = [[0] * (n + 1) for _ in range(k + 1)] + dp[0][n] = 0.0 + for kk in range(1, k + 1): + for i in range(n - 1, -1, -1): + j = i + while j < n: + ll = linelen(i, j) + if ll > cols and j > i: + break + rest = dp[kk - 1][j + 1] + if rest < INF: + slack = cols - ll + cost = slack * slack + rest + if words[j][-1:] in ".!?": + cost -= cols + if cost < dp[kk][i]: + dp[kk][i] = cost + nxt[kk][i] = j + 1 + j += 1 + if dp[k][0] >= INF: + return None + out, i, kk = [], 0, k + while kk > 0: + j = nxt[kk][i] + out.append(" ".join(words[i:j])) + i, kk = j, kk - 1 + return out + + +def _greedy(words, cols): + lines, cur = [], '' + for w in words: + w = w if len(w) <= cols else w[:cols] + if len(cur) + len(w) + (1 if cur else 0) <= cols: + cur = f'{cur} {w}'.strip() + else: + lines.append(cur) + cur = w + if cur: + lines.append(cur) + return lines or [''] + + +def _pages(format_lines, title, text, rows, cols): + """Lay the text out under a title. When it fits on one page the words are + balanced evenly across the lines it needs; longer text word-wraps and + paginates.""" + words = text.split() or [''] + lens = [len(w) for w in words] + if rows == 1: + return [ln.center(cols)[:cols] for ln in _greedy(words, cols)] + body = rows - 1 if title else rows + if max(lens) <= cols: + need = _need_lines(lens, cols) + if need <= body: + bal = _balance(words, lens, cols, need) + if bal is not None: + return [format_lines(title, *bal)] if title else [format_lines(*bal)] + lines = _greedy(words, cols) + pages, i = ([format_lines(title, *lines[:body])], body) if title else ([], 0) + while i < len(lines): + pages.append(format_lines(*lines[i:i + rows])) + i += rows + return pages + +def fetch(settings, format_lines, get_rows, get_cols): + import requests + rows, cols = get_rows(), get_cols() + try: + max_len = int(float(settings.get('max_length', '150') or 150)) + except (TypeError, ValueError): + max_len = 150 + max_len = max(40, min(300, max_len)) + + def one(): + d = requests.get('https://dummyjson.com/quotes/random', timeout=8).json() + return str(d.get('quote', '') or '').strip(), str(d.get('author', '') or '').strip() + + try: + # The API can't filter by length, so try a few times for a short quote, + # keeping the shortest seen if none come in under the limit. + best = None + for _ in range(3): + q, a = one() + if not q: + continue + if len(q) <= max_len: + best = (q, a) + break + if best is None or len(q) < len(best[0]): + best = (q, a) + if not best: + return [format_lines('QUOTE', 'NO DATA', '')] + q, a = best + text = f'{q.upper()} - {a.upper()}' if a else q.upper() + return _pages(format_lines, '', f'QUOTE: {text}', rows, cols) + except Exception: + return [format_lines('QUOTE', 'OFFLINE', '')] diff --git a/apps/quote/manifest.json b/apps/quote/manifest.json new file mode 100644 index 0000000..2df8f7d --- /dev/null +++ b/apps/quote/manifest.json @@ -0,0 +1,44 @@ +{ + "id": "quote", + "name": "Quote", + "icon": "💬", + "description": "An inspirational quote", + "type": "functional", + "refresh_interval": 1800, + "loop_delay": 7, + "category": "entertainment", + "min_rows": 3, + "min_cols": 15, + "settings": [ + { + "key": "max_length", + "label": "Max quote length (characters)", + "type": "number", + "default": "150", + "min": "40", + "max": "300", + "step": "10", + "stepper": true + }, + { + "key": "refresh_minutes", + "label": "Fetch a new quote every (minutes)", + "type": "number", + "default": "30", + "min": "1", + "max": "1440", + "step": "1", + "stepper": true + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "7", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/registry.json b/apps/registry.json index 76d7208..459ca77 100644 --- a/apps/registry.json +++ b/apps/registry.json @@ -225,6 +225,141 @@ "category": "data", "type": "functional", "version": "1.0" + }, + { + "id": "advice", + "name": "Advice", + "icon": "🧭", + "description": "A random piece of advice", + "category": "entertainment", + "type": "functional", + "version": "1.0" + }, + { + "id": "aurora", + "name": "Aurora Watch", + "icon": "🌌", + "description": "Geomagnetic activity (Kp index)", + "category": "data", + "type": "functional", + "version": "1.0" + }, + { + "id": "cat-facts", + "name": "Cat Facts", + "icon": "🐱", + "description": "A concise cat fact", + "category": "entertainment", + "type": "functional", + "version": "1.0" + }, + { + "id": "earthquakes", + "name": "Earthquakes", + "icon": "🌎", + "description": "Recent significant earthquakes (USGS)", + "category": "news", + "type": "functional", + "version": "1.0" + }, + { + "id": "exchange-rates", + "name": "Exchange Rates", + "icon": "💱", + "description": "Live currency rates (ECB)", + "category": "finance", + "type": "functional", + "version": "1.0" + }, + { + "id": "formula1", + "name": "Formula 1", + "icon": "🏎️", + "description": "Next Grand Prix & championship leader", + "category": "sports", + "type": "functional", + "version": "1.0" + }, + { + "id": "holidays", + "name": "Public Holidays", + "icon": "📅", + "description": "Upcoming public holidays", + "category": "data", + "type": "functional", + "version": "1.0" + }, + { + "id": "metals", + "name": "Precious Metals", + "icon": "🥇", + "description": "Gold & silver spot prices", + "category": "finance", + "type": "functional", + "version": "1.0" + }, + { + "id": "quote", + "name": "Quote", + "icon": "💬", + "description": "An inspirational quote", + "category": "entertainment", + "type": "functional", + "version": "1.0" + }, + { + "id": "rocket-launch", + "name": "Rocket Launch", + "icon": "🚀", + "description": "Next orbital rocket launch", + "category": "data", + "type": "functional", + "version": "1.0" + }, + { + "id": "sarcastic-fortune-cookies", + "name": "Sarcastic Fortune Cookies", + "icon": "🥠", + "description": "Cynical fortune-cookie wisdom", + "category": "entertainment", + "type": "functional", + "version": "1.0" + }, + { + "id": "sun-times", + "name": "Sun Times", + "icon": "☀️", + "description": "Sunrise, sunset & day length", + "category": "data", + "type": "functional", + "version": "1.0" + }, + { + "id": "tides", + "name": "Tides", + "icon": "🌊", + "description": "Today's high & low tides (NOAA)", + "category": "data", + "type": "functional", + "version": "1.0" + }, + { + "id": "useless-fact", + "name": "Random Fact", + "icon": "🤓", + "description": "A concise random fact", + "category": "entertainment", + "type": "functional", + "version": "1.0" + }, + { + "id": "wiki-today", + "name": "Wikipedia Today", + "icon": "📚", + "description": "Featured article & most-read on Wikipedia", + "category": "news", + "type": "functional", + "version": "1.0" } ] } diff --git a/apps/rocket-launch/app.py b/apps/rocket-launch/app.py new file mode 100644 index 0000000..33d6070 --- /dev/null +++ b/apps/rocket-launch/app.py @@ -0,0 +1,48 @@ +"""Next orbital rocket launch (Launch Library 2 / The Space Devs, keyless).""" + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + import requests + from datetime import datetime, timezone + rows, cols = get_rows(), get_cols() + + def t(s, ctx="space"): + return i18n.t(s, ctx) if i18n is not None else s + + def u(k): # localized D/H/M duration suffix + return i18n.unit(k) if i18n is not None else k + + try: + data = requests.get('https://ll.thespacedevs.com/2.2.0/launch/upcoming/', + params={'limit': 1, 'mode': 'list'}, timeout=10).json() + res = data.get('results') or [] + if not res: + return [format_lines(t('NEXT LAUNCH'), t('NONE'), t('SCHEDULED'))] + r = res[0] + name = str(r.get('name', '')).upper() + rocket, _, mission = name.partition('|') + rocket = rocket.strip() or 'ROCKET' + mission = mission.strip() or rocket + cd = '' + net = r.get('net') + if net: + try: + dt = datetime.fromisoformat(str(net).replace('Z', '+00:00')) + secs = int((dt - datetime.now(timezone.utc)).total_seconds()) + if secs <= 0: + cd = t('IMMINENT') + else: + d, h, m = secs // 86400, (secs % 86400) // 3600, (secs % 3600) // 60 + in_ = t('IN', 'time') + cd = (f'{in_} {d}{u("D")} {h}{u("H")}' if d + else (f'{in_} {h}{u("H")} {m}{u("M")}' if h + else f'{in_} {m}{u("M")}')) + except ValueError: + cd = '' + if rows == 1: + return [f'{rocket} {cd}'[:cols].center(cols)] + if rows == 2: + return [format_lines(t('NEXT LAUNCH'), rocket), format_lines(mission, cd)] + return [format_lines(t('NEXT LAUNCH'), rocket, cd), format_lines(t('MISSION'), mission, cd)] + except Exception: + return [format_lines(t('NEXT LAUNCH'), t('OFFLINE'), '')] diff --git a/apps/rocket-launch/manifest.json b/apps/rocket-launch/manifest.json new file mode 100644 index 0000000..fefbf8c --- /dev/null +++ b/apps/rocket-launch/manifest.json @@ -0,0 +1,25 @@ +{ + "id": "rocket-launch", + "name": "Rocket Launch", + "icon": "🚀", + "description": "Next orbital rocket launch", + "type": "functional", + "i18n": true, + "refresh_interval": 900, + "loop_delay": 6, + "category": "data", + "min_rows": 2, + "min_cols": 12, + "settings": [ + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/sarcastic-fortune-cookies/app.py b/apps/sarcastic-fortune-cookies/app.py new file mode 100644 index 0000000..36188e5 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/app.py @@ -0,0 +1,153 @@ +""" +Sarcastic Fortune Cookies — a functional Split-Flap plugin. + +Shows a random tongue-in-cheek "fortune cookie" one-liner and swaps it for a new +random one on a chosen interval. Fortunes ship in several languages, one bundled +``fortunes_.json`` file each; the language follows the global Language +setting, falling back to English when there's no file for it. Accented fortunes +keep their Windows-1252 accents (É, Ü, ß, Œ, …) — the gateway and modules render +the cp1252 code page directly, so nothing is stripped. + +Drop-in compatible with the splitflap-os plugin ABI: + fetch(settings, format_lines, get_rows, get_cols) -> list[str] +""" + +import json +import os +import random +import time + +_HERE = os.path.dirname(os.path.abspath(__file__)) + + +def _load(lang): + """Load + cache the fortune list for a language (read once per process).""" + cache = getattr(fetch, "_data", None) + if cache is None: + cache = {} + fetch._data = cache + if lang not in cache: + path = os.path.join(_HERE, "fortunes_%s.json" % lang) + entries = [] + # Bundled files are UTF-8; fall back to cp1252 in case a file is replaced + # with a Windows-1252 one. + for enc in ("utf-8", "cp1252"): + try: + with open(path, encoding=enc) as fh: + entries = json.load(fh) + break + except (UnicodeDecodeError, FileNotFoundError, ValueError, OSError): + continue + cache[lang] = [e["fortune"] for e in entries + if isinstance(e, dict) and e.get("fortune")] + return cache[lang] + + +def _hard_wrap(words, rows, cols): + flat = " ".join(words) + return [flat[i:i + cols] for i in range(0, len(flat), cols)][:rows] + + +def _balance(words, lens, cols, k): + """Split ``words`` into exactly ``k`` lines (each <= cols), minimizing + raggedness (sum of squared trailing slack) so the lines are evenly filled + instead of packing the top and orphaning the last word — nudged toward + ending a line at sentence punctuation. A short DP; fortunes are tiny.""" + n = len(words) + pre = [0] + for wl in lens: + pre.append(pre[-1] + wl) + + def linelen(i, j): # words[i..j] inclusive, with spaces + return pre[j + 1] - pre[i] + (j - i) + + INF = float("inf") + dp = [[INF] * (n + 1) for _ in range(k + 1)] + nxt = [[0] * (n + 1) for _ in range(k + 1)] + dp[0][n] = 0.0 + for kk in range(1, k + 1): + for i in range(n - 1, -1, -1): + j = i + while j < n: + ll = linelen(i, j) + if ll > cols and j > i: + break + rest = dp[kk - 1][j + 1] + if rest < INF: + slack = cols - ll + cost = slack * slack + rest + if words[j][-1:] in ".!?": + cost -= cols # prefer breaking after a sentence + if cost < dp[kk][i]: + dp[kk][i] = cost + nxt[kk][i] = j + 1 + j += 1 + if dp[k][0] >= INF: + return _hard_wrap(words, k, cols) + out, i, kk = [], 0, k + while kk > 0: + j = nxt[kk][i] + out.append(" ".join(words[i:j])) + i, kk = j, kk - 1 + return out + + +def _wrap(text, rows, cols): + """Fit ``text`` into at most ``rows`` lines of ``cols`` characters, balanced. + + When the text fits on the page, its words are spread evenly across the lines + it needs (not greedily packed, which leaves a lonely last word); only if even + the tightest word-wrap needs more rows than the board has do we fall back to a + hard character wrap. An accented letter counts as one character (one module). + """ + words = text.split() + if not words: + return [] + lens = [len(w) for w in words] + if max(lens) > cols: + return _hard_wrap(words, rows, cols) + # Fewest lines a word-wrap needs. + need, cur = 1, 0 + for wl in lens: + add = wl if cur == 0 else cur + 1 + wl + if add <= cols: + cur = add + else: + need += 1 + cur = wl + if need > rows: + return _hard_wrap(words, rows, cols) + return _balance(words, lens, cols, need) + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + rows, cols = get_rows(), get_cols() + + # Language follows the global Language (or a per-app override, via i18n); use + # it when we bundle fortunes for it, otherwise fall back to English. Off a + # companion host (i18n is None) we read the raw setting. + lang = str((i18n.lang if i18n is not None else settings.get("language")) or "en").lower() + if not _load(lang): + lang = "en" + try: + every = int(settings.get("frequency") or 300) + except (ValueError, TypeError): + every = 300 + + now = time.time() + state = getattr(fetch, "_state", None) + # Pick a new fortune on first run, when the chosen interval elapses, or when + # the language changes (so a language switch shows on the next tick). + if (state is None + or state.get("lang") != lang + or not state.get("pages") + or (now - state.get("at", 0)) >= every): + fortunes = _load(lang) + text = random.choice(fortunes) if fortunes else "NO FORTUNES FOUND" + lines = _wrap(text, rows, cols) + # Vertically centre when the board has spare rows (format_lines centres + # each line horizontally and pads the remaining rows at the bottom). + top = (rows - len(lines)) // 2 + page = format_lines(*([""] * top + lines)) + fetch._state = {"at": now, "lang": lang, "pages": [page]} + return fetch._state["pages"] diff --git a/apps/sarcastic-fortune-cookies/fortunes_ca.json b/apps/sarcastic-fortune-cookies/fortunes_ca.json new file mode 100644 index 0000000..3f6469e --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_ca.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "TOT PASSA PER UNA RA. NORMALMENT DOLENTA" + }, + { + "id": 2, + "fortune": "LA SORT ARRIBA. CAMINA MOLT A POC A POC" + }, + { + "id": 3, + "fortune": "LUNIVERS T UN PLA PER TU. UN DE PETIT" + }, + { + "id": 4, + "fortune": "EL TEU DEST HA TRUCAT. HO AJORNA" + }, + { + "id": 5, + "fortune": "ELS ASTRES SALINEAREN. DESPRS ET VEIEREN" + }, + { + "id": 6, + "fortune": "EL TEU VAIXELL ARRIBA. S UNA CANOA" + }, + { + "id": 7, + "fortune": "CONFIA EN EL PROCS. ELL DUBTA DE TU" + }, + { + "id": 8, + "fortune": "UN SENYAL ARRIBA. DIU CEDIU EL PAS" + }, + { + "id": 9, + "fortune": "EL TEU ESTEL EXISTEIX. EN UNA ALTRA GALAXIA" + }, + { + "id": 10, + "fortune": "EL KARMA S REAL. AIX EXPLICA MOLT" + }, + { + "id": 11, + "fortune": "EL TEU FUTUR S BRILLANT. POSAT CREMA" + }, + { + "id": 12, + "fortune": "EL DEST ESPERA. SHA POSAT A LLEGIR" + }, + { + "id": 13, + "fortune": "ELS MIRACLES PASSEN CADA DIA. LLUNY DAQU" + }, + { + "id": 14, + "fortune": "EL TEU MOMENT ARRIBA. S AL TRNSIT" + }, + { + "id": 15, + "fortune": "LA SORT VA TRUCAR. TU HAVIES SORTIT" + }, + { + "id": 16, + "fortune": "LA MAREA GIRA. A VELOCITAT DE GLACERA" + }, + { + "id": 17, + "fortune": "ARRIBEN GRANS COSES. ABAIXA EL LLIST" + }, + { + "id": 18, + "fortune": "LES OCASIONS HI SN. SEMPRE US PERDEU" + }, + { + "id": 19, + "fortune": "LUNIVERS TESCOLTA. FES CUA SI US PLAU" + }, + { + "id": 20, + "fortune": "LES TEVES PREGRIES SHAN SENTIT. I ARXIVAT" + }, + { + "id": 21, + "fortune": "LABUNDNCIA FLUEIX CAP A TU. RIU AMUNT" + }, + { + "id": 22, + "fortune": "LA RODA GIRA. TU ETS EL HMSTER" + }, + { + "id": 23, + "fortune": "CADA NVOL T UN COSTAT BO. EL TEU GOTEJA" + }, + { + "id": 24, + "fortune": "LATZAR PREGUNTA PER TU. PER CURIOSITAT" + }, + { + "id": 25, + "fortune": "ELS PRESAGIS PARLEN. MS AVIAT SOSPIREN" + }, + { + "id": 26, + "fortune": "EL TEU HORSCOP S BO. I FICTICI" + }, + { + "id": 27, + "fortune": "EL LLAMP NO CAU DOS COPS. TU S" + }, + { + "id": 28, + "fortune": "EL DEST PREMIA LA PACINCIA. FACTURA DESPRS" + }, + { + "id": 29, + "fortune": "LA LLUNA VA VEURE EL TEU NOU INICI. UN ALTRE" + }, + { + "id": 30, + "fortune": "EL TEU NGEL ET VETLLA. VA PRENENT NOTES" + }, + { + "id": 31, + "fortune": "CREU I REBRS. EL LLIURAMENT VARIA" + }, + { + "id": 32, + "fortune": "LA TEVA ERA DAUR ARRIBA. XAPADA EN OR" + }, + { + "id": 33, + "fortune": "EL QUE S TEU ARRIBA. SENSE CAP PRESSA" + }, + { + "id": 34, + "fortune": "LUNIVERS ET VA FER LULLET. O TENIA UN TIC" + }, + { + "id": 35, + "fortune": "LA TEVA SORT CANVIAR. RUMB INCERT" + }, + { + "id": 36, + "fortune": "LA PROVIDNCIA PROVEEIX. REVISA ELS TIQUETS" + }, + { + "id": 37, + "fortune": "DEMANA UN DESIG. LESTEL EL MARCA SPAM" + }, + { + "id": 38, + "fortune": "TOT ARRIBA AL SEU TEMPS. EL TEU TRIGA" + }, + { + "id": 39, + "fortune": "ELS SIGNES HI EREN. LLEGIR S OPCIONAL" + }, + { + "id": 40, + "fortune": "ETS NIC. COM TOTHOM" + }, + { + "id": 41, + "fortune": "EL MILLOR EST PER VENIR. NO T CAP PRESSA" + }, + { + "id": 42, + "fortune": "LA TEVA AURA BRILLA. FA HORES EXTRES" + }, + { + "id": 43, + "fortune": "LA SORT ET VA SOMRIURE. CORTESA. DE LLUNY" + }, + { + "id": 44, + "fortune": "EL TEU NGEL VA DEMANAR TRASLLAT" + }, + { + "id": 45, + "fortune": "EL DEST REPARTEIX. TU PERDS LES CARTES" + }, + { + "id": 46, + "fortune": "UN PRESAGI APAREIX. SARRONSA DESPATLLES" + }, + { + "id": 47, + "fortune": "LXIT S A PROP. I EL BOT DE POSPOSAR" + }, + { + "id": 48, + "fortune": "EL TREBALL SEMPRE PAGA. EN EXPERINCIA" + }, + { + "id": 49, + "fortune": "EL TEU POTENCIAL S IMMENS. I SENSE S" + }, + { + "id": 50, + "fortune": "APUNTA A LA LLUNA. VIGILA EL SOSTRE" + }, + { + "id": 51, + "fortune": "QUI MATINA VA VEURE EL CUC. TU DORMIES" + }, + { + "id": 52, + "fortune": "LA TEVA GRAN OCASI ARRIBA. NO LA TRENQUIS" + }, + { + "id": 53, + "fortune": "ROMA NO ES VA FER EN UN DIA. LA TEVA TAMPOC" + }, + { + "id": 54, + "fortune": "ELS TEUS TALENTS ES TROBARAN. AMB ORDRE" + }, + { + "id": 55, + "fortune": "QUI GUANYA NO ES RENDEIX. TU SURES" + }, + { + "id": 56, + "fortune": "LES TEVES IDEES VAN DAVANT. ELS TERMINIS NO" + }, + { + "id": 57, + "fortune": "LA QUALITAT S UN HBIT. EL TEU TAMB" + }, + { + "id": 58, + "fortune": "EL TEU TREBALL PARLA SOL. BEN FLUIXET" + }, + { + "id": 59, + "fortune": "EL CIM S SOLITARI. PROBLEMA RESOLT" + }, + { + "id": 60, + "fortune": "UN ASCENS ARRIBA. EL DUN COMPANY" + }, + { + "id": 61, + "fortune": "EL TEU CV IMPRESSIONA. ALS FANS DE FICCI" + }, + { + "id": 62, + "fortune": "LA TEVA MILLOR FEINA ARRIBA. CORRE DE PRESSA" + }, + { + "id": 63, + "fortune": "AQUELLA REUNI PODIA SER UN CORREU" + }, + { + "id": 64, + "fortune": "LA TEVA SAFATA NO S ENEMIGA. NOMS TESTIMONI" + }, + { + "id": 65, + "fortune": "ELS TERMINIS NO TESPANTEN. ELS IGNORES" + }, + { + "id": 66, + "fortune": "EL TEU PLA A CINC ANYS T CINC ANYS" + }, + { + "id": 67, + "fortune": "LENT PER SEGUR GUANYA. DOMINES EL LENT" + }, + { + "id": 68, + "fortune": "LA TEVA AGENDA S PLENA. DE MARGES" + }, + { + "id": 69, + "fortune": "EL TEU EQUIP TAMB SOMIA. AMB EL TRASLLAT" + }, + { + "id": 70, + "fortune": "LOCASI VA BAIXAR AL TEU NIVELL" + }, + { + "id": 71, + "fortune": "LXIT DEIXA PISTES. TU PREFEREIXES EL MISTERI" + }, + { + "id": 72, + "fortune": "LA TEVA ZONA DE CONFORT T CODI POSTAL" + }, + { + "id": 73, + "fortune": "QUALITAT O QUANTITAT. LES REBUTGES TOTES DUES" + }, + { + "id": 74, + "fortune": "EL TEU INSTINT S FI. I SOVINT SEQUIVOCA" + }, + { + "id": 75, + "fortune": "TREBALLES B SOTA PRESSI. ELLA NO HI EST" + }, + { + "id": 76, + "fortune": "LA MESTRIA DEMANA 10000 HORES. EN TENS 40" + }, + { + "id": 77, + "fortune": "LA TEVA PLANTA CREIA EN TU. I EN LAIGUA" + }, + { + "id": 78, + "fortune": "LA IMPRESSORA NOTA LA PRESSA. PER AIX FALLA" + }, + { + "id": 79, + "fortune": "EL TEU LLEGAT EST EN OBRES. ENCARA" + }, + { + "id": 80, + "fortune": "UN DIPLOMA TESPERA. EL DASSISTNCIA" + }, + { + "id": 81, + "fortune": "FER XARXA OBRE PORTES. TRUCAR TAMB" + }, + { + "id": 82, + "fortune": "DNES EXEMPLE. ELS RH EN VOLEN UN ALTRE" + }, + { + "id": 83, + "fortune": "EL TEU PROJECTE DESCANSA AMB LA RESTA" + }, + { + "id": 84, + "fortune": "EL GENI S UN PER CENT SUOR. TU PARES AQU" + }, + { + "id": 85, + "fortune": "EL TEU MISSATGE DABSNCIA S UNA OBRA MESTRA" + }, + { + "id": 86, + "fortune": "FALLAR S UN ESGLA. QUINA ESCALA" + }, + { + "id": 87, + "fortune": "ETS INSUBSTITUBLE. LANUNCI JA EST FET" + }, + { + "id": 88, + "fortune": "LA TEVA AVALUACI ANUAL ARRIBA. ASSAJA B" + }, + { + "id": 89, + "fortune": "EFICINCIA S EL TEU SEGON NOM. AL PAPER" + }, + { + "id": 90, + "fortune": "CAUS DE PEUS. LATERRATGE SHA RETARDAT" + }, + { + "id": 91, + "fortune": "EL CIM S A PROP. EL CAMPAMENT BASE TAMB" + }, + { + "id": 92, + "fortune": "LA TEVA AMBICI ES DESPERTA. EL RELLOTGE NO" + }, + { + "id": 93, + "fortune": "SIGUES TU MATEIX. ELS ALTRES SHAN AMONAT" + }, + { + "id": 94, + "fortune": "LA TEVA REUNI VA ANAR B. JA SHA ACABAT" + }, + { + "id": 95, + "fortune": "DESCANSAR S SA. HO PRACTIQUES MOLT" + }, + { + "id": 96, + "fortune": "LA TEVA DIETA COMENA DILLUNS. ELLS FUGEN" + }, + { + "id": 97, + "fortune": "THO MEREIXES. RESPIRA FONDO" + }, + { + "id": 98, + "fortune": "UN DESCONEGUT ET SOMRIU. MANTN LA CALMA" + }, + { + "id": 99, + "fortune": "NO GUARDES RANCOR. LARXIVES AMB DATA" + }, + { + "id": 100, + "fortune": "LA TEVA PACINCIA T UNA BARRA. BLOCADA" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_da.json b/apps/sarcastic-fortune-cookies/fortunes_da.json new file mode 100644 index 0000000..aaf3575 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_da.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "ALT SKER AF EN GRUND. OFTEST EN DRLIG" + }, + { + "id": 2, + "fortune": "HELDET ER P VEJ. DET GR LANGSOMT" + }, + { + "id": 3, + "fortune": "UNIVERSET HAR EN PLAN. EN LILLE EN" + }, + { + "id": 4, + "fortune": "DIN SKBNE RINGEDE. DEN UDSKYDER" + }, + { + "id": 5, + "fortune": "STJERNERNE STOD RIGTIGT. S S DE DIG" + }, + { + "id": 6, + "fortune": "DIT SKIB KOMMER IND. DET ER EN KANO" + }, + { + "id": 7, + "fortune": "STOL P PROCESSEN. DEN TVIVLER P DIG" + }, + { + "id": 8, + "fortune": "ET TEGN KOMMER. DET SIGER HOLD TILBAGE" + }, + { + "id": 9, + "fortune": "DIN STJERNE FINDES. I EN ANDEN GALAKSE" + }, + { + "id": 10, + "fortune": "KARMA ER GTE. DET FORKLARER MEGET" + }, + { + "id": 11, + "fortune": "DIN FREMTID ER LYS. TAG SOLCREME" + }, + { + "id": 12, + "fortune": "SKBNEN VENTER. DEN GIK I GANG MED AT LSE" + }, + { + "id": 13, + "fortune": "MIRAKLER SKER HVER DAG. BARE ET ANDET STED" + }, + { + "id": 14, + "fortune": "DIT JEBLIK KOMMER. DET SIDDER I KEN" + }, + { + "id": 15, + "fortune": "HELDET BANKEDE P. DU VAR UDE" + }, + { + "id": 16, + "fortune": "TIDEVANDET VENDER. I GLETSJERFART" + }, + { + "id": 17, + "fortune": "STORE TING KOMMER. SNK BARREN" + }, + { + "id": 18, + "fortune": "CHANCERNE ER DER. I RAMMER ALTID FORBI" + }, + { + "id": 19, + "fortune": "UNIVERSET HRER DIG. STIL DIG I KEN" + }, + { + "id": 20, + "fortune": "DINE BNNER BLEV HRT. OG ARKIVERET" + }, + { + "id": 21, + "fortune": "OVERFLODEN FLYDER MOD DIG. MOD STRMMEN" + }, + { + "id": 22, + "fortune": "HJULET DREJER. DU ER HAMSTEREN" + }, + { + "id": 23, + "fortune": "HVER SKY HAR EN KANT. DIN DRYPPER" + }, + { + "id": 24, + "fortune": "TILFLDET SPRGER TIL DIG. AF NYSGERRIGHED" + }, + { + "id": 25, + "fortune": "VARSLERNE TALER. MEST SUKKER DE" + }, + { + "id": 26, + "fortune": "DIT HOROSKOP ER FINT. OG OPDIGTET" + }, + { + "id": 27, + "fortune": "LYNET SLR ALDRIG NED TO GANGE. DET GR DU" + }, + { + "id": 28, + "fortune": "SKBNEN BELNNER TLMOD. FAKTURA FLGER" + }, + { + "id": 29, + "fortune": "MNEN S DIN NYE START. ENDNU EN" + }, + { + "id": 30, + "fortune": "DIN ENGEL VGER. DEN TAGER NOTER" + }, + { + "id": 31, + "fortune": "TRO OG DU MODTAGER. LEVERING VARIERER" + }, + { + "id": 32, + "fortune": "DIN GULDALDER KOMMER. FORGYLDT S" + }, + { + "id": 33, + "fortune": "DET DER ER DIT KOMMER. UDEN NOGET HASTVRK" + }, + { + "id": 34, + "fortune": "UNIVERSET BLINKEDE. ELLER FIK NOGET I JET" + }, + { + "id": 35, + "fortune": "DIT HELD VENDER. RETNING UKENDT" + }, + { + "id": 36, + "fortune": "FORSYNET SRGER. DET TJEKKER BONERNE" + }, + { + "id": 37, + "fortune": "NSK DIG NOGET. STJERNEN SPAMMER DET" + }, + { + "id": 38, + "fortune": "ALT KOMMER TIL SIN TID. DIT TRKKER UD" + }, + { + "id": 39, + "fortune": "TEGNENE VAR DER. AT LSE ER FRIVILLIGT" + }, + { + "id": 40, + "fortune": "DU ER UNIK. LIGESOM ALLE ANDRE" + }, + { + "id": 41, + "fortune": "DET BEDSTE VENTER FORUDE. DET HAR INGEN HAST" + }, + { + "id": 42, + "fortune": "DIN AURA STRLER. DEN TAGER OVERARBEJDE" + }, + { + "id": 43, + "fortune": "HELDET SMILEDE. HFLIGT. P AFSTAND" + }, + { + "id": 44, + "fortune": "DIN ENGEL BAD OM FORFLYTTELSE" + }, + { + "id": 45, + "fortune": "SKBNEN GIVER KORTENE. DU TABER DEM" + }, + { + "id": 46, + "fortune": "ET VARSEL DUKKER OP. DET TRKKER P SKULDRENE" + }, + { + "id": 47, + "fortune": "SUCCES ER NR. OG S ER SNOOZE KNAPPEN" + }, + { + "id": 48, + "fortune": "ARBEJDE BETALER SIG. I ERFARING" + }, + { + "id": 49, + "fortune": "DIT POTENTIALE ER STORT. OG UBRUGT" + }, + { + "id": 50, + "fortune": "SIGT MOD MNEN. PAS P LOFTET" + }, + { + "id": 51, + "fortune": "DEN TIDLIGE FUGL FIK ORMEN. DU SOV" + }, + { + "id": 52, + "fortune": "DIN STORE CHANCE KOMMER. KNK DEN IKKE" + }, + { + "id": 53, + "fortune": "ROM BLEV IKKE BYGGET P EN DAG. DU HELLER" + }, + { + "id": 54, + "fortune": "DINE TALENTER FINDES. MED EN KENDELSE" + }, + { + "id": 55, + "fortune": "VINDERE GIVER ALDRIG OP. DU FLYDER" + }, + { + "id": 56, + "fortune": "DINE IDER ER FORAN. DINE DEADLINES BAGEFTER" + }, + { + "id": 57, + "fortune": "KVALITET ER EN VANE. DIN OGS" + }, + { + "id": 58, + "fortune": "DIT ARBEJDE TALER FOR SIG. MEGET STILLE" + }, + { + "id": 59, + "fortune": "TOPPEN ER ENSOM. PROBLEM LST" + }, + { + "id": 60, + "fortune": "EN FORFREMMELSE KOMMER. EN ANDENS" + }, + { + "id": 61, + "fortune": "DIT CV IMPONERER. FANTASY FANSENE" + }, + { + "id": 62, + "fortune": "DIT BEDSTE ARBEJDE KOMMER. DET LBER STRKT" + }, + { + "id": 63, + "fortune": "DET MDE KUNNE VRE EN MAIL" + }, + { + "id": 64, + "fortune": "DIN INDBAKKE ER IKKE FJENDEN. KUN VIDNE" + }, + { + "id": 65, + "fortune": "DEADLINES SKRMMER DIG IKKE. DU IGNORERER DEM" + }, + { + "id": 66, + "fortune": "DIN FEMRSPLAN ER FEM R GAMMEL" + }, + { + "id": 67, + "fortune": "LANGSOMT MEN SIKKERT VINDER. DU HAR LANGSOMT" + }, + { + "id": 68, + "fortune": "DIN KALENDER ER FULD. AF MARGENER" + }, + { + "id": 69, + "fortune": "DIT HOLD DRMMER OGS. OM FORFLYTTELSE" + }, + { + "id": 70, + "fortune": "CHANCEN SNKEDE SIG TIL DIT NIVEAU" + }, + { + "id": 71, + "fortune": "SUCCES EFTERLADER SPOR. DU KAN LIDE GDER" + }, + { + "id": 72, + "fortune": "DIN KOMFORTZONE FORTJENER ET POSTNUMMER" + }, + { + "id": 73, + "fortune": "KVALITET ELLER KVANTITET. DU AFVISER BEGGE" + }, + { + "id": 74, + "fortune": "DIN INSTINKT ER SKARP. OG OFTE FORKERT" + }, + { + "id": 75, + "fortune": "DU ARBEJDER GODT UNDER PRES. DEN ER UENIG" + }, + { + "id": 76, + "fortune": "MESTERSKAB KRVER 10000 TIMER. DU HAR 40" + }, + { + "id": 77, + "fortune": "DIN PLANTE TROEDE P DIG. OG P VAND" + }, + { + "id": 78, + "fortune": "PRINTEREN MRKER DIT HASTVRK. DEN DRILLER" + }, + { + "id": 79, + "fortune": "DIN ARV ER UNDER OPBYGNING. STADIG" + }, + { + "id": 80, + "fortune": "ET DIPLOM VENTER. DELTAGERDIPLOMET" + }, + { + "id": 81, + "fortune": "AT NETVRKE BNER DRE. AT BANKE OGS" + }, + { + "id": 82, + "fortune": "DU GR FORREST. HR VIL HAVE EN ANDEN" + }, + { + "id": 83, + "fortune": "DIT SIDEPROJEKT HVILER MED DE ANDRE" + }, + { + "id": 84, + "fortune": "GENI ER EN PROCENT SVED. DER STOPPER DU" + }, + { + "id": 85, + "fortune": "DIT FRAVRSSVAR ER DIT MESTERVRK" + }, + { + "id": 86, + "fortune": "AT FEJLE ER ET TRIN. FLOT TRAPPE" + }, + { + "id": 87, + "fortune": "DU ER UERSTATTELIG. OPSLAGET ER KLAR" + }, + { + "id": 88, + "fortune": "DIN MEDARBEJDERSAMTALE KOMMER. V DIG" + }, + { + "id": 89, + "fortune": "EFFEKTIVITET ER DIT MELLEMNAVN. P PAPIR" + }, + { + "id": 90, + "fortune": "DU LANDER P FDDERNE. LANDINGEN ER FORSINKET" + }, + { + "id": 91, + "fortune": "TOPPEN ER NR. BASISLEJREN OGS" + }, + { + "id": 92, + "fortune": "DIN AMBITION VGNEDE. IKKE DIT VKKEUR" + }, + { + "id": 93, + "fortune": "VR DIG SELV. DE ANDRE BLEV BEKYMREDE" + }, + { + "id": 94, + "fortune": "DIT MDE GIK GODT. DET ER SLUT" + }, + { + "id": 95, + "fortune": "AT HVILE ER SUNDT. DU VER MEGET" + }, + { + "id": 96, + "fortune": "DIN DIT STARTER P MANDAG. MANDAGE FLYGTER" + }, + { + "id": 97, + "fortune": "DU FORTJENER DETTE. TRK VEJRET DYBT" + }, + { + "id": 98, + "fortune": "EN FREMMED SMILER TIL DIG. HOLD DIG ROLIG" + }, + { + "id": 99, + "fortune": "DU BRER IKKE NAG. DU ARKIVERER DET" + }, + { + "id": 100, + "fortune": "DIN TLMODIGHED HAR EN BJLKE. LST FAST" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_de.json b/apps/sarcastic-fortune-cookies/fortunes_de.json new file mode 100644 index 0000000..bde6dd7 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_de.json @@ -0,0 +1,4002 @@ +[ +{ +"id":1, +"fortune":"ALLES HAT EINEN GRUND. MEIST SCHLECHTE WAHL" +}, +{ +"id":2, +"fortune":"DAS GLÜCK KOMMT. ES GEHT ZU FUß" +}, +{ +"id":3, +"fortune":"DAS UNIVERSUM HAT EINEN PLAN. EINEN KLEINEN" +}, +{ +"id":4, +"fortune":"DEIN SCHICKSAL RIEF AN. ES VERSCHIEBT" +}, +{ +"id":5, +"fortune":"DIE STERNE STANDEN GUT. DANN SAHEN SIE DICH" +}, +{ +"id":6, +"fortune":"DEIN SCHIFF KOMMT. ES IST EIN KANU" +}, +{ +"id":7, +"fortune":"VERTRAU DEM PROZESS. ER VERTRAUT DIR NICHT" +}, +{ +"id":8, +"fortune":"EIN ZEICHEN KOMMT. ES SAGT VORFAHRT ACHTEN" +}, +{ +"id":9, +"fortune":"DEIN GLÜCKSSTERN WOHNT IN FERNER GALAXIE" +}, +{ +"id":10, +"fortune":"KARMA IST REAL. DAS ERKLÄRT EINIGES" +}, +{ +"id":11, +"fortune":"DIE ZUKUNFT IST HELL. TRAG SONNENCREME" +}, +{ +"id":12, +"fortune":"DAS SCHICKSAL WARTET. ES LIEST INZWISCHEN" +}, +{ +"id":13, +"fortune":"WUNDER GESCHEHEN TÄGLICH. MEIST WOANDERS" +}, +{ +"id":14, +"fortune":"DEIN MOMENT KOMMT. ER STEHT IM STAU" +}, +{ +"id":15, +"fortune":"DAS GLÜCK KLOPFTE AN. DU WARST NICHT DA" +}, +{ +"id":16, +"fortune":"DIE FLUT WENDET SICH. IM SCHNECKENTEMPO" +}, +{ +"id":17, +"fortune":"GROßES KOMMT AUF DICH ZU. SENK DIE LATTE" +}, +{ +"id":18, +"fortune":"CHANCEN SIND NAH. IHR VERPASST EUCH STETS" +}, +{ +"id":19, +"fortune":"DER KOSMOS HÖRTE DICH. BITTE WARTEN" +}, +{ +"id":20, +"fortune":"DEINE GEBETE WURDEN GEHÖRT. UND ABGELEGT" +}, +{ +"id":21, +"fortune":"FÜLLE FLIEßT ZU DIR. LEIDER FLUSSAUFWÄRTS" +}, +{ +"id":22, +"fortune":"DAS GLÜCKSRAD DREHT SICH. DU BIST DER HAMSTER" +}, +{ +"id":23, +"fortune":"JEDE WOLKE HAT EINEN RAND. DEINER IST FEUCHT" +}, +{ +"id":24, +"fortune":"DER ZUFALL FRAGT NACH DIR HERUM" +}, +{ +"id":25, +"fortune":"DAS ORAKEL SPRACH. ES SEUFZTE NUR" +}, +{ +"id":26, +"fortune":"DEIN HOROSKOP KLINGT GUT. ES IST FIKTION" +}, +{ +"id":27, +"fortune":"DER BLITZ TRIFFT NIE ZWEIMAL. DU SCHON" +}, +{ +"id":28, +"fortune":"DAS SCHICKSAL BELOHNT GEDULD. RECHNUNG FOLGT" +}, +{ +"id":29, +"fortune":"DER MOND SAH DEINEN NEUSTART. SCHON WIEDER" +}, +{ +"id":30, +"fortune":"DEIN SCHUTZENGEL SCHAUT ZU. ER MACHT NOTIZEN" +}, +{ +"id":31, +"fortune":"GLAUBE UND EMPFANGE. LIEFERUNG VARIIERT" +}, +{ +"id":32, +"fortune":"DEINE GOLDENE ÄRA NAHT. VERGOLDET IMMERHIN" +}, +{ +"id":33, +"fortune":"WAS DIR BESTIMMT IST HAT ES NICHT EILIG" +}, +{ +"id":34, +"fortune":"DAS UNIVERSUM ZWINKERTE. ODER ES WAR STAUB" +}, +{ +"id":35, +"fortune":"DEIN GLÜCK ÄNDERT SICH. RICHTUNG UNKLAR" +}, +{ +"id":36, +"fortune":"DIE VORSEHUNG SORGT. SIE PRÜFT NUR BELEGE" +}, +{ +"id":37, +"fortune":"WÜNSCH DIR WAS. DER STERN MELDET ES ALS SPAM" +}, +{ +"id":38, +"fortune":"GUT DING WILL WEILE. DEINS WILL JAHRZEHNTE" +}, +{ +"id":39, +"fortune":"EIN GELDSEGEN NAHT. ZIEH DICH WARM AN" +}, +{ +"id":40, +"fortune":"DIE ZEICHEN WAREN DA. LESEN IST FREIWILLIG" +}, +{ +"id":41, +"fortune":"DU BIST EINER VON MILLIONEN. WÖRTLICH" +}, +{ +"id":42, +"fortune":"DAS BESTE KOMMT NOCH. ES HAT KEINE EILE" +}, +{ +"id":43, +"fortune":"DEINE AURA STRAHLT. SIE MACHT ÜBERSTUNDEN" +}, +{ +"id":44, +"fortune":"FORTUNA LÄCHELTE. HÖFLICH. EINEM FREMDEN ZU" +}, +{ +"id":45, +"fortune":"DEIN ENGEL BEANTRAGTE EINE VERSETZUNG" +}, +{ +"id":46, +"fortune":"GROßE DINGE BRAUCHEN ZEIT. DEINE URLAUB" +}, +{ +"id":47, +"fortune":"DAS SCHICKSAL MISCHT KARTEN. DU VERLEGST SIE" +}, +{ +"id":48, +"fortune":"EIN OMEN ERSCHEINT. ES ZUCKT MIT SCHULTERN" +}, +{ +"id":49, +"fortune":"DEIN STERN GEHT AUF. IRGENDWANN. VERMUTLICH" +}, +{ +"id":50, +"fortune":"GLÜCK IST MIT DEN DUMMEN. DANN VIEL SPAß" +}, +{ +"id":51, +"fortune":"MORGEN WIRD ALLES BESSER. MORGEN IST DEHNBAR" +}, +{ +"id":52, +"fortune":"DER ERFOLG IST NAH. DIE SCHLUMMERTASTE AUCH" +}, +{ +"id":53, +"fortune":"HARTE ARBEIT ZAHLT SICH AUS. IN ERFAHRUNG" +}, +{ +"id":54, +"fortune":"DEIN POTENZIAL IST GRENZENLOS. UND UNGENUTZT" +}, +{ +"id":55, +"fortune":"TRÄUM GROß. STELL ABER EINEN WECKER" +}, +{ +"id":56, +"fortune":"DER FRÜHE VOGEL FLOG OHNE DICH LOS" +}, +{ +"id":57, +"fortune":"DEIN DURCHBRUCH NAHT. BRICH NICHTS" +}, +{ +"id":58, +"fortune":"ROM ENTSTAND NICHT AN EINEM TAG. DEINS NIE" +}, +{ +"id":59, +"fortune":"DEINE TALENTE WERDEN GEFUNDEN. MIT SPÜRHUND" +}, +{ +"id":60, +"fortune":"GREIF NACH DEN STERNEN. ACHTUNG DECKE" +}, +{ +"id":61, +"fortune":"GEWINNER GEBEN NIE AUF. DU FANDEST PAUSIEREN" +}, +{ +"id":62, +"fortune":"DEINE IDEEN SIND VORAUS. DEINE FRISTEN HINTEN" +}, +{ +"id":63, +"fortune":"QUALITÄT IST GEWOHNHEIT. DEINE AUCH" +}, +{ +"id":64, +"fortune":"DEINE ARBEIT SPRICHT FÜR SICH. LEISE" +}, +{ +"id":65, +"fortune":"DIE SPITZE IST EINSAM. PROBLEM GELÖST" +}, +{ +"id":66, +"fortune":"EINE BEFÖRDERUNG NAHT. DIE EINES KOLLEGEN" +}, +{ +"id":67, +"fortune":"DEIN LEBENSLAUF BEGEISTERT. ALS ROMAN" +}, +{ +"id":68, +"fortune":"DEIN BESTES WERK KOMMT NOCH. ES RENNT SCHNELL" +}, +{ +"id":69, +"fortune":"DAS MEETING WÄRE EINE MAIL GEWESEN" +}, +{ +"id":70, +"fortune":"DEIN POSTFACH IST KEIN FEIND. NUR ZEUGE" +}, +{ +"id":71, +"fortune":"FRISTEN FÜRCHTEN NICHTS. DU GEHST VORBEI" +}, +{ +"id":72, +"fortune":"DEIN FÜNFJAHRESPLAN IST FÜNF JAHRE ALT" +}, +{ +"id":73, +"fortune":"LANGSAM UND STETIG GEWINNT. DIR FEHLT STETIG" +}, +{ +"id":74, +"fortune":"DEIN KALENDER IST VOLL. MIT PUFFERN" +}, +{ +"id":75, +"fortune":"DEIN TEAM TRÄUMT AUCH. VON VERSETZUNG" +}, +{ +"id":76, +"fortune":"DER ANLASS HAT SICH ZU DIR HERABGELASSEN" +}, +{ +"id":77, +"fortune":"ERFOLG HINTERLÄSST SPUREN. DU MAGST RÄTSEL" +}, +{ +"id":78, +"fortune":"DEINE KOMFORTZONE BRAUCHT EINE POSTLEITZAHL" +}, +{ +"id":79, +"fortune":"QUALITÄT VOR QUANTITÄT. DU LEHNST BEIDES AB" +}, +{ +"id":80, +"fortune":"DEIN BAUCHGEFÜHL IST STARK. UND FALSCH" +}, +{ +"id":81, +"fortune":"DU ARBEITEST GUT UNTER DRUCK. SAGT WER" +}, +{ +"id":82, +"fortune":"MEISTERSCHAFT BRAUCHT 10000 STUNDEN. DU 40" +}, +{ +"id":83, +"fortune":"DEINE BÜROPFLANZE GLAUBTE AN DICH. UND WASSER" +}, +{ +"id":84, +"fortune":"DER DRUCKER SPÜRT DEINE EILE. DESHALB" +}, +{ +"id":85, +"fortune":"DEIN VERMÄCHTNIS IST IM BAU. IMMER NOCH" +}, +{ +"id":86, +"fortune":"EINE URKUNDE WARTET. TEILNAHME ZÄHLT" +}, +{ +"id":87, +"fortune":"NETZWERKEN ÖFFNET TÜREN. KLOPFEN AUCH" +}, +{ +"id":88, +"fortune":"DU FÜHRST MIT BEISPIEL. HR SUCHT EIN NEUES" +}, +{ +"id":89, +"fortune":"DEIN NEBENPROJEKT RUHT BEI DEN ANDEREN" +}, +{ +"id":90, +"fortune":"GENIE IST EIN PROZENT ARBEIT. DA STOPPST DU" +}, +{ +"id":91, +"fortune":"DEINE ABWESENHEITSNOTIZ IST DEIN BESTES WERK" +}, +{ +"id":92, +"fortune":"SCHEITERN IST EINE TREPPE. SCHÖNES HAUS" +}, +{ +"id":93, +"fortune":"DU BIST UNERSETZLICH. DIE ANZEIGE IST FERTIG" +}, +{ +"id":94, +"fortune":"DEIN JAHRESGESPRÄCH NAHT. PROBE LÄUFT" +}, +{ +"id":95, +"fortune":"EFFIZIENZ IST DEIN ZWEITER NAME. NUR AMTLICH" +}, +{ +"id":96, +"fortune":"DU LANDEST AUF DEN FÜßEN. LANDUNG VERSPÄTET" +}, +{ +"id":97, +"fortune":"DER GIPFEL IST NAH. DAS BASISLAGER AUCH" +}, +{ +"id":98, +"fortune":"DEIN EHRGEIZ ERWACHTE. DEIN WECKER NICHT" +}, +{ +"id":99, +"fortune":"SEI DU SELBST. ALLE ANDEREN WAREN BESORGT" +}, +{ +"id":100, +"fortune":"DEIN MEETING LIEF GUT. ES IST VORBEI" +}, +{ +"id":101, +"fortune":"ERKENNE DICH SELBST. EIN KURZES HALLO REICHT" +}, +{ +"id":102, +"fortune":"DEIN GLOW UP KOMMT. DAS NETZ IST INFORMIERT" +}, +{ +"id":103, +"fortune":"NEUES JAHR NEUES ICH. DAS ALTE LIEß NOTIZEN" +}, +{ +"id":104, +"fortune":"DU BIST GENUG. DIE LATTE WAR VERSTELLBAR" +}, +{ +"id":105, +"fortune":"DEIN INNERER FRIEDEN SAH DEINEN KALENDER. WEG" +}, +{ +"id":106, +"fortune":"WACHSTUM BRAUCHT ZEIT. DEINS BEANTRAGT FRIST" +}, +{ +"id":107, +"fortune":"DU BIST EIN WERK IN ARBEIT. VIEL ARBEIT" +}, +{ +"id":108, +"fortune":"SELBSTERKENNTNIS IST EIN GESCHENK. UNTERWEGS" +}, +{ +"id":109, +"fortune":"HEILUNG IST NICHT LINEAR. DEINE KRITZELT" +}, +{ +"id":110, +"fortune":"DEIN BESTES ICH ERWACHT. ES DRÜCKT SCHLUMMERN" +}, +{ +"id":111, +"fortune":"SELFCARE IST WICHTIG. SERIEN SIND KEIN SPA" +}, +{ +"id":112, +"fortune":"DEINE GRENZEN SIND GESUND. UND UNGETESTET" +}, +{ +"id":113, +"fortune":"DANKBARKEIT HILFT. PROBIER SIE AN MENSCHEN" +}, +{ +"id":114, +"fortune":"DU VERZEIHST LEICHT. DIR SELBST BESONDERS" +}, +{ +"id":115, +"fortune":"DEINE GEWOHNHEITEN PRÄGEN DICH. BEILEID" +}, +{ +"id":116, +"fortune":"KLEINE SCHRITTE ZÄHLEN. AUCH ZUM KÜHLSCHRANK" +}, +{ +"id":117, +"fortune":"ACHTSAMKEIT HILFT. DEIN HANDY WIDERSPRICHT" +}, +{ +"id":118, +"fortune":"DU LIEßT LOS. ES KENNT DEINE ADRESSE" +}, +{ +"id":119, +"fortune":"DEINE MORGENROUTINE IST HEILIG. VIER MINUTEN" +}, +{ +"id":120, +"fortune":"DU LERNST NEIN ZU SAGEN. ZU GEMÜSE ZUERST" +}, +{ +"id":121, +"fortune":"DEIN WILLE STEMMT FAST EINEN GANZEN KEKS" +}, +{ +"id":122, +"fortune":"DEIN LEBENSZWECK EXISTIERT. ER BLEIBT ANONYM" +}, +{ +"id":123, +"fortune":"DU UMARMST VERÄNDERUNG. VOM SOFA AUS" +}, +{ +"id":124, +"fortune":"DEIN TAGEBUCH IST EHRLICH. BEIDE SEITEN" +}, +{ +"id":125, +"fortune":"DU LEBST DEINE WAHRHEIT. PRÜFUNG LÄUFT" +}, +{ +"id":126, +"fortune":"DEIN INNERER KRITIKER SEUFZT NUR NOCH" +}, +{ +"id":127, +"fortune":"DEINE ZIELE SIND IN SICHT. GUTES FERNGLAS" +}, +{ +"id":128, +"fortune":"DEINE NEUEN MUSTER WIRKEN VERTRAUT. SEHR" +}, +{ +"id":129, +"fortune":"DEINE ENERGIE ZIEHT AN. VOR ALLEM PFLICHTEN" +}, +{ +"id":130, +"fortune":"DEINE MAUERN FIELEN. DER GRABEN WUCHS" +}, +{ +"id":131, +"fortune":"DU FEIERST KLEINE SIEGE. TÄGLICH. WER SONST" +}, +{ +"id":132, +"fortune":"DEINE ENTWICKLUNG VERWIRRT SOGAR DARWIN" +}, +{ +"id":133, +"fortune":"DU KOMMST JETZT ZUERST. KURZE SCHLANGE" +}, +{ +"id":134, +"fortune":"DEINE NEUERFINDUNG TOURT. GLEICHES PROGRAMM" +}, +{ +"id":135, +"fortune":"DU BIST PRÄSENT. KÖRPERLICH IMMERHIN" +}, +{ +"id":136, +"fortune":"DEIN NEUSTART BEGINNT MONTAG. EINEM SPÄTEREN" +}, +{ +"id":137, +"fortune":"DEIN VISIONBOARD IST SCHÖN. UND IM RUHESTAND" +}, +{ +"id":138, +"fortune":"DU EHRST DEINE GEFÜHLE. IN VOLLER LAUTSTÄRKE" +}, +{ +"id":139, +"fortune":"DEINE RUHE IST ECHT. DU LIEST KEINE MAILS" +}, +{ +"id":140, +"fortune":"DEINE STANDARDS STEIGEN. VOM MEERESSPIEGEL" +}, +{ +"id":141, +"fortune":"DU BLÜHST AUF. SPÄTE SAISON. ZÄHLT TROTZDEM" +}, +{ +"id":142, +"fortune":"DEINE DISZIPLIN IST LEGENDÄR. LEGENDEN LÜGEN" +}, +{ +"id":143, +"fortune":"DEINE AFFIRMATIONEN WIRKEN. AN DER DECKE" +}, +{ +"id":144, +"fortune":"DEINE INTUITION IST LAUT. UND OFT DANEBEN" +}, +{ +"id":145, +"fortune":"DEIN INNERES KIND IST GEHEILT. ES WILL EIS" +}, +{ +"id":146, +"fortune":"DIE GROßE LIEBE WARTET. SIE HAT VERSPÄTUNG" +}, +{ +"id":147, +"fortune":"DEINE BESSERE HÄLFTE EXISTIERT. NETZ SCHWANKT" +}, +{ +"id":148, +"fortune":"ROMANTIK LIEGT IN DER LUFT. POLLEN AUCH" +}, +{ +"id":149, +"fortune":"AMOR HAT DEINE ADRESSE. ER FUHR VORBEI" +}, +{ +"id":150, +"fortune":"DEIN HERZ KENNT DEN WEG. DEINE CHATS NICHT" +}, +{ +"id":151, +"fortune":"LIEBE MACHT BLIND. DEINE AUCH VERGESSLICH" +}, +{ +"id":152, +"fortune":"DEIN EX DENKT AN DICH. ALS LEKTION" +}, +{ +"id":153, +"fortune":"DEIN FLIRTEN IST SUBTIL. NICHT NACHWEISBAR" +}, +{ +"id":154, +"fortune":"DEIN BEUTESCHEMA IST KONSTANT. LEIDER" +}, +{ +"id":155, +"fortune":"JEMAND BEWUNDERT DICH VON FERN. BLEIB DORT" +}, +{ +"id":156, +"fortune":"DEINE GRÜNEN FLAGGEN SIND IN DER UNTERZAHL" +}, +{ +"id":157, +"fortune":"LIEBE BESIEGT ALLES. SIE BAT UM VERSTÄRKUNG" +}, +{ +"id":158, +"fortune":"DAS HERZ AUF DER ZUNGE. BITTE BEIDE REINIGEN" +}, +{ +"id":159, +"fortune":"EINE NACHRICHT VON FRÜHER NAHT. IGNORIEREN" +}, +{ +"id":160, +"fortune":"DEIN SCHWARM WEIß VON DIR. ALS KONZEPT" +}, +{ +"id":161, +"fortune":"DU LIEBST TIEF. KURZ. ABER TIEF" +}, +{ +"id":162, +"fortune":"DEIN HERZ IST OFFEN. DEINE RECHNUNG AUCH" +}, +{ +"id":163, +"fortune":"ES WIRD FUNKEN. PRÜF DEN RAUCHMELDER" +}, +{ +"id":164, +"fortune":"DU BIST BEREIT FÜR BINDUNG. ANS SOFA" +}, +{ +"id":165, +"fortune":"DEIN HERZ IST GEHEILT. MIT ALARMANLAGE" +}, +{ +"id":166, +"fortune":"LIEBE IST GEDULDIG. SIE ÜBTE AN DIR" +}, +{ +"id":167, +"fortune":"DEINE FLITTERWOCHEN DAUERTEN ELF TAGE" +}, +{ +"id":168, +"fortune":"DEIN HAUSTIER IST DEINE BESTE BEZIEHUNG" +}, +{ +"id":169, +"fortune":"DEINE GELÜBDE RÜHREN ZU TRÄNEN. DIE GRAMMATIK" +}, +{ +"id":170, +"fortune":"DU BIST EIN FANG. FANGEN UND FREILASSEN GIBTS" +}, +{ +"id":171, +"fortune":"DEIN PERFECT MATCH EXISTIERT. DIE APP GAB AUF" +}, +{ +"id":172, +"fortune":"DEINE ROTEN FLAGGEN SIND NUN WEINROT. GUT" +}, +{ +"id":173, +"fortune":"LIEBE AUF DEN ERSTEN BLICK. KAUF EINE BRILLE" +}, +{ +"id":174, +"fortune":"JEMAND FINDET DICH PERFEKT. AUS DER FERNE" +}, +{ +"id":175, +"fortune":"DU GLAUBST AN ZWEITE CHANCEN. UND AN FÜNFTE" +}, +{ +"id":176, +"fortune":"DEINE TRENNUNGSPLAYLIST LÄUFT OFT" +}, +{ +"id":177, +"fortune":"DU BIST DAS WARTEN WERT. ES WARTET NOCH" +}, +{ +"id":178, +"fortune":"ROMANTIK IST NICHT TOT. DEINE RUHT SICH AUS" +}, +{ +"id":179, +"fortune":"DEINE SCHWIEGERELTERN LIEBEN DICH. IRGENDWANN" +}, +{ +"id":180, +"fortune":"DEIN DATINGPROFIL IST EHRLICH. STELLENWEISE" +}, +{ +"id":181, +"fortune":"DEINE UMARMUNGEN SIND SELTEN. WIE EKLIPSEN" +}, +{ +"id":182, +"fortune":"JEMAND TRÄUMT VON DEINEM ESSEN. ANGSTVOLL" +}, +{ +"id":183, +"fortune":"DEIN CHARME ÖFFNET TÜREN. DRÜCKEN HILFT" +}, +{ +"id":184, +"fortune":"DEINE ANSPRÜCHE TRAFEN DEINE WAHL. PEINLICH" +}, +{ +"id":185, +"fortune":"DU WIRST UMGEHAUEN. DEHN DICH VORHER" +}, +{ +"id":186, +"fortune":"INTIMITÄT HEIßT GESEHEN SEIN. DU VERHANDELST" +}, +{ +"id":187, +"fortune":"EURE GESCHICHTE WIRD ERZÄHLT. ALS WARNUNG" +}, +{ +"id":188, +"fortune":"DER FUNKE IST NOCH DA. SUCHTRUPP LÄUFT" +}, +{ +"id":189, +"fortune":"EUER JAHRESTAG NAHT. DIES IST DIE ERINNERUNG" +}, +{ +"id":190, +"fortune":"LIEB DICH SELBST ZUERST. DAS KANNST DU SCHON" +}, +{ +"id":191, +"fortune":"DEIN HERZ SETZTE AUS. GEH ZUM ARZT" +}, +{ +"id":192, +"fortune":"DU HOLST DAS BESTE AUS ALLEN. BEIM ABSCHIED" +}, +{ +"id":193, +"fortune":"NIE ZUFRIEDENGEBEN. DAHER DIE KLAPPSTÜHLE" +}, +{ +"id":194, +"fortune":"DEIN KÜNFTIGER PARTNER TRAINIERT. AHNUNGSLOS" +}, +{ +"id":195, +"fortune":"DEIN HERZ IST EINE FESTUNG. SHOP GEÖFFNET" +}, +{ +"id":196, +"fortune":"DEIN KUSCHELBEDARF HAT SPRECHZEITEN" +}, +{ +"id":197, +"fortune":"JEMAND VERMISST DICH. DIE NUMMER IST WEG" +}, +{ +"id":198, +"fortune":"DU FLIRTEST MIT BLICKEN. NIEMAND SAH SIE" +}, +{ +"id":199, +"fortune":"DEINE LIEBESBRIEFE SIND JETZT SPRACHNOTIZEN" +}, +{ +"id":200, +"fortune":"FREUNDE SCHÄTZEN DEINE EHRLICHKEIT. VON FERN" +}, +{ +"id":201, +"fortune":"EIN FREUND RUFT BALD AN. ER ZIEHT UM" +}, +{ +"id":202, +"fortune":"DU BIST DER KLEBER. KLEBER DANKT MAN SELTEN" +}, +{ +"id":203, +"fortune":"DER GRUPPENCHAT GENIEßT DEINE STILLE" +}, +{ +"id":204, +"fortune":"WAHRE FREUNDE SIND RAR. DEINE VERSTECKEN SICH" +}, +{ +"id":205, +"fortune":"GROßE TREUE. KLEINE PÜNKTLICHKEIT" +}, +{ +"id":206, +"fortune":"EIN FEST BRINGT FREUDE. DAS GEHEN NOCH MEHR" +}, +{ +"id":207, +"fortune":"DU BIST DER LUSTIGE. EIGENANGABE" +}, +{ +"id":208, +"fortune":"EIN ALTER FREUND MELDET SICH. ER BRAUCHT WAS" +}, +{ +"id":209, +"fortune":"DEIN RAT WIRD GESCHÄTZT. NICHT BESTELLT" +}, +{ +"id":210, +"fortune":"DU ERHELLST JEDEN RAUM. MANCHE WOLLEN DIMMER" +}, +{ +"id":211, +"fortune":"DEIN GEBURTSTAG WIRD ERINNERT. EINEN TAG SPÄT" +}, +{ +"id":212, +"fortune":"DEINE GESCHICHTEN WERDEN BESSER. UND FALSCHER" +}, +{ +"id":213, +"fortune":"MENSCHEN FÜHLEN SICH ZU DIR HINGEZOGEN. KURZ" +}, +{ +"id":214, +"fortune":"DU WEIßT STETS WAS ZU SAGEN IST. WANN NICHT" +}, +{ +"id":215, +"fortune":"FREUNDE KOMMEN UND GEHEN. DEINE KÖNNEN GEHEN" +}, +{ +"id":216, +"fortune":"DEIN TERMINKALENDER IST VOLL. MIT VIELLEICHTS" +}, +{ +"id":217, +"fortune":"DEINE INSIDERWITZE SIND JETZT SOLOAUFTRITTE" +}, +{ +"id":218, +"fortune":"DEINE PARTYS SIND LEGENDÄR. DIE ABGESAGTEN" +}, +{ +"id":219, +"fortune":"DU BRINGST MENSCHEN ZUSAMMEN. ALS THEMA" +}, +{ +"id":220, +"fortune":"DEINE GROßZÜGIGKEIT HAT ÖFFNUNGSZEITEN" +}, +{ +"id":221, +"fortune":"DU VERGISST NIE EIN GESICHT. NAMEN SCHON" +}, +{ +"id":222, +"fortune":"DEINE AUFMUNTERUNGEN BRAUCHEN NACHSORGE" +}, +{ +"id":223, +"fortune":"DU BIST DA WENN ES ZÄHLT. FÜR DICH" +}, +{ +"id":224, +"fortune":"DEINE ABSCHIEDSFESTE SIND GUT BESUCHT" +}, +{ +"id":225, +"fortune":"MAN VERTRAUT DIR GEHEIMNISSE AN. UND ANDEREN" +}, +{ +"id":226, +"fortune":"DEINE EHRLICHKEIT ERFRISCHT. WIE EISWASSER" +}, +{ +"id":227, +"fortune":"DU HEGST KEINEN GROLL. DU ARCHIVIERST IHN" +}, +{ +"id":228, +"fortune":"DEINE MEMES KOMMEN IM MORGENGRAUEN. UNGEFRAGT" +}, +{ +"id":229, +"fortune":"DEINE SCHULTER IST FREI. NUR MIT TERMIN" +}, +{ +"id":230, +"fortune":"DU HÄLTST ALLE AM BODEN. WIE NEBEL" +}, +{ +"id":231, +"fortune":"DEINE BEGEISTERUNG STECKT AN. MASKEN HELFEN" +}, +{ +"id":232, +"fortune":"EIN FREUND WILL DEINE EHRLICHE MEINUNG. FALLE" +}, +{ +"id":233, +"fortune":"DU TEILST RECHNUNGEN FAIR. DEINE MATHE NICHT" +}, +{ +"id":234, +"fortune":"DEINE ANWESENHEIT IST EIN GESCHENK. MIT BELEG" +}, +{ +"id":235, +"fortune":"DEIN EHRGEIZ BEENDETE DIE SPIELEABENDE" +}, +{ +"id":236, +"fortune":"DEINE ÜBERRASCHUNGSPARTYS ÜBERRASCHEN KEINEN" +}, +{ +"id":237, +"fortune":"MAN FÜHLT SICH WOHL BEI DIR. BEIM GEHEN" +}, +{ +"id":238, +"fortune":"DU SAGST WAS ALLE DENKEN. AUF BEERDIGUNGEN" +}, +{ +"id":239, +"fortune":"DEIN JAHRESRUNDBRIEF HAT EINE LESERSCHAFT" +}, +{ +"id":240, +"fortune":"DEINE ENTSCHULDIGUNGEN SIND HERZLICH. UND OFT" +}, +{ +"id":241, +"fortune":"DU PFLEGST DIE GRUPPENHISTORIE. ÜBERARBEITET" +}, +{ +"id":242, +"fortune":"DU HILFST NIE UNBEMERKT. DAS SAGST DU AUCH" +}, +{ +"id":243, +"fortune":"DEINE DIREKTHEIT IST CHARMANT. LAUT PROTOKOLL" +}, +{ +"id":244, +"fortune":"DU BIST MODISCH SPÄT. OHNE DAS MODISCH" +}, +{ +"id":245, +"fortune":"MAN SUCHT DEINE ZUSTIMMUNG. UM ZU GEHEN" +}, +{ +"id":246, +"fortune":"DU LÄSTERST NIE. DU INFORMIERST ABWESENDE" +}, +{ +"id":247, +"fortune":"DIE EINLADUNG SAGT LOCKER. DEINE MAILS NICHT" +}, +{ +"id":248, +"fortune":"EIN JUGENDFREUND DENKT AN DICH. AUS DER FERNE" +}, +{ +"id":249, +"fortune":"DU VERLIERST NIE STREITS. DU VERLEGST SIE" +}, +{ +"id":250, +"fortune":"DEINE HILFE IST BEDINGUNGSLOS. SIEHE AGB" +}, +{ +"id":251, +"fortune":"REICHTUM NAHT. ER HAT DEINE ALTE ADRESSE" +}, +{ +"id":252, +"fortune":"GELD FLIEßT ZU DIR. DURCH DICH. WEG" +}, +{ +"id":253, +"fortune":"DEIN BUDGET IST KUNST. ABSTRAKTE KUNST" +}, +{ +"id":254, +"fortune":"SPAR FÜR SCHLECHTE ZEITEN. MONSUN GEMELDET" +}, +{ +"id":255, +"fortune":"DEINE SCHUFA IST EIN THRILLER" +}, +{ +"id":256, +"fortune":"DEIN ERSPARTES WÄCHST. AN CHARAKTER" +}, +{ +"id":257, +"fortune":"GELD SPRICHT. DEINS SAGT TSCHÜSS" +}, +{ +"id":258, +"fortune":"DEINE ALTERSVORSORGE IST EIN LOTTOSCHEIN" +}, +{ +"id":259, +"fortune":"DEIN GESCHMACK IST TEUER. DEIN KONTO NICHT" +}, +{ +"id":260, +"fortune":"ZINSESZINS IST MAGIE. DU WÄHLTEST SCHULDEN" +}, +{ +"id":261, +"fortune":"DEIN NOTGROSCHEN DECKT KLEINE NOTFÄLLE" +}, +{ +"id":262, +"fortune":"EINE GEHALTSERHÖHUNG IST VERDIENT. UND OFFEN" +}, +{ +"id":263, +"fortune":"DEIN WARENKORB IST EIN VISIONBOARD MIT KASSE" +}, +{ +"id":264, +"fortune":"DEINE GROßZÜGIGKEIT KENNT JEDER HÄNDLER" +}, +{ +"id":265, +"fortune":"DAS BESTE IST GRATIS. DEINS HAT VERSANDKOSTEN" +}, +{ +"id":266, +"fortune":"DEINE ABOS ÜBERTREFFEN DEINE FREUNDE. AN ZAHL" +}, +{ +"id":267, +"fortune":"BILLIG KAUFEN TEUER VERKAUFEN. DU DREHST UM" +}, +{ +"id":268, +"fortune":"DEINE BANK SCHREIBT DIR AUS SORGE" +}, +{ +"id":269, +"fortune":"DEINE STEUERERSTATTUNG HAT EIGENE PLÄNE" +}, +{ +"id":270, +"fortune":"DEINE KÄUFE SIND STRATEGISCH. ANGEBLICH" +}, +{ +"id":271, +"fortune":"DU FINDEST GELD IM MANTEL. ES WAR DEINS" +}, +{ +"id":272, +"fortune":"DEIN PORTFOLIO IST BREIT GESTREUT. IN REUE" +}, +{ +"id":273, +"fortune":"ZAHLTAG BRINGT FREUDE. ETWA 18 STUNDEN LANG" +}, +{ +"id":274, +"fortune":"DEINE MAHNGEBÜHREN HABEN MAHNGEBÜHREN" +}, +{ +"id":275, +"fortune":"KLEINVIEH MACHT AUCH MIST. DEINS MACHT PAUSE" +}, +{ +"id":276, +"fortune":"REICH IM HERZEN. DIE KASSE SIEHT DAS ANDERS" +}, +{ +"id":277, +"fortune":"DEINE BELEGE ERZÄHLEN EINE LANGE GESCHICHTE" +}, +{ +"id":278, +"fortune":"DEINE ANZAHLUNG WURDE SUSHI. ZWEIMAL" +}, +{ +"id":279, +"fortune":"DEIN HAUSHALTSPLAN IST HISTORISCHE FIKTION" +}, +{ +"id":280, +"fortune":"DEINE PROBEABOS LEBEN EWIG. SIE BUCHEN AB" +}, +{ +"id":281, +"fortune":"BARGELD IST KÖNIG. DEIN REICH LEBT AUF PUMP" +}, +{ +"id":282, +"fortune":"DEIN KAUFSTOPP HIELT 40 MINUTEN" +}, +{ +"id":283, +"fortune":"DEINE RECHNUNGEN KOMMEN PÜNKTLICH. DU NICHT" +}, +{ +"id":284, +"fortune":"DEIN GELD ARBEITET HART. FÜR ANDERE" +}, +{ +"id":285, +"fortune":"DEINE GUTSCHEINE LIEFEN AB. ALLE. HEUTE" +}, +{ +"id":286, +"fortune":"DEIN FINANZPLAN HAT PHASEN. ERST VERDRÄNGUNG" +}, +{ +"id":287, +"fortune":"DEINE RABATTE FINANZIEREN DEINE SPONTANKÄUFE" +}, +{ +"id":288, +"fortune":"DEINE KRYPTOPHASE WAR LEHRREICH. UND TEUER" +}, +{ +"id":289, +"fortune":"LOTTO IST HOFFNUNGSSTEUER. DU SPENDEST GERN" +}, +{ +"id":290, +"fortune":"DEIN SPARZIEL STEHT SEIT DEM FRÜHJAHR STILL" +}, +{ +"id":291, +"fortune":"REICHTUM FLÜSTERT. DEINER LEGTE AUF" +}, +{ +"id":292, +"fortune":"DU NOTIERST JEDE AUSGABE. DANN KOMMEN NEUE" +}, +{ +"id":293, +"fortune":"DEIN SPARSCHWEIN HAT VERTRAUENSPROBLEME" +}, +{ +"id":294, +"fortune":"DEINE ERSTATTUNG KAM AN. SIE IST SCHON WEG" +}, +{ +"id":295, +"fortune":"GELD MACHT NICHT GLÜCKLICH. DEINS GAB AUF" +}, +{ +"id":296, +"fortune":"DEINE RECHNUNGEN REIFEN WIE WEIN. UNBEZAHLT" +}, +{ +"id":297, +"fortune":"DEIN KONTOSTAND UND DEIN EGO SANKEN GEMEINSAM" +}, +{ +"id":298, +"fortune":"DU KAUFST ORDNUNGSBOXEN FÜR ORDNUNGSBOXEN" +}, +{ +"id":299, +"fortune":"GRATISVERSAND KOSTET DICH EIN VERMÖGEN" +}, +{ +"id":300, +"fortune":"GEDULD IST EINE TUGEND. DU WÄHLTEST ANDERE" +}, +{ +"id":301, +"fortune":"REDEN IST SILBER. DEINS IST BLECH" +}, +{ +"id":302, +"fortune":"ERST DENKEN DANN REDEN. EIN PILOTPROJEKT" +}, +{ +"id":303, +"fortune":"STILLE WASSER SIND TIEF. DEINE KNÖCHELTIEF" +}, +{ +"id":304, +"fortune":"WISSEN IST MACHT. DEINS IST IM STANDBY" +}, +{ +"id":305, +"fortune":"EIN OFFENER GEIST IST GOLD. SCHÖNER DURCHZUG" +}, +{ +"id":306, +"fortune":"ZWEIMAL HÖREN EINMAL REDEN. DREH ES UM" +}, +{ +"id":307, +"fortune":"DIE WAHRHEIT MACHT FREI. DEINE SITZT NOCH" +}, +{ +"id":308, +"fortune":"ERST SCHAUEN DANN SPRINGEN. ODER DANACH" +}, +{ +"id":309, +"fortune":"NARR UND GELD TRENNEN SICH. SCHÖNE FEIER WARS" +}, +{ +"id":310, +"fortune":"TATEN SAGEN MEHR ALS WORTE. DEINE FLÜSTERN" +}, +{ +"id":311, +"fortune":"ZWEIMAL MESSEN EINMAL SCHNEIDEN. DU SÄGST" +}, +{ +"id":312, +"fortune":"DIE FEDER IST MÄCHTIG. DEINE MAILS AUCH" +}, +{ +"id":313, +"fortune":"BESSER SPÄT ALS NIE. DU TESTEST DAS TÄGLICH" +}, +{ +"id":314, +"fortune":"EHRLICH WÄHRT AM LÄNGSTEN. SIEHE FUßNOTEN" +}, +{ +"id":315, +"fortune":"ZÄHL DEINE HÜHNER NICHT. DEINE STREIKEN" +}, +{ +"id":316, +"fortune":"GRAS IST GRÜNER WO MAN GIEßT. KAUF SCHLAUCH" +}, +{ +"id":317, +"fortune":"JEDER HEILIGE HAT EINE AKTE. DEINE IST DICK" +}, +{ +"id":318, +"fortune":"PREDIGE WAS DU LEBST. ODER PREDIGE WENIGER" +}, +{ +"id":319, +"fortune":"ZWEI FEHLER MACHEN KEIN RECHT. STOPP BEI NEUN" +}, +{ +"id":320, +"fortune":"NICHT ALLES GOLD WAS GLÄNZT. PRÜF DEN BELEG" +}, +{ +"id":321, +"fortune":"EIN ROLLENDER STEIN. DEINER SETZTE MOOS AN" +}, +{ +"id":322, +"fortune":"NICHT ALLE EIER IN EINEN KORB. WO IST ER" +}, +{ +"id":323, +"fortune":"LEERE FÄSSER KLINGEN LAUT. TOLLE AKUSTIK" +}, +{ +"id":324, +"fortune":"WER ZULETZT LACHT DACHTE LANGSAM. HALLO" +}, +{ +"id":325, +"fortune":"DER SPATZ IN DER HAND. DEINER FLOG WEG" +}, +{ +"id":326, +"fortune":"REPARIER NUR KAPUTTES. JETZT IST ES KAPUTT" +}, +{ +"id":327, +"fortune":"DU FÜHRST PFERDE ZUM WASSER. SIE LEHNEN AB" +}, +{ +"id":328, +"fortune":"HOCHMUT KOMMT VOR DEM FALL. GUTE BALANCE" +}, +{ +"id":329, +"fortune":"DIE ZEIT HEILT ALLE WUNDEN. DU KRATZT DRAN" +}, +{ +"id":330, +"fortune":"ALTE GEWOHNHEITEN STERBEN SCHWER. DEINE NIE" +}, +{ +"id":331, +"fortune":"WO RAUCH IST DA BIST DU" +}, +{ +"id":332, +"fortune":"DIE BESTE VERTEIDIGUNG. ABSTAND. SIE LERNTEN" +}, +{ +"id":333, +"fortune":"NÄHE ZÜCHTET VERACHTUNG. BEI EUCH BLÜHT SIE" +}, +{ +"id":334, +"fortune":"DER TEUFEL STECKT IM DETAIL. DEINE SIND LEER" +}, +{ +"id":335, +"fortune":"DES EINEN MÜLL IST DEINE GARAGE" +}, +{ +"id":336, +"fortune":"EIN BEOBACHTETER TOPF KOCHT NIE. DEINER SCHON" +}, +{ +"id":337, +"fortune":"UNWISSENHEIT IST SEGEN. DU WIRKST SELIG" +}, +{ +"id":338, +"fortune":"SCHÖNHEIT LIEGT IM AUGE. LASS DAS AUGE PRÜFEN" +}, +{ +"id":339, +"fortune":"ES BRAUCHT EIN DORF. DEINS BAT UM VERSTÄRKUNG" +}, +{ +"id":340, +"fortune":"GROßE GEISTER DENKEN GLEICH. DEINER SOLO" +}, +{ +"id":341, +"fortune":"PROBIEREN GEHT ÜBER STUDIEREN. DU LÄSST BEIDE" +}, +{ +"id":342, +"fortune":"JEDER HUND HAT SEINEN TAG. DEINER WAR 2019" +}, +{ +"id":343, +"fortune":"WER NICHT WAGT GEWINNT NICHT. PERFEKTES REMIS" +}, +{ +"id":344, +"fortune":"VIELE KÖCHE VERDERBEN DEN BREI. DU AUCH SOLO" +}, +{ +"id":345, +"fortune":"DU ERNTEST WAS DU SÄST. INTERESSANTE ERNTE" +}, +{ +"id":346, +"fortune":"WER FRAGT BEKOMMT. DEIN TON SCHUF EINE LISTE" +}, +{ +"id":347, +"fortune":"GEH EINE MEILE IN FREMDEN SCHUHEN. RETOUR" +}, +{ +"id":348, +"fortune":"EILE MIT WEILE. DU BEHIELTST NUR DIE WEILE" +}, +{ +"id":349, +"fortune":"ALLES GUTE HAT EIN ENDE. DEINS KOMMT FRÜH" +}, +{ +"id":350, +"fortune":"WORTE SIND BILLIG. DEINE SIND GRATIS" +}, +{ +"id":351, +"fortune":"DIE ZEIT WARTET AUF NIEMANDEN. BEI DIR SCHON" +}, +{ +"id":352, +"fortune":"DIE FÜTTERNDE HAND TRÄGT NUN HANDSCHUHE" +}, +{ +"id":353, +"fortune":"VERGLEICHE STEHLEN FREUDE. DEINE IN VOLLZEIT" +}, +{ +"id":354, +"fortune":"HALBES BROT SCHLÄGT KEINS. DU BIETEST KRÜMEL" +}, +{ +"id":355, +"fortune":"GLATTE SEE MACHT KEINE SEELEUTE. BLEIB DAHEIM" +}, +{ +"id":356, +"fortune":"DIE WAHRHEIT BRAUCHT KEINE PROBE. DEINE SCHON" +}, +{ +"id":357, +"fortune":"ALLES IN MAßEN. AUCH DAS. HÖR AUF" +}, +{ +"id":358, +"fortune":"WAS DU SÄST KOMMT ZURÜCK. SENDUNG VERFOLGBAR" +}, +{ +"id":359, +"fortune":"STREITE NIE MIT NARREN. MAN RÄT WER WER IST" +}, +{ +"id":360, +"fortune":"WEISHEIT FLÜSTERT. DEINE IST STUMMGESCHALTET" +}, +{ +"id":361, +"fortune":"DER WEG BEGINNT MIT EINEM SCHRITT. DU DEHNST" +}, +{ +"id":362, +"fortune":"BRÜCKEN ÜBERQUEREN. NICHT ANZÜNDEN. ZUR INFO" +}, +{ +"id":363, +"fortune":"DIE EICHE WAR EINE NUSS. TRADITION GEWAHRT" +}, +{ +"id":364, +"fortune":"WER EINMAL TÄUSCHT. DEINE KARTE IST VOLL" +}, +{ +"id":365, +"fortune":"MORGENSTUND HAT GOLD IM MUND. DU SCHLÄFST" +}, +{ +"id":366, +"fortune":"ÜBUNG MACHT DEN MEISTER. DU SAMMELST THEORIE" +}, +{ +"id":367, +"fortune":"LÜGEN HABEN KURZE BEINE. DEINE JOGGEN GERN" +}, +{ +"id":368, +"fortune":"JEDER SCHMIEDET SEIN GLÜCK. DEINE ESSE RUHT" +}, +{ +"id":369, +"fortune":"DER APFEL FIEL STAMMNAH. DER STAMM SCHWEIGT" +}, +{ +"id":370, +"fortune":"ABENTEUER WARTET. ES GRÜNDETE EINE FIRMA" +}, +{ +"id":371, +"fortune":"DU WIRST WEIT REISEN. DER SHUTTLE ZÄHLT" +}, +{ +"id":372, +"fortune":"DEIN PASSFOTO ZEIGT DEIN WAHRES ICH. BEILEID" +}, +{ +"id":373, +"fortune":"DEINE LÖFFELLISTE BRAUCHT EINEN LÖFFEL" +}, +{ +"id":374, +"fortune":"DU SIEHST DIE WELT. PER DOKU" +}, +{ +"id":375, +"fortune":"DEINE URLAUBSTAGE REIFEN WIE EDLER FRUST" +}, +{ +"id":376, +"fortune":"EIN FERNES ZIEL RIEF AN. DU DRÜCKTEST WEG" +}, +{ +"id":377, +"fortune":"DEINE ROADTRIP PLAYLIST ÜBERLEBTE DEN TRIP" +}, +{ +"id":378, +"fortune":"DU PACKST LEICHT. EMOTIONAL EHER NICHT" +}, +{ +"id":379, +"fortune":"DEINE SOUVENIRS ERZÄHLEN VON FLUGHAFENPREISEN" +}, +{ +"id":380, +"fortune":"DU VERIRRST DICH IM AUSLAND. WIE DAHEIM" +}, +{ +"id":381, +"fortune":"DEINE REISEFOTOS ZEIGEN DEINEN DAUMEN" +}, +{ +"id":382, +"fortune":"EIN SPONTANTRIP NAHT. MIT TABELLENKALKULATION" +}, +{ +"id":383, +"fortune":"DU BIST WELTBÜRGER. REFERENZEN AUSSTEHEND" +}, +{ +"id":384, +"fortune":"DEIN STRANDKÖRPER IST BEREIT. DER STRAND AUCH" +}, +{ +"id":385, +"fortune":"DIE BERGE RUFEN. DU HAST SIE STUMMGESCHALTET" +}, +{ +"id":386, +"fortune":"DEIN URLAUB AUF BALKONIEN IST UNGESCHLAGEN" +}, +{ +"id":387, +"fortune":"DU NAVIGIERST WIE EIN VERIRRTER PROFI" +}, +{ +"id":388, +"fortune":"DEIN REISEPLAN IST HAUPTSÄCHLICH PUFFERZEIT" +}, +{ +"id":389, +"fortune":"DEINE WANDERSCHUHE BESTIEGEN DEN SCHRANK" +}, +{ +"id":390, +"fortune":"JETLAG SCHONT NIEMANDEN. DU KAMST MÜDE AN" +}, +{ +"id":391, +"fortune":"DEIN REISETAGEBUCH HAT EINEN EINTRAG. FREUDE" +}, +{ +"id":392, +"fortune":"DU SAMMELST ERLEBNISSE. DIE KARTE SAGT DINGE" +}, +{ +"id":393, +"fortune":"DEIN ORIENTIERUNGSSINN IST FAMILIENLEGENDE" +}, +{ +"id":394, +"fortune":"EIN KURZTRIP NAHT. DIE WÄSCHE WARTET TREU" +}, +{ +"id":395, +"fortune":"DU KOMMST VERÄNDERT ZURÜCK. VOR ALLEM MÜDE" +}, +{ +"id":396, +"fortune":"DEINE ANKUNFTSZEIT AM FLUGHAFEN SAGT ALLES" +}, +{ +"id":397, +"fortune":"DEINE FENSTERPLATZFOTOS ZEIGEN DEN FLÜGEL" +}, +{ +"id":398, +"fortune":"DEIN HANDGEPÄCK HAT EIGENE SCHWERKRAFT" +}, +{ +"id":399, +"fortune":"DEINE CAMPINGKÜNSTE AMÜSIEREN DIE WASCHBÄREN" +}, +{ +"id":400, +"fortune":"DEIN HANDYAKKU HÄLT LÄNGER ALS DEIN ELAN" +}, +{ +"id":401, +"fortune":"DU LIEST DIE AGB IRGENDWANN. NEIN" +}, +{ +"id":402, +"fortune":"DEIN BILDSCHIRMZEITBERICHT SCHONT DICH SCHON" +}, +{ +"id":403, +"fortune":"DEIN WÄSCHESTUHL HAT NUN EINE FESTANSTELLUNG" +}, +{ +"id":404, +"fortune":"DEIN WECKER HAT FÜNF ERSATZWECKER. ALLE STUMM" +}, +{ +"id":405, +"fortune":"DEIN KÜHLSCHRANK BEHERBERGT EIN EXPERIMENT" +}, +{ +"id":406, +"fortune":"DIE MOTORLEUCHTE IST JETZT STIMMUNGSLICHT" +}, +{ +"id":407, +"fortune":"DEINE ZIMMERPFLANZEN HABEN SICH GEFÜGT" +}, +{ +"id":408, +"fortune":"DEINE KRIMSKRAMSSCHUBLADE EXPANDIERTE" +}, +{ +"id":409, +"fortune":"DEINE SPORTTASCHE IST GEPACKT. DAS ZÄHLT" +}, +{ +"id":410, +"fortune":"DEINE MAILBOX IST VOLL. MAN ZOG WEITER" +}, +{ +"id":411, +"fortune":"DEINE BROWSERTABS SIND EIN ÖKOSYSTEM" +}, +{ +"id":412, +"fortune":"DEIN SCHIRM WARTET. DU VERGISST IHN EH" +}, +{ +"id":413, +"fortune":"DEINE RESTE HATTEN TRÄUME. SIE KOMPOSTIEREN" +}, +{ +"id":414, +"fortune":"DEINE TODOLISTE HAT EINE TODOLISTE" +}, +{ +"id":415, +"fortune":"DEIN SCHRANK KLEIDET DREI VERSIONEN VON DIR" +}, +{ +"id":416, +"fortune":"DEIN MORGENLAUF IST GEPLANT. SEIT MONATEN" +}, +{ +"id":417, +"fortune":"DEIN ROUTER STEHT AUF EINEM SCHREIN. KORREKT" +}, +{ +"id":418, +"fortune":"DEIN INBOX ZERO VERSUCH IST GESCHICHTE" +}, +{ +"id":419, +"fortune":"DEINE SOCKENSCHUBLADE SCHÜTZT EINZELGÄNGER" +}, +{ +"id":420, +"fortune":"DEIN EINKAUFSZETTEL BLEIBT DAHEIM. ER WEIß" +}, +{ +"id":421, +"fortune":"DEINE WATCHLIST ÜBERLEBTE DREI HOBBYS" +}, +{ +"id":422, +"fortune":"DER DRUCKER SPÜRT ANGST. UND AKTUALISIERT" +}, +{ +"id":423, +"fortune":"DEINE SCHLAFENSZEIT IST EIN ANTRAG. ABGELEHNT" +}, +{ +"id":424, +"fortune":"DEINE KOPFHÖRER VERKNOTEN SICH ALLEIN" +}, +{ +"id":425, +"fortune":"DEIN GEWÜRZREGAL IST SORTIERT BIS C" +}, +{ +"id":426, +"fortune":"DEIN RÜCKSITZ IST EIN FUNDBÜRO" +}, +{ +"id":427, +"fortune":"DAS GUTE KABEL IST IMMER WOANDERS" +}, +{ +"id":428, +"fortune":"DEIN STEHPULT SITZT MEISTENS. WIE DU" +}, +{ +"id":429, +"fortune":"DEIN MEALPREP ERGAB EIN GERICHT. SECHS DOSEN" +}, +{ +"id":430, +"fortune":"DER PAKETBOTE WINKT DIR INZWISCHEN ZU" +}, +{ +"id":431, +"fortune":"DEINE HEIßLUFTFRITTEUSE ERSETZTE DEN HERD" +}, +{ +"id":432, +"fortune":"DEINE LESEZEICHEN SIND EIN VORSATZARCHIV" +}, +{ +"id":433, +"fortune":"DEINE SCHLUMMERTASTE ZEIGT ABNUTZUNG" +}, +{ +"id":434, +"fortune":"DEINE STOFFTASCHEN WARTEN IM AUTO. TREU" +}, +{ +"id":435, +"fortune":"DEINE UPDATES HABEN JETZT DIENSTALTER" +}, +{ +"id":436, +"fortune":"DER EISWÜRFELBEHÄLTER KOMMT LEER ZURÜCK" +}, +{ +"id":437, +"fortune":"DEINE GARAGE LAGERT ALLES AUßER DEM AUTO" +}, +{ +"id":438, +"fortune":"DEIN SCHRITTZÄHLER RAHMTE SEINEN BESTEN TAG" +}, +{ +"id":439, +"fortune":"DEINE LIEBLINGSTASSE STEHT UNTER SCHUTZ" +}, +{ +"id":440, +"fortune":"DIE WETTERAPP GAB DEINE OUTFITS AUF" +}, +{ +"id":441, +"fortune":"DEINE WAAGE ÜBT RADIKALE EHRLICHKEIT" +}, +{ +"id":442, +"fortune":"DEINE FERNBEDIENUNGEN PENDELN IM SOFA" +}, +{ +"id":443, +"fortune":"DER FLURSCHRANK HÜTET DEINE WAHRHEIT. KNAPP" +}, +{ +"id":444, +"fortune":"DU HAST JEDE BATTERIE AUßER DER RICHTIGEN" +}, +{ +"id":445, +"fortune":"DEIN STAUBSAUGER MEIDET ECKEN. WIE DU" +}, +{ +"id":446, +"fortune":"DEINE DUSCHGEDANKEN BLEIBEN IN DER DUSCHE" +}, +{ +"id":447, +"fortune":"DIE KAFFEEMASCHINE KENNT DEIN MONTAGSGESICHT" +}, +{ +"id":448, +"fortune":"DEIN GEFRIERFACH IST ÄLTER ALS MANCHE FREUNDE" +}, +{ +"id":449, +"fortune":"DEIN SPEICHER IST VOLL. NUR SCREENSHOTS" +}, +{ +"id":450, +"fortune":"DEINE FAHRRADREIFEN SEUFZEN LANGSAM AUS" +}, +{ +"id":451, +"fortune":"DEIN RETOURENSTAPEL HAT EINE ABFLUGHALLE" +}, +{ +"id":452, +"fortune":"DEINE KERZEN SIND DEKO. STREICHHÖLZER AUCH" +}, +{ +"id":453, +"fortune":"DEIN ESSTISCH HAT DAS ESSEN AUFGEGEBEN" +}, +{ +"id":454, +"fortune":"DEINE AUTOKORREKTUR SCHLÄGT SORRY VOR" +}, +{ +"id":455, +"fortune":"DEINE FITNESSAPP SCHREIBT KÜRZERE SÄTZE" +}, +{ +"id":456, +"fortune":"DEINE MANTELTASCHE IST EINE ZEITKAPSEL" +}, +{ +"id":457, +"fortune":"DIE PLUS 30 SEKUNDEN TASTE FÜHRT DEINE KÜCHE" +}, +{ +"id":458, +"fortune":"DIE GUTE SCHERE FEHLT. EIN VERDÄCHTIGER" +}, +{ +"id":459, +"fortune":"DEIN DOWNLOADORDNER IST EINE DEPONIE" +}, +{ +"id":460, +"fortune":"DEINE PFLANZEN LEBEN VON SCHULDGEFÜHLEN" +}, +{ +"id":461, +"fortune":"DER TROCKNER NIMMT EINE SOCKE ALS TRIBUT" +}, +{ +"id":462, +"fortune":"DEINE UNTERSETZER SCHAUEN NUR NOCH ZU" +}, +{ +"id":463, +"fortune":"DEINE NOTIZAPP IST EINE GENIEDEPONIE" +}, +{ +"id":464, +"fortune":"DER REGEN WÄSCHT DEIN AUTO. WIE GEPLANT" +}, +{ +"id":465, +"fortune":"DEINE BRETTSPIELE ALTERN IN FOLIE" +}, +{ +"id":466, +"fortune":"DEINE YOGAMATTE LAG ZWEIMAL AUS. FÜR NAPS" +}, +{ +"id":467, +"fortune":"DEINE VERLÄNGERUNGSKABEL VERMEHREN SICH" +}, +{ +"id":468, +"fortune":"DEIN SMARTSPEAKER HAT DINGE GEHÖRT" +}, +{ +"id":469, +"fortune":"DEINE DOSEN UND DECKEL PASSEN NIE. NIE" +}, +{ +"id":470, +"fortune":"DEINE WANDERSCHUHE BEREISEN DEN KOFFERRAUM" +}, +{ +"id":471, +"fortune":"DEIN ORDNER WICHTIG IST EIN HOSPIZ" +}, +{ +"id":472, +"fortune":"DEIN TÜRKRANZ IST JETZT GANZJÄHRIG. FESTLICH" +}, +{ +"id":473, +"fortune":"DIE EINE SCHUBLADE ERKLÄRT SICH NICHT MEHR" +}, +{ +"id":474, +"fortune":"DEIN BILDSCHIRM UM 2 UHR ZEIGT ALLES" +}, +{ +"id":475, +"fortune":"DEIN FEUERLÖSCHER LEBT VON SELBSTVERTRAUEN" +}, +{ +"id":476, +"fortune":"DEIN WASSERZIEL WURDE EINMAL ERREICHT. FEIER" +}, +{ +"id":477, +"fortune":"ÄLTER WERDEN STEHT DIR. DIE ALTERNATIVE NICHT" +}, +{ +"id":478, +"fortune":"DEIN ALTER IST NUR EINE ZAHL. EINE STEIGENDE" +}, +{ +"id":479, +"fortune":"DEINE KNIE MELDEN JETZT DAS WETTER. TALENT" +}, +{ +"id":480, +"fortune":"DEIN RÜCKEN GING ÖFTER RAUS ALS DU" +}, +{ +"id":481, +"fortune":"WEISHEIT KOMMT MIT GRAU. DEINS KAM FRÜH" +}, +{ +"id":482, +"fortune":"DU REIFST WIE WEIN. LIEGEND GELAGERT" +}, +{ +"id":483, +"fortune":"DEINE GEBURTSTAGSKERZEN SIND BRANDGEFÄHRLICH" +}, +{ +"id":484, +"fortune":"DEINE LESEBRILLE BRAUCHT EINE LESEBRILLE" +}, +{ +"id":485, +"fortune":"DEINE PLAYLIST HEIßT JETZT OLDIES. SAGT MAN" +}, +{ +"id":486, +"fortune":"DU STÖHNST BEIM HINSETZEN. EINE QUITTUNG" +}, +{ +"id":487, +"fortune":"DEIN STOFFWECHSEL GING OHNE ABSCHIED" +}, +{ +"id":488, +"fortune":"DU FÜHLST DICH WIE 25. DEIN KATER NICHT" +}, +{ +"id":489, +"fortune":"EIN APFEL AM TAG. ALS KUCHEN. SCHLUPFLOCH" +}, +{ +"id":490, +"fortune":"DEINE HALTUNG BESSERT SICH ZWEIMAL TÄGLICH" +}, +{ +"id":491, +"fortune":"DU SCHLÄFST ACHT STUNDEN. IN DREI NÄCHTEN" +}, +{ +"id":492, +"fortune":"DEINE VITAMINE VERFALLEN UNGENUTZT. JÄHRLICH" +}, +{ +"id":493, +"fortune":"DEINE DIÄT STARTET MONTAG. WELCHER IST OFFEN" +}, +{ +"id":494, +"fortune":"DER ZAHNARZT WEIß DU FLOSSTEST NUR HEUTE" +}, +{ +"id":495, +"fortune":"DEIN RUHEPULS IST SUPER. DU RUHST JA VIEL" +}, +{ +"id":496, +"fortune":"DU WIRST 100. AUS PROTEST" +}, +{ +"id":497, +"fortune":"DEIN SCHLAFTRACKER MELDET FIKTION" +}, +{ +"id":498, +"fortune":"DEINE ALLERGIEN KOMMEN PÜNKTLICH. IMMERHIN" +}, +{ +"id":499, +"fortune":"DEINE VERSTECKTEN TALENTE BLEIBEN VERSTECKT" +}, +{ +"id":500, +"fortune":"DEINE KREATIVITÄT KENNT NUR PAUSEN" +}, +{ +"id":501, +"fortune":"DU HAST EINE GABE. OHNE KASSENBON" +}, +{ +"id":502, +"fortune":"DEIN ROMAN WIRD FERTIG. VON JEMANDEM" +}, +{ +"id":503, +"fortune":"ZUM SCHAFFEN GEBOREN. AUSREDEN ZÄHLEN MIT" +}, +{ +"id":504, +"fortune":"DEIN MEISTERWERK IST IN DIR. ES WOHNT GERN DA" +}, +{ +"id":505, +"fortune":"DEIN GESANG RÜHRT ZU TRÄNEN. BIOLOGIE HALT" +}, +{ +"id":506, +"fortune":"DIE MUSE BESUCHT DICH. SIE RUFT VORHER AN" +}, +{ +"id":507, +"fortune":"DEINE FOTOS FANGEN ROHE VERWIRRUNG EIN" +}, +{ +"id":508, +"fortune":"DU DENKST UM DIE ECKE. DIE ECKE IST BESORGT" +}, +{ +"id":509, +"fortune":"DEINE GEDICHTE BEWEGEN. RICHTUNG AUSGANG" +}, +{ +"id":510, +"fortune":"DEINE FANTASIE IST GROß. DIE UMSETZUNG NICHT" +}, +{ +"id":511, +"fortune":"DU SIEHST DIE WELT ANDERS. LASS DAS PRÜFEN" +}, +{ +"id":512, +"fortune":"DEINE PODCASTIDEE GRÜßT DIE ANDEREN SECHS" +}, +{ +"id":513, +"fortune":"KREATIVITÄT FLIEßT AN DIR VORBEI. WINKEND" +}, +{ +"id":514, +"fortune":"DEINE SKIZZEN GEHÖREN WOHIN. IN DIE SCHUBLADE" +}, +{ +"id":515, +"fortune":"DEIN KOCHEN IST PERFORMANCEKUNST. MIT ALARM" +}, +{ +"id":516, +"fortune":"DEIN DREHBUCH HAT NUR POTENZIELLE ENERGIE" +}, +{ +"id":517, +"fortune":"DIE WELT IST DEINE LEINWAND. NOCH GRUNDIERT" +}, +{ +"id":518, +"fortune":"DEINE PROJEKTE SIND EINE OFFENE TRILOGIE" +}, +{ +"id":519, +"fortune":"DEIN MUSIKGESCHMACK IST TOP. SAGST DU" +}, +{ +"id":520, +"fortune":"DEIN TANZSTIL TROTZT KONVENTION. UND PHYSIK" +}, +{ +"id":521, +"fortune":"DU ERZÄHLST TOLL. DIE ENDEN FEHLEN NOCH" +}, +{ +"id":522, +"fortune":"APOTHEKER RAHMEN DEINE HANDSCHRIFT" +}, +{ +"id":523, +"fortune":"DEINE IDEEN KOMMEN UM 2. WEG UM 8" +}, +{ +"id":524, +"fortune":"DEIN SKIZZENBUCH HÜTET GROßE VERSPRECHEN" +}, +{ +"id":525, +"fortune":"DU KÖNNTEST EIN BUCH SCHREIBEN. EIN HEFT" +}, +{ +"id":526, +"fortune":"DEINE TÖPFERPHASE SCHUF UNVERGESSLICHES" +}, +{ +"id":527, +"fortune":"DEIN INNERER KÜNSTLER WILL ERST KAFFEE" +}, +{ +"id":528, +"fortune":"DEINE FARBWAHL IST MUTIG. SEHR MUTIG" +}, +{ +"id":529, +"fortune":"DEINE GITARRE KENNT DREI AKKORDE GUT" +}, +{ +"id":530, +"fortune":"DEIN SCHAFFENSPROZESS IST UNDOKUMENTIERT" +}, +{ +"id":531, +"fortune":"DEINE SCHALS WURDEN ERFAHRUNGEN. STRICKE FORT" +}, +{ +"id":532, +"fortune":"DU MALST MIT GEFÜHL. DER BODEN STIMMT ZU" +}, +{ +"id":533, +"fortune":"DEIN BONSAI IST JETZT EIN NORMALER BAUM" +}, +{ +"id":534, +"fortune":"DEINE SCHREIBSTIMME IST STARK. IN CHATS" +}, +{ +"id":535, +"fortune":"DEIN GARTEN WÄCHST. DAS UNKRAUT AM BESTEN" +}, +{ +"id":536, +"fortune":"DEINE KALLIGRAFIEPHASE WAR EIN WOCHENENDE" +}, +{ +"id":537, +"fortune":"DEIN HOLZWERK IST EHRLICH. SPLITTER LÜGEN NIE" +}, +{ +"id":538, +"fortune":"DEINE FANFICTION HAT FANS. BEIDE" +}, +{ +"id":539, +"fortune":"DEIN ORIGAMI FÜLLT DAS ALTPAPIER" +}, +{ +"id":540, +"fortune":"DEINE SCHREIBBLOCKADE IST JETZT TRAGEND" +}, +{ +"id":541, +"fortune":"DEIN SAUERTEIG ÜBERLEBTE DAS HOBBY" +}, +{ +"id":542, +"fortune":"DEINE AQUARELLE FANGEN ETWAS EIN. UNKLAR WAS" +}, +{ +"id":543, +"fortune":"DU GLÄNZT BEI ANFÄNGEN. MITTEN LEHNST DU AB" +}, +{ +"id":544, +"fortune":"DEINE UKULELE IST JETZT DEKO. WÜRDEVOLL" +}, +{ +"id":545, +"fortune":"DU BIST DEIN SCHÄRFSTER KRITIKER. STIMMT WOHL" +}, +{ +"id":546, +"fortune":"DEINE KUNST SPRICHT FÜR SICH. LEISE" +}, +{ +"id":547, +"fortune":"DEIN ATELIER IST WIEDER EIN SCHRANK" +}, +{ +"id":548, +"fortune":"DEINE ERSTFASSUNGEN TREFFEN NIE ZWEITE" +}, +{ +"id":549, +"fortune":"DEINE KERZENPHASE HINTERLIEß SPUREN. WACHS" +}, +{ +"id":550, +"fortune":"DEIN OPENMIC DEBÜT BLEIBT BEVORSTEHEND" +}, +{ +"id":551, +"fortune":"DEINE KOSTÜME ZEIGEN HINGABE. ZU KONZEPTEN" +}, +{ +"id":552, +"fortune":"DEINE MAKRAMEEEULE SAH DEINE PROJEKTE" +}, +{ +"id":553, +"fortune":"DEINE SPRACHMEMOS SIND MEIST EINKAUFSLISTEN" +}, +{ +"id":554, +"fortune":"DU WIRST ENTDECKT. AUF DEINEM SOFA" +}, +{ +"id":555, +"fortune":"DEIN MOODBOARD IST NUR MOOD. KEIN BOARD" +}, +{ +"id":556, +"fortune":"DEIN MUSEUMSBESUCH ENDET IM CAFE" +}, +{ +"id":557, +"fortune":"DEINE COVERSONGS SCHLAGEN DIE ORIGINALE" +}, +{ +"id":558, +"fortune":"DEINE SCHREIBMASCHINE STEHT SCHÖN DA. STILL" +}, +{ +"id":559, +"fortune":"DEINE ABSTRAKTE PHASE VERWIRRTE AUCH DICH" +}, +{ +"id":560, +"fortune":"DEIN COMIC HAT EINEN FOLLOWER. HALLO MAMA" +}, +{ +"id":561, +"fortune":"DEIN REIMSCHEMA IST AMBITIONIERT. SEHR" +}, +{ +"id":562, +"fortune":"DEINE BASTELECKE ANNEKTIERTE DAS GÄSTEZIMMER" +}, +{ +"id":563, +"fortune":"DEIN GENIE WIRD VERKANNT. UND NIE GEZEIGT" +}, +{ +"id":564, +"fortune":"DEIN OPUS MAGNUM ZIEHT SEIT JAHREN DURCH" +}, +{ +"id":565, +"fortune":"DEIN INSPIRATIONSORDNER HAT UNTERORDNER" +}, +{ +"id":566, +"fortune":"DEIN KAFFEE IST INZWISCHEN EIN ABSATZ LANG" +}, +{ +"id":567, +"fortune":"ERST KAFFEE. DANN PERSÖNLICHKEIT. FAIR" +}, +{ +"id":568, +"fortune":"DEIN VIERTER KAFFEE BEOBACHTET DICH" +}, +{ +"id":569, +"fortune":"ENTKOFFEINIERT EXISTIERT. DU LEUGNEST ES" +}, +{ +"id":570, +"fortune":"DEINE TASSENSAMMLUNG SPRENGT DEN SCHRANK" +}, +{ +"id":571, +"fortune":"DU NENNST ES BRUNCH. ES WAR SPÄTES FRÜHSTÜCK" +}, +{ +"id":572, +"fortune":"DEINE SALATPHASE ENDETE BEIM DRESSING" +}, +{ +"id":573, +"fortune":"DU PLANST MAHLZEITEN SCHÖN. DANN BESTELLST DU" +}, +{ +"id":574, +"fortune":"DEIN LEIBGERICHT HAT EINEN FAN. DICH" +}, +{ +"id":575, +"fortune":"DER OFENTIMER IST FÜR DICH EIN VORSCHLAG" +}, +{ +"id":576, +"fortune":"DEINE SMOOTHIES VERSTECKEN GEMÜSE. VOR DIR" +}, +{ +"id":577, +"fortune":"DU KOCHST MIT LIEBE. UND ZU VIEL SALZ" +}, +{ +"id":578, +"fortune":"DEINE REZEPTÄNDERUNGEN SIND TAPFER" +}, +{ +"id":579, +"fortune":"KNOBLAUCH MISST DU MIT DEM HERZEN. WIEDER" +}, +{ +"id":580, +"fortune":"DEIN TOAST IST STARK. STARK VERBRANNT" +}, +{ +"id":581, +"fortune":"DESSERT ZUERST. DAS LEBEN IST KURZ. JA JA" +}, +{ +"id":582, +"fortune":"DEINE SNACKSCHUBLADE HAT EINE WARTELISTE" +}, +{ +"id":583, +"fortune":"DER LIEFERDIENST KENNT DICH BEIM NAMEN" +}, +{ +"id":584, +"fortune":"DEINE KÜCHENGERÄTE BILDEN EIN MUSEUM" +}, +{ +"id":585, +"fortune":"DEINE VORRATSDOSEN SIND JETZT ERBSTÜCKE" +}, +{ +"id":586, +"fortune":"DU ISST ANGEBLICH ALLES. DANN DOCH NICHT" +}, +{ +"id":587, +"fortune":"DEINE PIZZAWAHL HAT KRITIKER" +}, +{ +"id":588, +"fortune":"DEIN HUND LIEBT DICH BEDINGUNGSLOS. DRESSIERT" +}, +{ +"id":589, +"fortune":"DEINE KATZE DULDET DICH. EINE HOHE EHRE" +}, +{ +"id":590, +"fortune":"DEIN HAUSTIER ISST BESSER ALS DU" +}, +{ +"id":591, +"fortune":"DEIN HUND HAT MEHR FREUNDE ALS DU" +}, +{ +"id":592, +"fortune":"DIE KATZE WARF ES MIT ABSICHT UM. RESPEKT" +}, +{ +"id":593, +"fortune":"DEIN FISCH KENNT DEINEN PLAN. ER SORGT SICH" +}, +{ +"id":594, +"fortune":"DER HUND FRAß DEINE MOTIVATION" +}, +{ +"id":595, +"fortune":"DEINE KATZE BEWERTET NACHTS DEIN LEBEN" +}, +{ +"id":596, +"fortune":"DEIN VOGEL ZITIERT DEINE SCHLECHTESTEN SÄTZE" +}, +{ +"id":597, +"fortune":"DEIN HAUSTIER HÖRT GUT ZU. UND KOSTENLOS" +}, +{ +"id":598, +"fortune":"REGEN KOMMT. DEINE AUTOWÄSCHE JUBELT" +}, +{ +"id":599, +"fortune":"DEINE WINTERJACKENDEBATTE STARTET IM OKTOBER" +}, +{ +"id":600, +"fortune":"DU PRÜFST DAS WETTER. UND ZIEHST FALSCH AN" +}, +{ +"id":601, +"fortune":"DER FRÜHLING KOMMT. DEINE ALLERGIE AUCH" +}, +{ +"id":602, +"fortune":"DEINE SONNENCREME VERFÄLLT UNGENUTZT" +}, +{ +"id":603, +"fortune":"SCHNEE IST MAGISCH. BIS ZUR SCHAUFEL" +}, +{ +"id":604, +"fortune":"DEINE SCHIRME WOHNEN ALLE WOANDERS" +}, +{ +"id":605, +"fortune":"SMALLTALK ÜBERS WETTER LIEGT DIR JETZT" +}, +{ +"id":606, +"fortune":"DIE VORHERSAGE ÄNDERTE SICH. DEINE PLÄNE NIE" +}, +{ +"id":607, +"fortune":"DEINE GARTENMÖBEL FÜRCHTEN JEDE SAISON" +}, +{ +"id":608, +"fortune":"DAS LAUB FÄLLT. WIE DEINE VORSÄTZE" +}, +{ +"id":609, +"fortune":"DEIN PASSWORT IST DEIN HAUSTIER. MAN WEIß ES" +}, +{ +"id":610, +"fortune":"DU HAST 47 UNGELESENE UPDATES. SIE WARTEN" +}, +{ +"id":611, +"fortune":"DEINE CLOUD IST VOLL. MIT DUPLIKATEN" +}, +{ +"id":612, +"fortune":"DIE AUTOKORREKTUR WUSSTE ES. SIE LEHNTE AB" +}, +{ +"id":613, +"fortune":"DEIN ROUTER BRAUCHT EINEN NEUSTART. DU AUCH" +}, +{ +"id":614, +"fortune":"DEIN SUCHVERLAUF IST EINE SAGA" +}, +{ +"id":615, +"fortune":"DU SCHLOSSEST HEUTE EINEN TAB. FORTSCHRITT" +}, +{ +"id":616, +"fortune":"DEIN SPAMORDNER VERMISST DICH" +}, +{ +"id":617, +"fortune":"DER ALGORITHMUS KENNT DICH GUT. ZU GUT" +}, +{ +"id":618, +"fortune":"DEINE SMARTWATCH EMPFIEHLT ATMEN. SPITZE" +}, +{ +"id":619, +"fortune":"DU TIPPST AM SCHNELLSTEN IM STREIT" +}, +{ +"id":620, +"fortune":"DU HAST DIE GRUPPE STUMM. DIE GRUPPE WEIß ES" +}, +{ +"id":621, +"fortune":"DEINE FESTSTELLTASTE TRAINIERT REGELMÄßIG" +}, +{ +"id":622, +"fortune":"DEIN EMOJIGEBRAUCH WURDE BESPROCHEN" +}, +{ +"id":623, +"fortune":"DEIN WLAN NAME IST DEIN BESTER WITZ" +}, +{ +"id":624, +"fortune":"NEUSTARTEN IST DEIN LEBENSSTIL" +}, +{ +"id":625, +"fortune":"DEIN FITNESSSTUDIO DANKT FÜR DIE SPENDE" +}, +{ +"id":626, +"fortune":"DEIN MARATHONPLAN IST GESPEICHERT. SICHER" +}, +{ +"id":627, +"fortune":"DER BEINTAG RESPEKTIERT DEINE ABWESENHEIT" +}, +{ +"id":628, +"fortune":"DEIN PROTEINPULVER ALTERT IN WÜRDE" +}, +{ +"id":629, +"fortune":"DU DEHNST DICH EINMAL IM JAHR. AMBITIONIERT" +}, +{ +"id":630, +"fortune":"DEIN VEREIN VERLIERT. DU NIMMST ES PERSÖNLICH" +}, +{ +"id":631, +"fortune":"DU KOMMST ZU SPÄT. DAS ZÄHLT ALS CARDIO" +}, +{ +"id":632, +"fortune":"DEIN HEIMSTUDIO LAGERT JETZT WÄSCHE" +}, +{ +"id":633, +"fortune":"DEINE BESTZEIT WAR EINE TEAMLEISTUNG" +}, +{ +"id":634, +"fortune":"DEIN AUFWÄRMEN IST DAS GANZE TRAINING" +}, +{ +"id":635, +"fortune":"DEINE RUHETAGE HABEN RUHETAGE" +}, +{ +"id":636, +"fortune":"SCHLAF IST FÜR STARKE. DU SCROLLST" +}, +{ +"id":637, +"fortune":"DEIN NICKERCHENPLAN IST DEIN WAHRER KALENDER" +}, +{ +"id":638, +"fortune":"DU ZÄHLST SCHAFE. SIE ZÄHLEN DEINE AUSREDEN" +}, +{ +"id":639, +"fortune":"DEIN KISSEN KENNT ALLE GEHEIMNISSE" +}, +{ +"id":640, +"fortune":"EINE FOLGE NOCH WAREN VIER FOLGEN" +}, +{ +"id":641, +"fortune":"DEINE TRÄUME SIND LEBHAFT. DEINE MORGEN NICHT" +}, +{ +"id":642, +"fortune":"DU STELLST SECHS WECKER. DU FÜRCHTEST KEINEN" +}, +{ +"id":643, +"fortune":"AUFSCHIEBEN VOR DEM SCHLAFEN IST AUCH WAHL" +}, +{ +"id":644, +"fortune":"DEINE WOCHENENDSCHLAFSCHULD VERZINST SICH" +}, +{ +"id":645, +"fortune":"DEINE FAMILIE LIEBT DICH. KNAPPE ABSTIMMUNG" +}, +{ +"id":646, +"fortune":"DEINE MUTTER HATTE RECHT. MIT ALLEM" +}, +{ +"id":647, +"fortune":"FAMILIENESSEN TESTEN DEINE DIPLOMATIE" +}, +{ +"id":648, +"fortune":"DEIN GESCHWISTER VERGISST NICHTS. NIE" +}, +{ +"id":649, +"fortune":"DIE VERWANDTEN FRAGEN NACH PLÄNEN. HALT DURCH" +}, +{ +"id":650, +"fortune":"DU BIST DAS LIEBLINGSKIND. UNBESTÄTIGT" +}, +{ +"id":651, +"fortune":"DER FAMILIENCHAT SCHLÄFT NIE" +}, +{ +"id":652, +"fortune":"OMA FÜTTERT DICH. WIDERSTAND IST ZWECKLOS" +}, +{ +"id":653, +"fortune":"DEINE FLACHWITZE VERERBEN SICH LÜCKENLOS" +}, +{ +"id":654, +"fortune":"DIE SITZORDNUNG AN FEIERTAGEN IST POLITIK" +}, +{ +"id":655, +"fortune":"DEIN NACHBAR WINKT. DER ZAUN WAR SEINE IDEE" +}, +{ +"id":656, +"fortune":"DIE HAUSVERWALTUNG SAH DEINEN RASEN. WIEDER" +}, +{ +"id":657, +"fortune":"DEINE NACHBARN KENNEN DEINEN TAGESABLAUF" +}, +{ +"id":658, +"fortune":"GELIEHENES WERKZEUG WIRD IRGENDWANN GESCHENK" +}, +{ +"id":659, +"fortune":"DEINE TÜRKAMERA SAH DEINEN BESTEN SPRINT" +}, +{ +"id":660, +"fortune":"DEIN ARBEITSWEG BILDET CHARAKTER. TÄGLICH" +}, +{ +"id":661, +"fortune":"DER STAU IST NICHT PERSÖNLICH. DEINER SCHON" +}, +{ +"id":662, +"fortune":"DEIN PARKSTIL LÖST GESPRÄCHE AUS" +}, +{ +"id":663, +"fortune":"DEIN NAVI SAGT NEUBERECHNUNG. MIT GEFÜHL" +}, +{ +"id":664, +"fortune":"DU FÄHRST WIE DU LEBST. BLINKEN OPTIONAL" +}, +{ +"id":665, +"fortune":"DEIN TANK LÄUFT AUF HOFFNUNG. UND DÄMPFEN" +}, +{ +"id":666, +"fortune":"DIE LINKE SPUR IST ZUM ÜBERHOLEN. NUR SO" +}, +{ +"id":667, +"fortune":"DEINE AUTOPLAYLIST HATTE 2016 IHREN GIPFEL" +}, +{ +"id":668, +"fortune":"DEINE HUPE ARBEITET MEHR ALS DEIN BLINKER" +}, +{ +"id":669, +"fortune":"DEIN EINPARKEN ZIEHT PUBLIKUM AN" +}, +{ +"id":670, +"fortune":"DIE ZEIT FLIEGT. DEINE MELDETE EINEN FLUGPLAN" +}, +{ +"id":671, +"fortune":"AUFSCHIEBEN IST EINE KUNST. DU LEHRST SIE" +}, +{ +"id":672, +"fortune":"DU MACHST ES MORGEN. MORGEN WEIß BESCHEID" +}, +{ +"id":673, +"fortune":"FRISTEN NAHEN. DU GENIEßT DIE AUSSICHT" +}, +{ +"id":674, +"fortune":"DEINE FÜNF MINUTEN SIND FREMDE STUNDEN" +}, +{ +"id":675, +"fortune":"SPÄTER IST DEINE LIEBSTE ZEITZONE" +}, +{ +"id":676, +"fortune":"DU BEENDEST DINGE. IRGENDWANN IST EIN WORT" +}, +{ +"id":677, +"fortune":"DEINE IRGENDWANNLISTE BRAUCHT EIN REGAL" +}, +{ +"id":678, +"fortune":"ZEITMANAGEMENT IST EINE FÄHIGKEIT. NOTIERT" +}, +{ +"id":679, +"fortune":"DU BIST EINMAL IM JAHR FRÜH. ES VERWIRRT ALLE" +}, +{ +"id":680, +"fortune":"DEINE PÜNKTLICHKEIT IST LOKAL BEKANNT. LEIDER" +}, +{ +"id":681, +"fortune":"DU LIEST DIES STATT ZU ARBEITEN. NOTIERT" +}, +{ +"id":682, +"fortune":"DEINE AUFMERKSAMKEIT IST. OH EIN VOGEL" +}, +{ +"id":683, +"fortune":"NOCH EINE MINUTE. BERÜHMTE LETZTE WORTE" +}, +{ +"id":684, +"fortune":"JEDE MAIL BEGINNT MIT ENTSCHULDIGE DIE SPÄTE" +}, +{ +"id":685, +"fortune":"DU ANTWORTEST IN GEOLOGISCHER ZEIT" +}, +{ +"id":686, +"fortune":"DEINE LESEBESTÄTIGUNGEN VERRATEN DICH" +}, +{ +"id":687, +"fortune":"DU LIEßT SIE AUF GELESEN. SIE SAHEN ES" +}, +{ +"id":688, +"fortune":"DEINE TIPPBLASE ERSCHIEN. UND VERSCHWAND" +}, +{ +"id":689, +"fortune":"DU SAGTEST MAN MÜSSTE MAL. MAN WIRD NIE" +}, +{ +"id":690, +"fortune":"DEINE SPRACHNOTIZEN SIND JETZT PODCASTS" +}, +{ +"id":691, +"fortune":"DU WINKTEST ZURÜCK. ES GALT JEMAND ANDEREM" +}, +{ +"id":692, +"fortune":"DEIN SMALLTALK HAT EIN DREHBUCH. ÜB ES" +}, +{ +"id":693, +"fortune":"DU SAGST WIR SOLLTEN MAL WIEDER. KLASSIKER" +}, +{ +"id":694, +"fortune":"DEIN HANDY IST AUF LAUTLOS. SEIT JAHREN" +}, +{ +"id":695, +"fortune":"DU MACHST SCREENSHOTS STATT ZU ANTWORTEN" +}, +{ +"id":696, +"fortune":"DEINE MEINUNG WURDE NOTIERT. UND ENTSORGT" +}, +{ +"id":697, +"fortune":"EIN KOMPLIMENT NAHT. NIMM ES UNBEHOLFEN AN" +}, +{ +"id":698, +"fortune":"DEIN NEUTRALER BLICK HAT EINEN RUF" +}, +{ +"id":699, +"fortune":"EINIG IN DER UNEINIGKEIT. DU VERLORST" +}, +{ +"id":700, +"fortune":"DEIN AUGENROLLEN IST IRGENDWIE HÖRBAR" +}, +{ +"id":701, +"fortune":"DEIN SEUFZER SPRACH GERADE BÄNDE" +}, +{ +"id":702, +"fortune":"DU SAGTEST PASST SCHON. NICHTS PASSTE" +}, +{ +"id":703, +"fortune":"DEIN DAUMEN HOCH BEENDETE FREUNDSCHAFTEN" +}, +{ +"id":704, +"fortune":"KEIN STRESS SAGTEST DU. GESTRESST" +}, +{ +"id":705, +"fortune":"DEIN SCHULTERZUCKEN LEISTET SCHWERSTARBEIT" +}, +{ +"id":706, +"fortune":"DU HAST DURCHGELÄCHELT. KNAPP. MAN SAH ES" +}, +{ +"id":707, +"fortune":"DEINE GEDULD HAT EINEN LADEBALKEN. ER HÄNGT" +}, +{ +"id":708, +"fortune":"DU VERGABST IHNEN. DIE TABELLE BLEIBT" +}, +{ +"id":709, +"fortune":"DEINE ANDEUTUNGEN BRAUCHEN UNTERTITEL" +}, +{ +"id":710, +"fortune":"DU HÄTTEST ES FAST GESAGT. DAS FAST WAR LAUT" +}, +{ +"id":711, +"fortune":"DEIN SCHWEIGEN HAT EINE AGENDA. WIE IMMER" +}, +{ +"id":712, +"fortune":"DU LIEßT ES GUT SEIN. IN DEINER AKTE" +}, +{ +"id":713, +"fortune":"DEINE GELASSENHEIT WIRKT VERDÄCHTIG" +}, +{ +"id":714, +"fortune":"DU NAHMST DEN HOHEN WEG. MIT KOMMENTAR" +}, +{ +"id":715, +"fortune":"DEIN FEEDBACKSANDWICH IST NUR BROT" +}, +{ +"id":716, +"fortune":"DU HÖRTEST ZU. UND MACHTEST ES TROTZDEM" +}, +{ +"id":717, +"fortune":"GUTEN MORGEN. DIE LATTE IST SCHON GERISSEN" +}, +{ +"id":718, +"fortune":"DEIN OPTIMISMUS IST HEUTE NIEDLICH" +}, +{ +"id":719, +"fortune":"HEUTE IST DEIN TAG. TEIL IHN NETT" +}, +{ +"id":720, +"fortune":"DU BIST SO AUFGEWACHT. BEILEID" +}, +{ +"id":721, +"fortune":"DER SPIEGEL SAH DICH ZUERST. ER VERARBEITET" +}, +{ +"id":722, +"fortune":"DEINE FRISUR HAT HEUTE EIGENE PLÄNE" +}, +{ +"id":723, +"fortune":"DER MONTAG SAH DICH KOMMEN. ER ÜBTE" +}, +{ +"id":724, +"fortune":"DEIN WOCHENENDE IST VORBEI. ES GRÜßT" +}, +{ +"id":725, +"fortune":"DER FREITAG LIEBT DICH. ES BERUHT AUF BEIDEM" +}, +{ +"id":726, +"fortune":"DEINE MITTAGSPAUSE VERDIENT EINE MEDAILLE" +}, +{ +"id":727, +"fortune":"DEIN OUTFIT SAGT MÜHE. DIE UHR SAGT HEKTIK" +}, +{ +"id":728, +"fortune":"DU TRÄGST PASSENDE SOCKEN. EIN FESTAKT" +}, +{ +"id":729, +"fortune":"DEINE SONNENBRILLE VERSTECKT NICHTS" +}, +{ +"id":730, +"fortune":"KLEIDE DICH FÜR DEN TRAUMJOB. SCHLAFTESTER" +}, +{ +"id":731, +"fortune":"DEIN BÜGELBRETT GING IN RENTE" +}, +{ +"id":732, +"fortune":"FALTEN SIND EINE TEXTUR. DEIN BESCHLUSS" +}, +{ +"id":733, +"fortune":"DEIN MODEZYKLUS RICHTET SICH NACH WÄSCHE" +}, +{ +"id":734, +"fortune":"DEINE SCHUHE PASSEN. DER ANLASS NICHT" +}, +{ +"id":735, +"fortune":"DU GEWINNST DEN STREIT. UNTER DER DUSCHE" +}, +{ +"id":736, +"fortune":"DEIN KONTER KAM AN. DREI TAGE SPÄTER" +}, +{ +"id":737, +"fortune":"DEIN WITZ IST SCHNELL. DEIN TIMING NICHT" +}, +{ +"id":738, +"fortune":"DIE PERFEKTE ANTWORT KAM UM MITTERNACHT" +}, +{ +"id":739, +"fortune":"DEIN INNERER MONOLOG BRAUCHT EINEN LEKTOR" +}, +{ +"id":740, +"fortune":"DEINE HEIßEN TAKES SIND ZIMMERWARM" +}, +{ +"id":741, +"fortune":"DEINE MEINUNGEN KOMMEN VORGEWÄRMT" +}, +{ +"id":742, +"fortune":"DEIN DEBATTENSTIL BASIERT AUF LAUTSTÄRKE" +}, +{ +"id":743, +"fortune":"DU PRÜFST FAKTEN. NUR FREMDE" +}, +{ +"id":744, +"fortune":"DEIN QUIZWISSEN GLÄNZT NUR AUF PARTYS" +}, +{ +"id":745, +"fortune":"EINE ENTSCHEIDUNG NAHT. WIRF EINE MÜNZE" +}, +{ +"id":746, +"fortune":"DEINE PROKONTRALISTE HAT EINE SPALTE" +}, +{ +"id":747, +"fortune":"DU FRAGTEST ALLE. UND MACHTEST DEINS" +}, +{ +"id":748, +"fortune":"DEIN BAUCH BRAUCHT EINE ZWEITMEINUNG" +}, +{ +"id":749, +"fortune":"DU SCHLIEFST DRÜBER. DAS PROBLEM WACHTE" +}, +{ +"id":750, +"fortune":"DEIN PLAN B IST PLAN A MIT REUE" +}, +{ +"id":751, +"fortune":"DU WÄHLTEST CHAOS. WIEDER. KONSEQUENT" +}, +{ +"id":752, +"fortune":"DEIN NOTFALLPLAN BRAUCHT EINEN NOTFALLPLAN" +}, +{ +"id":753, +"fortune":"BINDUNG MACHT DIR ANGST. DIE KARTE AUCH" +}, +{ +"id":754, +"fortune":"DU BESTELLTEST DASSELBE. ABENTEUERLICH" +}, +{ +"id":755, +"fortune":"VERÄNDERUNG KOMMT. DU WIRST DICH WEHREN" +}, +{ +"id":756, +"fortune":"EINE ÜBERRASCHUNG NAHT. DU HASST SOWAS" +}, +{ +"id":757, +"fortune":"GUTE DINGE KOMMEN ZU DRITT. DEINE IM STAU" +}, +{ +"id":758, +"fortune":"DEIN HOROSKOP KÜNDIGTE. BURNOUT" +}, +{ +"id":759, +"fortune":"MERKUR IST RÜCKLÄUFIG. PRAKTISCHE AUSREDE" +}, +{ +"id":760, +"fortune":"DEIN KARTENLEGER BRAUCHTE DANACH URLAUB" +}, +{ +"id":761, +"fortune":"DIE KRISTALLKUGEL BESCHLUG. ABSICHTLICH" +}, +{ +"id":762, +"fortune":"DEIN HANDLESER BAT UM HANDSCHUHE" +}, +{ +"id":763, +"fortune":"DEINE TEEBLÄTTER BUCHSTABIERTEN NAJA" +}, +{ +"id":764, +"fortune":"DEINE VISIONSSUCHE FAND DAS SOFA" +}, +{ +"id":765, +"fortune":"DAS UNIVERSUM TESTET DICH. OFFENES BUCH" +}, +{ +"id":766, +"fortune":"DEINE MANIFESTATIONEN BRAUCHEN EINEN BÜRGEN" +}, +{ +"id":767, +"fortune":"DEINE CHAKREN ZEIGEN ZUM KÜHLSCHRANK" +}, +{ +"id":768, +"fortune":"DEIN ZENGARTEN HAT UNKRAUT. IRONISCH" +}, +{ +"id":769, +"fortune":"DEIN MANTRA IST NOCH FÜNF MINUTEN" +}, +{ +"id":770, +"fortune":"DEIN DRITTES AUGE BRAUCHT AUCH EINE BRILLE" +}, +{ +"id":771, +"fortune":"DEINE ENERGIEREINIGUNG VERGAß EINE STELLE" +}, +{ +"id":772, +"fortune":"DEIN RÄUCHERWERK LÖSTE DEN ALARM AUS. PASSEND" +}, +{ +"id":773, +"fortune":"INNERER FRIEDEN IST NAH. ANDERE TÜR" +}, +{ +"id":774, +"fortune":"EIN FREMDER LÄCHELT DICH AN. BLEIB RUHIG" +}, +{ +"id":775, +"fortune":"JEMAND DACHTE HEUTE AN DICH. KURZ" +}, +{ +"id":776, +"fortune":"DU GINGST JEMANDEM DURCH DEN KOPF. ZÜGIG" +}, +{ +"id":777, +"fortune":"EIN BEWUNDERER BEOBACHTET DICH. DEINE KATZE" +}, +{ +"id":778, +"fortune":"DU WURDEST HEUTE ERWÄHNT. KONTEXT UNKLAR" +}, +{ +"id":779, +"fortune":"DEIN NAME FIEL. DER RAUM WURDE STILL" +}, +{ +"id":780, +"fortune":"JEMAND VERMISST DICH. OHNE DEINE NUMMER" +}, +{ +"id":781, +"fortune":"DU BIST UNVERGESSLICH. VIELE VERSUCHTEN ES" +}, +{ +"id":782, +"fortune":"DEINE ABWESENHEIT FIEL AUF. POSITIV" +}, +{ +"id":783, +"fortune":"MAN SPRICHT ÜBER DICH. LASS ES SO" +}, +{ +"id":784, +"fortune":"DEIN RUF KAM VOR DIR AN. ENTSCHULDIGE DICH" +}, +{ +"id":785, +"fortune":"DU HINTERLIEßT EINDRUCK. DELLEN ZÄHLEN" +}, +{ +"id":786, +"fortune":"JEMAND ZITIERTE DICH HEUTE. FALSCH" +}, +{ +"id":787, +"fortune":"DU INSPIRIERTEST JEMANDEN. ZUM GEGENTEIL" +}, +{ +"id":788, +"fortune":"DEIN VERMÄCHTNIS IST SICHER. KEINER PRÜFT ES" +}, +{ +"id":789, +"fortune":"DIE GESCHICHTE KENNT DICH. ALS FUßNOTE" +}, +{ +"id":790, +"fortune":"DEINE BIOGRAFIE BRAUCHT NOCH HANDLUNG" +}, +{ +"id":791, +"fortune":"DEIN AUTOGRAMM IST WERTLOS. VORERST" +}, +{ +"id":792, +"fortune":"RUHM WARTET. LOKALER RUHM. SEHR LOKAL" +}, +{ +"id":793, +"fortune":"DEINE 15 MINUTEN LADEN NOCH" +}, +{ +"id":794, +"fortune":"DU FINDEST DEINE SCHLÜSSEL. WO DU SIE LIEßT" +}, +{ +"id":795, +"fortune":"DEIN HANDY IST IN DER ANDEREN HAND. WIEDER" +}, +{ +"id":796, +"fortune":"DU BETRATST DEN RAUM. DER GRUND GING RAUS" +}, +{ +"id":797, +"fortune":"DEIN GEDÄCHTNIS IST GUT. ES KURATIERT NUR" +}, +{ +"id":798, +"fortune":"DU VERGAßT WARUM DER KÜHLSCHRANK OFFEN IST" +}, +{ +"id":799, +"fortune":"DEINE MERKZETTEL BRAUCHEN EIN ARCHIV" +}, +{ +"id":800, +"fortune":"DIE MELODIE BLIEB. DIE AUFGABE NICHT" +}, +{ +"id":801, +"fortune":"DEIN EINKAUFSGEDÄCHTNIS ENDET IM LADEN" +}, +{ +"id":802, +"fortune":"DAS GESICHT KENNST DU. DER NAME FLOH. LAUF" +}, +{ +"id":803, +"fortune":"DEIN HIRN HAT AUCH TABS OFFEN. EINGEFROREN" +}, +{ +"id":804, +"fortune":"EINE TOLLE IDEE KAM UND GING. UNNOTIERT" +}, +{ +"id":805, +"fortune":"DU SCHLOSSEST DIE TÜR AB. VERMUTLICH. PRÜF" +}, +{ +"id":806, +"fortune":"DEIN GEDANKENZUG FUHR OHNE DICH AB" +}, +{ +"id":807, +"fortune":"DU GINGST ZURÜCK. DER WEG FÜHRTE ZU SNACKS" +}, +{ +"id":808, +"fortune":"DEIN PASSWORTRESET BRAUCHT EINEN RESET" +}, +{ +"id":809, +"fortune":"DAS LEBEN IST KURZ. DEINE MEETINGS NICHT" +}, +{ +"id":810, +"fortune":"DAS LEBEN GAB DIR ZITRONEN. DU REKLAMIERST" +}, +{ +"id":811, +"fortune":"DAS LEBEN IST EINE REISE. DEINE BRAUCHT NAVI" +}, +{ +"id":812, +"fortune":"DAS LEBEN PASSIERT WÄHREND DU SCROLLST" +}, +{ +"id":813, +"fortune":"DAS LEBEN HAT KEINE FERNBEDIENUNG. STEH AUF" +}, +{ +"id":814, +"fortune":"DAS LEBEN IST KEIN RENNEN. DU PARKTEST EH" +}, +{ +"id":815, +"fortune":"DAS LEBEN IST EIN GESCHENK. HEB DEN BON AUF" +}, +{ +"id":816, +"fortune":"DAS LEBEN BELOHNT TATEN. DEINS SCHRIEB MEMOS" +}, +{ +"id":817, +"fortune":"DEINE GESCHICHTE HAT LOGIKLÖCHER. STEH DAZU" +}, +{ +"id":818, +"fortune":"DEIN KAPITEL ZWEI WARTET AUF KAPITEL EINS" +}, +{ +"id":819, +"fortune":"DEIN ERZÄHLER KLINGT NEUERDINGS MÜDE" +}, +{ +"id":820, +"fortune":"DEIN CLIFFHANGER IST NUR UNENTSCHLOSSENHEIT" +}, +{ +"id":821, +"fortune":"MORGEN IST EIN NEUER TAG. GLEICHES DU" +}, +{ +"id":822, +"fortune":"GESTERN RIEF AN. ES WILL NICHTS ZURÜCK" +}, +{ +"id":823, +"fortune":"HEUTE WIRD PRODUKTIV. AB SPÄTER" +}, +{ +"id":824, +"fortune":"DIESE WOCHE HAT POTENZIAL. HATTE" +}, +{ +"id":825, +"fortune":"NÄCHSTEN MONAT STARTEST DU. ER WEIß ES" +}, +{ +"id":826, +"fortune":"DAS JAHR IST HALB UM. DEINE ZIELE UNBERÜHRT" +}, +{ +"id":827, +"fortune":"BALD IST KEIN DATUM. DU NUTZT ES SO" +}, +{ +"id":828, +"fortune":"IRGENDWANN IST DEINE LIEBLINGSFRIST" +}, +{ +"id":829, +"fortune":"DER RICHTIGE MOMENT KOMMT NIE. PRAKTISCH" +}, +{ +"id":830, +"fortune":"DEIN GELEGENHEITSFENSTER HAT JALOUSIEN" +}, +{ +"id":831, +"fortune":"GEDULD KOMMT ZU DEM DER WARTET. IRONISCH" +}, +{ +"id":832, +"fortune":"DU BIST GLEICH DRAN. DIE SCHLANGE GING WEITER" +}, +{ +"id":833, +"fortune":"DU WARTEST AUF EIN ZEICHEN. DIES IST KEINS" +}, +{ +"id":834, +"fortune":"HALT DEN GEDANKEN. GERN FÜR IMMER" +}, +{ +"id":835, +"fortune":"DEINE PAUSETASTE IST DEINE LIEBSTE" +}, +{ +"id":836, +"fortune":"DU MERKST ES DIR VOR. DAS MERKBUCH IST VOLL" +}, +{ +"id":837, +"fortune":"ES IST AUF DEINEM RADAR. DAS RADAR IST AUS" +}, +{ +"id":838, +"fortune":"DU KÜMMERST DICH DRUM. ES WARTET NICHT MEHR" +}, +{ +"id":839, +"fortune":"DER BALL LIEGT BEI DIR. ER SETZT STAUB AN" +}, +{ +"id":840, +"fortune":"DEINE NACHFRAGE BRAUCHT EINE NACHFRAGE" +}, +{ +"id":841, +"fortune":"DIES IST DEINE ERINNERUNG. DIE VIERTE" +}, +{ +"id":842, +"fortune":"DEINE ABSICHTEN SIND GUT. UND ORTSFEST" +}, +{ +"id":843, +"fortune":"MÜHE WURDE GEGEBEN. EIN RUNDUNGSFEHLER" +}, +{ +"id":844, +"fortune":"DU GABST 100 PROZENT. DEINES MINIMUMS" +}, +{ +"id":845, +"fortune":"DEIN RATEN SCHLUG DEIN RECHERCHIEREN. WIEDER" +}, +{ +"id":846, +"fortune":"FAST RICHTIG IST DEIN MARKENZEICHEN" +}, +{ +"id":847, +"fortune":"GUT GENUG GING RAUS. PERFEKT SCHMOLLT" +}, +{ +"id":848, +"fortune":"DEINE ABKÜRZUNGEN NAHMEN DEN LANGEN WEG" +}, +{ +"id":849, +"fortune":"DU IMPROVISIERTEST. DAS ERGEBNIS AUCH" +}, +{ +"id":850, +"fortune":"DEIN FREESTYLE HAT VIELFLIEGERMEILEN" +}, +{ +"id":851, +"fortune":"DETAILS ZÄHLEN. DEINE SIND IM STREIK" +}, +{ +"id":852, +"fortune":"DEIN ROHENTWURF GING IN PRODUKTION" +}, +{ +"id":853, +"fortune":"DU HAST ES ÜBERFLOGEN. MAN SIEHT ES" +}, +{ +"id":854, +"fortune":"DEIN KORREKTURLESEN ÜBERSAH AUCH DIES" +}, +{ +"id":855, +"fortune":"FAST FERTIG IST DEINE MELDEADRESSE" +}, +{ +"id":856, +"fortune":"DEINE CHECKLISTE HAT ÜBERLEBENDE" +}, +{ +"id":857, +"fortune":"FERTIG SCHLÄGT PERFEKT. VERSUCH EINS DAVON" +}, +{ +"id":858, +"fortune":"DEINE STANDARDS RUTSCHTEN. MIT ANSAGE" +}, +{ +"id":859, +"fortune":"MITTELMAß KOSTET AUCH MÜHE. GUT GEMACHT" +}, +{ +"id":860, +"fortune":"DU ÜBERTRAFST DIE ERWARTUNGEN. SIE WAREN TIEF" +}, +{ +"id":861, +"fortune":"DEIN MINIMUM HAT EINE TREUE FANBASIS" +}, +{ +"id":862, +"fortune":"DU LEGTEST DIE LATTE HÖHER. VOM BODEN AUS" +}, +{ +"id":863, +"fortune":"KONSTANZ IST ALLES. DEINE IST KONSTANT" +}, +{ +"id":864, +"fortune":"FORTSCHRITT GAB ES. SEITWÄRTS. ABER GAB ES" +}, +{ +"id":865, +"fortune":"DEINE KURVE IST STABIL. FLACH. STABIL" +}, +{ +"id":866, +"fortune":"VORWÄRTS UND AUFWÄRTS. ODER SEITLICH. LOS" +}, +{ +"id":867, +"fortune":"DU HAST GESCHWENKT. RICHTUNG WAR ZUFALL" +}, +{ +"id":868, +"fortune":"DEIN SCHWUNG NAHM SICH FREI" +}, +{ +"id":869, +"fortune":"VOLLGAS VORAUS. DEIN GAS. SO SANFT" +}, +{ +"id":870, +"fortune":"DU KAMST GEHEND INS ROLLEN. FLOTT SOGAR" +}, +{ +"id":871, +"fortune":"DEIN SPRINT WURDE EIN SPAZIERGANG. MALERISCH" +}, +{ +"id":872, +"fortune":"KLEINE SCHRITTE ZÄHLEN. DEINE SIND WINZIG" +}, +{ +"id":873, +"fortune":"DU BIST IM FLOW. EIN GEMÄCHLICHER FLOW" +}, +{ +"id":874, +"fortune":"DEINE SERIE HÄLT AN. IRGENDEINE SERIE" +}, +{ +"id":875, +"fortune":"DER SCHWUNG BAUT SICH AUF. WOANDERS" +}, +{ +"id":876, +"fortune":"DIE ZIELLINIE WANDERTE. DU AUCH. RÜCKWÄRTS" +}, +{ +"id":877, +"fortune":"DEIN MARATHON IST EINE SNACKPAUSENKETTE" +}, +{ +"id":878, +"fortune":"DU ÜBERSCHRITTEST EINE LINIE. NICHT DAS ZIEL" +}, +{ +"id":879, +"fortune":"DER SIEG IST NAH. DEFINIERE SIEG GROßZÜGIG" +}, +{ +"id":880, +"fortune":"DU GEWANNST DEN STREIT. DER RAUM WAR LEER" +}, +{ +"id":881, +"fortune":"CHAMPIONS TRAINIEREN TÄGLICH. DU SCHAUST ZU" +}, +{ +"id":882, +"fortune":"DEIN POKALREGAL EHRT DIE TEILNAHME" +}, +{ +"id":883, +"fortune":"DEIN COMEBACK KOMMT NÄCHSTE SAISON. IMMER" +}, +{ +"id":884, +"fortune":"DIE AUßENSEITERSTORY BRAUCHT EINEN VERSUCH" +}, +{ +"id":885, +"fortune":"DEINE RIVALEN FRAGEN NICHT MEHR NACH" +}, +{ +"id":886, +"fortune":"DER RUHM WARTET. ER HAT DOPPELT GEBUCHT" +}, +{ +"id":887, +"fortune":"DU SCHAFFTEST ES IN DIE HIGHLIGHTS. ALS PANNE" +}, +{ +"id":888, +"fortune":"GLÜCK IST EINE LEITER. DU HAST EINEN HOCKER" +}, +{ +"id":889, +"fortune":"DEIN CHARISMA WIRKT NUR OFFLINE" +}, +{ +"id":890, +"fortune":"DU BIST LIMITIERTE AUFLAGE. SEHR LIMITIERT" +}, +{ +"id":891, +"fortune":"NORMAL IST EINE EINSTELLUNG. DEINE IST EIGEN" +}, +{ +"id":892, +"fortune":"DU BIST NICHT FAUL. NUR IM SPARMODUS" +}, +{ +"id":893, +"fortune":"SARKASMUS IST DEINE ZWEITSPRACHE. FLIEßEND" +}, +{ +"id":894, +"fortune":"DU BIST TECHNISCH KORREKT. DIE SCHLIMMSTE ART" +}, +{ +"id":895, +"fortune":"DEINE AUSREDEN ZEIGEN ECHTES HANDWERK" +}, +{ +"id":896, +"fortune":"DU HATTEST DEINEN HÖHEPUNKT. UNGÜNSTIG FRÜH" +}, +{ +"id":897, +"fortune":"DEINE LIEBLINGSSERIE LÄUFT ZUM NEUNTEN MAL" +}, +{ +"id":898, +"fortune":"DU GIBST DEIN BESTES. DAS BESTE SCHWANKT" +}, +{ +"id":899, +"fortune":"DEIN POTENZIAL RIEF AN. KEINE NACHRICHT" +}, +{ +"id":900, +"fortune":"DU BIST BESONDERS. WIE ALLE ANDEREN" +}, +{ +"id":901, +"fortune":"DEINE ENERGIE IST HEUTE DEKORATIV" +}, +{ +"id":902, +"fortune":"DU BIST DIE HAUPTFIGUR. EINER NEBENQUEST" +}, +{ +"id":903, +"fortune":"DEIN HELDENBOGEN IST IN VORPRODUKTION" +}, +{ +"id":904, +"fortune":"DAS ORAKEL VON DELPHI HÄTTE GESCHWIEGEN" +}, +{ +"id":905, +"fortune":"EIN LÄCHELN KOSTET NICHTS. DEINS WIRKT TEUER" +}, +{ +"id":906, +"fortune":"DEINE KOMFORTSERIE KENNT DICH AUSWENDIG" +}, +{ +"id":907, +"fortune":"DU HAST RECHT. STATISTISCH IRGENDWANN MAL" +}, +{ +"id":908, +"fortune":"DEINE LOGIK IST WASSERDICHT. FAST" +}, +{ +"id":909, +"fortune":"DU ARGUMENTIERST MIT GEFÜHL. NUR DAMIT" +}, +{ +"id":910, +"fortune":"DEIN STANDPUNKT IST FEST. WIE BETON. GENAU SO" +}, +{ +"id":911, +"fortune":"DU BIST OFFEN FÜR KRITIK. THEORETISCH" +}, +{ +"id":912, +"fortune":"DEINE SELBSTIRONIE SCHÜTZT DICH. KNAPP" +}, +{ +"id":913, +"fortune":"DU NIMMST NICHTS PERSÖNLICH. AUßER ALLES" +}, +{ +"id":914, +"fortune":"DEIN DICKES FELL HAT DÜNNE STELLEN" +}, +{ +"id":915, +"fortune":"DU STEHST ÜBER DEN DINGEN. AUF ZEHENSPITZEN" +}, +{ +"id":916, +"fortune":"DEIN EGO PASST KNAPP DURCH DIE TÜR" +}, +{ +"id":917, +"fortune":"DU BIST BODENSTÄNDIG. DER BODEN WIDERSPRICHT" +}, +{ +"id":918, +"fortune":"DEINE BESCHEIDENHEIT ERWÄHNT SICH SELBST" +}, +{ +"id":919, +"fortune":"DU HÖRST AUF DEIN HERZ. ES BRAUCHT EINEN RAT" +}, +{ +"id":920, +"fortune":"DEIN GEWISSEN IST REIN. UND UNGENUTZT" +}, +{ +"id":921, +"fortune":"DU BEREUST NICHTS. DIE LISTE SAGT ANDERES" +}, +{ +"id":922, +"fortune":"DEIN STOLZ FÄHRT AUFZUG. NIE TREPPE" +}, +{ +"id":923, +"fortune":"DU BIST GEERDET. WIE EIN DRACHEN" +}, +{ +"id":924, +"fortune":"DEIN OPTIMISMUS HAT EINE RÜCKGABEFRIST" +}, +{ +"id":925, +"fortune":"DU SIEHST DAS GLAS HALB VOLL. ES IST LEER" +}, +{ +"id":926, +"fortune":"DEINE GEDULD IST GRENZENLOS. BIS MITTAG" +}, +{ +"id":927, +"fortune":"DU BIST FLEXIBEL. WIE EIN BAUKRAN" +}, +{ +"id":928, +"fortune":"DEIN HUMOR IST TROCKEN. WIE DEIN BASILIKUM" +}, +{ +"id":929, +"fortune":"DU BIST SPONTAN. NACH VORANMELDUNG" +}, +{ +"id":930, +"fortune":"DEIN FREIGEIST HAT KERNARBEITSZEITEN" +}, +{ +"id":931, +"fortune":"DU LEBST IM MOMENT. IM FALSCHEN MEIST" +}, +{ +"id":932, +"fortune":"DEIN MUT KOMMT IN SCHÜBEN. KLEINEN" +}, +{ +"id":933, +"fortune":"DIESER KEKS ENTHÄLT KEINE WEISHEIT. ZUCKER" +}, +{ +"id":934, +"fortune":"DAS GLÜCK DAS DU SUCHST IST IM ANDEREN KEKS" +}, +{ +"id":935, +"fortune":"ES IST DUNKEL IN DIESEM KEKS. UND STILL" +}, +{ +"id":936, +"fortune":"DIESER SPRUCH BLIEB ABSICHTLICH LEER" +}, +{ +"id":937, +"fortune":"KONFUZIUS SAGT NICHTS ÜBER DICH. BEWUSST" +}, +{ +"id":938, +"fortune":"DIESER SPRUCH WURDE ZURÜCKGERUFEN. DU AUCH" +}, +{ +"id":939, +"fortune":"DU LIEST DAS GLEICH LAUT VOR. UNGEFRAGT" +}, +{ +"id":940, +"fortune":"DER KEKS WUSSTE DASS DU DEN LETZTEN NIMMST" +}, +{ +"id":941, +"fortune":"MANCHE KRIEGEN WEISHEIT. DU NAHMST DESSERT" +}, +{ +"id":942, +"fortune":"DIES IST EIN KEKS. KEIN LEBENSCOACH" +}, +{ +"id":943, +"fortune":"DEINE GLÜCKSZAHLEN SIND AUSGESTIEGEN" +}, +{ +"id":944, +"fortune":"DER KEKS BEWUNDERT DEINEN OPTIMISMUS" +}, +{ +"id":945, +"fortune":"DU HAST DEN KEKS GESCHÜTTELT. ER SPÜRTE DAS" +}, +{ +"id":946, +"fortune":"FRAG SPÄTER NOCHMAL. ODER LASS ES" +}, +{ +"id":947, +"fortune":"DIESER KEKS WURDE OHNE ERWARTUNG GEBACKEN" +}, +{ +"id":948, +"fortune":"DER SPRUCHSCHREIBER HAT PAUSE. ER URTEILT" +}, +{ +"id":949, +"fortune":"HEUTE KEINE WEISHEIT. LIEFERENGPASS" +}, +{ +"id":950, +"fortune":"DEIN SPRUCH WARTET AUF FREIGABE" +}, +{ +"id":951, +"fortune":"DIESE NACHRICHT WIRD SICH SELBST ENTTÄUSCHEN" +}, +{ +"id":952, +"fortune":"DER KEKS BRÖCKELT. WIE DEINE PLÄNE" +}, +{ +"id":953, +"fortune":"DU ERWARTETEST MEHR VON EINEM KEKS. NOTIERT" +}, +{ +"id":954, +"fortune":"SPRUCH NICHT GEFUNDEN. ANDERES LOKAL" +}, +{ +"id":955, +"fortune":"DIESER KEKS KENNT DEINE BESTELLHISTORIE" +}, +{ +"id":956, +"fortune":"DER LETZTE KEKS SAGT IMMER DIE WAHRHEIT" +}, +{ +"id":957, +"fortune":"DEIN SPRUCH HAT ZU WENIG ZEICHEN. ZUM GLÜCK" +}, +{ +"id":958, +"fortune":"EIN WEISER SAGTE EINST NICHTS. PROBIER DAS" +}, +{ +"id":959, +"fortune":"DIESER SPRUCH IST PRÄZISE. DETAILS GESCHWÄRZT" +}, +{ +"id":960, +"fortune":"DU HÄLTST DEN SCHLÜSSEL ZUM GLÜCK. FINDE IHN" +}, +{ +"id":961, +"fortune":"DEIN SPRUCH WIRD NOCH GESCHRIEBEN. LANGSAM" +}, +{ +"id":962, +"fortune":"DEIN SPLITFLAP VERDIENTE BESSERE SPRÜCHE" +}, +{ +"id":963, +"fortune":"JEDE KLAPPE DREHTE SICH FÜR DIESE WEISHEIT" +}, +{ +"id":964, +"fortune":"DU BAUTEST EINE ANZEIGE DAFÜR. IMMERHIN" +}, +{ +"id":965, +"fortune":"45 ZEICHEN REICHEN FÜR DIESE WAHRHEIT KNAPP" +}, +{ +"id":966, +"fortune":"DIESE ANZEIGE VERDIENT LÄNGERE WEISHEITEN" +}, +{ +"id":967, +"fortune":"DEINE ANZEIGE RATTERTE EXTRA FÜR DICH" +}, +{ +"id":968, +"fortune":"GEDULD. DIE KLAPPEN GEBEN IHR BESTES" +}, +{ +"id":969, +"fortune":"DIESER TEXT KOSTETE 45 KLAPPEN. WOFÜR" +}, +{ +"id":970, +"fortune":"DEIN PROJEKT ZEIGT NUN FREMDE MEINUNGEN" +}, +{ +"id":971, +"fortune":"DIE ANZEIGE IST FERTIG. DIE SPRÜCHE NIE" +}, +{ +"id":972, +"fortune":"EIN FREMDER LOBT DICH BALD. PRÜF SEIN MOTIV" +}, +{ +"id":973, +"fortune":"DEIN BAUCHGEFÜHL MELDET SICH. MEIST HUNGER" +}, +{ +"id":974, +"fortune":"DU TRIFFST HEUTE EINE GUTE WAHL. EINE" +}, +{ +"id":975, +"fortune":"DEIN VORSATZ LEBT NOCH. IN GEFANGENSCHAFT" +}, +{ +"id":976, +"fortune":"DU BEKOMMST WAS DU VERDIENST. VIEL SPAß" +}, +{ +"id":977, +"fortune":"DEINE ZUKUNFT DANKT DIR. SARKASTISCH" +}, +{ +"id":978, +"fortune":"DU WIRST HEUTE UNTERSCHÄTZT. ZU RECHT" +}, +{ +"id":979, +"fortune":"EINE TÜR SCHLIEßT SICH. DEINE KLEMMT NUR" +}, +{ +"id":980, +"fortune":"DEIN WEG IST DAS ZIEL. DU STEHST TROTZDEM" +}, +{ +"id":981, +"fortune":"DAS SCHICKSAL LACHT. NICHT MIT DIR" +}, +{ +"id":982, +"fortune":"DEIN GLÜCKSKEKS HAT MEHR BISS ALS DU" +}, +{ +"id":983, +"fortune":"MAN ERNTET WAS MAN SÄT. DU SÄTEST NICHTS" +}, +{ +"id":984, +"fortune":"DEINE STERNSTUNDE FIEL AUS. TECHNISCHE GRÜNDE" +}, +{ +"id":985, +"fortune":"DU BIST AUF DEM RECHTEN WEG. FALSCHE RICHTUNG" +}, +{ +"id":986, +"fortune":"DAS UNIVERSUM SCHULDET DIR NICHTS. DU MAHNST" +}, +{ +"id":987, +"fortune":"DEIN KARMAKONTO IST ÜBERZOGEN. ZINSEN LAUFEN" +}, +{ +"id":988, +"fortune":"GEDULD ZAHLT SICH AUS. DEINE ZAHLT NIE" +}, +{ +"id":989, +"fortune":"DEIN STERN LEUCHTET. AUF SPARFLAMME" +}, +{ +"id":990, +"fortune":"HEUTE GEHÖRT DIR DIE WELT. BIS MITTAG" +}, +{ +"id":991, +"fortune":"MORGEN WIRST DU ANDERS SEIN. KAUM ABER ANDERS" +}, +{ +"id":992, +"fortune":"DEIN NAVI GLAUBT NOCH AN DICH. ALS EINZIGES" +}, +{ +"id":993, +"fortune":"DU BIST EIN VORBILD. ALS ABSCHRECKUNG ZÄHLT" +}, +{ +"id":994, +"fortune":"DEINE ZIMMERTEMPERATUR MEINUNG IST NOTIERT" +}, +{ +"id":995, +"fortune":"HEUT LÄUFT ALLES GLATT. AUF EIS GENAUER" +}, +{ +"id":996, +"fortune":"DEIN GLÜCKSBRINGER BAT UM VERSETZUNG" +}, +{ +"id":997, +"fortune":"DIE STILLE NACH DEINEM WITZ SPRICHT BÄNDE" +}, +{ +"id":998, +"fortune":"DEIN PLAN IST NARRENSICHER. FAST ÜBERALL" +}, +{ +"id":999, +"fortune":"DU DENKST LAUT. LEISER WÄRE AUCH SCHÖN" +}, +{ +"id":1000, +"fortune":"ENDE GUT ALLES GUT. DEINS IST OFFEN" +} +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_en-au.json b/apps/sarcastic-fortune-cookies/fortunes_en-au.json new file mode 100644 index 0000000..294fd42 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_en-au.json @@ -0,0 +1,4066 @@ +[ + { + "id": 1, + "fortune": "EVERYTHING HAPPENS. RARELY FOR A REASON" + }, + { + "id": 2, + "fortune": "GOOD LUCK IS COMING. IT WALKS SLOWLY" + }, + { + "id": 3, + "fortune": "THE UNIVERSE HAS A PLAN. A MODEST ONE" + }, + { + "id": 4, + "fortune": "YOUR DESTINY CALLED. IT RESCHEDULED" + }, + { + "id": 5, + "fortune": "FATE HAS PLANS FOR YOU. BACKUP PLANS" + }, + { + "id": 6, + "fortune": "THE STARS ALIGNED. THEN THEY SAW YOU" + }, + { + "id": 7, + "fortune": "LUCK FAVOURS THE BOLD. YOU CAN WATCH" + }, + { + "id": 8, + "fortune": "YOUR SHIP IS COMING IN. IT IS A CANOE" + }, + { + "id": 9, + "fortune": "TRUST THE PROCESS. IT DOES NOT TRUST YOU" + }, + { + "id": 10, + "fortune": "A SIGN IS COMING. IT SAYS YIELD" + }, + { + "id": 11, + "fortune": "YOUR LUCKY STAR IS IN ANOTHER GALAXY" + }, + { + "id": 12, + "fortune": "KARMA IS REAL. THAT EXPLAINS A LOT" + }, + { + "id": 13, + "fortune": "THE FUTURE IS BRIGHT. WEAR SUNSCREEN" + }, + { + "id": 14, + "fortune": "DESTINY AWAITS. IT BROUGHT A BOOK" + }, + { + "id": 15, + "fortune": "MIRACLES HAPPEN DAILY. ELSEWHERE MOSTLY" + }, + { + "id": 16, + "fortune": "YOUR MOMENT IS COMING. IT IS IN TRAFFIC" + }, + { + "id": 17, + "fortune": "FORTUNE KNOCKED ONCE. YOU WERE OUT" + }, + { + "id": 18, + "fortune": "THE TIDE IS TURNING. GLACIALLY" + }, + { + "id": 19, + "fortune": "BIG THINGS ARE COMING. LOWER THE BAR" + }, + { + "id": 20, + "fortune": "OPPORTUNITY IS NEAR. YOU TWO KEEP MISSING" + }, + { + "id": 21, + "fortune": "THE COSMOS HEARD YOU. YOU ARE IN THE QUEUE" + }, + { + "id": 22, + "fortune": "YOUR STARS ARE FINE. YOUR CHOICES ARENT" + }, + { + "id": 23, + "fortune": "WISH ON A STAR. THE STAR MARKED IT SPAM" + }, + { + "id": 24, + "fortune": "GOOD THINGS TAKE TIME. YOURS TAKE DECADES" + }, + { + "id": 25, + "fortune": "A WINDFALL NEARS. DRESS IN LAYERS" + }, + { + "id": 26, + "fortune": "THE SIGNS WERE THERE. READING IS OPTIONAL" + }, + { + "id": 27, + "fortune": "YOU ARE ONE IN A MILLION. SO ARE THOUSANDS" + }, + { + "id": 28, + "fortune": "THE BEST IS YET TO COME. NO RUSH APPARENTLY" + }, + { + "id": 29, + "fortune": "YOUR AURA IS RADIANT. IT WORKS OVERTIME" + }, + { + "id": 30, + "fortune": "LADY LUCK SMILED. POLITELY. AT A STRANGER" + }, + { + "id": 31, + "fortune": "YOUR PRAYERS WERE HEARD. AND FILED" + }, + { + "id": 32, + "fortune": "ABUNDANCE FLOWS TO YOU. UPSTREAM SADLY" + }, + { + "id": 33, + "fortune": "FORTUNES WHEEL TURNS. YOU ARE THE HAMSTER" + }, + { + "id": 34, + "fortune": "EVERY CLOUD HAS A LINING. YOURS IS DAMP" + }, + { + "id": 35, + "fortune": "SERENDIPITY IS ASKING AROUND ABOUT YOU" + }, + { + "id": 36, + "fortune": "A LUCKY BREAK NEARS. BREAK HAS TWO MEANINGS" + }, + { + "id": 37, + "fortune": "THE ORACLE SPOKE. MOSTLY IT SIGHED" + }, + { + "id": 38, + "fortune": "YOUR HOROSCOPE LOOKS GREAT. IT IS FICTION" + }, + { + "id": 39, + "fortune": "COSMIC JUSTICE EXISTS. SETTLE OUT OF COURT" + }, + { + "id": 40, + "fortune": "LIGHTNING WONT STRIKE TWICE. YOU MIGHT" + }, + { + "id": 41, + "fortune": "FATE REWARDS PATIENCE. INVOICE PENDING" + }, + { + "id": 42, + "fortune": "THE MOON SAW YOUR FRESH START. AGAIN" + }, + { + "id": 43, + "fortune": "YOUR SPIRIT GUIDE REQUESTED A TRANSFER" + }, + { + "id": 44, + "fortune": "ANGELS WATCH OVER YOU. TAKING NOTES" + }, + { + "id": 45, + "fortune": "BELIEVE AND RECEIVE. RECEIPTS VARY" + }, + { + "id": 46, + "fortune": "YOUR GOLDEN ERA NEARS. GOLD PLATED" + }, + { + "id": 47, + "fortune": "WHAT IS MEANT FOR YOU IS NOT HURRYING" + }, + { + "id": 48, + "fortune": "THE UNIVERSE WINKED. OR HAD AN EYE ISSUE" + }, + { + "id": 49, + "fortune": "YOUR LUCK IS CHANGING. DIRECTION UNCLEAR" + }, + { + "id": 50, + "fortune": "PROVIDENCE PROVIDES. IT CHECKS RECEIPTS" + }, + { + "id": 51, + "fortune": "SUCCESS IS NEAR. SO IS THE SNOOZE BUTTON" + }, + { + "id": 52, + "fortune": "HARD WORK PAYS OFF. IN EXPOSURE" + }, + { + "id": 53, + "fortune": "YOUR POTENTIAL IS LIMITLESS. AND UNUSED" + }, + { + "id": 54, + "fortune": "DREAM BIG. SET AN ALARM THOUGH" + }, + { + "id": 55, + "fortune": "THE EARLY BIRD LEFT WITHOUT YOU" + }, + { + "id": 56, + "fortune": "YOUR BIG BREAK NEARS. DO NOT BREAK IT" + }, + { + "id": 57, + "fortune": "ROME WASNT BUILT IN A DAY. YOURS ISNT STARTED" + }, + { + "id": 58, + "fortune": "YOUR TALENTS WILL BE FOUND. WITH A WARRANT" + }, + { + "id": 59, + "fortune": "AIM FOR THE STARS. MIND THE CEILING" + }, + { + "id": 60, + "fortune": "WINNERS NEVER QUIT. YOU FOUND COASTING" + }, + { + "id": 61, + "fortune": "YOUR IDEAS ARE AHEAD. YOUR DEADLINES BEHIND" + }, + { + "id": 62, + "fortune": "EXCELLENCE IS A HABIT. SO IS YOURS" + }, + { + "id": 63, + "fortune": "YOUR WORK SPEAKS. IT REQUESTED A LAWYER" + }, + { + "id": 64, + "fortune": "THE TOP IS LONELY. YOU SOLVED THAT PROBLEM" + }, + { + "id": 65, + "fortune": "A PROMOTION NEARS. SOMEONE ELSES" + }, + { + "id": 66, + "fortune": "YOUR RESUME IMPRESSES FICTION FANS" + }, + { + "id": 67, + "fortune": "YOUR BEST WORK IS AHEAD. IT IS VERY FAST" + }, + { + "id": 68, + "fortune": "THAT MEETING COULD HAVE BEEN AN EMAIL" + }, + { + "id": 69, + "fortune": "YOUR INBOX IS NOT YOUR ENEMY. JUST A WITNESS" + }, + { + "id": 70, + "fortune": "DEADLINES FEAR NOTHING. YOU WALK PAST THEM" + }, + { + "id": 71, + "fortune": "YOUR FIVE YEAR PLAN IS FIVE YEARS OLD" + }, + { + "id": 72, + "fortune": "SLOW AND STEADY WINS. YOU NAILED SLOW" + }, + { + "id": 73, + "fortune": "YOUR CALENDAR IS FULL. OF BUFFERS" + }, + { + "id": 74, + "fortune": "YOUR TEAM DREAMS TOO. OF TRANSFERS" + }, + { + "id": 75, + "fortune": "THE OCCASION LOWERED ITSELF TO MEET YOU" + }, + { + "id": 76, + "fortune": "SUCCESS LEAVES CLUES. YOU PREFER MYSTERY" + }, + { + "id": 77, + "fortune": "YOUR COMFORT ZONE NEEDS ITS OWN POSTCODE" + }, + { + "id": 78, + "fortune": "QUALITY OVER QUANTITY. YOU DECLINED BOTH" + }, + { + "id": 79, + "fortune": "YOUR INSTINCTS ARE SHARP. FACTS ON SABBATICAL" + }, + { + "id": 80, + "fortune": "YOU WORK WELL UNDER PRESSURE. IT DISAGREES" + }, + { + "id": 81, + "fortune": "MASTERY TAKES 10000 HOURS. YOU HAVE 40" + }, + { + "id": 82, + "fortune": "YOUR DESK PLANT BELIEVED IN YOU. AND WATER" + }, + { + "id": 83, + "fortune": "THE PRINTER KNOWS YOU ARE IN A HURRY" + }, + { + "id": 84, + "fortune": "YOUR LEGACY IS UNDER CONSTRUCTION. STILL" + }, + { + "id": 85, + "fortune": "AN AWARD AWAITS. PARTICIPATION COUNTS" + }, + { + "id": 86, + "fortune": "YOUR CAN DO ATTITUDE MET YOUR DID NOT RECORD" + }, + { + "id": 87, + "fortune": "NETWORKING OPENS DOORS. TRY KNOCKING TOO" + }, + { + "id": 88, + "fortune": "YOU LEAD BY EXAMPLE. HR WANTS A NEW ONE" + }, + { + "id": 89, + "fortune": "YOUR SIDE HUSTLE JOINED THE OTHERS. RESTING" + }, + { + "id": 90, + "fortune": "GENIUS IS 1 PERCENT WORK. YOU STOPPED THERE" + }, + { + "id": 91, + "fortune": "YOUR OUT OF OFFICE REPLY IS YOUR BEST WORK" + }, + { + "id": 92, + "fortune": "FAILURE IS A STEPPING STONE. NICE STAIRCASE" + }, + { + "id": 93, + "fortune": "YOU ARE IRREPLACEABLE. THE POSTING IS DRAFTED" + }, + { + "id": 94, + "fortune": "YOUR PERFORMANCE REVIEW NEARS. REHEARSE" + }, + { + "id": 95, + "fortune": "EFFICIENCY IS YOUR MIDDLE NAME. LEGALLY ONLY" + }, + { + "id": 96, + "fortune": "YOU WILL LAND ON YOUR FEET. LANDING DELAYED" + }, + { + "id": 97, + "fortune": "THE SUMMIT IS CLOSE. SO IS BASE CAMP" + }, + { + "id": 98, + "fortune": "YOUR AMBITION WOKE UP. YOUR ALARM DID NOT" + }, + { + "id": 99, + "fortune": "BE YOURSELF. EVERYONE ELSE WAS ALARMED" + }, + { + "id": 100, + "fortune": "KNOW THYSELF. A BRIEF INTRO MAY HELP" + }, + { + "id": 101, + "fortune": "YOUR GLOW UP IS COMING. NOTIFY THE GRID" + }, + { + "id": 102, + "fortune": "NEW YEAR NEW YOU. THE OLD YOU LEFT NOTES" + }, + { + "id": 103, + "fortune": "YOU ARE ENOUGH. THE BAR WAS ADJUSTABLE" + }, + { + "id": 104, + "fortune": "YOUR INNER PEACE SAW YOUR SCHEDULE. IT LEFT" + }, + { + "id": 105, + "fortune": "GROWTH TAKES TIME. YOURS FILED AN EXTENSION" + }, + { + "id": 106, + "fortune": "YOU ARE A WORK IN PROGRESS. MOSTLY WORK" + }, + { + "id": 107, + "fortune": "SELF AWARENESS IS A GIFT. YOURS SHIPPED" + }, + { + "id": 108, + "fortune": "HEALING IS NOT LINEAR. YOURS IS A SCRIBBLE" + }, + { + "id": 109, + "fortune": "YOUR BEST SELF IS EMERGING. IT HIT SNOOZE" + }, + { + "id": 110, + "fortune": "SELF CARE MATTERS. STREAMING IS NOT A SPA" + }, + { + "id": 111, + "fortune": "YOUR BOUNDARIES ARE HEALTHY. AND UNTESTED" + }, + { + "id": 112, + "fortune": "GRATITUDE HELPS. TRY IT ON PEOPLE" + }, + { + "id": 113, + "fortune": "YOU FORGIVE EASILY. YOURSELF ESPECIALLY" + }, + { + "id": 114, + "fortune": "YOUR HABITS DEFINE YOU. OUR CONDOLENCES" + }, + { + "id": 115, + "fortune": "SMALL STEPS COUNT. EVEN TO THE FRIDGE" + }, + { + "id": 116, + "fortune": "YOUR INTUITION IS POWERFUL. AND WRONG" + }, + { + "id": 117, + "fortune": "MINDFULNESS HELPS. YOUR PHONE DISAGREES" + }, + { + "id": 118, + "fortune": "YOU LET GO OF THE PAST. IT HAS YOUR ADDRESS" + }, + { + "id": 119, + "fortune": "YOUR MORNING ROUTINE IS SACRED. ALL 4 MINUTES" + }, + { + "id": 120, + "fortune": "YOU ARE LEARNING TO SAY NO. TO VEGETABLES" + }, + { + "id": 121, + "fortune": "YOUR WILLPOWER LIFTS ALMOST A WHOLE BIKKIE" + }, + { + "id": 122, + "fortune": "YOUR PURPOSE EXISTS. IT STAYS ANONYMOUS" + }, + { + "id": 123, + "fortune": "YOU EMBRACE CHANGE. MOSTLY COUCH CHANGE" + }, + { + "id": 124, + "fortune": "YOUR JOURNAL IS RAW AND HONEST. BOTH PAGES" + }, + { + "id": 125, + "fortune": "YOU LIVE YOUR TRUTH. FACT CHECK PENDING" + }, + { + "id": 126, + "fortune": "YOUR INNER CRITIC ONLY SIGHS NOW" + }, + { + "id": 127, + "fortune": "YOUR TRANSFORMATION NEEDED LABELLED PHOTOS" + }, + { + "id": 128, + "fortune": "YOUR GOALS ARE IN SIGHT. NICE BINOCULARS" + }, + { + "id": 129, + "fortune": "YOUR NEW HABITS LOOK FAMILIAR. SUSPICIOUSLY" + }, + { + "id": 130, + "fortune": "YOUR ENERGY IS MAGNETIC. TO OBLIGATIONS" + }, + { + "id": 131, + "fortune": "YOUR WALLS CAME DOWN. THE MOAT EXPANDED" + }, + { + "id": 132, + "fortune": "YOU CELEBRATE SMALL WINS. DAILY. SOMEONE MUST" + }, + { + "id": 133, + "fortune": "YOUR EVOLUTION PUZZLES DARWIN" + }, + { + "id": 134, + "fortune": "YOU PUT YOURSELF FIRST. THE LINE WAS SHORT" + }, + { + "id": 135, + "fortune": "YOUR REINVENTION TOUR CONTINUES. SAME SETLIST" + }, + { + "id": 136, + "fortune": "YOU ARE PRESENT. PHYSICALLY AT LEAST" + }, + { + "id": 137, + "fortune": "YOUR FRESH START STARTS MONDAY. A FUTURE ONE" + }, + { + "id": 138, + "fortune": "YOUR VISION BOARD IS STUNNING. AND RETIRED" + }, + { + "id": 139, + "fortune": "YOU HONOUR YOUR FEELINGS. AT FULL VOLUME" + }, + { + "id": 140, + "fortune": "YOUR CALM IS REAL. YOU STOPPED CHECKING EMAIL" + }, + { + "id": 141, + "fortune": "YOUR STANDARDS ARE RISING. FROM SEA LEVEL" + }, + { + "id": 142, + "fortune": "YOU ARE BLOOMING. LATE SEASON. STILL COUNTS" + }, + { + "id": 143, + "fortune": "YOUR DISCIPLINE IS THE STUFF OF LEGEND" + }, + { + "id": 144, + "fortune": "YOUR AFFIRMATIONS WORK. ON THE CEILING" + }, + { + "id": 145, + "fortune": "TRUE LOVE AWAITS. IT IS RUNNING LATE TOO" + }, + { + "id": 146, + "fortune": "YOUR SOULMATE EXISTS. COVERAGE MAY VARY" + }, + { + "id": 147, + "fortune": "ROMANCE IS IN THE AIR. SO IS POLLEN" + }, + { + "id": 148, + "fortune": "CUPID HAS YOUR ADDRESS. HE DROVE PAST TWICE" + }, + { + "id": 149, + "fortune": "YOUR HEART KNOWS THE WAY. YOUR TEXTS DONT" + }, + { + "id": 150, + "fortune": "LOVE IS BLIND. YOURS ALSO FORGETS" + }, + { + "id": 151, + "fortune": "YOUR EX THINKS OF YOU. AS A LESSON" + }, + { + "id": 152, + "fortune": "YOUR FLIRTING IS SUBTLE. UNDETECTABLE EVEN" + }, + { + "id": 153, + "fortune": "YOUR TYPE IS CONSISTENT. THAT IS THE PROBLEM" + }, + { + "id": 154, + "fortune": "SOMEONE ADMIRES YOU FROM AFAR. STAY THERE" + }, + { + "id": 155, + "fortune": "YOUR GREEN FLAGS ARE LOVELY. AND OUTNUMBERED" + }, + { + "id": 156, + "fortune": "LOVE CONQUERS ALL. IT REQUESTED BACKUP" + }, + { + "id": 157, + "fortune": "HEART ON YOUR SLEEVE. DRY CLEAN BOTH" + }, + { + "id": 158, + "fortune": "A TEXT FROM THE PAST NEARS. DO NOT REPLY" + }, + { + "id": 159, + "fortune": "YOUR CRUSH KNOWS YOU EXIST. AS A CONCEPT" + }, + { + "id": 160, + "fortune": "YOU LOVE DEEPLY. BRIEFLY. BUT DEEPLY" + }, + { + "id": 161, + "fortune": "YOUR HEART IS OPEN. SO IS YOUR TAB" + }, + { + "id": 162, + "fortune": "SPARKS WILL FLY. CHECK THE SMOKE ALARM" + }, + { + "id": 163, + "fortune": "YOU ARE READY FOR COMMITMENT. TO A COUCH" + }, + { + "id": 164, + "fortune": "YOUR MEET CUTE NEARS. A MEET ADEQUATE" + }, + { + "id": 165, + "fortune": "YOUR HEART HEALED. IT ADDED SECURITY" + }, + { + "id": 166, + "fortune": "LOVE IS PATIENT. IT HAD PRACTICE WITH YOU" + }, + { + "id": 167, + "fortune": "YOUR REBOUND GAME BEATS THE ORIGINAL" + }, + { + "id": 168, + "fortune": "YOUR HONEYMOON PHASE LASTED 11 DAYS" + }, + { + "id": 169, + "fortune": "YOUR PET IS YOUR BEST RELATIONSHIP. IT AGREES" + }, + { + "id": 170, + "fortune": "YOUR VOWS WILL MAKE PEOPLE CRY. THE GRAMMAR" + }, + { + "id": 171, + "fortune": "YOU ARE A CATCH. CATCH AND RELEASE EXISTS" + }, + { + "id": 172, + "fortune": "ABSENCE MAKES HEARTS FONDER. KEEP TESTING" + }, + { + "id": 173, + "fortune": "YOUR PERFECT MATCH EXISTS. THE APP GAVE UP" + }, + { + "id": 174, + "fortune": "YOUR RED FLAGS ARE MAROON NOW. PROGRESS" + }, + { + "id": 175, + "fortune": "LOVE AT FIRST SIGHT IS REAL. GET GLASSES" + }, + { + "id": 176, + "fortune": "YOUR HEART WANTS THINGS. SEE A SPECIALIST" + }, + { + "id": 177, + "fortune": "SOMEONE THINKS YOU ARE PERFECT. FROM AFAR" + }, + { + "id": 178, + "fortune": "YOU BELIEVE IN SECOND CHANCES. AND FIFTHS" + }, + { + "id": 179, + "fortune": "YOUR BREAKUP PLAYLIST GETS HEAVY USE" + }, + { + "id": 180, + "fortune": "YOU ARE WORTH THE WAIT. THE WAIT CONTINUES" + }, + { + "id": 181, + "fortune": "ROMANCE IS NOT DEAD. YOURS IS RESTING" + }, + { + "id": 182, + "fortune": "YOUR IN LAWS WILL ADORE YOU. EVENTUALLY" + }, + { + "id": 183, + "fortune": "YOUR DATING BIO IS HONEST. SELECTIVELY" + }, + { + "id": 184, + "fortune": "YOUR HUGS ARE GREAT. AND RARE. LIKE ECLIPSES" + }, + { + "id": 185, + "fortune": "SOMEONE DREAMS OF YOUR COOKING. IN FEAR" + }, + { + "id": 186, + "fortune": "YOUR CHARM OPENS DOORS. PUSH DONT PULL" + }, + { + "id": 187, + "fortune": "YOUR STANDARDS MET YOUR CHOICES. AWKWARD" + }, + { + "id": 188, + "fortune": "YOU WILL BE SWEPT AWAY. STRETCH FIRST" + }, + { + "id": 189, + "fortune": "INTIMACY MEANS BEING SEEN. YOU NEGOTIATED" + }, + { + "id": 190, + "fortune": "YOUR LOVE STORY WILL BE TOLD. AS A WARNING" + }, + { + "id": 191, + "fortune": "THE SPARK IS STILL THERE. SEND A SEARCH PARTY" + }, + { + "id": 192, + "fortune": "YOUR ANNIVERSARY NEARS. THIS IS THE REMINDER" + }, + { + "id": 193, + "fortune": "LOVE YOURSELF FIRST. YOU MASTERED THAT PART" + }, + { + "id": 194, + "fortune": "YOUR HEART SKIPPED A BEAT. SEE A DOCTOR" + }, + { + "id": 195, + "fortune": "YOU BRING OUT THE BEST. AS PEOPLE LEAVE" + }, + { + "id": 196, + "fortune": "YOU NEVER SETTLE. HENCE THE FOLDING CHAIRS" + }, + { + "id": 197, + "fortune": "YOUR FUTURE PARTNER IS TRAINING. UNKNOWINGLY" + }, + { + "id": 198, + "fortune": "YOU GET GREAT ADVICE. FOLLOWING IT IS NEW" + }, + { + "id": 199, + "fortune": "YOUR HEART IS A FORTRESS. GIFT SHOP OPEN" + }, + { + "id": 200, + "fortune": "YOUR MATES VALUE YOUR HONESTY. FROM AFAR" + }, + { + "id": 201, + "fortune": "A MATE WILL CALL SOON. THEY NEED A TRUCK" + }, + { + "id": 202, + "fortune": "YOU ARE THE GLUE. GLUE IS RARELY THANKED" + }, + { + "id": 203, + "fortune": "THE GROUP CHAT ENJOYS YOUR SILENCE" + }, + { + "id": 204, + "fortune": "TRUE MATES ARE RARE. YOURS ARE HIDING" + }, + { + "id": 205, + "fortune": "YOUR LOYALTY IS UNMATCHED. YOUR TIMING ISNT" + }, + { + "id": 206, + "fortune": "A GATHERING BRINGS JOY. LEAVING BRINGS MORE" + }, + { + "id": 207, + "fortune": "YOU ARE THE FUN ONE. SELF REPORTED" + }, + { + "id": 208, + "fortune": "AN OLD MATE RESURFACES. THEY ARE MOVING" + }, + { + "id": 209, + "fortune": "YOUR ADVICE IS APPRECIATED. NOT REQUESTED" + }, + { + "id": 210, + "fortune": "YOU LIGHT UP ROOMS. SOME WANT DIMMERS" + }, + { + "id": 211, + "fortune": "YOUR BIRTHDAY WILL BE REMEMBERED. LATE" + }, + { + "id": 212, + "fortune": "YOUR STORIES IMPROVE YEARLY. ACCURACY DROPS" + }, + { + "id": 213, + "fortune": "PEOPLE GRAVITATE TO YOU. GRAVITY PULLS DOWN" + }, + { + "id": 214, + "fortune": "YOU ALWAYS KNOW WHAT TO SAY. TIMING EXTRA" + }, + { + "id": 215, + "fortune": "MATES COME AND GO. YOURS EXCEL AT GO" + }, + { + "id": 216, + "fortune": "YOUR SOCIAL CALENDAR IS FULL. OF MAYBES" + }, + { + "id": 217, + "fortune": "YOU ARE A PEOPLE PERSON. UNVERIFIED" + }, + { + "id": 218, + "fortune": "YOUR INSIDE JOKES ARE NOW SOLO ACTS" + }, + { + "id": 219, + "fortune": "YOUR HOSTING IMPROVES. THE FIRE DEPT AGREES" + }, + { + "id": 220, + "fortune": "YOU BRING PEOPLE TOGETHER. TO DISCUSS YOU" + }, + { + "id": 221, + "fortune": "YOUR GENEROSITY HAS OFFICE HOURS" + }, + { + "id": 222, + "fortune": "YOU NEVER FORGET A FACE. NAMES OPTED OUT" + }, + { + "id": 223, + "fortune": "YOUR PEP TALKS REQUIRE FOLLOW UP CARE" + }, + { + "id": 224, + "fortune": "YOU SHOW UP WHEN IT MATTERS. TO YOU" + }, + { + "id": 225, + "fortune": "YOUR GOING AWAY PARTIES DRAW CROWDS" + }, + { + "id": 226, + "fortune": "PEOPLE CONFIDE IN YOU. AND THEN IN OTHERS" + }, + { + "id": 227, + "fortune": "YOUR HONESTY IS REFRESHING. LIKE ICE WATER" + }, + { + "id": 228, + "fortune": "YOU NEVER HOLD GRUDGES. YOU ARCHIVE THEM" + }, + { + "id": 229, + "fortune": "YOUR MEMES ARRIVE AT DAWN. UNREQUESTED" + }, + { + "id": 230, + "fortune": "YOU ARE A SHOULDER TO CRY ON. BY APPOINTMENT" + }, + { + "id": 231, + "fortune": "YOUR CANCELLED DINNER PARTIES ARE LEGEND" + }, + { + "id": 232, + "fortune": "YOU KEEP EVERYONE GROUNDED. LIKE FOG" + }, + { + "id": 233, + "fortune": "YOUR ENTHUSIASM IS INFECTIOUS. MASKS EXIST" + }, + { + "id": 234, + "fortune": "A MATE WANTS YOUR HONEST OPINION. A TRAP" + }, + { + "id": 235, + "fortune": "YOU SPLIT BILLS FAIRLY. YOUR MATH DIFFERS" + }, + { + "id": 236, + "fortune": "YOUR PRESENCE IS A GIFT. REGIFTING HAPPENS" + }, + { + "id": 237, + "fortune": "YOUR COMPETITIVENESS RETIRED THE GAMES" + }, + { + "id": 238, + "fortune": "YOUR SURPRISE PARTIES SURPRISE NO ONE" + }, + { + "id": 239, + "fortune": "PEOPLE FEEL COMFORTABLE AROUND YOU. TO LEAVE" + }, + { + "id": 240, + "fortune": "YOU SAY WHAT EVERYONE THINKS. AT FUNERALS" + }, + { + "id": 241, + "fortune": "YOUR HOLIDAY LETTER HAS A READERSHIP" + }, + { + "id": 242, + "fortune": "YOUR APOLOGIES ARE HEARTFELT. AND FREQUENT" + }, + { + "id": 243, + "fortune": "YOU ARE THE KEEPER OF GROUP HISTORY. REVISED" + }, + { + "id": 244, + "fortune": "YOU NEVER MISS A CHANCE TO HELP. OR SAY SO" + }, + { + "id": 245, + "fortune": "YOUR DIRECTNESS IS CHARMING. AGREED WORD" + }, + { + "id": 246, + "fortune": "YOU ARE FASHIONABLY LATE. MINUS THE FASHION" + }, + { + "id": 247, + "fortune": "PEOPLE SEEK YOUR APPROVAL. TO END THE CHAT" + }, + { + "id": 248, + "fortune": "YOU NEVER GOSSIP. YOU BRIEF THE ABSENT" + }, + { + "id": 249, + "fortune": "YOUR INVITES SAY CASUAL. YOUR TEXTS DONT" + }, + { + "id": 250, + "fortune": "AN OLD MATE REMEMBERS YOU. FROM AFAR" + }, + { + "id": 251, + "fortune": "YOU NEVER LOSE ARGUMENTS. YOU RELOCATE THEM" + }, + { + "id": 252, + "fortune": "YOUR SUPPORT IS UNCONDITIONAL. SEE TERMS" + }, + { + "id": 253, + "fortune": "WEALTH IS COMING. IT HAS YOUR OLD ADDRESS" + }, + { + "id": 254, + "fortune": "MONEY FLOWS TO YOU. THROUGH YOU. GONE" + }, + { + "id": 255, + "fortune": "YOUR BUDGET IS ART. ABSTRACT ART" + }, + { + "id": 256, + "fortune": "SAVE FOR A RAINY DAY. MONSOONS FORECAST" + }, + { + "id": 257, + "fortune": "YOUR CREDIT SCORE IS A THRILLER" + }, + { + "id": 258, + "fortune": "YOUR SAVINGS GROW. CHARACTER MOSTLY" + }, + { + "id": 259, + "fortune": "MONEY TALKS. YOURS SAYS GOODBYE" + }, + { + "id": 260, + "fortune": "YOUR RETIREMENT PLAN IS A LOTTERY TICKET" + }, + { + "id": 261, + "fortune": "YOU HAVE EXPENSIVE TASTE. AND A BUDGET" + }, + { + "id": 262, + "fortune": "COMPOUND INTEREST IS MAGIC. YOU CHOSE DEBT" + }, + { + "id": 263, + "fortune": "YOUR EMERGENCY FUND COVERS SMALL EMERGENCIES" + }, + { + "id": 264, + "fortune": "A RAISE IS DESERVED. AND UNSCHEDULED" + }, + { + "id": 265, + "fortune": "YOUR CART IS A VISION BOARD WITH CHECKOUT" + }, + { + "id": 266, + "fortune": "YOUR GENEROSITY IS FAMOUS. AMONG VENDORS" + }, + { + "id": 267, + "fortune": "THE BEST THINGS ARE FREE. YOURS SHIP" + }, + { + "id": 268, + "fortune": "YOUR SUBSCRIPTIONS OUTNUMBER YOUR MATES" + }, + { + "id": 269, + "fortune": "BUY LOW SELL HIGH. YOU INVENTED THE REVERSE" + }, + { + "id": 270, + "fortune": "YOUR BANK TEXTS OUT OF CONCERN NOW" + }, + { + "id": 271, + "fortune": "YOUR TAX REFUND HAS OTHER PLANS" + }, + { + "id": 272, + "fortune": "YOUR SPLURGES ARE STRATEGIC. ALLEGEDLY" + }, + { + "id": 273, + "fortune": "YOU WILL FIND MONEY IN A COAT. IT WAS YOURS" + }, + { + "id": 274, + "fortune": "YOUR PORTFOLIO IS DIVERSIFIED. IN REGRETS" + }, + { + "id": 275, + "fortune": "PAYDAY BRINGS JOY. ABOUT 18 HOURS OF IT" + }, + { + "id": 276, + "fortune": "YOUR LATE FEES HAVE LATE FEES NOW" + }, + { + "id": 277, + "fortune": "A PENNY SAVED IS A START. A SMALL ONE" + }, + { + "id": 278, + "fortune": "RICH IN SPIRIT. THE REGISTER DISAGREES" + }, + { + "id": 279, + "fortune": "YOUR RECEIPTS TELL A STORY. A LONG ONE" + }, + { + "id": 280, + "fortune": "YOUR DOWN PAYMENT BECAME SUSHI. TWICE" + }, + { + "id": 281, + "fortune": "YOUR BUDGET SHEET IS HISTORICAL FICTION" + }, + { + "id": 282, + "fortune": "YOUR FREE TRIALS NEVER DIE. THEY BILL" + }, + { + "id": 283, + "fortune": "CASH IS KING. YOUR KINGDOM RUNS ON CREDIT" + }, + { + "id": 284, + "fortune": "YOUR SPENDING FREEZE LASTED 40 MINUTES" + }, + { + "id": 285, + "fortune": "YOUR BILLS ARRIVE ON TIME. UNLIKE YOU" + }, + { + "id": 286, + "fortune": "YOUR MONEY WORKS HARD. FOR OTHER PEOPLE" + }, + { + "id": 287, + "fortune": "YOUR COUPONS EXPIRED. ALL OF THEM. TODAY" + }, + { + "id": 288, + "fortune": "YOUR FINANCIAL PLAN HAS PHASES. DENIAL FIRST" + }, + { + "id": 289, + "fortune": "YOUR DISCOUNTS FUND YOUR IMPULSE BUYS" + }, + { + "id": 290, + "fortune": "YOUR CRYPTO PHASE WAS EDUCATIONAL. AND COSTLY" + }, + { + "id": 291, + "fortune": "THE LOTTERY IS A HOPE TAX. YOU DONATE WEEKLY" + }, + { + "id": 292, + "fortune": "YOUR SAVINGS GOAL HASNT MOVED SINCE SPRING" + }, + { + "id": 293, + "fortune": "WEALTH WHISPERS. YOURS BLOCKED THE NUMBER" + }, + { + "id": 294, + "fortune": "YOU TRACK EVERY EXPENSE. THEN MAKE MORE" + }, + { + "id": 295, + "fortune": "YOUR PIGGY BANK HAS TRUST ISSUES. EARNED" + }, + { + "id": 296, + "fortune": "YOUR REFUND ARRIVED. ALREADY SPENT. TWICE" + }, + { + "id": 297, + "fortune": "MONEY CANT BUY HAPPINESS. YOURS QUIT TRYING" + }, + { + "id": 298, + "fortune": "YOUR INVOICES AGE LIKE FINE WINE. UNPAID" + }, + { + "id": 299, + "fortune": "YOUR NET WORTH AND SELF WORTH BOTH DIPPED" + }, + { + "id": 300, + "fortune": "PATIENCE IS A VIRTUE. YOU CHOSE OTHERS" + }, + { + "id": 301, + "fortune": "SILENCE IS GOLDEN. YOURS WOULD FUND A NATION" + }, + { + "id": 302, + "fortune": "THINK BEFORE YOU SPEAK. A PILOT PROGRAM" + }, + { + "id": 303, + "fortune": "STILL WATERS RUN DEEP. YOURS RUN ANKLE HIGH" + }, + { + "id": 304, + "fortune": "KNOWLEDGE IS POWER. YOURS IS ON STANDBY" + }, + { + "id": 305, + "fortune": "AN OPEN MIND IS A TREASURE. NICE BREEZE" + }, + { + "id": 306, + "fortune": "LISTEN TWICE SPEAK ONCE. INVERT YOUR RATIO" + }, + { + "id": 307, + "fortune": "THE TRUTH WILL SET YOU FREE. YOURS SAT DOWN" + }, + { + "id": 308, + "fortune": "LOOK BEFORE YOU LEAP. OR AFTER. YOUR WAY" + }, + { + "id": 309, + "fortune": "A FOOL AND HIS MONEY HAD A NICE CEREMONY" + }, + { + "id": 310, + "fortune": "ACTIONS SPEAK LOUDER. YOURS WHISPER" + }, + { + "id": 311, + "fortune": "MEASURE TWICE CUT ONCE. YOU CUT FIRST" + }, + { + "id": 312, + "fortune": "THE PEN IS MIGHTY. YOUR EMAILS ARE WEAPONS" + }, + { + "id": 313, + "fortune": "BETTER LATE THAN NEVER. YOU TEST THIS DAILY" + }, + { + "id": 314, + "fortune": "HONESTY IS THE BEST POLICY. READ THE RIDERS" + }, + { + "id": 315, + "fortune": "DONT COUNT YOUR CHICKENS. YOURS UNIONIZED" + }, + { + "id": 316, + "fortune": "GRASS IS GREENER WHERE WATERED. BUY A HOSE" + }, + { + "id": 317, + "fortune": "EVERY SAINT HAS A PAST. YOURS HAS A FILE" + }, + { + "id": 318, + "fortune": "PRACTICE WHAT YOU PREACH. OR PREACH LESS" + }, + { + "id": 319, + "fortune": "TWO WRONGS DONT MAKE A RIGHT. STOP AT NINE" + }, + { + "id": 320, + "fortune": "ALL THAT GLITTERS ISNT GOLD. CHECK RECEIPTS" + }, + { + "id": 321, + "fortune": "A ROLLING STONE GATHERS NO MOSS. NICE MOSS" + }, + { + "id": 322, + "fortune": "DONT PUT ALL EGGS IN ONE BASKET. FIND BASKET" + }, + { + "id": 323, + "fortune": "EMPTY VESSELS ARE LOUD. GREAT ACOUSTICS" + }, + { + "id": 324, + "fortune": "HE WHO LAUGHS LAST THOUGHT SLOWEST. HI" + }, + { + "id": 325, + "fortune": "A BIRD IN HAND IS WORTH TWO. YOURS FLEW" + }, + { + "id": 326, + "fortune": "IF IT AINT BROKE DONT FIX IT. TOO LATE" + }, + { + "id": 327, + "fortune": "YOU CAN LEAD A HORSE TO WATER. IT DECLINED" + }, + { + "id": 328, + "fortune": "PRIDE GOES BEFORE A FALL. NICE BALANCE" + }, + { + "id": 329, + "fortune": "TIME HEALS ALL WOUNDS. YOURS PICK AT IT" + }, + { + "id": 330, + "fortune": "OLD HABITS DIE HARD. YOURS BOUGHT INSURANCE" + }, + { + "id": 331, + "fortune": "WHERE THERE IS SMOKE THERE IS YOU" + }, + { + "id": 332, + "fortune": "THE BEST DEFENCE IS DISTANCE. THEY LEARNED" + }, + { + "id": 333, + "fortune": "FAMILIARITY BREEDS CONTEMPT. THRIVING HERE" + }, + { + "id": 334, + "fortune": "THE DEVIL IS IN THE DETAILS. YOURS ARE EMPTY" + }, + { + "id": 335, + "fortune": "ONE MANS RUBBISH IS YOUR GARAGE" + }, + { + "id": 336, + "fortune": "A WATCHED POT NEVER BOILS. YOURS BOILED OVER" + }, + { + "id": 337, + "fortune": "IGNORANCE IS BLISS. YOU SEEM SERENE" + }, + { + "id": 338, + "fortune": "BEAUTY IS IN THE EYE. GET THE EYE CHECKED" + }, + { + "id": 339, + "fortune": "IT TAKES A VILLAGE. YOURS REQUESTED BACKUP" + }, + { + "id": 340, + "fortune": "GREAT MINDS THINK ALIKE. YOURS WENT SOLO" + }, + { + "id": 341, + "fortune": "THE PROOF IS IN THE PUDDING. NO COMMENT" + }, + { + "id": 342, + "fortune": "EVERY DOG HAS ITS DAY. YOURS WAS A TUESDAY" + }, + { + "id": 343, + "fortune": "NOTHING VENTURED NOTHING GAINED. PERFECT TIE" + }, + { + "id": 344, + "fortune": "TOO MANY COOKS SPOIL BROTH. YOU SOLOED IT" + }, + { + "id": 345, + "fortune": "YOU REAP WHAT YOU SOW. INTERESTING HARVEST" + }, + { + "id": 346, + "fortune": "ASK AND RECEIVE. YOUR ASKING MADE A LINE" + }, + { + "id": 347, + "fortune": "WALK A MILE IN THEIR SHOES. RETURN THEM" + }, + { + "id": 348, + "fortune": "HASTE MAKES WASTE. YOU KEPT ONLY WASTE" + }, + { + "id": 349, + "fortune": "ALL GOOD THINGS END. YOURS END EARLY" + }, + { + "id": 350, + "fortune": "WORDS ARE CHEAP. YOURS ARE FREE" + }, + { + "id": 351, + "fortune": "TIME WAITS FOR NO ONE. IT MADE AN EXCEPTION" + }, + { + "id": 352, + "fortune": "DONT BITE THE FEEDING HAND. IT WEARS GLOVES" + }, + { + "id": 353, + "fortune": "COMPARISON STEALS JOY. YOURS HIRED IT" + }, + { + "id": 354, + "fortune": "HALF A LOAF BEATS NONE. YOU OFFER CRUMBS" + }, + { + "id": 355, + "fortune": "A SMOOTH SEA NEVER MADE A SAILOR. STAY DOCKED" + }, + { + "id": 356, + "fortune": "THE TRUTH NEEDS NO REHEARSAL. YOURS DOES" + }, + { + "id": 357, + "fortune": "EVERYTHING IN MODERATION. EVEN THAT. STOP" + }, + { + "id": 358, + "fortune": "WHAT GOES AROUND COMES AROUND. TRACK IT" + }, + { + "id": 359, + "fortune": "NEVER ARGUE WITH A FOOL. ONLOOKERS STRUGGLE" + }, + { + "id": 360, + "fortune": "WISDOM WHISPERS. YOURS IS ON MUTE" + }, + { + "id": 361, + "fortune": "A THOUSAND MILE JOURNEY STARTS. YOU STRETCH" + }, + { + "id": 362, + "fortune": "CROSS BRIDGES WHEN YOU REACH THEM. NOT BURN" + }, + { + "id": 363, + "fortune": "THE MIGHTY OAK WAS A NUT. HERITAGE PRESERVED" + }, + { + "id": 364, + "fortune": "FOOL ME ONCE. YOUR CARD HAS NINE STAMPS" + }, + { + "id": 365, + "fortune": "ADVENTURE AWAITS. IT OPENED A BUSINESS" + }, + { + "id": 366, + "fortune": "YOU WILL TRAVEL FAR. THE SHUTTLE COUNTS" + }, + { + "id": 367, + "fortune": "YOUR PASSPORT PHOTO IS THE REAL YOU" + }, + { + "id": 368, + "fortune": "YOUR BUCKET LIST NEEDS A BUCKET" + }, + { + "id": 369, + "fortune": "YOU WILL SEE THE WORLD. VIA DOCUMENTARY" + }, + { + "id": 370, + "fortune": "YOUR HOLIDAY DAYS AGE LIKE FINE GUILT" + }, + { + "id": 371, + "fortune": "AN EXOTIC PLACE CALLED. YOU SCREENED IT" + }, + { + "id": 372, + "fortune": "YOUR ROAD TRIP PLAYLIST OUTLIVED THE TRIP" + }, + { + "id": 373, + "fortune": "YOU PACK LIGHT. EMOTIONALLY YOU DONT" + }, + { + "id": 374, + "fortune": "YOUR SOUVENIRS TELL STORIES. ABOUT PRICING" + }, + { + "id": 375, + "fortune": "YOU WILL GET LOST ABROAD. A HOME SKILL" + }, + { + "id": 376, + "fortune": "YOUR TRAVEL PICS STAR YOUR THUMB" + }, + { + "id": 377, + "fortune": "A SPONTANEOUS TRIP NEARS. WITH SPREADSHEETS" + }, + { + "id": 378, + "fortune": "YOU ARE A WORLD CITIZEN. REFERENCES PENDING" + }, + { + "id": 379, + "fortune": "YOUR BEACH BODY IS READY. THE BEACH ADAPTED" + }, + { + "id": 380, + "fortune": "THE MOUNTAINS ARE CALLING. YOU MUTED THEM" + }, + { + "id": 381, + "fortune": "YOUR STAYCATION GAME IS UNRIVALED" + }, + { + "id": 382, + "fortune": "YOU NAVIGATE LIKE A LOCAL. A LOST ONE" + }, + { + "id": 383, + "fortune": "YOUR ITINERARY IS MOSTLY BUFFER TIME" + }, + { + "id": 384, + "fortune": "YOUR HIKING BOOTS SUMMITED THE CLOSET" + }, + { + "id": 385, + "fortune": "JET LAG RESPECTS NO ONE. YOU CAME PRE TIRED" + }, + { + "id": 386, + "fortune": "YOUR TRAVEL JOURNAL HAS ONE ENTRY. EXCITED" + }, + { + "id": 387, + "fortune": "YOU COLLECT EXPERIENCES. THE CARD DISAGREES" + }, + { + "id": 388, + "fortune": "YOUR SENSE OF DIRECTION IS A FAMILY LEGEND" + }, + { + "id": 389, + "fortune": "A GETAWAY NEARS. THE LAUNDRY WILL WAIT" + }, + { + "id": 390, + "fortune": "YOU WILL RETURN CHANGED. MOSTLY YOUR SLEEP" + }, + { + "id": 391, + "fortune": "YOUR AIRPORT TIMING IS A PERSONALITY TEST" + }, + { + "id": 392, + "fortune": "YOUR WINDOW SEAT PICS FEATURE THE WING" + }, + { + "id": 393, + "fortune": "YOUR CARRY ON HAS ITS OWN GRAVITY NOW" + }, + { + "id": 394, + "fortune": "YOUR CAMPING SKILLS AMUSE THE RACCOONS" + }, + { + "id": 395, + "fortune": "TIME ZONES CONFUSE YOUR SLEEP. IT COPES" + }, + { + "id": 396, + "fortune": "YOUR HOTEL REVIEWS ARE FEARED. BY TOWELS" + }, + { + "id": 397, + "fortune": "YOU BEFRIEND STRANGERS ABROAD. ALSO LOST ONES" + }, + { + "id": 398, + "fortune": "YOUR CRUISE PACE MATCHES YOUR BUFFET PACE" + }, + { + "id": 399, + "fortune": "FORTUNE FAVOURS TRAVELLERS. YOURS LIKES COUCHES" + }, + { + "id": 400, + "fortune": "YOUR PHONE BATTERY OUTLASTS YOUR DRIVE" + }, + { + "id": 401, + "fortune": "YOU WILL READ THE TERMS SOMEDAY. NO" + }, + { + "id": 402, + "fortune": "YOUR SCREEN TIME REPORT SOFTENS THE NEWS" + }, + { + "id": 403, + "fortune": "YOUR LAUNDRY CHAIR EARNED TENURE" + }, + { + "id": 404, + "fortune": "YOUR ALARM HAS FIVE BACKUPS. ALL IGNORED" + }, + { + "id": 405, + "fortune": "YOUR FRIDGE HOSTS A SCIENCE EXPERIMENT" + }, + { + "id": 406, + "fortune": "THE CHECK ENGINE LIGHT IS A MOOD LIGHT NOW" + }, + { + "id": 407, + "fortune": "YOUR HOUSEPLANTS ACCEPTED THEIR FATE" + }, + { + "id": 408, + "fortune": "YOUR JUNK DRAWER OPENED A SECOND LOCATION" + }, + { + "id": 409, + "fortune": "YOUR GYM BAG IS PACKED. THAT COUNTS" + }, + { + "id": 410, + "fortune": "YOUR VOICEMAIL IS FULL. PEOPLE MOVED ON" + }, + { + "id": 411, + "fortune": "YOUR BROWSER TABS ARE AN ECOSYSTEM NOW" + }, + { + "id": 412, + "fortune": "YOUR UMBRELLA WAITS. YOU WILL FORGET IT" + }, + { + "id": 413, + "fortune": "YOUR LEFTOVERS HAD DREAMS. THEY COMPOST" + }, + { + "id": 414, + "fortune": "YOUR TO DO LIST HAS A TO DO LIST" + }, + { + "id": 415, + "fortune": "YOUR CLOSET DRESSES THREE VERSIONS OF YOU" + }, + { + "id": 416, + "fortune": "YOUR MORNING RUN IS LAMINATED. NOT RUN" + }, + { + "id": 417, + "fortune": "YOUR WIFI ROUTER SITS ON A SHRINE. CORRECT" + }, + { + "id": 418, + "fortune": "YOUR INBOX ZERO ATTEMPT IS HISTORY NOW" + }, + { + "id": 419, + "fortune": "YOUR SOCK DRAWER RUNS WITNESS PROTECTION" + }, + { + "id": 420, + "fortune": "YOUR GROCERY LIST STAYS HOME. IT KNOWS" + }, + { + "id": 421, + "fortune": "YOUR WATCHLIST OUTLIVED THREE HOBBIES" + }, + { + "id": 422, + "fortune": "YOUR DESK IS ERGONOMIC. YOUR COUCH ISNT" + }, + { + "id": 423, + "fortune": "THE PRINTER SENSES FEAR. AND UPDATES" + }, + { + "id": 424, + "fortune": "YOUR BEDTIME IS A MOTION YOU VOTE DOWN" + }, + { + "id": 425, + "fortune": "YOUR HEADPHONES TANGLE ALONE. SCIENCE WEEPS" + }, + { + "id": 426, + "fortune": "YOUR SPICE RACK IS SORTED THROUGH C" + }, + { + "id": 427, + "fortune": "YOUR BACKSEAT IS A LOST AND FOUND" + }, + { + "id": 428, + "fortune": "YOUR CART ABANDONMENT RATE MADE THE NEWS" + }, + { + "id": 429, + "fortune": "THE GOOD CABLE IS WHEREVER YOU ARENT" + }, + { + "id": 430, + "fortune": "YOUR STANDING DESK MOSTLY SITS. LIKE YOU" + }, + { + "id": 431, + "fortune": "YOUR MEAL PREP MADE ONE MEAL. SIX BOXES" + }, + { + "id": 432, + "fortune": "THE DELIVERY DRIVER WAVES AT YOU NOW" + }, + { + "id": 433, + "fortune": "YOUR AIR FRYER REPLACED THE OVEN. AND YOU" + }, + { + "id": 434, + "fortune": "YOUR BOOKMARKS ARE A HALL OF INTENTIONS" + }, + { + "id": 435, + "fortune": "YOUR SNOOZE BUTTON SHOWS GEOLOGIC WEAR" + }, + { + "id": 436, + "fortune": "YOUR REUSABLE BAGS WAIT IN THE CAR. LOYAL" + }, + { + "id": 437, + "fortune": "YOUR UPDATES HAVE SENIORITY NOW" + }, + { + "id": 438, + "fortune": "THE ICE TRAY RETURNS EMPTY. A TRADITION" + }, + { + "id": 439, + "fortune": "YOUR GARAGE STORES EVERYTHING BUT THE CAR" + }, + { + "id": 440, + "fortune": "YOUR STEP COUNTER FRAMED ITS BEST DAY" + }, + { + "id": 441, + "fortune": "YOUR FAVOURITE MUG HAS PROTECTED STATUS" + }, + { + "id": 442, + "fortune": "YOUR WEATHER APP GAVE UP ON YOUR OUTFITS" + }, + { + "id": 443, + "fortune": "YOUR SCALE PRACTICES RADICAL HONESTY" + }, + { + "id": 444, + "fortune": "YOUR REMOTES COMMUTE FROM THE CUSHIONS" + }, + { + "id": 445, + "fortune": "THE HALLWAY CLOSET HOLDS YOUR TRUTH. BARELY" + }, + { + "id": 446, + "fortune": "YOU OWN EVERY BATTERY SIZE BUT THE ONE NEEDED" + }, + { + "id": 447, + "fortune": "YOUR VACUUM AVOIDS CORNERS. LIKE YOU" + }, + { + "id": 448, + "fortune": "YOUR SHOWER THOUGHTS STAY IN THE SHOWER" + }, + { + "id": 449, + "fortune": "YOUR COFFEE MAKER KNOWS YOUR MONDAY FACE" + }, + { + "id": 450, + "fortune": "YOUR FREEZER FLOOR PREDATES FRIENDSHIPS" + }, + { + "id": 451, + "fortune": "YOUR PHONE STORAGE IS ALL SCREENSHOTS" + }, + { + "id": 452, + "fortune": "YOUR BIKE TIRES EXHALE SLOWLY. LIKE A SIGH" + }, + { + "id": 453, + "fortune": "YOUR RETURNS PILE HAS A DEPARTURE LOUNGE" + }, + { + "id": 454, + "fortune": "YOUR CANDLES ARE DECOR. MATCHES AGREE" + }, + { + "id": 455, + "fortune": "YOUR DINING TABLE RETIRED FROM DINING" + }, + { + "id": 456, + "fortune": "YOUR PREDICTIVE TEXT SUGGESTS SORRY FIRST" + }, + { + "id": 457, + "fortune": "YOUR FITNESS APP USES SHORTER SENTENCES NOW" + }, + { + "id": 458, + "fortune": "YOUR COAT POCKET IS A TIME CAPSULE" + }, + { + "id": 459, + "fortune": "THE ADD 30 SECONDS BUTTON RUNS YOUR KITCHEN" + }, + { + "id": 460, + "fortune": "THE GOOD SCISSORS ARE MISSING. ONE SUSPECT" + }, + { + "id": 461, + "fortune": "YOUR DOWNLOADS FOLDER IS A LANDFILL" + }, + { + "id": 462, + "fortune": "YOUR PLANTS RUN ON GUILT BASED WATERING" + }, + { + "id": 463, + "fortune": "THE DRYER TAKES ONE SOCK AS TRIBUTE" + }, + { + "id": 464, + "fortune": "YOUR COASTERS WATCH FROM THE SIDELINES" + }, + { + "id": 465, + "fortune": "YOUR NOTES APP IS A GENIUS LANDFILL" + }, + { + "id": 466, + "fortune": "RAIN WILL WASH YOUR CAR. YOUR PLAN EXACTLY" + }, + { + "id": 467, + "fortune": "YOUR BOARD GAMES AGE IN SHRINK WRAP" + }, + { + "id": 468, + "fortune": "YOUR YOGA MAT UNROLLED TWICE. FOR NAPS" + }, + { + "id": 469, + "fortune": "YOUR EXTENSION CORDS BREED IN THE DARK" + }, + { + "id": 470, + "fortune": "YOUR SMART SPEAKER HAS HEARD THINGS" + }, + { + "id": 471, + "fortune": "YOUR LIDS AND CONTAINERS NEVER MATCH. EVER" + }, + { + "id": 472, + "fortune": "YOUR WALKING SHOES TOUR THE TRUNK" + }, + { + "id": 473, + "fortune": "YOUR IMPORTANT FOLDER IS A HOSPICE" + }, + { + "id": 474, + "fortune": "YOUR WREATH IS PERENNIAL NOW. FESTIVE" + }, + { + "id": 475, + "fortune": "THAT ONE DRAWER STOPPED EXPLAINING ITSELF" + }, + { + "id": 476, + "fortune": "YOUR SCREEN AT 2AM REVEALS EVERYTHING" + }, + { + "id": 477, + "fortune": "YOUR FIRE EXTINGUISHER RUNS ON CONFIDENCE" + }, + { + "id": 478, + "fortune": "YOUR WATER GOAL WAS MET ONCE. PLAQUE PENDING" + }, + { + "id": 479, + "fortune": "AGING SUITS YOU. THE ALTERNATIVE DIDNT" + }, + { + "id": 480, + "fortune": "YOUR AGE IS JUST A NUMBER. AN ASCENDING ONE" + }, + { + "id": 481, + "fortune": "YOUR KNEES FORECAST WEATHER NOW. A SKILL" + }, + { + "id": 482, + "fortune": "YOUR BACK WENT OUT MORE THAN YOU DID" + }, + { + "id": 483, + "fortune": "WISDOM COMES WITH GREY HAIR. YOURS CAME EARLY" + }, + { + "id": 484, + "fortune": "YOU AGE LIKE WINE. STORED HORIZONTALLY" + }, + { + "id": 485, + "fortune": "YOUR BIRTHDAY CANDLES ARE A FIRE HAZARD" + }, + { + "id": 486, + "fortune": "YOUR READING GLASSES NEED READING GLASSES" + }, + { + "id": 487, + "fortune": "YOUR PLAYLIST IS CALLED OLDIES NOW. BY KIDS" + }, + { + "id": 488, + "fortune": "YOU GROAN WHEN SITTING. A VERBAL RECEIPT" + }, + { + "id": 489, + "fortune": "YOUR METABOLISM RETIRED WITHOUT NOTICE" + }, + { + "id": 490, + "fortune": "YOU FEEL 25. YOUR HANGOVERS DISAGREE" + }, + { + "id": 491, + "fortune": "AN APPLE A DAY. PIE IS A LOOPHOLE. SURE" + }, + { + "id": 492, + "fortune": "YOUR POSTURE IMPROVES TWICE DAILY. BRIEFLY" + }, + { + "id": 493, + "fortune": "YOU WILL SLEEP 8 HOURS. ACROSS 3 NIGHTS" + }, + { + "id": 494, + "fortune": "YOUR VITAMINS EXPIRE UNTAKEN. RENEWABLE" + }, + { + "id": 495, + "fortune": "YOUR DIET STARTS MONDAY. MONDAYS UNIONIZED" + }, + { + "id": 496, + "fortune": "YOUR DENTIST KNOWS YOU FLOSSED TODAY ONLY" + }, + { + "id": 497, + "fortune": "YOUR RESTING HEART RATE IS GREAT. FITTING" + }, + { + "id": 498, + "fortune": "YOU WILL LIVE TO 100. OUT OF SPITE" + }, + { + "id": 499, + "fortune": "YOUR HIDDEN TALENTS REMAIN WELL HIDDEN" + }, + { + "id": 500, + "fortune": "YOUR CREATIVITY HAS NO BOUNDS. OR OUTPUT" + }, + { + "id": 501, + "fortune": "YOU HAVE A GIFT. NO RECEIPT INCLUDED" + }, + { + "id": 502, + "fortune": "YOUR NOVEL WILL BE FINISHED. BY SOMEONE" + }, + { + "id": 503, + "fortune": "YOU WERE BORN TO CREATE. EXCUSES COUNT" + }, + { + "id": 504, + "fortune": "YOUR MASTERPIECE IS INSIDE YOU. COZY THERE" + }, + { + "id": 505, + "fortune": "YOUR SINGING BRINGS TEARS. BIOLOGY IS ODD" + }, + { + "id": 506, + "fortune": "THE MUSE VISITS YOU. SHE CALLS AHEAD NOW" + }, + { + "id": 507, + "fortune": "YOUR PHOTOS CAPTURE RAW CONFUSION" + }, + { + "id": 508, + "fortune": "YOU THINK OUTSIDE THE BOX. THE BOX WORRIES" + }, + { + "id": 509, + "fortune": "YOUR POETRY MOVES PEOPLE. TO THE EXITS" + }, + { + "id": 510, + "fortune": "YOUR IMAGINATION IS VAST. EXECUTION ISNT" + }, + { + "id": 511, + "fortune": "YOU SEE THE WORLD DIFFERENTLY. GET CHECKED" + }, + { + "id": 512, + "fortune": "YOUR PODCAST IDEA JOINS THE OTHER SIX" + }, + { + "id": 513, + "fortune": "CREATIVITY FLOWS PAST YOU. WAVING" + }, + { + "id": 514, + "fortune": "YOUR DOODLES BELONG SOMEWHERE. A DRAWER" + }, + { + "id": 515, + "fortune": "YOUR COOKING IS PERFORMANCE ART. WITH ALARMS" + }, + { + "id": 516, + "fortune": "YOUR SCREENPLAY HAS POTENTIAL ENERGY ONLY" + }, + { + "id": 517, + "fortune": "THE WORLD IS YOUR CANVAS. STILL PRIMED" + }, + { + "id": 518, + "fortune": "YOUR DIY PROJECTS ARE AN UNFINISHED TRILOGY" + }, + { + "id": 519, + "fortune": "YOUR MUSIC TASTE IS GREAT. NEIGHBOURS DISSENT" + }, + { + "id": 520, + "fortune": "YOUR DANCE MOVES DEFY CONVENTION. AND PHYSICS" + }, + { + "id": 521, + "fortune": "YOU TELL GREAT STORIES. ENDINGS PENDING" + }, + { + "id": 522, + "fortune": "PHARMACISTS FRAME YOUR HANDWRITING" + }, + { + "id": 523, + "fortune": "YOUR IDEAS ARRIVE AT 2AM. GONE BY 8" + }, + { + "id": 524, + "fortune": "YOUR SKETCHBOOK HOLDS GREAT PROMISES" + }, + { + "id": 525, + "fortune": "YOU COULD WRITE A BOOK. A STRONG PAMPHLET" + }, + { + "id": 526, + "fortune": "YOUR POTTERY PHASE MADE MEMORABLE PIECES" + }, + { + "id": 527, + "fortune": "YOUR INNER ARTIST WANTS COFFEE FIRST" + }, + { + "id": 528, + "fortune": "YOUR COLOUR CHOICES ARE COURAGEOUS" + }, + { + "id": 529, + "fortune": "YOUR GUITAR KNOWS THREE CHORDS WELL" + }, + { + "id": 530, + "fortune": "YOUR CREATIVE PROCESS IS UNDOCUMENTED" + }, + { + "id": 531, + "fortune": "YOUR SCARVES BECAME EXPERIENCES. KNIT ON" + }, + { + "id": 532, + "fortune": "YOU PAINT WITH EMOTION. THE FLOOR AGREES" + }, + { + "id": 533, + "fortune": "YOUR BONSAI IS A REGULAR TREE NOW. PATIENCE" + }, + { + "id": 534, + "fortune": "YOUR WRITING VOICE IS STRONG. IN TEXTS" + }, + { + "id": 535, + "fortune": "YOUR GARDEN GROWS. THE WEEDS THRIVE MOST" + }, + { + "id": 536, + "fortune": "YOUR CALLIGRAPHY PHASE WAS ONE WEEKEND" + }, + { + "id": 537, + "fortune": "YOUR WOODWORK IS HONEST. SPLINTERS DONT LIE" + }, + { + "id": 538, + "fortune": "YOUR FAN FICTION HAS FANS. BOTH OF THEM" + }, + { + "id": 539, + "fortune": "YOUR ORIGAMI FILLS THE RECYCLING BIN" + }, + { + "id": 540, + "fortune": "YOUR CREATIVE BLOCK IS LOAD BEARING NOW" + }, + { + "id": 541, + "fortune": "YOUR SOURDOUGH STARTER OUTLIVED THE HOBBY" + }, + { + "id": 542, + "fortune": "YOUR WATERCOLORS CAPTURE SOMETHING. UNCLEAR" + }, + { + "id": 543, + "fortune": "YOU EXCEL AT BEGINNINGS. MIDDLES DECLINED" + }, + { + "id": 544, + "fortune": "YOUR UKULELE EMBRACED ITS ROLE AS DECOR" + }, + { + "id": 545, + "fortune": "YOU ARE YOUR OWN WORST CRITIC. UNDISPUTED" + }, + { + "id": 546, + "fortune": "YOUR ART SPEAKS FOR ITSELF. QUIETLY" + }, + { + "id": 547, + "fortune": "YOUR STUDIO IS A CLOSET AGAIN. FUNCTIONAL" + }, + { + "id": 548, + "fortune": "YOUR FIRST DRAFTS NEVER MEET SECOND ONES" + }, + { + "id": 549, + "fortune": "YOUR CANDLE PHASE LEFT EVIDENCE. WAXY" + }, + { + "id": 550, + "fortune": "YOUR OPEN MIC DEBUT REMAINS IMMINENT" + }, + { + "id": 551, + "fortune": "YOUR PLAYLIST TRANSITIONS ARE ART. SHUFFLED" + }, + { + "id": 552, + "fortune": "YOUR COSTUMES SHOW COMMITMENT. TO CONCEPTS" + }, + { + "id": 553, + "fortune": "YOUR MACRAME OWL HAS SEEN YOUR PROJECTS" + }, + { + "id": 554, + "fortune": "YOUR VOICE MEMOS ARE MOSTLY GROCERIES" + }, + { + "id": 555, + "fortune": "YOU WILL BE DISCOVERED. ON YOUR COUCH" + }, + { + "id": 556, + "fortune": "YOUR MOOD BOARD IS ALL MOOD. NO BOARD" + }, + { + "id": 557, + "fortune": "YOUR FREESTYLE RAPS SHOULD STAY FREE" + }, + { + "id": 558, + "fortune": "YOUR MUSEUM VISITS END AT THE CAFE" + }, + { + "id": 559, + "fortune": "YOUR COVERS BEAT THE ORIGINALS. UNNOTIFIED" + }, + { + "id": 560, + "fortune": "YOUR TYPEWRITER LOOKS GREAT. STILL" + }, + { + "id": 561, + "fortune": "YOUR ABSTRACT PHASE CONFUSED EVEN YOU" + }, + { + "id": 562, + "fortune": "YOUR COMIC HAS A FOLLOWER. HI MUM" + }, + { + "id": 563, + "fortune": "YOUR SONG RHYMES ORANGE WITH DOOR HINGE" + }, + { + "id": 564, + "fortune": "YOUR CRAFT CORNER ANNEXED THE GUEST ROOM" + }, + { + "id": 565, + "fortune": "YOUR GENIUS IS MISUNDERSTOOD. AND UNSEEN" + }, + { + "id": 566, + "fortune": "YOUR MAGNUM OPUS IS BASICALLY ESPRESSO NOW" + }, + { + "id": 567, + "fortune": "YOUR INSPIRATION FOLDER HAS SUBFOLDERS" + }, + { + "id": 568, + "fortune": "THE FORTUNE YOU SEEK IS IN ANOTHER BIKKIE" + }, + { + "id": 569, + "fortune": "THIS BIKKIE CONTAINS NO FORTUNE. JUST CARBS" + }, + { + "id": 570, + "fortune": "IT IS DARK INSIDE THIS BIKKIE. AND QUIET" + }, + { + "id": 571, + "fortune": "THIS FORTUNE LEFT INTENTIONALLY BLANK" + }, + { + "id": 572, + "fortune": "CONFUCIUS SAYS NOTHING ABOUT YOU. WISELY" + }, + { + "id": 573, + "fortune": "THIS FORTUNE WAS RECALLED. SAME TO YOU" + }, + { + "id": 574, + "fortune": "YOU WILL READ THIS ALOUD. UNPROMPTED" + }, + { + "id": 575, + "fortune": "THE BIKKIE KNEW YOU WOULD TAKE THE LAST ONE" + }, + { + "id": 576, + "fortune": "SOME GET WISDOM. YOU CHOSE DESSERT" + }, + { + "id": 577, + "fortune": "THIS IS A BIKKIE. NOT A LIFE COACH" + }, + { + "id": 578, + "fortune": "YOUR LUCKY NUMBERS HAVE OPTED OUT" + }, + { + "id": 579, + "fortune": "THE BIKKIE ADMIRES YOUR OPTIMISM" + }, + { + "id": 580, + "fortune": "YOU SHOOK THE BIKKIE FIRST. IT FELT THAT" + }, + { + "id": 581, + "fortune": "ASK AGAIN LATER. OR DONT. YOUR CALL" + }, + { + "id": 582, + "fortune": "THIS BIKKIE WAS BAKED WITH LOW EXPECTATIONS" + }, + { + "id": 583, + "fortune": "THE FORTUNE WRITER IS ON BREAK. JUDGING" + }, + { + "id": 584, + "fortune": "NO WISDOM TODAY. INVENTORY ISSUES" + }, + { + "id": 585, + "fortune": "YOUR FORTUNE IS PENDING APPROVAL" + }, + { + "id": 586, + "fortune": "THIS MESSAGE WILL SELF DISAPPOINT" + }, + { + "id": 587, + "fortune": "THE BIKKIE CRUMBLES. SO DO PLANS" + }, + { + "id": 588, + "fortune": "YOU EXPECTED MORE FROM A BIKKIE. NOTED" + }, + { + "id": 589, + "fortune": "FORTUNE NOT FOUND. TRY ANOTHER DINNER" + }, + { + "id": 590, + "fortune": "THIS BIKKIE HAS SEEN YOUR ORDER HISTORY" + }, + { + "id": 591, + "fortune": "THE LAST BIKKIE ALWAYS TELLS THE TRUTH" + }, + { + "id": 592, + "fortune": "YOUR FORTUNE RAN OUT OF CHARACTERS. LUCKY" + }, + { + "id": 593, + "fortune": "A WISE MAN ONCE SAID NOTHING. TRY IT" + }, + { + "id": 594, + "fortune": "THE BIKKIE BELIEVED IN YOU. PAST TENSE" + }, + { + "id": 595, + "fortune": "THIS FORTUNE IS ACCURATE. DETAILS REDACTED" + }, + { + "id": 596, + "fortune": "YOU HOLD THE KEY TO HAPPINESS. NOW FIND IT" + }, + { + "id": 597, + "fortune": "YOUR FORTUNE IS BEING WRITTEN. SLOWLY" + }, + { + "id": 598, + "fortune": "YOUR COFFEE ORDER IS A PARAGRAPH NOW" + }, + { + "id": 599, + "fortune": "COFFEE FIRST. PERSONALITY SECOND. FAIR" + }, + { + "id": 600, + "fortune": "YOUR FOURTH COFFEE IS WATCHING YOU" + }, + { + "id": 601, + "fortune": "DECAF EXISTS. YOU PRETEND IT DOESNT" + }, + { + "id": 602, + "fortune": "YOUR MUG COLLECTION OUTGREW THE CABINET" + }, + { + "id": 603, + "fortune": "YOUR ESPRESSO MACHINE JUDGES YOUR PODS" + }, + { + "id": 604, + "fortune": "YOU CALL IT BRUNCH. IT WAS BREKKIE. LATE" + }, + { + "id": 605, + "fortune": "YOUR SALAD PHASE ENDED AT THE DRESSING" + }, + { + "id": 606, + "fortune": "YOU MEAL PLAN BEAUTIFULLY. THEN ORDER OUT" + }, + { + "id": 607, + "fortune": "YOUR SPICE TOLERANCE IS A PERSONALITY. SADLY" + }, + { + "id": 608, + "fortune": "YOUR SIGNATURE DISH HAS ONE FAN. YOU" + }, + { + "id": 609, + "fortune": "THE OVEN TIMER IS A SUGGESTION TO YOU" + }, + { + "id": 610, + "fortune": "YOUR SMOOTHIES HIDE VEGETABLES. FROM YOU" + }, + { + "id": 611, + "fortune": "YOU COOK WITH LOVE. AND TOO MUCH SALT" + }, + { + "id": 612, + "fortune": "YOUR RECIPE SUBSTITUTIONS ARE BRAVE" + }, + { + "id": 613, + "fortune": "GARLIC MEASURED WITH YOUR HEART. AGAIN" + }, + { + "id": 614, + "fortune": "YOUR TOAST GAME IS STRONG. LITERALLY BURNT" + }, + { + "id": 615, + "fortune": "YOU EAT DESSERT FIRST. LIFE IS SHORT. SURE" + }, + { + "id": 616, + "fortune": "YOUR SNACK DRAWER HAS A WAITING LIST" + }, + { + "id": 617, + "fortune": "THE FOOD DELIVERY APP KNOWS YOU BY NAME" + }, + { + "id": 618, + "fortune": "YOUR KITCHEN GADGETS FORM A MUSEUM" + }, + { + "id": 619, + "fortune": "YOUR TAKEOUT CONTAINERS ARE HEIRLOOMS NOW" + }, + { + "id": 620, + "fortune": "YOU SAY YOU COULD EAT ANYTHING. THEN DONT" + }, + { + "id": 621, + "fortune": "YOUR PIZZA TOPPINGS HAVE CRITICS" + }, + { + "id": 622, + "fortune": "YOUR DOG LOVES YOU UNCONDITIONALLY. TRAINED" + }, + { + "id": 623, + "fortune": "YOUR CAT TOLERATES YOU. A HIGH HONOUR" + }, + { + "id": 624, + "fortune": "YOUR PET EATS BETTER THAN YOU DO" + }, + { + "id": 625, + "fortune": "YOUR DOG HAS MORE MATES THAN YOU" + }, + { + "id": 626, + "fortune": "THE CAT KNOCKED IT OVER ON PURPOSE. RESPECT" + }, + { + "id": 627, + "fortune": "YOUR FISH KNOWS YOUR SCHEDULE. IT WORRIES" + }, + { + "id": 628, + "fortune": "YOUR PETS INSTAGRAM OUTPERFORMS YOURS" + }, + { + "id": 629, + "fortune": "THE DOG ATE YOUR MOTIVATION. NOT HOMEWORK" + }, + { + "id": 630, + "fortune": "YOUR CAT REVIEWS YOUR LIFE CHOICES NIGHTLY" + }, + { + "id": 631, + "fortune": "YOUR BIRD REPEATS YOUR WORST PHRASES" + }, + { + "id": 632, + "fortune": "YOUR PET THERAPIST IS A GOOD LISTENER. FREE" + }, + { + "id": 633, + "fortune": "RAIN IS COMING. YOUR CAR WASH REJOICES" + }, + { + "id": 634, + "fortune": "YOUR WINTER COAT DEBATE STARTS IN OCTOBER" + }, + { + "id": 635, + "fortune": "YOU CHECK THE WEATHER. THEN DRESS WRONG" + }, + { + "id": 636, + "fortune": "SPRING IS COMING. SO ARE YOUR ALLERGIES" + }, + { + "id": 637, + "fortune": "YOUR SUNSCREEN EXPIRES UNUSED. YEARLY" + }, + { + "id": 638, + "fortune": "SNOW IS MAGICAL. UNTIL YOU OWN A SHOVEL" + }, + { + "id": 639, + "fortune": "YOUR UMBRELLA COLLECTION LIVES ELSEWHERE" + }, + { + "id": 640, + "fortune": "SMALL TALK ABOUT WEATHER SUITS YOU NOW" + }, + { + "id": 641, + "fortune": "THE FORECAST CHANGED. YOUR PLANS DIDNT EXIST" + }, + { + "id": 642, + "fortune": "YOUR PATIO FURNITURE FEARS EVERY SEASON" + }, + { + "id": 643, + "fortune": "AUTUMN LEAVES FALL. LIKE YOUR RESOLUTIONS" + }, + { + "id": 644, + "fortune": "YOUR PASSWORD IS YOUR PETS NAME. WE KNOW" + }, + { + "id": 645, + "fortune": "YOU HAVE 47 UNREAD UPDATES. THEY WAIT" + }, + { + "id": 646, + "fortune": "YOUR CLOUD STORAGE IS FULL. OF DUPLICATES" + }, + { + "id": 647, + "fortune": "AUTOCORRECT KNOWS WHAT YOU MEANT. IT DECLINED" + }, + { + "id": 648, + "fortune": "YOUR ROUTER NEEDS A RESTART. LIKE YOU" + }, + { + "id": 649, + "fortune": "YOUR SEARCH HISTORY TELLS A SAGA" + }, + { + "id": 650, + "fortune": "YOU CLOSED ONE TAB TODAY. PROGRESS" + }, + { + "id": 651, + "fortune": "YOUR SPAM FOLDER MISSES YOU" + }, + { + "id": 652, + "fortune": "THE ALGORITHM KNOWS YOU TOO WELL. IT WORRIES" + }, + { + "id": 653, + "fortune": "YOUR SMARTWATCH SUGGESTS BREATHING. POINTED" + }, + { + "id": 654, + "fortune": "YOUR TYPING SPEED PEAKS DURING ARGUMENTS" + }, + { + "id": 655, + "fortune": "YOU MUTED THE GROUP. THE GROUP KNOWS" + }, + { + "id": 656, + "fortune": "YOUR CAPS LOCK GETS REGULAR EXERCISE" + }, + { + "id": 657, + "fortune": "YOUR EMOJI USE HAS BEEN DISCUSSED" + }, + { + "id": 658, + "fortune": "YOUR WIFI NAME IS YOUR BEST JOKE" + }, + { + "id": 659, + "fortune": "YOU RESTART THINGS AS A LIFESTYLE" + }, + { + "id": 660, + "fortune": "YOUR GYM MEMBERSHIP IS A DONATION NOW" + }, + { + "id": 661, + "fortune": "YOUR MARATHON PLAN IS SAVED. AND SAFE" + }, + { + "id": 662, + "fortune": "LEG DAY RESPECTS YOUR ABSENCE" + }, + { + "id": 663, + "fortune": "YOUR PROTEIN POWDER AGES GRACEFULLY" + }, + { + "id": 664, + "fortune": "YOU STRETCH ONCE A YEAR. AMBITIOUSLY" + }, + { + "id": 665, + "fortune": "YOUR SPORTS TEAM LOSES. YOU TAKE CREDIT" + }, + { + "id": 666, + "fortune": "YOUR FANTASY TEAM IS FANTASY INDEED" + }, + { + "id": 667, + "fortune": "YOU RUN LATE. IT COUNTS AS CARDIO" + }, + { + "id": 668, + "fortune": "YOUR HOME GYM STORES THE LAUNDRY NOW" + }, + { + "id": 669, + "fortune": "YOUR PERSONAL BEST WAS A GROUP EFFORT" + }, + { + "id": 670, + "fortune": "YOUR WARM UP IS THE WHOLE WORKOUT" + }, + { + "id": 671, + "fortune": "YOUR REST DAYS HAVE REST DAYS" + }, + { + "id": 672, + "fortune": "SLEEP IS FOR THE STRONG. YOU SCROLL" + }, + { + "id": 673, + "fortune": "YOUR NAP SCHEDULE IS YOUR REAL CALENDAR" + }, + { + "id": 674, + "fortune": "YOU COUNT SHEEP. THEY COUNT YOUR EXCUSES" + }, + { + "id": 675, + "fortune": "YOUR PILLOW KNOWS ALL YOUR SECRETS" + }, + { + "id": 676, + "fortune": "ONE MORE EPISODE WAS FOUR EPISODES" + }, + { + "id": 677, + "fortune": "YOUR DREAMS ARE VIVID. YOUR MORNINGS ARENT" + }, + { + "id": 678, + "fortune": "YOU SET SIX ALARMS. YOU FEAR NONE" + }, + { + "id": 679, + "fortune": "BEDTIME PROCRASTINATION IS STILL A CHOICE" + }, + { + "id": 680, + "fortune": "YOUR WEEKEND SLEEP DEBT COLLECTS INTEREST" + }, + { + "id": 681, + "fortune": "YOUR FAMILY LOVES YOU. THEY VOTED. CLOSE ONE" + }, + { + "id": 682, + "fortune": "YOUR MOTHER WAS RIGHT. ABOUT EVERYTHING" + }, + { + "id": 683, + "fortune": "FAMILY DINNERS TEST YOUR DIPLOMACY" + }, + { + "id": 684, + "fortune": "YOUR SIBLING REMEMBERS EVERYTHING. FOREVER" + }, + { + "id": 685, + "fortune": "YOUR RELATIVES ASK ABOUT YOUR PLANS. BRACE" + }, + { + "id": 686, + "fortune": "YOU ARE THE FAVOURITE CHILD. UNCONFIRMED" + }, + { + "id": 687, + "fortune": "YOUR FAMILY GROUP CHAT NEVER SLEEPS" + }, + { + "id": 688, + "fortune": "GRANDMA FEEDS YOU. RESISTANCE IS FUTILE" + }, + { + "id": 689, + "fortune": "YOUR DAD JOKES SKIPPED NO GENERATIONS" + }, + { + "id": 690, + "fortune": "THANKSGIVING SEATING IS POLITICAL. YOURS IS" + }, + { + "id": 691, + "fortune": "YOUR NEIGHBOUR WAVES. THE FENCE WAS HIS IDEA" + }, + { + "id": 692, + "fortune": "THE HOA NOTICED YOUR LAWN. AGAIN" + }, + { + "id": 693, + "fortune": "YOUR NEIGHBOURS KNOW YOUR SCHEDULE. AND MORE" + }, + { + "id": 694, + "fortune": "BORROWED TOOLS BECOME GIFTS EVENTUALLY" + }, + { + "id": 695, + "fortune": "YOUR DOORBELL CAMERA SAW YOUR BEST SPRINT" + }, + { + "id": 696, + "fortune": "YOUR COMMUTE BUILDS CHARACTER. DAILY" + }, + { + "id": 697, + "fortune": "TRAFFIC IS NOT PERSONAL. YOURS FEELS PERSONAL" + }, + { + "id": 698, + "fortune": "YOUR PARKING JOB SPARKED CONVERSATIONS" + }, + { + "id": 699, + "fortune": "YOUR GPS SAYS RECALCULATING. WITH FEELING" + }, + { + "id": 700, + "fortune": "YOU DRIVE LIKE YOU LIVE. SIGNALS OPTIONAL" + }, + { + "id": 701, + "fortune": "YOUR GAS TANK RUNS ON FAITH. AND FUMES" + }, + { + "id": 702, + "fortune": "THE LEFT LANE IS FOR PASSING. JUST SAYING" + }, + { + "id": 703, + "fortune": "YOUR CAR PLAYLIST PEAKED IN 2016" + }, + { + "id": 704, + "fortune": "YOUR HORN GETS MORE USE THAN YOUR BLINKER" + }, + { + "id": 705, + "fortune": "ROAD RAGE IS BENEATH YOU. USUALLY" + }, + { + "id": 706, + "fortune": "YOUR PARALLEL PARKING DRAWS AUDIENCES" + }, + { + "id": 707, + "fortune": "TIME FLIES. YOURS FILED A FLIGHT PLAN" + }, + { + "id": 708, + "fortune": "PROCRASTINATION IS AN ART. YOU TEACH IT" + }, + { + "id": 709, + "fortune": "YOU WILL DO IT TOMORROW. TOMORROW KNOWS" + }, + { + "id": 710, + "fortune": "DEADLINES APPROACH. YOU ADMIRE THE VIEW" + }, + { + "id": 711, + "fortune": "YOUR FIVE MINUTES IS EVERYONE ELSES HOUR" + }, + { + "id": 712, + "fortune": "LATER IS YOUR FAVOURITE TIME ZONE" + }, + { + "id": 713, + "fortune": "YOU FINISH THINGS. EVENTUALLY IS A WORD" + }, + { + "id": 714, + "fortune": "YOUR SOMEDAY LIST NEEDS ITS OWN SHELF" + }, + { + "id": 715, + "fortune": "TIME MANAGEMENT IS A SKILL. NOTED" + }, + { + "id": 716, + "fortune": "YOU ARE EARLY ONCE A YEAR. IT CONFUSES ALL" + }, + { + "id": 717, + "fortune": "THE PRESENT IS A GIFT. YOU CHOSE STORE CREDIT" + }, + { + "id": 718, + "fortune": "YOUR PUNCTUALITY IS LEGEND. THE BAD KIND" + }, + { + "id": 719, + "fortune": "YOU READ THIS INSTEAD OF WORKING. NOTED" + }, + { + "id": 720, + "fortune": "YOUR ATTENTION SPAN IS. OH LOOK A BIRD" + }, + { + "id": 721, + "fortune": "JUST ONE MORE MINUTE. THE FAMOUS LAST WORDS" + }, + { + "id": 722, + "fortune": "YOUR EMAILS START WITH SORRY FOR THE DELAY" + }, + { + "id": 723, + "fortune": "YOU REPLY TO TEXTS IN GEOLOGIC TIME" + }, + { + "id": 724, + "fortune": "YOUR READ RECEIPTS INCRIMINATE YOU" + }, + { + "id": 725, + "fortune": "YOU LEFT THEM ON READ. THEY NOTICED" + }, + { + "id": 726, + "fortune": "YOUR TYPING BUBBLE APPEARED. THEN LEFT" + }, + { + "id": 727, + "fortune": "YOU SAID LETS CIRCLE BACK. YOU WONT" + }, + { + "id": 728, + "fortune": "PER YOUR LAST EMAIL. YOU KNOW WHAT YOU DID" + }, + { + "id": 729, + "fortune": "YOUR VOICE NOTES ARE PODCASTS NOW" + }, + { + "id": 730, + "fortune": "YOU WAVED AT SOMEONE WAVING ELSEWHERE. AGAIN" + }, + { + "id": 731, + "fortune": "YOUR SMALL TALK HAS A SCRIPT. REHEARSE" + }, + { + "id": 732, + "fortune": "YOU SAID WE SHOULD HANG OUT SOON. CLASSIC" + }, + { + "id": 733, + "fortune": "YOUR PHONE IS ON SILENT. FOR YEARS NOW" + }, + { + "id": 734, + "fortune": "YOU SCREENSHOT INSTEAD OF RESPONDING" + }, + { + "id": 735, + "fortune": "YOUR OPINION WAS NOTED. AND RECYCLED" + }, + { + "id": 736, + "fortune": "YOU INTERRUPT WITH ENTHUSIASM. OFTEN" + }, + { + "id": 737, + "fortune": "RETAIL THERAPY IS STILL THERAPY. INVOICED" + }, + { + "id": 738, + "fortune": "YOUR PACKAGE ARRIVES TODAY. YOU ORDERED MORE" + }, + { + "id": 739, + "fortune": "YOU CAME FOR ONE ITEM. YOU LEFT WITH NINE" + }, + { + "id": 740, + "fortune": "YOUR WISHLIST IS A NOVEL NOW" + }, + { + "id": 741, + "fortune": "FREE SHIPPING COSTS YOU PLENTY" + }, + { + "id": 742, + "fortune": "YOUR RETURNS WINDOW CLOSED. LIKE ALWAYS" + }, + { + "id": 743, + "fortune": "YOU COMPARE PRICES. AFTER BUYING" + }, + { + "id": 744, + "fortune": "THE SALE ENDED. YOUR REGRET BEGINS" + }, + { + "id": 745, + "fortune": "YOUR LOYALTY CARD OUTRANKS YOUR GYM CARD" + }, + { + "id": 746, + "fortune": "YOU BUY ORGANIZERS TO ORGANISE ORGANIZERS" + }, + { + "id": 747, + "fortune": "YOUR HOME PROJECT IS 90 PERCENT DONE. FOREVER" + }, + { + "id": 748, + "fortune": "THE PAINT SAMPLES OUTLIVED THE PROJECT" + }, + { + "id": 749, + "fortune": "YOUR TOOLBOX HAS EVERYTHING BUT ANSWERS" + }, + { + "id": 750, + "fortune": "YOU MEASURED ONCE. IT SHOWS" + }, + { + "id": 751, + "fortune": "THE INSTRUCTIONS WERE OPTIONAL. APPARENTLY" + }, + { + "id": 752, + "fortune": "YOUR SHELF LEANS. YOU CALL IT CHARACTER" + }, + { + "id": 753, + "fortune": "DUCT TAPE IS NOT A PHILOSOPHY. YOURS IS" + }, + { + "id": 754, + "fortune": "YOUR SMART BULBS OUTSMART YOU NIGHTLY" + }, + { + "id": 755, + "fortune": "THE LEAK WAITED FOR THE LONG WEEKEND" + }, + { + "id": 756, + "fortune": "YOUR GAMING BACKLOG IS A SECOND CAREER" + }, + { + "id": 757, + "fortune": "ONE MORE LEVEL WAS THREE HOURS AGO" + }, + { + "id": 758, + "fortune": "YOUR CHARACTER HAS BETTER GEAR THAN YOU" + }, + { + "id": 759, + "fortune": "YOU PAUSED AN ONLINE GAME. BOLD MOVE" + }, + { + "id": 760, + "fortune": "YOUR HIGH SCORE IS SOMEONE ELSES WARMUP" + }, + { + "id": 761, + "fortune": "YOU RAGE QUIT GRACEFULLY. ALMOST" + }, + { + "id": 762, + "fortune": "YOUR BOOKSHELF JUDGES YOUR SCREEN TIME" + }, + { + "id": 763, + "fortune": "YOU BUY BOOKS FASTER THAN YOU READ THEM" + }, + { + "id": 764, + "fortune": "YOUR BOOKMARK HASNT MOVED SINCE MARCH" + }, + { + "id": 765, + "fortune": "YOU JOINED A BOOK CLUB FOR THE SNACKS" + }, + { + "id": 766, + "fortune": "THE AUDIOBOOK COUNTS. NOBODY ASKED" + }, + { + "id": 767, + "fortune": "YOUR TO BE READ PILE IS FURNITURE NOW" + }, + { + "id": 768, + "fortune": "YOU QUOTE BOOKS YOU HAVENT FINISHED" + }, + { + "id": 769, + "fortune": "YOUR KARAOKE SONG CLEARED THE ROOM. TWICE" + }, + { + "id": 770, + "fortune": "YOU SING IN THE CAR. THE CAR ENDURES" + }, + { + "id": 771, + "fortune": "YOUR SHOWER CONCERTS HAVE NO REFUNDS" + }, + { + "id": 772, + "fortune": "YOUR AIR GUITAR NEEDS TUNING SOMEHOW" + }, + { + "id": 773, + "fortune": "YOUR PLANT NAMES OUTNUMBER YOUR PLANTS" + }, + { + "id": 774, + "fortune": "YOU TALK TO YOUR PLANTS. THEY HEARD THAT" + }, + { + "id": 775, + "fortune": "YOUR SUCCULENT DIED. IMPRESSIVELY RARE" + }, + { + "id": 776, + "fortune": "THE FERN SAW EVERYTHING. IT STAYS QUIET" + }, + { + "id": 777, + "fortune": "YOUR GREEN THUMB IS MORE OF A BEIGE" + }, + { + "id": 778, + "fortune": "LUCK IS A LADDER. YOU BROUGHT A STOOL" + }, + { + "id": 779, + "fortune": "FORTUNE ARRIVES UNANNOUNCED. SO DO YOU" + }, + { + "id": 780, + "fortune": "YOUR CHARISMA WORKS OFFLINE ONLY" + }, + { + "id": 781, + "fortune": "YOU ARE A LIMITED EDITION. VERY LIMITED" + }, + { + "id": 782, + "fortune": "YOUR VIBE ATTRACTS YOUR TRIBE. EXPLAINS IT" + }, + { + "id": 783, + "fortune": "NORMAL IS A SETTING. YOURS IS CUSTOM" + }, + { + "id": 784, + "fortune": "NOT LAZY. JUST IN ENERGY SAVER MODE" + }, + { + "id": 785, + "fortune": "YOUR SARCASM IS A SECOND LANGUAGE. FLUENT" + }, + { + "id": 786, + "fortune": "YOU ARE TECHNICALLY CORRECT. THE WORST KIND" + }, + { + "id": 787, + "fortune": "YOUR EXCUSES SHOW REAL CRAFTSMANSHIP" + }, + { + "id": 788, + "fortune": "YOU PEAKED. THE TIMING WAS UNFORTUNATE" + }, + { + "id": 789, + "fortune": "YOUR COMFORT SHOW IS ON ITS NINTH RERUN" + }, + { + "id": 790, + "fortune": "YOU ARE DOING YOUR BEST. THE BEST VARIES" + }, + { + "id": 791, + "fortune": "YOUR POTENTIAL CALLED. IT LEFT NO MESSAGE" + }, + { + "id": 792, + "fortune": "YOU ARE SPECIAL. LIKE EVERYONE ELSE" + }, + { + "id": 793, + "fortune": "YOUR ENERGY TODAY IS DECORATIVE" + }, + { + "id": 794, + "fortune": "YOU ARE THE MAIN CHARACTER. OF A SIDE QUEST" + }, + { + "id": 795, + "fortune": "YOUR PLOT ARMOR HAS EXPIRED. WALK CAREFULLY" + }, + { + "id": 796, + "fortune": "YOUR REDEMPTION ARC IS IN PREPRODUCTION" + }, + { + "id": 797, + "fortune": "A COMPLIMENT NEARS. ACCEPT IT AWKWARDLY" + }, + { + "id": 798, + "fortune": "YOUR RESTING FACE HAS A REPUTATION" + }, + { + "id": 799, + "fortune": "YOU AGREED TO DISAGREE. YOU LOST" + }, + { + "id": 800, + "fortune": "YOUR EYE ROLL IS AUDIBLE SOMEHOW" + }, + { + "id": 801, + "fortune": "YOUR SIGH SPOKE PARAGRAPHS JUST NOW" + }, + { + "id": 802, + "fortune": "YOU SAID FINE. NOTHING WAS FINE" + }, + { + "id": 803, + "fortune": "YOUR THUMBS UP ENDED THREE FRIENDSHIPS" + }, + { + "id": 804, + "fortune": "NO WORRIES YOU SAID. WORRYING INTENSELY" + }, + { + "id": 805, + "fortune": "YOUR SHRUG IS DOING HEAVY LIFTING TODAY" + }, + { + "id": 806, + "fortune": "YOU SMILED THROUGH THAT. BARELY. WE SAW" + }, + { + "id": 807, + "fortune": "YOUR PATIENCE HAS A LOADING BAR. STUCK" + }, + { + "id": 808, + "fortune": "YOU FORGAVE THEM. THE SPREADSHEET REMAINS" + }, + { + "id": 809, + "fortune": "YOUR HINTS NEED SUBTITLES. STILL" + }, + { + "id": 810, + "fortune": "YOU ALMOST SAID IT. THE ALMOST WAS LOUD" + }, + { + "id": 811, + "fortune": "YOUR SILENCE HAS AN AGENDA. AS USUAL" + }, + { + "id": 812, + "fortune": "YOU LET IT GO. INTO YOUR PERMANENT RECORD" + }, + { + "id": 813, + "fortune": "YOUR CALM IS SUSPICIOUS. EVERYONE AGREES" + }, + { + "id": 814, + "fortune": "YOU TOOK THE HIGH ROAD. WITH COMMENTARY" + }, + { + "id": 815, + "fortune": "YOUR FEEDBACK SANDWICH IS ALL BREAD" + }, + { + "id": 816, + "fortune": "YOU HEARD THEM OUT. THEN PROCEEDED ANYWAY" + }, + { + "id": 817, + "fortune": "GOOD MORNING. THE BAR IS ALREADY MET" + }, + { + "id": 818, + "fortune": "YOUR OPTIMISM IS ADORABLE TODAY" + }, + { + "id": 819, + "fortune": "TODAY IS YOUR DAY. SHARE IT NICELY" + }, + { + "id": 820, + "fortune": "YOU WOKE UP LIKE THIS. CONDOLENCES" + }, + { + "id": 821, + "fortune": "THE MIRROR SAW YOU FIRST. IT COPES" + }, + { + "id": 822, + "fortune": "YOUR BEDHEAD HAS ARCHITECTURE NOW" + }, + { + "id": 823, + "fortune": "MONDAY SAW YOU COMING. IT PREPARED" + }, + { + "id": 824, + "fortune": "YOUR WEEKEND ENDED. IT SENDS REGARDS" + }, + { + "id": 825, + "fortune": "FRIDAY LOVES YOU. THE FEELING IS MUTUAL" + }, + { + "id": 826, + "fortune": "YOUR LUNCH BREAK DESERVES A MEDAL. SO LONG" + }, + { + "id": 827, + "fortune": "HUMP DAY IS A STATE OF MIND. YOURS DAILY" + }, + { + "id": 828, + "fortune": "YOUR OUTFIT SAYS EFFORT. THE CLOCK SAYS RUSH" + }, + { + "id": 829, + "fortune": "YOUR HAIR HAS PLANS OF ITS OWN TODAY" + }, + { + "id": 830, + "fortune": "YOU MATCHED YOUR SOCKS. A CEREMONY IS DUE" + }, + { + "id": 831, + "fortune": "YOUR SUNNIES HIDE NOTHING. NICE TRY" + }, + { + "id": 832, + "fortune": "DRESS FOR THE JOB YOU WANT. A NAP TESTER" + }, + { + "id": 833, + "fortune": "YOUR IRONING BOARD RETIRED YEARS AGO" + }, + { + "id": 834, + "fortune": "WRINKLES ARE A TEXTURE. YOU DECIDED" + }, + { + "id": 835, + "fortune": "YOUR FASHION CYCLE IS LAUNDRY BASED" + }, + { + "id": 836, + "fortune": "YOUR SHOES MATCH. THE OCCASION DOESNT" + }, + { + "id": 837, + "fortune": "YOU WILL WIN AN ARGUMENT. IN THE SHOWER" + }, + { + "id": 838, + "fortune": "YOUR COMEBACK ARRIVED. THREE DAYS LATE" + }, + { + "id": 839, + "fortune": "YOUR WIT IS QUICK. YOUR TIMING ISNT" + }, + { + "id": 840, + "fortune": "YOU HAD THE PERFECT REPLY. AT MIDNIGHT" + }, + { + "id": 841, + "fortune": "YOUR INNER MONOLOGUE NEEDS AN EDITOR" + }, + { + "id": 842, + "fortune": "YOUR HOT TAKES ARE ROOM TEMPERATURE" + }, + { + "id": 843, + "fortune": "YOUR OPINIONS ARRIVE PRE HEATED" + }, + { + "id": 844, + "fortune": "YOUR DEBATE STYLE IS VOLUME BASED" + }, + { + "id": 845, + "fortune": "YOU FACT CHECK OTHERS. NEVER YOURSELF" + }, + { + "id": 846, + "fortune": "YOUR TRIVIA KNOWLEDGE PEAKS AT PARTIES ONLY" + }, + { + "id": 847, + "fortune": "A DECISION AWAITS. FLIP A COIN. IGNORE IT" + }, + { + "id": 848, + "fortune": "YOUR PRO CON LIST HAS ONE COLUMN" + }, + { + "id": 849, + "fortune": "YOU ASKED EVERYONE. THEN DID YOUR THING" + }, + { + "id": 850, + "fortune": "YOUR GUT FEELING NEEDS A SECOND OPINION" + }, + { + "id": 851, + "fortune": "YOU SLEPT ON IT. THE PROBLEM STAYED AWAKE" + }, + { + "id": 852, + "fortune": "YOUR PLAN B IS PLAN A WITH REGRET" + }, + { + "id": 853, + "fortune": "YOU CHOSE CHAOS. AGAIN. CONSISTENTLY" + }, + { + "id": 854, + "fortune": "YOUR BACKUP PLAN NEEDS A BACKUP PLAN" + }, + { + "id": 855, + "fortune": "COMMITMENT SCARES YOU. SO DOES THE MENU" + }, + { + "id": 856, + "fortune": "YOU ORDERED THE SAME THING. ADVENTUROUS" + }, + { + "id": 857, + "fortune": "CHANGE IS COMING. YOU WILL RESIST IT" + }, + { + "id": 858, + "fortune": "A SURPRISE AWAITS. YOU HATE SURPRISES" + }, + { + "id": 859, + "fortune": "GOOD NEWS COMES IN THREES. YOURS CARPOOLS" + }, + { + "id": 860, + "fortune": "YOUR HOROSCOPE QUIT. IT CITED BURNOUT" + }, + { + "id": 861, + "fortune": "MERCURY IS IN RETROGRADE. CONVENIENT EXCUSE" + }, + { + "id": 862, + "fortune": "YOUR TAROT READER NEEDED A BREAK AFTER YOU" + }, + { + "id": 863, + "fortune": "THE MAGIC 8 BALL SAID ASK SOMEONE ELSE" + }, + { + "id": 864, + "fortune": "YOUR PALM READER REQUESTED GLOVES" + }, + { + "id": 865, + "fortune": "THE CRYSTAL BALL FOGGED UP. ON PURPOSE" + }, + { + "id": 866, + "fortune": "YOUR TEA LEAVES SPELLED LUCK. SARCASTICALLY" + }, + { + "id": 867, + "fortune": "YOUR VISION QUEST FOUND THE COUCH" + }, + { + "id": 868, + "fortune": "THE UNIVERSE IS TESTING YOU. OPEN BOOK. STILL" + }, + { + "id": 869, + "fortune": "YOUR MANIFESTATIONS NEED A COSIGNER" + }, + { + "id": 870, + "fortune": "YOUR CHAKRAS ARE ALIGNED. WITH THE FRIDGE" + }, + { + "id": 871, + "fortune": "YOUR ZEN GARDEN NEEDS WEEDING. IRONIC" + }, + { + "id": 872, + "fortune": "YOUR MANTRA IS FIVE MORE MINUTES" + }, + { + "id": 873, + "fortune": "YOUR THIRD EYE NEEDS GLASSES TOO" + }, + { + "id": 874, + "fortune": "YOUR ENERGY CLEANSE MISSED A SPOT" + }, + { + "id": 875, + "fortune": "YOUR SAGE SMOKE SET OFF THE ALARM. FITTING" + }, + { + "id": 876, + "fortune": "INNER PEACE IS CLOSE. TRY THE OTHER DOOR" + }, + { + "id": 877, + "fortune": "A STRANGER WILL SMILE AT YOU. STAY CALM" + }, + { + "id": 878, + "fortune": "SOMEONE THOUGHT OF YOU TODAY. BRIEFLY" + }, + { + "id": 879, + "fortune": "YOU CROSSED SOMEONES MIND. IT KEPT WALKING" + }, + { + "id": 880, + "fortune": "AN ADMIRER WATCHES. IT IS YOUR CAT" + }, + { + "id": 881, + "fortune": "YOU WERE MENTIONED TODAY. CONTEXT UNKNOWN" + }, + { + "id": 882, + "fortune": "YOUR NAME CAME UP. THE ROOM WENT QUIET" + }, + { + "id": 883, + "fortune": "SOMEONE MISSES YOU. THEY LOST YOUR NUMBER" + }, + { + "id": 884, + "fortune": "YOU ARE UNFORGETTABLE. MANY HAVE TRIED" + }, + { + "id": 885, + "fortune": "YOUR ABSENCE WAS NOTICED. AND ENJOYED" + }, + { + "id": 886, + "fortune": "PEOPLE TALK ABOUT YOU. KEEP IT THAT WAY" + }, + { + "id": 887, + "fortune": "YOUR REPUTATION ARRIVED FIRST. APOLOGISE" + }, + { + "id": 888, + "fortune": "YOU MADE AN IMPRESSION. DENTS COUNT" + }, + { + "id": 889, + "fortune": "SOMEONE QUOTED YOU TODAY. INCORRECTLY" + }, + { + "id": 890, + "fortune": "YOU INSPIRED SOMEONE. TO DO THE OPPOSITE" + }, + { + "id": 891, + "fortune": "YOUR LEGACY IS SAFE. NOBODY CHECKED" + }, + { + "id": 892, + "fortune": "HISTORY WILL REMEMBER YOU. AS A FOOTNOTE" + }, + { + "id": 893, + "fortune": "YOUR BIOGRAPHY NEEDS A GHOSTWRITER. AND PLOT" + }, + { + "id": 894, + "fortune": "YOUR AUTOGRAPH IS WORTHLESS. FOR NOW" + }, + { + "id": 895, + "fortune": "FAME AWAITS. LOCAL FAME. VERY LOCAL" + }, + { + "id": 896, + "fortune": "YOUR FIFTEEN MINUTES ARE BUFFERING" + }, + { + "id": 897, + "fortune": "YOU WILL FIND YOUR KEYS. WHERE YOU LEFT THEM" + }, + { + "id": 898, + "fortune": "YOUR PHONE IS IN YOUR OTHER HAND. AGAIN" + }, + { + "id": 899, + "fortune": "YOU WALKED INTO A ROOM. THE REASON LEFT" + }, + { + "id": 900, + "fortune": "YOUR MEMORY IS FINE. IT JUST CURATES" + }, + { + "id": 901, + "fortune": "YOU FORGOT WHY YOU OPENED THE FRIDGE. SNACK" + }, + { + "id": 902, + "fortune": "YOUR MENTAL NOTES NEED A FILING SYSTEM" + }, + { + "id": 903, + "fortune": "YOU REMEMBERED THE TUNE. NOT THE TASK" + }, + { + "id": 904, + "fortune": "YOUR SHOPPING MEMORY EXPIRES AT THE STORE" + }, + { + "id": 905, + "fortune": "YOU KNOW THAT FACE. THE NAME ESCAPED. RUN" + }, + { + "id": 906, + "fortune": "YOUR BRAIN HAS TABS OPEN TOO. ALL FROZEN" + }, + { + "id": 907, + "fortune": "A GREAT IDEA CAME AND WENT. UNRECORDED" + }, + { + "id": 908, + "fortune": "YOU LOCKED THE DOOR. PROBABLY. GO CHECK" + }, + { + "id": 909, + "fortune": "YOUR TRAIN OF THOUGHT DEPARTED WITHOUT YOU" + }, + { + "id": 910, + "fortune": "YOU RETRACED YOUR STEPS. THEY LED TO SNACKS" + }, + { + "id": 911, + "fortune": "YOUR PASSWORD RESET NEEDS A PASSWORD RESET" + }, + { + "id": 912, + "fortune": "LIFE IS SHORT. YOUR MEETINGS ARENT" + }, + { + "id": 913, + "fortune": "LIFE GAVE YOU LEMONS. YOU FILED A COMPLAINT" + }, + { + "id": 914, + "fortune": "LIFE IS A JOURNEY. YOURS NEEDS A MAP" + }, + { + "id": 915, + "fortune": "LIFE IS WHAT HAPPENS WHILE YOU SCROLL" + }, + { + "id": 916, + "fortune": "LIFE HAS NO REMOTE. GET UP AND CHANGE IT" + }, + { + "id": 917, + "fortune": "LIFE IS NOT A RACE. YOU PARKED ANYWAY" + }, + { + "id": 918, + "fortune": "LIFE IS A GIFT. KEEP THE RECEIPT" + }, + { + "id": 919, + "fortune": "LIFE IS UNSCRIPTED. YOURS NEEDS A WRITER" + }, + { + "id": 920, + "fortune": "LIFE REWARDS ACTION. YOURS SENT A MEMO" + }, + { + "id": 921, + "fortune": "LIFE IS A CLASSROOM. YOU SIT IN BACK" + }, + { + "id": 922, + "fortune": "YOUR STORY HAS PLOT HOLES. EMBRACE THEM" + }, + { + "id": 923, + "fortune": "YOUR CHAPTER TWO NEEDS CHAPTER ONE DONE" + }, + { + "id": 924, + "fortune": "YOUR SEQUEL DEPENDS ON THIS PART. NO PRESSURE" + }, + { + "id": 925, + "fortune": "YOUR NARRATOR SOUNDS TIRED LATELY" + }, + { + "id": 926, + "fortune": "YOUR CLIFFHANGER IS JUST INDECISION" + }, + { + "id": 927, + "fortune": "TOMORROW IS A NEW DAY. SAME YOU THOUGH" + }, + { + "id": 928, + "fortune": "YESTERDAY CALLED. IT WANTS NOTHING BACK" + }, + { + "id": 929, + "fortune": "TODAY WILL BE PRODUCTIVE. STARTING LATER" + }, + { + "id": 930, + "fortune": "THIS WEEK HAS POTENTIAL. HAD. HAS. UNCLEAR" + }, + { + "id": 931, + "fortune": "NEXT MONTH YOU WILL START. NEXT MONTH AGREES" + }, + { + "id": 932, + "fortune": "THE YEAR IS HALF OVER. YOUR GOALS ARE INTACT" + }, + { + "id": 933, + "fortune": "SOON IS NOT A DATE. YOU TREAT IT AS ONE" + }, + { + "id": 934, + "fortune": "EVENTUALLY IS YOUR FAVOURITE DEADLINE" + }, + { + "id": 935, + "fortune": "THE RIGHT TIME NEVER COMES. CONVENIENT" + }, + { + "id": 936, + "fortune": "YOUR WINDOW OF OPPORTUNITY HAS BLINDS" + }, + { + "id": 937, + "fortune": "PATIENCE COMES TO THOSE WHO WAIT. IRONIC" + }, + { + "id": 938, + "fortune": "YOUR TURN IS COMING. THE LINE MOVED ON" + }, + { + "id": 939, + "fortune": "YOU WAITED FOR A SIGN. THIS IS NOT IT" + }, + { + "id": 940, + "fortune": "HOLD THAT THOUGHT. FOREVER IF POSSIBLE" + }, + { + "id": 941, + "fortune": "YOUR PAUSE BUTTON IS YOUR FAVOURITE" + }, + { + "id": 942, + "fortune": "YOU PUT A PIN IN IT. THE PIN CUSHION IS FULL" + }, + { + "id": 943, + "fortune": "IT IS ON YOUR RADAR. YOUR RADAR IS OFF" + }, + { + "id": 944, + "fortune": "YOU WILL GET TO IT. IT STOPPED WAITING" + }, + { + "id": 945, + "fortune": "THE BALL IS IN YOUR COURT. GATHERING DUST" + }, + { + "id": 946, + "fortune": "YOUR FOLLOW UP NEEDS A FOLLOW UP" + }, + { + "id": 947, + "fortune": "CONSIDER THIS YOUR REMINDER. THE FOURTH" + }, + { + "id": 948, + "fortune": "YOUR INTENTIONS ARE GOOD. AND STATIONARY" + }, + { + "id": 949, + "fortune": "EFFORT WAS MADE. A ROUNDING ERROR OF IT" + }, + { + "id": 950, + "fortune": "YOU GAVE 100 PERCENT. OF YOUR MINIMUM" + }, + { + "id": 951, + "fortune": "YOUR BEST GUESS BEAT YOUR RESEARCH. AGAIN" + }, + { + "id": 952, + "fortune": "CLOSE ENOUGH IS YOUR SIGNATURE MOVE" + }, + { + "id": 953, + "fortune": "GOOD ENOUGH SHIPPED. PERFECTION SULKS" + }, + { + "id": 954, + "fortune": "YOUR SHORTCUTS TOOK THE LONG WAY" + }, + { + "id": 955, + "fortune": "YOU IMPROVISED. THE RESULTS IMPROVISED BACK" + }, + { + "id": 956, + "fortune": "YOUR WINGING IT HAS FREQUENT FLYER MILES" + }, + { + "id": 957, + "fortune": "DETAILS MATTER. YOURS WENT ON STRIKE" + }, + { + "id": 958, + "fortune": "YOUR ROUGH DRAFT WENT TO PRODUCTION" + }, + { + "id": 959, + "fortune": "YOU SKIMMED IT. IT SHOWED. IT ALWAYS SHOWS" + }, + { + "id": 960, + "fortune": "YOUR PROOFREADING MISSED THIS SENTENCE TOO" + }, + { + "id": 961, + "fortune": "ALMOST DONE IS YOUR PERMANENT ADDRESS" + }, + { + "id": 962, + "fortune": "YOUR CHECKLIST HAS SURVIVORS" + }, + { + "id": 963, + "fortune": "DONE IS BETTER THAN PERFECT. TRY EITHER" + }, + { + "id": 964, + "fortune": "YOUR STANDARDS SLIPPED. THEY LEFT A NOTE" + }, + { + "id": 965, + "fortune": "MEDIOCRITY TAKES EFFORT TOO. WELL DONE" + }, + { + "id": 966, + "fortune": "YOU EXCEEDED EXPECTATIONS. THEY WERE LOW" + }, + { + "id": 967, + "fortune": "YOUR BARE MINIMUM HAS A LOYAL FOLLOWING" + }, + { + "id": 968, + "fortune": "YOU RAISED THE BAR. FROM THE FLOOR" + }, + { + "id": 969, + "fortune": "CONSISTENCY IS KEY. YOURS IS CONSISTENT" + }, + { + "id": 970, + "fortune": "YOUR AVERAGE IS ABOVE AVERAGE. AT AVERAGING" + }, + { + "id": 971, + "fortune": "PROGRESS WAS MADE. LATERALLY. BUT MADE" + }, + { + "id": 972, + "fortune": "YOUR TRAJECTORY IS STABLE. FLAT. STABLE" + }, + { + "id": 973, + "fortune": "ONWARD AND UPWARD. OR SIDEWAYS. ONWARD" + }, + { + "id": 974, + "fortune": "YOU PIVOTED. THE DIRECTION WAS RANDOM" + }, + { + "id": 975, + "fortune": "YOUR MOMENTUM TOOK A PERSONAL DAY" + }, + { + "id": 976, + "fortune": "FULL SPEED AHEAD. YOUR SPEED. SO GENTLE" + }, + { + "id": 977, + "fortune": "YOU HIT THE GROUND WALKING. BRISKLY EVEN" + }, + { + "id": 978, + "fortune": "YOUR SPRINT BECAME A STROLL. SCENIC ONE" + }, + { + "id": 979, + "fortune": "BABY STEPS COUNT. YOURS ARE NEWBORN" + }, + { + "id": 980, + "fortune": "YOU ARE ON A ROLL. A SLOW GENTLE ROLL" + }, + { + "id": 981, + "fortune": "YOUR STREAK CONTINUES. WHICHEVER ONE" + }, + { + "id": 982, + "fortune": "MOMENTUM IS BUILDING. SOMEWHERE ELSE" + }, + { + "id": 983, + "fortune": "THE FINISH LINE MOVED. SO DID YOU. BACKWARD" + }, + { + "id": 984, + "fortune": "YOUR MARATHON IS A SERIES OF SNACK BREAKS" + }, + { + "id": 985, + "fortune": "YOU CROSSED A LINE TODAY. NOT THE FINISH ONE" + }, + { + "id": 986, + "fortune": "VICTORY IS NEAR. DEFINE VICTORY LOOSELY" + }, + { + "id": 987, + "fortune": "YOU WON THE ARGUMENT. THE ROOM WAS EMPTY" + }, + { + "id": 988, + "fortune": "CHAMPIONS TRAIN DAILY. YOU WATCHED THEM" + }, + { + "id": 989, + "fortune": "YOUR TROPHY SHELF HOLDS PARTICIPATION" + }, + { + "id": 990, + "fortune": "SECOND PLACE IS FIRST LOSER. YOU GOT FIFTH" + }, + { + "id": 991, + "fortune": "YOUR COMEBACK SEASON IS ALWAYS NEXT SEASON" + }, + { + "id": 992, + "fortune": "THE UNDERDOG STORY NEEDS AN ATTEMPT FIRST" + }, + { + "id": 993, + "fortune": "YOUR RIVALS STOPPED CHECKING ON YOU" + }, + { + "id": 994, + "fortune": "GLORY AWAITS. IT DOUBLE BOOKED THOUGH" + }, + { + "id": 995, + "fortune": "YOU MADE THE HIGHLIGHT REEL. AS A BLOOPER" + }, + { + "id": 996, + "fortune": "HISTORY FAVOURS THE BOLD. YOU FAVOUR NAPS" + }, + { + "id": 997, + "fortune": "YOUR SPLIT FLAP DISPLAY DESERVED BETTER TEXT" + }, + { + "id": 998, + "fortune": "THIS MESSAGE USED 45 CHARACTERS WISELY. ISH" + }, + { + "id": 999, + "fortune": "YOU BUILT A DISPLAY FOR THIS. WORTH IT" + }, + { + "id": 1000, + "fortune": "EACH FLAP TURNED FOR THIS WISDOM. SAVOR IT" + }, + { + "id": 1001, + "fortune": "SHE WILL BE RIGHT. SHE IS NOT RIGHT" + }, + { + "id": 1002, + "fortune": "NO WORRIES. THERE ARE SEVERAL WORRIES" + }, + { + "id": 1003, + "fortune": "YOUR ARVO PLANS BECAME A NAP. GOOD CALL" + }, + { + "id": 1004, + "fortune": "A BIN CHICKEN NICKED YOUR CHIPS. FAIR ENOUGH" + }, + { + "id": 1005, + "fortune": "YOU ARE FLAT OUT LIKE A LIZARD DRINKING. STILL BROKE" + }, + { + "id": 1006, + "fortune": "YOUR SERVO PIE IS THE HIGHLIGHT OF THE WEEK" + }, + { + "id": 1007, + "fortune": "A BIT DODGY MATE. LIKE YOUR PLANS" + }, + { + "id": 1008, + "fortune": "YOUR ESKY IS CHOCKERS. YOUR WALLET ISNT" + }, + { + "id": 1009, + "fortune": "HEAPS GOOD NEWS AHEAD. HEAPS DELAYED" + }, + { + "id": 1010, + "fortune": "YOUR THONGS BROKE AT THE WORST TIME. AS THEY DO" + }, + { + "id": 1011, + "fortune": "A MACCAS RUN AT MIDNIGHT COUNTS AS A PLAN" + }, + { + "id": 1012, + "fortune": "YOU RECKON IT WILL WORK. YOU RECKON HEAPS OF THINGS" + }, + { + "id": 1013, + "fortune": "STOP CARRYING ON LIKE A PORK CHOP" + }, + { + "id": 1014, + "fortune": "YOUR SUNNIES ARE ON YOUR HEAD. AS ALWAYS" + }, + { + "id": 1015, + "fortune": "TOO EASY MATE. NARR IT WAS NOT" + }, + { + "id": 1016, + "fortune": "YOUR BARBIE PLANS MET A SUDDEN SOUTHERLY" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_en-gb.json b/apps/sarcastic-fortune-cookies/fortunes_en-gb.json new file mode 100644 index 0000000..e6a76b7 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_en-gb.json @@ -0,0 +1,4066 @@ +[ + { + "id": 1, + "fortune": "EVERYTHING HAPPENS. RARELY FOR A REASON" + }, + { + "id": 2, + "fortune": "GOOD LUCK IS COMING. IT WALKS SLOWLY" + }, + { + "id": 3, + "fortune": "THE UNIVERSE HAS A PLAN. A MODEST ONE" + }, + { + "id": 4, + "fortune": "YOUR DESTINY CALLED. IT RESCHEDULED" + }, + { + "id": 5, + "fortune": "FATE HAS PLANS FOR YOU. BACKUP PLANS" + }, + { + "id": 6, + "fortune": "THE STARS ALIGNED. THEN THEY SAW YOU" + }, + { + "id": 7, + "fortune": "LUCK FAVOURS THE BOLD. YOU CAN WATCH" + }, + { + "id": 8, + "fortune": "YOUR SHIP IS COMING IN. IT IS A CANOE" + }, + { + "id": 9, + "fortune": "TRUST THE PROCESS. IT DOES NOT TRUST YOU" + }, + { + "id": 10, + "fortune": "A SIGN IS COMING. IT SAYS YIELD" + }, + { + "id": 11, + "fortune": "YOUR LUCKY STAR IS IN ANOTHER GALAXY" + }, + { + "id": 12, + "fortune": "KARMA IS REAL. THAT EXPLAINS A LOT" + }, + { + "id": 13, + "fortune": "THE FUTURE IS BRIGHT. WEAR SUNSCREEN" + }, + { + "id": 14, + "fortune": "DESTINY AWAITS. IT BROUGHT A BOOK" + }, + { + "id": 15, + "fortune": "MIRACLES HAPPEN DAILY. ELSEWHERE MOSTLY" + }, + { + "id": 16, + "fortune": "YOUR MOMENT IS COMING. IT IS IN TRAFFIC" + }, + { + "id": 17, + "fortune": "FORTUNE KNOCKED ONCE. YOU WERE OUT" + }, + { + "id": 18, + "fortune": "THE TIDE IS TURNING. GLACIALLY" + }, + { + "id": 19, + "fortune": "BIG THINGS ARE COMING. LOWER THE BAR" + }, + { + "id": 20, + "fortune": "OPPORTUNITY IS NEAR. YOU TWO KEEP MISSING" + }, + { + "id": 21, + "fortune": "THE COSMOS HEARD YOU. YOU ARE IN THE QUEUE" + }, + { + "id": 22, + "fortune": "YOUR STARS ARE FINE. YOUR CHOICES ARENT" + }, + { + "id": 23, + "fortune": "WISH ON A STAR. THE STAR MARKED IT SPAM" + }, + { + "id": 24, + "fortune": "GOOD THINGS TAKE TIME. YOURS TAKE DECADES" + }, + { + "id": 25, + "fortune": "A WINDFALL NEARS. DRESS IN LAYERS" + }, + { + "id": 26, + "fortune": "THE SIGNS WERE THERE. READING IS OPTIONAL" + }, + { + "id": 27, + "fortune": "YOU ARE ONE IN A MILLION. SO ARE THOUSANDS" + }, + { + "id": 28, + "fortune": "THE BEST IS YET TO COME. NO RUSH APPARENTLY" + }, + { + "id": 29, + "fortune": "YOUR AURA IS RADIANT. IT WORKS OVERTIME" + }, + { + "id": 30, + "fortune": "LADY LUCK SMILED. POLITELY. AT A STRANGER" + }, + { + "id": 31, + "fortune": "YOUR PRAYERS WERE HEARD. AND FILED" + }, + { + "id": 32, + "fortune": "ABUNDANCE FLOWS TO YOU. UPSTREAM SADLY" + }, + { + "id": 33, + "fortune": "FORTUNES WHEEL TURNS. YOU ARE THE HAMSTER" + }, + { + "id": 34, + "fortune": "EVERY CLOUD HAS A LINING. YOURS IS DAMP" + }, + { + "id": 35, + "fortune": "SERENDIPITY IS ASKING AROUND ABOUT YOU" + }, + { + "id": 36, + "fortune": "A LUCKY BREAK NEARS. BREAK HAS TWO MEANINGS" + }, + { + "id": 37, + "fortune": "THE ORACLE SPOKE. MOSTLY IT SIGHED" + }, + { + "id": 38, + "fortune": "YOUR HOROSCOPE LOOKS GREAT. IT IS FICTION" + }, + { + "id": 39, + "fortune": "COSMIC JUSTICE EXISTS. SETTLE OUT OF COURT" + }, + { + "id": 40, + "fortune": "LIGHTNING WONT STRIKE TWICE. YOU MIGHT" + }, + { + "id": 41, + "fortune": "FATE REWARDS PATIENCE. INVOICE PENDING" + }, + { + "id": 42, + "fortune": "THE MOON SAW YOUR FRESH START. AGAIN" + }, + { + "id": 43, + "fortune": "YOUR SPIRIT GUIDE REQUESTED A TRANSFER" + }, + { + "id": 44, + "fortune": "ANGELS WATCH OVER YOU. TAKING NOTES" + }, + { + "id": 45, + "fortune": "BELIEVE AND RECEIVE. RECEIPTS VARY" + }, + { + "id": 46, + "fortune": "YOUR GOLDEN ERA NEARS. GOLD PLATED" + }, + { + "id": 47, + "fortune": "WHAT IS MEANT FOR YOU IS NOT HURRYING" + }, + { + "id": 48, + "fortune": "THE UNIVERSE WINKED. OR HAD AN EYE ISSUE" + }, + { + "id": 49, + "fortune": "YOUR LUCK IS CHANGING. DIRECTION UNCLEAR" + }, + { + "id": 50, + "fortune": "PROVIDENCE PROVIDES. IT CHECKS RECEIPTS" + }, + { + "id": 51, + "fortune": "SUCCESS IS NEAR. SO IS THE SNOOZE BUTTON" + }, + { + "id": 52, + "fortune": "HARD WORK PAYS OFF. IN EXPOSURE" + }, + { + "id": 53, + "fortune": "YOUR POTENTIAL IS LIMITLESS. AND UNUSED" + }, + { + "id": 54, + "fortune": "DREAM BIG. SET AN ALARM THOUGH" + }, + { + "id": 55, + "fortune": "THE EARLY BIRD LEFT WITHOUT YOU" + }, + { + "id": 56, + "fortune": "YOUR BIG BREAK NEARS. DO NOT BREAK IT" + }, + { + "id": 57, + "fortune": "ROME WASNT BUILT IN A DAY. YOURS ISNT STARTED" + }, + { + "id": 58, + "fortune": "YOUR TALENTS WILL BE FOUND. WITH A WARRANT" + }, + { + "id": 59, + "fortune": "AIM FOR THE STARS. MIND THE CEILING" + }, + { + "id": 60, + "fortune": "WINNERS NEVER QUIT. YOU FOUND COASTING" + }, + { + "id": 61, + "fortune": "YOUR IDEAS ARE AHEAD. YOUR DEADLINES BEHIND" + }, + { + "id": 62, + "fortune": "EXCELLENCE IS A HABIT. SO IS YOURS" + }, + { + "id": 63, + "fortune": "YOUR WORK SPEAKS. IT REQUESTED A LAWYER" + }, + { + "id": 64, + "fortune": "THE TOP IS LONELY. YOU SOLVED THAT PROBLEM" + }, + { + "id": 65, + "fortune": "A PROMOTION NEARS. SOMEONE ELSES" + }, + { + "id": 66, + "fortune": "YOUR RESUME IMPRESSES FICTION FANS" + }, + { + "id": 67, + "fortune": "YOUR BEST WORK IS AHEAD. IT IS VERY FAST" + }, + { + "id": 68, + "fortune": "THAT MEETING COULD HAVE BEEN AN EMAIL" + }, + { + "id": 69, + "fortune": "YOUR INBOX IS NOT YOUR ENEMY. JUST A WITNESS" + }, + { + "id": 70, + "fortune": "DEADLINES FEAR NOTHING. YOU WALK PAST THEM" + }, + { + "id": 71, + "fortune": "YOUR FIVE YEAR PLAN IS FIVE YEARS OLD" + }, + { + "id": 72, + "fortune": "SLOW AND STEADY WINS. YOU NAILED SLOW" + }, + { + "id": 73, + "fortune": "YOUR CALENDAR IS FULL. OF BUFFERS" + }, + { + "id": 74, + "fortune": "YOUR TEAM DREAMS TOO. OF TRANSFERS" + }, + { + "id": 75, + "fortune": "THE OCCASION LOWERED ITSELF TO MEET YOU" + }, + { + "id": 76, + "fortune": "SUCCESS LEAVES CLUES. YOU PREFER MYSTERY" + }, + { + "id": 77, + "fortune": "YOUR COMFORT ZONE NEEDS ITS OWN POSTCODE" + }, + { + "id": 78, + "fortune": "QUALITY OVER QUANTITY. YOU DECLINED BOTH" + }, + { + "id": 79, + "fortune": "YOUR INSTINCTS ARE SHARP. FACTS ON SABBATICAL" + }, + { + "id": 80, + "fortune": "YOU WORK WELL UNDER PRESSURE. IT DISAGREES" + }, + { + "id": 81, + "fortune": "MASTERY TAKES 10000 HOURS. YOU HAVE 40" + }, + { + "id": 82, + "fortune": "YOUR DESK PLANT BELIEVED IN YOU. AND WATER" + }, + { + "id": 83, + "fortune": "THE PRINTER KNOWS YOU ARE IN A HURRY" + }, + { + "id": 84, + "fortune": "YOUR LEGACY IS UNDER CONSTRUCTION. STILL" + }, + { + "id": 85, + "fortune": "AN AWARD AWAITS. PARTICIPATION COUNTS" + }, + { + "id": 86, + "fortune": "YOUR CAN DO ATTITUDE MET YOUR DID NOT RECORD" + }, + { + "id": 87, + "fortune": "NETWORKING OPENS DOORS. TRY KNOCKING TOO" + }, + { + "id": 88, + "fortune": "YOU LEAD BY EXAMPLE. HR WANTS A NEW ONE" + }, + { + "id": 89, + "fortune": "YOUR SIDE HUSTLE JOINED THE OTHERS. RESTING" + }, + { + "id": 90, + "fortune": "GENIUS IS 1 PERCENT WORK. YOU STOPPED THERE" + }, + { + "id": 91, + "fortune": "YOUR OUT OF OFFICE REPLY IS YOUR BEST WORK" + }, + { + "id": 92, + "fortune": "FAILURE IS A STEPPING STONE. NICE STAIRCASE" + }, + { + "id": 93, + "fortune": "YOU ARE IRREPLACEABLE. THE POSTING IS DRAFTED" + }, + { + "id": 94, + "fortune": "YOUR PERFORMANCE REVIEW NEARS. REHEARSE" + }, + { + "id": 95, + "fortune": "EFFICIENCY IS YOUR MIDDLE NAME. LEGALLY ONLY" + }, + { + "id": 96, + "fortune": "YOU WILL LAND ON YOUR FEET. LANDING DELAYED" + }, + { + "id": 97, + "fortune": "THE SUMMIT IS CLOSE. SO IS BASE CAMP" + }, + { + "id": 98, + "fortune": "YOUR AMBITION WOKE UP. YOUR ALARM DID NOT" + }, + { + "id": 99, + "fortune": "BE YOURSELF. EVERYONE ELSE WAS ALARMED" + }, + { + "id": 100, + "fortune": "KNOW THYSELF. A BRIEF INTRO MAY HELP" + }, + { + "id": 101, + "fortune": "YOUR GLOW UP IS COMING. NOTIFY THE GRID" + }, + { + "id": 102, + "fortune": "NEW YEAR NEW YOU. THE OLD YOU LEFT NOTES" + }, + { + "id": 103, + "fortune": "YOU ARE ENOUGH. THE BAR WAS ADJUSTABLE" + }, + { + "id": 104, + "fortune": "YOUR INNER PEACE SAW YOUR SCHEDULE. IT LEFT" + }, + { + "id": 105, + "fortune": "GROWTH TAKES TIME. YOURS FILED AN EXTENSION" + }, + { + "id": 106, + "fortune": "YOU ARE A WORK IN PROGRESS. MOSTLY WORK" + }, + { + "id": 107, + "fortune": "SELF AWARENESS IS A GIFT. YOURS SHIPPED" + }, + { + "id": 108, + "fortune": "HEALING IS NOT LINEAR. YOURS IS A SCRIBBLE" + }, + { + "id": 109, + "fortune": "YOUR BEST SELF IS EMERGING. IT HIT SNOOZE" + }, + { + "id": 110, + "fortune": "SELF CARE MATTERS. STREAMING IS NOT A SPA" + }, + { + "id": 111, + "fortune": "YOUR BOUNDARIES ARE HEALTHY. AND UNTESTED" + }, + { + "id": 112, + "fortune": "GRATITUDE HELPS. TRY IT ON PEOPLE" + }, + { + "id": 113, + "fortune": "YOU FORGIVE EASILY. YOURSELF ESPECIALLY" + }, + { + "id": 114, + "fortune": "YOUR HABITS DEFINE YOU. OUR CONDOLENCES" + }, + { + "id": 115, + "fortune": "SMALL STEPS COUNT. EVEN TO THE FRIDGE" + }, + { + "id": 116, + "fortune": "YOUR INTUITION IS POWERFUL. AND WRONG" + }, + { + "id": 117, + "fortune": "MINDFULNESS HELPS. YOUR PHONE DISAGREES" + }, + { + "id": 118, + "fortune": "YOU LET GO OF THE PAST. IT HAS YOUR ADDRESS" + }, + { + "id": 119, + "fortune": "YOUR MORNING ROUTINE IS SACRED. ALL 4 MINUTES" + }, + { + "id": 120, + "fortune": "YOU ARE LEARNING TO SAY NO. TO VEGETABLES" + }, + { + "id": 121, + "fortune": "YOUR WILLPOWER LIFTS ALMOST A WHOLE BISCUIT" + }, + { + "id": 122, + "fortune": "YOUR PURPOSE EXISTS. IT STAYS ANONYMOUS" + }, + { + "id": 123, + "fortune": "YOU EMBRACE CHANGE. MOSTLY COUCH CHANGE" + }, + { + "id": 124, + "fortune": "YOUR JOURNAL IS RAW AND HONEST. BOTH PAGES" + }, + { + "id": 125, + "fortune": "YOU LIVE YOUR TRUTH. FACT CHECK PENDING" + }, + { + "id": 126, + "fortune": "YOUR INNER CRITIC ONLY SIGHS NOW" + }, + { + "id": 127, + "fortune": "YOUR TRANSFORMATION NEEDED LABELLED PHOTOS" + }, + { + "id": 128, + "fortune": "YOUR GOALS ARE IN SIGHT. NICE BINOCULARS" + }, + { + "id": 129, + "fortune": "YOUR NEW HABITS LOOK FAMILIAR. SUSPICIOUSLY" + }, + { + "id": 130, + "fortune": "YOUR ENERGY IS MAGNETIC. TO OBLIGATIONS" + }, + { + "id": 131, + "fortune": "YOUR WALLS CAME DOWN. THE MOAT EXPANDED" + }, + { + "id": 132, + "fortune": "YOU CELEBRATE SMALL WINS. DAILY. SOMEONE MUST" + }, + { + "id": 133, + "fortune": "YOUR EVOLUTION PUZZLES DARWIN" + }, + { + "id": 134, + "fortune": "YOU PUT YOURSELF FIRST. THE LINE WAS SHORT" + }, + { + "id": 135, + "fortune": "YOUR REINVENTION TOUR CONTINUES. SAME SETLIST" + }, + { + "id": 136, + "fortune": "YOU ARE PRESENT. PHYSICALLY AT LEAST" + }, + { + "id": 137, + "fortune": "YOUR FRESH START STARTS MONDAY. A FUTURE ONE" + }, + { + "id": 138, + "fortune": "YOUR VISION BOARD IS STUNNING. AND RETIRED" + }, + { + "id": 139, + "fortune": "YOU HONOUR YOUR FEELINGS. AT FULL VOLUME" + }, + { + "id": 140, + "fortune": "YOUR CALM IS REAL. YOU STOPPED CHECKING EMAIL" + }, + { + "id": 141, + "fortune": "YOUR STANDARDS ARE RISING. FROM SEA LEVEL" + }, + { + "id": 142, + "fortune": "YOU ARE BLOOMING. LATE SEASON. STILL COUNTS" + }, + { + "id": 143, + "fortune": "YOUR DISCIPLINE IS THE STUFF OF LEGEND" + }, + { + "id": 144, + "fortune": "YOUR AFFIRMATIONS WORK. ON THE CEILING" + }, + { + "id": 145, + "fortune": "TRUE LOVE AWAITS. IT IS RUNNING LATE TOO" + }, + { + "id": 146, + "fortune": "YOUR SOULMATE EXISTS. COVERAGE MAY VARY" + }, + { + "id": 147, + "fortune": "ROMANCE IS IN THE AIR. SO IS POLLEN" + }, + { + "id": 148, + "fortune": "CUPID HAS YOUR ADDRESS. HE DROVE PAST TWICE" + }, + { + "id": 149, + "fortune": "YOUR HEART KNOWS THE WAY. YOUR TEXTS DONT" + }, + { + "id": 150, + "fortune": "LOVE IS BLIND. YOURS ALSO FORGETS" + }, + { + "id": 151, + "fortune": "YOUR EX THINKS OF YOU. AS A LESSON" + }, + { + "id": 152, + "fortune": "YOUR FLIRTING IS SUBTLE. UNDETECTABLE EVEN" + }, + { + "id": 153, + "fortune": "YOUR TYPE IS CONSISTENT. THAT IS THE PROBLEM" + }, + { + "id": 154, + "fortune": "SOMEONE ADMIRES YOU FROM AFAR. STAY THERE" + }, + { + "id": 155, + "fortune": "YOUR GREEN FLAGS ARE LOVELY. AND OUTNUMBERED" + }, + { + "id": 156, + "fortune": "LOVE CONQUERS ALL. IT REQUESTED BACKUP" + }, + { + "id": 157, + "fortune": "HEART ON YOUR SLEEVE. DRY CLEAN BOTH" + }, + { + "id": 158, + "fortune": "A TEXT FROM THE PAST NEARS. DO NOT REPLY" + }, + { + "id": 159, + "fortune": "YOUR CRUSH KNOWS YOU EXIST. AS A CONCEPT" + }, + { + "id": 160, + "fortune": "YOU LOVE DEEPLY. BRIEFLY. BUT DEEPLY" + }, + { + "id": 161, + "fortune": "YOUR HEART IS OPEN. SO IS YOUR TAB" + }, + { + "id": 162, + "fortune": "SPARKS WILL FLY. CHECK THE SMOKE ALARM" + }, + { + "id": 163, + "fortune": "YOU ARE READY FOR COMMITMENT. TO A COUCH" + }, + { + "id": 164, + "fortune": "YOUR MEET CUTE NEARS. A MEET ADEQUATE" + }, + { + "id": 165, + "fortune": "YOUR HEART HEALED. IT ADDED SECURITY" + }, + { + "id": 166, + "fortune": "LOVE IS PATIENT. IT HAD PRACTICE WITH YOU" + }, + { + "id": 167, + "fortune": "YOUR REBOUND GAME BEATS THE ORIGINAL" + }, + { + "id": 168, + "fortune": "YOUR HONEYMOON PHASE LASTED 11 DAYS" + }, + { + "id": 169, + "fortune": "YOUR PET IS YOUR BEST RELATIONSHIP. IT AGREES" + }, + { + "id": 170, + "fortune": "YOUR VOWS WILL MAKE PEOPLE CRY. THE GRAMMAR" + }, + { + "id": 171, + "fortune": "YOU ARE A CATCH. CATCH AND RELEASE EXISTS" + }, + { + "id": 172, + "fortune": "ABSENCE MAKES HEARTS FONDER. KEEP TESTING" + }, + { + "id": 173, + "fortune": "YOUR PERFECT MATCH EXISTS. THE APP GAVE UP" + }, + { + "id": 174, + "fortune": "YOUR RED FLAGS ARE MAROON NOW. PROGRESS" + }, + { + "id": 175, + "fortune": "LOVE AT FIRST SIGHT IS REAL. GET GLASSES" + }, + { + "id": 176, + "fortune": "YOUR HEART WANTS THINGS. SEE A SPECIALIST" + }, + { + "id": 177, + "fortune": "SOMEONE THINKS YOU ARE PERFECT. FROM AFAR" + }, + { + "id": 178, + "fortune": "YOU BELIEVE IN SECOND CHANCES. AND FIFTHS" + }, + { + "id": 179, + "fortune": "YOUR BREAKUP PLAYLIST GETS HEAVY USE" + }, + { + "id": 180, + "fortune": "YOU ARE WORTH THE WAIT. THE WAIT CONTINUES" + }, + { + "id": 181, + "fortune": "ROMANCE IS NOT DEAD. YOURS IS RESTING" + }, + { + "id": 182, + "fortune": "YOUR IN LAWS WILL ADORE YOU. EVENTUALLY" + }, + { + "id": 183, + "fortune": "YOUR DATING BIO IS HONEST. SELECTIVELY" + }, + { + "id": 184, + "fortune": "YOUR HUGS ARE GREAT. AND RARE. LIKE ECLIPSES" + }, + { + "id": 185, + "fortune": "SOMEONE DREAMS OF YOUR COOKING. IN FEAR" + }, + { + "id": 186, + "fortune": "YOUR CHARM OPENS DOORS. PUSH DONT PULL" + }, + { + "id": 187, + "fortune": "YOUR STANDARDS MET YOUR CHOICES. AWKWARD" + }, + { + "id": 188, + "fortune": "YOU WILL BE SWEPT AWAY. STRETCH FIRST" + }, + { + "id": 189, + "fortune": "INTIMACY MEANS BEING SEEN. YOU NEGOTIATED" + }, + { + "id": 190, + "fortune": "YOUR LOVE STORY WILL BE TOLD. AS A WARNING" + }, + { + "id": 191, + "fortune": "THE SPARK IS STILL THERE. SEND A SEARCH PARTY" + }, + { + "id": 192, + "fortune": "YOUR ANNIVERSARY NEARS. THIS IS THE REMINDER" + }, + { + "id": 193, + "fortune": "LOVE YOURSELF FIRST. YOU MASTERED THAT PART" + }, + { + "id": 194, + "fortune": "YOUR HEART SKIPPED A BEAT. SEE A DOCTOR" + }, + { + "id": 195, + "fortune": "YOU BRING OUT THE BEST. AS PEOPLE LEAVE" + }, + { + "id": 196, + "fortune": "YOU NEVER SETTLE. HENCE THE FOLDING CHAIRS" + }, + { + "id": 197, + "fortune": "YOUR FUTURE PARTNER IS TRAINING. UNKNOWINGLY" + }, + { + "id": 198, + "fortune": "YOU GET GREAT ADVICE. FOLLOWING IT IS NEW" + }, + { + "id": 199, + "fortune": "YOUR HEART IS A FORTRESS. GIFT SHOP OPEN" + }, + { + "id": 200, + "fortune": "YOUR FRIENDS VALUE YOUR HONESTY. FROM AFAR" + }, + { + "id": 201, + "fortune": "A FRIEND WILL CALL SOON. THEY NEED A LORRY" + }, + { + "id": 202, + "fortune": "YOU ARE THE GLUE. GLUE IS RARELY THANKED" + }, + { + "id": 203, + "fortune": "THE GROUP CHAT ENJOYS YOUR SILENCE" + }, + { + "id": 204, + "fortune": "TRUE FRIENDS ARE RARE. YOURS ARE HIDING" + }, + { + "id": 205, + "fortune": "YOUR LOYALTY IS UNMATCHED. YOUR TIMING ISNT" + }, + { + "id": 206, + "fortune": "A GATHERING BRINGS JOY. LEAVING BRINGS MORE" + }, + { + "id": 207, + "fortune": "YOU ARE THE FUN ONE. SELF REPORTED" + }, + { + "id": 208, + "fortune": "AN OLD FRIEND RESURFACES. THEY ARE MOVING" + }, + { + "id": 209, + "fortune": "YOUR ADVICE IS APPRECIATED. NOT REQUESTED" + }, + { + "id": 210, + "fortune": "YOU LIGHT UP ROOMS. SOME WANT DIMMERS" + }, + { + "id": 211, + "fortune": "YOUR BIRTHDAY WILL BE REMEMBERED. LATE" + }, + { + "id": 212, + "fortune": "YOUR STORIES IMPROVE YEARLY. ACCURACY DROPS" + }, + { + "id": 213, + "fortune": "PEOPLE GRAVITATE TO YOU. GRAVITY PULLS DOWN" + }, + { + "id": 214, + "fortune": "YOU ALWAYS KNOW WHAT TO SAY. TIMING EXTRA" + }, + { + "id": 215, + "fortune": "FRIENDS COME AND GO. YOURS EXCEL AT GO" + }, + { + "id": 216, + "fortune": "YOUR SOCIAL CALENDAR IS FULL. OF MAYBES" + }, + { + "id": 217, + "fortune": "YOU ARE A PEOPLE PERSON. UNVERIFIED" + }, + { + "id": 218, + "fortune": "YOUR INSIDE JOKES ARE NOW SOLO ACTS" + }, + { + "id": 219, + "fortune": "YOUR HOSTING IMPROVES. THE FIRE DEPT AGREES" + }, + { + "id": 220, + "fortune": "YOU BRING PEOPLE TOGETHER. TO DISCUSS YOU" + }, + { + "id": 221, + "fortune": "YOUR GENEROSITY HAS OFFICE HOURS" + }, + { + "id": 222, + "fortune": "YOU NEVER FORGET A FACE. NAMES OPTED OUT" + }, + { + "id": 223, + "fortune": "YOUR PEP TALKS REQUIRE FOLLOW UP CARE" + }, + { + "id": 224, + "fortune": "YOU SHOW UP WHEN IT MATTERS. TO YOU" + }, + { + "id": 225, + "fortune": "YOUR GOING AWAY PARTIES DRAW CROWDS" + }, + { + "id": 226, + "fortune": "PEOPLE CONFIDE IN YOU. AND THEN IN OTHERS" + }, + { + "id": 227, + "fortune": "YOUR HONESTY IS REFRESHING. LIKE ICE WATER" + }, + { + "id": 228, + "fortune": "YOU NEVER HOLD GRUDGES. YOU ARCHIVE THEM" + }, + { + "id": 229, + "fortune": "YOUR MEMES ARRIVE AT DAWN. UNREQUESTED" + }, + { + "id": 230, + "fortune": "YOU ARE A SHOULDER TO CRY ON. BY APPOINTMENT" + }, + { + "id": 231, + "fortune": "YOUR CANCELLED DINNER PARTIES ARE LEGEND" + }, + { + "id": 232, + "fortune": "YOU KEEP EVERYONE GROUNDED. LIKE FOG" + }, + { + "id": 233, + "fortune": "YOUR ENTHUSIASM IS INFECTIOUS. MASKS EXIST" + }, + { + "id": 234, + "fortune": "A FRIEND WANTS YOUR HONEST OPINION. A TRAP" + }, + { + "id": 235, + "fortune": "YOU SPLIT BILLS FAIRLY. YOUR MATH DIFFERS" + }, + { + "id": 236, + "fortune": "YOUR PRESENCE IS A GIFT. REGIFTING HAPPENS" + }, + { + "id": 237, + "fortune": "YOUR COMPETITIVENESS RETIRED THE GAMES" + }, + { + "id": 238, + "fortune": "YOUR SURPRISE PARTIES SURPRISE NO ONE" + }, + { + "id": 239, + "fortune": "PEOPLE FEEL COMFORTABLE AROUND YOU. TO LEAVE" + }, + { + "id": 240, + "fortune": "YOU SAY WHAT EVERYONE THINKS. AT FUNERALS" + }, + { + "id": 241, + "fortune": "YOUR HOLIDAY LETTER HAS A READERSHIP" + }, + { + "id": 242, + "fortune": "YOUR APOLOGIES ARE HEARTFELT. AND FREQUENT" + }, + { + "id": 243, + "fortune": "YOU ARE THE KEEPER OF GROUP HISTORY. REVISED" + }, + { + "id": 244, + "fortune": "YOU NEVER MISS A CHANCE TO HELP. OR SAY SO" + }, + { + "id": 245, + "fortune": "YOUR DIRECTNESS IS CHARMING. AGREED WORD" + }, + { + "id": 246, + "fortune": "YOU ARE FASHIONABLY LATE. MINUS THE FASHION" + }, + { + "id": 247, + "fortune": "PEOPLE SEEK YOUR APPROVAL. TO END THE CHAT" + }, + { + "id": 248, + "fortune": "YOU NEVER GOSSIP. YOU BRIEF THE ABSENT" + }, + { + "id": 249, + "fortune": "YOUR INVITES SAY CASUAL. YOUR TEXTS DONT" + }, + { + "id": 250, + "fortune": "AN OLD FRIEND REMEMBERS YOU. FROM AFAR" + }, + { + "id": 251, + "fortune": "YOU NEVER LOSE ARGUMENTS. YOU RELOCATE THEM" + }, + { + "id": 252, + "fortune": "YOUR SUPPORT IS UNCONDITIONAL. SEE TERMS" + }, + { + "id": 253, + "fortune": "WEALTH IS COMING. IT HAS YOUR OLD ADDRESS" + }, + { + "id": 254, + "fortune": "MONEY FLOWS TO YOU. THROUGH YOU. GONE" + }, + { + "id": 255, + "fortune": "YOUR BUDGET IS ART. ABSTRACT ART" + }, + { + "id": 256, + "fortune": "SAVE FOR A RAINY DAY. MONSOONS FORECAST" + }, + { + "id": 257, + "fortune": "YOUR CREDIT SCORE IS A THRILLER" + }, + { + "id": 258, + "fortune": "YOUR SAVINGS GROW. CHARACTER MOSTLY" + }, + { + "id": 259, + "fortune": "MONEY TALKS. YOURS SAYS GOODBYE" + }, + { + "id": 260, + "fortune": "YOUR RETIREMENT PLAN IS A LOTTERY TICKET" + }, + { + "id": 261, + "fortune": "YOU HAVE EXPENSIVE TASTE. AND A BUDGET" + }, + { + "id": 262, + "fortune": "COMPOUND INTEREST IS MAGIC. YOU CHOSE DEBT" + }, + { + "id": 263, + "fortune": "YOUR EMERGENCY FUND COVERS SMALL EMERGENCIES" + }, + { + "id": 264, + "fortune": "A RAISE IS DESERVED. AND UNSCHEDULED" + }, + { + "id": 265, + "fortune": "YOUR CART IS A VISION BOARD WITH CHECKOUT" + }, + { + "id": 266, + "fortune": "YOUR GENEROSITY IS FAMOUS. AMONG VENDORS" + }, + { + "id": 267, + "fortune": "THE BEST THINGS ARE FREE. YOURS SHIP" + }, + { + "id": 268, + "fortune": "YOUR SUBSCRIPTIONS OUTNUMBER YOUR FRIENDS" + }, + { + "id": 269, + "fortune": "BUY LOW SELL HIGH. YOU INVENTED THE REVERSE" + }, + { + "id": 270, + "fortune": "YOUR BANK TEXTS OUT OF CONCERN NOW" + }, + { + "id": 271, + "fortune": "YOUR TAX REFUND HAS OTHER PLANS" + }, + { + "id": 272, + "fortune": "YOUR SPLURGES ARE STRATEGIC. ALLEGEDLY" + }, + { + "id": 273, + "fortune": "YOU WILL FIND MONEY IN A COAT. IT WAS YOURS" + }, + { + "id": 274, + "fortune": "YOUR PORTFOLIO IS DIVERSIFIED. IN REGRETS" + }, + { + "id": 275, + "fortune": "PAYDAY BRINGS JOY. ABOUT 18 HOURS OF IT" + }, + { + "id": 276, + "fortune": "YOUR LATE FEES HAVE LATE FEES NOW" + }, + { + "id": 277, + "fortune": "A PENNY SAVED IS A START. A SMALL ONE" + }, + { + "id": 278, + "fortune": "RICH IN SPIRIT. THE REGISTER DISAGREES" + }, + { + "id": 279, + "fortune": "YOUR RECEIPTS TELL A STORY. A LONG ONE" + }, + { + "id": 280, + "fortune": "YOUR DOWN PAYMENT BECAME SUSHI. TWICE" + }, + { + "id": 281, + "fortune": "YOUR BUDGET SHEET IS HISTORICAL FICTION" + }, + { + "id": 282, + "fortune": "YOUR FREE TRIALS NEVER DIE. THEY BILL" + }, + { + "id": 283, + "fortune": "CASH IS KING. YOUR KINGDOM RUNS ON CREDIT" + }, + { + "id": 284, + "fortune": "YOUR SPENDING FREEZE LASTED 40 MINUTES" + }, + { + "id": 285, + "fortune": "YOUR BILLS ARRIVE ON TIME. UNLIKE YOU" + }, + { + "id": 286, + "fortune": "YOUR MONEY WORKS HARD. FOR OTHER PEOPLE" + }, + { + "id": 287, + "fortune": "YOUR COUPONS EXPIRED. ALL OF THEM. TODAY" + }, + { + "id": 288, + "fortune": "YOUR FINANCIAL PLAN HAS PHASES. DENIAL FIRST" + }, + { + "id": 289, + "fortune": "YOUR DISCOUNTS FUND YOUR IMPULSE BUYS" + }, + { + "id": 290, + "fortune": "YOUR CRYPTO PHASE WAS EDUCATIONAL. AND COSTLY" + }, + { + "id": 291, + "fortune": "THE LOTTERY IS A HOPE TAX. YOU DONATE WEEKLY" + }, + { + "id": 292, + "fortune": "YOUR SAVINGS GOAL HASNT MOVED SINCE SPRING" + }, + { + "id": 293, + "fortune": "WEALTH WHISPERS. YOURS BLOCKED THE NUMBER" + }, + { + "id": 294, + "fortune": "YOU TRACK EVERY EXPENSE. THEN MAKE MORE" + }, + { + "id": 295, + "fortune": "YOUR PIGGY BANK HAS TRUST ISSUES. EARNED" + }, + { + "id": 296, + "fortune": "YOUR REFUND ARRIVED. ALREADY SPENT. TWICE" + }, + { + "id": 297, + "fortune": "MONEY CANT BUY HAPPINESS. YOURS QUIT TRYING" + }, + { + "id": 298, + "fortune": "YOUR INVOICES AGE LIKE FINE WINE. UNPAID" + }, + { + "id": 299, + "fortune": "YOUR NET WORTH AND SELF WORTH BOTH DIPPED" + }, + { + "id": 300, + "fortune": "PATIENCE IS A VIRTUE. YOU CHOSE OTHERS" + }, + { + "id": 301, + "fortune": "SILENCE IS GOLDEN. YOURS WOULD FUND A NATION" + }, + { + "id": 302, + "fortune": "THINK BEFORE YOU SPEAK. A PILOT PROGRAM" + }, + { + "id": 303, + "fortune": "STILL WATERS RUN DEEP. YOURS RUN ANKLE HIGH" + }, + { + "id": 304, + "fortune": "KNOWLEDGE IS POWER. YOURS IS ON STANDBY" + }, + { + "id": 305, + "fortune": "AN OPEN MIND IS A TREASURE. NICE BREEZE" + }, + { + "id": 306, + "fortune": "LISTEN TWICE SPEAK ONCE. INVERT YOUR RATIO" + }, + { + "id": 307, + "fortune": "THE TRUTH WILL SET YOU FREE. YOURS SAT DOWN" + }, + { + "id": 308, + "fortune": "LOOK BEFORE YOU LEAP. OR AFTER. YOUR WAY" + }, + { + "id": 309, + "fortune": "A FOOL AND HIS MONEY HAD A NICE CEREMONY" + }, + { + "id": 310, + "fortune": "ACTIONS SPEAK LOUDER. YOURS WHISPER" + }, + { + "id": 311, + "fortune": "MEASURE TWICE CUT ONCE. YOU CUT FIRST" + }, + { + "id": 312, + "fortune": "THE PEN IS MIGHTY. YOUR EMAILS ARE WEAPONS" + }, + { + "id": 313, + "fortune": "BETTER LATE THAN NEVER. YOU TEST THIS DAILY" + }, + { + "id": 314, + "fortune": "HONESTY IS THE BEST POLICY. READ THE RIDERS" + }, + { + "id": 315, + "fortune": "DONT COUNT YOUR CHICKENS. YOURS UNIONIZED" + }, + { + "id": 316, + "fortune": "GRASS IS GREENER WHERE WATERED. BUY A HOSE" + }, + { + "id": 317, + "fortune": "EVERY SAINT HAS A PAST. YOURS HAS A FILE" + }, + { + "id": 318, + "fortune": "PRACTICE WHAT YOU PREACH. OR PREACH LESS" + }, + { + "id": 319, + "fortune": "TWO WRONGS DONT MAKE A RIGHT. STOP AT NINE" + }, + { + "id": 320, + "fortune": "ALL THAT GLITTERS ISNT GOLD. CHECK RECEIPTS" + }, + { + "id": 321, + "fortune": "A ROLLING STONE GATHERS NO MOSS. NICE MOSS" + }, + { + "id": 322, + "fortune": "DONT PUT ALL EGGS IN ONE BASKET. FIND BASKET" + }, + { + "id": 323, + "fortune": "EMPTY VESSELS ARE LOUD. GREAT ACOUSTICS" + }, + { + "id": 324, + "fortune": "HE WHO LAUGHS LAST THOUGHT SLOWEST. HI" + }, + { + "id": 325, + "fortune": "A BIRD IN HAND IS WORTH TWO. YOURS FLEW" + }, + { + "id": 326, + "fortune": "IF IT AINT BROKE DONT FIX IT. TOO LATE" + }, + { + "id": 327, + "fortune": "YOU CAN LEAD A HORSE TO WATER. IT DECLINED" + }, + { + "id": 328, + "fortune": "PRIDE GOES BEFORE A FALL. NICE BALANCE" + }, + { + "id": 329, + "fortune": "TIME HEALS ALL WOUNDS. YOURS PICK AT IT" + }, + { + "id": 330, + "fortune": "OLD HABITS DIE HARD. YOURS BOUGHT INSURANCE" + }, + { + "id": 331, + "fortune": "WHERE THERE IS SMOKE THERE IS YOU" + }, + { + "id": 332, + "fortune": "THE BEST DEFENCE IS DISTANCE. THEY LEARNED" + }, + { + "id": 333, + "fortune": "FAMILIARITY BREEDS CONTEMPT. THRIVING HERE" + }, + { + "id": 334, + "fortune": "THE DEVIL IS IN THE DETAILS. YOURS ARE EMPTY" + }, + { + "id": 335, + "fortune": "ONE MANS RUBBISH IS YOUR GARAGE" + }, + { + "id": 336, + "fortune": "A WATCHED POT NEVER BOILS. YOURS BOILED OVER" + }, + { + "id": 337, + "fortune": "IGNORANCE IS BLISS. YOU SEEM SERENE" + }, + { + "id": 338, + "fortune": "BEAUTY IS IN THE EYE. GET THE EYE CHECKED" + }, + { + "id": 339, + "fortune": "IT TAKES A VILLAGE. YOURS REQUESTED BACKUP" + }, + { + "id": 340, + "fortune": "GREAT MINDS THINK ALIKE. YOURS WENT SOLO" + }, + { + "id": 341, + "fortune": "THE PROOF IS IN THE PUDDING. NO COMMENT" + }, + { + "id": 342, + "fortune": "EVERY DOG HAS ITS DAY. YOURS WAS A TUESDAY" + }, + { + "id": 343, + "fortune": "NOTHING VENTURED NOTHING GAINED. PERFECT TIE" + }, + { + "id": 344, + "fortune": "TOO MANY COOKS SPOIL BROTH. YOU SOLOED IT" + }, + { + "id": 345, + "fortune": "YOU REAP WHAT YOU SOW. INTERESTING HARVEST" + }, + { + "id": 346, + "fortune": "ASK AND RECEIVE. YOUR ASKING MADE A LINE" + }, + { + "id": 347, + "fortune": "WALK A MILE IN THEIR SHOES. RETURN THEM" + }, + { + "id": 348, + "fortune": "HASTE MAKES WASTE. YOU KEPT ONLY WASTE" + }, + { + "id": 349, + "fortune": "ALL GOOD THINGS END. YOURS END EARLY" + }, + { + "id": 350, + "fortune": "WORDS ARE CHEAP. YOURS ARE FREE" + }, + { + "id": 351, + "fortune": "TIME WAITS FOR NO ONE. IT MADE AN EXCEPTION" + }, + { + "id": 352, + "fortune": "DONT BITE THE FEEDING HAND. IT WEARS GLOVES" + }, + { + "id": 353, + "fortune": "COMPARISON STEALS JOY. YOURS HIRED IT" + }, + { + "id": 354, + "fortune": "HALF A LOAF BEATS NONE. YOU OFFER CRUMBS" + }, + { + "id": 355, + "fortune": "A SMOOTH SEA NEVER MADE A SAILOR. STAY DOCKED" + }, + { + "id": 356, + "fortune": "THE TRUTH NEEDS NO REHEARSAL. YOURS DOES" + }, + { + "id": 357, + "fortune": "EVERYTHING IN MODERATION. EVEN THAT. STOP" + }, + { + "id": 358, + "fortune": "WHAT GOES AROUND COMES AROUND. TRACK IT" + }, + { + "id": 359, + "fortune": "NEVER ARGUE WITH A FOOL. ONLOOKERS STRUGGLE" + }, + { + "id": 360, + "fortune": "WISDOM WHISPERS. YOURS IS ON MUTE" + }, + { + "id": 361, + "fortune": "A THOUSAND MILE JOURNEY STARTS. YOU STRETCH" + }, + { + "id": 362, + "fortune": "CROSS BRIDGES WHEN YOU REACH THEM. NOT BURN" + }, + { + "id": 363, + "fortune": "THE MIGHTY OAK WAS A NUT. HERITAGE PRESERVED" + }, + { + "id": 364, + "fortune": "FOOL ME ONCE. YOUR CARD HAS NINE STAMPS" + }, + { + "id": 365, + "fortune": "ADVENTURE AWAITS. IT OPENED A BUSINESS" + }, + { + "id": 366, + "fortune": "YOU WILL TRAVEL FAR. THE SHUTTLE COUNTS" + }, + { + "id": 367, + "fortune": "YOUR PASSPORT PHOTO IS THE REAL YOU" + }, + { + "id": 368, + "fortune": "YOUR BUCKET LIST NEEDS A BUCKET" + }, + { + "id": 369, + "fortune": "YOU WILL SEE THE WORLD. VIA DOCUMENTARY" + }, + { + "id": 370, + "fortune": "YOUR HOLIDAY DAYS AGE LIKE FINE GUILT" + }, + { + "id": 371, + "fortune": "AN EXOTIC PLACE CALLED. YOU SCREENED IT" + }, + { + "id": 372, + "fortune": "YOUR ROAD TRIP PLAYLIST OUTLIVED THE TRIP" + }, + { + "id": 373, + "fortune": "YOU PACK LIGHT. EMOTIONALLY YOU DONT" + }, + { + "id": 374, + "fortune": "YOUR SOUVENIRS TELL STORIES. ABOUT PRICING" + }, + { + "id": 375, + "fortune": "YOU WILL GET LOST ABROAD. A HOME SKILL" + }, + { + "id": 376, + "fortune": "YOUR TRAVEL PICS STAR YOUR THUMB" + }, + { + "id": 377, + "fortune": "A SPONTANEOUS TRIP NEARS. WITH SPREADSHEETS" + }, + { + "id": 378, + "fortune": "YOU ARE A WORLD CITIZEN. REFERENCES PENDING" + }, + { + "id": 379, + "fortune": "YOUR BEACH BODY IS READY. THE BEACH ADAPTED" + }, + { + "id": 380, + "fortune": "THE MOUNTAINS ARE CALLING. YOU MUTED THEM" + }, + { + "id": 381, + "fortune": "YOUR STAYCATION GAME IS UNRIVALED" + }, + { + "id": 382, + "fortune": "YOU NAVIGATE LIKE A LOCAL. A LOST ONE" + }, + { + "id": 383, + "fortune": "YOUR ITINERARY IS MOSTLY BUFFER TIME" + }, + { + "id": 384, + "fortune": "YOUR HIKING BOOTS SUMMITED THE CLOSET" + }, + { + "id": 385, + "fortune": "JET LAG RESPECTS NO ONE. YOU CAME PRE TIRED" + }, + { + "id": 386, + "fortune": "YOUR TRAVEL JOURNAL HAS ONE ENTRY. EXCITED" + }, + { + "id": 387, + "fortune": "YOU COLLECT EXPERIENCES. THE CARD DISAGREES" + }, + { + "id": 388, + "fortune": "YOUR SENSE OF DIRECTION IS A FAMILY LEGEND" + }, + { + "id": 389, + "fortune": "A GETAWAY NEARS. THE LAUNDRY WILL WAIT" + }, + { + "id": 390, + "fortune": "YOU WILL RETURN CHANGED. MOSTLY YOUR SLEEP" + }, + { + "id": 391, + "fortune": "YOUR AIRPORT TIMING IS A PERSONALITY TEST" + }, + { + "id": 392, + "fortune": "YOUR WINDOW SEAT PICS FEATURE THE WING" + }, + { + "id": 393, + "fortune": "YOUR CARRY ON HAS ITS OWN GRAVITY NOW" + }, + { + "id": 394, + "fortune": "YOUR CAMPING SKILLS AMUSE THE RACCOONS" + }, + { + "id": 395, + "fortune": "TIME ZONES CONFUSE YOUR SLEEP. IT COPES" + }, + { + "id": 396, + "fortune": "YOUR HOTEL REVIEWS ARE FEARED. BY TOWELS" + }, + { + "id": 397, + "fortune": "YOU BEFRIEND STRANGERS ABROAD. ALSO LOST ONES" + }, + { + "id": 398, + "fortune": "YOUR CRUISE PACE MATCHES YOUR BUFFET PACE" + }, + { + "id": 399, + "fortune": "FORTUNE FAVOURS TRAVELLERS. YOURS LIKES COUCHES" + }, + { + "id": 400, + "fortune": "YOUR PHONE BATTERY OUTLASTS YOUR DRIVE" + }, + { + "id": 401, + "fortune": "YOU WILL READ THE TERMS SOMEDAY. NO" + }, + { + "id": 402, + "fortune": "YOUR SCREEN TIME REPORT SOFTENS THE NEWS" + }, + { + "id": 403, + "fortune": "YOUR LAUNDRY CHAIR EARNED TENURE" + }, + { + "id": 404, + "fortune": "YOUR ALARM HAS FIVE BACKUPS. ALL IGNORED" + }, + { + "id": 405, + "fortune": "YOUR FRIDGE HOSTS A SCIENCE EXPERIMENT" + }, + { + "id": 406, + "fortune": "THE CHECK ENGINE LIGHT IS A MOOD LIGHT NOW" + }, + { + "id": 407, + "fortune": "YOUR HOUSEPLANTS ACCEPTED THEIR FATE" + }, + { + "id": 408, + "fortune": "YOUR JUNK DRAWER OPENED A SECOND LOCATION" + }, + { + "id": 409, + "fortune": "YOUR GYM BAG IS PACKED. THAT COUNTS" + }, + { + "id": 410, + "fortune": "YOUR VOICEMAIL IS FULL. PEOPLE MOVED ON" + }, + { + "id": 411, + "fortune": "YOUR BROWSER TABS ARE AN ECOSYSTEM NOW" + }, + { + "id": 412, + "fortune": "YOUR UMBRELLA WAITS. YOU WILL FORGET IT" + }, + { + "id": 413, + "fortune": "YOUR LEFTOVERS HAD DREAMS. THEY COMPOST" + }, + { + "id": 414, + "fortune": "YOUR TO DO LIST HAS A TO DO LIST" + }, + { + "id": 415, + "fortune": "YOUR CLOSET DRESSES THREE VERSIONS OF YOU" + }, + { + "id": 416, + "fortune": "YOUR MORNING RUN IS LAMINATED. NOT RUN" + }, + { + "id": 417, + "fortune": "YOUR WIFI ROUTER SITS ON A SHRINE. CORRECT" + }, + { + "id": 418, + "fortune": "YOUR INBOX ZERO ATTEMPT IS HISTORY NOW" + }, + { + "id": 419, + "fortune": "YOUR SOCK DRAWER RUNS WITNESS PROTECTION" + }, + { + "id": 420, + "fortune": "YOUR GROCERY LIST STAYS HOME. IT KNOWS" + }, + { + "id": 421, + "fortune": "YOUR WATCHLIST OUTLIVED THREE HOBBIES" + }, + { + "id": 422, + "fortune": "YOUR DESK IS ERGONOMIC. YOUR COUCH ISNT" + }, + { + "id": 423, + "fortune": "THE PRINTER SENSES FEAR. AND UPDATES" + }, + { + "id": 424, + "fortune": "YOUR BEDTIME IS A MOTION YOU VOTE DOWN" + }, + { + "id": 425, + "fortune": "YOUR HEADPHONES TANGLE ALONE. SCIENCE WEEPS" + }, + { + "id": 426, + "fortune": "YOUR SPICE RACK IS SORTED THROUGH C" + }, + { + "id": 427, + "fortune": "YOUR BACKSEAT IS A LOST AND FOUND" + }, + { + "id": 428, + "fortune": "YOUR CART ABANDONMENT RATE MADE THE NEWS" + }, + { + "id": 429, + "fortune": "THE GOOD CABLE IS WHEREVER YOU ARENT" + }, + { + "id": 430, + "fortune": "YOUR STANDING DESK MOSTLY SITS. LIKE YOU" + }, + { + "id": 431, + "fortune": "YOUR MEAL PREP MADE ONE MEAL. SIX BOXES" + }, + { + "id": 432, + "fortune": "THE DELIVERY DRIVER WAVES AT YOU NOW" + }, + { + "id": 433, + "fortune": "YOUR AIR FRYER REPLACED THE OVEN. AND YOU" + }, + { + "id": 434, + "fortune": "YOUR BOOKMARKS ARE A HALL OF INTENTIONS" + }, + { + "id": 435, + "fortune": "YOUR SNOOZE BUTTON SHOWS GEOLOGIC WEAR" + }, + { + "id": 436, + "fortune": "YOUR REUSABLE BAGS WAIT IN THE CAR. LOYAL" + }, + { + "id": 437, + "fortune": "YOUR UPDATES HAVE SENIORITY NOW" + }, + { + "id": 438, + "fortune": "THE ICE TRAY RETURNS EMPTY. A TRADITION" + }, + { + "id": 439, + "fortune": "YOUR GARAGE STORES EVERYTHING BUT THE CAR" + }, + { + "id": 440, + "fortune": "YOUR STEP COUNTER FRAMED ITS BEST DAY" + }, + { + "id": 441, + "fortune": "YOUR FAVOURITE MUG HAS PROTECTED STATUS" + }, + { + "id": 442, + "fortune": "YOUR WEATHER APP GAVE UP ON YOUR OUTFITS" + }, + { + "id": 443, + "fortune": "YOUR SCALE PRACTICES RADICAL HONESTY" + }, + { + "id": 444, + "fortune": "YOUR REMOTES COMMUTE FROM THE CUSHIONS" + }, + { + "id": 445, + "fortune": "THE HALLWAY CLOSET HOLDS YOUR TRUTH. BARELY" + }, + { + "id": 446, + "fortune": "YOU OWN EVERY BATTERY SIZE BUT THE ONE NEEDED" + }, + { + "id": 447, + "fortune": "YOUR VACUUM AVOIDS CORNERS. LIKE YOU" + }, + { + "id": 448, + "fortune": "YOUR SHOWER THOUGHTS STAY IN THE SHOWER" + }, + { + "id": 449, + "fortune": "YOUR COFFEE MAKER KNOWS YOUR MONDAY FACE" + }, + { + "id": 450, + "fortune": "YOUR FREEZER FLOOR PREDATES FRIENDSHIPS" + }, + { + "id": 451, + "fortune": "YOUR PHONE STORAGE IS ALL SCREENSHOTS" + }, + { + "id": 452, + "fortune": "YOUR BIKE TIRES EXHALE SLOWLY. LIKE A SIGH" + }, + { + "id": 453, + "fortune": "YOUR RETURNS PILE HAS A DEPARTURE LOUNGE" + }, + { + "id": 454, + "fortune": "YOUR CANDLES ARE DECOR. MATCHES AGREE" + }, + { + "id": 455, + "fortune": "YOUR DINING TABLE RETIRED FROM DINING" + }, + { + "id": 456, + "fortune": "YOUR PREDICTIVE TEXT SUGGESTS SORRY FIRST" + }, + { + "id": 457, + "fortune": "YOUR FITNESS APP USES SHORTER SENTENCES NOW" + }, + { + "id": 458, + "fortune": "YOUR COAT POCKET IS A TIME CAPSULE" + }, + { + "id": 459, + "fortune": "THE ADD 30 SECONDS BUTTON RUNS YOUR KITCHEN" + }, + { + "id": 460, + "fortune": "THE GOOD SCISSORS ARE MISSING. ONE SUSPECT" + }, + { + "id": 461, + "fortune": "YOUR DOWNLOADS FOLDER IS A LANDFILL" + }, + { + "id": 462, + "fortune": "YOUR PLANTS RUN ON GUILT BASED WATERING" + }, + { + "id": 463, + "fortune": "THE DRYER TAKES ONE SOCK AS TRIBUTE" + }, + { + "id": 464, + "fortune": "YOUR COASTERS WATCH FROM THE SIDELINES" + }, + { + "id": 465, + "fortune": "YOUR NOTES APP IS A GENIUS LANDFILL" + }, + { + "id": 466, + "fortune": "RAIN WILL WASH YOUR CAR. YOUR PLAN EXACTLY" + }, + { + "id": 467, + "fortune": "YOUR BOARD GAMES AGE IN SHRINK WRAP" + }, + { + "id": 468, + "fortune": "YOUR YOGA MAT UNROLLED TWICE. FOR NAPS" + }, + { + "id": 469, + "fortune": "YOUR EXTENSION CORDS BREED IN THE DARK" + }, + { + "id": 470, + "fortune": "YOUR SMART SPEAKER HAS HEARD THINGS" + }, + { + "id": 471, + "fortune": "YOUR LIDS AND CONTAINERS NEVER MATCH. EVER" + }, + { + "id": 472, + "fortune": "YOUR WALKING SHOES TOUR THE TRUNK" + }, + { + "id": 473, + "fortune": "YOUR IMPORTANT FOLDER IS A HOSPICE" + }, + { + "id": 474, + "fortune": "YOUR WREATH IS PERENNIAL NOW. FESTIVE" + }, + { + "id": 475, + "fortune": "THAT ONE DRAWER STOPPED EXPLAINING ITSELF" + }, + { + "id": 476, + "fortune": "YOUR SCREEN AT 2AM REVEALS EVERYTHING" + }, + { + "id": 477, + "fortune": "YOUR FIRE EXTINGUISHER RUNS ON CONFIDENCE" + }, + { + "id": 478, + "fortune": "YOUR WATER GOAL WAS MET ONCE. PLAQUE PENDING" + }, + { + "id": 479, + "fortune": "AGING SUITS YOU. THE ALTERNATIVE DIDNT" + }, + { + "id": 480, + "fortune": "YOUR AGE IS JUST A NUMBER. AN ASCENDING ONE" + }, + { + "id": 481, + "fortune": "YOUR KNEES FORECAST WEATHER NOW. A SKILL" + }, + { + "id": 482, + "fortune": "YOUR BACK WENT OUT MORE THAN YOU DID" + }, + { + "id": 483, + "fortune": "WISDOM COMES WITH GREY HAIR. YOURS CAME EARLY" + }, + { + "id": 484, + "fortune": "YOU AGE LIKE WINE. STORED HORIZONTALLY" + }, + { + "id": 485, + "fortune": "YOUR BIRTHDAY CANDLES ARE A FIRE HAZARD" + }, + { + "id": 486, + "fortune": "YOUR READING GLASSES NEED READING GLASSES" + }, + { + "id": 487, + "fortune": "YOUR PLAYLIST IS CALLED OLDIES NOW. BY KIDS" + }, + { + "id": 488, + "fortune": "YOU GROAN WHEN SITTING. A VERBAL RECEIPT" + }, + { + "id": 489, + "fortune": "YOUR METABOLISM RETIRED WITHOUT NOTICE" + }, + { + "id": 490, + "fortune": "YOU FEEL 25. YOUR HANGOVERS DISAGREE" + }, + { + "id": 491, + "fortune": "AN APPLE A DAY. PIE IS A LOOPHOLE. SURE" + }, + { + "id": 492, + "fortune": "YOUR POSTURE IMPROVES TWICE DAILY. BRIEFLY" + }, + { + "id": 493, + "fortune": "YOU WILL SLEEP 8 HOURS. ACROSS 3 NIGHTS" + }, + { + "id": 494, + "fortune": "YOUR VITAMINS EXPIRE UNTAKEN. RENEWABLE" + }, + { + "id": 495, + "fortune": "YOUR DIET STARTS MONDAY. MONDAYS UNIONIZED" + }, + { + "id": 496, + "fortune": "YOUR DENTIST KNOWS YOU FLOSSED TODAY ONLY" + }, + { + "id": 497, + "fortune": "YOUR RESTING HEART RATE IS GREAT. FITTING" + }, + { + "id": 498, + "fortune": "YOU WILL LIVE TO 100. OUT OF SPITE" + }, + { + "id": 499, + "fortune": "YOUR HIDDEN TALENTS REMAIN WELL HIDDEN" + }, + { + "id": 500, + "fortune": "YOUR CREATIVITY HAS NO BOUNDS. OR OUTPUT" + }, + { + "id": 501, + "fortune": "YOU HAVE A GIFT. NO RECEIPT INCLUDED" + }, + { + "id": 502, + "fortune": "YOUR NOVEL WILL BE FINISHED. BY SOMEONE" + }, + { + "id": 503, + "fortune": "YOU WERE BORN TO CREATE. EXCUSES COUNT" + }, + { + "id": 504, + "fortune": "YOUR MASTERPIECE IS INSIDE YOU. COZY THERE" + }, + { + "id": 505, + "fortune": "YOUR SINGING BRINGS TEARS. BIOLOGY IS ODD" + }, + { + "id": 506, + "fortune": "THE MUSE VISITS YOU. SHE CALLS AHEAD NOW" + }, + { + "id": 507, + "fortune": "YOUR PHOTOS CAPTURE RAW CONFUSION" + }, + { + "id": 508, + "fortune": "YOU THINK OUTSIDE THE BOX. THE BOX WORRIES" + }, + { + "id": 509, + "fortune": "YOUR POETRY MOVES PEOPLE. TO THE EXITS" + }, + { + "id": 510, + "fortune": "YOUR IMAGINATION IS VAST. EXECUTION ISNT" + }, + { + "id": 511, + "fortune": "YOU SEE THE WORLD DIFFERENTLY. GET CHECKED" + }, + { + "id": 512, + "fortune": "YOUR PODCAST IDEA JOINS THE OTHER SIX" + }, + { + "id": 513, + "fortune": "CREATIVITY FLOWS PAST YOU. WAVING" + }, + { + "id": 514, + "fortune": "YOUR DOODLES BELONG SOMEWHERE. A DRAWER" + }, + { + "id": 515, + "fortune": "YOUR COOKING IS PERFORMANCE ART. WITH ALARMS" + }, + { + "id": 516, + "fortune": "YOUR SCREENPLAY HAS POTENTIAL ENERGY ONLY" + }, + { + "id": 517, + "fortune": "THE WORLD IS YOUR CANVAS. STILL PRIMED" + }, + { + "id": 518, + "fortune": "YOUR DIY PROJECTS ARE AN UNFINISHED TRILOGY" + }, + { + "id": 519, + "fortune": "YOUR MUSIC TASTE IS GREAT. NEIGHBOURS DISSENT" + }, + { + "id": 520, + "fortune": "YOUR DANCE MOVES DEFY CONVENTION. AND PHYSICS" + }, + { + "id": 521, + "fortune": "YOU TELL GREAT STORIES. ENDINGS PENDING" + }, + { + "id": 522, + "fortune": "PHARMACISTS FRAME YOUR HANDWRITING" + }, + { + "id": 523, + "fortune": "YOUR IDEAS ARRIVE AT 2AM. GONE BY 8" + }, + { + "id": 524, + "fortune": "YOUR SKETCHBOOK HOLDS GREAT PROMISES" + }, + { + "id": 525, + "fortune": "YOU COULD WRITE A BOOK. A STRONG PAMPHLET" + }, + { + "id": 526, + "fortune": "YOUR POTTERY PHASE MADE MEMORABLE PIECES" + }, + { + "id": 527, + "fortune": "YOUR INNER ARTIST WANTS COFFEE FIRST" + }, + { + "id": 528, + "fortune": "YOUR COLOUR CHOICES ARE COURAGEOUS" + }, + { + "id": 529, + "fortune": "YOUR GUITAR KNOWS THREE CHORDS WELL" + }, + { + "id": 530, + "fortune": "YOUR CREATIVE PROCESS IS UNDOCUMENTED" + }, + { + "id": 531, + "fortune": "YOUR SCARVES BECAME EXPERIENCES. KNIT ON" + }, + { + "id": 532, + "fortune": "YOU PAINT WITH EMOTION. THE FLOOR AGREES" + }, + { + "id": 533, + "fortune": "YOUR BONSAI IS A REGULAR TREE NOW. PATIENCE" + }, + { + "id": 534, + "fortune": "YOUR WRITING VOICE IS STRONG. IN TEXTS" + }, + { + "id": 535, + "fortune": "YOUR GARDEN GROWS. THE WEEDS THRIVE MOST" + }, + { + "id": 536, + "fortune": "YOUR CALLIGRAPHY PHASE WAS ONE WEEKEND" + }, + { + "id": 537, + "fortune": "YOUR WOODWORK IS HONEST. SPLINTERS DONT LIE" + }, + { + "id": 538, + "fortune": "YOUR FAN FICTION HAS FANS. BOTH OF THEM" + }, + { + "id": 539, + "fortune": "YOUR ORIGAMI FILLS THE RECYCLING BIN" + }, + { + "id": 540, + "fortune": "YOUR CREATIVE BLOCK IS LOAD BEARING NOW" + }, + { + "id": 541, + "fortune": "YOUR SOURDOUGH STARTER OUTLIVED THE HOBBY" + }, + { + "id": 542, + "fortune": "YOUR WATERCOLORS CAPTURE SOMETHING. UNCLEAR" + }, + { + "id": 543, + "fortune": "YOU EXCEL AT BEGINNINGS. MIDDLES DECLINED" + }, + { + "id": 544, + "fortune": "YOUR UKULELE EMBRACED ITS ROLE AS DECOR" + }, + { + "id": 545, + "fortune": "YOU ARE YOUR OWN WORST CRITIC. UNDISPUTED" + }, + { + "id": 546, + "fortune": "YOUR ART SPEAKS FOR ITSELF. QUIETLY" + }, + { + "id": 547, + "fortune": "YOUR STUDIO IS A CLOSET AGAIN. FUNCTIONAL" + }, + { + "id": 548, + "fortune": "YOUR FIRST DRAFTS NEVER MEET SECOND ONES" + }, + { + "id": 549, + "fortune": "YOUR CANDLE PHASE LEFT EVIDENCE. WAXY" + }, + { + "id": 550, + "fortune": "YOUR OPEN MIC DEBUT REMAINS IMMINENT" + }, + { + "id": 551, + "fortune": "YOUR PLAYLIST TRANSITIONS ARE ART. SHUFFLED" + }, + { + "id": 552, + "fortune": "YOUR COSTUMES SHOW COMMITMENT. TO CONCEPTS" + }, + { + "id": 553, + "fortune": "YOUR MACRAME OWL HAS SEEN YOUR PROJECTS" + }, + { + "id": 554, + "fortune": "YOUR VOICE MEMOS ARE MOSTLY GROCERIES" + }, + { + "id": 555, + "fortune": "YOU WILL BE DISCOVERED. ON YOUR COUCH" + }, + { + "id": 556, + "fortune": "YOUR MOOD BOARD IS ALL MOOD. NO BOARD" + }, + { + "id": 557, + "fortune": "YOUR FREESTYLE RAPS SHOULD STAY FREE" + }, + { + "id": 558, + "fortune": "YOUR MUSEUM VISITS END AT THE CAFE" + }, + { + "id": 559, + "fortune": "YOUR COVERS BEAT THE ORIGINALS. UNNOTIFIED" + }, + { + "id": 560, + "fortune": "YOUR TYPEWRITER LOOKS GREAT. STILL" + }, + { + "id": 561, + "fortune": "YOUR ABSTRACT PHASE CONFUSED EVEN YOU" + }, + { + "id": 562, + "fortune": "YOUR COMIC HAS A FOLLOWER. HI MUM" + }, + { + "id": 563, + "fortune": "YOUR SONG RHYMES ORANGE WITH DOOR HINGE" + }, + { + "id": 564, + "fortune": "YOUR CRAFT CORNER ANNEXED THE GUEST ROOM" + }, + { + "id": 565, + "fortune": "YOUR GENIUS IS MISUNDERSTOOD. AND UNSEEN" + }, + { + "id": 566, + "fortune": "YOUR MAGNUM OPUS IS BASICALLY ESPRESSO NOW" + }, + { + "id": 567, + "fortune": "YOUR INSPIRATION FOLDER HAS SUBFOLDERS" + }, + { + "id": 568, + "fortune": "THE FORTUNE YOU SEEK IS IN ANOTHER BISCUIT" + }, + { + "id": 569, + "fortune": "THIS BISCUIT CONTAINS NO FORTUNE. JUST CARBS" + }, + { + "id": 570, + "fortune": "IT IS DARK INSIDE THIS BISCUIT. AND QUIET" + }, + { + "id": 571, + "fortune": "THIS FORTUNE LEFT INTENTIONALLY BLANK" + }, + { + "id": 572, + "fortune": "CONFUCIUS SAYS NOTHING ABOUT YOU. WISELY" + }, + { + "id": 573, + "fortune": "THIS FORTUNE WAS RECALLED. SAME TO YOU" + }, + { + "id": 574, + "fortune": "YOU WILL READ THIS ALOUD. UNPROMPTED" + }, + { + "id": 575, + "fortune": "THE BISCUIT KNEW YOU WOULD TAKE THE LAST ONE" + }, + { + "id": 576, + "fortune": "SOME GET WISDOM. YOU CHOSE DESSERT" + }, + { + "id": 577, + "fortune": "THIS IS A BISCUIT. NOT A LIFE COACH" + }, + { + "id": 578, + "fortune": "YOUR LUCKY NUMBERS HAVE OPTED OUT" + }, + { + "id": 579, + "fortune": "THE BISCUIT ADMIRES YOUR OPTIMISM" + }, + { + "id": 580, + "fortune": "YOU SHOOK THE BISCUIT FIRST. IT FELT THAT" + }, + { + "id": 581, + "fortune": "ASK AGAIN LATER. OR DONT. YOUR CALL" + }, + { + "id": 582, + "fortune": "THIS BISCUIT WAS BAKED WITH LOW EXPECTATIONS" + }, + { + "id": 583, + "fortune": "THE FORTUNE WRITER IS ON BREAK. JUDGING" + }, + { + "id": 584, + "fortune": "NO WISDOM TODAY. INVENTORY ISSUES" + }, + { + "id": 585, + "fortune": "YOUR FORTUNE IS PENDING APPROVAL" + }, + { + "id": 586, + "fortune": "THIS MESSAGE WILL SELF DISAPPOINT" + }, + { + "id": 587, + "fortune": "THE BISCUIT CRUMBLES. SO DO PLANS" + }, + { + "id": 588, + "fortune": "YOU EXPECTED MORE FROM A BISCUIT. NOTED" + }, + { + "id": 589, + "fortune": "FORTUNE NOT FOUND. TRY ANOTHER DINNER" + }, + { + "id": 590, + "fortune": "THIS BISCUIT HAS SEEN YOUR ORDER HISTORY" + }, + { + "id": 591, + "fortune": "THE LAST BISCUIT ALWAYS TELLS THE TRUTH" + }, + { + "id": 592, + "fortune": "YOUR FORTUNE RAN OUT OF CHARACTERS. LUCKY" + }, + { + "id": 593, + "fortune": "A WISE MAN ONCE SAID NOTHING. TRY IT" + }, + { + "id": 594, + "fortune": "THE BISCUIT BELIEVED IN YOU. PAST TENSE" + }, + { + "id": 595, + "fortune": "THIS FORTUNE IS ACCURATE. DETAILS REDACTED" + }, + { + "id": 596, + "fortune": "YOU HOLD THE KEY TO HAPPINESS. NOW FIND IT" + }, + { + "id": 597, + "fortune": "YOUR FORTUNE IS BEING WRITTEN. SLOWLY" + }, + { + "id": 598, + "fortune": "YOUR COFFEE ORDER IS A PARAGRAPH NOW" + }, + { + "id": 599, + "fortune": "COFFEE FIRST. PERSONALITY SECOND. FAIR" + }, + { + "id": 600, + "fortune": "YOUR FOURTH COFFEE IS WATCHING YOU" + }, + { + "id": 601, + "fortune": "DECAF EXISTS. YOU PRETEND IT DOESNT" + }, + { + "id": 602, + "fortune": "YOUR MUG COLLECTION OUTGREW THE CABINET" + }, + { + "id": 603, + "fortune": "YOUR ESPRESSO MACHINE JUDGES YOUR PODS" + }, + { + "id": 604, + "fortune": "YOU CALL IT BRUNCH. IT WAS BREAKFAST. LATE" + }, + { + "id": 605, + "fortune": "YOUR SALAD PHASE ENDED AT THE DRESSING" + }, + { + "id": 606, + "fortune": "YOU MEAL PLAN BEAUTIFULLY. THEN ORDER OUT" + }, + { + "id": 607, + "fortune": "YOUR SPICE TOLERANCE IS A PERSONALITY. SADLY" + }, + { + "id": 608, + "fortune": "YOUR SIGNATURE DISH HAS ONE FAN. YOU" + }, + { + "id": 609, + "fortune": "THE OVEN TIMER IS A SUGGESTION TO YOU" + }, + { + "id": 610, + "fortune": "YOUR SMOOTHIES HIDE VEGETABLES. FROM YOU" + }, + { + "id": 611, + "fortune": "YOU COOK WITH LOVE. AND TOO MUCH SALT" + }, + { + "id": 612, + "fortune": "YOUR RECIPE SUBSTITUTIONS ARE BRAVE" + }, + { + "id": 613, + "fortune": "GARLIC MEASURED WITH YOUR HEART. AGAIN" + }, + { + "id": 614, + "fortune": "YOUR TOAST GAME IS STRONG. LITERALLY BURNT" + }, + { + "id": 615, + "fortune": "YOU EAT DESSERT FIRST. LIFE IS SHORT. SURE" + }, + { + "id": 616, + "fortune": "YOUR SNACK DRAWER HAS A WAITING LIST" + }, + { + "id": 617, + "fortune": "THE FOOD DELIVERY APP KNOWS YOU BY NAME" + }, + { + "id": 618, + "fortune": "YOUR KITCHEN GADGETS FORM A MUSEUM" + }, + { + "id": 619, + "fortune": "YOUR TAKEOUT CONTAINERS ARE HEIRLOOMS NOW" + }, + { + "id": 620, + "fortune": "YOU SAY YOU COULD EAT ANYTHING. THEN DONT" + }, + { + "id": 621, + "fortune": "YOUR PIZZA TOPPINGS HAVE CRITICS" + }, + { + "id": 622, + "fortune": "YOUR DOG LOVES YOU UNCONDITIONALLY. TRAINED" + }, + { + "id": 623, + "fortune": "YOUR CAT TOLERATES YOU. A HIGH HONOUR" + }, + { + "id": 624, + "fortune": "YOUR PET EATS BETTER THAN YOU DO" + }, + { + "id": 625, + "fortune": "YOUR DOG HAS MORE FRIENDS THAN YOU" + }, + { + "id": 626, + "fortune": "THE CAT KNOCKED IT OVER ON PURPOSE. RESPECT" + }, + { + "id": 627, + "fortune": "YOUR FISH KNOWS YOUR SCHEDULE. IT WORRIES" + }, + { + "id": 628, + "fortune": "YOUR PETS INSTAGRAM OUTPERFORMS YOURS" + }, + { + "id": 629, + "fortune": "THE DOG ATE YOUR MOTIVATION. NOT HOMEWORK" + }, + { + "id": 630, + "fortune": "YOUR CAT REVIEWS YOUR LIFE CHOICES NIGHTLY" + }, + { + "id": 631, + "fortune": "YOUR BIRD REPEATS YOUR WORST PHRASES" + }, + { + "id": 632, + "fortune": "YOUR PET THERAPIST IS A GOOD LISTENER. FREE" + }, + { + "id": 633, + "fortune": "RAIN IS COMING. YOUR CAR WASH REJOICES" + }, + { + "id": 634, + "fortune": "YOUR WINTER COAT DEBATE STARTS IN OCTOBER" + }, + { + "id": 635, + "fortune": "YOU CHECK THE WEATHER. THEN DRESS WRONG" + }, + { + "id": 636, + "fortune": "SPRING IS COMING. SO ARE YOUR ALLERGIES" + }, + { + "id": 637, + "fortune": "YOUR SUNSCREEN EXPIRES UNUSED. YEARLY" + }, + { + "id": 638, + "fortune": "SNOW IS MAGICAL. UNTIL YOU OWN A SHOVEL" + }, + { + "id": 639, + "fortune": "YOUR UMBRELLA COLLECTION LIVES ELSEWHERE" + }, + { + "id": 640, + "fortune": "SMALL TALK ABOUT WEATHER SUITS YOU NOW" + }, + { + "id": 641, + "fortune": "THE FORECAST CHANGED. YOUR PLANS DIDNT EXIST" + }, + { + "id": 642, + "fortune": "YOUR PATIO FURNITURE FEARS EVERY SEASON" + }, + { + "id": 643, + "fortune": "AUTUMN LEAVES FALL. LIKE YOUR RESOLUTIONS" + }, + { + "id": 644, + "fortune": "YOUR PASSWORD IS YOUR PETS NAME. WE KNOW" + }, + { + "id": 645, + "fortune": "YOU HAVE 47 UNREAD UPDATES. THEY WAIT" + }, + { + "id": 646, + "fortune": "YOUR CLOUD STORAGE IS FULL. OF DUPLICATES" + }, + { + "id": 647, + "fortune": "AUTOCORRECT KNOWS WHAT YOU MEANT. IT DECLINED" + }, + { + "id": 648, + "fortune": "YOUR ROUTER NEEDS A RESTART. LIKE YOU" + }, + { + "id": 649, + "fortune": "YOUR SEARCH HISTORY TELLS A SAGA" + }, + { + "id": 650, + "fortune": "YOU CLOSED ONE TAB TODAY. PROGRESS" + }, + { + "id": 651, + "fortune": "YOUR SPAM FOLDER MISSES YOU" + }, + { + "id": 652, + "fortune": "THE ALGORITHM KNOWS YOU TOO WELL. IT WORRIES" + }, + { + "id": 653, + "fortune": "YOUR SMARTWATCH SUGGESTS BREATHING. POINTED" + }, + { + "id": 654, + "fortune": "YOUR TYPING SPEED PEAKS DURING ARGUMENTS" + }, + { + "id": 655, + "fortune": "YOU MUTED THE GROUP. THE GROUP KNOWS" + }, + { + "id": 656, + "fortune": "YOUR CAPS LOCK GETS REGULAR EXERCISE" + }, + { + "id": 657, + "fortune": "YOUR EMOJI USE HAS BEEN DISCUSSED" + }, + { + "id": 658, + "fortune": "YOUR WIFI NAME IS YOUR BEST JOKE" + }, + { + "id": 659, + "fortune": "YOU RESTART THINGS AS A LIFESTYLE" + }, + { + "id": 660, + "fortune": "YOUR GYM MEMBERSHIP IS A DONATION NOW" + }, + { + "id": 661, + "fortune": "YOUR MARATHON PLAN IS SAVED. AND SAFE" + }, + { + "id": 662, + "fortune": "LEG DAY RESPECTS YOUR ABSENCE" + }, + { + "id": 663, + "fortune": "YOUR PROTEIN POWDER AGES GRACEFULLY" + }, + { + "id": 664, + "fortune": "YOU STRETCH ONCE A YEAR. AMBITIOUSLY" + }, + { + "id": 665, + "fortune": "YOUR SPORTS TEAM LOSES. YOU TAKE CREDIT" + }, + { + "id": 666, + "fortune": "YOUR FANTASY TEAM IS FANTASY INDEED" + }, + { + "id": 667, + "fortune": "YOU RUN LATE. IT COUNTS AS CARDIO" + }, + { + "id": 668, + "fortune": "YOUR HOME GYM STORES THE LAUNDRY NOW" + }, + { + "id": 669, + "fortune": "YOUR PERSONAL BEST WAS A GROUP EFFORT" + }, + { + "id": 670, + "fortune": "YOUR WARM UP IS THE WHOLE WORKOUT" + }, + { + "id": 671, + "fortune": "YOUR REST DAYS HAVE REST DAYS" + }, + { + "id": 672, + "fortune": "SLEEP IS FOR THE STRONG. YOU SCROLL" + }, + { + "id": 673, + "fortune": "YOUR NAP SCHEDULE IS YOUR REAL CALENDAR" + }, + { + "id": 674, + "fortune": "YOU COUNT SHEEP. THEY COUNT YOUR EXCUSES" + }, + { + "id": 675, + "fortune": "YOUR PILLOW KNOWS ALL YOUR SECRETS" + }, + { + "id": 676, + "fortune": "ONE MORE EPISODE WAS FOUR EPISODES" + }, + { + "id": 677, + "fortune": "YOUR DREAMS ARE VIVID. YOUR MORNINGS ARENT" + }, + { + "id": 678, + "fortune": "YOU SET SIX ALARMS. YOU FEAR NONE" + }, + { + "id": 679, + "fortune": "BEDTIME PROCRASTINATION IS STILL A CHOICE" + }, + { + "id": 680, + "fortune": "YOUR WEEKEND SLEEP DEBT COLLECTS INTEREST" + }, + { + "id": 681, + "fortune": "YOUR FAMILY LOVES YOU. THEY VOTED. CLOSE ONE" + }, + { + "id": 682, + "fortune": "YOUR MOTHER WAS RIGHT. ABOUT EVERYTHING" + }, + { + "id": 683, + "fortune": "FAMILY DINNERS TEST YOUR DIPLOMACY" + }, + { + "id": 684, + "fortune": "YOUR SIBLING REMEMBERS EVERYTHING. FOREVER" + }, + { + "id": 685, + "fortune": "YOUR RELATIVES ASK ABOUT YOUR PLANS. BRACE" + }, + { + "id": 686, + "fortune": "YOU ARE THE FAVOURITE CHILD. UNCONFIRMED" + }, + { + "id": 687, + "fortune": "YOUR FAMILY GROUP CHAT NEVER SLEEPS" + }, + { + "id": 688, + "fortune": "GRANDMA FEEDS YOU. RESISTANCE IS FUTILE" + }, + { + "id": 689, + "fortune": "YOUR DAD JOKES SKIPPED NO GENERATIONS" + }, + { + "id": 690, + "fortune": "THANKSGIVING SEATING IS POLITICAL. YOURS IS" + }, + { + "id": 691, + "fortune": "YOUR NEIGHBOUR WAVES. THE FENCE WAS HIS IDEA" + }, + { + "id": 692, + "fortune": "THE HOA NOTICED YOUR LAWN. AGAIN" + }, + { + "id": 693, + "fortune": "YOUR NEIGHBOURS KNOW YOUR SCHEDULE. AND MORE" + }, + { + "id": 694, + "fortune": "BORROWED TOOLS BECOME GIFTS EVENTUALLY" + }, + { + "id": 695, + "fortune": "YOUR DOORBELL CAMERA SAW YOUR BEST SPRINT" + }, + { + "id": 696, + "fortune": "YOUR COMMUTE BUILDS CHARACTER. DAILY" + }, + { + "id": 697, + "fortune": "TRAFFIC IS NOT PERSONAL. YOURS FEELS PERSONAL" + }, + { + "id": 698, + "fortune": "YOUR PARKING JOB SPARKED CONVERSATIONS" + }, + { + "id": 699, + "fortune": "YOUR GPS SAYS RECALCULATING. WITH FEELING" + }, + { + "id": 700, + "fortune": "YOU DRIVE LIKE YOU LIVE. SIGNALS OPTIONAL" + }, + { + "id": 701, + "fortune": "YOUR GAS TANK RUNS ON FAITH. AND FUMES" + }, + { + "id": 702, + "fortune": "THE LEFT LANE IS FOR PASSING. JUST SAYING" + }, + { + "id": 703, + "fortune": "YOUR CAR PLAYLIST PEAKED IN 2016" + }, + { + "id": 704, + "fortune": "YOUR HORN GETS MORE USE THAN YOUR BLINKER" + }, + { + "id": 705, + "fortune": "ROAD RAGE IS BENEATH YOU. USUALLY" + }, + { + "id": 706, + "fortune": "YOUR PARALLEL PARKING DRAWS AUDIENCES" + }, + { + "id": 707, + "fortune": "TIME FLIES. YOURS FILED A FLIGHT PLAN" + }, + { + "id": 708, + "fortune": "PROCRASTINATION IS AN ART. YOU TEACH IT" + }, + { + "id": 709, + "fortune": "YOU WILL DO IT TOMORROW. TOMORROW KNOWS" + }, + { + "id": 710, + "fortune": "DEADLINES APPROACH. YOU ADMIRE THE VIEW" + }, + { + "id": 711, + "fortune": "YOUR FIVE MINUTES IS EVERYONE ELSES HOUR" + }, + { + "id": 712, + "fortune": "LATER IS YOUR FAVOURITE TIME ZONE" + }, + { + "id": 713, + "fortune": "YOU FINISH THINGS. EVENTUALLY IS A WORD" + }, + { + "id": 714, + "fortune": "YOUR SOMEDAY LIST NEEDS ITS OWN SHELF" + }, + { + "id": 715, + "fortune": "TIME MANAGEMENT IS A SKILL. NOTED" + }, + { + "id": 716, + "fortune": "YOU ARE EARLY ONCE A YEAR. IT CONFUSES ALL" + }, + { + "id": 717, + "fortune": "THE PRESENT IS A GIFT. YOU CHOSE STORE CREDIT" + }, + { + "id": 718, + "fortune": "YOUR PUNCTUALITY IS LEGEND. THE BAD KIND" + }, + { + "id": 719, + "fortune": "YOU READ THIS INSTEAD OF WORKING. NOTED" + }, + { + "id": 720, + "fortune": "YOUR ATTENTION SPAN IS. OH LOOK A BIRD" + }, + { + "id": 721, + "fortune": "JUST ONE MORE MINUTE. THE FAMOUS LAST WORDS" + }, + { + "id": 722, + "fortune": "YOUR EMAILS START WITH SORRY FOR THE DELAY" + }, + { + "id": 723, + "fortune": "YOU REPLY TO TEXTS IN GEOLOGIC TIME" + }, + { + "id": 724, + "fortune": "YOUR READ RECEIPTS INCRIMINATE YOU" + }, + { + "id": 725, + "fortune": "YOU LEFT THEM ON READ. THEY NOTICED" + }, + { + "id": 726, + "fortune": "YOUR TYPING BUBBLE APPEARED. THEN LEFT" + }, + { + "id": 727, + "fortune": "YOU SAID LETS CIRCLE BACK. YOU WONT" + }, + { + "id": 728, + "fortune": "PER YOUR LAST EMAIL. YOU KNOW WHAT YOU DID" + }, + { + "id": 729, + "fortune": "YOUR VOICE NOTES ARE PODCASTS NOW" + }, + { + "id": 730, + "fortune": "YOU WAVED AT SOMEONE WAVING ELSEWHERE. AGAIN" + }, + { + "id": 731, + "fortune": "YOUR SMALL TALK HAS A SCRIPT. REHEARSE" + }, + { + "id": 732, + "fortune": "YOU SAID WE SHOULD HANG OUT SOON. CLASSIC" + }, + { + "id": 733, + "fortune": "YOUR PHONE IS ON SILENT. FOR YEARS NOW" + }, + { + "id": 734, + "fortune": "YOU SCREENSHOT INSTEAD OF RESPONDING" + }, + { + "id": 735, + "fortune": "YOUR OPINION WAS NOTED. AND RECYCLED" + }, + { + "id": 736, + "fortune": "YOU INTERRUPT WITH ENTHUSIASM. OFTEN" + }, + { + "id": 737, + "fortune": "RETAIL THERAPY IS STILL THERAPY. INVOICED" + }, + { + "id": 738, + "fortune": "YOUR PACKAGE ARRIVES TODAY. YOU ORDERED MORE" + }, + { + "id": 739, + "fortune": "YOU CAME FOR ONE ITEM. YOU LEFT WITH NINE" + }, + { + "id": 740, + "fortune": "YOUR WISHLIST IS A NOVEL NOW" + }, + { + "id": 741, + "fortune": "FREE SHIPPING COSTS YOU PLENTY" + }, + { + "id": 742, + "fortune": "YOUR RETURNS WINDOW CLOSED. LIKE ALWAYS" + }, + { + "id": 743, + "fortune": "YOU COMPARE PRICES. AFTER BUYING" + }, + { + "id": 744, + "fortune": "THE SALE ENDED. YOUR REGRET BEGINS" + }, + { + "id": 745, + "fortune": "YOUR LOYALTY CARD OUTRANKS YOUR GYM CARD" + }, + { + "id": 746, + "fortune": "YOU BUY ORGANIZERS TO ORGANISE ORGANIZERS" + }, + { + "id": 747, + "fortune": "YOUR HOME PROJECT IS 90 PERCENT DONE. FOREVER" + }, + { + "id": 748, + "fortune": "THE PAINT SAMPLES OUTLIVED THE PROJECT" + }, + { + "id": 749, + "fortune": "YOUR TOOLBOX HAS EVERYTHING BUT ANSWERS" + }, + { + "id": 750, + "fortune": "YOU MEASURED ONCE. IT SHOWS" + }, + { + "id": 751, + "fortune": "THE INSTRUCTIONS WERE OPTIONAL. APPARENTLY" + }, + { + "id": 752, + "fortune": "YOUR SHELF LEANS. YOU CALL IT CHARACTER" + }, + { + "id": 753, + "fortune": "DUCT TAPE IS NOT A PHILOSOPHY. YOURS IS" + }, + { + "id": 754, + "fortune": "YOUR SMART BULBS OUTSMART YOU NIGHTLY" + }, + { + "id": 755, + "fortune": "THE LEAK WAITED FOR THE LONG WEEKEND" + }, + { + "id": 756, + "fortune": "YOUR GAMING BACKLOG IS A SECOND CAREER" + }, + { + "id": 757, + "fortune": "ONE MORE LEVEL WAS THREE HOURS AGO" + }, + { + "id": 758, + "fortune": "YOUR CHARACTER HAS BETTER GEAR THAN YOU" + }, + { + "id": 759, + "fortune": "YOU PAUSED AN ONLINE GAME. BOLD MOVE" + }, + { + "id": 760, + "fortune": "YOUR HIGH SCORE IS SOMEONE ELSES WARMUP" + }, + { + "id": 761, + "fortune": "YOU RAGE QUIT GRACEFULLY. ALMOST" + }, + { + "id": 762, + "fortune": "YOUR BOOKSHELF JUDGES YOUR SCREEN TIME" + }, + { + "id": 763, + "fortune": "YOU BUY BOOKS FASTER THAN YOU READ THEM" + }, + { + "id": 764, + "fortune": "YOUR BOOKMARK HASNT MOVED SINCE MARCH" + }, + { + "id": 765, + "fortune": "YOU JOINED A BOOK CLUB FOR THE SNACKS" + }, + { + "id": 766, + "fortune": "THE AUDIOBOOK COUNTS. NOBODY ASKED" + }, + { + "id": 767, + "fortune": "YOUR TO BE READ PILE IS FURNITURE NOW" + }, + { + "id": 768, + "fortune": "YOU QUOTE BOOKS YOU HAVENT FINISHED" + }, + { + "id": 769, + "fortune": "YOUR KARAOKE SONG CLEARED THE ROOM. TWICE" + }, + { + "id": 770, + "fortune": "YOU SING IN THE CAR. THE CAR ENDURES" + }, + { + "id": 771, + "fortune": "YOUR SHOWER CONCERTS HAVE NO REFUNDS" + }, + { + "id": 772, + "fortune": "YOUR AIR GUITAR NEEDS TUNING SOMEHOW" + }, + { + "id": 773, + "fortune": "YOUR PLANT NAMES OUTNUMBER YOUR PLANTS" + }, + { + "id": 774, + "fortune": "YOU TALK TO YOUR PLANTS. THEY HEARD THAT" + }, + { + "id": 775, + "fortune": "YOUR SUCCULENT DIED. IMPRESSIVELY RARE" + }, + { + "id": 776, + "fortune": "THE FERN SAW EVERYTHING. IT STAYS QUIET" + }, + { + "id": 777, + "fortune": "YOUR GREEN THUMB IS MORE OF A BEIGE" + }, + { + "id": 778, + "fortune": "LUCK IS A LADDER. YOU BROUGHT A STOOL" + }, + { + "id": 779, + "fortune": "FORTUNE ARRIVES UNANNOUNCED. SO DO YOU" + }, + { + "id": 780, + "fortune": "YOUR CHARISMA WORKS OFFLINE ONLY" + }, + { + "id": 781, + "fortune": "YOU ARE A LIMITED EDITION. VERY LIMITED" + }, + { + "id": 782, + "fortune": "YOUR VIBE ATTRACTS YOUR TRIBE. EXPLAINS IT" + }, + { + "id": 783, + "fortune": "NORMAL IS A SETTING. YOURS IS CUSTOM" + }, + { + "id": 784, + "fortune": "NOT LAZY. JUST IN ENERGY SAVER MODE" + }, + { + "id": 785, + "fortune": "YOUR SARCASM IS A SECOND LANGUAGE. FLUENT" + }, + { + "id": 786, + "fortune": "YOU ARE TECHNICALLY CORRECT. THE WORST KIND" + }, + { + "id": 787, + "fortune": "YOUR EXCUSES SHOW REAL CRAFTSMANSHIP" + }, + { + "id": 788, + "fortune": "YOU PEAKED. THE TIMING WAS UNFORTUNATE" + }, + { + "id": 789, + "fortune": "YOUR COMFORT SHOW IS ON ITS NINTH RERUN" + }, + { + "id": 790, + "fortune": "YOU ARE DOING YOUR BEST. THE BEST VARIES" + }, + { + "id": 791, + "fortune": "YOUR POTENTIAL CALLED. IT LEFT NO MESSAGE" + }, + { + "id": 792, + "fortune": "YOU ARE SPECIAL. LIKE EVERYONE ELSE" + }, + { + "id": 793, + "fortune": "YOUR ENERGY TODAY IS DECORATIVE" + }, + { + "id": 794, + "fortune": "YOU ARE THE MAIN CHARACTER. OF A SIDE QUEST" + }, + { + "id": 795, + "fortune": "YOUR PLOT ARMOR HAS EXPIRED. WALK CAREFULLY" + }, + { + "id": 796, + "fortune": "YOUR REDEMPTION ARC IS IN PREPRODUCTION" + }, + { + "id": 797, + "fortune": "A COMPLIMENT NEARS. ACCEPT IT AWKWARDLY" + }, + { + "id": 798, + "fortune": "YOUR RESTING FACE HAS A REPUTATION" + }, + { + "id": 799, + "fortune": "YOU AGREED TO DISAGREE. YOU LOST" + }, + { + "id": 800, + "fortune": "YOUR EYE ROLL IS AUDIBLE SOMEHOW" + }, + { + "id": 801, + "fortune": "YOUR SIGH SPOKE PARAGRAPHS JUST NOW" + }, + { + "id": 802, + "fortune": "YOU SAID FINE. NOTHING WAS FINE" + }, + { + "id": 803, + "fortune": "YOUR THUMBS UP ENDED THREE FRIENDSHIPS" + }, + { + "id": 804, + "fortune": "NO WORRIES YOU SAID. WORRYING INTENSELY" + }, + { + "id": 805, + "fortune": "YOUR SHRUG IS DOING HEAVY LIFTING TODAY" + }, + { + "id": 806, + "fortune": "YOU SMILED THROUGH THAT. BARELY. WE SAW" + }, + { + "id": 807, + "fortune": "YOUR PATIENCE HAS A LOADING BAR. STUCK" + }, + { + "id": 808, + "fortune": "YOU FORGAVE THEM. THE SPREADSHEET REMAINS" + }, + { + "id": 809, + "fortune": "YOUR HINTS NEED SUBTITLES. STILL" + }, + { + "id": 810, + "fortune": "YOU ALMOST SAID IT. THE ALMOST WAS LOUD" + }, + { + "id": 811, + "fortune": "YOUR SILENCE HAS AN AGENDA. AS USUAL" + }, + { + "id": 812, + "fortune": "YOU LET IT GO. INTO YOUR PERMANENT RECORD" + }, + { + "id": 813, + "fortune": "YOUR CALM IS SUSPICIOUS. EVERYONE AGREES" + }, + { + "id": 814, + "fortune": "YOU TOOK THE HIGH ROAD. WITH COMMENTARY" + }, + { + "id": 815, + "fortune": "YOUR FEEDBACK SANDWICH IS ALL BREAD" + }, + { + "id": 816, + "fortune": "YOU HEARD THEM OUT. THEN PROCEEDED ANYWAY" + }, + { + "id": 817, + "fortune": "GOOD MORNING. THE BAR IS ALREADY MET" + }, + { + "id": 818, + "fortune": "YOUR OPTIMISM IS ADORABLE TODAY" + }, + { + "id": 819, + "fortune": "TODAY IS YOUR DAY. SHARE IT NICELY" + }, + { + "id": 820, + "fortune": "YOU WOKE UP LIKE THIS. CONDOLENCES" + }, + { + "id": 821, + "fortune": "THE MIRROR SAW YOU FIRST. IT COPES" + }, + { + "id": 822, + "fortune": "YOUR BEDHEAD HAS ARCHITECTURE NOW" + }, + { + "id": 823, + "fortune": "MONDAY SAW YOU COMING. IT PREPARED" + }, + { + "id": 824, + "fortune": "YOUR WEEKEND ENDED. IT SENDS REGARDS" + }, + { + "id": 825, + "fortune": "FRIDAY LOVES YOU. THE FEELING IS MUTUAL" + }, + { + "id": 826, + "fortune": "YOUR LUNCH BREAK DESERVES A MEDAL. SO LONG" + }, + { + "id": 827, + "fortune": "HUMP DAY IS A STATE OF MIND. YOURS DAILY" + }, + { + "id": 828, + "fortune": "YOUR OUTFIT SAYS EFFORT. THE CLOCK SAYS RUSH" + }, + { + "id": 829, + "fortune": "YOUR HAIR HAS PLANS OF ITS OWN TODAY" + }, + { + "id": 830, + "fortune": "YOU MATCHED YOUR SOCKS. A CEREMONY IS DUE" + }, + { + "id": 831, + "fortune": "YOUR SUNGLASSES HIDE NOTHING. NICE TRY" + }, + { + "id": 832, + "fortune": "DRESS FOR THE JOB YOU WANT. A NAP TESTER" + }, + { + "id": 833, + "fortune": "YOUR IRONING BOARD RETIRED YEARS AGO" + }, + { + "id": 834, + "fortune": "WRINKLES ARE A TEXTURE. YOU DECIDED" + }, + { + "id": 835, + "fortune": "YOUR FASHION CYCLE IS LAUNDRY BASED" + }, + { + "id": 836, + "fortune": "YOUR SHOES MATCH. THE OCCASION DOESNT" + }, + { + "id": 837, + "fortune": "YOU WILL WIN AN ARGUMENT. IN THE SHOWER" + }, + { + "id": 838, + "fortune": "YOUR COMEBACK ARRIVED. THREE DAYS LATE" + }, + { + "id": 839, + "fortune": "YOUR WIT IS QUICK. YOUR TIMING ISNT" + }, + { + "id": 840, + "fortune": "YOU HAD THE PERFECT REPLY. AT MIDNIGHT" + }, + { + "id": 841, + "fortune": "YOUR INNER MONOLOGUE NEEDS AN EDITOR" + }, + { + "id": 842, + "fortune": "YOUR HOT TAKES ARE ROOM TEMPERATURE" + }, + { + "id": 843, + "fortune": "YOUR OPINIONS ARRIVE PRE HEATED" + }, + { + "id": 844, + "fortune": "YOUR DEBATE STYLE IS VOLUME BASED" + }, + { + "id": 845, + "fortune": "YOU FACT CHECK OTHERS. NEVER YOURSELF" + }, + { + "id": 846, + "fortune": "YOUR TRIVIA KNOWLEDGE PEAKS AT PARTIES ONLY" + }, + { + "id": 847, + "fortune": "A DECISION AWAITS. FLIP A COIN. IGNORE IT" + }, + { + "id": 848, + "fortune": "YOUR PRO CON LIST HAS ONE COLUMN" + }, + { + "id": 849, + "fortune": "YOU ASKED EVERYONE. THEN DID YOUR THING" + }, + { + "id": 850, + "fortune": "YOUR GUT FEELING NEEDS A SECOND OPINION" + }, + { + "id": 851, + "fortune": "YOU SLEPT ON IT. THE PROBLEM STAYED AWAKE" + }, + { + "id": 852, + "fortune": "YOUR PLAN B IS PLAN A WITH REGRET" + }, + { + "id": 853, + "fortune": "YOU CHOSE CHAOS. AGAIN. CONSISTENTLY" + }, + { + "id": 854, + "fortune": "YOUR BACKUP PLAN NEEDS A BACKUP PLAN" + }, + { + "id": 855, + "fortune": "COMMITMENT SCARES YOU. SO DOES THE MENU" + }, + { + "id": 856, + "fortune": "YOU ORDERED THE SAME THING. ADVENTUROUS" + }, + { + "id": 857, + "fortune": "CHANGE IS COMING. YOU WILL RESIST IT" + }, + { + "id": 858, + "fortune": "A SURPRISE AWAITS. YOU HATE SURPRISES" + }, + { + "id": 859, + "fortune": "GOOD NEWS COMES IN THREES. YOURS CARPOOLS" + }, + { + "id": 860, + "fortune": "YOUR HOROSCOPE QUIT. IT CITED BURNOUT" + }, + { + "id": 861, + "fortune": "MERCURY IS IN RETROGRADE. CONVENIENT EXCUSE" + }, + { + "id": 862, + "fortune": "YOUR TAROT READER NEEDED A BREAK AFTER YOU" + }, + { + "id": 863, + "fortune": "THE MAGIC 8 BALL SAID ASK SOMEONE ELSE" + }, + { + "id": 864, + "fortune": "YOUR PALM READER REQUESTED GLOVES" + }, + { + "id": 865, + "fortune": "THE CRYSTAL BALL FOGGED UP. ON PURPOSE" + }, + { + "id": 866, + "fortune": "YOUR TEA LEAVES SPELLED LUCK. SARCASTICALLY" + }, + { + "id": 867, + "fortune": "YOUR VISION QUEST FOUND THE COUCH" + }, + { + "id": 868, + "fortune": "THE UNIVERSE IS TESTING YOU. OPEN BOOK. STILL" + }, + { + "id": 869, + "fortune": "YOUR MANIFESTATIONS NEED A COSIGNER" + }, + { + "id": 870, + "fortune": "YOUR CHAKRAS ARE ALIGNED. WITH THE FRIDGE" + }, + { + "id": 871, + "fortune": "YOUR ZEN GARDEN NEEDS WEEDING. IRONIC" + }, + { + "id": 872, + "fortune": "YOUR MANTRA IS FIVE MORE MINUTES" + }, + { + "id": 873, + "fortune": "YOUR THIRD EYE NEEDS GLASSES TOO" + }, + { + "id": 874, + "fortune": "YOUR ENERGY CLEANSE MISSED A SPOT" + }, + { + "id": 875, + "fortune": "YOUR SAGE SMOKE SET OFF THE ALARM. FITTING" + }, + { + "id": 876, + "fortune": "INNER PEACE IS CLOSE. TRY THE OTHER DOOR" + }, + { + "id": 877, + "fortune": "A STRANGER WILL SMILE AT YOU. STAY CALM" + }, + { + "id": 878, + "fortune": "SOMEONE THOUGHT OF YOU TODAY. BRIEFLY" + }, + { + "id": 879, + "fortune": "YOU CROSSED SOMEONES MIND. IT KEPT WALKING" + }, + { + "id": 880, + "fortune": "AN ADMIRER WATCHES. IT IS YOUR CAT" + }, + { + "id": 881, + "fortune": "YOU WERE MENTIONED TODAY. CONTEXT UNKNOWN" + }, + { + "id": 882, + "fortune": "YOUR NAME CAME UP. THE ROOM WENT QUIET" + }, + { + "id": 883, + "fortune": "SOMEONE MISSES YOU. THEY LOST YOUR NUMBER" + }, + { + "id": 884, + "fortune": "YOU ARE UNFORGETTABLE. MANY HAVE TRIED" + }, + { + "id": 885, + "fortune": "YOUR ABSENCE WAS NOTICED. AND ENJOYED" + }, + { + "id": 886, + "fortune": "PEOPLE TALK ABOUT YOU. KEEP IT THAT WAY" + }, + { + "id": 887, + "fortune": "YOUR REPUTATION ARRIVED FIRST. APOLOGISE" + }, + { + "id": 888, + "fortune": "YOU MADE AN IMPRESSION. DENTS COUNT" + }, + { + "id": 889, + "fortune": "SOMEONE QUOTED YOU TODAY. INCORRECTLY" + }, + { + "id": 890, + "fortune": "YOU INSPIRED SOMEONE. TO DO THE OPPOSITE" + }, + { + "id": 891, + "fortune": "YOUR LEGACY IS SAFE. NOBODY CHECKED" + }, + { + "id": 892, + "fortune": "HISTORY WILL REMEMBER YOU. AS A FOOTNOTE" + }, + { + "id": 893, + "fortune": "YOUR BIOGRAPHY NEEDS A GHOSTWRITER. AND PLOT" + }, + { + "id": 894, + "fortune": "YOUR AUTOGRAPH IS WORTHLESS. FOR NOW" + }, + { + "id": 895, + "fortune": "FAME AWAITS. LOCAL FAME. VERY LOCAL" + }, + { + "id": 896, + "fortune": "YOUR FIFTEEN MINUTES ARE BUFFERING" + }, + { + "id": 897, + "fortune": "YOU WILL FIND YOUR KEYS. WHERE YOU LEFT THEM" + }, + { + "id": 898, + "fortune": "YOUR PHONE IS IN YOUR OTHER HAND. AGAIN" + }, + { + "id": 899, + "fortune": "YOU WALKED INTO A ROOM. THE REASON LEFT" + }, + { + "id": 900, + "fortune": "YOUR MEMORY IS FINE. IT JUST CURATES" + }, + { + "id": 901, + "fortune": "YOU FORGOT WHY YOU OPENED THE FRIDGE. SNACK" + }, + { + "id": 902, + "fortune": "YOUR MENTAL NOTES NEED A FILING SYSTEM" + }, + { + "id": 903, + "fortune": "YOU REMEMBERED THE TUNE. NOT THE TASK" + }, + { + "id": 904, + "fortune": "YOUR SHOPPING MEMORY EXPIRES AT THE STORE" + }, + { + "id": 905, + "fortune": "YOU KNOW THAT FACE. THE NAME ESCAPED. RUN" + }, + { + "id": 906, + "fortune": "YOUR BRAIN HAS TABS OPEN TOO. ALL FROZEN" + }, + { + "id": 907, + "fortune": "A GREAT IDEA CAME AND WENT. UNRECORDED" + }, + { + "id": 908, + "fortune": "YOU LOCKED THE DOOR. PROBABLY. GO CHECK" + }, + { + "id": 909, + "fortune": "YOUR TRAIN OF THOUGHT DEPARTED WITHOUT YOU" + }, + { + "id": 910, + "fortune": "YOU RETRACED YOUR STEPS. THEY LED TO SNACKS" + }, + { + "id": 911, + "fortune": "YOUR PASSWORD RESET NEEDS A PASSWORD RESET" + }, + { + "id": 912, + "fortune": "LIFE IS SHORT. YOUR MEETINGS ARENT" + }, + { + "id": 913, + "fortune": "LIFE GAVE YOU LEMONS. YOU FILED A COMPLAINT" + }, + { + "id": 914, + "fortune": "LIFE IS A JOURNEY. YOURS NEEDS A MAP" + }, + { + "id": 915, + "fortune": "LIFE IS WHAT HAPPENS WHILE YOU SCROLL" + }, + { + "id": 916, + "fortune": "LIFE HAS NO REMOTE. GET UP AND CHANGE IT" + }, + { + "id": 917, + "fortune": "LIFE IS NOT A RACE. YOU PARKED ANYWAY" + }, + { + "id": 918, + "fortune": "LIFE IS A GIFT. KEEP THE RECEIPT" + }, + { + "id": 919, + "fortune": "LIFE IS UNSCRIPTED. YOURS NEEDS A WRITER" + }, + { + "id": 920, + "fortune": "LIFE REWARDS ACTION. YOURS SENT A MEMO" + }, + { + "id": 921, + "fortune": "LIFE IS A CLASSROOM. YOU SIT IN BACK" + }, + { + "id": 922, + "fortune": "YOUR STORY HAS PLOT HOLES. EMBRACE THEM" + }, + { + "id": 923, + "fortune": "YOUR CHAPTER TWO NEEDS CHAPTER ONE DONE" + }, + { + "id": 924, + "fortune": "YOUR SEQUEL DEPENDS ON THIS PART. NO PRESSURE" + }, + { + "id": 925, + "fortune": "YOUR NARRATOR SOUNDS TIRED LATELY" + }, + { + "id": 926, + "fortune": "YOUR CLIFFHANGER IS JUST INDECISION" + }, + { + "id": 927, + "fortune": "TOMORROW IS A NEW DAY. SAME YOU THOUGH" + }, + { + "id": 928, + "fortune": "YESTERDAY CALLED. IT WANTS NOTHING BACK" + }, + { + "id": 929, + "fortune": "TODAY WILL BE PRODUCTIVE. STARTING LATER" + }, + { + "id": 930, + "fortune": "THIS WEEK HAS POTENTIAL. HAD. HAS. UNCLEAR" + }, + { + "id": 931, + "fortune": "NEXT MONTH YOU WILL START. NEXT MONTH AGREES" + }, + { + "id": 932, + "fortune": "THE YEAR IS HALF OVER. YOUR GOALS ARE INTACT" + }, + { + "id": 933, + "fortune": "SOON IS NOT A DATE. YOU TREAT IT AS ONE" + }, + { + "id": 934, + "fortune": "EVENTUALLY IS YOUR FAVOURITE DEADLINE" + }, + { + "id": 935, + "fortune": "THE RIGHT TIME NEVER COMES. CONVENIENT" + }, + { + "id": 936, + "fortune": "YOUR WINDOW OF OPPORTUNITY HAS BLINDS" + }, + { + "id": 937, + "fortune": "PATIENCE COMES TO THOSE WHO WAIT. IRONIC" + }, + { + "id": 938, + "fortune": "YOUR TURN IS COMING. THE LINE MOVED ON" + }, + { + "id": 939, + "fortune": "YOU WAITED FOR A SIGN. THIS IS NOT IT" + }, + { + "id": 940, + "fortune": "HOLD THAT THOUGHT. FOREVER IF POSSIBLE" + }, + { + "id": 941, + "fortune": "YOUR PAUSE BUTTON IS YOUR FAVOURITE" + }, + { + "id": 942, + "fortune": "YOU PUT A PIN IN IT. THE PIN CUSHION IS FULL" + }, + { + "id": 943, + "fortune": "IT IS ON YOUR RADAR. YOUR RADAR IS OFF" + }, + { + "id": 944, + "fortune": "YOU WILL GET TO IT. IT STOPPED WAITING" + }, + { + "id": 945, + "fortune": "THE BALL IS IN YOUR COURT. GATHERING DUST" + }, + { + "id": 946, + "fortune": "YOUR FOLLOW UP NEEDS A FOLLOW UP" + }, + { + "id": 947, + "fortune": "CONSIDER THIS YOUR REMINDER. THE FOURTH" + }, + { + "id": 948, + "fortune": "YOUR INTENTIONS ARE GOOD. AND STATIONARY" + }, + { + "id": 949, + "fortune": "EFFORT WAS MADE. A ROUNDING ERROR OF IT" + }, + { + "id": 950, + "fortune": "YOU GAVE 100 PERCENT. OF YOUR MINIMUM" + }, + { + "id": 951, + "fortune": "YOUR BEST GUESS BEAT YOUR RESEARCH. AGAIN" + }, + { + "id": 952, + "fortune": "CLOSE ENOUGH IS YOUR SIGNATURE MOVE" + }, + { + "id": 953, + "fortune": "GOOD ENOUGH SHIPPED. PERFECTION SULKS" + }, + { + "id": 954, + "fortune": "YOUR SHORTCUTS TOOK THE LONG WAY" + }, + { + "id": 955, + "fortune": "YOU IMPROVISED. THE RESULTS IMPROVISED BACK" + }, + { + "id": 956, + "fortune": "YOUR WINGING IT HAS FREQUENT FLYER MILES" + }, + { + "id": 957, + "fortune": "DETAILS MATTER. YOURS WENT ON STRIKE" + }, + { + "id": 958, + "fortune": "YOUR ROUGH DRAFT WENT TO PRODUCTION" + }, + { + "id": 959, + "fortune": "YOU SKIMMED IT. IT SHOWED. IT ALWAYS SHOWS" + }, + { + "id": 960, + "fortune": "YOUR PROOFREADING MISSED THIS SENTENCE TOO" + }, + { + "id": 961, + "fortune": "ALMOST DONE IS YOUR PERMANENT ADDRESS" + }, + { + "id": 962, + "fortune": "YOUR CHECKLIST HAS SURVIVORS" + }, + { + "id": 963, + "fortune": "DONE IS BETTER THAN PERFECT. TRY EITHER" + }, + { + "id": 964, + "fortune": "YOUR STANDARDS SLIPPED. THEY LEFT A NOTE" + }, + { + "id": 965, + "fortune": "MEDIOCRITY TAKES EFFORT TOO. WELL DONE" + }, + { + "id": 966, + "fortune": "YOU EXCEEDED EXPECTATIONS. THEY WERE LOW" + }, + { + "id": 967, + "fortune": "YOUR BARE MINIMUM HAS A LOYAL FOLLOWING" + }, + { + "id": 968, + "fortune": "YOU RAISED THE BAR. FROM THE FLOOR" + }, + { + "id": 969, + "fortune": "CONSISTENCY IS KEY. YOURS IS CONSISTENT" + }, + { + "id": 970, + "fortune": "YOUR AVERAGE IS ABOVE AVERAGE. AT AVERAGING" + }, + { + "id": 971, + "fortune": "PROGRESS WAS MADE. LATERALLY. BUT MADE" + }, + { + "id": 972, + "fortune": "YOUR TRAJECTORY IS STABLE. FLAT. STABLE" + }, + { + "id": 973, + "fortune": "ONWARD AND UPWARD. OR SIDEWAYS. ONWARD" + }, + { + "id": 974, + "fortune": "YOU PIVOTED. THE DIRECTION WAS RANDOM" + }, + { + "id": 975, + "fortune": "YOUR MOMENTUM TOOK A PERSONAL DAY" + }, + { + "id": 976, + "fortune": "FULL SPEED AHEAD. YOUR SPEED. SO GENTLE" + }, + { + "id": 977, + "fortune": "YOU HIT THE GROUND WALKING. BRISKLY EVEN" + }, + { + "id": 978, + "fortune": "YOUR SPRINT BECAME A STROLL. SCENIC ONE" + }, + { + "id": 979, + "fortune": "BABY STEPS COUNT. YOURS ARE NEWBORN" + }, + { + "id": 980, + "fortune": "YOU ARE ON A ROLL. A SLOW GENTLE ROLL" + }, + { + "id": 981, + "fortune": "YOUR STREAK CONTINUES. WHICHEVER ONE" + }, + { + "id": 982, + "fortune": "MOMENTUM IS BUILDING. SOMEWHERE ELSE" + }, + { + "id": 983, + "fortune": "THE FINISH LINE MOVED. SO DID YOU. BACKWARD" + }, + { + "id": 984, + "fortune": "YOUR MARATHON IS A SERIES OF SNACK BREAKS" + }, + { + "id": 985, + "fortune": "YOU CROSSED A LINE TODAY. NOT THE FINISH ONE" + }, + { + "id": 986, + "fortune": "VICTORY IS NEAR. DEFINE VICTORY LOOSELY" + }, + { + "id": 987, + "fortune": "YOU WON THE ARGUMENT. THE ROOM WAS EMPTY" + }, + { + "id": 988, + "fortune": "CHAMPIONS TRAIN DAILY. YOU WATCHED THEM" + }, + { + "id": 989, + "fortune": "YOUR TROPHY SHELF HOLDS PARTICIPATION" + }, + { + "id": 990, + "fortune": "SECOND PLACE IS FIRST LOSER. YOU GOT FIFTH" + }, + { + "id": 991, + "fortune": "YOUR COMEBACK SEASON IS ALWAYS NEXT SEASON" + }, + { + "id": 992, + "fortune": "THE UNDERDOG STORY NEEDS AN ATTEMPT FIRST" + }, + { + "id": 993, + "fortune": "YOUR RIVALS STOPPED CHECKING ON YOU" + }, + { + "id": 994, + "fortune": "GLORY AWAITS. IT DOUBLE BOOKED THOUGH" + }, + { + "id": 995, + "fortune": "YOU MADE THE HIGHLIGHT REEL. AS A BLOOPER" + }, + { + "id": 996, + "fortune": "HISTORY FAVOURS THE BOLD. YOU FAVOUR NAPS" + }, + { + "id": 997, + "fortune": "YOUR SPLIT FLAP DISPLAY DESERVED BETTER TEXT" + }, + { + "id": 998, + "fortune": "THIS MESSAGE USED 45 CHARACTERS WISELY. ISH" + }, + { + "id": 999, + "fortune": "YOU BUILT A DISPLAY FOR THIS. WORTH IT" + }, + { + "id": 1000, + "fortune": "EACH FLAP TURNED FOR THIS WISDOM. SAVOR IT" + }, + { + "id": 1001, + "fortune": "YOUR TEA IS BREWING. YOU FORGOT IT. AGAIN" + }, + { + "id": 1002, + "fortune": "GOOD FORTUNE QUEUED POLITELY. THEN LEFT" + }, + { + "id": 1003, + "fortune": "YOU ARE DEAD CHUFFED. ABOUT VERY LITTLE" + }, + { + "id": 1004, + "fortune": "YOUR PLANS WENT PEAR SHAPED. AS FORECAST" + }, + { + "id": 1005, + "fortune": "MIND THE GAP. BETWEEN HOPE AND MONDAY" + }, + { + "id": 1006, + "fortune": "YOU SAID SORRY FIRST. YOU ALWAYS DO" + }, + { + "id": 1007, + "fortune": "A CHEEKY WIN NEARS. VERY CHEEKY. VERY SMALL" + }, + { + "id": 1008, + "fortune": "YOUR BISCUIT DUNKED TOO LONG. TRAGEDY STRUCK" + }, + { + "id": 1009, + "fortune": "IT HAS ALL GONE PETE TONG. AS USUAL" + }, + { + "id": 1010, + "fortune": "YOU ARE GUTTED. AND IT IS ONLY TUESDAY" + }, + { + "id": 1011, + "fortune": "YOUR FORTNIGHT PLAN LASTED ONE DAY" + }, + { + "id": 1012, + "fortune": "KEEP CALM. YOU HAVE NO OTHER SETTING" + }, + { + "id": 1013, + "fortune": "THE KETTLE IS ON. YOUR AMBITIONS ARENT" + }, + { + "id": 1014, + "fortune": "BRILLIANT NEWS AWAITS. FOR SOMEONE ELSE" + }, + { + "id": 1015, + "fortune": "YOU FANCY A CHANGE. THE CHANGE FANCIES OTHERS" + }, + { + "id": 1016, + "fortune": "THE FORECAST SAYS SUN. PACK A BROLLY" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_en.json b/apps/sarcastic-fortune-cookies/fortunes_en.json new file mode 100644 index 0000000..bb516dc --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_en.json @@ -0,0 +1,4002 @@ +[ +{ +"id":1, +"fortune":"EVERYTHING HAPPENS. RARELY FOR A REASON" +}, +{ +"id":2, +"fortune":"GOOD LUCK IS COMING. IT WALKS SLOWLY" +}, +{ +"id":3, +"fortune":"THE UNIVERSE HAS A PLAN. A MODEST ONE" +}, +{ +"id":4, +"fortune":"YOUR DESTINY CALLED. IT RESCHEDULED" +}, +{ +"id":5, +"fortune":"FATE HAS PLANS FOR YOU. BACKUP PLANS" +}, +{ +"id":6, +"fortune":"THE STARS ALIGNED. THEN THEY SAW YOU" +}, +{ +"id":7, +"fortune":"LUCK FAVORS THE BOLD. YOU CAN WATCH" +}, +{ +"id":8, +"fortune":"YOUR SHIP IS COMING IN. IT IS A CANOE" +}, +{ +"id":9, +"fortune":"TRUST THE PROCESS. IT DOES NOT TRUST YOU" +}, +{ +"id":10, +"fortune":"A SIGN IS COMING. IT SAYS YIELD" +}, +{ +"id":11, +"fortune":"YOUR LUCKY STAR IS IN ANOTHER GALAXY" +}, +{ +"id":12, +"fortune":"KARMA IS REAL. THAT EXPLAINS A LOT" +}, +{ +"id":13, +"fortune":"THE FUTURE IS BRIGHT. WEAR SUNSCREEN" +}, +{ +"id":14, +"fortune":"DESTINY AWAITS. IT BROUGHT A BOOK" +}, +{ +"id":15, +"fortune":"MIRACLES HAPPEN DAILY. ELSEWHERE MOSTLY" +}, +{ +"id":16, +"fortune":"YOUR MOMENT IS COMING. IT IS IN TRAFFIC" +}, +{ +"id":17, +"fortune":"FORTUNE KNOCKED ONCE. YOU WERE OUT" +}, +{ +"id":18, +"fortune":"THE TIDE IS TURNING. GLACIALLY" +}, +{ +"id":19, +"fortune":"BIG THINGS ARE COMING. LOWER THE BAR" +}, +{ +"id":20, +"fortune":"OPPORTUNITY IS NEAR. YOU TWO KEEP MISSING" +}, +{ +"id":21, +"fortune":"THE COSMOS HEARD YOU. YOU ARE IN THE QUEUE" +}, +{ +"id":22, +"fortune":"YOUR STARS ARE FINE. YOUR CHOICES ARENT" +}, +{ +"id":23, +"fortune":"WISH ON A STAR. THE STAR MARKED IT SPAM" +}, +{ +"id":24, +"fortune":"GOOD THINGS TAKE TIME. YOURS TAKE DECADES" +}, +{ +"id":25, +"fortune":"A WINDFALL NEARS. DRESS IN LAYERS" +}, +{ +"id":26, +"fortune":"THE SIGNS WERE THERE. READING IS OPTIONAL" +}, +{ +"id":27, +"fortune":"YOU ARE ONE IN A MILLION. SO ARE THOUSANDS" +}, +{ +"id":28, +"fortune":"THE BEST IS YET TO COME. NO RUSH APPARENTLY" +}, +{ +"id":29, +"fortune":"YOUR AURA IS RADIANT. IT WORKS OVERTIME" +}, +{ +"id":30, +"fortune":"LADY LUCK SMILED. POLITELY. AT A STRANGER" +}, +{ +"id":31, +"fortune":"YOUR PRAYERS WERE HEARD. AND FILED" +}, +{ +"id":32, +"fortune":"ABUNDANCE FLOWS TO YOU. UPSTREAM SADLY" +}, +{ +"id":33, +"fortune":"FORTUNES WHEEL TURNS. YOU ARE THE HAMSTER" +}, +{ +"id":34, +"fortune":"EVERY CLOUD HAS A LINING. YOURS IS DAMP" +}, +{ +"id":35, +"fortune":"SERENDIPITY IS ASKING AROUND ABOUT YOU" +}, +{ +"id":36, +"fortune":"A LUCKY BREAK NEARS. BREAK HAS TWO MEANINGS" +}, +{ +"id":37, +"fortune":"THE ORACLE SPOKE. MOSTLY IT SIGHED" +}, +{ +"id":38, +"fortune":"YOUR HOROSCOPE LOOKS GREAT. IT IS FICTION" +}, +{ +"id":39, +"fortune":"COSMIC JUSTICE EXISTS. SETTLE OUT OF COURT" +}, +{ +"id":40, +"fortune":"LIGHTNING WONT STRIKE TWICE. YOU MIGHT" +}, +{ +"id":41, +"fortune":"FATE REWARDS PATIENCE. INVOICE PENDING" +}, +{ +"id":42, +"fortune":"THE MOON SAW YOUR FRESH START. AGAIN" +}, +{ +"id":43, +"fortune":"YOUR SPIRIT GUIDE REQUESTED A TRANSFER" +}, +{ +"id":44, +"fortune":"ANGELS WATCH OVER YOU. TAKING NOTES" +}, +{ +"id":45, +"fortune":"BELIEVE AND RECEIVE. RECEIPTS VARY" +}, +{ +"id":46, +"fortune":"YOUR GOLDEN ERA NEARS. GOLD PLATED" +}, +{ +"id":47, +"fortune":"WHAT IS MEANT FOR YOU IS NOT HURRYING" +}, +{ +"id":48, +"fortune":"THE UNIVERSE WINKED. OR HAD AN EYE ISSUE" +}, +{ +"id":49, +"fortune":"YOUR LUCK IS CHANGING. DIRECTION UNCLEAR" +}, +{ +"id":50, +"fortune":"PROVIDENCE PROVIDES. IT CHECKS RECEIPTS" +}, +{ +"id":51, +"fortune":"SUCCESS IS NEAR. SO IS THE SNOOZE BUTTON" +}, +{ +"id":52, +"fortune":"HARD WORK PAYS OFF. IN EXPOSURE" +}, +{ +"id":53, +"fortune":"YOUR POTENTIAL IS LIMITLESS. AND UNUSED" +}, +{ +"id":54, +"fortune":"DREAM BIG. SET AN ALARM THOUGH" +}, +{ +"id":55, +"fortune":"THE EARLY BIRD LEFT WITHOUT YOU" +}, +{ +"id":56, +"fortune":"YOUR BIG BREAK NEARS. DO NOT BREAK IT" +}, +{ +"id":57, +"fortune":"ROME WASNT BUILT IN A DAY. YOURS ISNT STARTED" +}, +{ +"id":58, +"fortune":"YOUR TALENTS WILL BE FOUND. WITH A WARRANT" +}, +{ +"id":59, +"fortune":"AIM FOR THE STARS. MIND THE CEILING" +}, +{ +"id":60, +"fortune":"WINNERS NEVER QUIT. YOU FOUND COASTING" +}, +{ +"id":61, +"fortune":"YOUR IDEAS ARE AHEAD. YOUR DEADLINES BEHIND" +}, +{ +"id":62, +"fortune":"EXCELLENCE IS A HABIT. SO IS YOURS" +}, +{ +"id":63, +"fortune":"YOUR WORK SPEAKS. IT REQUESTED A LAWYER" +}, +{ +"id":64, +"fortune":"THE TOP IS LONELY. YOU SOLVED THAT PROBLEM" +}, +{ +"id":65, +"fortune":"A PROMOTION NEARS. SOMEONE ELSES" +}, +{ +"id":66, +"fortune":"YOUR RESUME IMPRESSES FICTION FANS" +}, +{ +"id":67, +"fortune":"YOUR BEST WORK IS AHEAD. IT IS VERY FAST" +}, +{ +"id":68, +"fortune":"THAT MEETING COULD HAVE BEEN AN EMAIL" +}, +{ +"id":69, +"fortune":"YOUR INBOX IS NOT YOUR ENEMY. JUST A WITNESS" +}, +{ +"id":70, +"fortune":"DEADLINES FEAR NOTHING. YOU WALK PAST THEM" +}, +{ +"id":71, +"fortune":"YOUR FIVE YEAR PLAN IS FIVE YEARS OLD" +}, +{ +"id":72, +"fortune":"SLOW AND STEADY WINS. YOU NAILED SLOW" +}, +{ +"id":73, +"fortune":"YOUR CALENDAR IS FULL. OF BUFFERS" +}, +{ +"id":74, +"fortune":"YOUR TEAM DREAMS TOO. OF TRANSFERS" +}, +{ +"id":75, +"fortune":"THE OCCASION LOWERED ITSELF TO MEET YOU" +}, +{ +"id":76, +"fortune":"SUCCESS LEAVES CLUES. YOU PREFER MYSTERY" +}, +{ +"id":77, +"fortune":"YOUR COMFORT ZONE NEEDS ITS OWN ZIP CODE" +}, +{ +"id":78, +"fortune":"QUALITY OVER QUANTITY. YOU DECLINED BOTH" +}, +{ +"id":79, +"fortune":"YOUR INSTINCTS ARE SHARP. FACTS ON SABBATICAL" +}, +{ +"id":80, +"fortune":"YOU WORK WELL UNDER PRESSURE. IT DISAGREES" +}, +{ +"id":81, +"fortune":"MASTERY TAKES 10000 HOURS. YOU HAVE 40" +}, +{ +"id":82, +"fortune":"YOUR DESK PLANT BELIEVED IN YOU. AND WATER" +}, +{ +"id":83, +"fortune":"THE PRINTER KNOWS YOU ARE IN A HURRY" +}, +{ +"id":84, +"fortune":"YOUR LEGACY IS UNDER CONSTRUCTION. STILL" +}, +{ +"id":85, +"fortune":"AN AWARD AWAITS. PARTICIPATION COUNTS" +}, +{ +"id":86, +"fortune":"YOUR CAN DO ATTITUDE MET YOUR DID NOT RECORD" +}, +{ +"id":87, +"fortune":"NETWORKING OPENS DOORS. TRY KNOCKING TOO" +}, +{ +"id":88, +"fortune":"YOU LEAD BY EXAMPLE. HR WANTS A NEW ONE" +}, +{ +"id":89, +"fortune":"YOUR SIDE HUSTLE JOINED THE OTHERS. RESTING" +}, +{ +"id":90, +"fortune":"GENIUS IS 1 PERCENT WORK. YOU STOPPED THERE" +}, +{ +"id":91, +"fortune":"YOUR OUT OF OFFICE REPLY IS YOUR BEST WORK" +}, +{ +"id":92, +"fortune":"FAILURE IS A STEPPING STONE. NICE STAIRCASE" +}, +{ +"id":93, +"fortune":"YOU ARE IRREPLACEABLE. THE POSTING IS DRAFTED" +}, +{ +"id":94, +"fortune":"YOUR PERFORMANCE REVIEW NEARS. REHEARSE" +}, +{ +"id":95, +"fortune":"EFFICIENCY IS YOUR MIDDLE NAME. LEGALLY ONLY" +}, +{ +"id":96, +"fortune":"YOU WILL LAND ON YOUR FEET. LANDING DELAYED" +}, +{ +"id":97, +"fortune":"THE SUMMIT IS CLOSE. SO IS BASE CAMP" +}, +{ +"id":98, +"fortune":"YOUR AMBITION WOKE UP. YOUR ALARM DID NOT" +}, +{ +"id":99, +"fortune":"BE YOURSELF. EVERYONE ELSE WAS ALARMED" +}, +{ +"id":100, +"fortune":"KNOW THYSELF. A BRIEF INTRO MAY HELP" +}, +{ +"id":101, +"fortune":"YOUR GLOW UP IS COMING. NOTIFY THE GRID" +}, +{ +"id":102, +"fortune":"NEW YEAR NEW YOU. THE OLD YOU LEFT NOTES" +}, +{ +"id":103, +"fortune":"YOU ARE ENOUGH. THE BAR WAS ADJUSTABLE" +}, +{ +"id":104, +"fortune":"YOUR INNER PEACE SAW YOUR SCHEDULE. IT LEFT" +}, +{ +"id":105, +"fortune":"GROWTH TAKES TIME. YOURS FILED AN EXTENSION" +}, +{ +"id":106, +"fortune":"YOU ARE A WORK IN PROGRESS. MOSTLY WORK" +}, +{ +"id":107, +"fortune":"SELF AWARENESS IS A GIFT. YOURS SHIPPED" +}, +{ +"id":108, +"fortune":"HEALING IS NOT LINEAR. YOURS IS A SCRIBBLE" +}, +{ +"id":109, +"fortune":"YOUR BEST SELF IS EMERGING. IT HIT SNOOZE" +}, +{ +"id":110, +"fortune":"SELF CARE MATTERS. STREAMING IS NOT A SPA" +}, +{ +"id":111, +"fortune":"YOUR BOUNDARIES ARE HEALTHY. AND UNTESTED" +}, +{ +"id":112, +"fortune":"GRATITUDE HELPS. TRY IT ON PEOPLE" +}, +{ +"id":113, +"fortune":"YOU FORGIVE EASILY. YOURSELF ESPECIALLY" +}, +{ +"id":114, +"fortune":"YOUR HABITS DEFINE YOU. OUR CONDOLENCES" +}, +{ +"id":115, +"fortune":"SMALL STEPS COUNT. EVEN TO THE FRIDGE" +}, +{ +"id":116, +"fortune":"YOUR INTUITION IS POWERFUL. AND WRONG" +}, +{ +"id":117, +"fortune":"MINDFULNESS HELPS. YOUR PHONE DISAGREES" +}, +{ +"id":118, +"fortune":"YOU LET GO OF THE PAST. IT HAS YOUR ADDRESS" +}, +{ +"id":119, +"fortune":"YOUR MORNING ROUTINE IS SACRED. ALL 4 MINUTES" +}, +{ +"id":120, +"fortune":"YOU ARE LEARNING TO SAY NO. TO VEGETABLES" +}, +{ +"id":121, +"fortune":"YOUR WILLPOWER LIFTS ALMOST A WHOLE COOKIE" +}, +{ +"id":122, +"fortune":"YOUR PURPOSE EXISTS. IT STAYS ANONYMOUS" +}, +{ +"id":123, +"fortune":"YOU EMBRACE CHANGE. MOSTLY COUCH CHANGE" +}, +{ +"id":124, +"fortune":"YOUR JOURNAL IS RAW AND HONEST. BOTH PAGES" +}, +{ +"id":125, +"fortune":"YOU LIVE YOUR TRUTH. FACT CHECK PENDING" +}, +{ +"id":126, +"fortune":"YOUR INNER CRITIC ONLY SIGHS NOW" +}, +{ +"id":127, +"fortune":"YOUR TRANSFORMATION NEEDED LABELED PHOTOS" +}, +{ +"id":128, +"fortune":"YOUR GOALS ARE IN SIGHT. NICE BINOCULARS" +}, +{ +"id":129, +"fortune":"YOUR NEW HABITS LOOK FAMILIAR. SUSPICIOUSLY" +}, +{ +"id":130, +"fortune":"YOUR ENERGY IS MAGNETIC. TO OBLIGATIONS" +}, +{ +"id":131, +"fortune":"YOUR WALLS CAME DOWN. THE MOAT EXPANDED" +}, +{ +"id":132, +"fortune":"YOU CELEBRATE SMALL WINS. DAILY. SOMEONE MUST" +}, +{ +"id":133, +"fortune":"YOUR EVOLUTION PUZZLES DARWIN" +}, +{ +"id":134, +"fortune":"YOU PUT YOURSELF FIRST. THE LINE WAS SHORT" +}, +{ +"id":135, +"fortune":"YOUR REINVENTION TOUR CONTINUES. SAME SETLIST" +}, +{ +"id":136, +"fortune":"YOU ARE PRESENT. PHYSICALLY AT LEAST" +}, +{ +"id":137, +"fortune":"YOUR FRESH START STARTS MONDAY. A FUTURE ONE" +}, +{ +"id":138, +"fortune":"YOUR VISION BOARD IS STUNNING. AND RETIRED" +}, +{ +"id":139, +"fortune":"YOU HONOR YOUR FEELINGS. AT FULL VOLUME" +}, +{ +"id":140, +"fortune":"YOUR CALM IS REAL. YOU STOPPED CHECKING EMAIL" +}, +{ +"id":141, +"fortune":"YOUR STANDARDS ARE RISING. FROM SEA LEVEL" +}, +{ +"id":142, +"fortune":"YOU ARE BLOOMING. LATE SEASON. STILL COUNTS" +}, +{ +"id":143, +"fortune":"YOUR DISCIPLINE IS THE STUFF OF LEGEND" +}, +{ +"id":144, +"fortune":"YOUR AFFIRMATIONS WORK. ON THE CEILING" +}, +{ +"id":145, +"fortune":"TRUE LOVE AWAITS. IT IS RUNNING LATE TOO" +}, +{ +"id":146, +"fortune":"YOUR SOULMATE EXISTS. COVERAGE MAY VARY" +}, +{ +"id":147, +"fortune":"ROMANCE IS IN THE AIR. SO IS POLLEN" +}, +{ +"id":148, +"fortune":"CUPID HAS YOUR ADDRESS. HE DROVE PAST TWICE" +}, +{ +"id":149, +"fortune":"YOUR HEART KNOWS THE WAY. YOUR TEXTS DONT" +}, +{ +"id":150, +"fortune":"LOVE IS BLIND. YOURS ALSO FORGETS" +}, +{ +"id":151, +"fortune":"YOUR EX THINKS OF YOU. AS A LESSON" +}, +{ +"id":152, +"fortune":"YOUR FLIRTING IS SUBTLE. UNDETECTABLE EVEN" +}, +{ +"id":153, +"fortune":"YOUR TYPE IS CONSISTENT. THAT IS THE PROBLEM" +}, +{ +"id":154, +"fortune":"SOMEONE ADMIRES YOU FROM AFAR. STAY THERE" +}, +{ +"id":155, +"fortune":"YOUR GREEN FLAGS ARE LOVELY. AND OUTNUMBERED" +}, +{ +"id":156, +"fortune":"LOVE CONQUERS ALL. IT REQUESTED BACKUP" +}, +{ +"id":157, +"fortune":"HEART ON YOUR SLEEVE. DRY CLEAN BOTH" +}, +{ +"id":158, +"fortune":"A TEXT FROM THE PAST NEARS. DO NOT REPLY" +}, +{ +"id":159, +"fortune":"YOUR CRUSH KNOWS YOU EXIST. AS A CONCEPT" +}, +{ +"id":160, +"fortune":"YOU LOVE DEEPLY. BRIEFLY. BUT DEEPLY" +}, +{ +"id":161, +"fortune":"YOUR HEART IS OPEN. SO IS YOUR TAB" +}, +{ +"id":162, +"fortune":"SPARKS WILL FLY. CHECK THE SMOKE ALARM" +}, +{ +"id":163, +"fortune":"YOU ARE READY FOR COMMITMENT. TO A COUCH" +}, +{ +"id":164, +"fortune":"YOUR MEET CUTE NEARS. A MEET ADEQUATE" +}, +{ +"id":165, +"fortune":"YOUR HEART HEALED. IT ADDED SECURITY" +}, +{ +"id":166, +"fortune":"LOVE IS PATIENT. IT HAD PRACTICE WITH YOU" +}, +{ +"id":167, +"fortune":"YOUR REBOUND GAME BEATS THE ORIGINAL" +}, +{ +"id":168, +"fortune":"YOUR HONEYMOON PHASE LASTED 11 DAYS" +}, +{ +"id":169, +"fortune":"YOUR PET IS YOUR BEST RELATIONSHIP. IT AGREES" +}, +{ +"id":170, +"fortune":"YOUR VOWS WILL MAKE PEOPLE CRY. THE GRAMMAR" +}, +{ +"id":171, +"fortune":"YOU ARE A CATCH. CATCH AND RELEASE EXISTS" +}, +{ +"id":172, +"fortune":"ABSENCE MAKES HEARTS FONDER. KEEP TESTING" +}, +{ +"id":173, +"fortune":"YOUR PERFECT MATCH EXISTS. THE APP GAVE UP" +}, +{ +"id":174, +"fortune":"YOUR RED FLAGS ARE MAROON NOW. PROGRESS" +}, +{ +"id":175, +"fortune":"LOVE AT FIRST SIGHT IS REAL. GET GLASSES" +}, +{ +"id":176, +"fortune":"YOUR HEART WANTS THINGS. SEE A SPECIALIST" +}, +{ +"id":177, +"fortune":"SOMEONE THINKS YOU ARE PERFECT. FROM AFAR" +}, +{ +"id":178, +"fortune":"YOU BELIEVE IN SECOND CHANCES. AND FIFTHS" +}, +{ +"id":179, +"fortune":"YOUR BREAKUP PLAYLIST GETS HEAVY USE" +}, +{ +"id":180, +"fortune":"YOU ARE WORTH THE WAIT. THE WAIT CONTINUES" +}, +{ +"id":181, +"fortune":"ROMANCE IS NOT DEAD. YOURS IS RESTING" +}, +{ +"id":182, +"fortune":"YOUR IN LAWS WILL ADORE YOU. EVENTUALLY" +}, +{ +"id":183, +"fortune":"YOUR DATING BIO IS HONEST. SELECTIVELY" +}, +{ +"id":184, +"fortune":"YOUR HUGS ARE GREAT. AND RARE. LIKE ECLIPSES" +}, +{ +"id":185, +"fortune":"SOMEONE DREAMS OF YOUR COOKING. IN FEAR" +}, +{ +"id":186, +"fortune":"YOUR CHARM OPENS DOORS. PUSH DONT PULL" +}, +{ +"id":187, +"fortune":"YOUR STANDARDS MET YOUR CHOICES. AWKWARD" +}, +{ +"id":188, +"fortune":"YOU WILL BE SWEPT AWAY. STRETCH FIRST" +}, +{ +"id":189, +"fortune":"INTIMACY MEANS BEING SEEN. YOU NEGOTIATED" +}, +{ +"id":190, +"fortune":"YOUR LOVE STORY WILL BE TOLD. AS A WARNING" +}, +{ +"id":191, +"fortune":"THE SPARK IS STILL THERE. SEND A SEARCH PARTY" +}, +{ +"id":192, +"fortune":"YOUR ANNIVERSARY NEARS. THIS IS THE REMINDER" +}, +{ +"id":193, +"fortune":"LOVE YOURSELF FIRST. YOU MASTERED THAT PART" +}, +{ +"id":194, +"fortune":"YOUR HEART SKIPPED A BEAT. SEE A DOCTOR" +}, +{ +"id":195, +"fortune":"YOU BRING OUT THE BEST. AS PEOPLE LEAVE" +}, +{ +"id":196, +"fortune":"YOU NEVER SETTLE. HENCE THE FOLDING CHAIRS" +}, +{ +"id":197, +"fortune":"YOUR FUTURE PARTNER IS TRAINING. UNKNOWINGLY" +}, +{ +"id":198, +"fortune":"YOU GET GREAT ADVICE. FOLLOWING IT IS NEW" +}, +{ +"id":199, +"fortune":"YOUR HEART IS A FORTRESS. GIFT SHOP OPEN" +}, +{ +"id":200, +"fortune":"YOUR FRIENDS VALUE YOUR HONESTY. FROM AFAR" +}, +{ +"id":201, +"fortune":"A FRIEND WILL CALL SOON. THEY NEED A TRUCK" +}, +{ +"id":202, +"fortune":"YOU ARE THE GLUE. GLUE IS RARELY THANKED" +}, +{ +"id":203, +"fortune":"THE GROUP CHAT ENJOYS YOUR SILENCE" +}, +{ +"id":204, +"fortune":"TRUE FRIENDS ARE RARE. YOURS ARE HIDING" +}, +{ +"id":205, +"fortune":"YOUR LOYALTY IS UNMATCHED. YOUR TIMING ISNT" +}, +{ +"id":206, +"fortune":"A GATHERING BRINGS JOY. LEAVING BRINGS MORE" +}, +{ +"id":207, +"fortune":"YOU ARE THE FUN ONE. SELF REPORTED" +}, +{ +"id":208, +"fortune":"AN OLD FRIEND RESURFACES. THEY ARE MOVING" +}, +{ +"id":209, +"fortune":"YOUR ADVICE IS APPRECIATED. NOT REQUESTED" +}, +{ +"id":210, +"fortune":"YOU LIGHT UP ROOMS. SOME WANT DIMMERS" +}, +{ +"id":211, +"fortune":"YOUR BIRTHDAY WILL BE REMEMBERED. LATE" +}, +{ +"id":212, +"fortune":"YOUR STORIES IMPROVE YEARLY. ACCURACY DROPS" +}, +{ +"id":213, +"fortune":"PEOPLE GRAVITATE TO YOU. GRAVITY PULLS DOWN" +}, +{ +"id":214, +"fortune":"YOU ALWAYS KNOW WHAT TO SAY. TIMING EXTRA" +}, +{ +"id":215, +"fortune":"FRIENDS COME AND GO. YOURS EXCEL AT GO" +}, +{ +"id":216, +"fortune":"YOUR SOCIAL CALENDAR IS FULL. OF MAYBES" +}, +{ +"id":217, +"fortune":"YOU ARE A PEOPLE PERSON. UNVERIFIED" +}, +{ +"id":218, +"fortune":"YOUR INSIDE JOKES ARE NOW SOLO ACTS" +}, +{ +"id":219, +"fortune":"YOUR HOSTING IMPROVES. THE FIRE DEPT AGREES" +}, +{ +"id":220, +"fortune":"YOU BRING PEOPLE TOGETHER. TO DISCUSS YOU" +}, +{ +"id":221, +"fortune":"YOUR GENEROSITY HAS OFFICE HOURS" +}, +{ +"id":222, +"fortune":"YOU NEVER FORGET A FACE. NAMES OPTED OUT" +}, +{ +"id":223, +"fortune":"YOUR PEP TALKS REQUIRE FOLLOW UP CARE" +}, +{ +"id":224, +"fortune":"YOU SHOW UP WHEN IT MATTERS. TO YOU" +}, +{ +"id":225, +"fortune":"YOUR GOING AWAY PARTIES DRAW CROWDS" +}, +{ +"id":226, +"fortune":"PEOPLE CONFIDE IN YOU. AND THEN IN OTHERS" +}, +{ +"id":227, +"fortune":"YOUR HONESTY IS REFRESHING. LIKE ICE WATER" +}, +{ +"id":228, +"fortune":"YOU NEVER HOLD GRUDGES. YOU ARCHIVE THEM" +}, +{ +"id":229, +"fortune":"YOUR MEMES ARRIVE AT DAWN. UNREQUESTED" +}, +{ +"id":230, +"fortune":"YOU ARE A SHOULDER TO CRY ON. BY APPOINTMENT" +}, +{ +"id":231, +"fortune":"YOUR CANCELED DINNER PARTIES ARE LEGEND" +}, +{ +"id":232, +"fortune":"YOU KEEP EVERYONE GROUNDED. LIKE FOG" +}, +{ +"id":233, +"fortune":"YOUR ENTHUSIASM IS INFECTIOUS. MASKS EXIST" +}, +{ +"id":234, +"fortune":"A FRIEND WANTS YOUR HONEST OPINION. A TRAP" +}, +{ +"id":235, +"fortune":"YOU SPLIT BILLS FAIRLY. YOUR MATH DIFFERS" +}, +{ +"id":236, +"fortune":"YOUR PRESENCE IS A GIFT. REGIFTING HAPPENS" +}, +{ +"id":237, +"fortune":"YOUR COMPETITIVENESS RETIRED THE GAMES" +}, +{ +"id":238, +"fortune":"YOUR SURPRISE PARTIES SURPRISE NO ONE" +}, +{ +"id":239, +"fortune":"PEOPLE FEEL COMFORTABLE AROUND YOU. TO LEAVE" +}, +{ +"id":240, +"fortune":"YOU SAY WHAT EVERYONE THINKS. AT FUNERALS" +}, +{ +"id":241, +"fortune":"YOUR HOLIDAY LETTER HAS A READERSHIP" +}, +{ +"id":242, +"fortune":"YOUR APOLOGIES ARE HEARTFELT. AND FREQUENT" +}, +{ +"id":243, +"fortune":"YOU ARE THE KEEPER OF GROUP HISTORY. REVISED" +}, +{ +"id":244, +"fortune":"YOU NEVER MISS A CHANCE TO HELP. OR SAY SO" +}, +{ +"id":245, +"fortune":"YOUR DIRECTNESS IS CHARMING. AGREED WORD" +}, +{ +"id":246, +"fortune":"YOU ARE FASHIONABLY LATE. MINUS THE FASHION" +}, +{ +"id":247, +"fortune":"PEOPLE SEEK YOUR APPROVAL. TO END THE CHAT" +}, +{ +"id":248, +"fortune":"YOU NEVER GOSSIP. YOU BRIEF THE ABSENT" +}, +{ +"id":249, +"fortune":"YOUR INVITES SAY CASUAL. YOUR TEXTS DONT" +}, +{ +"id":250, +"fortune":"AN OLD FRIEND REMEMBERS YOU. FROM AFAR" +}, +{ +"id":251, +"fortune":"YOU NEVER LOSE ARGUMENTS. YOU RELOCATE THEM" +}, +{ +"id":252, +"fortune":"YOUR SUPPORT IS UNCONDITIONAL. SEE TERMS" +}, +{ +"id":253, +"fortune":"WEALTH IS COMING. IT HAS YOUR OLD ADDRESS" +}, +{ +"id":254, +"fortune":"MONEY FLOWS TO YOU. THROUGH YOU. GONE" +}, +{ +"id":255, +"fortune":"YOUR BUDGET IS ART. ABSTRACT ART" +}, +{ +"id":256, +"fortune":"SAVE FOR A RAINY DAY. MONSOONS FORECAST" +}, +{ +"id":257, +"fortune":"YOUR CREDIT SCORE IS A THRILLER" +}, +{ +"id":258, +"fortune":"YOUR SAVINGS GROW. CHARACTER MOSTLY" +}, +{ +"id":259, +"fortune":"MONEY TALKS. YOURS SAYS GOODBYE" +}, +{ +"id":260, +"fortune":"YOUR RETIREMENT PLAN IS A LOTTERY TICKET" +}, +{ +"id":261, +"fortune":"YOU HAVE EXPENSIVE TASTE. AND A BUDGET" +}, +{ +"id":262, +"fortune":"COMPOUND INTEREST IS MAGIC. YOU CHOSE DEBT" +}, +{ +"id":263, +"fortune":"YOUR EMERGENCY FUND COVERS SMALL EMERGENCIES" +}, +{ +"id":264, +"fortune":"A RAISE IS DESERVED. AND UNSCHEDULED" +}, +{ +"id":265, +"fortune":"YOUR CART IS A VISION BOARD WITH CHECKOUT" +}, +{ +"id":266, +"fortune":"YOUR GENEROSITY IS FAMOUS. AMONG VENDORS" +}, +{ +"id":267, +"fortune":"THE BEST THINGS ARE FREE. YOURS SHIP" +}, +{ +"id":268, +"fortune":"YOUR SUBSCRIPTIONS OUTNUMBER YOUR FRIENDS" +}, +{ +"id":269, +"fortune":"BUY LOW SELL HIGH. YOU INVENTED THE REVERSE" +}, +{ +"id":270, +"fortune":"YOUR BANK TEXTS OUT OF CONCERN NOW" +}, +{ +"id":271, +"fortune":"YOUR TAX REFUND HAS OTHER PLANS" +}, +{ +"id":272, +"fortune":"YOUR SPLURGES ARE STRATEGIC. ALLEGEDLY" +}, +{ +"id":273, +"fortune":"YOU WILL FIND MONEY IN A COAT. IT WAS YOURS" +}, +{ +"id":274, +"fortune":"YOUR PORTFOLIO IS DIVERSIFIED. IN REGRETS" +}, +{ +"id":275, +"fortune":"PAYDAY BRINGS JOY. ABOUT 18 HOURS OF IT" +}, +{ +"id":276, +"fortune":"YOUR LATE FEES HAVE LATE FEES NOW" +}, +{ +"id":277, +"fortune":"A PENNY SAVED IS A START. A SMALL ONE" +}, +{ +"id":278, +"fortune":"RICH IN SPIRIT. THE REGISTER DISAGREES" +}, +{ +"id":279, +"fortune":"YOUR RECEIPTS TELL A STORY. A LONG ONE" +}, +{ +"id":280, +"fortune":"YOUR DOWN PAYMENT BECAME SUSHI. TWICE" +}, +{ +"id":281, +"fortune":"YOUR BUDGET SHEET IS HISTORICAL FICTION" +}, +{ +"id":282, +"fortune":"YOUR FREE TRIALS NEVER DIE. THEY BILL" +}, +{ +"id":283, +"fortune":"CASH IS KING. YOUR KINGDOM RUNS ON CREDIT" +}, +{ +"id":284, +"fortune":"YOUR SPENDING FREEZE LASTED 40 MINUTES" +}, +{ +"id":285, +"fortune":"YOUR BILLS ARRIVE ON TIME. UNLIKE YOU" +}, +{ +"id":286, +"fortune":"YOUR MONEY WORKS HARD. FOR OTHER PEOPLE" +}, +{ +"id":287, +"fortune":"YOUR COUPONS EXPIRED. ALL OF THEM. TODAY" +}, +{ +"id":288, +"fortune":"YOUR FINANCIAL PLAN HAS PHASES. DENIAL FIRST" +}, +{ +"id":289, +"fortune":"YOUR DISCOUNTS FUND YOUR IMPULSE BUYS" +}, +{ +"id":290, +"fortune":"YOUR CRYPTO PHASE WAS EDUCATIONAL. AND COSTLY" +}, +{ +"id":291, +"fortune":"THE LOTTERY IS A HOPE TAX. YOU DONATE WEEKLY" +}, +{ +"id":292, +"fortune":"YOUR SAVINGS GOAL HASNT MOVED SINCE SPRING" +}, +{ +"id":293, +"fortune":"WEALTH WHISPERS. YOURS BLOCKED THE NUMBER" +}, +{ +"id":294, +"fortune":"YOU TRACK EVERY EXPENSE. THEN MAKE MORE" +}, +{ +"id":295, +"fortune":"YOUR PIGGY BANK HAS TRUST ISSUES. EARNED" +}, +{ +"id":296, +"fortune":"YOUR REFUND ARRIVED. ALREADY SPENT. TWICE" +}, +{ +"id":297, +"fortune":"MONEY CANT BUY HAPPINESS. YOURS QUIT TRYING" +}, +{ +"id":298, +"fortune":"YOUR INVOICES AGE LIKE FINE WINE. UNPAID" +}, +{ +"id":299, +"fortune":"YOUR NET WORTH AND SELF WORTH BOTH DIPPED" +}, +{ +"id":300, +"fortune":"PATIENCE IS A VIRTUE. YOU CHOSE OTHERS" +}, +{ +"id":301, +"fortune":"SILENCE IS GOLDEN. YOURS WOULD FUND A NATION" +}, +{ +"id":302, +"fortune":"THINK BEFORE YOU SPEAK. A PILOT PROGRAM" +}, +{ +"id":303, +"fortune":"STILL WATERS RUN DEEP. YOURS RUN ANKLE HIGH" +}, +{ +"id":304, +"fortune":"KNOWLEDGE IS POWER. YOURS IS ON STANDBY" +}, +{ +"id":305, +"fortune":"AN OPEN MIND IS A TREASURE. NICE BREEZE" +}, +{ +"id":306, +"fortune":"LISTEN TWICE SPEAK ONCE. INVERT YOUR RATIO" +}, +{ +"id":307, +"fortune":"THE TRUTH WILL SET YOU FREE. YOURS SAT DOWN" +}, +{ +"id":308, +"fortune":"LOOK BEFORE YOU LEAP. OR AFTER. YOUR WAY" +}, +{ +"id":309, +"fortune":"A FOOL AND HIS MONEY HAD A NICE CEREMONY" +}, +{ +"id":310, +"fortune":"ACTIONS SPEAK LOUDER. YOURS WHISPER" +}, +{ +"id":311, +"fortune":"MEASURE TWICE CUT ONCE. YOU CUT FIRST" +}, +{ +"id":312, +"fortune":"THE PEN IS MIGHTY. YOUR EMAILS ARE WEAPONS" +}, +{ +"id":313, +"fortune":"BETTER LATE THAN NEVER. YOU TEST THIS DAILY" +}, +{ +"id":314, +"fortune":"HONESTY IS THE BEST POLICY. READ THE RIDERS" +}, +{ +"id":315, +"fortune":"DONT COUNT YOUR CHICKENS. YOURS UNIONIZED" +}, +{ +"id":316, +"fortune":"GRASS IS GREENER WHERE WATERED. BUY A HOSE" +}, +{ +"id":317, +"fortune":"EVERY SAINT HAS A PAST. YOURS HAS A FILE" +}, +{ +"id":318, +"fortune":"PRACTICE WHAT YOU PREACH. OR PREACH LESS" +}, +{ +"id":319, +"fortune":"TWO WRONGS DONT MAKE A RIGHT. STOP AT NINE" +}, +{ +"id":320, +"fortune":"ALL THAT GLITTERS ISNT GOLD. CHECK RECEIPTS" +}, +{ +"id":321, +"fortune":"A ROLLING STONE GATHERS NO MOSS. NICE MOSS" +}, +{ +"id":322, +"fortune":"DONT PUT ALL EGGS IN ONE BASKET. FIND BASKET" +}, +{ +"id":323, +"fortune":"EMPTY VESSELS ARE LOUD. GREAT ACOUSTICS" +}, +{ +"id":324, +"fortune":"HE WHO LAUGHS LAST THOUGHT SLOWEST. HI" +}, +{ +"id":325, +"fortune":"A BIRD IN HAND IS WORTH TWO. YOURS FLEW" +}, +{ +"id":326, +"fortune":"IF IT AINT BROKE DONT FIX IT. TOO LATE" +}, +{ +"id":327, +"fortune":"YOU CAN LEAD A HORSE TO WATER. IT DECLINED" +}, +{ +"id":328, +"fortune":"PRIDE GOES BEFORE A FALL. NICE BALANCE" +}, +{ +"id":329, +"fortune":"TIME HEALS ALL WOUNDS. YOURS PICK AT IT" +}, +{ +"id":330, +"fortune":"OLD HABITS DIE HARD. YOURS BOUGHT INSURANCE" +}, +{ +"id":331, +"fortune":"WHERE THERE IS SMOKE THERE IS YOU" +}, +{ +"id":332, +"fortune":"THE BEST DEFENSE IS DISTANCE. THEY LEARNED" +}, +{ +"id":333, +"fortune":"FAMILIARITY BREEDS CONTEMPT. THRIVING HERE" +}, +{ +"id":334, +"fortune":"THE DEVIL IS IN THE DETAILS. YOURS ARE EMPTY" +}, +{ +"id":335, +"fortune":"ONE MANS TRASH IS YOUR GARAGE" +}, +{ +"id":336, +"fortune":"A WATCHED POT NEVER BOILS. YOURS BOILED OVER" +}, +{ +"id":337, +"fortune":"IGNORANCE IS BLISS. YOU SEEM SERENE" +}, +{ +"id":338, +"fortune":"BEAUTY IS IN THE EYE. GET THE EYE CHECKED" +}, +{ +"id":339, +"fortune":"IT TAKES A VILLAGE. YOURS REQUESTED BACKUP" +}, +{ +"id":340, +"fortune":"GREAT MINDS THINK ALIKE. YOURS WENT SOLO" +}, +{ +"id":341, +"fortune":"THE PROOF IS IN THE PUDDING. NO COMMENT" +}, +{ +"id":342, +"fortune":"EVERY DOG HAS ITS DAY. YOURS WAS A TUESDAY" +}, +{ +"id":343, +"fortune":"NOTHING VENTURED NOTHING GAINED. PERFECT TIE" +}, +{ +"id":344, +"fortune":"TOO MANY COOKS SPOIL BROTH. YOU SOLOED IT" +}, +{ +"id":345, +"fortune":"YOU REAP WHAT YOU SOW. INTERESTING HARVEST" +}, +{ +"id":346, +"fortune":"ASK AND RECEIVE. YOUR ASKING MADE A LINE" +}, +{ +"id":347, +"fortune":"WALK A MILE IN THEIR SHOES. RETURN THEM" +}, +{ +"id":348, +"fortune":"HASTE MAKES WASTE. YOU KEPT ONLY WASTE" +}, +{ +"id":349, +"fortune":"ALL GOOD THINGS END. YOURS END EARLY" +}, +{ +"id":350, +"fortune":"WORDS ARE CHEAP. YOURS ARE FREE" +}, +{ +"id":351, +"fortune":"TIME WAITS FOR NO ONE. IT MADE AN EXCEPTION" +}, +{ +"id":352, +"fortune":"DONT BITE THE FEEDING HAND. IT WEARS GLOVES" +}, +{ +"id":353, +"fortune":"COMPARISON STEALS JOY. YOURS HIRED IT" +}, +{ +"id":354, +"fortune":"HALF A LOAF BEATS NONE. YOU OFFER CRUMBS" +}, +{ +"id":355, +"fortune":"A SMOOTH SEA NEVER MADE A SAILOR. STAY DOCKED" +}, +{ +"id":356, +"fortune":"THE TRUTH NEEDS NO REHEARSAL. YOURS DOES" +}, +{ +"id":357, +"fortune":"EVERYTHING IN MODERATION. EVEN THAT. STOP" +}, +{ +"id":358, +"fortune":"WHAT GOES AROUND COMES AROUND. TRACK IT" +}, +{ +"id":359, +"fortune":"NEVER ARGUE WITH A FOOL. ONLOOKERS STRUGGLE" +}, +{ +"id":360, +"fortune":"WISDOM WHISPERS. YOURS IS ON MUTE" +}, +{ +"id":361, +"fortune":"A THOUSAND MILE JOURNEY STARTS. YOU STRETCH" +}, +{ +"id":362, +"fortune":"CROSS BRIDGES WHEN YOU REACH THEM. NOT BURN" +}, +{ +"id":363, +"fortune":"THE MIGHTY OAK WAS A NUT. HERITAGE PRESERVED" +}, +{ +"id":364, +"fortune":"FOOL ME ONCE. YOUR CARD HAS NINE STAMPS" +}, +{ +"id":365, +"fortune":"ADVENTURE AWAITS. IT OPENED A BUSINESS" +}, +{ +"id":366, +"fortune":"YOU WILL TRAVEL FAR. THE SHUTTLE COUNTS" +}, +{ +"id":367, +"fortune":"YOUR PASSPORT PHOTO IS THE REAL YOU" +}, +{ +"id":368, +"fortune":"YOUR BUCKET LIST NEEDS A BUCKET" +}, +{ +"id":369, +"fortune":"YOU WILL SEE THE WORLD. VIA DOCUMENTARY" +}, +{ +"id":370, +"fortune":"YOUR VACATION DAYS AGE LIKE FINE GUILT" +}, +{ +"id":371, +"fortune":"AN EXOTIC PLACE CALLED. YOU SCREENED IT" +}, +{ +"id":372, +"fortune":"YOUR ROAD TRIP PLAYLIST OUTLIVED THE TRIP" +}, +{ +"id":373, +"fortune":"YOU PACK LIGHT. EMOTIONALLY YOU DONT" +}, +{ +"id":374, +"fortune":"YOUR SOUVENIRS TELL STORIES. ABOUT PRICING" +}, +{ +"id":375, +"fortune":"YOU WILL GET LOST ABROAD. A HOME SKILL" +}, +{ +"id":376, +"fortune":"YOUR TRAVEL PICS STAR YOUR THUMB" +}, +{ +"id":377, +"fortune":"A SPONTANEOUS TRIP NEARS. WITH SPREADSHEETS" +}, +{ +"id":378, +"fortune":"YOU ARE A WORLD CITIZEN. REFERENCES PENDING" +}, +{ +"id":379, +"fortune":"YOUR BEACH BODY IS READY. THE BEACH ADAPTED" +}, +{ +"id":380, +"fortune":"THE MOUNTAINS ARE CALLING. YOU MUTED THEM" +}, +{ +"id":381, +"fortune":"YOUR STAYCATION GAME IS UNRIVALED" +}, +{ +"id":382, +"fortune":"YOU NAVIGATE LIKE A LOCAL. A LOST ONE" +}, +{ +"id":383, +"fortune":"YOUR ITINERARY IS MOSTLY BUFFER TIME" +}, +{ +"id":384, +"fortune":"YOUR HIKING BOOTS SUMMITED THE CLOSET" +}, +{ +"id":385, +"fortune":"JET LAG RESPECTS NO ONE. YOU CAME PRE TIRED" +}, +{ +"id":386, +"fortune":"YOUR TRAVEL JOURNAL HAS ONE ENTRY. EXCITED" +}, +{ +"id":387, +"fortune":"YOU COLLECT EXPERIENCES. THE CARD DISAGREES" +}, +{ +"id":388, +"fortune":"YOUR SENSE OF DIRECTION IS A FAMILY LEGEND" +}, +{ +"id":389, +"fortune":"A GETAWAY NEARS. THE LAUNDRY WILL WAIT" +}, +{ +"id":390, +"fortune":"YOU WILL RETURN CHANGED. MOSTLY YOUR SLEEP" +}, +{ +"id":391, +"fortune":"YOUR AIRPORT TIMING IS A PERSONALITY TEST" +}, +{ +"id":392, +"fortune":"YOUR WINDOW SEAT PICS FEATURE THE WING" +}, +{ +"id":393, +"fortune":"YOUR CARRY ON HAS ITS OWN GRAVITY NOW" +}, +{ +"id":394, +"fortune":"YOUR CAMPING SKILLS AMUSE THE RACCOONS" +}, +{ +"id":395, +"fortune":"TIME ZONES CONFUSE YOUR SLEEP. IT COPES" +}, +{ +"id":396, +"fortune":"YOUR HOTEL REVIEWS ARE FEARED. BY TOWELS" +}, +{ +"id":397, +"fortune":"YOU BEFRIEND STRANGERS ABROAD. ALSO LOST ONES" +}, +{ +"id":398, +"fortune":"YOUR CRUISE PACE MATCHES YOUR BUFFET PACE" +}, +{ +"id":399, +"fortune":"FORTUNE FAVORS TRAVELERS. YOURS LIKES COUCHES" +}, +{ +"id":400, +"fortune":"YOUR PHONE BATTERY OUTLASTS YOUR DRIVE" +}, +{ +"id":401, +"fortune":"YOU WILL READ THE TERMS SOMEDAY. NO" +}, +{ +"id":402, +"fortune":"YOUR SCREEN TIME REPORT SOFTENS THE NEWS" +}, +{ +"id":403, +"fortune":"YOUR LAUNDRY CHAIR EARNED TENURE" +}, +{ +"id":404, +"fortune":"YOUR ALARM HAS FIVE BACKUPS. ALL IGNORED" +}, +{ +"id":405, +"fortune":"YOUR FRIDGE HOSTS A SCIENCE EXPERIMENT" +}, +{ +"id":406, +"fortune":"THE CHECK ENGINE LIGHT IS A MOOD LIGHT NOW" +}, +{ +"id":407, +"fortune":"YOUR HOUSEPLANTS ACCEPTED THEIR FATE" +}, +{ +"id":408, +"fortune":"YOUR JUNK DRAWER OPENED A SECOND LOCATION" +}, +{ +"id":409, +"fortune":"YOUR GYM BAG IS PACKED. THAT COUNTS" +}, +{ +"id":410, +"fortune":"YOUR VOICEMAIL IS FULL. PEOPLE MOVED ON" +}, +{ +"id":411, +"fortune":"YOUR BROWSER TABS ARE AN ECOSYSTEM NOW" +}, +{ +"id":412, +"fortune":"YOUR UMBRELLA WAITS. YOU WILL FORGET IT" +}, +{ +"id":413, +"fortune":"YOUR LEFTOVERS HAD DREAMS. THEY COMPOST" +}, +{ +"id":414, +"fortune":"YOUR TO DO LIST HAS A TO DO LIST" +}, +{ +"id":415, +"fortune":"YOUR CLOSET DRESSES THREE VERSIONS OF YOU" +}, +{ +"id":416, +"fortune":"YOUR MORNING RUN IS LAMINATED. NOT RUN" +}, +{ +"id":417, +"fortune":"YOUR WIFI ROUTER SITS ON A SHRINE. CORRECT" +}, +{ +"id":418, +"fortune":"YOUR INBOX ZERO ATTEMPT IS HISTORY NOW" +}, +{ +"id":419, +"fortune":"YOUR SOCK DRAWER RUNS WITNESS PROTECTION" +}, +{ +"id":420, +"fortune":"YOUR GROCERY LIST STAYS HOME. IT KNOWS" +}, +{ +"id":421, +"fortune":"YOUR WATCHLIST OUTLIVED THREE HOBBIES" +}, +{ +"id":422, +"fortune":"YOUR DESK IS ERGONOMIC. YOUR COUCH ISNT" +}, +{ +"id":423, +"fortune":"THE PRINTER SENSES FEAR. AND UPDATES" +}, +{ +"id":424, +"fortune":"YOUR BEDTIME IS A MOTION YOU VOTE DOWN" +}, +{ +"id":425, +"fortune":"YOUR HEADPHONES TANGLE ALONE. SCIENCE WEEPS" +}, +{ +"id":426, +"fortune":"YOUR SPICE RACK IS SORTED THROUGH C" +}, +{ +"id":427, +"fortune":"YOUR BACKSEAT IS A LOST AND FOUND" +}, +{ +"id":428, +"fortune":"YOUR CART ABANDONMENT RATE MADE THE NEWS" +}, +{ +"id":429, +"fortune":"THE GOOD CABLE IS WHEREVER YOU ARENT" +}, +{ +"id":430, +"fortune":"YOUR STANDING DESK MOSTLY SITS. LIKE YOU" +}, +{ +"id":431, +"fortune":"YOUR MEAL PREP MADE ONE MEAL. SIX BOXES" +}, +{ +"id":432, +"fortune":"THE DELIVERY DRIVER WAVES AT YOU NOW" +}, +{ +"id":433, +"fortune":"YOUR AIR FRYER REPLACED THE OVEN. AND YOU" +}, +{ +"id":434, +"fortune":"YOUR BOOKMARKS ARE A HALL OF INTENTIONS" +}, +{ +"id":435, +"fortune":"YOUR SNOOZE BUTTON SHOWS GEOLOGIC WEAR" +}, +{ +"id":436, +"fortune":"YOUR REUSABLE BAGS WAIT IN THE CAR. LOYAL" +}, +{ +"id":437, +"fortune":"YOUR UPDATES HAVE SENIORITY NOW" +}, +{ +"id":438, +"fortune":"THE ICE TRAY RETURNS EMPTY. A TRADITION" +}, +{ +"id":439, +"fortune":"YOUR GARAGE STORES EVERYTHING BUT THE CAR" +}, +{ +"id":440, +"fortune":"YOUR STEP COUNTER FRAMED ITS BEST DAY" +}, +{ +"id":441, +"fortune":"YOUR FAVORITE MUG HAS PROTECTED STATUS" +}, +{ +"id":442, +"fortune":"YOUR WEATHER APP GAVE UP ON YOUR OUTFITS" +}, +{ +"id":443, +"fortune":"YOUR SCALE PRACTICES RADICAL HONESTY" +}, +{ +"id":444, +"fortune":"YOUR REMOTES COMMUTE FROM THE CUSHIONS" +}, +{ +"id":445, +"fortune":"THE HALLWAY CLOSET HOLDS YOUR TRUTH. BARELY" +}, +{ +"id":446, +"fortune":"YOU OWN EVERY BATTERY SIZE BUT THE ONE NEEDED" +}, +{ +"id":447, +"fortune":"YOUR VACUUM AVOIDS CORNERS. LIKE YOU" +}, +{ +"id":448, +"fortune":"YOUR SHOWER THOUGHTS STAY IN THE SHOWER" +}, +{ +"id":449, +"fortune":"YOUR COFFEE MAKER KNOWS YOUR MONDAY FACE" +}, +{ +"id":450, +"fortune":"YOUR FREEZER FLOOR PREDATES FRIENDSHIPS" +}, +{ +"id":451, +"fortune":"YOUR PHONE STORAGE IS ALL SCREENSHOTS" +}, +{ +"id":452, +"fortune":"YOUR BIKE TIRES EXHALE SLOWLY. LIKE A SIGH" +}, +{ +"id":453, +"fortune":"YOUR RETURNS PILE HAS A DEPARTURE LOUNGE" +}, +{ +"id":454, +"fortune":"YOUR CANDLES ARE DECOR. MATCHES AGREE" +}, +{ +"id":455, +"fortune":"YOUR DINING TABLE RETIRED FROM DINING" +}, +{ +"id":456, +"fortune":"YOUR PREDICTIVE TEXT SUGGESTS SORRY FIRST" +}, +{ +"id":457, +"fortune":"YOUR FITNESS APP USES SHORTER SENTENCES NOW" +}, +{ +"id":458, +"fortune":"YOUR COAT POCKET IS A TIME CAPSULE" +}, +{ +"id":459, +"fortune":"THE ADD 30 SECONDS BUTTON RUNS YOUR KITCHEN" +}, +{ +"id":460, +"fortune":"THE GOOD SCISSORS ARE MISSING. ONE SUSPECT" +}, +{ +"id":461, +"fortune":"YOUR DOWNLOADS FOLDER IS A LANDFILL" +}, +{ +"id":462, +"fortune":"YOUR PLANTS RUN ON GUILT BASED WATERING" +}, +{ +"id":463, +"fortune":"THE DRYER TAKES ONE SOCK AS TRIBUTE" +}, +{ +"id":464, +"fortune":"YOUR COASTERS WATCH FROM THE SIDELINES" +}, +{ +"id":465, +"fortune":"YOUR NOTES APP IS A GENIUS LANDFILL" +}, +{ +"id":466, +"fortune":"RAIN WILL WASH YOUR CAR. YOUR PLAN EXACTLY" +}, +{ +"id":467, +"fortune":"YOUR BOARD GAMES AGE IN SHRINK WRAP" +}, +{ +"id":468, +"fortune":"YOUR YOGA MAT UNROLLED TWICE. FOR NAPS" +}, +{ +"id":469, +"fortune":"YOUR EXTENSION CORDS BREED IN THE DARK" +}, +{ +"id":470, +"fortune":"YOUR SMART SPEAKER HAS HEARD THINGS" +}, +{ +"id":471, +"fortune":"YOUR LIDS AND CONTAINERS NEVER MATCH. EVER" +}, +{ +"id":472, +"fortune":"YOUR WALKING SHOES TOUR THE TRUNK" +}, +{ +"id":473, +"fortune":"YOUR IMPORTANT FOLDER IS A HOSPICE" +}, +{ +"id":474, +"fortune":"YOUR WREATH IS PERENNIAL NOW. FESTIVE" +}, +{ +"id":475, +"fortune":"THAT ONE DRAWER STOPPED EXPLAINING ITSELF" +}, +{ +"id":476, +"fortune":"YOUR SCREEN AT 2AM REVEALS EVERYTHING" +}, +{ +"id":477, +"fortune":"YOUR FIRE EXTINGUISHER RUNS ON CONFIDENCE" +}, +{ +"id":478, +"fortune":"YOUR WATER GOAL WAS MET ONCE. PLAQUE PENDING" +}, +{ +"id":479, +"fortune":"AGING SUITS YOU. THE ALTERNATIVE DIDNT" +}, +{ +"id":480, +"fortune":"YOUR AGE IS JUST A NUMBER. AN ASCENDING ONE" +}, +{ +"id":481, +"fortune":"YOUR KNEES FORECAST WEATHER NOW. A SKILL" +}, +{ +"id":482, +"fortune":"YOUR BACK WENT OUT MORE THAN YOU DID" +}, +{ +"id":483, +"fortune":"WISDOM COMES WITH GRAY HAIR. YOURS CAME EARLY" +}, +{ +"id":484, +"fortune":"YOU AGE LIKE WINE. STORED HORIZONTALLY" +}, +{ +"id":485, +"fortune":"YOUR BIRTHDAY CANDLES ARE A FIRE HAZARD" +}, +{ +"id":486, +"fortune":"YOUR READING GLASSES NEED READING GLASSES" +}, +{ +"id":487, +"fortune":"YOUR PLAYLIST IS CALLED OLDIES NOW. BY KIDS" +}, +{ +"id":488, +"fortune":"YOU GROAN WHEN SITTING. A VERBAL RECEIPT" +}, +{ +"id":489, +"fortune":"YOUR METABOLISM RETIRED WITHOUT NOTICE" +}, +{ +"id":490, +"fortune":"YOU FEEL 25. YOUR HANGOVERS DISAGREE" +}, +{ +"id":491, +"fortune":"AN APPLE A DAY. PIE IS A LOOPHOLE. SURE" +}, +{ +"id":492, +"fortune":"YOUR POSTURE IMPROVES TWICE DAILY. BRIEFLY" +}, +{ +"id":493, +"fortune":"YOU WILL SLEEP 8 HOURS. ACROSS 3 NIGHTS" +}, +{ +"id":494, +"fortune":"YOUR VITAMINS EXPIRE UNTAKEN. RENEWABLE" +}, +{ +"id":495, +"fortune":"YOUR DIET STARTS MONDAY. MONDAYS UNIONIZED" +}, +{ +"id":496, +"fortune":"YOUR DENTIST KNOWS YOU FLOSSED TODAY ONLY" +}, +{ +"id":497, +"fortune":"YOUR RESTING HEART RATE IS GREAT. FITTING" +}, +{ +"id":498, +"fortune":"YOU WILL LIVE TO 100. OUT OF SPITE" +}, +{ +"id":499, +"fortune":"YOUR HIDDEN TALENTS REMAIN WELL HIDDEN" +}, +{ +"id":500, +"fortune":"YOUR CREATIVITY HAS NO BOUNDS. OR OUTPUT" +}, +{ +"id":501, +"fortune":"YOU HAVE A GIFT. NO RECEIPT INCLUDED" +}, +{ +"id":502, +"fortune":"YOUR NOVEL WILL BE FINISHED. BY SOMEONE" +}, +{ +"id":503, +"fortune":"YOU WERE BORN TO CREATE. EXCUSES COUNT" +}, +{ +"id":504, +"fortune":"YOUR MASTERPIECE IS INSIDE YOU. COZY THERE" +}, +{ +"id":505, +"fortune":"YOUR SINGING BRINGS TEARS. BIOLOGY IS ODD" +}, +{ +"id":506, +"fortune":"THE MUSE VISITS YOU. SHE CALLS AHEAD NOW" +}, +{ +"id":507, +"fortune":"YOUR PHOTOS CAPTURE RAW CONFUSION" +}, +{ +"id":508, +"fortune":"YOU THINK OUTSIDE THE BOX. THE BOX WORRIES" +}, +{ +"id":509, +"fortune":"YOUR POETRY MOVES PEOPLE. TO THE EXITS" +}, +{ +"id":510, +"fortune":"YOUR IMAGINATION IS VAST. EXECUTION ISNT" +}, +{ +"id":511, +"fortune":"YOU SEE THE WORLD DIFFERENTLY. GET CHECKED" +}, +{ +"id":512, +"fortune":"YOUR PODCAST IDEA JOINS THE OTHER SIX" +}, +{ +"id":513, +"fortune":"CREATIVITY FLOWS PAST YOU. WAVING" +}, +{ +"id":514, +"fortune":"YOUR DOODLES BELONG SOMEWHERE. A DRAWER" +}, +{ +"id":515, +"fortune":"YOUR COOKING IS PERFORMANCE ART. WITH ALARMS" +}, +{ +"id":516, +"fortune":"YOUR SCREENPLAY HAS POTENTIAL ENERGY ONLY" +}, +{ +"id":517, +"fortune":"THE WORLD IS YOUR CANVAS. STILL PRIMED" +}, +{ +"id":518, +"fortune":"YOUR DIY PROJECTS ARE AN UNFINISHED TRILOGY" +}, +{ +"id":519, +"fortune":"YOUR MUSIC TASTE IS GREAT. NEIGHBORS DISSENT" +}, +{ +"id":520, +"fortune":"YOUR DANCE MOVES DEFY CONVENTION. AND PHYSICS" +}, +{ +"id":521, +"fortune":"YOU TELL GREAT STORIES. ENDINGS PENDING" +}, +{ +"id":522, +"fortune":"PHARMACISTS FRAME YOUR HANDWRITING" +}, +{ +"id":523, +"fortune":"YOUR IDEAS ARRIVE AT 2AM. GONE BY 8" +}, +{ +"id":524, +"fortune":"YOUR SKETCHBOOK HOLDS GREAT PROMISES" +}, +{ +"id":525, +"fortune":"YOU COULD WRITE A BOOK. A STRONG PAMPHLET" +}, +{ +"id":526, +"fortune":"YOUR POTTERY PHASE MADE MEMORABLE PIECES" +}, +{ +"id":527, +"fortune":"YOUR INNER ARTIST WANTS COFFEE FIRST" +}, +{ +"id":528, +"fortune":"YOUR COLOR CHOICES ARE COURAGEOUS" +}, +{ +"id":529, +"fortune":"YOUR GUITAR KNOWS THREE CHORDS WELL" +}, +{ +"id":530, +"fortune":"YOUR CREATIVE PROCESS IS UNDOCUMENTED" +}, +{ +"id":531, +"fortune":"YOUR SCARVES BECAME EXPERIENCES. KNIT ON" +}, +{ +"id":532, +"fortune":"YOU PAINT WITH EMOTION. THE FLOOR AGREES" +}, +{ +"id":533, +"fortune":"YOUR BONSAI IS A REGULAR TREE NOW. PATIENCE" +}, +{ +"id":534, +"fortune":"YOUR WRITING VOICE IS STRONG. IN TEXTS" +}, +{ +"id":535, +"fortune":"YOUR GARDEN GROWS. THE WEEDS THRIVE MOST" +}, +{ +"id":536, +"fortune":"YOUR CALLIGRAPHY PHASE WAS ONE WEEKEND" +}, +{ +"id":537, +"fortune":"YOUR WOODWORK IS HONEST. SPLINTERS DONT LIE" +}, +{ +"id":538, +"fortune":"YOUR FAN FICTION HAS FANS. BOTH OF THEM" +}, +{ +"id":539, +"fortune":"YOUR ORIGAMI FILLS THE RECYCLING BIN" +}, +{ +"id":540, +"fortune":"YOUR CREATIVE BLOCK IS LOAD BEARING NOW" +}, +{ +"id":541, +"fortune":"YOUR SOURDOUGH STARTER OUTLIVED THE HOBBY" +}, +{ +"id":542, +"fortune":"YOUR WATERCOLORS CAPTURE SOMETHING. UNCLEAR" +}, +{ +"id":543, +"fortune":"YOU EXCEL AT BEGINNINGS. MIDDLES DECLINED" +}, +{ +"id":544, +"fortune":"YOUR UKULELE EMBRACED ITS ROLE AS DECOR" +}, +{ +"id":545, +"fortune":"YOU ARE YOUR OWN WORST CRITIC. UNDISPUTED" +}, +{ +"id":546, +"fortune":"YOUR ART SPEAKS FOR ITSELF. QUIETLY" +}, +{ +"id":547, +"fortune":"YOUR STUDIO IS A CLOSET AGAIN. FUNCTIONAL" +}, +{ +"id":548, +"fortune":"YOUR FIRST DRAFTS NEVER MEET SECOND ONES" +}, +{ +"id":549, +"fortune":"YOUR CANDLE PHASE LEFT EVIDENCE. WAXY" +}, +{ +"id":550, +"fortune":"YOUR OPEN MIC DEBUT REMAINS IMMINENT" +}, +{ +"id":551, +"fortune":"YOUR PLAYLIST TRANSITIONS ARE ART. SHUFFLED" +}, +{ +"id":552, +"fortune":"YOUR COSTUMES SHOW COMMITMENT. TO CONCEPTS" +}, +{ +"id":553, +"fortune":"YOUR MACRAME OWL HAS SEEN YOUR PROJECTS" +}, +{ +"id":554, +"fortune":"YOUR VOICE MEMOS ARE MOSTLY GROCERIES" +}, +{ +"id":555, +"fortune":"YOU WILL BE DISCOVERED. ON YOUR COUCH" +}, +{ +"id":556, +"fortune":"YOUR MOOD BOARD IS ALL MOOD. NO BOARD" +}, +{ +"id":557, +"fortune":"YOUR FREESTYLE RAPS SHOULD STAY FREE" +}, +{ +"id":558, +"fortune":"YOUR MUSEUM VISITS END AT THE CAFE" +}, +{ +"id":559, +"fortune":"YOUR COVERS BEAT THE ORIGINALS. UNNOTIFIED" +}, +{ +"id":560, +"fortune":"YOUR TYPEWRITER LOOKS GREAT. STILL" +}, +{ +"id":561, +"fortune":"YOUR ABSTRACT PHASE CONFUSED EVEN YOU" +}, +{ +"id":562, +"fortune":"YOUR COMIC HAS A FOLLOWER. HI MOM" +}, +{ +"id":563, +"fortune":"YOUR SONG RHYMES ORANGE WITH DOOR HINGE" +}, +{ +"id":564, +"fortune":"YOUR CRAFT CORNER ANNEXED THE GUEST ROOM" +}, +{ +"id":565, +"fortune":"YOUR GENIUS IS MISUNDERSTOOD. AND UNSEEN" +}, +{ +"id":566, +"fortune":"YOUR MAGNUM OPUS IS BASICALLY ESPRESSO NOW" +}, +{ +"id":567, +"fortune":"YOUR INSPIRATION FOLDER HAS SUBFOLDERS" +}, +{ +"id":568, +"fortune":"THE FORTUNE YOU SEEK IS IN ANOTHER COOKIE" +}, +{ +"id":569, +"fortune":"THIS COOKIE CONTAINS NO FORTUNE. JUST CARBS" +}, +{ +"id":570, +"fortune":"IT IS DARK INSIDE THIS COOKIE. AND QUIET" +}, +{ +"id":571, +"fortune":"THIS FORTUNE LEFT INTENTIONALLY BLANK" +}, +{ +"id":572, +"fortune":"CONFUCIUS SAYS NOTHING ABOUT YOU. WISELY" +}, +{ +"id":573, +"fortune":"THIS FORTUNE WAS RECALLED. SAME TO YOU" +}, +{ +"id":574, +"fortune":"YOU WILL READ THIS ALOUD. UNPROMPTED" +}, +{ +"id":575, +"fortune":"THE COOKIE KNEW YOU WOULD TAKE THE LAST ONE" +}, +{ +"id":576, +"fortune":"SOME GET WISDOM. YOU CHOSE DESSERT" +}, +{ +"id":577, +"fortune":"THIS IS A COOKIE. NOT A LIFE COACH" +}, +{ +"id":578, +"fortune":"YOUR LUCKY NUMBERS HAVE OPTED OUT" +}, +{ +"id":579, +"fortune":"THE COOKIE ADMIRES YOUR OPTIMISM" +}, +{ +"id":580, +"fortune":"YOU SHOOK THE COOKIE FIRST. IT FELT THAT" +}, +{ +"id":581, +"fortune":"ASK AGAIN LATER. OR DONT. YOUR CALL" +}, +{ +"id":582, +"fortune":"THIS COOKIE WAS BAKED WITH LOW EXPECTATIONS" +}, +{ +"id":583, +"fortune":"THE FORTUNE WRITER IS ON BREAK. JUDGING" +}, +{ +"id":584, +"fortune":"NO WISDOM TODAY. INVENTORY ISSUES" +}, +{ +"id":585, +"fortune":"YOUR FORTUNE IS PENDING APPROVAL" +}, +{ +"id":586, +"fortune":"THIS MESSAGE WILL SELF DISAPPOINT" +}, +{ +"id":587, +"fortune":"THE COOKIE CRUMBLES. SO DO PLANS" +}, +{ +"id":588, +"fortune":"YOU EXPECTED MORE FROM A COOKIE. NOTED" +}, +{ +"id":589, +"fortune":"FORTUNE NOT FOUND. TRY ANOTHER DINNER" +}, +{ +"id":590, +"fortune":"THIS COOKIE HAS SEEN YOUR ORDER HISTORY" +}, +{ +"id":591, +"fortune":"THE LAST COOKIE ALWAYS TELLS THE TRUTH" +}, +{ +"id":592, +"fortune":"YOUR FORTUNE RAN OUT OF CHARACTERS. LUCKY" +}, +{ +"id":593, +"fortune":"A WISE MAN ONCE SAID NOTHING. TRY IT" +}, +{ +"id":594, +"fortune":"THE COOKIE BELIEVED IN YOU. PAST TENSE" +}, +{ +"id":595, +"fortune":"THIS FORTUNE IS ACCURATE. DETAILS REDACTED" +}, +{ +"id":596, +"fortune":"YOU HOLD THE KEY TO HAPPINESS. NOW FIND IT" +}, +{ +"id":597, +"fortune":"YOUR FORTUNE IS BEING WRITTEN. SLOWLY" +}, +{ +"id":598, +"fortune":"YOUR COFFEE ORDER IS A PARAGRAPH NOW" +}, +{ +"id":599, +"fortune":"COFFEE FIRST. PERSONALITY SECOND. FAIR" +}, +{ +"id":600, +"fortune":"YOUR FOURTH COFFEE IS WATCHING YOU" +}, +{ +"id":601, +"fortune":"DECAF EXISTS. YOU PRETEND IT DOESNT" +}, +{ +"id":602, +"fortune":"YOUR MUG COLLECTION OUTGREW THE CABINET" +}, +{ +"id":603, +"fortune":"YOUR ESPRESSO MACHINE JUDGES YOUR PODS" +}, +{ +"id":604, +"fortune":"YOU CALL IT BRUNCH. IT WAS BREAKFAST. LATE" +}, +{ +"id":605, +"fortune":"YOUR SALAD PHASE ENDED AT THE DRESSING" +}, +{ +"id":606, +"fortune":"YOU MEAL PLAN BEAUTIFULLY. THEN ORDER OUT" +}, +{ +"id":607, +"fortune":"YOUR SPICE TOLERANCE IS A PERSONALITY. SADLY" +}, +{ +"id":608, +"fortune":"YOUR SIGNATURE DISH HAS ONE FAN. YOU" +}, +{ +"id":609, +"fortune":"THE OVEN TIMER IS A SUGGESTION TO YOU" +}, +{ +"id":610, +"fortune":"YOUR SMOOTHIES HIDE VEGETABLES. FROM YOU" +}, +{ +"id":611, +"fortune":"YOU COOK WITH LOVE. AND TOO MUCH SALT" +}, +{ +"id":612, +"fortune":"YOUR RECIPE SUBSTITUTIONS ARE BRAVE" +}, +{ +"id":613, +"fortune":"GARLIC MEASURED WITH YOUR HEART. AGAIN" +}, +{ +"id":614, +"fortune":"YOUR TOAST GAME IS STRONG. LITERALLY BURNT" +}, +{ +"id":615, +"fortune":"YOU EAT DESSERT FIRST. LIFE IS SHORT. SURE" +}, +{ +"id":616, +"fortune":"YOUR SNACK DRAWER HAS A WAITING LIST" +}, +{ +"id":617, +"fortune":"THE FOOD DELIVERY APP KNOWS YOU BY NAME" +}, +{ +"id":618, +"fortune":"YOUR KITCHEN GADGETS FORM A MUSEUM" +}, +{ +"id":619, +"fortune":"YOUR TAKEOUT CONTAINERS ARE HEIRLOOMS NOW" +}, +{ +"id":620, +"fortune":"YOU SAY YOU COULD EAT ANYTHING. THEN DONT" +}, +{ +"id":621, +"fortune":"YOUR PIZZA TOPPINGS HAVE CRITICS" +}, +{ +"id":622, +"fortune":"YOUR DOG LOVES YOU UNCONDITIONALLY. TRAINED" +}, +{ +"id":623, +"fortune":"YOUR CAT TOLERATES YOU. A HIGH HONOR" +}, +{ +"id":624, +"fortune":"YOUR PET EATS BETTER THAN YOU DO" +}, +{ +"id":625, +"fortune":"YOUR DOG HAS MORE FRIENDS THAN YOU" +}, +{ +"id":626, +"fortune":"THE CAT KNOCKED IT OVER ON PURPOSE. RESPECT" +}, +{ +"id":627, +"fortune":"YOUR FISH KNOWS YOUR SCHEDULE. IT WORRIES" +}, +{ +"id":628, +"fortune":"YOUR PETS INSTAGRAM OUTPERFORMS YOURS" +}, +{ +"id":629, +"fortune":"THE DOG ATE YOUR MOTIVATION. NOT HOMEWORK" +}, +{ +"id":630, +"fortune":"YOUR CAT REVIEWS YOUR LIFE CHOICES NIGHTLY" +}, +{ +"id":631, +"fortune":"YOUR BIRD REPEATS YOUR WORST PHRASES" +}, +{ +"id":632, +"fortune":"YOUR PET THERAPIST IS A GOOD LISTENER. FREE" +}, +{ +"id":633, +"fortune":"RAIN IS COMING. YOUR CAR WASH REJOICES" +}, +{ +"id":634, +"fortune":"YOUR WINTER COAT DEBATE STARTS IN OCTOBER" +}, +{ +"id":635, +"fortune":"YOU CHECK THE WEATHER. THEN DRESS WRONG" +}, +{ +"id":636, +"fortune":"SPRING IS COMING. SO ARE YOUR ALLERGIES" +}, +{ +"id":637, +"fortune":"YOUR SUNSCREEN EXPIRES UNUSED. YEARLY" +}, +{ +"id":638, +"fortune":"SNOW IS MAGICAL. UNTIL YOU OWN A SHOVEL" +}, +{ +"id":639, +"fortune":"YOUR UMBRELLA COLLECTION LIVES ELSEWHERE" +}, +{ +"id":640, +"fortune":"SMALL TALK ABOUT WEATHER SUITS YOU NOW" +}, +{ +"id":641, +"fortune":"THE FORECAST CHANGED. YOUR PLANS DIDNT EXIST" +}, +{ +"id":642, +"fortune":"YOUR PATIO FURNITURE FEARS EVERY SEASON" +}, +{ +"id":643, +"fortune":"AUTUMN LEAVES FALL. LIKE YOUR RESOLUTIONS" +}, +{ +"id":644, +"fortune":"YOUR PASSWORD IS YOUR PETS NAME. WE KNOW" +}, +{ +"id":645, +"fortune":"YOU HAVE 47 UNREAD UPDATES. THEY WAIT" +}, +{ +"id":646, +"fortune":"YOUR CLOUD STORAGE IS FULL. OF DUPLICATES" +}, +{ +"id":647, +"fortune":"AUTOCORRECT KNOWS WHAT YOU MEANT. IT DECLINED" +}, +{ +"id":648, +"fortune":"YOUR ROUTER NEEDS A RESTART. LIKE YOU" +}, +{ +"id":649, +"fortune":"YOUR SEARCH HISTORY TELLS A SAGA" +}, +{ +"id":650, +"fortune":"YOU CLOSED ONE TAB TODAY. PROGRESS" +}, +{ +"id":651, +"fortune":"YOUR SPAM FOLDER MISSES YOU" +}, +{ +"id":652, +"fortune":"THE ALGORITHM KNOWS YOU TOO WELL. IT WORRIES" +}, +{ +"id":653, +"fortune":"YOUR SMARTWATCH SUGGESTS BREATHING. POINTED" +}, +{ +"id":654, +"fortune":"YOUR TYPING SPEED PEAKS DURING ARGUMENTS" +}, +{ +"id":655, +"fortune":"YOU MUTED THE GROUP. THE GROUP KNOWS" +}, +{ +"id":656, +"fortune":"YOUR CAPS LOCK GETS REGULAR EXERCISE" +}, +{ +"id":657, +"fortune":"YOUR EMOJI USE HAS BEEN DISCUSSED" +}, +{ +"id":658, +"fortune":"YOUR WIFI NAME IS YOUR BEST JOKE" +}, +{ +"id":659, +"fortune":"YOU RESTART THINGS AS A LIFESTYLE" +}, +{ +"id":660, +"fortune":"YOUR GYM MEMBERSHIP IS A DONATION NOW" +}, +{ +"id":661, +"fortune":"YOUR MARATHON PLAN IS SAVED. AND SAFE" +}, +{ +"id":662, +"fortune":"LEG DAY RESPECTS YOUR ABSENCE" +}, +{ +"id":663, +"fortune":"YOUR PROTEIN POWDER AGES GRACEFULLY" +}, +{ +"id":664, +"fortune":"YOU STRETCH ONCE A YEAR. AMBITIOUSLY" +}, +{ +"id":665, +"fortune":"YOUR SPORTS TEAM LOSES. YOU TAKE CREDIT" +}, +{ +"id":666, +"fortune":"YOUR FANTASY TEAM IS FANTASY INDEED" +}, +{ +"id":667, +"fortune":"YOU RUN LATE. IT COUNTS AS CARDIO" +}, +{ +"id":668, +"fortune":"YOUR HOME GYM STORES THE LAUNDRY NOW" +}, +{ +"id":669, +"fortune":"YOUR PERSONAL BEST WAS A GROUP EFFORT" +}, +{ +"id":670, +"fortune":"YOUR WARM UP IS THE WHOLE WORKOUT" +}, +{ +"id":671, +"fortune":"YOUR REST DAYS HAVE REST DAYS" +}, +{ +"id":672, +"fortune":"SLEEP IS FOR THE STRONG. YOU SCROLL" +}, +{ +"id":673, +"fortune":"YOUR NAP SCHEDULE IS YOUR REAL CALENDAR" +}, +{ +"id":674, +"fortune":"YOU COUNT SHEEP. THEY COUNT YOUR EXCUSES" +}, +{ +"id":675, +"fortune":"YOUR PILLOW KNOWS ALL YOUR SECRETS" +}, +{ +"id":676, +"fortune":"ONE MORE EPISODE WAS FOUR EPISODES" +}, +{ +"id":677, +"fortune":"YOUR DREAMS ARE VIVID. YOUR MORNINGS ARENT" +}, +{ +"id":678, +"fortune":"YOU SET SIX ALARMS. YOU FEAR NONE" +}, +{ +"id":679, +"fortune":"BEDTIME PROCRASTINATION IS STILL A CHOICE" +}, +{ +"id":680, +"fortune":"YOUR WEEKEND SLEEP DEBT COLLECTS INTEREST" +}, +{ +"id":681, +"fortune":"YOUR FAMILY LOVES YOU. THEY VOTED. CLOSE ONE" +}, +{ +"id":682, +"fortune":"YOUR MOTHER WAS RIGHT. ABOUT EVERYTHING" +}, +{ +"id":683, +"fortune":"FAMILY DINNERS TEST YOUR DIPLOMACY" +}, +{ +"id":684, +"fortune":"YOUR SIBLING REMEMBERS EVERYTHING. FOREVER" +}, +{ +"id":685, +"fortune":"YOUR RELATIVES ASK ABOUT YOUR PLANS. BRACE" +}, +{ +"id":686, +"fortune":"YOU ARE THE FAVORITE CHILD. UNCONFIRMED" +}, +{ +"id":687, +"fortune":"YOUR FAMILY GROUP CHAT NEVER SLEEPS" +}, +{ +"id":688, +"fortune":"GRANDMA FEEDS YOU. RESISTANCE IS FUTILE" +}, +{ +"id":689, +"fortune":"YOUR DAD JOKES SKIPPED NO GENERATIONS" +}, +{ +"id":690, +"fortune":"THANKSGIVING SEATING IS POLITICAL. YOURS IS" +}, +{ +"id":691, +"fortune":"YOUR NEIGHBOR WAVES. THE FENCE WAS HIS IDEA" +}, +{ +"id":692, +"fortune":"THE HOA NOTICED YOUR LAWN. AGAIN" +}, +{ +"id":693, +"fortune":"YOUR NEIGHBORS KNOW YOUR SCHEDULE. AND MORE" +}, +{ +"id":694, +"fortune":"BORROWED TOOLS BECOME GIFTS EVENTUALLY" +}, +{ +"id":695, +"fortune":"YOUR DOORBELL CAMERA SAW YOUR BEST SPRINT" +}, +{ +"id":696, +"fortune":"YOUR COMMUTE BUILDS CHARACTER. DAILY" +}, +{ +"id":697, +"fortune":"TRAFFIC IS NOT PERSONAL. YOURS FEELS PERSONAL" +}, +{ +"id":698, +"fortune":"YOUR PARKING JOB SPARKED CONVERSATIONS" +}, +{ +"id":699, +"fortune":"YOUR GPS SAYS RECALCULATING. WITH FEELING" +}, +{ +"id":700, +"fortune":"YOU DRIVE LIKE YOU LIVE. SIGNALS OPTIONAL" +}, +{ +"id":701, +"fortune":"YOUR GAS TANK RUNS ON FAITH. AND FUMES" +}, +{ +"id":702, +"fortune":"THE LEFT LANE IS FOR PASSING. JUST SAYING" +}, +{ +"id":703, +"fortune":"YOUR CAR PLAYLIST PEAKED IN 2016" +}, +{ +"id":704, +"fortune":"YOUR HORN GETS MORE USE THAN YOUR BLINKER" +}, +{ +"id":705, +"fortune":"ROAD RAGE IS BENEATH YOU. USUALLY" +}, +{ +"id":706, +"fortune":"YOUR PARALLEL PARKING DRAWS AUDIENCES" +}, +{ +"id":707, +"fortune":"TIME FLIES. YOURS FILED A FLIGHT PLAN" +}, +{ +"id":708, +"fortune":"PROCRASTINATION IS AN ART. YOU TEACH IT" +}, +{ +"id":709, +"fortune":"YOU WILL DO IT TOMORROW. TOMORROW KNOWS" +}, +{ +"id":710, +"fortune":"DEADLINES APPROACH. YOU ADMIRE THE VIEW" +}, +{ +"id":711, +"fortune":"YOUR FIVE MINUTES IS EVERYONE ELSES HOUR" +}, +{ +"id":712, +"fortune":"LATER IS YOUR FAVORITE TIME ZONE" +}, +{ +"id":713, +"fortune":"YOU FINISH THINGS. EVENTUALLY IS A WORD" +}, +{ +"id":714, +"fortune":"YOUR SOMEDAY LIST NEEDS ITS OWN SHELF" +}, +{ +"id":715, +"fortune":"TIME MANAGEMENT IS A SKILL. NOTED" +}, +{ +"id":716, +"fortune":"YOU ARE EARLY ONCE A YEAR. IT CONFUSES ALL" +}, +{ +"id":717, +"fortune":"THE PRESENT IS A GIFT. YOU CHOSE STORE CREDIT" +}, +{ +"id":718, +"fortune":"YOUR PUNCTUALITY IS LEGEND. THE BAD KIND" +}, +{ +"id":719, +"fortune":"YOU READ THIS INSTEAD OF WORKING. NOTED" +}, +{ +"id":720, +"fortune":"YOUR ATTENTION SPAN IS. OH LOOK A BIRD" +}, +{ +"id":721, +"fortune":"JUST ONE MORE MINUTE. THE FAMOUS LAST WORDS" +}, +{ +"id":722, +"fortune":"YOUR EMAILS START WITH SORRY FOR THE DELAY" +}, +{ +"id":723, +"fortune":"YOU REPLY TO TEXTS IN GEOLOGIC TIME" +}, +{ +"id":724, +"fortune":"YOUR READ RECEIPTS INCRIMINATE YOU" +}, +{ +"id":725, +"fortune":"YOU LEFT THEM ON READ. THEY NOTICED" +}, +{ +"id":726, +"fortune":"YOUR TYPING BUBBLE APPEARED. THEN LEFT" +}, +{ +"id":727, +"fortune":"YOU SAID LETS CIRCLE BACK. YOU WONT" +}, +{ +"id":728, +"fortune":"PER YOUR LAST EMAIL. YOU KNOW WHAT YOU DID" +}, +{ +"id":729, +"fortune":"YOUR VOICE NOTES ARE PODCASTS NOW" +}, +{ +"id":730, +"fortune":"YOU WAVED AT SOMEONE WAVING ELSEWHERE. AGAIN" +}, +{ +"id":731, +"fortune":"YOUR SMALL TALK HAS A SCRIPT. REHEARSE" +}, +{ +"id":732, +"fortune":"YOU SAID WE SHOULD HANG OUT SOON. CLASSIC" +}, +{ +"id":733, +"fortune":"YOUR PHONE IS ON SILENT. FOR YEARS NOW" +}, +{ +"id":734, +"fortune":"YOU SCREENSHOT INSTEAD OF RESPONDING" +}, +{ +"id":735, +"fortune":"YOUR OPINION WAS NOTED. AND RECYCLED" +}, +{ +"id":736, +"fortune":"YOU INTERRUPT WITH ENTHUSIASM. OFTEN" +}, +{ +"id":737, +"fortune":"RETAIL THERAPY IS STILL THERAPY. INVOICED" +}, +{ +"id":738, +"fortune":"YOUR PACKAGE ARRIVES TODAY. YOU ORDERED MORE" +}, +{ +"id":739, +"fortune":"YOU CAME FOR ONE ITEM. YOU LEFT WITH NINE" +}, +{ +"id":740, +"fortune":"YOUR WISHLIST IS A NOVEL NOW" +}, +{ +"id":741, +"fortune":"FREE SHIPPING COSTS YOU PLENTY" +}, +{ +"id":742, +"fortune":"YOUR RETURNS WINDOW CLOSED. LIKE ALWAYS" +}, +{ +"id":743, +"fortune":"YOU COMPARE PRICES. AFTER BUYING" +}, +{ +"id":744, +"fortune":"THE SALE ENDED. YOUR REGRET BEGINS" +}, +{ +"id":745, +"fortune":"YOUR LOYALTY CARD OUTRANKS YOUR GYM CARD" +}, +{ +"id":746, +"fortune":"YOU BUY ORGANIZERS TO ORGANIZE ORGANIZERS" +}, +{ +"id":747, +"fortune":"YOUR HOME PROJECT IS 90 PERCENT DONE. FOREVER" +}, +{ +"id":748, +"fortune":"THE PAINT SAMPLES OUTLIVED THE PROJECT" +}, +{ +"id":749, +"fortune":"YOUR TOOLBOX HAS EVERYTHING BUT ANSWERS" +}, +{ +"id":750, +"fortune":"YOU MEASURED ONCE. IT SHOWS" +}, +{ +"id":751, +"fortune":"THE INSTRUCTIONS WERE OPTIONAL. APPARENTLY" +}, +{ +"id":752, +"fortune":"YOUR SHELF LEANS. YOU CALL IT CHARACTER" +}, +{ +"id":753, +"fortune":"DUCT TAPE IS NOT A PHILOSOPHY. YOURS IS" +}, +{ +"id":754, +"fortune":"YOUR SMART BULBS OUTSMART YOU NIGHTLY" +}, +{ +"id":755, +"fortune":"THE LEAK WAITED FOR THE LONG WEEKEND" +}, +{ +"id":756, +"fortune":"YOUR GAMING BACKLOG IS A SECOND CAREER" +}, +{ +"id":757, +"fortune":"ONE MORE LEVEL WAS THREE HOURS AGO" +}, +{ +"id":758, +"fortune":"YOUR CHARACTER HAS BETTER GEAR THAN YOU" +}, +{ +"id":759, +"fortune":"YOU PAUSED AN ONLINE GAME. BOLD MOVE" +}, +{ +"id":760, +"fortune":"YOUR HIGH SCORE IS SOMEONE ELSES WARMUP" +}, +{ +"id":761, +"fortune":"YOU RAGE QUIT GRACEFULLY. ALMOST" +}, +{ +"id":762, +"fortune":"YOUR BOOKSHELF JUDGES YOUR SCREEN TIME" +}, +{ +"id":763, +"fortune":"YOU BUY BOOKS FASTER THAN YOU READ THEM" +}, +{ +"id":764, +"fortune":"YOUR BOOKMARK HASNT MOVED SINCE MARCH" +}, +{ +"id":765, +"fortune":"YOU JOINED A BOOK CLUB FOR THE SNACKS" +}, +{ +"id":766, +"fortune":"THE AUDIOBOOK COUNTS. NOBODY ASKED" +}, +{ +"id":767, +"fortune":"YOUR TO BE READ PILE IS FURNITURE NOW" +}, +{ +"id":768, +"fortune":"YOU QUOTE BOOKS YOU HAVENT FINISHED" +}, +{ +"id":769, +"fortune":"YOUR KARAOKE SONG CLEARED THE ROOM. TWICE" +}, +{ +"id":770, +"fortune":"YOU SING IN THE CAR. THE CAR ENDURES" +}, +{ +"id":771, +"fortune":"YOUR SHOWER CONCERTS HAVE NO REFUNDS" +}, +{ +"id":772, +"fortune":"YOUR AIR GUITAR NEEDS TUNING SOMEHOW" +}, +{ +"id":773, +"fortune":"YOUR PLANT NAMES OUTNUMBER YOUR PLANTS" +}, +{ +"id":774, +"fortune":"YOU TALK TO YOUR PLANTS. THEY HEARD THAT" +}, +{ +"id":775, +"fortune":"YOUR SUCCULENT DIED. IMPRESSIVELY RARE" +}, +{ +"id":776, +"fortune":"THE FERN SAW EVERYTHING. IT STAYS QUIET" +}, +{ +"id":777, +"fortune":"YOUR GREEN THUMB IS MORE OF A BEIGE" +}, +{ +"id":778, +"fortune":"LUCK IS A LADDER. YOU BROUGHT A STOOL" +}, +{ +"id":779, +"fortune":"FORTUNE ARRIVES UNANNOUNCED. SO DO YOU" +}, +{ +"id":780, +"fortune":"YOUR CHARISMA WORKS OFFLINE ONLY" +}, +{ +"id":781, +"fortune":"YOU ARE A LIMITED EDITION. VERY LIMITED" +}, +{ +"id":782, +"fortune":"YOUR VIBE ATTRACTS YOUR TRIBE. EXPLAINS IT" +}, +{ +"id":783, +"fortune":"NORMAL IS A SETTING. YOURS IS CUSTOM" +}, +{ +"id":784, +"fortune":"NOT LAZY. JUST IN ENERGY SAVER MODE" +}, +{ +"id":785, +"fortune":"YOUR SARCASM IS A SECOND LANGUAGE. FLUENT" +}, +{ +"id":786, +"fortune":"YOU ARE TECHNICALLY CORRECT. THE WORST KIND" +}, +{ +"id":787, +"fortune":"YOUR EXCUSES SHOW REAL CRAFTSMANSHIP" +}, +{ +"id":788, +"fortune":"YOU PEAKED. THE TIMING WAS UNFORTUNATE" +}, +{ +"id":789, +"fortune":"YOUR COMFORT SHOW IS ON ITS NINTH RERUN" +}, +{ +"id":790, +"fortune":"YOU ARE DOING YOUR BEST. THE BEST VARIES" +}, +{ +"id":791, +"fortune":"YOUR POTENTIAL CALLED. IT LEFT NO MESSAGE" +}, +{ +"id":792, +"fortune":"YOU ARE SPECIAL. LIKE EVERYONE ELSE" +}, +{ +"id":793, +"fortune":"YOUR ENERGY TODAY IS DECORATIVE" +}, +{ +"id":794, +"fortune":"YOU ARE THE MAIN CHARACTER. OF A SIDE QUEST" +}, +{ +"id":795, +"fortune":"YOUR PLOT ARMOR HAS EXPIRED. WALK CAREFULLY" +}, +{ +"id":796, +"fortune":"YOUR REDEMPTION ARC IS IN PREPRODUCTION" +}, +{ +"id":797, +"fortune":"A COMPLIMENT NEARS. ACCEPT IT AWKWARDLY" +}, +{ +"id":798, +"fortune":"YOUR RESTING FACE HAS A REPUTATION" +}, +{ +"id":799, +"fortune":"YOU AGREED TO DISAGREE. YOU LOST" +}, +{ +"id":800, +"fortune":"YOUR EYE ROLL IS AUDIBLE SOMEHOW" +}, +{ +"id":801, +"fortune":"YOUR SIGH SPOKE PARAGRAPHS JUST NOW" +}, +{ +"id":802, +"fortune":"YOU SAID FINE. NOTHING WAS FINE" +}, +{ +"id":803, +"fortune":"YOUR THUMBS UP ENDED THREE FRIENDSHIPS" +}, +{ +"id":804, +"fortune":"NO WORRIES YOU SAID. WORRYING INTENSELY" +}, +{ +"id":805, +"fortune":"YOUR SHRUG IS DOING HEAVY LIFTING TODAY" +}, +{ +"id":806, +"fortune":"YOU SMILED THROUGH THAT. BARELY. WE SAW" +}, +{ +"id":807, +"fortune":"YOUR PATIENCE HAS A LOADING BAR. STUCK" +}, +{ +"id":808, +"fortune":"YOU FORGAVE THEM. THE SPREADSHEET REMAINS" +}, +{ +"id":809, +"fortune":"YOUR HINTS NEED SUBTITLES. STILL" +}, +{ +"id":810, +"fortune":"YOU ALMOST SAID IT. THE ALMOST WAS LOUD" +}, +{ +"id":811, +"fortune":"YOUR SILENCE HAS AN AGENDA. AS USUAL" +}, +{ +"id":812, +"fortune":"YOU LET IT GO. INTO YOUR PERMANENT RECORD" +}, +{ +"id":813, +"fortune":"YOUR CALM IS SUSPICIOUS. EVERYONE AGREES" +}, +{ +"id":814, +"fortune":"YOU TOOK THE HIGH ROAD. WITH COMMENTARY" +}, +{ +"id":815, +"fortune":"YOUR FEEDBACK SANDWICH IS ALL BREAD" +}, +{ +"id":816, +"fortune":"YOU HEARD THEM OUT. THEN PROCEEDED ANYWAY" +}, +{ +"id":817, +"fortune":"GOOD MORNING. THE BAR IS ALREADY MET" +}, +{ +"id":818, +"fortune":"YOUR OPTIMISM IS ADORABLE TODAY" +}, +{ +"id":819, +"fortune":"TODAY IS YOUR DAY. SHARE IT NICELY" +}, +{ +"id":820, +"fortune":"YOU WOKE UP LIKE THIS. CONDOLENCES" +}, +{ +"id":821, +"fortune":"THE MIRROR SAW YOU FIRST. IT COPES" +}, +{ +"id":822, +"fortune":"YOUR BEDHEAD HAS ARCHITECTURE NOW" +}, +{ +"id":823, +"fortune":"MONDAY SAW YOU COMING. IT PREPARED" +}, +{ +"id":824, +"fortune":"YOUR WEEKEND ENDED. IT SENDS REGARDS" +}, +{ +"id":825, +"fortune":"FRIDAY LOVES YOU. THE FEELING IS MUTUAL" +}, +{ +"id":826, +"fortune":"YOUR LUNCH BREAK DESERVES A MEDAL. SO LONG" +}, +{ +"id":827, +"fortune":"HUMP DAY IS A STATE OF MIND. YOURS DAILY" +}, +{ +"id":828, +"fortune":"YOUR OUTFIT SAYS EFFORT. THE CLOCK SAYS RUSH" +}, +{ +"id":829, +"fortune":"YOUR HAIR HAS PLANS OF ITS OWN TODAY" +}, +{ +"id":830, +"fortune":"YOU MATCHED YOUR SOCKS. A CEREMONY IS DUE" +}, +{ +"id":831, +"fortune":"YOUR SUNGLASSES HIDE NOTHING. NICE TRY" +}, +{ +"id":832, +"fortune":"DRESS FOR THE JOB YOU WANT. A NAP TESTER" +}, +{ +"id":833, +"fortune":"YOUR IRONING BOARD RETIRED YEARS AGO" +}, +{ +"id":834, +"fortune":"WRINKLES ARE A TEXTURE. YOU DECIDED" +}, +{ +"id":835, +"fortune":"YOUR FASHION CYCLE IS LAUNDRY BASED" +}, +{ +"id":836, +"fortune":"YOUR SHOES MATCH. THE OCCASION DOESNT" +}, +{ +"id":837, +"fortune":"YOU WILL WIN AN ARGUMENT. IN THE SHOWER" +}, +{ +"id":838, +"fortune":"YOUR COMEBACK ARRIVED. THREE DAYS LATE" +}, +{ +"id":839, +"fortune":"YOUR WIT IS QUICK. YOUR TIMING ISNT" +}, +{ +"id":840, +"fortune":"YOU HAD THE PERFECT REPLY. AT MIDNIGHT" +}, +{ +"id":841, +"fortune":"YOUR INNER MONOLOGUE NEEDS AN EDITOR" +}, +{ +"id":842, +"fortune":"YOUR HOT TAKES ARE ROOM TEMPERATURE" +}, +{ +"id":843, +"fortune":"YOUR OPINIONS ARRIVE PRE HEATED" +}, +{ +"id":844, +"fortune":"YOUR DEBATE STYLE IS VOLUME BASED" +}, +{ +"id":845, +"fortune":"YOU FACT CHECK OTHERS. NEVER YOURSELF" +}, +{ +"id":846, +"fortune":"YOUR TRIVIA KNOWLEDGE PEAKS AT PARTIES ONLY" +}, +{ +"id":847, +"fortune":"A DECISION AWAITS. FLIP A COIN. IGNORE IT" +}, +{ +"id":848, +"fortune":"YOUR PRO CON LIST HAS ONE COLUMN" +}, +{ +"id":849, +"fortune":"YOU ASKED EVERYONE. THEN DID YOUR THING" +}, +{ +"id":850, +"fortune":"YOUR GUT FEELING NEEDS A SECOND OPINION" +}, +{ +"id":851, +"fortune":"YOU SLEPT ON IT. THE PROBLEM STAYED AWAKE" +}, +{ +"id":852, +"fortune":"YOUR PLAN B IS PLAN A WITH REGRET" +}, +{ +"id":853, +"fortune":"YOU CHOSE CHAOS. AGAIN. CONSISTENTLY" +}, +{ +"id":854, +"fortune":"YOUR BACKUP PLAN NEEDS A BACKUP PLAN" +}, +{ +"id":855, +"fortune":"COMMITMENT SCARES YOU. SO DOES THE MENU" +}, +{ +"id":856, +"fortune":"YOU ORDERED THE SAME THING. ADVENTUROUS" +}, +{ +"id":857, +"fortune":"CHANGE IS COMING. YOU WILL RESIST IT" +}, +{ +"id":858, +"fortune":"A SURPRISE AWAITS. YOU HATE SURPRISES" +}, +{ +"id":859, +"fortune":"GOOD NEWS COMES IN THREES. YOURS CARPOOLS" +}, +{ +"id":860, +"fortune":"YOUR HOROSCOPE QUIT. IT CITED BURNOUT" +}, +{ +"id":861, +"fortune":"MERCURY IS IN RETROGRADE. CONVENIENT EXCUSE" +}, +{ +"id":862, +"fortune":"YOUR TAROT READER NEEDED A BREAK AFTER YOU" +}, +{ +"id":863, +"fortune":"THE MAGIC 8 BALL SAID ASK SOMEONE ELSE" +}, +{ +"id":864, +"fortune":"YOUR PALM READER REQUESTED GLOVES" +}, +{ +"id":865, +"fortune":"THE CRYSTAL BALL FOGGED UP. ON PURPOSE" +}, +{ +"id":866, +"fortune":"YOUR TEA LEAVES SPELLED LUCK. SARCASTICALLY" +}, +{ +"id":867, +"fortune":"YOUR VISION QUEST FOUND THE COUCH" +}, +{ +"id":868, +"fortune":"THE UNIVERSE IS TESTING YOU. OPEN BOOK. STILL" +}, +{ +"id":869, +"fortune":"YOUR MANIFESTATIONS NEED A COSIGNER" +}, +{ +"id":870, +"fortune":"YOUR CHAKRAS ARE ALIGNED. WITH THE FRIDGE" +}, +{ +"id":871, +"fortune":"YOUR ZEN GARDEN NEEDS WEEDING. IRONIC" +}, +{ +"id":872, +"fortune":"YOUR MANTRA IS FIVE MORE MINUTES" +}, +{ +"id":873, +"fortune":"YOUR THIRD EYE NEEDS GLASSES TOO" +}, +{ +"id":874, +"fortune":"YOUR ENERGY CLEANSE MISSED A SPOT" +}, +{ +"id":875, +"fortune":"YOUR SAGE SMOKE SET OFF THE ALARM. FITTING" +}, +{ +"id":876, +"fortune":"INNER PEACE IS CLOSE. TRY THE OTHER DOOR" +}, +{ +"id":877, +"fortune":"A STRANGER WILL SMILE AT YOU. STAY CALM" +}, +{ +"id":878, +"fortune":"SOMEONE THOUGHT OF YOU TODAY. BRIEFLY" +}, +{ +"id":879, +"fortune":"YOU CROSSED SOMEONES MIND. IT KEPT WALKING" +}, +{ +"id":880, +"fortune":"AN ADMIRER WATCHES. IT IS YOUR CAT" +}, +{ +"id":881, +"fortune":"YOU WERE MENTIONED TODAY. CONTEXT UNKNOWN" +}, +{ +"id":882, +"fortune":"YOUR NAME CAME UP. THE ROOM WENT QUIET" +}, +{ +"id":883, +"fortune":"SOMEONE MISSES YOU. THEY LOST YOUR NUMBER" +}, +{ +"id":884, +"fortune":"YOU ARE UNFORGETTABLE. MANY HAVE TRIED" +}, +{ +"id":885, +"fortune":"YOUR ABSENCE WAS NOTICED. AND ENJOYED" +}, +{ +"id":886, +"fortune":"PEOPLE TALK ABOUT YOU. KEEP IT THAT WAY" +}, +{ +"id":887, +"fortune":"YOUR REPUTATION ARRIVED FIRST. APOLOGIZE" +}, +{ +"id":888, +"fortune":"YOU MADE AN IMPRESSION. DENTS COUNT" +}, +{ +"id":889, +"fortune":"SOMEONE QUOTED YOU TODAY. INCORRECTLY" +}, +{ +"id":890, +"fortune":"YOU INSPIRED SOMEONE. TO DO THE OPPOSITE" +}, +{ +"id":891, +"fortune":"YOUR LEGACY IS SAFE. NOBODY CHECKED" +}, +{ +"id":892, +"fortune":"HISTORY WILL REMEMBER YOU. AS A FOOTNOTE" +}, +{ +"id":893, +"fortune":"YOUR BIOGRAPHY NEEDS A GHOSTWRITER. AND PLOT" +}, +{ +"id":894, +"fortune":"YOUR AUTOGRAPH IS WORTHLESS. FOR NOW" +}, +{ +"id":895, +"fortune":"FAME AWAITS. LOCAL FAME. VERY LOCAL" +}, +{ +"id":896, +"fortune":"YOUR FIFTEEN MINUTES ARE BUFFERING" +}, +{ +"id":897, +"fortune":"YOU WILL FIND YOUR KEYS. WHERE YOU LEFT THEM" +}, +{ +"id":898, +"fortune":"YOUR PHONE IS IN YOUR OTHER HAND. AGAIN" +}, +{ +"id":899, +"fortune":"YOU WALKED INTO A ROOM. THE REASON LEFT" +}, +{ +"id":900, +"fortune":"YOUR MEMORY IS FINE. IT JUST CURATES" +}, +{ +"id":901, +"fortune":"YOU FORGOT WHY YOU OPENED THE FRIDGE. SNACK" +}, +{ +"id":902, +"fortune":"YOUR MENTAL NOTES NEED A FILING SYSTEM" +}, +{ +"id":903, +"fortune":"YOU REMEMBERED THE TUNE. NOT THE TASK" +}, +{ +"id":904, +"fortune":"YOUR SHOPPING MEMORY EXPIRES AT THE STORE" +}, +{ +"id":905, +"fortune":"YOU KNOW THAT FACE. THE NAME ESCAPED. RUN" +}, +{ +"id":906, +"fortune":"YOUR BRAIN HAS TABS OPEN TOO. ALL FROZEN" +}, +{ +"id":907, +"fortune":"A GREAT IDEA CAME AND WENT. UNRECORDED" +}, +{ +"id":908, +"fortune":"YOU LOCKED THE DOOR. PROBABLY. GO CHECK" +}, +{ +"id":909, +"fortune":"YOUR TRAIN OF THOUGHT DEPARTED WITHOUT YOU" +}, +{ +"id":910, +"fortune":"YOU RETRACED YOUR STEPS. THEY LED TO SNACKS" +}, +{ +"id":911, +"fortune":"YOUR PASSWORD RESET NEEDS A PASSWORD RESET" +}, +{ +"id":912, +"fortune":"LIFE IS SHORT. YOUR MEETINGS ARENT" +}, +{ +"id":913, +"fortune":"LIFE GAVE YOU LEMONS. YOU FILED A COMPLAINT" +}, +{ +"id":914, +"fortune":"LIFE IS A JOURNEY. YOURS NEEDS A MAP" +}, +{ +"id":915, +"fortune":"LIFE IS WHAT HAPPENS WHILE YOU SCROLL" +}, +{ +"id":916, +"fortune":"LIFE HAS NO REMOTE. GET UP AND CHANGE IT" +}, +{ +"id":917, +"fortune":"LIFE IS NOT A RACE. YOU PARKED ANYWAY" +}, +{ +"id":918, +"fortune":"LIFE IS A GIFT. KEEP THE RECEIPT" +}, +{ +"id":919, +"fortune":"LIFE IS UNSCRIPTED. YOURS NEEDS A WRITER" +}, +{ +"id":920, +"fortune":"LIFE REWARDS ACTION. YOURS SENT A MEMO" +}, +{ +"id":921, +"fortune":"LIFE IS A CLASSROOM. YOU SIT IN BACK" +}, +{ +"id":922, +"fortune":"YOUR STORY HAS PLOT HOLES. EMBRACE THEM" +}, +{ +"id":923, +"fortune":"YOUR CHAPTER TWO NEEDS CHAPTER ONE DONE" +}, +{ +"id":924, +"fortune":"YOUR SEQUEL DEPENDS ON THIS PART. NO PRESSURE" +}, +{ +"id":925, +"fortune":"YOUR NARRATOR SOUNDS TIRED LATELY" +}, +{ +"id":926, +"fortune":"YOUR CLIFFHANGER IS JUST INDECISION" +}, +{ +"id":927, +"fortune":"TOMORROW IS A NEW DAY. SAME YOU THOUGH" +}, +{ +"id":928, +"fortune":"YESTERDAY CALLED. IT WANTS NOTHING BACK" +}, +{ +"id":929, +"fortune":"TODAY WILL BE PRODUCTIVE. STARTING LATER" +}, +{ +"id":930, +"fortune":"THIS WEEK HAS POTENTIAL. HAD. HAS. UNCLEAR" +}, +{ +"id":931, +"fortune":"NEXT MONTH YOU WILL START. NEXT MONTH AGREES" +}, +{ +"id":932, +"fortune":"THE YEAR IS HALF OVER. YOUR GOALS ARE INTACT" +}, +{ +"id":933, +"fortune":"SOON IS NOT A DATE. YOU TREAT IT AS ONE" +}, +{ +"id":934, +"fortune":"EVENTUALLY IS YOUR FAVORITE DEADLINE" +}, +{ +"id":935, +"fortune":"THE RIGHT TIME NEVER COMES. CONVENIENT" +}, +{ +"id":936, +"fortune":"YOUR WINDOW OF OPPORTUNITY HAS BLINDS" +}, +{ +"id":937, +"fortune":"PATIENCE COMES TO THOSE WHO WAIT. IRONIC" +}, +{ +"id":938, +"fortune":"YOUR TURN IS COMING. THE LINE MOVED ON" +}, +{ +"id":939, +"fortune":"YOU WAITED FOR A SIGN. THIS IS NOT IT" +}, +{ +"id":940, +"fortune":"HOLD THAT THOUGHT. FOREVER IF POSSIBLE" +}, +{ +"id":941, +"fortune":"YOUR PAUSE BUTTON IS YOUR FAVORITE" +}, +{ +"id":942, +"fortune":"YOU PUT A PIN IN IT. THE PIN CUSHION IS FULL" +}, +{ +"id":943, +"fortune":"IT IS ON YOUR RADAR. YOUR RADAR IS OFF" +}, +{ +"id":944, +"fortune":"YOU WILL GET TO IT. IT STOPPED WAITING" +}, +{ +"id":945, +"fortune":"THE BALL IS IN YOUR COURT. GATHERING DUST" +}, +{ +"id":946, +"fortune":"YOUR FOLLOW UP NEEDS A FOLLOW UP" +}, +{ +"id":947, +"fortune":"CONSIDER THIS YOUR REMINDER. THE FOURTH" +}, +{ +"id":948, +"fortune":"YOUR INTENTIONS ARE GOOD. AND STATIONARY" +}, +{ +"id":949, +"fortune":"EFFORT WAS MADE. A ROUNDING ERROR OF IT" +}, +{ +"id":950, +"fortune":"YOU GAVE 100 PERCENT. OF YOUR MINIMUM" +}, +{ +"id":951, +"fortune":"YOUR BEST GUESS BEAT YOUR RESEARCH. AGAIN" +}, +{ +"id":952, +"fortune":"CLOSE ENOUGH IS YOUR SIGNATURE MOVE" +}, +{ +"id":953, +"fortune":"GOOD ENOUGH SHIPPED. PERFECTION SULKS" +}, +{ +"id":954, +"fortune":"YOUR SHORTCUTS TOOK THE LONG WAY" +}, +{ +"id":955, +"fortune":"YOU IMPROVISED. THE RESULTS IMPROVISED BACK" +}, +{ +"id":956, +"fortune":"YOUR WINGING IT HAS FREQUENT FLYER MILES" +}, +{ +"id":957, +"fortune":"DETAILS MATTER. YOURS WENT ON STRIKE" +}, +{ +"id":958, +"fortune":"YOUR ROUGH DRAFT WENT TO PRODUCTION" +}, +{ +"id":959, +"fortune":"YOU SKIMMED IT. IT SHOWED. IT ALWAYS SHOWS" +}, +{ +"id":960, +"fortune":"YOUR PROOFREADING MISSED THIS SENTENCE TOO" +}, +{ +"id":961, +"fortune":"ALMOST DONE IS YOUR PERMANENT ADDRESS" +}, +{ +"id":962, +"fortune":"YOUR CHECKLIST HAS SURVIVORS" +}, +{ +"id":963, +"fortune":"DONE IS BETTER THAN PERFECT. TRY EITHER" +}, +{ +"id":964, +"fortune":"YOUR STANDARDS SLIPPED. THEY LEFT A NOTE" +}, +{ +"id":965, +"fortune":"MEDIOCRITY TAKES EFFORT TOO. WELL DONE" +}, +{ +"id":966, +"fortune":"YOU EXCEEDED EXPECTATIONS. THEY WERE LOW" +}, +{ +"id":967, +"fortune":"YOUR BARE MINIMUM HAS A LOYAL FOLLOWING" +}, +{ +"id":968, +"fortune":"YOU RAISED THE BAR. FROM THE FLOOR" +}, +{ +"id":969, +"fortune":"CONSISTENCY IS KEY. YOURS IS CONSISTENT" +}, +{ +"id":970, +"fortune":"YOUR AVERAGE IS ABOVE AVERAGE. AT AVERAGING" +}, +{ +"id":971, +"fortune":"PROGRESS WAS MADE. LATERALLY. BUT MADE" +}, +{ +"id":972, +"fortune":"YOUR TRAJECTORY IS STABLE. FLAT. STABLE" +}, +{ +"id":973, +"fortune":"ONWARD AND UPWARD. OR SIDEWAYS. ONWARD" +}, +{ +"id":974, +"fortune":"YOU PIVOTED. THE DIRECTION WAS RANDOM" +}, +{ +"id":975, +"fortune":"YOUR MOMENTUM TOOK A PERSONAL DAY" +}, +{ +"id":976, +"fortune":"FULL SPEED AHEAD. YOUR SPEED. SO GENTLE" +}, +{ +"id":977, +"fortune":"YOU HIT THE GROUND WALKING. BRISKLY EVEN" +}, +{ +"id":978, +"fortune":"YOUR SPRINT BECAME A STROLL. SCENIC ONE" +}, +{ +"id":979, +"fortune":"BABY STEPS COUNT. YOURS ARE NEWBORN" +}, +{ +"id":980, +"fortune":"YOU ARE ON A ROLL. A SLOW GENTLE ROLL" +}, +{ +"id":981, +"fortune":"YOUR STREAK CONTINUES. WHICHEVER ONE" +}, +{ +"id":982, +"fortune":"MOMENTUM IS BUILDING. SOMEWHERE ELSE" +}, +{ +"id":983, +"fortune":"THE FINISH LINE MOVED. SO DID YOU. BACKWARD" +}, +{ +"id":984, +"fortune":"YOUR MARATHON IS A SERIES OF SNACK BREAKS" +}, +{ +"id":985, +"fortune":"YOU CROSSED A LINE TODAY. NOT THE FINISH ONE" +}, +{ +"id":986, +"fortune":"VICTORY IS NEAR. DEFINE VICTORY LOOSELY" +}, +{ +"id":987, +"fortune":"YOU WON THE ARGUMENT. THE ROOM WAS EMPTY" +}, +{ +"id":988, +"fortune":"CHAMPIONS TRAIN DAILY. YOU WATCHED THEM" +}, +{ +"id":989, +"fortune":"YOUR TROPHY SHELF HOLDS PARTICIPATION" +}, +{ +"id":990, +"fortune":"SECOND PLACE IS FIRST LOSER. YOU GOT FIFTH" +}, +{ +"id":991, +"fortune":"YOUR COMEBACK SEASON IS ALWAYS NEXT SEASON" +}, +{ +"id":992, +"fortune":"THE UNDERDOG STORY NEEDS AN ATTEMPT FIRST" +}, +{ +"id":993, +"fortune":"YOUR RIVALS STOPPED CHECKING ON YOU" +}, +{ +"id":994, +"fortune":"GLORY AWAITS. IT DOUBLE BOOKED THOUGH" +}, +{ +"id":995, +"fortune":"YOU MADE THE HIGHLIGHT REEL. AS A BLOOPER" +}, +{ +"id":996, +"fortune":"HISTORY FAVORS THE BOLD. YOU FAVOR NAPS" +}, +{ +"id":997, +"fortune":"YOUR SPLIT FLAP DISPLAY DESERVED BETTER TEXT" +}, +{ +"id":998, +"fortune":"THIS MESSAGE USED 45 CHARACTERS WISELY. ISH" +}, +{ +"id":999, +"fortune":"YOU BUILT A DISPLAY FOR THIS. WORTH IT" +}, +{ +"id":1000, +"fortune":"EACH FLAP TURNED FOR THIS WISDOM. SAVOR IT" +} +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_es.json b/apps/sarcastic-fortune-cookies/fortunes_es.json new file mode 100644 index 0000000..7757037 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_es.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "TODO PASA POR UNA RAZN. NORMALMENTE MALA" + }, + { + "id": 2, + "fortune": "LA SUERTE VIENE. CAMINA MUY DESPACIO" + }, + { + "id": 3, + "fortune": "EL UNIVERSO TIENE UN PLAN. UNO PEQUEO" + }, + { + "id": 4, + "fortune": "TU DESTINO LLAM. LO HA APLAZADO" + }, + { + "id": 5, + "fortune": "LAS ESTRELLAS SE ALINEARON. Y TE VIERON" + }, + { + "id": 6, + "fortune": "TU BARCO YA LLEGA. ES UNA CANOA" + }, + { + "id": 7, + "fortune": "CONFA EN EL PROCESO. L DUDA DE TI" + }, + { + "id": 8, + "fortune": "UNA SEAL LLEGA. DICE CEDA EL PASO" + }, + { + "id": 9, + "fortune": "TU ESTRELLA EXISTE. EN OTRA GALAXIA" + }, + { + "id": 10, + "fortune": "EL KARMA ES REAL. ESO EXPLICA MUCHO" + }, + { + "id": 11, + "fortune": "TU FUTURO ES BRILLANTE. PONTE CREMA" + }, + { + "id": 12, + "fortune": "EL DESTINO ESPERA. SE PUSO A LEER" + }, + { + "id": 13, + "fortune": "LOS MILAGROS PASAN A DIARIO. EN OTRA PARTE" + }, + { + "id": 14, + "fortune": "TU MOMENTO LLEGA. EST EN EL ATASCO" + }, + { + "id": 15, + "fortune": "LA SUERTE LLAM. T HABAS SALIDO" + }, + { + "id": 16, + "fortune": "LA MAREA CAMBIA. A PASO DE GLACIAR" + }, + { + "id": 17, + "fortune": "LLEGAN GRANDES COSAS. BAJA EL LISTN" + }, + { + "id": 18, + "fortune": "LAS OPORTUNIDADES ESTN. SIEMPRE TE PIERDES" + }, + { + "id": 19, + "fortune": "EL COSMOS TE OYE. HAZ COLA POR FAVOR" + }, + { + "id": 20, + "fortune": "TUS RUEGOS FUERON ODOS. Y ARCHIVADOS" + }, + { + "id": 21, + "fortune": "LA ABUNDANCIA FLUYE HACIA TI. RO ARRIBA" + }, + { + "id": 22, + "fortune": "LA RUEDA GIRA. T ERES EL HMSTER" + }, + { + "id": 23, + "fortune": "CADA NUBE TIENE UN LADO BUENO. EL TUYO GOTEA" + }, + { + "id": 24, + "fortune": "EL AZAR PREGUNTA POR TI. POR CURIOSIDAD" + }, + { + "id": 25, + "fortune": "LOS PRESAGIOS HABLAN. MS BIEN SUSPIRAN" + }, + { + "id": 26, + "fortune": "TU HORSCOPO ES BUENO. Y FICTICIO" + }, + { + "id": 27, + "fortune": "EL RAYO NO CAE DOS VECES. T S" + }, + { + "id": 28, + "fortune": "EL DESTINO PAGA LA PACIENCIA. FACTURA LUEGO" + }, + { + "id": 29, + "fortune": "LA LUNA VIO TU NUEVO COMIENZO. OTRO MS" + }, + { + "id": 30, + "fortune": "TU NGEL VIGILA. VA TOMANDO NOTAS" + }, + { + "id": 31, + "fortune": "CREE Y RECIBIRS. LA ENTREGA VARA" + }, + { + "id": 32, + "fortune": "TU ERA DORADA LLEGA. CHAPADA EN ORO" + }, + { + "id": 33, + "fortune": "LO QUE ES TUYO LLEGA. SIN NINGUNA PRISA" + }, + { + "id": 34, + "fortune": "EL COSMOS TE GUI. O LE ENTR ALGO" + }, + { + "id": 35, + "fortune": "TU SUERTE VA A CAMBIAR. RUMBO INCIERTO" + }, + { + "id": 36, + "fortune": "LA PROVIDENCIA PROVEE. REVISA LOS RECIBOS" + }, + { + "id": 37, + "fortune": "PIDE UN DESEO. LA ESTRELLA LO MARCA SPAM" + }, + { + "id": 38, + "fortune": "TODO LLEGA A SU TIEMPO. EL TUYO SE DEMORA" + }, + { + "id": 39, + "fortune": "LOS SIGNOS ESTABAN AH. LEER ES OPCIONAL" + }, + { + "id": 40, + "fortune": "ERES NICO. COMO TODO EL MUNDO" + }, + { + "id": 41, + "fortune": "LO MEJOR EST POR VENIR. NO TIENE PRISA" + }, + { + "id": 42, + "fortune": "TU AURA BRILLA. HACE HORAS EXTRA" + }, + { + "id": 43, + "fortune": "LA FORTUNA TE SONRI. CORTS. DE LEJOS" + }, + { + "id": 44, + "fortune": "TU NGEL PIDI EL TRASLADO" + }, + { + "id": 45, + "fortune": "EL DESTINO REPARTE. T PIERDES LAS CARTAS" + }, + { + "id": 46, + "fortune": "UN PRESAGIO APARECE. SE ENCOGE DE HOMBROS" + }, + { + "id": 47, + "fortune": "EL XITO EST CERCA. Y EL BOTN DE POSPONER" + }, + { + "id": 48, + "fortune": "EL TRABAJO SIEMPRE PAGA. EN EXPERIENCIA" + }, + { + "id": 49, + "fortune": "TU POTENCIAL ES INFINITO. Y SIN USAR" + }, + { + "id": 50, + "fortune": "APUNTA A LA LUNA. CUIDADO CON EL TECHO" + }, + { + "id": 51, + "fortune": "EL QUE MADRUGA VIO AL GUSANO. T DORMAS" + }, + { + "id": 52, + "fortune": "TU GRAN OPORTUNIDAD LLEGA. NO LA ROMPAS" + }, + { + "id": 53, + "fortune": "ROMA NO SE HIZO EN UN DA. LA TUYA TAMPOCO" + }, + { + "id": 54, + "fortune": "TUS TALENTOS SE HALLARN. CON UNA ORDEN" + }, + { + "id": 55, + "fortune": "LOS QUE GANAN NO SE RINDEN. T FLOTAS" + }, + { + "id": 56, + "fortune": "TUS IDEAS VAN POR DELANTE. TUS PLAZOS DETRS" + }, + { + "id": 57, + "fortune": "LA CALIDAD ES UN HBITO. EL TUYO TAMBIN" + }, + { + "id": 58, + "fortune": "TU TRABAJO HABLA POR TI. MUY BAJITO" + }, + { + "id": 59, + "fortune": "LA CIMA ES SOLITARIA. PROBLEMA RESUELTO" + }, + { + "id": 60, + "fortune": "UN ASCENSO SE ACERCA. EL DE UN COLEGA" + }, + { + "id": 61, + "fortune": "TU CV IMPRESIONA. A LOS DE FICCIN" + }, + { + "id": 62, + "fortune": "TU MEJOR TRABAJO LLEGA. CORRE MUY RPIDO" + }, + { + "id": 63, + "fortune": "ESA REUNIN PUDO SER UN CORREO" + }, + { + "id": 64, + "fortune": "TU BANDEJA NO ES TU ENEMIGA. SOLO TESTIGO" + }, + { + "id": 65, + "fortune": "LOS PLAZOS NO TE ASUSTAN. LOS IGNORAS" + }, + { + "id": 66, + "fortune": "TU PLAN A CINCO AOS TIENE CINCO AOS" + }, + { + "id": 67, + "fortune": "LENTO PERO SEGURO GANA. DOMINAS LO LENTO" + }, + { + "id": 68, + "fortune": "TU AGENDA EST LLENA. DE MRGENES" + }, + { + "id": 69, + "fortune": "TU EQUIPO TAMBIN SUEA. CON EL TRASLADO" + }, + { + "id": 70, + "fortune": "LA OCASIN BAJ HASTA TU NIVEL" + }, + { + "id": 71, + "fortune": "EL XITO DEJA PISTAS. PREFIERES EL MISTERIO" + }, + { + "id": 72, + "fortune": "TU ZONA DE CONFORT MERECE CDIGO POSTAL" + }, + { + "id": 73, + "fortune": "CALIDAD O CANTIDAD. RECHAZAS AMBAS" + }, + { + "id": 74, + "fortune": "TU INSTINTO ES AGUDO. Y SUELE FALLAR" + }, + { + "id": 75, + "fortune": "TRABAJAS BIEN BAJO PRESIN. ELLA DISCREPA" + }, + { + "id": 76, + "fortune": "LA MAESTRA PIDE 10000 HORAS. TIENES 40" + }, + { + "id": 77, + "fortune": "TU PLANTA CREY EN TI. Y EN EL AGUA" + }, + { + "id": 78, + "fortune": "LA IMPRESORA HUELE TU PRISA. POR ESO FALLA" + }, + { + "id": 79, + "fortune": "TU LEGADO EST EN OBRAS. TODAVA" + }, + { + "id": 80, + "fortune": "UN DIPLOMA TE ESPERA. EL DE ASISTENCIA" + }, + { + "id": 81, + "fortune": "CONOCE A GENTE. ABRE PUERTAS. TOCAR TAMBIN" + }, + { + "id": 82, + "fortune": "DAS EJEMPLO. RECURSOS HUMANOS QUIERE OTRO" + }, + { + "id": 83, + "fortune": "TU PROYECTO PERSONAL DESCANSA CON LOS OTROS" + }, + { + "id": 84, + "fortune": "EL GENIO ES UNO POR CIENTO SUDOR. AH PARAS" + }, + { + "id": 85, + "fortune": "TU MENSAJE DE AUSENCIA ES TU OBRA MAESTRA" + }, + { + "id": 86, + "fortune": "FALLAR ES UN ESCALN. BONITA ESCALERA" + }, + { + "id": 87, + "fortune": "ERES IRREEMPLAZABLE. EL ANUNCIO YA EST" + }, + { + "id": 88, + "fortune": "TU EVALUACIN ANUAL LLEGA. ENSAYA BIEN" + }, + { + "id": 89, + "fortune": "EFICIENCIA ES TU SEGUNDO NOMBRE. EN PAPEL" + }, + { + "id": 90, + "fortune": "CAES DE PIE. EL ATERRIZAJE SE RETRASA" + }, + { + "id": 91, + "fortune": "LA CUMBRE EST CERCA. Y EL CAMPO BASE" + }, + { + "id": 92, + "fortune": "TU AMBICIN DESPERT. TU DESPERTADOR NO" + }, + { + "id": 93, + "fortune": "S T MISMO. LOS DEMS SE PREOCUPARON" + }, + { + "id": 94, + "fortune": "TU REUNIN SALI BIEN. YA TERMIN" + }, + { + "id": 95, + "fortune": "DESCANSAR ES SANO. LO PRACTICAS MUCHO" + }, + { + "id": 96, + "fortune": "TU DIETA EMPIEZA EL LUNES. LOS LUNES HUYEN" + }, + { + "id": 97, + "fortune": "TE MERECES ESTO. RESPIRA HONDO" + }, + { + "id": 98, + "fortune": "UN EXTRAO TE SONRE. MANTN LA CALMA" + }, + { + "id": 99, + "fortune": "GUARDAS RENCOR NO. LO ARCHIVAS CON FECHA" + }, + { + "id": 100, + "fortune": "TU PACIENCIA TIENE UNA BARRA. ATASCADA" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_fr.json b/apps/sarcastic-fortune-cookies/fortunes_fr.json new file mode 100644 index 0000000..115a78a --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_fr.json @@ -0,0 +1,2802 @@ +[ +{ +"id":1, +"fortune":"TOUT ARRIVE POUR UNE RAISON. SOUVENT MAUVAISE" +}, +{ +"id":2, +"fortune":"LA CHANCE ARRIVE. ELLE MARCHE LENTEMENT" +}, +{ +"id":3, +"fortune":"LE COSMOS A UN PLAN POUR TOI. UN PETIT" +}, +{ +"id":4, +"fortune":"TON DESTIN A APPELÉ. IL REPORTE" +}, +{ +"id":5, +"fortune":"LES ASTRES SONT ALIGNÉS. ILS ÉPELLENT BOF" +}, +{ +"id":6, +"fortune":"LA FORTUNE SOURIT AUX AUDACIEUX. TOI REGARDE" +}, +{ +"id":7, +"fortune":"TON NAVIRE ARRIVE. EN FAIT UN PÉDALO" +}, +{ +"id":8, +"fortune":"FAIS CONFIANCE AU PROCESSUS. LUI DOUTE DE TOI" +}, +{ +"id":9, +"fortune":"UN SIGNE ARRIVE. IL DIT CÉDEZ LE PASSAGE" +}, +{ +"id":10, +"fortune":"TON ÉTOILE EXISTE. DANS UNE AUTRE GALAXIE" +}, +{ +"id":11, +"fortune":"LE KARMA EXISTE. ÇA EXPLIQUE TOUT" +}, +{ +"id":12, +"fortune":"TON AVENIR EST RADIEUX. PRENDS DE LA CRÈME" +}, +{ +"id":13, +"fortune":"LE DESTIN ATTEND. IL A PRIS UN LIVRE" +}, +{ +"id":14, +"fortune":"LES MIRACLES ARRIVENT CHAQUE JOUR. AILLEURS" +}, +{ +"id":15, +"fortune":"TON MOMENT ARRIVE. IL EST DANS LES BOUCHONS" +}, +{ +"id":16, +"fortune":"LA CHANCE A FRAPPÉ. TU ÉTAIS SORTI" +}, +{ +"id":17, +"fortune":"LA MARÉE TOURNE. À VITESSE DE GLACIER" +}, +{ +"id":18, +"fortune":"DE GRANDES CHOSES ARRIVENT. BAISSE LA BARRE" +}, +{ +"id":19, +"fortune":"LES OCCASIONS SONT LÀ. VOUS VOUS RATEZ" +}, +{ +"id":20, +"fortune":"LE COSMOS TE RÉPOND. PATIENTE DANS LA FILE" +}, +{ +"id":21, +"fortune":"TES PRIÈRES SONT REÇUES. ET CLASSÉES" +}, +{ +"id":22, +"fortune":"LA PROSPÉRITÉ COULE VERS TOI. À CONTRESENS" +}, +{ +"id":23, +"fortune":"LA ROUE DE FORTUNE TOURNE. TU ES LE HAMSTER" +}, +{ +"id":24, +"fortune":"CHAQUE NUAGE A UN BON CÔTÉ. LE TIEN FUIT" +}, +{ +"id":25, +"fortune":"LE HASARD DEMANDE DE TES NOUVELLES. POLI" +}, +{ +"id":26, +"fortune":"LES PRÉSAGES PARLENT. ILS SOUPIRENT SURTOUT" +}, +{ +"id":27, +"fortune":"TON HOROSCOPE EST FLATTEUR. ET FICTIF" +}, +{ +"id":28, +"fortune":"LA FOUDRE NE FRAPPE JAMAIS DEUX FOIS. TOI SI" +}, +{ +"id":29, +"fortune":"LE DESTIN PAIE LA PATIENCE. FACTURE SUIT" +}, +{ +"id":30, +"fortune":"LA LUNE A VU TON NOUVEAU DÉPART. ENCORE UN" +}, +{ +"id":31, +"fortune":"TON ANGE GARDIEN OBSERVE. IL PREND DES NOTES" +}, +{ +"id":32, +"fortune":"CROIS ET TU RECEVRAS. LIVRAISON VARIABLE" +}, +{ +"id":33, +"fortune":"TON ÈRE DORÉE APPROCHE. PLAQUÉ OR DISONS" +}, +{ +"id":34, +"fortune":"CE QUI TE REVIENT ARRIVE. SANS SE PRESSER" +}, +{ +"id":35, +"fortune":"LE COSMOS CLIGNE VERS TOI. OU IL A UN TIC" +}, +{ +"id":36, +"fortune":"TA CHANCE VA TOURNER. SENS INCONNU" +}, +{ +"id":37, +"fortune":"LA PROVIDENCE POURVOIT. ELLE GARDE LES REÇUS" +}, +{ +"id":38, +"fortune":"FAIS UN VŒU. TON ÉTOILE LE MET EN SPAM" +}, +{ +"id":39, +"fortune":"TOUT VIENT À POINT. LE TIEN PREND SON TEMPS" +}, +{ +"id":40, +"fortune":"UNE MANNE APPROCHE. COUVRE TOI BIEN" +}, +{ +"id":41, +"fortune":"LES SIGNES ÉTAIENT LÀ. LIRE RESTE FACULTATIF" +}, +{ +"id":42, +"fortune":"TU ES UNIQUE. COMME TOUT LE MONDE" +}, +{ +"id":43, +"fortune":"LE MEILLEUR RESTE À VENIR. IL FLÂNE" +}, +{ +"id":44, +"fortune":"TON AURA RAYONNE. ELLE FAIT DES HEURES SUP" +}, +{ +"id":45, +"fortune":"LA FORTUNE TE SOURIT. POLIMENT. DE LOIN" +}, +{ +"id":46, +"fortune":"TON ANGE A DEMANDÉ SA MUTATION" +}, +{ +"id":47, +"fortune":"UN GRAND PROJET PREND DU TEMPS. LE TIEN DORT" +}, +{ +"id":48, +"fortune":"LE DESTIN BAT LES CARTES. TU LES PERDS" +}, +{ +"id":49, +"fortune":"UN PRÉSAGE APPARAÎT. IL HAUSSE LES ÉPAULES" +}, +{ +"id":50, +"fortune":"TON ÉTOILE MONTE. UN JOUR. SANS DOUTE" +}, +{ +"id":51, +"fortune":"LA CHANCE SOURIT AUX IDIOTS. BONNE NOUVELLE" +}, +{ +"id":52, +"fortune":"DEMAIN TOUT IRA MIEUX. DEMAIN EST EXTENSIBLE" +}, +{ +"id":53, +"fortune":"LE SUCCÈS EST PROCHE. LE BOUTON SNOOZE AUSSI" +}, +{ +"id":54, +"fortune":"LE TRAVAIL PAIE TOUJOURS. EN EXPÉRIENCE" +}, +{ +"id":55, +"fortune":"TON POTENTIEL EST IMMENSE. ET INTACT" +}, +{ +"id":56, +"fortune":"VISE LA LUNE. ATTENTION AU PLAFOND" +}, +{ +"id":57, +"fortune":"LE LÈVE TÔT A EU LE VER. TU DORMAIS" +}, +{ +"id":58, +"fortune":"TA GRANDE CHANCE ARRIVE. NE LA CASSE PAS" +}, +{ +"id":59, +"fortune":"ROME PRIT DU TEMPS. LA TIENNE EST EN DEVIS" +}, +{ +"id":60, +"fortune":"TES TALENTS SERONT DÉCOUVERTS. AVEC UN MANDAT" +}, +{ +"id":61, +"fortune":"LES GAGNANTS PERSISTENT. TOI TU PLANES" +}, +{ +"id":62, +"fortune":"TES IDÉES SONT EN AVANCE. TES DÉLAIS NON" +}, +{ +"id":63, +"fortune":"LA QUALITÉ EST UNE HABITUDE. LA TIENNE AUSSI" +}, +{ +"id":64, +"fortune":"TON TRAVAIL PARLE POUR TOI. TOUT BAS" +}, +{ +"id":65, +"fortune":"LE SOMMET EST SOLITAIRE. PROBLÈME RÉGLÉ" +}, +{ +"id":66, +"fortune":"UNE PROMOTION APPROCHE. CELLE DU COLLÈGUE" +}, +{ +"id":67, +"fortune":"TON CV IMPRESSIONNE. LES AMATEURS DE FICTION" +}, +{ +"id":68, +"fortune":"TON MEILLEUR TRAVAIL ARRIVE. IL COURT VITE" +}, +{ +"id":69, +"fortune":"CETTE RÉUNION AURAIT PU ÊTRE UN MAIL" +}, +{ +"id":70, +"fortune":"TA BOÎTE MAIL EST INNOCENTE. SIMPLE TÉMOIN" +}, +{ +"id":71, +"fortune":"LES DÉLAIS NE TE FONT RIEN. TU PASSES DEVANT" +}, +{ +"id":72, +"fortune":"TON PLAN SUR CINQ ANS A CINQ ANS" +}, +{ +"id":73, +"fortune":"LENT MAIS SÛR GAGNE. TU MAÎTRISES LE LENT" +}, +{ +"id":74, +"fortune":"TON AGENDA EST PLEIN. DE MARGES" +}, +{ +"id":75, +"fortune":"TON ÉQUIPE RÊVE AUSSI. DE MUTATION" +}, +{ +"id":76, +"fortune":"LA GRANDE OCCASION DESCEND À TON NIVEAU" +}, +{ +"id":77, +"fortune":"LE SUCCÈS LAISSE DES INDICES. TU LES ÉVITES" +}, +{ +"id":78, +"fortune":"TA ZONE DE CONFORT MÉRITE SON CODE POSTAL" +}, +{ +"id":79, +"fortune":"QUALITÉ OU QUANTITÉ. TU DÉCLINES LES DEUX" +}, +{ +"id":80, +"fortune":"TON INSTINCT EST VIF. ET SOUVENT FAUX" +}, +{ +"id":81, +"fortune":"TU BOSSES BIEN SOUS PRESSION. QUI LA DIT" +}, +{ +"id":82, +"fortune":"LA MAÎTRISE DEMANDE 10000 HEURES. TU EN AS 40" +}, +{ +"id":83, +"fortune":"TA PLANTE CROYAIT EN TOI. ET EN ARROSAGE" +}, +{ +"id":84, +"fortune":"TON IMPRIMANTE SENT TON URGENCE. ELLE PLANTE" +}, +{ +"id":85, +"fortune":"TON HÉRITAGE EST EN CHANTIER. TOUJOURS" +}, +{ +"id":86, +"fortune":"UN DIPLÔME TATTEND. CELUI DE PARTICIPATION" +}, +{ +"id":87, +"fortune":"UN DIPLÔME ARRIVE. CELUI DE PARTICIPATION" +}, +{ +"id":88, +"fortune":"TU DONNES LE TON. LES RH EN VEULENT UN AUTRE" +}, +{ +"id":89, +"fortune":"TON PROJET PERSO SE REPOSE AVEC LES AUTRES" +}, +{ +"id":90, +"fortune":"LE GÉNIE EST 1 POUR CENT DE SUEUR. TU STOPPES" +}, +{ +"id":91, +"fortune":"TA RÉPONSE AUTOMATIQUE EST TON MEILLEUR TEXTE" +}, +{ +"id":92, +"fortune":"RATER EST UNE MARCHE. BEL ESCALIER DÉJÀ" +}, +{ +"id":93, +"fortune":"TU ES IRREMPLAÇABLE. TON ANNONCE EST PRÊTE" +}, +{ +"id":94, +"fortune":"TON ENTRETIEN ANNUEL APPROCHE. RÉPÈTE BIEN" +}, +{ +"id":95, +"fortune":"EFFICACITÉ. TON DEUXIÈME PRÉNOM. SUR PAPIER" +}, +{ +"id":96, +"fortune":"TU RETOMBES SUR TES PIEDS. VOL RETARDÉ" +}, +{ +"id":97, +"fortune":"LE SOMMET EST PROCHE. LE CAMP DE BASE AUSSI" +}, +{ +"id":98, +"fortune":"TON AMBITION SE RÉVEILLE. PAS TON RÉVEIL" +}, +{ +"id":99, +"fortune":"SOIS TOI MÊME. LES AUTRES ONT EU PEUR" +}, +{ +"id":100, +"fortune":"TA RÉUNION FUT UN SUCCÈS. ELLE EST FINIE" +}, +{ +"id":101, +"fortune":"CONNAIS TOI TOI MÊME. FAITES CONNAISSANCE" +}, +{ +"id":102, +"fortune":"TA MÉTAMORPHOSE ARRIVE. PRÉVIENS LE RÉSEAU" +}, +{ +"id":103, +"fortune":"NOUVEL AN NOUVEAU TOI. LE VIEUX PREND NOTE" +}, +{ +"id":104, +"fortune":"TU SUFFIS. LA BARRE ÉTAIT RÉGLABLE" +}, +{ +"id":105, +"fortune":"TA PAIX INTÉRIEURE A VU TON AGENDA. ELLE FUIT" +}, +{ +"id":106, +"fortune":"GRANDIR PREND DU TEMPS. LE TIEN VEUT UN DÉLAI" +}, +{ +"id":107, +"fortune":"TU ES UNE ŒUVRE EN COURS. SURTOUT EN COURS" +}, +{ +"id":108, +"fortune":"SE CONNAÎTRE EST UN CADEAU. EN TRANSIT" +}, +{ +"id":109, +"fortune":"GUÉRIR EST RAREMENT LINÉAIRE. TU GRIBOUILLES" +}, +{ +"id":110, +"fortune":"TON MEILLEUR TOI ÉMERGE. IL APPUIE SUR SNOOZE" +}, +{ +"id":111, +"fortune":"PRENDRE SOIN DE SOI COMPTE. LES SÉRIES NON" +}, +{ +"id":112, +"fortune":"TES LIMITES SONT SAINES. ET JAMAIS TESTÉES" +}, +{ +"id":113, +"fortune":"LA GRATITUDE CHANGE TOUT. ESSAIE SUR LES GENS" +}, +{ +"id":114, +"fortune":"TU PARDONNES VITE. À TOI MÊME SURTOUT" +}, +{ +"id":115, +"fortune":"TES HABITUDES TE DÉFINISSENT. CONDOLÉANCES" +}, +{ +"id":116, +"fortune":"CHAQUE PAS COMPTE. MÊME VERS LE FRIGO" +}, +{ +"id":117, +"fortune":"TON INTUITION EST FORTE. ET SOUVENT À CÔTÉ" +}, +{ +"id":118, +"fortune":"LA MÉDITATION AIDE. TON TÉLÉPHONE PROTESTE" +}, +{ +"id":119, +"fortune":"TU AS TOURNÉ LA PAGE. ELLE A TON ADRESSE" +}, +{ +"id":120, +"fortune":"TA ROUTINE MATINALE EST SACRÉE. 4 MINUTES" +}, +{ +"id":121, +"fortune":"TU APPRENDS À DIRE NON. AUX LÉGUMES SURTOUT" +}, +{ +"id":122, +"fortune":"TA VOLONTÉ SOULÈVE PRESQUE UN BISCUIT ENTIER" +}, +{ +"id":123, +"fortune":"TA MISSION DE VIE EXISTE. ELLE RESTE ANONYME" +}, +{ +"id":124, +"fortune":"TU ACCUEILLES LE CHANGEMENT. DEPUIS LE CANAPÉ" +}, +{ +"id":125, +"fortune":"TON JOURNAL INTIME EST BRUT. LES DEUX PAGES" +}, +{ +"id":126, +"fortune":"TU VIS TA VÉRITÉ. VÉRIFICATION EN COURS" +}, +{ +"id":127, +"fortune":"TON CRITIQUE INTÉRIEUR NE FAIT QUE SOUPIRER" +}, +{ +"id":128, +"fortune":"TES OBJECTIFS SONT EN VUE. BELLES JUMELLES" +}, +{ +"id":129, +"fortune":"TES NOUVELLES HABITUDES SEMBLENT FAMILIÈRES" +}, +{ +"id":130, +"fortune":"TON ÉNERGIE ATTIRE. SURTOUT LES CORVÉES" +}, +{ +"id":131, +"fortune":"TES MURS SONT TOMBÉS. LE FOSSÉ A GRANDI" +}, +{ +"id":132, +"fortune":"TU FÊTES LES PETITES VICTOIRES. CHAQUE JOUR" +}, +{ +"id":133, +"fortune":"TON ÉVOLUTION DÉCONCERTE MÊME DARWIN" +}, +{ +"id":134, +"fortune":"TU PASSES ENFIN EN PREMIER. FILE COURTE" +}, +{ +"id":135, +"fortune":"TA RÉINVENTION TOURNE. MÊME PROGRAMME" +}, +{ +"id":136, +"fortune":"TU ES PRÉSENT. PHYSIQUEMENT DU MOINS" +}, +{ +"id":137, +"fortune":"TON NOUVEAU DÉPART COMMENCE LUNDI. UN AUTRE" +}, +{ +"id":138, +"fortune":"TON TABLEAU DE VISION EST BEAU. ET RETRAITÉ" +}, +{ +"id":139, +"fortune":"TU HONORES TES ÉMOTIONS. À PLEIN VOLUME" +}, +{ +"id":140, +"fortune":"TON CALME EST RÉEL. TU IGNORES TES MAILS" +}, +{ +"id":141, +"fortune":"TES STANDARDS MONTENT. DEPUIS LA CAVE" +}, +{ +"id":142, +"fortune":"TU FLEURIS. HORS SAISON. MAIS TU FLEURIS" +}, +{ +"id":143, +"fortune":"TA DISCIPLINE EST LÉGENDAIRE. DONC FICTIVE" +}, +{ +"id":144, +"fortune":"TES AFFIRMATIONS MARCHENT. SUR LE PLAFOND" +}, +{ +"id":145, +"fortune":"TON ENFANT INTÉRIEUR VEUT SURTOUT UNE GLACE" +}, +{ +"id":146, +"fortune":"LE GRAND AMOUR ARRIVE. IL EST AUSSI EN RETARD" +}, +{ +"id":147, +"fortune":"TON ÂME SŒUR EXISTE. RÉSEAU FAIBLE PAR ICI" +}, +{ +"id":148, +"fortune":"LA ROMANCE EST DANS LES RUES. LE POLLEN AUSSI" +}, +{ +"id":149, +"fortune":"CUPIDON A TON ADRESSE. IL EST PASSÉ DEVANT" +}, +{ +"id":150, +"fortune":"TON CŒUR CONNAÎT LE CHEMIN. TES TEXTOS NON" +}, +{ +"id":151, +"fortune":"LE COUP DE FOUDRE EXISTE. PORTE DES LUNETTES" +}, +{ +"id":152, +"fortune":"TON EX PENSE À TOI. COMME LEÇON DE VIE" +}, +{ +"id":153, +"fortune":"TA DRAGUE EST SUBTILE. INDÉTECTABLE MÊME" +}, +{ +"id":154, +"fortune":"TES CHOIX AMOUREUX SONT CONSTANTS. HÉLAS" +}, +{ +"id":155, +"fortune":"ON TE CONTEMPLE DE LOIN. GARDE LA DISTANCE" +}, +{ +"id":156, +"fortune":"TES SIGNAUX VERTS SONT EN MINORITÉ" +}, +{ +"id":157, +"fortune":"LE VRAI AMOUR TRIOMPHE. IL DEMANDE DU RENFORT" +}, +{ +"id":158, +"fortune":"LE CŒUR SUR LA MAIN. LAVE LES DEUX" +}, +{ +"id":159, +"fortune":"UN MESSAGE DU PASSÉ ARRIVE. NE RÉPONDS PAS" +}, +{ +"id":160, +"fortune":"TON CRUSH SAIT QUE TU EXISTES. EN THÉORIE" +}, +{ +"id":161, +"fortune":"TU AIMES PROFONDÉMENT. BRIÈVEMENT. MAIS FORT" +}, +{ +"id":162, +"fortune":"TON CŒUR EST OUVERT. TON ARDOISE AUSSI" +}, +{ +"id":163, +"fortune":"DES ÉTINCELLES ARRIVENT. TESTE LE DÉTECTEUR" +}, +{ +"id":164, +"fortune":"TU ES PRÊT À TE POSER. SUR LE CANAPÉ" +}, +{ +"id":165, +"fortune":"TON CŒUR EST GUÉRI. AVEC ALARME EN PRIME" +}, +{ +"id":166, +"fortune":"LE VRAI AMOUR EST PATIENT. GRÂCE À TOI" +}, +{ +"id":167, +"fortune":"TA LUNE DE MIEL A DURÉ ONZE JOURS" +}, +{ +"id":168, +"fortune":"TON ANIMAL EST TA MEILLEURE RELATION" +}, +{ +"id":169, +"fortune":"TES VŒUX FERONT PLEURER. LA GRAMMAIRE SURTOUT" +}, +{ +"id":170, +"fortune":"TU ES UN BON PARTI. PÊCHE AVEC REMISE À LEAU" +}, +{ +"id":171, +"fortune":"TU ES UNE BELLE PRISE. VITE RELÂCHÉE" +}, +{ +"id":172, +"fortune":"TES SIGNAUX ROUGES SONT BORDEAUX. PROGRÈS" +}, +{ +"id":173, +"fortune":"UNE PERSONNE TE TROUVE PARFAIT. DE LOIN" +}, +{ +"id":174, +"fortune":"SECONDES CHANCES POUR TOUS. SIXIÈMES AUSSI" +}, +{ +"id":175, +"fortune":"TA PLAYLIST DE RUPTURE TOURNE SOUVENT" +}, +{ +"id":176, +"fortune":"TU MÉRITES UNE LONGUE ATTENTE. ELLE CONTINUE" +}, +{ +"id":177, +"fortune":"LA ROMANCE VIT ENCORE. LA TIENNE SE REPOSE" +}, +{ +"id":178, +"fortune":"TA BELLE FAMILLE VA CÉDER. AVEC LE TEMPS" +}, +{ +"id":179, +"fortune":"TON PROFIL EST HONNÊTE. PAR ENDROITS" +}, +{ +"id":180, +"fortune":"TES CÂLINS SONT RARES. COMME LES ÉCLIPSES" +}, +{ +"id":181, +"fortune":"ON RÊVE DE TA CUISINE. EN SUEUR" +}, +{ +"id":182, +"fortune":"TON CHARME OUVRE DES PORTES. POUSSE PLUTÔT" +}, +{ +"id":183, +"fortune":"TES CRITÈRES ONT VU TES CHOIX. MALAISE" +}, +{ +"id":184, +"fortune":"TU SERAS BALAYÉ PAR LA PASSION. ÉCHAUFFE TOI" +}, +{ +"id":185, +"fortune":"AIMER VEUT DIRE ÊTRE VU. TU NÉGOCIES ENCORE" +}, +{ +"id":186, +"fortune":"VOTRE HISTOIRE SERA RACONTÉE. EN PRÉVENTION" +}, +{ +"id":187, +"fortune":"LA FLAMME BRÛLE ENCORE. BATTUE RECOMMANDÉE" +}, +{ +"id":188, +"fortune":"VOTRE ANNIVERSAIRE APPROCHE. VOICI LE RAPPEL" +}, +{ +"id":189, +"fortune":"AIME TOI TOI MÊME. ÇA TU SAIS DÉJÀ FAIRE" +}, +{ +"id":190, +"fortune":"TON CŒUR A RATÉ UN BATTEMENT. VOIS UN MÉDECIN" +}, +{ +"id":191, +"fortune":"TU RÉVÈLES LE MEILLEUR DES GENS. AU DÉPART" +}, +{ +"id":192, +"fortune":"TU REFUSES DE TE CONTENTER. VOILÀ LES CHAISES" +}, +{ +"id":193, +"fortune":"TON FUTUR PARTENAIRE MUSCLE SA PATIENCE" +}, +{ +"id":194, +"fortune":"TON CŒUR EST UNE FORTERESSE. BOUTIQUE OUVERTE" +}, +{ +"id":195, +"fortune":"TES BESOINS DE TENDRESSE ONT DES HORAIRES" +}, +{ +"id":196, +"fortune":"ON PENSE À TOI SANS TON NUMÉRO" +}, +{ +"id":197, +"fortune":"TU FLIRTES PAR REGARDS. PERSONNE NE LES VOIT" +}, +{ +"id":198, +"fortune":"TES MOTS DOUX SONT DEVENUS DES VOCAUX" +}, +{ +"id":199, +"fortune":"TES AMIS AIMENT TA FRANCHISE. DE LOIN" +}, +{ +"id":200, +"fortune":"UN AMI VA APPELER. IL DÉMÉNAGE BIENTÔT" +}, +{ +"id":201, +"fortune":"TU ES LA COLLE DU GROUPE. ON REMERCIE PEU" +}, +{ +"id":202, +"fortune":"LE GROUPE SAVOURE TON SILENCE" +}, +{ +"id":203, +"fortune":"LES VRAIS AMIS SONT RARES. LES TIENS AUSSI" +}, +{ +"id":204, +"fortune":"GRANDE LOYAUTÉ. PETITE PONCTUALITÉ" +}, +{ +"id":205, +"fortune":"UNE FÊTE APPORTE DE LA JOIE. PARTIR AUSSI" +}, +{ +"id":206, +"fortune":"TU ES LE MARRANT DU GROUPE. SELON TOI" +}, +{ +"id":207, +"fortune":"UN VIEIL AMI REVIENT. IL A BESOIN DE BRAS" +}, +{ +"id":208, +"fortune":"TES CONSEILS SONT APPRÉCIÉS. JAMAIS COMMANDÉS" +}, +{ +"id":209, +"fortune":"TU ILLUMINES LA PIÈCE. ON VEUT UN VARIATEUR" +}, +{ +"id":210, +"fortune":"TON ANNIVERSAIRE SERA FÊTÉ. UN JOUR APRÈS" +}, +{ +"id":211, +"fortune":"TES ANECDOTES EMBELLISSENT. LES FAITS NON" +}, +{ +"id":212, +"fortune":"LES GENS GRAVITENT VERS TOI. PUIS FILENT" +}, +{ +"id":213, +"fortune":"TU SAIS TOUJOURS QUOI DIRE. RAREMENT QUAND" +}, +{ +"id":214, +"fortune":"LES AMIS VONT ET VIENNENT. LES TIENS VONT" +}, +{ +"id":215, +"fortune":"TON AGENDA EST PLEIN. DE PEUT ÊTRE" +}, +{ +"id":216, +"fortune":"TES BLAGUES INTERNES SONT DEVENUES DES SOLOS" +}, +{ +"id":217, +"fortune":"TES SOIRÉES SONT LÉGENDAIRES. LES ANNULÉES" +}, +{ +"id":218, +"fortune":"TU RÉUNIS LES GENS. COMME SUJET DE DISCUSSION" +}, +{ +"id":219, +"fortune":"TA GÉNÉROSITÉ A DES HEURES DE BUREAU" +}, +{ +"id":220, +"fortune":"TU RETIENS CHAQUE VISAGE. AUCUN PRÉNOM" +}, +{ +"id":221, +"fortune":"TES ENCOURAGEMENTS DEMANDENT UN SUIVI MÉDICAL" +}, +{ +"id":222, +"fortune":"TU ES LÀ QUAND ÇA COMPTE. POUR TOI" +}, +{ +"id":223, +"fortune":"TES POTS DE DÉPART FONT SALLE COMBLE" +}, +{ +"id":224, +"fortune":"ON TE CONFIE UN SECRET. PUIS TU LE PARTAGES" +}, +{ +"id":225, +"fortune":"TA FRANCHISE RAFRAÎCHIT. COMME UN SEAU GLACÉ" +}, +{ +"id":226, +"fortune":"TU NE GARDES PAS RANCUNE. TU CLASSES TOUT" +}, +{ +"id":227, +"fortune":"TES MEMES ARRIVENT DÈS 6 HEURES. SANS DEMANDE" +}, +{ +"id":228, +"fortune":"TON ÉPAULE EST DISPONIBLE. SUR RENDEZ VOUS" +}, +{ +"id":229, +"fortune":"TU GARDES LES GENS AU SOL. COMME LA BRUME" +}, +{ +"id":230, +"fortune":"TON ENTRAIN SE PROPAGE. MASQUE CONSEILLÉ" +}, +{ +"id":231, +"fortune":"UN AMI VEUT TON AVIS SINCÈRE. PIÈGE ÉVIDENT" +}, +{ +"id":232, +"fortune":"TU PARTAGES LA NOTE EN PARTS ÉGALES. PRESQUE" +}, +{ +"id":233, +"fortune":"TA PRÉSENCE EST UN CADEAU. ÉCHANGE POSSIBLE" +}, +{ +"id":234, +"fortune":"TON ESPRIT DE COMPÉTITION A TUÉ LES JEUX" +}, +{ +"id":235, +"fortune":"TES FÊTES SURPRISES NE SURPRENNENT PERSONNE" +}, +{ +"id":236, +"fortune":"ON SE SENT BIEN AVEC TOI. EN PARTANT" +}, +{ +"id":237, +"fortune":"TU DIS CE QUE CHACUN PENSE. AUX FUNÉRAILLES" +}, +{ +"id":238, +"fortune":"TA LETTRE ANNUELLE A SON LECTORAT" +}, +{ +"id":239, +"fortune":"TES EXCUSES SONT SINCÈRES. ET FRÉQUENTES" +}, +{ +"id":240, +"fortune":"TU TIENS LA MÉMOIRE DU GROUPE. RÉVISÉE" +}, +{ +"id":241, +"fortune":"TU AIDES SANS BRUIT. PUIS TU LE RACONTES" +}, +{ +"id":242, +"fortune":"TA FRANCHISE EST CHARMANTE. MOT DU COMITÉ" +}, +{ +"id":243, +"fortune":"TU ES EN RETARD AVEC STYLE. ENFIN EN RETARD" +}, +{ +"id":244, +"fortune":"ON CHERCHE TON APPROBATION. POUR PARTIR" +}, +{ +"id":245, +"fortune":"TU NE MÉDIS JAMAIS. TU INFORMES LES ABSENTS" +}, +{ +"id":246, +"fortune":"LA CARTE DIT DÉCONTRACTÉ. TES RELANCES NON" +}, +{ +"id":247, +"fortune":"UN AMI DE JEUNESSE PENSE À TOI. DE LOIN" +}, +{ +"id":248, +"fortune":"TU NE PERDS JAMAIS UN DÉBAT. TU LE DÉPLACES" +}, +{ +"id":249, +"fortune":"TON SOUTIEN EST SANS CONDITION. VOIR ANNEXE" +}, +{ +"id":250, +"fortune":"LA RICHESSE ARRIVE. À TON ANCIENNE ADRESSE" +}, +{ +"id":251, +"fortune":"LES FONDS COULENT VERS TOI. À TRAVERS TOI" +}, +{ +"id":252, +"fortune":"TON BUDGET EST UNE ŒUVRE. ABSTRAITE" +}, +{ +"id":253, +"fortune":"ÉPARGNE POUR LA PLUIE. MOUSSON EN VUE" +}, +{ +"id":254, +"fortune":"TON DOSSIER BANCAIRE EST UN THRILLER" +}, +{ +"id":255, +"fortune":"TES ÉCONOMIES GRANDISSENT. EN CARACTÈRE" +}, +{ +"id":256, +"fortune":"TON ARGENT PARLE. IL DIT ADIEU" +}, +{ +"id":257, +"fortune":"TA RETRAITE REPOSE SUR UN TICKET DE LOTO" +}, +{ +"id":258, +"fortune":"TES GOÛTS SONT CHERS. TON COMPTE EST MODESTE" +}, +{ +"id":259, +"fortune":"INTÉRÊTS COMPOSÉS. TU AS CHOISI LES DETTES" +}, +{ +"id":260, +"fortune":"TON FONDS DE SECOURS COUVRE UN PETIT SOUCI" +}, +{ +"id":261, +"fortune":"UNE AUGMENTATION EST MÉRITÉE. ET NON DATÉE" +}, +{ +"id":262, +"fortune":"TON PANIER EST UN RÊVE AVEC UNE CAISSE" +}, +{ +"id":263, +"fortune":"TA GÉNÉROSITÉ EST CONNUE. DES COMMERÇANTS" +}, +{ +"id":264, +"fortune":"LE MEILLEUR EST GRATUIT. LE TIEN A DES FRAIS" +}, +{ +"id":265, +"fortune":"TES ABONNEMENTS DÉPASSENT TES AMIS. EN NOMBRE" +}, +{ +"id":266, +"fortune":"ACHETER BAS VENDRE HAUT. TU FAIS LE CONTRAIRE" +}, +{ +"id":267, +"fortune":"TA BANQUE TE CONTACTE PAR INQUIÉTUDE" +}, +{ +"id":268, +"fortune":"TON REMBOURSEMENT FISCAL A DES PROJETS" +}, +{ +"id":269, +"fortune":"TES ACHATS SONT STRATÉGIQUES. PARAÎT IL" +}, +{ +"id":270, +"fortune":"UN BILLET DORT DANS UN MANTEAU. LE TIEN" +}, +{ +"id":271, +"fortune":"TON PORTEFEUILLE EST DIVERSIFIÉ. EN REGRETS" +}, +{ +"id":272, +"fortune":"LE JOUR DE PAIE APPORTE 18 HEURES DE JOIE" +}, +{ +"id":273, +"fortune":"TES FRAIS DE RETARD ONT DES FRAIS DE RETARD" +}, +{ +"id":274, +"fortune":"LES PETITS RUISSEAUX SÈCHENT. LES TIENS VITE" +}, +{ +"id":275, +"fortune":"RICHE DE CŒUR. LA CAISSE VOIT AUTREMENT" +}, +{ +"id":276, +"fortune":"TES TICKETS DE CAISSE RACONTENT UNE SAGA" +}, +{ +"id":277, +"fortune":"TON APPORT EST DEVENU DES SUSHIS. DEUX FOIS" +}, +{ +"id":278, +"fortune":"TON BUDGET PRÉVISIONNEL EST DE LA FICTION" +}, +{ +"id":279, +"fortune":"TES ESSAIS GRATUITS VIVENT ET PRÉLÈVENT" +}, +{ +"id":280, +"fortune":"LE CASH EST ROI. TON ROYAUME VIT À CRÉDIT" +}, +{ +"id":281, +"fortune":"TON GEL DES DÉPENSES A TENU 40 MINUTES" +}, +{ +"id":282, +"fortune":"TES FACTURES SONT PONCTUELLES. PAS TOI" +}, +{ +"id":283, +"fortune":"TON ARGENT TRAVAILLE DUR. POUR LES AUTRES" +}, +{ +"id":284, +"fortune":"TES BONS DE RÉDUCTION ONT EXPIRÉ. TOUS" +}, +{ +"id":285, +"fortune":"TON PLAN FINANCIER A DES PHASES. DÉNI SURTOUT" +}, +{ +"id":286, +"fortune":"TES REMISES FINANCENT TES ACHATS IMPULSIFS" +}, +{ +"id":287, +"fortune":"TA PHASE CRYPTO FUT INSTRUCTIVE. ET COÛTEUSE" +}, +{ +"id":288, +"fortune":"LE LOTO TAXE LES RÊVEURS. GÉNÉREUX VA" +}, +{ +"id":289, +"fortune":"TON OBJECTIF ÉPARGNE DORT DEPUIS MARS" +}, +{ +"id":290, +"fortune":"LA RICHESSE CHUCHOTE. LA TIENNE A RACCROCHÉ" +}, +{ +"id":291, +"fortune":"TU NOTES CHAQUE DÉPENSE. PUIS TU RECOMMENCES" +}, +{ +"id":292, +"fortune":"TA TIRELIRE A DES PROBLÈMES DE CONFIANCE" +}, +{ +"id":293, +"fortune":"TON VIREMENT EST ARRIVÉ. IL EST DÉJÀ REPARTI" +}, +{ +"id":294, +"fortune":"LE BONHEUR EST SANS PRIX. TON SOLDE CONFIRME" +}, +{ +"id":295, +"fortune":"TES FACTURES VIEILLISSENT COMME UN GRAND CRU" +}, +{ +"id":296, +"fortune":"TON SOLDE ET TON MORAL ONT PLONGÉ ENSEMBLE" +}, +{ +"id":297, +"fortune":"TU RANGES TES BOÎTES DANS DES BOÎTES" +}, +{ +"id":298, +"fortune":"LA LIVRAISON GRATUITE TE COÛTE UNE FORTUNE" +}, +{ +"id":299, +"fortune":"LA PATIENCE EST UNE VERTU. PAS TON GENRE" +}, +{ +"id":300, +"fortune":"LE SILENCE EST PRÉCIEUX. LE TIEN EST RARE" +}, +{ +"id":301, +"fortune":"TOURNE TA LANGUE SEPT FOIS. PROJET PILOTE" +}, +{ +"id":302, +"fortune":"EAU CALME EAU PROFONDE. LA TIENNE FAIT 10 CM" +}, +{ +"id":303, +"fortune":"LE SAVOIR EST UNE ARME. LA TIENNE EN VEILLE" +}, +{ +"id":304, +"fortune":"UN ESPRIT OUVERT EST UN TRÉSOR. BEAU COURANT" +}, +{ +"id":305, +"fortune":"ÉCOUTE DEUX FOIS PARLE UNE FOIS. INVERSE TOUT" +}, +{ +"id":306, +"fortune":"LA VÉRITÉ REND LIBRE. LA TIENNE RESTE ASSISE" +}, +{ +"id":307, +"fortune":"REGARDE AVANT DE SAUTER. OU APRÈS. À TA GUISE" +}, +{ +"id":308, +"fortune":"LES ACTES PARLENT FORT. LES TIENS CHUCHOTENT" +}, +{ +"id":309, +"fortune":"MESURE DEUX FOIS COUPE UNE FOIS. TU COUPES" +}, +{ +"id":310, +"fortune":"MIEUX VAUT TARD QUE JAMAIS. TU TESTES FORT" +}, +{ +"id":311, +"fortune":"QUI VOLE UN ŒUF VOLE UN BŒUF. TU COMPTES TOUT" +}, +{ +"id":312, +"fortune":"PIERRE QUI ROULE. LA TIENNE A PRIS LA MOUSSE" +}, +{ +"id":313, +"fortune":"TONNEAU VIDE FAIT DU BRUIT. BELLE ACOUSTIQUE" +}, +{ +"id":314, +"fortune":"QUI RIRA LE DERNIER PENSAIT LENTEMENT. SALUT" +}, +{ +"id":315, +"fortune":"UN TIENS VAUT MIEUX. LE TIEN A FILÉ" +}, +{ +"id":316, +"fortune":"NE RÉPARE QUE LE CASSÉ. TROP TARD DÉSORMAIS" +}, +{ +"id":317, +"fortune":"TU MÈNES LES CHEVAUX AU PUITS. ILS REFUSENT" +}, +{ +"id":318, +"fortune":"LA FIERTÉ PRÉCÈDE LA CHUTE. BEL ÉQUILIBRE" +}, +{ +"id":319, +"fortune":"LE TEMPS GUÉRIT TOUT. TU GRATTES LA PLAIE" +}, +{ +"id":320, +"fortune":"LES VIEILLES HABITUDES RÉSISTENT. SURTOUT ICI" +}, +{ +"id":321, +"fortune":"OÙ IL Y A DE LA FUMÉE. IL Y A TOI" +}, +{ +"id":322, +"fortune":"LA MEILLEURE DÉFENSE. LA DISTANCE. ILS SAVENT" +}, +{ +"id":323, +"fortune":"LE DIABLE AIME LES DÉTAILS. LES TIENS DORMENT" +}, +{ +"id":324, +"fortune":"LE REBUT DES UNS REMPLIT TON GARAGE" +}, +{ +"id":325, +"fortune":"MARMITE SURVEILLÉE NE BOUT PAS. LA TIENNE SI" +}, +{ +"id":326, +"fortune":"QUI NE SAIT RIEN DORT BIEN. TU SEMBLES REPOSÉ" +}, +{ +"id":327, +"fortune":"LA BEAUTÉ EST DANS LE REGARD. CONSULTE VITE" +}, +{ +"id":328, +"fortune":"IL FAUT UN VILLAGE. LE TIEN VEUT DU RENFORT" +}, +{ +"id":329, +"fortune":"LES GRANDS ESPRITS SE CROISENT. LE TIEN FUIT" +}, +{ +"id":330, +"fortune":"CHAQUE CHIEN A SON JOUR. LE TIEN FUT EN 2019" +}, +{ +"id":331, +"fortune":"QUI NE TENTE RIEN. TOI EN RÉSUMÉ" +}, +{ +"id":332, +"fortune":"TROP DE CHEFS GÂTENT LA SOUPE. TOI SEUL AUSSI" +}, +{ +"id":333, +"fortune":"ON RÉCOLTE CE QUI FUT SEMÉ. RÉCOLTE CURIEUSE" +}, +{ +"id":334, +"fortune":"DEMANDE ET TU RECEVRAS. IL Y A UNE FILE" +}, +{ +"id":335, +"fortune":"PRENDS LES CHAUSSURES DES AUTRES. PUIS RENDS" +}, +{ +"id":336, +"fortune":"RIEN NE SERT DE COURIR. TU NE COURS JAMAIS" +}, +{ +"id":337, +"fortune":"TOUT A UNE FIN. LES TIENNES ARRIVENT TÔT" +}, +{ +"id":338, +"fortune":"LES PAROLES SENVOLENT. LES TIENNES AUSSI" +}, +{ +"id":339, +"fortune":"LE TEMPS PERDU NE REVIENT PAS. TU LE STOCKES" +}, +{ +"id":340, +"fortune":"LA MAIN QUI TE NOURRIT PORTE DES GANTS" +}, +{ +"id":341, +"fortune":"COMPARER VOLE LA JOIE. CHEZ TOI À PLEIN TEMPS" +}, +{ +"id":342, +"fortune":"MIEUX VAUT MOITIÉ QUE RIEN. TOI. DES MIETTES" +}, +{ +"id":343, +"fortune":"MER CALME NE FORME PAS DE MARIN. RESTE À QUAI" +}, +{ +"id":344, +"fortune":"LA VÉRITÉ VIT SANS RÉPÉTITION. SAUF LA TIENNE" +}, +{ +"id":345, +"fortune":"TOUT AVEC MODÉRATION. MÊME ÇA. ARRÊTE" +}, +{ +"id":346, +"fortune":"CE QUI PART REVIENT. SUIVI DE COLIS ACTIVÉ" +}, +{ +"id":347, +"fortune":"NE DISCUTE PAS AVEC UN SOT. ON VOUS CONFOND" +}, +{ +"id":348, +"fortune":"LA SAGESSE CHUCHOTE. LA TIENNE EST EN MUET" +}, +{ +"id":349, +"fortune":"UN LONG VOYAGE COMMENCE PAR UN PAS. ÉTIRE TOI" +}, +{ +"id":350, +"fortune":"TRAVERSE LES PONTS. SANS LES BRÛLER. INFO" +}, +{ +"id":351, +"fortune":"LE GRAND CHÊNE FUT UNE NOIX. BELLE TRADITION" +}, +{ +"id":352, +"fortune":"CHAT ÉCHAUDÉ CRAINT. TOI TU REPLONGES" +}, +{ +"id":353, +"fortune":"LES MENSONGES ONT DE COURTES JAMBES. RAPIDES" +}, +{ +"id":354, +"fortune":"CHACUN FORGE SA CHANCE. TA FORGE EST ÉTEINTE" +}, +{ +"id":355, +"fortune":"LA POMME TOMBE PRÈS DU POMMIER. LUI SE TAIT" +}, +{ +"id":356, +"fortune":"PETIT À PETIT LES NIDS SE FONT. LES TIENS NON" +}, +{ +"id":357, +"fortune":"LA NUIT PORTE CONSEIL. LA TIENNE DES SÉRIES" +}, +{ +"id":358, +"fortune":"LE GRAND VOYAGE ATTEND. IL A MONTÉ SA BOÎTE" +}, +{ +"id":359, +"fortune":"TU VOYAGERAS LOIN. LA NAVETTE COMPTE" +}, +{ +"id":360, +"fortune":"TA PHOTO DE PASSEPORT MONTRE LE VRAI TOI" +}, +{ +"id":361, +"fortune":"TA LISTE DE RÊVES A BESOIN DE RÊVES" +}, +{ +"id":362, +"fortune":"TU VERRAS LE MONDE. EN DOCUMENTAIRE" +}, +{ +"id":363, +"fortune":"TES CONGÉS MÛRISSENT COMME UN BON REGRET" +}, +{ +"id":364, +"fortune":"UNE DESTINATION DE RÊVE APPELLE. TU FILTRES" +}, +{ +"id":365, +"fortune":"TA PLAYLIST DE ROUTE A SURVÉCU AU VOYAGE" +}, +{ +"id":366, +"fortune":"TU VOYAGES LÉGER. SAUF ÉMOTIONNELLEMENT" +}, +{ +"id":367, +"fortune":"TES SOUVENIRS PARLENT SURTOUT DES PRIX" +}, +{ +"id":368, +"fortune":"TU TE PERDS PARTOUT. TALENT PORTABLE" +}, +{ +"id":369, +"fortune":"TES PHOTOS DE VOYAGE STARIFIENT TON POUCE" +}, +{ +"id":370, +"fortune":"UN VOYAGE SPONTANÉ APPROCHE. AVEC TABLEUR" +}, +{ +"id":371, +"fortune":"TU ES CITOYEN DU MONDE. RÉFÉRENCES À VENIR" +}, +{ +"id":372, +"fortune":"TON CORPS EST PRÊT. LA PLAGE FERA AVEC" +}, +{ +"id":373, +"fortune":"LA MONTAGNE APPELLE. TU AS COUPÉ LA SONNERIE" +}, +{ +"id":374, +"fortune":"TES VACANCES AU BALCON RESTENT IMBATTABLES" +}, +{ +"id":375, +"fortune":"TU NAVIGUES COMME UN GUIDE. UN GUIDE PERDU" +}, +{ +"id":376, +"fortune":"TON ITINÉRAIRE EST SURTOUT DES MARGES" +}, +{ +"id":377, +"fortune":"TES CHAUSSURES DE RANDO ONT GRAVI LE PLACARD" +}, +{ +"id":378, +"fortune":"LE DÉCALAGE ÉPARGNE PERSONNE. TU PARS FATIGUÉ" +}, +{ +"id":379, +"fortune":"TON CARNET DE VOYAGE A UNE ENTRÉE. CONTENT" +}, +{ +"id":380, +"fortune":"TU COLLECTIONNES LES MOMENTS. PAS LA CARTE" +}, +{ +"id":381, +"fortune":"TON SENS DES DIRECTIONS EST UNE LÉGENDE" +}, +{ +"id":382, +"fortune":"UNE ESCAPADE APPROCHE. LE LINGE ATTENDRA" +}, +{ +"id":383, +"fortune":"TU REVIENS TRANSFORMÉ. SURTOUT FATIGUÉ" +}, +{ +"id":384, +"fortune":"TON HORAIRE AU TERMINAL DIT TOUT DE TOI" +}, +{ +"id":385, +"fortune":"TES PHOTOS DE HUBLOT. UNE SÉRIE SUR LES AILES" +}, +{ +"id":386, +"fortune":"TON BAGAGE À MAIN A SA PROPRE GRAVITÉ" +}, +{ +"id":387, +"fortune":"TES TALENTS DE CAMPEUR AMUSENT LES RATONS" +}, +{ +"id":388, +"fortune":"LA PLUIE VA LAVER TA VOITURE. TON PLAN EXACT" +}, +{ +"id":389, +"fortune":"TON DÉBAT SUR LA VESTE COMMENCE EN OCTOBRE" +}, +{ +"id":390, +"fortune":"TU CONSULTES LA MÉTÉO. PUIS TU IGNORES TOUT" +}, +{ +"id":391, +"fortune":"LE PRINTEMPS ARRIVE. TES ALLERGIES AUSSI" +}, +{ +"id":392, +"fortune":"TA CRÈME SOLAIRE EXPIRE INTACTE. CHAQUE ANNÉE" +}, +{ +"id":393, +"fortune":"LA NEIGE EST MAGIQUE. PUIS VIENT LA PELLE" +}, +{ +"id":394, +"fortune":"TES PARAPLUIES VIVENT TOUS AILLEURS" +}, +{ +"id":395, +"fortune":"LA MÉTÉO EST TON GRAND SUJET DÉSORMAIS" +}, +{ +"id":396, +"fortune":"LA PRÉVISION A CHANGÉ. PAS TES PLANS. VIDES" +}, +{ +"id":397, +"fortune":"TON SALON DE JARDIN CRAINT CHAQUE SAISON" +}, +{ +"id":398, +"fortune":"LES FEUILLES TOMBENT. COMME TES RÉSOLUTIONS" +}, +{ +"id":399, +"fortune":"TA BATTERIE TIENT PLUS LONGTEMPS QUE TOI" +}, +{ +"id":400, +"fortune":"TU LIRAS LES CONDITIONS UN JOUR. NON" +}, +{ +"id":401, +"fortune":"TON RAPPORT DE TEMPS DEVANT ÉCRAN TE MÉNAGE" +}, +{ +"id":402, +"fortune":"TA CHAISE À LINGE A UN POSTE FIXE DÉSORMAIS" +}, +{ +"id":403, +"fortune":"TON RÉVEIL A CINQ RÉVEILS DE SECOURS. MUETS" +}, +{ +"id":404, +"fortune":"TON FRIGO HÉBERGE UNE EXPÉRIENCE SCIENTIFIQUE" +}, +{ +"id":405, +"fortune":"LE VOYANT MOTEUR EST DEVENU UNE AMBIANCE" +}, +{ +"id":406, +"fortune":"TES PLANTES VERTES ONT ACCEPTÉ LEUR SORT" +}, +{ +"id":407, +"fortune":"TON TIROIR FOURRE TOUT A OUVERT UNE ANNEXE" +}, +{ +"id":408, +"fortune":"TON SAC DE SPORT EST PRÊT. ÇA COMPTE" +}, +{ +"id":409, +"fortune":"TA MESSAGERIE EST PLEINE. ON A RENONCÉ" +}, +{ +"id":410, +"fortune":"TES ONGLETS FORMENT UN ÉCOSYSTÈME" +}, +{ +"id":411, +"fortune":"TON PARAPLUIE ATTEND. TU VAS LE LAISSER LÀ" +}, +{ +"id":412, +"fortune":"TES RESTES AVAIENT DES RÊVES. ILS COMPOSTENT" +}, +{ +"id":413, +"fortune":"TA LISTE DE TÂCHES A UNE LISTE DE TÂCHES" +}, +{ +"id":414, +"fortune":"TON ARMOIRE HABILLE TROIS VERSIONS DE TOI" +}, +{ +"id":415, +"fortune":"TON JOGGING MATINAL EST PLANIFIÉ. DEPUIS MARS" +}, +{ +"id":416, +"fortune":"TON ROUTEUR TRÔNE SUR UN AUTEL. NORMAL" +}, +{ +"id":417, +"fortune":"TA BOÎTE MAIL VIDE RESTE UNE LÉGENDE" +}, +{ +"id":418, +"fortune":"TON TIROIR À CHAUSSETTES PROTÈGE LES VEUVES" +}, +{ +"id":419, +"fortune":"TA LISTE DE COURSES RESTE À LA MAISON. EXPRÈS" +}, +{ +"id":420, +"fortune":"TA LISTE DE SÉRIES A SURVÉCU À TROIS PASSIONS" +}, +{ +"id":421, +"fortune":"TON IMPRIMANTE SENT LA PANIQUE. DONC PANNE" +}, +{ +"id":422, +"fortune":"TON COUCHER EST UNE MOTION. TOUJOURS REJETÉE" +}, +{ +"id":423, +"fortune":"TES ÉCOUTEURS SE NOUENT SEULS. MYSTÈRE TOTAL" +}, +{ +"id":424, +"fortune":"TES ÉPICES SONT CLASSÉES DE A À C. BON DÉBUT" +}, +{ +"id":425, +"fortune":"TA BANQUETTE ARRIÈRE EST UN BUREAU DES OBJETS" +}, +{ +"id":426, +"fortune":"LE BON CÂBLE EST TOUJOURS AILLEURS" +}, +{ +"id":427, +"fortune":"TON BUREAU DEBOUT RESTE ASSIS. COMME TOI" +}, +{ +"id":428, +"fortune":"TON BATCH COOKING DONNE UN PLAT. SIX BOÎTES" +}, +{ +"id":429, +"fortune":"LE LIVREUR TE SALUE DE LOIN MAINTENANT" +}, +{ +"id":430, +"fortune":"TA FRITEUSE À AIR A REMPLACÉ LE FOUR. ET TOI" +}, +{ +"id":431, +"fortune":"TES MARQUE PAGES SONT UN MUSÉE DES INTENTIONS" +}, +{ +"id":432, +"fortune":"TON BOUTON SNOOZE MONTRE UNE USURE GÉOLOGIQUE" +}, +{ +"id":433, +"fortune":"TES SACS RÉUTILISABLES VIVENT DANS LE COFFRE" +}, +{ +"id":434, +"fortune":"TES MISES À JOUR ONT DES ANNÉES DE SERVICE" +}, +{ +"id":435, +"fortune":"LE BAC À GLAÇONS REVIENT VIDE. UNE TRADITION" +}, +{ +"id":436, +"fortune":"TON GARAGE STOCKE TOUT SAUF LA VOITURE" +}, +{ +"id":437, +"fortune":"TON PODOMÈTRE A ENCADRÉ SON MEILLEUR JOUR" +}, +{ +"id":438, +"fortune":"TA TASSE PRÉFÉRÉE EST SOUS PROTECTION" +}, +{ +"id":439, +"fortune":"LA MÉTÉO A RENONCÉ À TES TENUES" +}, +{ +"id":440, +"fortune":"TA BALANCE PRATIQUE LA FRANCHISE RADICALE" +}, +{ +"id":441, +"fortune":"TES TÉLÉCOMMANDES MIGRENT DANS LE CANAPÉ" +}, +{ +"id":442, +"fortune":"LE PLACARD DU COULOIR GARDE TA VÉRITÉ. JUSTE" +}, +{ +"id":443, +"fortune":"TU AS TOUTES LES PILES SAUF LA BONNE" +}, +{ +"id":444, +"fortune":"TON ASPIRATEUR ÉVITE LES COINS. COMME TOI" +}, +{ +"id":445, +"fortune":"TES IDÉES DE DOUCHE RESTENT SOUS LA DOUCHE" +}, +{ +"id":446, +"fortune":"TA CAFETIÈRE CONNAÎT TA TÊTE DU LUNDI" +}, +{ +"id":447, +"fortune":"LE FOND DU CONGÉLATEUR PRÉCÈDE TES AMITIÉS" +}, +{ +"id":448, +"fortune":"TON STOCKAGE EST PLEIN. DE CAPTURES INUTILES" +}, +{ +"id":449, +"fortune":"TES PNEUS DE VÉLO SOUPIRENT LENTEMENT" +}, +{ +"id":450, +"fortune":"TA PILE DE RETOURS A UNE ZONE DE DÉPART" +}, +{ +"id":451, +"fortune":"TES BOUGIES SONT DÉCO. LES ALLUMETTES AUSSI" +}, +{ +"id":452, +"fortune":"TA TABLE À MANGER A QUITTÉ LE MÉTIER" +}, +{ +"id":453, +"fortune":"TON CLAVIER PROPOSE PARDON EN PREMIER" +}, +{ +"id":454, +"fortune":"TON APPLI DE SPORT FAIT DES PHRASES COURTES" +}, +{ +"id":455, +"fortune":"TA POCHE DE MANTEAU EST UNE CAPSULE DU TEMPS" +}, +{ +"id":456, +"fortune":"LE BOUTON PLUS 30 SECONDES GÈRE TA CUISINE" +}, +{ +"id":457, +"fortune":"LES BONS CISEAUX ONT DISPARU. UN SEUL SUSPECT" +}, +{ +"id":458, +"fortune":"TON DOSSIER TÉLÉCHARGEMENTS EST UNE DÉCHARGE" +}, +{ +"id":459, +"fortune":"TES PLANTES VIVENT DE CULPABILITÉ" +}, +{ +"id":460, +"fortune":"LE SÈCHE LINGE PREND UNE CHAUSSETTE EN TRIBUT" +}, +{ +"id":461, +"fortune":"TES DESSOUS DE VERRE REGARDENT SANS AGIR" +}, +{ +"id":462, +"fortune":"TON APPLI DE NOTES EST UNE DÉCHARGE DE GÉNIE" +}, +{ +"id":463, +"fortune":"TES JEUX DE SOCIÉTÉ VIEILLISSENT SOUS BLISTER" +}, +{ +"id":464, +"fortune":"TON TAPIS DE YOGA A SERVI DEUX FOIS. SIESTES" +}, +{ +"id":465, +"fortune":"TES RALLONGES SE MULTIPLIENT DANS LE NOIR" +}, +{ +"id":466, +"fortune":"TON ENCEINTE CONNECTÉE A ENTENDU DES CHOSES" +}, +{ +"id":467, +"fortune":"TES BOÎTES ET LEURS COUVERCLES DIVORCENT" +}, +{ +"id":468, +"fortune":"TES BASKETS DE MARCHE VISITENT LE COFFRE" +}, +{ +"id":469, +"fortune":"TON DOSSIER IMPORTANT EST UN MOUROIR" +}, +{ +"id":470, +"fortune":"TA COURONNE DE NOËL EST PERMANENTE. FESTIF" +}, +{ +"id":471, +"fortune":"LE TIROIR QUI COINCE A CESSÉ DE PARLER" +}, +{ +"id":472, +"fortune":"TON ÉCRAN À 2 HEURES DU MATIN RÉVÈLE TOUT" +}, +{ +"id":473, +"fortune":"TON EXTINCTEUR VIT SUR SA RÉPUTATION" +}, +{ +"id":474, +"fortune":"TON OBJECTIF EAU FUT ATTEINT UNE FOIS. BRAVO" +}, +{ +"id":475, +"fortune":"VIEILLIR TE VA BIEN. LE CONTRAIRE MOINS" +}, +{ +"id":476, +"fortune":"TON ÂGE EST UN SIMPLE NOMBRE. CROISSANT" +}, +{ +"id":477, +"fortune":"TES GENOUX ANNONCENT LA PLUIE. UN TALENT" +}, +{ +"id":478, +"fortune":"TON DOS EST SORTI PLUS SOUVENT QUE TOI" +}, +{ +"id":479, +"fortune":"LA SAGESSE VIENT AVEC LE GRIS. LE TIEN EST LÀ" +}, +{ +"id":480, +"fortune":"TU VIEILLIS COMME LE VIN. COUCHÉ SURTOUT" +}, +{ +"id":481, +"fortune":"TES BOUGIES POSENT UN RISQUE INCENDIE" +}, +{ +"id":482, +"fortune":"TES LUNETTES DE LECTURE ONT DES LUNETTES" +}, +{ +"id":483, +"fortune":"TA PLAYLIST EST CLASSÉE RÉTRO. PAR LES JEUNES" +}, +{ +"id":484, +"fortune":"TU GÉMIS EN PRENANT PLACE. UN REÇU VOCAL" +}, +{ +"id":485, +"fortune":"TON MÉTABOLISME EST PARTI SANS UN MOT" +}, +{ +"id":486, +"fortune":"TU TE SENS COMME À 25 ANS. TES LENDEMAINS NON" +}, +{ +"id":487, +"fortune":"UNE POMME PAR JOUR. EN TARTE. BELLE ASTUCE" +}, +{ +"id":488, +"fortune":"TA POSTURE PROGRESSE DEUX FOIS PAR JOUR. BREF" +}, +{ +"id":489, +"fortune":"TU DORMIRAS HUIT HEURES. EN TROIS NUITS" +}, +{ +"id":490, +"fortune":"TES VITAMINES EXPIRENT INTACTES. CHAQUE FOIS" +}, +{ +"id":491, +"fortune":"TON RÉGIME COMMENCE LUNDI. LES LUNDIS FUIENT" +}, +{ +"id":492, +"fortune":"LE DENTISTE SAIT QUE LE FIL DATE DU MATIN" +}, +{ +"id":493, +"fortune":"TON POULS AU REPOS EST PARFAIT. LOGIQUE" +}, +{ +"id":494, +"fortune":"TU VIVRAS CENT ANS. PAR PURE REVANCHE" +}, +{ +"id":495, +"fortune":"TON TRACKER DE SOMMEIL PARLE DE FICTION" +}, +{ +"id":496, +"fortune":"TES ALLERGIES SONT PONCTUELLES. ELLES OUI" +}, +{ +"id":497, +"fortune":"TON MAL DE DOS A UNE VIE SOCIALE RICHE" +}, +{ +"id":498, +"fortune":"TES TALENTS CACHÉS RESTENT BIEN CACHÉS" +}, +{ +"id":499, +"fortune":"TA CRÉATIVITÉ NE CONNAÎT QUE LES PAUSES" +}, +{ +"id":500, +"fortune":"TU AS UN DON. SANS TICKET DE CAISSE" +}, +{ +"id":501, +"fortune":"TON ROMAN SERA FINI. PAR UNE AUTRE PERSONNE" +}, +{ +"id":502, +"fortune":"NÉ POUR CRÉER. LES EXCUSES COMPTENT AUSSI" +}, +{ +"id":503, +"fortune":"TON GRAND ŒUVRE VIT EN TOI. IL Y RESTE" +}, +{ +"id":504, +"fortune":"TON CHANT FAIT PLEURER. LA BIOLOGIE EST AINSI" +}, +{ +"id":505, +"fortune":"LA MUSE TE VISITE. ELLE PRÉVIENT AVANT" +}, +{ +"id":506, +"fortune":"TES PHOTOS CAPTURENT UNE CONFUSION BRUTE" +}, +{ +"id":507, +"fortune":"TU PENSES HORS DU CADRE. LE CADRE RESPIRE" +}, +{ +"id":508, +"fortune":"TES POÈMES ÉMEUVENT. DIRECTION LA SORTIE" +}, +{ +"id":509, +"fortune":"TON IMAGINATION EST VASTE. PAS TES ŒUVRES" +}, +{ +"id":510, +"fortune":"TU VOIS LE MONDE AUTREMENT. FAIS CONTRÔLER" +}, +{ +"id":511, +"fortune":"TON IDÉE DE PODCAST SALUE LES SIX AUTRES" +}, +{ +"id":512, +"fortune":"LA CRÉATIVITÉ PASSE DEVANT TOI. ELLE SALUE" +}, +{ +"id":513, +"fortune":"TES CROQUIS MÉRITENT UNE PLACE. UN TIROIR" +}, +{ +"id":514, +"fortune":"TA CUISINE EST DU SPECTACLE. AVEC ALARME" +}, +{ +"id":515, +"fortune":"TON SCÉNARIO A UNE ÉNERGIE POTENTIELLE" +}, +{ +"id":516, +"fortune":"LE MONDE EST TA TOILE. ENCORE VIERGE" +}, +{ +"id":517, +"fortune":"TES PROJETS FORMENT UNE TRILOGIE OUVERTE" +}, +{ +"id":518, +"fortune":"TES GOÛTS MUSICAUX SONT SÛRS. SELON TOI" +}, +{ +"id":519, +"fortune":"TA DANSE DÉFIE LES CODES. ET LA PHYSIQUE" +}, +{ +"id":520, +"fortune":"TU RACONTES BIEN. LES FINS RESTENT À VENIR" +}, +{ +"id":521, +"fortune":"LES PHARMACIENS ENCADRENT TON ÉCRITURE" +}, +{ +"id":522, +"fortune":"TES IDÉES VIENNENT À 2 HEURES. PARTENT À 8" +}, +{ +"id":523, +"fortune":"TON CARNET GARDE DE GRANDES PROMESSES" +}, +{ +"id":524, +"fortune":"TU POURRAIS ÉCRIRE UN LIVRE. UN DÉPLIANT" +}, +{ +"id":525, +"fortune":"TA PHASE POTERIE A CRÉÉ DES PIÈCES UNIQUES" +}, +{ +"id":526, +"fortune":"TON ARTISTE INTÉRIEUR VEUT UN CAFÉ AVANT" +}, +{ +"id":527, +"fortune":"TES CHOIX DE COULEURS SONT COURAGEUX" +}, +{ +"id":528, +"fortune":"TA GUITARE MAÎTRISE TROIS ACCORDS" +}, +{ +"id":529, +"fortune":"TON PROCESSUS CRÉATIF RESTE UN MYSTÈRE" +}, +{ +"id":530, +"fortune":"TES ÉCHARPES SONT DEVENUES DES EXPÉRIENCES" +}, +{ +"id":531, +"fortune":"TU PEINS AVEC ÉMOTION. LE SOL CONFIRME" +}, +{ +"id":532, +"fortune":"TON BONSAÏ EST UN ARBRE NORMAL DÉSORMAIS" +}, +{ +"id":533, +"fortune":"TA VOIX LITTÉRAIRE EST FORTE. EN TEXTOS" +}, +{ +"id":534, +"fortune":"TON JARDIN POUSSE. LES MAUVAISES HERBES OUI" +}, +{ +"id":535, +"fortune":"TA PHASE CALLIGRAPHIE DURA UN WEEK END" +}, +{ +"id":536, +"fortune":"TON BOIS EST HONNÊTE. LES ÉCHARDES AUSSI" +}, +{ +"id":537, +"fortune":"TA FANFICTION A DES FANS. LES DEUX" +}, +{ +"id":538, +"fortune":"TES ORIGAMIS REMPLISSENT LE BAC À PAPIER" +}, +{ +"id":539, +"fortune":"TON BLOCAGE CRÉATIF EST DEVENU PORTEUR" +}, +{ +"id":540, +"fortune":"TON LEVAIN A SURVÉCU À TA PASSION" +}, +{ +"id":541, +"fortune":"TES AQUARELLES CAPTURENT UN TRUC. LEQUEL" +}, +{ +"id":542, +"fortune":"TU BRILLES AUX DÉBUTS. LES MILIEUX ATTENDENT" +}, +{ +"id":543, +"fortune":"TON UKULÉLÉ ASSUME SON RÔLE DÉCORATIF" +}, +{ +"id":544, +"fortune":"TU ES TON PIRE CRITIQUE. SANS RIVAL SÉRIEUX" +}, +{ +"id":545, +"fortune":"TON ART PARLE POUR LUI. À VOIX BASSE" +}, +{ +"id":546, +"fortune":"TON ATELIER EST REDEVENU UN PLACARD" +}, +{ +"id":547, +"fortune":"TES PREMIERS JETS RESTENT ENFANTS UNIQUES" +}, +{ +"id":548, +"fortune":"TA PHASE BOUGIES A LAISSÉ DES TRACES. DE CIRE" +}, +{ +"id":549, +"fortune":"TES DÉBUTS SUR SCÈNE RESTENT IMMINENTS" +}, +{ +"id":550, +"fortune":"TES COSTUMES MONTRENT UN VRAI ENGAGEMENT" +}, +{ +"id":551, +"fortune":"TA CHOUETTE EN MACRAMÉ A TOUT VU. ELLE JUGE" +}, +{ +"id":552, +"fortune":"TES MÉMOS VOCAUX SONT DES LISTES DE COURSES" +}, +{ +"id":553, +"fortune":"TU SERAS DÉCOUVERT. SUR TON CANAPÉ" +}, +{ +"id":554, +"fortune":"TON MOODBOARD A DU MOOD. PAS DE BOARD" +}, +{ +"id":555, +"fortune":"TA VISITE DE MUSÉE FINIT AU CAFÉ DU MUSÉE" +}, +{ +"id":556, +"fortune":"TES REPRISES BATTENT LES ORIGINAUX. CHUT" +}, +{ +"id":557, +"fortune":"TA MACHINE À ÉCRIRE DÉCORE AVEC DIGNITÉ" +}, +{ +"id":558, +"fortune":"TA PÉRIODE ABSTRAITE PERDIT MÊME TOI" +}, +{ +"id":559, +"fortune":"TA BD A UN LECTEUR FIDÈLE. COUCOU MAMAN" +}, +{ +"id":560, +"fortune":"TES RIMES SONT AMBITIEUSES. TRÈS" +}, +{ +"id":561, +"fortune":"TON COIN BRICOLAGE A ANNEXÉ LA CHAMBRE" +}, +{ +"id":562, +"fortune":"TON GÉNIE EST INCOMPRIS. ET INVISIBLE" +}, +{ +"id":563, +"fortune":"TON GRAND ŒUVRE INFUSE DEPUIS DES ANNÉES" +}, +{ +"id":564, +"fortune":"TON DOSSIER INSPIRATION A DES SOUS DOSSIERS" +}, +{ +"id":565, +"fortune":"TON CAFÉ EST DEVENU UN PARAGRAPHE ENTIER" +}, +{ +"id":566, +"fortune":"LE CAFÉ EN PREMIER. LA PERSONNALITÉ SUIT" +}, +{ +"id":567, +"fortune":"TON QUATRIÈME CAFÉ TE SURVEILLE" +}, +{ +"id":568, +"fortune":"LE DÉCA EXISTE. TU NIES SON EXISTENCE" +}, +{ +"id":569, +"fortune":"TA COLLECTION DE TASSES DÉBORDE DU PLACARD" +}, +{ +"id":570, +"fortune":"TU DIS BRUNCH. TU VEUX DIRE RÉVEIL TARDIF" +}, +{ +"id":571, +"fortune":"TA PHASE SALADE EST MORTE À LA SAUCE" +}, +{ +"id":572, +"fortune":"TU PLANIFIES TES REPAS. PUIS TU COMMANDES" +}, +{ +"id":573, +"fortune":"TON PLAT SIGNATURE A UN FAN. TOI" +}, +{ +"id":574, +"fortune":"LE MINUTEUR DU FOUR EST UN SIMPLE AVIS" +}, +{ +"id":575, +"fortune":"TES SMOOTHIES CACHENT DES LÉGUMES. À TOI" +}, +{ +"id":576, +"fortune":"TU CUISINES AVEC AMOUR. ET TROP DE SEL" +}, +{ +"id":577, +"fortune":"TES SUBSTITUTIONS DE RECETTE SONT BRAVES" +}, +{ +"id":578, +"fortune":"TU DOSES TON AIL AVEC LE CŒUR. ENCORE" +}, +{ +"id":579, +"fortune":"TON PAIN GRILLÉ EST SOLIDE. TRÈS GRILLÉ" +}, +{ +"id":580, +"fortune":"LE DESSERT EN PREMIER. LA VIE EST COURTE" +}, +{ +"id":581, +"fortune":"TON TIROIR À SNACKS A SA FILE DE FANS" +}, +{ +"id":582, +"fortune":"LE LIVREUR CONNAÎT TON PRÉNOM ET TON CODE" +}, +{ +"id":583, +"fortune":"TES GADGETS DE CUISINE FORMENT UN MUSÉE" +}, +{ +"id":584, +"fortune":"TES BOÎTES DE TRAITEUR SONT DES HÉRITAGES" +}, +{ +"id":585, +"fortune":"TU MANGES DE TOUT. EN THÉORIE SEULEMENT" +}, +{ +"id":586, +"fortune":"TES CHOIX DE PIZZA ONT DES CRITIQUES" +}, +{ +"id":587, +"fortune":"TON CHIEN VOUS ADORE TOUS. IL EST DRESSÉ" +}, +{ +"id":588, +"fortune":"TON CHAT TE TOLÈRE. UN GRAND HONNEUR" +}, +{ +"id":589, +"fortune":"TON ANIMAL MANGE MIEUX QUE TOI" +}, +{ +"id":590, +"fortune":"TON CHIEN A UN CERCLE SOCIAL PLUS LARGE" +}, +{ +"id":591, +"fortune":"LE CHAT A TOUT FAIT TOMBER EXPRÈS. RESPECT" +}, +{ +"id":592, +"fortune":"TON POISSON CONNAÎT TON EMPLOI DU TEMPS" +}, +{ +"id":593, +"fortune":"LE CHIEN A MANGÉ TA MOTIVATION" +}, +{ +"id":594, +"fortune":"TON CHAT ÉVALUE TA VIE CHAQUE NUIT" +}, +{ +"id":595, +"fortune":"TON PERROQUET CITE TES PIRES PHRASES" +}, +{ +"id":596, +"fortune":"TON ANIMAL ÉCOUTE BIEN. ET GRATUITEMENT" +}, +{ +"id":597, +"fortune":"TON MOT DE PASSE EST TON CHAT. ON LE SAIT" +}, +{ +"id":598, +"fortune":"TU AS 47 MISES À JOUR EN ATTENTE. PATIENTES" +}, +{ +"id":599, +"fortune":"TON CLOUD EST PLEIN. DE DOUBLONS" +}, +{ +"id":600, +"fortune":"LE CORRECTEUR SAVAIT. IL A REFUSÉ" +}, +{ +"id":601, +"fortune":"TON ROUTEUR VEUT UN REDÉMARRAGE. TOI AUSSI" +}, +{ +"id":602, +"fortune":"TON HISTORIQUE DE RECHERCHE EST UNE SAGA" +}, +{ +"id":603, +"fortune":"TU AS FERMÉ UN ONGLET CE JOUR. PROGRÈS" +}, +{ +"id":604, +"fortune":"TON DOSSIER SPAM SE SENT SEUL" +}, +{ +"id":605, +"fortune":"LES ALGORITHMES TE CONNAISSENT TROP BIEN" +}, +{ +"id":606, +"fortune":"TA MONTRE TE CONSEILLE DE RESPIRER. SUBTIL" +}, +{ +"id":607, +"fortune":"TU TAPES PLUS VITE PENDANT LES DISPUTES" +}, +{ +"id":608, +"fortune":"TU AS COUPÉ LE GROUPE. LE GROUPE LE SAIT" +}, +{ +"id":609, +"fortune":"TA TOUCHE MAJUSCULE FAIT DU SPORT" +}, +{ +"id":610, +"fortune":"TES EMOJIS ONT FAIT DÉBAT. PLUS DUNE FOIS" +}, +{ +"id":611, +"fortune":"LE NOM DE TON WIFI EST TA MEILLEURE BLAGUE" +}, +{ +"id":612, +"fortune":"REDÉMARRER EST TON ART DE VIVRE" +}, +{ +"id":613, +"fortune":"TA SALLE DE SPORT TE REMERCIE POUR LE DON" +}, +{ +"id":614, +"fortune":"TON PLAN MARATHON EST SAUVEGARDÉ. EN LIEU SÛR" +}, +{ +"id":615, +"fortune":"LE JOUR DES JAMBES RESPECTE TON ABSENCE" +}, +{ +"id":616, +"fortune":"TA PROTÉINE EN POUDRE VIEILLIT AVEC CLASSE" +}, +{ +"id":617, +"fortune":"TU TÉTIRES UNE FOIS PAR AN. AVEC AMBITION" +}, +{ +"id":618, +"fortune":"TON ÉQUIPE PERD. TU PRENDS ÇA POUR TOI" +}, +{ +"id":619, +"fortune":"TU ARRIVES EN RETARD. ÇA COMPTE COMME CARDIO" +}, +{ +"id":620, +"fortune":"TON HOME GYM RANGE LE LINGE DÉSORMAIS" +}, +{ +"id":621, +"fortune":"TON RECORD PERSONNEL FUT UN TRAVAIL DE GROUPE" +}, +{ +"id":622, +"fortune":"TON ÉCHAUFFEMENT EST TOUTE LA SÉANCE" +}, +{ +"id":623, +"fortune":"TES JOURS DE REPOS ONT DES JOURS DE REPOS" +}, +{ +"id":624, +"fortune":"LE SOMMEIL EST POUR LES FORTS. TU DÉFILES" +}, +{ +"id":625, +"fortune":"TON PLANNING DE SIESTES EST TON VRAI AGENDA" +}, +{ +"id":626, +"fortune":"TU COMPTES LES MOUTONS. EUX TES EXCUSES" +}, +{ +"id":627, +"fortune":"TON OREILLER CONNAÎT TOUS TES SECRETS" +}, +{ +"id":628, +"fortune":"UN DERNIER ÉPISODE ÉGALE QUATRE ÉPISODES" +}, +{ +"id":629, +"fortune":"TES RÊVES SONT VIFS. TES MATINS MOINS" +}, +{ +"id":630, +"fortune":"TU METS SIX ALARMES. AUCUNE NE TE FAIT PEUR" +}, +{ +"id":631, +"fortune":"REPOUSSER LE COUCHER RESTE UN CHOIX" +}, +{ +"id":632, +"fortune":"TA DETTE DE SOMMEIL PREND DES INTÉRÊTS" +}, +{ +"id":633, +"fortune":"TA FAMILLE TE SOUTIENT. VOTE SERRÉ" +}, +{ +"id":634, +"fortune":"TA MÈRE AVAIT RAISON. SUR TOUT" +}, +{ +"id":635, +"fortune":"LES REPAS DE FAMILLE TESTENT TA DIPLOMATIE" +}, +{ +"id":636, +"fortune":"TA FRATRIE SE SOUVIENT DE TOUT. POUR TOUJOURS" +}, +{ +"id":637, +"fortune":"LES ONCLES DEMANDENT TES PROJETS. TIENS BON" +}, +{ +"id":638, +"fortune":"TU ES LE PRÉFÉRÉ. SOURCE NON CONFIRMÉE" +}, +{ +"id":639, +"fortune":"LE GROUPE FAMILLE NE DORT JAMAIS" +}, +{ +"id":640, +"fortune":"MAMIE TE NOURRIT. TOUTE RÉSISTANCE EST VAINE" +}, +{ +"id":641, +"fortune":"TES BLAGUES DE PAPA SE TRANSMETTENT INTACTES" +}, +{ +"id":642, +"fortune":"LE PLAN DE TABLE DES FÊTES EST POLITIQUE" +}, +{ +"id":643, +"fortune":"TON VOISIN TE SALUE. LA CLÔTURE FUT SON IDÉE" +}, +{ +"id":644, +"fortune":"LE SYNDIC A REVU TA PELOUSE. ENCORE" +}, +{ +"id":645, +"fortune":"TES VOISINS CONNAISSENT TON EMPLOI DU TEMPS" +}, +{ +"id":646, +"fortune":"UN OUTIL PRÊTÉ DEVIENT UN OUTIL DONNÉ" +}, +{ +"id":647, +"fortune":"TA CAMÉRA DE PORTE A FILMÉ TON SPRINT" +}, +{ +"id":648, +"fortune":"TON TRAJET QUOTIDIEN FORGE LE CARACTÈRE" +}, +{ +"id":649, +"fortune":"LES BOUCHONS NE VISENT PERSONNE. SAUF TOI" +}, +{ +"id":650, +"fortune":"TON CRÉNEAU LAISSE DES TÉMOINS SANS VOIX" +}, +{ +"id":651, +"fortune":"TON GPS DIT RECALCUL. AVEC LASSITUDE" +}, +{ +"id":652, +"fortune":"TU CONDUIS COMME TU VIS. CLIGNOTANT EN OPTION" +}, +{ +"id":653, +"fortune":"TON RÉSERVOIR ROULE À LA FOI. ET AUX VAPEURS" +}, +{ +"id":654, +"fortune":"LA VOIE DE GAUCHE SERT À DOUBLER. VOILÀ TOUT" +}, +{ +"id":655, +"fortune":"TA PLAYLIST AUTO A CULMINÉ EN 2016" +}, +{ +"id":656, +"fortune":"TON KLAXON TRAVAILLE PLUS QUE TON CLIGNOTANT" +}, +{ +"id":657, +"fortune":"LE TEMPS FILE. LE TIEN A UN PLAN DE VOL" +}, +{ +"id":658, +"fortune":"PROCRASTINER EST UN ART. TU ENSEIGNES" +}, +{ +"id":659, +"fortune":"TU LE FERAS DEMAIN. DEMAIN EST PRÉVENU" +}, +{ +"id":660, +"fortune":"LES DÉLAIS APPROCHENT. TU ADMIRES LA VUE" +}, +{ +"id":661, +"fortune":"TES CINQ MINUTES DURENT DES HEURES AILLEURS" +}, +{ +"id":662, +"fortune":"PLUS TARD EST TON FUSEAU HORAIRE PRÉFÉRÉ" +}, +{ +"id":663, +"fortune":"TU FINIS TOUT. UN JOUR EST UN MOT VALIDE" +}, +{ +"id":664, +"fortune":"TA LISTE UN JOUR PEUT REMPLIR UNE ÉTAGÈRE" +}, +{ +"id":665, +"fortune":"LA GESTION DU TEMPS EST UNE COMPÉTENCE. NOTÉ" +}, +{ +"id":666, +"fortune":"TU ES EN AVANCE UNE FOIS PAR AN. ON PANIQUE" +}, +{ +"id":667, +"fortune":"TA PONCTUALITÉ EST CÉLÈBRE. PAS EN BIEN" +}, +{ +"id":668, +"fortune":"TU LIS CECI AU LIEU DE TRAVAILLER. NOTÉ" +}, +{ +"id":669, +"fortune":"TON ATTENTION EST. TIENS UN OISEAU" +}, +{ +"id":670, +"fortune":"ENCORE UNE MINUTE. PAROLES CÉLÈBRES" +}, +{ +"id":671, +"fortune":"TU RÉPONDS AUX TEXTOS EN TEMPS GÉOLOGIQUE" +}, +{ +"id":672, +"fortune":"TES ACCUSÉS DE LECTURE TE TRAHISSENT" +}, +{ +"id":673, +"fortune":"TU AS VU LE MESSAGE. EUX AUSSI ONT VU" +}, +{ +"id":674, +"fortune":"TA BULLE DE FRAPPE EST APPARUE. PUIS PARTIE" +}, +{ +"id":675, +"fortune":"TU AS DIT ON DEVRAIT SE VOIR. UN CLASSIQUE" +}, +{ +"id":676, +"fortune":"TON TÉLÉPHONE EST MUET. DEPUIS DES ANNÉES" +}, +{ +"id":677, +"fortune":"TU FAIS DES CAPTURES AU LIEU DE RÉPONDRE" +}, +{ +"id":678, +"fortune":"TON AVIS FUT NOTÉ. PUIS RECYCLÉ" +}, +{ +"id":679, +"fortune":"UN COMPLIMENT ARRIVE. ACCEPTE LE MAL" +}, +{ +"id":680, +"fortune":"TON VISAGE NEUTRE A UNE RÉPUTATION" +}, +{ +"id":681, +"fortune":"VOUS ÊTES DACCORD SUR LE DÉSACCORD. TU PERDS" +}, +{ +"id":682, +"fortune":"TON ROULEMENT DES YEUX EST PRESQUE SONORE" +}, +{ +"id":683, +"fortune":"TON SOUPIR VIENT DE PARLER POUR TOI" +}, +{ +"id":684, +"fortune":"TU AS DIT ÇA VA. RIEN NE VA" +}, +{ +"id":685, +"fortune":"TON POUCE LEVÉ A BRISÉ TROIS AMITIÉS" +}, +{ +"id":686, +"fortune":"PAS DE SOUCI AS TU DIT. PLEIN DE SOUCIS" +}, +{ +"id":687, +"fortune":"TON HAUSSEMENT DE COUPE FAIT UN GROS TRAVAIL" +}, +{ +"id":688, +"fortune":"TU AS SOURI À TRAVERS TOUT ÇA. ON A VU" +}, +{ +"id":689, +"fortune":"TA PATIENCE A UNE BARRE DE CHARGEMENT. FIGÉE" +}, +{ +"id":690, +"fortune":"TU LEUR AS PARDONNÉ. LE TABLEUR RESTE" +}, +{ +"id":691, +"fortune":"TES SOUS ENTENDUS VEULENT DES SOUS TITRES" +}, +{ +"id":692, +"fortune":"TU AS FAILLI LE DIRE. LE FAILLI ÉTAIT FORT" +}, +{ +"id":693, +"fortune":"TON SILENCE A UN ORDRE DU JOUR. CLASSIQUE" +}, +{ +"id":694, +"fortune":"TU AS LAISSÉ COULER. DANS TES ARCHIVES" +}, +{ +"id":695, +"fortune":"TON CALME INTRIGUE TOUT LE MONDE" +}, +{ +"id":696, +"fortune":"TU AS PRIS LA VOIE NOBLE. AVEC COMMENTAIRES" +}, +{ +"id":697, +"fortune":"TU AS PRIS LA HAUTEUR. AVEC UN COMMENTAIRE" +}, +{ +"id":698, +"fortune":"TON CALME EST SUSPECT. TOUT LE MONDE LE DIT" +}, +{ +"id":699, +"fortune":"CE BISCUIT NA PAS DE SAGESSE. QUE DU SUCRE" +}, +{ +"id":700, +"fortune":"LA SAGESSE CHERCHÉE EST DANS UN AUTRE BISCUIT" +} +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_it.json b/apps/sarcastic-fortune-cookies/fortunes_it.json new file mode 100644 index 0000000..8a14ee6 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_it.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "TUTTO ACCADE PER UN MOTIVO. DI SOLITO BRUTTO" + }, + { + "id": 2, + "fortune": "LA FORTUNA ARRIVA. CAMMINA MOLTO PIANO" + }, + { + "id": 3, + "fortune": "IL COSMO HA UN PIANO PER TE. UNO PICCOLO" + }, + { + "id": 4, + "fortune": "IL TUO DESTINO HA CHIAMATO. RIMANDA" + }, + { + "id": 5, + "fortune": "LE STELLE SI ALLINEANO. POI TI HANNO VISTO" + }, + { + "id": 6, + "fortune": "LA TUA NAVE ARRIVA. UNA CANOA" + }, + { + "id": 7, + "fortune": "FIDATI DEL PROCESSO. LUI DUBITA DI TE" + }, + { + "id": 8, + "fortune": "UN SEGNO ARRIVA. DICE DARE PRECEDENZA" + }, + { + "id": 9, + "fortune": "LA TUA STELLA ESISTE. IN UNA GALASSIA LONTANA" + }, + { + "id": 10, + "fortune": "IL KARMA REALE. QUESTO SPIEGA MOLTO" + }, + { + "id": 11, + "fortune": "IL TUO FUTURO LUMINOSO. METTI LA CREMA" + }, + { + "id": 12, + "fortune": "IL DESTINO ATTENDE. SI MESSO A LEGGERE" + }, + { + "id": 13, + "fortune": "I MIRACOLI ACCADONO OGNI GIORNO. ALTROVE" + }, + { + "id": 14, + "fortune": "IL TUO MOMENTO ARRIVA. NEL TRAFFICO" + }, + { + "id": 15, + "fortune": "LA FORTUNA HA BUSSATO. ERI USCITO" + }, + { + "id": 16, + "fortune": "LA MAREA CAMBIA. A VELOCIT DI GHIACCIAIO" + }, + { + "id": 17, + "fortune": "ARRIVANO GRANDI COSE. ABBASSA LE ATTESE" + }, + { + "id": 18, + "fortune": "LE OCCASIONI CI SONO. VI PERDETE SEMPRE" + }, + { + "id": 19, + "fortune": "IL COSMO TI SENTE. METTITI IN CODA" + }, + { + "id": 20, + "fortune": "LE TUE PREGHIERE SONO SENTITE. E ARCHIVIATE" + }, + { + "id": 21, + "fortune": "IL BENE SCORRE VERSO DI TE. CONTROCORRENTE" + }, + { + "id": 22, + "fortune": "LA RUOTA GIRA. TU SEI IL CRICETO" + }, + { + "id": 23, + "fortune": "OGNI NUVOLA HA UN LATO BUONO. IL TUO GOCCIOLA" + }, + { + "id": 24, + "fortune": "IL CASO CHIEDE DI TE. PER CURIOSIT" + }, + { + "id": 25, + "fortune": "I PRESAGI PARLANO. PI CHE ALTRO SOSPIRANO" + }, + { + "id": 26, + "fortune": "IL TUO OROSCOPO BUONO. E FINTO" + }, + { + "id": 27, + "fortune": "IL FULMINE NON CADE DUE VOLTE. TU S" + }, + { + "id": 28, + "fortune": "IL DESTINO PREMIA LA PAZIENZA. FATTURA DOPO" + }, + { + "id": 29, + "fortune": "LA LUNA HA VISTO IL TUO NUOVO INIZIO. ANCORA" + }, + { + "id": 30, + "fortune": "IL TUO ANGELO VEGLIA. PRENDE APPUNTI" + }, + { + "id": 31, + "fortune": "CREDI E RICEVERAI. CONSEGNA VARIABILE" + }, + { + "id": 32, + "fortune": "LA TUA ERA DORATA ARRIVA. PLACCATA ORO" + }, + { + "id": 33, + "fortune": "CI CHE TUO ARRIVA. SENZA FRETTA" + }, + { + "id": 34, + "fortune": "IL COSMO TI FA UN CENNO. O UN TIC" + }, + { + "id": 35, + "fortune": "LA TUA SORTE CAMBIER. DIREZIONE IGNOTA" + }, + { + "id": 36, + "fortune": "LA PROVVIDENZA PROVVEDE. CONTA GLI SCONTRINI" + }, + { + "id": 37, + "fortune": "ESPRIMI UN DESIDERIO. LA STELLA LO METTE SPAM" + }, + { + "id": 38, + "fortune": "TUTTO ARRIVA A CHI ASPETTA. IL TUO TARDA" + }, + { + "id": 39, + "fortune": "I SEGNI CI SONO. LEGGERE FACOLTATIVO" + }, + { + "id": 40, + "fortune": "SEI UNICO. COME TUTTI GLI ALTRI" + }, + { + "id": 41, + "fortune": "IL MEGLIO DEVE VENIRE. NON HA FRETTA" + }, + { + "id": 42, + "fortune": "LA TUA AURA BRILLA. FA GLI STRAORDINARI" + }, + { + "id": 43, + "fortune": "LA FORTUNA TI HA SORRISO. CORTESE. DA LONTANO" + }, + { + "id": 44, + "fortune": "IL TUO ANGELO HA CHIESTO IL TRASFERIMENTO" + }, + { + "id": 45, + "fortune": "IL DESTINO D LE CARTE. TU LE PERDI" + }, + { + "id": 46, + "fortune": "UN PRESAGIO APPARE. ALZA LE SPALLE" + }, + { + "id": 47, + "fortune": "IL SUCCESSO VICINO. E ANCHE IL TASTO RINVIA" + }, + { + "id": 48, + "fortune": "IL LAVORO PAGA SEMPRE. IN ESPERIENZA" + }, + { + "id": 49, + "fortune": "IL TUO POTENZIALE ENORME. E INTATTO" + }, + { + "id": 50, + "fortune": "PUNTA ALLA LUNA. ATTENTO AL SOFFITTO" + }, + { + "id": 51, + "fortune": "CHI DORME NON PIGLIA PESCI. TU DORMIVI" + }, + { + "id": 52, + "fortune": "LA TUA GRANDE OCCASIONE ARRIVA. NON ROMPERLA" + }, + { + "id": 53, + "fortune": "ROMA NON FU FATTA IN UN GIORNO. NEANCHE TU" + }, + { + "id": 54, + "fortune": "I TUOI TALENTI SI TROVERANNO. CON UN MANDATO" + }, + { + "id": 55, + "fortune": "CHI VINCE NON MOLLA. TU GALLEGGI" + }, + { + "id": 56, + "fortune": "LE TUE IDEE SONO AVANTI. LE SCADENZE INDIETRO" + }, + { + "id": 57, + "fortune": "LA QUALIT UN VIZIO. HAI IL TUO" + }, + { + "id": 58, + "fortune": "IL TUO LAVORO PARLA DA S. SOTTOVOCE" + }, + { + "id": 59, + "fortune": "LA CIMA SOLITARIA. PROBLEMA RISOLTO" + }, + { + "id": 60, + "fortune": "UNA PROMOZIONE ARRIVA. QUELLA DI UN COLLEGA" + }, + { + "id": 61, + "fortune": "IL TUO CV IMPRESSIONA. GLI AMANTI DEL FANTASY" + }, + { + "id": 62, + "fortune": "IL TUO LAVORO MIGLIORE ARRIVA. CORRE VELOCE" + }, + { + "id": 63, + "fortune": "QUELLA RIUNIONE POTEVA ESSERE UN MAIL" + }, + { + "id": 64, + "fortune": "LA TUA CASELLA NON NEMICA. SOLO TESTIMONE" + }, + { + "id": 65, + "fortune": "LE SCADENZE NON TI SPAVENTANO. LE IGNORI" + }, + { + "id": 66, + "fortune": "IL TUO PIANO A CINQUE ANNI HA CINQUE ANNI" + }, + { + "id": 67, + "fortune": "LENTO MA SICURO VINCE. PADRONEGGI IL LENTO" + }, + { + "id": 68, + "fortune": "LA TUA AGENDA PIENA. DI MARGINI" + }, + { + "id": 69, + "fortune": "ANCHE LA TUA SQUADRA SOGNA. IL TRASFERIMENTO" + }, + { + "id": 70, + "fortune": "LA GRANDE OCCASIONE SCESA DA TE" + }, + { + "id": 71, + "fortune": "IL SUCCESSO LASCIA INDIZI. TU AMI IL MISTERO" + }, + { + "id": 72, + "fortune": "LA TUA COMFORT ZONE MERITA UN CAP" + }, + { + "id": 73, + "fortune": "QUALIT O QUANTIT. LE RIFIUTI ENTRAMBE" + }, + { + "id": 74, + "fortune": "IL TUO ISTINTO ACUTO. E SPESSO SBAGLIA" + }, + { + "id": 75, + "fortune": "LAVORI BENE SOTTO PRESSIONE. LEI DISSENTE" + }, + { + "id": 76, + "fortune": "LA MAESTRIA CHIEDE 10000 ORE. TU NE HAI 40" + }, + { + "id": 77, + "fortune": "LA TUA PIANTA CREDEVA IN TE. E POI SETE" + }, + { + "id": 78, + "fortune": "LA STAMPANTE SENTE LA FRETTA. QUINDI SI FERMA" + }, + { + "id": 79, + "fortune": "LA TUA EREDIT IN CANTIERE. ANCORA" + }, + { + "id": 80, + "fortune": "UN DIPLOMA TI ASPETTA. QUELLO DI PRESENZA" + }, + { + "id": 81, + "fortune": "FARE RETE APRE PORTE. ANCHE BUSSARE" + }, + { + "id": 82, + "fortune": "SEI UN ESEMPIO. NE VOGLIONO UN ALTRO" + }, + { + "id": 83, + "fortune": "IL TUO PROGETTO RIPOSA CON GLI ALTRI" + }, + { + "id": 84, + "fortune": "IL GENIO UN PER CENTO SUDORE. TU MOLLI L" + }, + { + "id": 85, + "fortune": "IL TUO MESSAGGIO DI ASSENZA UN CAPOLAVORO" + }, + { + "id": 86, + "fortune": "FALLIRE UN GRADINO. BELLA SCALINATA" + }, + { + "id": 87, + "fortune": "SEI INSOSTITUIBILE. IL BANDO PRONTO" + }, + { + "id": 88, + "fortune": "IL TUO COLLOQUIO ANNUALE ARRIVA. PROVA BENE" + }, + { + "id": 89, + "fortune": "EFFICIENZA IL TUO SECONDO NOME. SULLA CARTA" + }, + { + "id": 90, + "fortune": "CADI IN PIEDI. LA CADUTA RINVIATA" + }, + { + "id": 91, + "fortune": "LA VETTA VICINA. ANCHE IL CAMPO BASE" + }, + { + "id": 92, + "fortune": "LA TUA AMBIZIONE SI SVEGLIATA. NON TU" + }, + { + "id": 93, + "fortune": "SII TE STESSO. GLI ALTRI SI SONO PREOCCUPATI" + }, + { + "id": 94, + "fortune": "LA TUA RIUNIONE ANDATA BENE. FINITA" + }, + { + "id": 95, + "fortune": "RIPOSARE FA BENE. LO PRATICHI MOLTO" + }, + { + "id": 96, + "fortune": "LA TUA DIETA INIZIA LUNED. I LUNED FUGGONO" + }, + { + "id": 97, + "fortune": "TE LO MERITI. FAI UN BEL RESPIRO" + }, + { + "id": 98, + "fortune": "UNO SCONOSCIUTO TI SORRIDE. STAI CALMO" + }, + { + "id": 99, + "fortune": "NON SERBI RANCORE. LO ARCHIVI CON DATA" + }, + { + "id": 100, + "fortune": "LA PAZIENZA UNA VIRT. NE HAI SCELTE ALTRE" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_nl.json b/apps/sarcastic-fortune-cookies/fortunes_nl.json new file mode 100644 index 0000000..440383c --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_nl.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "ALLES GEBEURT MET EEN REDEN. MEESTAL SLECHT" + }, + { + "id": 2, + "fortune": "HET GELUK KOMT ERAAN. HET LOOPT TRAAG" + }, + { + "id": 3, + "fortune": "HET HEELAL HEEFT EEN PLAN. EEN KLEIN PLAN" + }, + { + "id": 4, + "fortune": "JE LOTSBESTEMMING BELDE. ZE VERZET HET" + }, + { + "id": 5, + "fortune": "DE STERREN STONDEN GOED. TOEN ZAGEN ZE JOU" + }, + { + "id": 6, + "fortune": "JE SCHIP KOMT BINNEN. HET IS EEN KANO" + }, + { + "id": 7, + "fortune": "VERTROUW HET PROCES. HET TWIJFELT AAN JOU" + }, + { + "id": 8, + "fortune": "EEN TEKEN KOMT. HET ZEGT VERLEEN VOORRANG" + }, + { + "id": 9, + "fortune": "JE STER BESTAAT. IN EEN ANDER STELSEL" + }, + { + "id": 10, + "fortune": "KARMA BESTAAT. DAT VERKLAART VEEL" + }, + { + "id": 11, + "fortune": "JE TOEKOMST IS STRALEND. NEEM ZONNEBRAND" + }, + { + "id": 12, + "fortune": "HET LOT WACHT. HET IS GAAN LEZEN" + }, + { + "id": 13, + "fortune": "WONDEREN GEBEUREN ELKE DAG. ELDERS DAN" + }, + { + "id": 14, + "fortune": "JE MOMENT KOMT. HET STAAT IN DE FILE" + }, + { + "id": 15, + "fortune": "HET GELUK KLOPTE AAN. JE WAS WEG" + }, + { + "id": 16, + "fortune": "HET TIJ KEERT. OP GLETSJERSNELHEID" + }, + { + "id": 17, + "fortune": "GROTE DINGEN KOMEN. VERLAAG DE LAT" + }, + { + "id": 18, + "fortune": "DE KANSEN ZIJN ER. JULLIE MISSEN ELKAAR" + }, + { + "id": 19, + "fortune": "HET HEELAL HOORT JE. GA IN DE RIJ STAAN" + }, + { + "id": 20, + "fortune": "JE GEBEDEN ZIJN GEHOORD. EN GEARCHIVEERD" + }, + { + "id": 21, + "fortune": "OVERVLOED STROOMT NAAR JE. STROOMOPWAARTS" + }, + { + "id": 22, + "fortune": "HET RAD DRAAIT. JIJ BENT DE HAMSTER" + }, + { + "id": 23, + "fortune": "ELKE WOLK HEEFT EEN RAND. DE JOUWE DRUPT" + }, + { + "id": 24, + "fortune": "HET TOEVAL VRAAGT NAAR JOU. UIT NIEUWSGIER" + }, + { + "id": 25, + "fortune": "DE VOORTEKENS SPREKEN. ZE ZUCHTEN VOORAL" + }, + { + "id": 26, + "fortune": "JE HOROSCOOP IS GUNSTIG. EN VERZONNEN" + }, + { + "id": 27, + "fortune": "DE BLIKSEM SLAAT NOOIT TWEE KEER. JIJ WEL" + }, + { + "id": 28, + "fortune": "HET LOT BELOONT GEDULD. FACTUUR VOLGT" + }, + { + "id": 29, + "fortune": "DE MAAN ZAG JE NIEUWE START. ALWEER EEN" + }, + { + "id": 30, + "fortune": "JE ENGEL WAAKT. HIJ MAAKT NOTITIES" + }, + { + "id": 31, + "fortune": "GELOOF EN JE ONTVANGT. LEVERING WISSELT" + }, + { + "id": 32, + "fortune": "JE GOUDEN TIJDPERK KOMT. VERGULD DAN" + }, + { + "id": 33, + "fortune": "WAT VOOR JOU IS KOMT. ZONDER ENIGE HAAST" + }, + { + "id": 34, + "fortune": "HET HEELAL KNIPOOGDE. OF HET HAD EEN TIC" + }, + { + "id": 35, + "fortune": "JE GELUK GAAT KEREN. RICHTING ONBEKEND" + }, + { + "id": 36, + "fortune": "DE VOORZIENIGHEID ZORGT. ZE CHECKT DE BONNEN" + }, + { + "id": 37, + "fortune": "DOE EEN WENS. DE STER ZET HEM OP SPAM" + }, + { + "id": 38, + "fortune": "ALLES KOMT OP ZIJN TIJD. DE JOUWE TREUZELT" + }, + { + "id": 39, + "fortune": "DE TEKENS WAREN ER. LEZEN IS OPTIONEEL" + }, + { + "id": 40, + "fortune": "JE BENT UNIEK. NET ALS IEDEREEN" + }, + { + "id": 41, + "fortune": "HET BESTE MOET NOG KOMEN. GEEN ENKELE HAAST" + }, + { + "id": 42, + "fortune": "JE AURA STRAALT. HIJ MAAKT OVERUREN" + }, + { + "id": 43, + "fortune": "HET GELUK LACHTE. BELEEFD. VAN VERRE" + }, + { + "id": 44, + "fortune": "JE ENGEL VROEG OM OVERPLAATSING" + }, + { + "id": 45, + "fortune": "HET LOT DEELT DE KAARTEN. JIJ VERLIEST ZE" + }, + { + "id": 46, + "fortune": "EEN VOORTEKEN VERSCHIJNT. HET SCHOKSCHOUDERT" + }, + { + "id": 47, + "fortune": "SUCCES IS NABIJ. NET ALS DE SLUIMERKNOP" + }, + { + "id": 48, + "fortune": "WERK LOONT ALTIJD. IN ERVARING" + }, + { + "id": 49, + "fortune": "JE POTENTIEEL IS ENORM. EN ONGEBRUIKT" + }, + { + "id": 50, + "fortune": "MIK OP DE MAAN. PAS OP HET PLAFOND" + }, + { + "id": 51, + "fortune": "DE VROEGE VOGEL KREEG DE WORM. JIJ SLIEP" + }, + { + "id": 52, + "fortune": "JE GROTE KANS KOMT. BREEK HEM NIET" + }, + { + "id": 53, + "fortune": "ROME WERD NIET IN EEN DAG GEBOUWD. JIJ NIET" + }, + { + "id": 54, + "fortune": "JE TALENTEN WORDEN GEVONDEN. MET EEN BEVEL" + }, + { + "id": 55, + "fortune": "WINNAARS STOPPEN NOOIT. JIJ ZWEEFT" + }, + { + "id": 56, + "fortune": "JE IDEEEN LOPEN VOOR. JE DEADLINES ACHTER" + }, + { + "id": 57, + "fortune": "KWALITEIT IS EEN GEWOONTE. DE JOUWE OOK" + }, + { + "id": 58, + "fortune": "JE WERK SPREEKT VOOR ZICH. HEEL ZACHTJES" + }, + { + "id": 59, + "fortune": "DE TOP IS EENZAAM. PROBLEEM OPGELOST" + }, + { + "id": 60, + "fortune": "EEN PROMOTIE KOMT. DIE VAN EEN COLLEGA" + }, + { + "id": 61, + "fortune": "JE CV IMPONEERT. DE LIEFHEBBERS VAN FICTIE" + }, + { + "id": 62, + "fortune": "JE BESTE WERK KOMT NOG. HET RENT SNEL" + }, + { + "id": 63, + "fortune": "DIE VERGADERING KON EEN MAIL ZIJN" + }, + { + "id": 64, + "fortune": "JE INBOX IS GEEN VIJAND. SLECHTS GETUIGE" + }, + { + "id": 65, + "fortune": "DEADLINES MAKEN JE NIET BANG. JE NEGEERT ZE" + }, + { + "id": 66, + "fortune": "JE VIJFJARENPLAN IS VIJF JAAR OUD" + }, + { + "id": 67, + "fortune": "LANGZAAM MAAR ZEKER WINT. JE HEBT LANGZAAM" + }, + { + "id": 68, + "fortune": "JE AGENDA IS VOL. MET MARGES" + }, + { + "id": 69, + "fortune": "JE TEAM DROOMT OOK. VAN OVERPLAATSING" + }, + { + "id": 70, + "fortune": "DE KANS DAALDE TOT JOUW NIVEAU" + }, + { + "id": 71, + "fortune": "SUCCES LAAT SPOREN NA. JIJ HOUDT VAN RAADSELS" + }, + { + "id": 72, + "fortune": "JE COMFORTZONE VERDIENT EEN POSTCODE" + }, + { + "id": 73, + "fortune": "KWALITEIT OF KWANTITEIT. JE WEIGERT BEIDE" + }, + { + "id": 74, + "fortune": "JE INSTINCT IS SCHERP. EN VAAK FOUT" + }, + { + "id": 75, + "fortune": "JE WERKT GOED ONDER DRUK. ZE IS HET ONEENS" + }, + { + "id": 76, + "fortune": "MEESTERSCHAP VRAAGT 10000 UUR. JIJ HEBT 40" + }, + { + "id": 77, + "fortune": "JE PLANT GELOOFDE IN JOU. EN IN WATER" + }, + { + "id": 78, + "fortune": "DE PRINTER RUIKT JE HAAST. DAAROM HAPERT HIJ" + }, + { + "id": 79, + "fortune": "JE ERFENIS IS IN AANBOUW. NOG STEEDS" + }, + { + "id": 80, + "fortune": "EEN DIPLOMA WACHT. DAT VAN DEELNAME" + }, + { + "id": 81, + "fortune": "NETWERKEN OPENT DEUREN. KLOPPEN OOK" + }, + { + "id": 82, + "fortune": "JIJ GEEFT HET VOORBEELD. HR WIL EEN ANDER" + }, + { + "id": 83, + "fortune": "JE ZIJPROJECT RUST UIT MET DE REST" + }, + { + "id": 84, + "fortune": "GENIE IS EEN PROCENT ZWEET. DAAR STOP JE" + }, + { + "id": 85, + "fortune": "JE AFWEZIGHEIDSBERICHT IS JE MEESTERWERK" + }, + { + "id": 86, + "fortune": "FALEN IS EEN TREDE. MOOIE TRAP" + }, + { + "id": 87, + "fortune": "JE BENT ONVERVANGBAAR. DE VACATURE IS ER AL" + }, + { + "id": 88, + "fortune": "JE JAARGESPREK KOMT. OEFEN GOED" + }, + { + "id": 89, + "fortune": "EFFICIENTIE IS JE TWEEDE NAAM. OP PAPIER" + }, + { + "id": 90, + "fortune": "JE LANDT OP JE VOETEN. LANDING VERTRAAGD" + }, + { + "id": 91, + "fortune": "DE TOP IS DICHTBIJ. HET BASISKAMP OOK" + }, + { + "id": 92, + "fortune": "JE AMBITIE ONTWAAKTE. JE WEKKER NIET" + }, + { + "id": 93, + "fortune": "WEES JEZELF. DE REST MAAKTE ZICH ZORGEN" + }, + { + "id": 94, + "fortune": "JE VERGADERING GING GOED. HIJ IS VOORBIJ" + }, + { + "id": 95, + "fortune": "RUSTEN IS GEZOND. JE OEFENT VEEL" + }, + { + "id": 96, + "fortune": "JE DIEET BEGINT MAANDAG. MAANDAGEN VLUCHTEN" + }, + { + "id": 97, + "fortune": "JE VERDIENT DIT. HAAL DIEP ADEM" + }, + { + "id": 98, + "fortune": "EEN VREEMDE LACHT NAAR JE. BLIJF KALM" + }, + { + "id": 99, + "fortune": "JE KOESTERT GEEN WROK. JE ARCHIVEERT HEM" + }, + { + "id": 100, + "fortune": "JE GEDULD HEEFT EEN BALK. VASTGELOPEN" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_pt.json b/apps/sarcastic-fortune-cookies/fortunes_pt.json new file mode 100644 index 0000000..7f6932c --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_pt.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "TUDO ACONTECE POR UM MOTIVO. QUASE SEMPRE MAU" + }, + { + "id": 2, + "fortune": "A SORTE VEM A CAMINHO. ANDA DEVAGAR" + }, + { + "id": 3, + "fortune": "O UNIVERSO TEM UM PLANO. UM PEQUENO" + }, + { + "id": 4, + "fortune": "O TEU DESTINO LIGOU. VAI REMARCAR" + }, + { + "id": 5, + "fortune": "AS ESTRELAS ALINHARAM. DEPOIS VIRAM TE" + }, + { + "id": 6, + "fortune": "O TEU NAVIO CHEGA. UMA CANOA" + }, + { + "id": 7, + "fortune": "CONFIA NO PROCESSO. ELE DUVIDA DE TI" + }, + { + "id": 8, + "fortune": "UM SINAL CHEGA. DIZ D PASSAGEM" + }, + { + "id": 9, + "fortune": "A TUA ESTRELA EXISTE. NOUTRA GALXIA" + }, + { + "id": 10, + "fortune": "O KARMA REAL. ISSO EXPLICA MUITO" + }, + { + "id": 11, + "fortune": "O TEU FUTURO BRILHANTE. LEVA PROTETOR" + }, + { + "id": 12, + "fortune": "O DESTINO ESPERA. FOI LER UM LIVRO" + }, + { + "id": 13, + "fortune": "OS MILAGRES ACONTECEM. NOUTRO LUGAR" + }, + { + "id": 14, + "fortune": "O TEU MOMENTO CHEGA. EST NO TRNSITO" + }, + { + "id": 15, + "fortune": "A SORTE BATEU. TU TINHAS SADO" + }, + { + "id": 16, + "fortune": "A MAR VIRA. VELOCIDADE DE UM GLACIAR" + }, + { + "id": 17, + "fortune": "GRANDES COISAS VM. BAIXA AS EXPETATIVAS" + }, + { + "id": 18, + "fortune": "AS OPORTUNIDADES ESTO A. FALHAM SE SEMPRE" + }, + { + "id": 19, + "fortune": "O COSMOS OUVE TE. ENTRA NA FILA" + }, + { + "id": 20, + "fortune": "AS TUAS PRECES FORAM OUVIDAS. E ARQUIVADAS" + }, + { + "id": 21, + "fortune": "A ABUNDNCIA FLUI PARA TI. RIO ACIMA" + }, + { + "id": 22, + "fortune": "A RODA GIRA. TU S O HAMSTER" + }, + { + "id": 23, + "fortune": "CADA NUVEM TEM UM LADO BOM. O TEU PINGA" + }, + { + "id": 24, + "fortune": "O ACASO PERGUNTA POR TI. POR CURIOSIDADE" + }, + { + "id": 25, + "fortune": "OS PRESSGIOS FALAM. MAIS SUSPIRAM" + }, + { + "id": 26, + "fortune": "O TEU HORSCOPO BOM. E FICTCIO" + }, + { + "id": 27, + "fortune": "O RAIO NO CAI DUAS VEZES. TU CAIS" + }, + { + "id": 28, + "fortune": "O DESTINO PREMEIA A PACINCIA. FATURA DEPOIS" + }, + { + "id": 29, + "fortune": "A LUA VIU O TEU RECOMEO. MAIS UM" + }, + { + "id": 30, + "fortune": "O TEU ANJO VIGIA. VAI TOMANDO NOTAS" + }, + { + "id": 31, + "fortune": "CR E RECEBERS. A ENTREGA VARIA" + }, + { + "id": 32, + "fortune": "A TUA ERA DOURADA CHEGA. BANHADA A OURO" + }, + { + "id": 33, + "fortune": "O QUE TEU CHEGA. SEM PRESSA NENHUMA" + }, + { + "id": 34, + "fortune": "O COSMOS PISCOU TE O OLHO. OU FOI UM TIQUE" + }, + { + "id": 35, + "fortune": "A TUA SORTE VAI MUDAR. RUMO INCERTO" + }, + { + "id": 36, + "fortune": "A PROVIDNCIA PROV. CONFERE OS RECIBOS" + }, + { + "id": 37, + "fortune": "FAZ UM PEDIDO. A ESTRELA MANDA PARA SPAM" + }, + { + "id": 38, + "fortune": "TUDO VEM A TEMPO. O TEU DEMORA" + }, + { + "id": 39, + "fortune": "OS SINAIS ESTAVAM L. LER OPCIONAL" + }, + { + "id": 40, + "fortune": "S NICO. COMO TODA A GENTE" + }, + { + "id": 41, + "fortune": "O MELHOR EST PARA VIR. NO TEM PRESSA" + }, + { + "id": 42, + "fortune": "A TUA AURA BRILHA. FAZ HORAS EXTRA" + }, + { + "id": 43, + "fortune": "A SORTE SORRIU TE. CORTS. DE LONGE" + }, + { + "id": 44, + "fortune": "O TEU ANJO PEDIU TRANSFERNCIA" + }, + { + "id": 45, + "fortune": "O DESTINO D AS CARTAS. TU PERDE LAS" + }, + { + "id": 46, + "fortune": "UM PRESSGIO SURGE. ENCOLHE OS OMBROS" + }, + { + "id": 47, + "fortune": "O SUCESSO EST PERTO. E O BOTO DE ADIAR" + }, + { + "id": 48, + "fortune": "O TRABALHO COMPENSA SEMPRE. EM EXPERINCIA" + }, + { + "id": 49, + "fortune": "O TEU POTENCIAL IMENSO. E POR USAR" + }, + { + "id": 50, + "fortune": "APONTA LUA. CUIDADO COM O TETO" + }, + { + "id": 51, + "fortune": "DEUS AJUDA QUEM CEDO MADRUGA. TU DORMIAS" + }, + { + "id": 52, + "fortune": "A TUA GRANDE CHANCE CHEGA. NO A PARTAS" + }, + { + "id": 53, + "fortune": "ROMA NO SE FEZ NUM DIA. A TUA TAMBM NO" + }, + { + "id": 54, + "fortune": "OS TEUS TALENTOS SERO ACHADOS. COM MANDADO" + }, + { + "id": 55, + "fortune": "QUEM VENCE NO DESISTE. TU FLUTUAS" + }, + { + "id": 56, + "fortune": "AS TUAS IDEIAS VO FRENTE. OS PRAZOS ATRS" + }, + { + "id": 57, + "fortune": "A QUALIDADE UM HBITO. O TEU TAMBM" + }, + { + "id": 58, + "fortune": "O TEU TRABALHO FALA POR SI. BAIXINHO" + }, + { + "id": 59, + "fortune": "O TOPO SOLITRIO. PROBLEMA RESOLVIDO" + }, + { + "id": 60, + "fortune": "UMA PROMOO CHEGA. A DE UM COLEGA" + }, + { + "id": 61, + "fortune": "O TEU CV IMPRESSIONA. OS FS DE FICO" + }, + { + "id": 62, + "fortune": "O TEU MELHOR TRABALHO VEM. CORRE DEPRESSA" + }, + { + "id": 63, + "fortune": "AQUELA REUNIO PODIA SER UM EMAIL" + }, + { + "id": 64, + "fortune": "A TUA CAIXA NO INIMIGA. S TESTEMUNHA" + }, + { + "id": 65, + "fortune": "OS PRAZOS NO TE ASSUSTAM. TU IGNORA LOS" + }, + { + "id": 66, + "fortune": "O TEU PLANO A CINCO ANOS TEM CINCO ANOS" + }, + { + "id": 67, + "fortune": "DEVAGAR MAS SEGURO GANHA. DOMINAS O DEVAGAR" + }, + { + "id": 68, + "fortune": "A TUA AGENDA EST CHEIA. DE MARGENS" + }, + { + "id": 69, + "fortune": "A TUA EQUIPA TAMBM SONHA. COM A SADA" + }, + { + "id": 70, + "fortune": "A OCASIO DESCEU AO TEU NVEL" + }, + { + "id": 71, + "fortune": "O SUCESSO DEIXA PISTAS. TU PREFERES MISTRIO" + }, + { + "id": 72, + "fortune": "A TUA ZONA DE CONFORTO TEM CDIGO POSTAL" + }, + { + "id": 73, + "fortune": "QUALIDADE OU QUANTIDADE. RECUSAS AMBAS" + }, + { + "id": 74, + "fortune": "O TEU INSTINTO AFIADO. E COSTUMA FALHAR" + }, + { + "id": 75, + "fortune": "TRABALHAS BEM SOB PRESSO. ELA DISCORDA" + }, + { + "id": 76, + "fortune": "A MESTRIA PEDE 10000 HORAS. TU TENS 40" + }, + { + "id": 77, + "fortune": "A TUA PLANTA CREU EM TI. E NA GUA" + }, + { + "id": 78, + "fortune": "A IMPRESSORA SENTE A PRESSA. POR ISSO FALHA" + }, + { + "id": 79, + "fortune": "O TEU LEGADO EST EM OBRAS. AINDA" + }, + { + "id": 80, + "fortune": "UM DIPLOMA ESPERA TE. O DE PRESENA" + }, + { + "id": 81, + "fortune": "FAZER REDE ABRE PORTAS. BATER TAMBM" + }, + { + "id": 82, + "fortune": "DS O EXEMPLO. OS RH QUEREM OUTRO" + }, + { + "id": 83, + "fortune": "O TEU PROJETO PESSOAL DESCANSA COM OS OUTROS" + }, + { + "id": 84, + "fortune": "O GNIO UM POR CENTO SUOR. PARAS A" + }, + { + "id": 85, + "fortune": "A TUA MENSAGEM DE AUSNCIA UMA OBRA PRIMA" + }, + { + "id": 86, + "fortune": "FALHAR UM DEGRAU. BELA ESCADARIA" + }, + { + "id": 87, + "fortune": "S INSUBSTITUVEL. O ANNCIO J SAIU" + }, + { + "id": 88, + "fortune": "A TUA AVALIAO ANUAL CHEGA. ENSAIA BEM" + }, + { + "id": 89, + "fortune": "EFICINCIA O TEU NOME DO MEIO. NO PAPEL" + }, + { + "id": 90, + "fortune": "CAIS DE P. A ATERRAGEM EST ATRASADA" + }, + { + "id": 91, + "fortune": "O CUME EST PERTO. O ACAMPAMENTO TAMBM" + }, + { + "id": 92, + "fortune": "A TUA AMBIO ACORDOU. O DESPERTADOR NO" + }, + { + "id": 93, + "fortune": "S TU MESMO. OS OUTROS FICARAM PREOCUPADOS" + }, + { + "id": 94, + "fortune": "A TUA REUNIO CORREU BEM. J ACABOU" + }, + { + "id": 95, + "fortune": "DESCANSAR FAZ BEM. PRATICAS IMENSO" + }, + { + "id": 96, + "fortune": "A TUA DIETA COMEA SEGUNDA. AS SEGUNDAS FOGEM" + }, + { + "id": 97, + "fortune": "TU MERECES ISTO. RESPIRA FUNDO" + }, + { + "id": 98, + "fortune": "UM ESTRANHO SORRI PARA TI. MANTM A CALMA" + }, + { + "id": 99, + "fortune": "NO GUARDAS RANCOR. TU ARQUIVA LO" + }, + { + "id": 100, + "fortune": "A TUA PACINCIA TEM UMA BARRA. TRAVADA" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/fortunes_sv.json b/apps/sarcastic-fortune-cookies/fortunes_sv.json new file mode 100644 index 0000000..880a23d --- /dev/null +++ b/apps/sarcastic-fortune-cookies/fortunes_sv.json @@ -0,0 +1,402 @@ +[ + { + "id": 1, + "fortune": "ALLT HNDER AV EN ANLEDNING. OFTAST EN DLIG" + }, + { + "id": 2, + "fortune": "LYCKAN R P VG. DEN GR LNGSAMT" + }, + { + "id": 3, + "fortune": "UNIVERSUM HAR EN PLAN. EN LITEN" + }, + { + "id": 4, + "fortune": "DITT DE RINGDE. DET BOKAR OM" + }, + { + "id": 5, + "fortune": "STJRNORNA STOD RTT. SEN SG DE DIG" + }, + { + "id": 6, + "fortune": "DITT SKEPP KOMMER IN. DET R EN KANOT" + }, + { + "id": 7, + "fortune": "LITA P PROCESSEN. DEN TVIVLAR P DIG" + }, + { + "id": 8, + "fortune": "ETT TECKEN KOMMER. DET SGER LMNA FRETRDE" + }, + { + "id": 9, + "fortune": "DIN STJRNA FINNS. I EN ANNAN GALAX" + }, + { + "id": 10, + "fortune": "KARMA R P RIKTIGT. DET FRKLARAR MYCKET" + }, + { + "id": 11, + "fortune": "DIN FRAMTID R LJUS. TA SOLKRM" + }, + { + "id": 12, + "fortune": "DET VNTAR. DET BRJADE LSA" + }, + { + "id": 13, + "fortune": "MIRAKEL SKER VARJE DAG. FAST NGON ANNANSTANS" + }, + { + "id": 14, + "fortune": "DITT GONBLICK KOMMER. DET SITTER I KN" + }, + { + "id": 15, + "fortune": "LYCKAN KNACKADE. DU VAR UTE" + }, + { + "id": 16, + "fortune": "TIDVATTNET VNDER. I GLACIRFART" + }, + { + "id": 17, + "fortune": "STORA SAKER KOMMER. SNK RIBBAN" + }, + { + "id": 18, + "fortune": "CHANSERNA FINNS. NI MISSAR ALLTID VARANN" + }, + { + "id": 19, + "fortune": "UNIVERSUM HR DIG. STLL DIG I KN" + }, + { + "id": 20, + "fortune": "DINA BNER HRDES. OCH ARKIVERADES" + }, + { + "id": 21, + "fortune": "VERFLDET FLDAR TILL DIG. UPPFR STRMMEN" + }, + { + "id": 22, + "fortune": "HJULET SNURRAR. DU R HAMSTERN" + }, + { + "id": 23, + "fortune": "VARJE MOLN HAR EN KANT. DIN DROPPAR" + }, + { + "id": 24, + "fortune": "SLUMPEN FRGAR EFTER DIG. AV NYFIKENHET" + }, + { + "id": 25, + "fortune": "FRTECKNEN TALAR. MEST SUCKAR DE" + }, + { + "id": 26, + "fortune": "DITT HOROSKOP R FINT. OCH PHITTAT" + }, + { + "id": 27, + "fortune": "BLIXTEN SLR ALDRIG TV GNGER. DU GR DET" + }, + { + "id": 28, + "fortune": "DET BELNAR TLAMOD. FAKTURA KOMMER" + }, + { + "id": 29, + "fortune": "MNEN SG DIN NYSTART. NNU EN" + }, + { + "id": 30, + "fortune": "DIN NGEL VAKAR. DEN FR ANTECKNINGAR" + }, + { + "id": 31, + "fortune": "TRO S FR DU. LEVERANS VARIERAR" + }, + { + "id": 32, + "fortune": "DIN GULDLDER KOMMER. FRGYLLD D" + }, + { + "id": 33, + "fortune": "DET SOM R DITT KOMMER. UTAN NGON BRDSKA" + }, + { + "id": 34, + "fortune": "UNIVERSUM BLINKADE. ELLER FICK NT I GAT" + }, + { + "id": 35, + "fortune": "DIN TUR VNDER. RIKTNING OKND" + }, + { + "id": 36, + "fortune": "FRSYNEN SRJER. DEN KOLLAR KVITTONA" + }, + { + "id": 37, + "fortune": "NSKA DIG NT. STJRNAN SPAMMAR DET" + }, + { + "id": 38, + "fortune": "ALLT KOMMER I TID. DITT DRJER" + }, + { + "id": 39, + "fortune": "TECKNEN FANNS DR. ATT LSA R FRIVILLIGT" + }, + { + "id": 40, + "fortune": "DU R UNIK. PRECIS SOM ALLA ANDRA" + }, + { + "id": 41, + "fortune": "DET BSTA KOMMER SEN. DET HAR INGEN BRDSKA" + }, + { + "id": 42, + "fortune": "DIN AURA LYSER. DEN JOBBAR VERTID" + }, + { + "id": 43, + "fortune": "LYCKAN LOG. ARTIGT. P AVSTND" + }, + { + "id": 44, + "fortune": "DIN NGEL BAD OM FRFLYTTNING" + }, + { + "id": 45, + "fortune": "DET GER KORTEN. DU TAPPAR DEM" + }, + { + "id": 46, + "fortune": "ETT OMEN DYKER UPP. DET RYCKER P AXLARNA" + }, + { + "id": 47, + "fortune": "FRAMGNG R NRA. OCH SNOOZE KNAPPEN" + }, + { + "id": 48, + "fortune": "ARBETE LNAR SIG. I ERFARENHET" + }, + { + "id": 49, + "fortune": "DIN POTENTIAL R STOR. OCH OANVND" + }, + { + "id": 50, + "fortune": "SIKTA P MNEN. AKTA TAKET" + }, + { + "id": 51, + "fortune": "TIDIG FGEL FICK MASKEN. DU SOV" + }, + { + "id": 52, + "fortune": "DIN STORA CHANS KOMMER. TAPPA DEN INTE" + }, + { + "id": 53, + "fortune": "ROM BYGGDES INTE P EN DAG. INTE DU HELLER" + }, + { + "id": 54, + "fortune": "DINA TALANGER HITTAS. MED EN ORDER" + }, + { + "id": 55, + "fortune": "VINNARE GER ALDRIG UPP. DU FLYTER" + }, + { + "id": 56, + "fortune": "DINA IDER LIGGER FRE. DINA DEADLINES EFTER" + }, + { + "id": 57, + "fortune": "KVALITET R EN VANA. DIN OCKS" + }, + { + "id": 58, + "fortune": "DITT ARBETE TALAR FR SIG. VLDIGT TYST" + }, + { + "id": 59, + "fortune": "TOPPEN R ENSAM. PROBLEM LST" + }, + { + "id": 60, + "fortune": "EN BEFORDRAN KOMMER. NGON ANNANS" + }, + { + "id": 61, + "fortune": "DITT CV IMPONERAR. P FANTASY FANSEN" + }, + { + "id": 62, + "fortune": "DITT BSTA JOBB KOMMER. DET SPRINGER FORT" + }, + { + "id": 63, + "fortune": "DET MTET KUNDE VARIT ETT MAIL" + }, + { + "id": 64, + "fortune": "DIN INKORG R INTE FIENDEN. BARA ETT VITTNE" + }, + { + "id": 65, + "fortune": "DEADLINES SKRMMER DIG INTE. DU STRUNTAR" + }, + { + "id": 66, + "fortune": "DIN FEMRSPLAN R FEM R GAMMAL" + }, + { + "id": 67, + "fortune": "LNGSAMT MEN SKERT VINNER. DU HAR LNGSAMT" + }, + { + "id": 68, + "fortune": "DIN KALENDER R FULL. AV MARGINALER" + }, + { + "id": 69, + "fortune": "DITT LAG DRMMER OCKS. OM FRFLYTTNING" + }, + { + "id": 70, + "fortune": "CHANSEN SNKTE SIG TILL DIN NIV" + }, + { + "id": 71, + "fortune": "FRAMGNG LMNAR SPR. DU GILLAR GTOR" + }, + { + "id": 72, + "fortune": "DIN KOMFORTZON FRTJNAR ETT POSTNUMMER" + }, + { + "id": 73, + "fortune": "KVALITET ELLER KVANTITET. DU NEKAR BDA" + }, + { + "id": 74, + "fortune": "DIN INSTINKT R VASS. OCH OFTA FEL" + }, + { + "id": 75, + "fortune": "DU JOBBAR BRA UNDER PRESS. DEN TVIVLAR" + }, + { + "id": 76, + "fortune": "MSTERSKAP KRVER 10000 TIMMAR. DU HAR 40" + }, + { + "id": 77, + "fortune": "DIN VXT TRODDE P DIG. OCH P VATTEN" + }, + { + "id": 78, + "fortune": "SKRIVAREN KNNER DIN STRESS. DEN KRNGLAR" + }, + { + "id": 79, + "fortune": "DITT ARV R UNDER BYGGE. FORTFARANDE" + }, + { + "id": 80, + "fortune": "ETT DIPLOM VNTAR. DELTAGARDIPLOMET" + }, + { + "id": 81, + "fortune": "ATT NTVERKA PPNAR DRRAR. KNACKA OCKS" + }, + { + "id": 82, + "fortune": "DU FREGR MED EXEMPEL. HR VILL HA ETT ANNAT" + }, + { + "id": 83, + "fortune": "DITT SIDOPROJEKT VILAR MED DE ANDRA" + }, + { + "id": 84, + "fortune": "GENI R EN PROCENT SVETT. DR STANNAR DU" + }, + { + "id": 85, + "fortune": "DITT FRNVAROSVAR R DITT MSTERVERK" + }, + { + "id": 86, + "fortune": "ATT MISSLYCKAS R ETT STEG. FIN TRAPPA" + }, + { + "id": 87, + "fortune": "DU R OERSTTLIG. ANNONSEN R REDAN KLAR" + }, + { + "id": 88, + "fortune": "DITT UTVECKLINGSSAMTAL KOMMER. VA NOGA" + }, + { + "id": 89, + "fortune": "EFFEKTIVITET R DITT MELLANNAMN. P PAPPER" + }, + { + "id": 90, + "fortune": "DU LANDAR P FTTERNA. LANDNINGEN DRJER" + }, + { + "id": 91, + "fortune": "TOPPEN R NRA. BASLGRET OCKS" + }, + { + "id": 92, + "fortune": "DIN AMBITION VAKNADE. INTE DIN VCKARKLOCKA" + }, + { + "id": 93, + "fortune": "VAR DIG SJLV. DE ANDRA BLEV OROLIGA" + }, + { + "id": 94, + "fortune": "DITT MTE GICK BRA. DET R SLUT" + }, + { + "id": 95, + "fortune": "ATT VILA R SUNT. DU VAR MYCKET" + }, + { + "id": 96, + "fortune": "DIN DIET BRJAR P MNDAG. MNDAGAR FLYR" + }, + { + "id": 97, + "fortune": "DU FRTJNAR DETTA. ANDAS DJUPT" + }, + { + "id": 98, + "fortune": "EN FRMLING LER MOT DIG. HLL DIG LUGN" + }, + { + "id": 99, + "fortune": "DU BR INTE AGG. DU ARKIVERAR DET" + }, + { + "id": 100, + "fortune": "DITT TLAMOD HAR EN LADDNINGSSTAPEL. FAST" + } +] \ No newline at end of file diff --git a/apps/sarcastic-fortune-cookies/manifest.json b/apps/sarcastic-fortune-cookies/manifest.json new file mode 100644 index 0000000..8816055 --- /dev/null +++ b/apps/sarcastic-fortune-cookies/manifest.json @@ -0,0 +1,28 @@ +{ + "id": "sarcastic-fortune-cookies", + "name": "Sarcastic Fortune Cookies", + "icon": "🥠", + "description": "Cynical fortune-cookie wisdom", + "category": "entertainment", + "type": "functional", + "i18n": true, + "version": "1.0", + "refresh_interval": 15, + "loop_delay": 15, + "min_modules": 45, + "settings": [ + { + "key": "frequency", + "label": "Change fortune every", + "type": "select", + "default": "300", + "options": [ + { "value": "60", "label": "1 minute" }, + { "value": "300", "label": "5 minutes" }, + { "value": "600", "label": "10 minutes" }, + { "value": "1200", "label": "20 minutes" }, + { "value": "1800", "label": "30 minutes" } + ] + } + ] +} diff --git a/apps/sports/app.py b/apps/sports/app.py index b0f949d..4cb969d 100644 --- a/apps/sports/app.py +++ b/apps/sports/app.py @@ -20,7 +20,19 @@ 'ufc': {'path': 'mma/ufc', 'name': 'UFC'}, } -def fetch(settings, format_lines, get_rows, get_cols): +# The active Localizer for the current fetch (set below). Sports has helper functions, +# so a module-level localizer avoids threading it through every signature; the plugin +# runtime serializes fetches per app, so it's set once per render. +_LOC = None + + +def _t(s): + return _LOC.t(s, "sports") if _LOC is not None else s + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + global _LOC + _LOC = i18n import requests, logging game_filter = settings.get('sports_filter', 'all') @@ -42,9 +54,11 @@ def fetch(settings, format_lines, get_rows, get_cols): if not all_games: if any(settings.get(f'sports_{key}', '').strip() for key in LEAGUES): - filter_labels = {'all': 'ALL', 'live': 'LIVE', 'live+upcoming': 'LIVE/UPCOMING', 'live+final': 'LIVE/FINAL'} - return [format_lines("SPORTS", "NO GAMES", filter_labels.get(game_filter, 'FOUND'))] - return [format_lines("SPORTS", "NO TEAMS", "CONFIGURED")] + filter_labels = {'all': _t('ALL'), 'live': _t('LIVE'), + 'live+upcoming': f"{_t('LIVE')}/{_t('UPCOMING')}", + 'live+final': f"{_t('LIVE')}/{_t('FINAL')}"} + return [format_lines("SPORTS", _t("NO GAMES"), filter_labels.get(game_filter, _t('FOUND')))] + return [format_lines("SPORTS", _t("NO TEAMS"), _t("CONFIGURED"))] rows = get_rows() cols = get_cols() @@ -161,8 +175,8 @@ def _fetch_last_game(info, team_abbr, format_lines, get_cols, requests, game_fil a_score = as_.get('displayValue', str(as_)) if isinstance(as_, dict) else str(as_) h_score = hs_.get('displayValue', str(hs_)) if isinstance(hs_, dict) else str(hs_) score_line = f"{aa} {a_score} {ha} {h_score}" - page = format_lines(info['name'], score_line, "FINAL") - return {'page': page, 'score_line': score_line, 'status': 'FINAL', 'state': 'post'} + page = format_lines(info['name'], score_line, _t("FINAL")) + return {'page': page, 'score_line': score_line, 'status': _t("FINAL"), 'state': 'post'} return None except Exception as e: logging.error(f"Schedule fetch error for {team_abbr}: {e}") @@ -201,7 +215,7 @@ def _parse_events(events, info, team_filter, show_all, format_lines, get_cols, g score_line = f"{aa} VS {ha}" else: score_line = f"{aa} {away.get('score','0')} {ha} {home.get('score','0')}" - status = "FINAL" if state == 'post' else detail.upper()[:15] + status = _t("FINAL") if state == 'post' else detail.upper()[:15] page = format_lines(info['name'], score_line, status) game = {'page': page, 'score_line': score_line, 'status': status, 'state': state} (live if state == 'in' else upcoming if state == 'pre' else final).append(game) @@ -209,10 +223,10 @@ def _parse_events(events, info, team_filter, show_all, format_lines, get_cols, g def _golf(events, info, format_lines): if not events: - return [format_lines("PGA TOUR", "NO EVENT", "THIS WEEK")] + return [format_lines("PGA TOUR", _t("NO EVENT"), _t("THIS WEEK"))] comps = events[0].get('competitions', [{}]) if not comps: - return [format_lines("PGA TOUR", "NO DATA", "")] + return [format_lines("PGA TOUR", _t("NO DATA"), "")] competitors = comps[0].get('competitors', []) competitors.sort(key=lambda c: int(c.get('order', 999))) pages = [] @@ -225,11 +239,11 @@ def _golf(events, info, format_lines): lines.append(f"{c.get('order','?')} {name[:8]} {score}"[:15]) while len(lines) < 3: lines.append('') pages.append(format_lines(*lines)) - return pages or [format_lines("PGA TOUR", "NO LEADERS", "")] + return pages or [format_lines("PGA TOUR", _t("NO LEADERS"), "")] def _mma(events, info, format_lines): if not events: - return [format_lines("UFC", "NO EVENT", "SCHEDULED")] + return [format_lines("UFC", _t("NO EVENT"), _t("SCHEDULED"))] pages = [] for comp in events[0].get('competitions', [])[:5]: competitors = comp.get('competitors', []) @@ -238,9 +252,9 @@ def _mma(events, info, format_lines): n2 = competitors[1].get('athlete', {}).get('shortName', '?').upper()[:7] state = comp.get('status', {}).get('type', {}).get('state', 'pre') detail = comp.get('status', {}).get('type', {}).get('shortDetail', '') - r3 = detail.upper()[:15] if detail else ("LIVE" if state == 'in' else "UPCOMING") + r3 = detail.upper()[:15] if detail else (_t("LIVE") if state == 'in' else _t("UPCOMING")) pages.append(format_lines("UFC", f"{n1} V {n2}", r3)) - return pages or [format_lines("UFC", "NO FIGHTS", "SCHEDULED")] + return pages or [format_lines("UFC", _t("NO FIGHTS"), _t("SCHEDULED"))] def trigger(settings, conditions): diff --git a/apps/sports/manifest.json b/apps/sports/manifest.json index 7d04395..b2f5ecb 100644 --- a/apps/sports/manifest.json +++ b/apps/sports/manifest.json @@ -1,5 +1,6 @@ { "id": "sports", + "i18n": true, "name": "Sports", "icon": "🏒", "description": "Scores & Schedules", diff --git a/apps/stocks/app.py b/apps/stocks/app.py index 6995a4a..639a248 100644 --- a/apps/stocks/app.py +++ b/apps/stocks/app.py @@ -1,31 +1,61 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): import yfinance as yf + + def t(s): + return i18n.t(s, "stocks") if i18n is not None else s + tickers = [s.strip() for s in settings.get('stocks_list', '').split(',') if s.strip()] if not tickers: - return [format_lines('STOCKS', 'NO TICKERS', 'CONFIGURE')] - currency = settings.get('currency_symbol', '$').strip() or '$' + return [format_lines('STOCKS', t('NO TICKERS'), t('CONFIGURE'))] + no_color = settings.get('disable_colors', 'no') == 'yes' rows = get_rows() + + # Each ticker is quoted in its exchange's own currency (AAPL->USD, VOD.L->GBP, + # SAP.DE->EUR); show that currency's symbol, not a single hardcoded one. + def sym_for(cur): + # With i18n the display can render € £ ¥ (Windows-1252); without it the modules + # are the basic charset, so use '$' for USD and the ASCII ISO code otherwise. + if i18n is not None: + return i18n.currency_symbol(cur) + return '$' if cur == 'USD' else cur + + # Numbers follow the global Language (1,234.50 vs 1.234,50 vs 1 234,50). + def n(v, d=2, grouping=True): + if i18n is not None: + return i18n.number(v, d, grouping) + return f'{v:,.{d}f}' if grouping else f'{v:.{d}f}' + + def pct(v): + return f"{'+' if v >= 0 else '-'}{n(abs(v), 1, grouping=False)}%" + pages = [] for i in range(0, len(tickers), rows): chunk = tickers[i:i+rows] price_lines, change_lines = [], [] for sym in chunk: try: - t = yf.Ticker(sym) - info = t.fast_info + info = yf.Ticker(sym).fast_info price = info['lastPrice'] prev = info['previousClose'] + try: + cur = (info['currency'] or 'USD') + except Exception: + cur = 'USD' + if cur in ('GBp', 'GBX'): # London quotes pence, not pounds + price, prev, cur = price / 100, prev / 100, 'GBP' chg = ((price - prev) / prev) * 100 - icon = '🟩' if chg >= 0 else '🟥' - price_lines.append(f'{sym} {currency}{price:.2f}') - change_lines.append(f'{sym} {icon}{chg:+.1f}%') + cs = sym_for(cur) + sep = '' if cs != cur else ' ' # 3-letter-code fallback reads better spaced + icon = '' if no_color else ('🟩' if chg >= 0 else '🟥') + price_lines.append(f'{sym} {cs}{sep}{n(price, 2)}') + change_lines.append(f'{sym} {icon}{pct(chg)}') except Exception: price_lines.append(f'{sym} ERR') change_lines.append(f'{sym} ERR') pad = [''] * (rows - len(chunk)) pages.append(format_lines(*(price_lines + pad))) pages.append(format_lines(*(change_lines + pad))) - return pages or [format_lines('STOCKS', 'NO DATA', '')] + return pages or [format_lines('STOCKS', t('NO DATA'), '')] def trigger(settings, conditions): diff --git a/apps/stocks/manifest.json b/apps/stocks/manifest.json index a5d6214..eb19d37 100644 --- a/apps/stocks/manifest.json +++ b/apps/stocks/manifest.json @@ -1,5 +1,6 @@ { "id": "stocks", + "i18n": true, "name": "Stocks", "icon": "📈", "description": "Live prices", diff --git a/apps/sun-times/app.py b/apps/sun-times/app.py new file mode 100644 index 0000000..0a31c41 --- /dev/null +++ b/apps/sun-times/app.py @@ -0,0 +1,74 @@ +"""Sunrise / sunset / day length for the configured location (keyless: Open-Meteo). + +Times track the location: Open-Meteo returns them in the place's own local time +(timezone=auto), just like the weather app — no separate timezone setting needed.""" + + +def _latlon(settings, requests): + """Global precise location, else geocode of the ZIP, else a Boston fallback.""" + lat = str(settings.get('location_lat', '') or '').strip() + lon = str(settings.get('location_lon', '') or '').strip() + if lat and lon: + try: + return float(lat), float(lon) + except ValueError: + pass + zip_code = str(settings.get('zip_code', '02118') or '02118').strip() + try: + import re + params = {'q': zip_code, 'format': 'json', 'limit': 1} + if re.fullmatch(r'\d{5}', zip_code): # a US ZIP — disambiguate (02118 also exists abroad) + params['countrycodes'] = 'us' + geo = requests.get('https://nominatim.openstreetmap.org/search', params=params, + headers={'User-Agent': 'SplitFlapGatewayCompanion/1.0'}, + timeout=6).json() + if geo: + return float(geo[0]['lat']), float(geo[0]['lon']) + except Exception: + pass + return 42.3601, -71.0589 + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + import requests + from datetime import datetime + rows, cols = get_rows(), get_cols() + + def t(s): + return i18n.t(s, "sun") if i18n is not None else s + + def u(k): # localized H/M duration suffix (Dutch U for uur, etc.) + return i18n.unit(k) if i18n is not None else k + + def line(label, value): # label trimmed to fit — never the time + return f'{label[:max(1, cols - len(value) - 1)]} {value}' + + def fmt_time(iso): # ISO is already the location's local time + if not iso: + return '--:--' + dt = datetime.fromisoformat(str(iso)) + # AM/PM is English-only — everyone else gets 24h. + if i18n is not None: + return i18n.time(dt, ampm_space=False) + return dt.strftime('%I:%M%p').lstrip('0') + + try: + lat, lon = _latlon(settings, requests) + data = requests.get('https://api.open-meteo.com/v1/forecast', + params={'latitude': lat, 'longitude': lon, + 'daily': 'sunrise,sunset,daylight_duration', + 'timezone': 'auto', 'forecast_days': 1}, + timeout=8).json() + daily = data.get('daily', {}) + rise = fmt_time((daily.get('sunrise') or [None])[0]) + sett = fmt_time((daily.get('sunset') or [None])[0]) + secs = int((daily.get('daylight_duration') or [0])[0] or 0) + length = f'{secs // 3600}{u("H")}{(secs % 3600) // 60:02d}{u("M")}' + if rows == 1: + return [format_lines(f'{t("UP")} {rise} {t("DN")} {sett}')] + if rows == 2: + return [format_lines(line(t('SUNRISE'), rise), line(t('SUNSET'), sett))] + return [format_lines(line(t('SUNRISE'), rise), line(t('SUNSET'), sett), + line(t('DAYLIGHT'), length))] + except Exception: + return [format_lines('SUN TIMES', 'OFFLINE', '')] diff --git a/apps/sun-times/manifest.json b/apps/sun-times/manifest.json new file mode 100644 index 0000000..2e465ea --- /dev/null +++ b/apps/sun-times/manifest.json @@ -0,0 +1,25 @@ +{ + "id": "sun-times", + "i18n": true, + "name": "Sun Times", + "icon": "☀️", + "description": "Sunrise, sunset & day length", + "type": "functional", + "refresh_interval": 1800, + "loop_delay": 6, + "category": "data", + "min_rows": 2, + "min_cols": 12, + "settings": [ + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/tides/app.py b/apps/tides/app.py new file mode 100644 index 0000000..97b268d --- /dev/null +++ b/apps/tides/app.py @@ -0,0 +1,52 @@ +"""Today's tide predictions for a NOAA station (keyless: NOAA CO-OPS).""" + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + import requests + from datetime import datetime + rows, cols = get_rows(), get_cols() + + def t(s): + return i18n.t(s, "tides") if i18n is not None else s + + def fmt_time(hhmm): # NOAA gives 24h local time ("15:48") + try: + dt = datetime.strptime(hhmm, '%H:%M') + except ValueError: + return hhmm + # AM/PM is English-only — everyone else gets 24h. + if i18n is not None: + return i18n.time(dt, ampm_space=False) + return dt.strftime('%I:%M%p').lstrip('0') + + station = str(settings.get('tide_station', '8443970') or '8443970').strip() + try: + data = requests.get( + 'https://api.tidesandcurrents.noaa.gov/api/prod/datagetter', + params={'product': 'predictions', 'application': 'SplitFlapCompanion', + 'datum': 'MLLW', 'station': station, 'time_zone': 'lst_ldt', + 'units': 'english', 'interval': 'hilo', 'format': 'json', 'date': 'today'}, + timeout=8).json() + preds = data.get('predictions') or [] + if not preds: + return [format_lines(t('TIDES'), t('NO DATA'), t('CHECK STATION'))] + pages = [] + for p in preds[:6]: + raw = str(p.get('t', '')) + hhmm = fmt_time(raw.split(' ')[-1] if ' ' in raw else raw) + is_high = p.get('type') == 'H' + v = str(p.get('v', '')) + if rows == 1: + # Compact single row: the short generic high/low word keeps the + # time + height on one line (the full "X TIDE" would crowd them out). + kind = t('HIGH') if is_high else t('LOW') + pages.append(f'{kind} {hhmm} {v}FT'[:cols].center(cols)) + elif rows == 2: + kind = t('HIGH TIDE') if is_high else t('LOW TIDE') + pages.append(format_lines(kind, f'{hhmm} {v}FT')) + else: + kind = t('HIGH TIDE') if is_high else t('LOW TIDE') + pages.append(format_lines(kind, hhmm, f'{v} FT')) + return pages or [format_lines(t('TIDES'), t('NO DATA'), '')] + except Exception: + return [format_lines(t('TIDES'), t('OFFLINE'), '')] diff --git a/apps/tides/manifest.json b/apps/tides/manifest.json new file mode 100644 index 0000000..f5994cd --- /dev/null +++ b/apps/tides/manifest.json @@ -0,0 +1,32 @@ +{ + "id": "tides", + "name": "Tides", + "icon": "🌊", + "description": "Today's high & low tides (NOAA)", + "type": "functional", + "i18n": true, + "refresh_interval": 3600, + "loop_delay": 6, + "category": "data", + "min_rows": 1, + "min_cols": 12, + "settings": [ + { + "key": "tide_station", + "label": "NOAA tide station ID", + "type": "text", + "default": "8443970", + "note": "Find yours at tidesandcurrents.noaa.gov (default is Boston, MA)." + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "6", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/time-since/app.py b/apps/time-since/app.py index 84a0dc4..4b8d4ab 100644 --- a/apps/time-since/app.py +++ b/apps/time-since/app.py @@ -1,6 +1,13 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): from datetime import datetime import pytz + + def t(s): + return i18n.t(s, "time") if i18n is not None else s + + def u(k): # localized Y/D/H/M/S suffix + return i18n.unit(k) if i18n is not None else k + tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) now = datetime.now(tz) event = settings.get('event_name', 'THE START').upper() @@ -9,20 +16,20 @@ def fetch(settings, format_lines, get_rows, get_cols): start = datetime.strptime(date_str, '%Y-%m-%d') start = tz.localize(start) except Exception: - return [format_lines(event, 'INVALID DATE', '')] + return [format_lines(event, t('INVALID DATE'), '')] diff = now - start if diff.total_seconds() < 0: - return [format_lines(event, 'NOT YET', 'STARTED')] + return [format_lines(event, t('NOT YET'), t('STARTED'))] days = diff.days hrs, rem = divmod(diff.seconds, 3600) mins, secs = divmod(rem, 60) years = days // 365 remaining_days = days % 365 if years > 0: - elapsed = f'{years}Y {remaining_days}D {hrs}H' + elapsed = f'{years}{u("Y")} {remaining_days}{u("D")} {hrs}{u("H")}' else: - elapsed = f'{days}D {hrs}H {mins}M {secs}S' - return [format_lines(event, elapsed, 'TIME SINCE')] + elapsed = f'{days}{u("D")} {hrs}{u("H")} {mins}{u("M")} {secs}{u("S")}' + return [format_lines(event, elapsed, t('TIME SINCE'))] def trigger(settings, conditions): diff --git a/apps/time-since/manifest.json b/apps/time-since/manifest.json index 3920a65..d10ec14 100644 --- a/apps/time-since/manifest.json +++ b/apps/time-since/manifest.json @@ -1,5 +1,6 @@ { "id": "time-since", + "i18n": true, "name": "Time Since", "icon": "⏱️", "description": "Track elapsed time", diff --git a/apps/time/app.py b/apps/time/app.py index 7375286..b9a5deb 100644 --- a/apps/time/app.py +++ b/apps/time/app.py @@ -1,10 +1,17 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): from datetime import datetime import pytz tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) now = datetime.now(tz) - fmt = "%H:%M" if settings.get('time_format') == '24hr' else "%I:%M%p" - time_str = now.strftime(fmt).lstrip("0") + # An explicit Time Format wins; otherwise the Language decides (12h AM/PM for + # English, 24h elsewhere) via the injected i18n helper. + tf = settings.get('time_format') + if tf in ('12hr', '24hr'): + time_str = now.strftime("%H:%M" if tf == '24hr' else "%I:%M%p").lstrip("0") + elif i18n is not None: + time_str = i18n.time(now, ampm_space=False) + else: + time_str = now.strftime("%I:%M%p").lstrip("0") rows = get_rows() if rows == 1: return [format_lines(time_str)] diff --git a/apps/time/manifest.json b/apps/time/manifest.json index 9878e16..49af419 100644 --- a/apps/time/manifest.json +++ b/apps/time/manifest.json @@ -1,5 +1,6 @@ { "id": "time", + "i18n": true, "name": "Time", "icon": "⏱️", "description": "Live clock", diff --git a/apps/useless-fact/app.py b/apps/useless-fact/app.py new file mode 100644 index 0000000..b573dbf --- /dev/null +++ b/apps/useless-fact/app.py @@ -0,0 +1,125 @@ +"""A random useless fact (keyless: uselessfacts).""" + + +def _need_lines(lens, cols): + need, cur = 1, 0 + for wl in lens: + add = wl if cur == 0 else cur + 1 + wl + if add <= cols: + cur = add + else: + need += 1 + cur = wl + return need + + +def _balance(words, lens, cols, k): + """Split words into exactly k lines (each <= cols) minimizing raggedness, so + lines fill evenly instead of orphaning the last word; prefers ending a line at + sentence punctuation. A tiny DP.""" + n = len(words) + pre = [0] + for wl in lens: + pre.append(pre[-1] + wl) + + def linelen(i, j): + return pre[j + 1] - pre[i] + (j - i) + + INF = float("inf") + dp = [[INF] * (n + 1) for _ in range(k + 1)] + nxt = [[0] * (n + 1) for _ in range(k + 1)] + dp[0][n] = 0.0 + for kk in range(1, k + 1): + for i in range(n - 1, -1, -1): + j = i + while j < n: + ll = linelen(i, j) + if ll > cols and j > i: + break + rest = dp[kk - 1][j + 1] + if rest < INF: + slack = cols - ll + cost = slack * slack + rest + if words[j][-1:] in ".!?": + cost -= cols + if cost < dp[kk][i]: + dp[kk][i] = cost + nxt[kk][i] = j + 1 + j += 1 + if dp[k][0] >= INF: + return None + out, i, kk = [], 0, k + while kk > 0: + j = nxt[kk][i] + out.append(" ".join(words[i:j])) + i, kk = j, kk - 1 + return out + + +def _greedy(words, cols): + lines, cur = [], '' + for w in words: + w = w if len(w) <= cols else w[:cols] + if len(cur) + len(w) + (1 if cur else 0) <= cols: + cur = f'{cur} {w}'.strip() + else: + lines.append(cur) + cur = w + if cur: + lines.append(cur) + return lines or [''] + + +def _pages(format_lines, title, text, rows, cols): + """Lay the text out under a title. When it fits on one page the words are + balanced evenly across the lines it needs; longer text word-wraps and + paginates.""" + words = text.split() or [''] + lens = [len(w) for w in words] + if rows == 1: + return [ln.center(cols)[:cols] for ln in _greedy(words, cols)] + body = rows - 1 + if max(lens) <= cols: + need = _need_lines(lens, cols) + if need <= body: + bal = _balance(words, lens, cols, need) + if bal is not None: + return [format_lines(title, *bal)] + lines = _greedy(words, cols) + pages = [format_lines(title, *lines[:body])] + i = body + while i < len(lines): + pages.append(format_lines(*lines[i:i + rows])) + i += rows + return pages + +def fetch(settings, format_lines, get_rows, get_cols): + import requests + rows, cols = get_rows(), get_cols() + try: + max_len = int(float(settings.get('max_length', '140') or 140)) + except (TypeError, ValueError): + max_len = 140 + max_len = max(40, min(280, max_len)) + + def one(): + d = requests.get('https://uselessfacts.jsph.pl/api/v2/facts/random', + params={'language': 'en'}, timeout=8).json() + return str(d.get('text', '') or '').strip() + + try: + # This API can't filter by length, so try a few times for a short one and + # keep the shortest we've seen if none come in under the limit. + best = None + for _ in range(3): + t = one() + if t and len(t) <= max_len: + best = t + break + if t and (best is None or len(t) < len(best)): + best = t + if not best: + return [format_lines('RANDOM FACT', 'NO DATA', '')] + return _pages(format_lines, 'DID YOU KNOW', best.upper(), rows, cols) + except Exception: + return [format_lines('RANDOM FACT', 'OFFLINE', '')] diff --git a/apps/useless-fact/manifest.json b/apps/useless-fact/manifest.json new file mode 100644 index 0000000..1f0ae3a --- /dev/null +++ b/apps/useless-fact/manifest.json @@ -0,0 +1,44 @@ +{ + "id": "useless-fact", + "name": "Random Fact", + "icon": "🤓", + "description": "A concise random fact", + "type": "functional", + "refresh_interval": 1800, + "loop_delay": 7, + "category": "entertainment", + "min_rows": 3, + "min_cols": 15, + "settings": [ + { + "key": "max_length", + "label": "Max fact length (characters)", + "type": "number", + "default": "140", + "min": "40", + "max": "280", + "step": "10", + "stepper": true + }, + { + "key": "refresh_minutes", + "label": "Fetch a new fact every (minutes)", + "type": "number", + "default": "30", + "min": "1", + "max": "1440", + "step": "1", + "stepper": true + }, + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "7", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/weather/app.py b/apps/weather/app.py index 233083d..d401239 100644 --- a/apps/weather/app.py +++ b/apps/weather/app.py @@ -172,7 +172,9 @@ def _format_temp(value, temp_unit): return f"{int(round(converted))}{temp_unit.upper()}" -def _compact_color(color): +def _compact_color(color, mono=False): + if mono: + return '' return { 'GREEN': '🟩', 'YELLOW': '🟨', @@ -183,9 +185,11 @@ def _compact_color(color): }.get(color, color) -def _decorate_status(label, color, cols): - swatch = _compact_color(color) +def _decorate_status(label, color, cols, mono=False): text = str(label or '').strip() + if mono: # colors disabled: show the label only + return text[:cols] + swatch = _compact_color(color) if not text: return swatch @@ -204,10 +208,20 @@ def _decorate_status(label, color, cols): return swatch -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): import time import requests + # Global Language (when the companion injects i18n). Open-Meteo maps codes to + # English text we translate ourselves; the keyed providers can return native + # condition text if we ask, so we pass the language through to them. + # Base language for the providers' `lang` param — they want 'en'/'fr', not a + # regional 'en-gb' (the English variants all return English weather text anyway). + lang = (i18n.lang.split('-')[0] if i18n is not None else 'en') + + def t(s): + return i18n.t(s, "weather") if i18n is not None else s + # --- Polling state (persists across calls on this plugin instance) --- state = getattr(fetch, '_state', None) if state is None: @@ -224,43 +238,51 @@ def fetch(settings, format_lines, get_rows, get_cols): temp_unit = str(settings.get('temperature_unit', 'f')).lower() if temp_unit not in ('f', 'c', 'k'): temp_unit = 'f' + no_color = settings.get('disable_colors', 'no') == 'yes' show_aqi = settings.get('show_aqi', 'yes') == 'yes' show_uv = settings.get('show_uv', 'yes') == 'yes' and weather_provider in ('openmeteo', 'weatherapi') show_pollen = settings.get('show_pollen', 'yes') == 'yes' and weather_provider in ('openmeteo', 'weatherapi') polling_seconds = max(30.0, min(86400.0, float(settings.get('polling_rate', 300) or 300))) openmeteo_air = None - # Resolve location: per-app override > global lat/lon > geocode zip_code + # Resolve location: per-app override > global lat/lon > geocode zip_code. + # Any bad input / geocode failure falls back to Boston instead of crashing. app_location = settings.get('location', '').strip() loc_lat = settings.get('location_lat', '') loc_lon = settings.get('location_lon', '') loc_name = settings.get('location_name', '') - if app_location and ',' in app_location: - if '|' in app_location: - coords, _city = app_location.split('|', 1) - _city = _city.strip().upper() - else: - coords = app_location - _city = 'LOCATION' - parts = coords.split(',', 1) - _lat, _lon = float(parts[0]), float(parts[1]) - elif loc_lat and loc_lon: - _lat, _lon = float(loc_lat), float(loc_lon) - _city = loc_name.split(',')[0].strip().upper() if loc_name else 'LOCATION' - else: - geo = requests.get( - f'https://nominatim.openstreetmap.org/search?q={zip_code}&format=json&limit=1', - timeout=5, headers={'User-Agent': 'SplitFlapOS/1.0'} - ).json() - if geo: - _lat, _lon = float(geo[0]['lat']), float(geo[0]['lon']) - _city = geo[0].get('display_name', zip_code).split(',')[0].strip().upper() + _lat, _lon, _city = 42.3496, -71.0783, 'BOSTON' + try: + if app_location and ',' in app_location: + if '|' in app_location: + coords, _city = app_location.split('|', 1) + _city = _city.strip().upper() + else: + coords = app_location + _city = 'LOCATION' + parts = coords.split(',', 1) + _lat, _lon = float(parts[0]), float(parts[1]) + elif loc_lat and loc_lon: + _lat, _lon = float(loc_lat), float(loc_lon) + _city = loc_name.split(',')[0].strip().upper() if loc_name else 'LOCATION' else: - _lat, _lon, _city = 42.3496, -71.0783, 'BOSTON' + import re + _geo_params = {'q': zip_code, 'format': 'json', 'limit': 1} + if re.fullmatch(r'\d{5}', str(zip_code).strip()): # US ZIP — 02118 also exists abroad + _geo_params['countrycodes'] = 'us' + geo = requests.get( + 'https://nominatim.openstreetmap.org/search', params=_geo_params, + timeout=5, headers={'User-Agent': 'SplitFlapGatewayCompanion/1.0'} + ).json() + if geo: + _lat, _lon = float(geo[0]['lat']), float(geo[0]['lon']) + _city = geo[0].get('display_name', zip_code).split(',')[0].strip().upper() + except (ValueError, KeyError, IndexError, TypeError, requests.RequestException): + _lat, _lon, _city = 42.3496, -71.0783, 'BOSTON' settings_sig = ( api_key, _lat, _lon, weather_provider, temp_unit, - show_aqi, show_uv, show_pollen, polling_seconds, + show_aqi, show_uv, show_pollen, polling_seconds, lang, ) now_ts = time.time() sig_changed = settings_sig != state['last_sig'] @@ -288,7 +310,7 @@ def _normalize_weatherapi_pollen(payload): def _fetch_openweather_weather(): payload = requests.get( 'https://api.openweathermap.org/data/2.5/weather', - params={'lat': _lat, 'lon': _lon, 'appid': api_key, 'units': 'imperial'}, + params={'lat': _lat, 'lon': _lon, 'appid': api_key, 'units': 'imperial', 'lang': lang}, timeout=10 ).json() return { @@ -326,7 +348,7 @@ def _fetch_openmeteo_weather(): 'feels_like': int(round(current.get('apparent_temperature', current.get('temperature_2m', 0)))), 'hi': int(round(hi_values[0] if hi_values else 0)), 'lo': int(round(lo_values[0] if lo_values else 0)), - 'desc': OPENMETEO_WEATHER_CODES.get(current.get('weather_code'), 'CURRENT CONDITIONS'), + 'desc': t(OPENMETEO_WEATHER_CODES.get(current.get('weather_code'), 'CURRENT CONDITIONS')), 'lat': _lat, 'lon': _lon, 'uv': current.get('uv_index'), @@ -341,6 +363,7 @@ def _fetch_weatherapi_weather(): 'days': 1, 'aqi': 'yes', 'pollen': 'yes', + 'lang': lang, }, timeout=10 ).json() @@ -355,7 +378,7 @@ def _fetch_weatherapi_weather(): 'feels_like': int(round(current.get('feelslike_f', current.get('temp_f', 0)))), 'hi': int(round(day.get('maxtemp_f', current.get('temp_f', 0)))), 'lo': int(round(day.get('mintemp_f', current.get('temp_f', 0)))), - 'desc': str((current.get('condition') or {}).get('text', 'CURRENT CONDITIONS')).upper(), + 'desc': str((current.get('condition') or {}).get('text', t('CURRENT CONDITIONS'))).upper(), 'lat': location.get('lat'), 'lon': location.get('lon'), 'uv': current.get('uv'), @@ -369,7 +392,7 @@ def _fetch_qweather_weather(): now_r = requests.get( 'https://devapi.qweather.com/v7/weather/now', - params={'location': location, 'lang': 'en', 'unit': 'i'}, + params={'location': location, 'lang': lang, 'unit': 'i'}, headers=headers, timeout=10 ).json() @@ -377,7 +400,7 @@ def _fetch_qweather_weather(): daily_r = requests.get( 'https://devapi.qweather.com/v7/weather/3d', - params={'location': location, 'lang': 'en', 'unit': 'i'}, + params={'location': location, 'lang': lang, 'unit': 'i'}, headers=headers, timeout=10 ).json() @@ -389,7 +412,7 @@ def _fetch_qweather_weather(): 'feels_like': _to_int(now.get('feelsLike'), _to_int(now.get('temp'))), 'hi': _to_int(first_day.get('tempMax'), _to_int(now.get('temp'))), 'lo': _to_int(first_day.get('tempMin'), _to_int(now.get('temp'))), - 'desc': str(now.get('text', 'CURRENT CONDITIONS')).upper(), + 'desc': str(now.get('text', t('CURRENT CONDITIONS'))).upper(), 'lat': _lat, 'lon': _lon, } @@ -442,14 +465,14 @@ def _get_openmeteo_air(lat, lon): cols = get_cols() narrow = cols <= 12 - feels_word = 'FLS' if narrow else 'FEELS' - pollen_word = 'POL' if narrow else 'POLLEN' - overall_word = 'OVR' if narrow else 'OVERALL' - provider_word = 'PRV' if narrow else 'PROV' - sun_exposure_text = 'SUN UV' if narrow else 'SUN EXPOSURE' - grass_word = 'GRS' if narrow else 'GRASS' - tree_word = 'TRE' if narrow else 'TREE' - weed_word = 'WED' if narrow else 'WEED' + feels_word = t('FLS') if narrow else t('FEELS') + pollen_word = t('POL') if narrow else t('POLLEN') + overall_word = t('OVR') if narrow else t('OVERALL') + provider_word = t('PRV') if narrow else t('PROV') + sun_exposure_text = t('SUN UV') if narrow else t('SUN EXPOSURE') + grass_word = t('GRS') if narrow else t('GRASS') + tree_word = t('TRE') if narrow else t('TREE') + weed_word = t('WED') if narrow else t('WEED') city = weather['city'] temp = _format_temp(weather.get('temp'), temp_unit) @@ -460,6 +483,8 @@ def _get_openmeteo_air(lat, lon): lat = weather['lat'] lon = weather['lon'] + # Only one location is supported, so we don't repeat it on every page — + # the current conditions fit on a single consolidated page. rows = get_rows() if rows == 1: pages = [format_lines(f'{temp} {desc}')] @@ -469,15 +494,10 @@ def _get_openmeteo_air(lat, lon): format_lines(f'{hi} {lo}', desc), ] elif rows == 3: - pages = [ - format_lines(city, f'{temp} {feels}', desc), - format_lines(city, f'{hi} {lo}', desc), - ] + pages = [format_lines(f'{temp} {feels}', f'{hi} {lo}', desc)] else: - pages = [ - format_lines(city, f'{temp} {feels}', desc, f'{hi} {lo}'), - format_lines(city, f'{hi} {lo}', desc, f'{provider_word} {weather_provider.upper()}'), - ] + pages = [format_lines(f'{temp} {feels}', f'{hi} {lo}', desc, + f'{provider_word} {weather_provider.upper()}')] if show_aqi: try: @@ -507,15 +527,15 @@ def _get_openmeteo_air(lat, lon): if aqi_num is None or aqi_num <= 0: raise ValueError('AQI unavailable') - aqi_display = _decorate_status(aqi_label, aqi_color, cols) + aqi_display = _decorate_status(t(aqi_label), aqi_color, cols, no_color) if rows == 1: pages.append(format_lines(f'AQI {aqi_display}')) elif rows == 2: pages.append(format_lines(f'AQI {aqi_num}', aqi_display)) elif rows == 3: - pages.append(format_lines(city, f'AQI {aqi_num}', aqi_display)) + pages.append(format_lines(t('AIR QUALITY'), f'AQI {aqi_num}', aqi_display)) else: - pages.append(format_lines(city, f'AQI {aqi_num}', aqi_display, f'{provider_word} {weather_provider.upper()}')) + pages.append(format_lines(t('AIR QUALITY'), f'AQI {aqi_num}', aqi_display, f'{provider_word} {weather_provider.upper()}')) except Exception: pass @@ -529,15 +549,15 @@ def _get_openmeteo_air(lat, lon): uv_num = int(round(float(uv_value))) uv_label = _uv_level(float(uv_value)) uv_color = _uv_color(float(uv_value)) - uv_display = _decorate_status(uv_label, uv_color, cols) + uv_display = _decorate_status(t(uv_label), uv_color, cols, no_color) if rows == 1: pages.append(format_lines(f'UV {uv_display}')) elif rows == 2: pages.append(format_lines(f'UV {uv_num}', uv_display)) elif rows == 3: - pages.append(format_lines(city, f'UV {uv_num}', uv_display)) + pages.append(format_lines(sun_exposure_text, f'UV {uv_num}', uv_display)) else: - pages.append(format_lines(city, f'UV {uv_num}', uv_display, sun_exposure_text)) + pages.append(format_lines(sun_exposure_text, f'UV {uv_num}', uv_display, '')) except Exception: pass @@ -566,22 +586,22 @@ def _get_openmeteo_air(lat, lon): raise ValueError('Pollen unavailable') overall = max(vals) if vals else None - overall_label = _pollen_level(overall) + overall_label = t(_pollen_level(overall)) overall_color = _pollen_color(overall) - grass_label = _pollen_level(grass) - tree_label = _pollen_level(birch) - weed_label = _pollen_level(weed or ragweed) - overall_display = _decorate_status(overall_label, overall_color, cols) + grass_label = t(_pollen_level(grass)) + tree_label = t(_pollen_level(birch)) + weed_label = t(_pollen_level(weed or ragweed)) + overall_display = _decorate_status(overall_label, overall_color, cols, no_color) component_displays = [] if grass is not None: - grass_display = f'{grass_word} {grass_label} {_compact_color(_pollen_color(grass))}' + grass_display = f'{grass_word} {grass_label} {_compact_color(_pollen_color(grass), no_color)}'.rstrip() component_displays.append(grass_display) if birch is not None: - tree_display = f'{tree_word} {tree_label} {_compact_color(_pollen_color(birch))}' + tree_display = f'{tree_word} {tree_label} {_compact_color(_pollen_color(birch), no_color)}'.rstrip() component_displays.append(tree_display) weed_value = weed or ragweed if weed_value is not None: - weed_display = f'{weed_word} {weed_label} {_compact_color(_pollen_color(weed_value))}' + weed_display = f'{weed_word} {weed_label} {_compact_color(_pollen_color(weed_value), no_color)}'.rstrip() component_displays.append(weed_display) if rows == 1: @@ -591,12 +611,12 @@ def _get_openmeteo_air(lat, lon): if component_displays: pages.append(format_lines(*component_displays)) elif rows == 3: - pages.append(format_lines(city, pollen_word, overall_display)) + pages.append(format_lines(pollen_word, overall_display)) if component_displays: pages.append(format_lines(*component_displays)) else: - pages.append(format_lines(city, pollen_word, overall_display, f'{provider_word} {weather_provider.upper()}')) - detail_lines = [city] + component_displays + pages.append(format_lines(pollen_word, overall_display, f'{provider_word} {weather_provider.upper()}')) + detail_lines = list(component_displays) if rows >= 5: detail_lines.append(f'{overall_word} {overall_display}') pages.append(format_lines(*detail_lines)) diff --git a/apps/weather/manifest.json b/apps/weather/manifest.json index 48c5915..d503631 100644 --- a/apps/weather/manifest.json +++ b/apps/weather/manifest.json @@ -1,5 +1,6 @@ { "id": "weather", + "i18n": true, "name": "Weather", "icon": "🌤️", "description": "Current conditions", diff --git a/apps/wiki-today/app.py b/apps/wiki-today/app.py new file mode 100644 index 0000000..478bc52 --- /dev/null +++ b/apps/wiki-today/app.py @@ -0,0 +1,57 @@ +"""Today on Wikipedia — featured article & most-read (keyless: Wikimedia REST).""" + + +def _wrap(text, cols, maxlines): + words, lines, cur = text.split(), [], '' + for w in words: + if len(cur) + len(w) + (1 if cur else 0) <= cols: + cur = f'{cur} {w}'.strip() + else: + lines.append(cur) + cur = w[:cols] + if len(lines) >= maxlines: + break + if cur and len(lines) < maxlines: + lines.append(cur) + return lines[:maxlines] or [''] + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + import requests + from datetime import datetime + import pytz + rows, cols = get_rows(), get_cols() + + def t(s): + return i18n.t(s, "content") if i18n is not None else s + + # Pull from the language's own Wikipedia edition (fr.wikipedia, de.wikipedia, …); + # the English variants all use en.wikipedia. Defaults to (American) English. + wl = i18n.lang_base if i18n is not None else 'en' + try: + try: + tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + except pytz.UnknownTimeZoneError: + tz = pytz.timezone('US/Eastern') + now = datetime.now(tz) + d = requests.get(f'https://{wl}.wikipedia.org/api/rest_v1/feed/featured/{now:%Y/%m/%d}', + headers={'User-Agent': 'SplitFlapGatewayCompanion/1.0'}, timeout=10).json() + pages = [] + tfa = d.get('tfa') or {} + title = str(tfa.get('normalizedtitle', '') or '').upper() + if title: + if rows == 1: + pages.append(f'WIKI {title}'[:cols].center(cols)) + else: + pages.append(format_lines(f'WIKI {t("FEATURED")}', *_wrap(title, cols, rows - 1))) + for a in ((d.get('mostread') or {}).get('articles', []) or [])[:3]: + art = str(a.get('normalizedtitle', '') or '').upper() + if not art: + continue + if rows == 1: + pages.append(f'WIKI {art}'[:cols].center(cols)) + else: + pages.append(format_lines(f'WIKI {t("MOST READ")}', *_wrap(art, cols, rows - 1))) + return pages or [format_lines('WIKIPEDIA', 'NO DATA', '')] + except Exception: + return [format_lines('WIKIPEDIA', 'OFFLINE', '')] diff --git a/apps/wiki-today/manifest.json b/apps/wiki-today/manifest.json new file mode 100644 index 0000000..61da9cb --- /dev/null +++ b/apps/wiki-today/manifest.json @@ -0,0 +1,25 @@ +{ + "id": "wiki-today", + "i18n": true, + "name": "Wikipedia Today", + "icon": "📚", + "description": "Featured article & most-read on Wikipedia", + "type": "functional", + "refresh_interval": 3600, + "loop_delay": 8, + "category": "news", + "min_rows": 2, + "min_cols": 15, + "settings": [ + { + "key": "loop_delay", + "label": "Delay Between Pages (seconds)", + "type": "number", + "default": "8", + "min": "2", + "max": "30", + "step": "1", + "stepper": true + } + ] +} diff --git a/apps/word-clock/app.py b/apps/word-clock/app.py index 93a5bda..c3180d0 100644 --- a/apps/word-clock/app.py +++ b/apps/word-clock/app.py @@ -1,21 +1,226 @@ -def fetch(settings, format_lines, get_rows, get_cols): - from datetime import datetime - import pytz - tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) - now = datetime.now(tz) - h = now.hour - m = now.minute +"""Word clock — spells the time out ("IT'S HALF PAST TEN"). + +Localized into the major Western-European languages when the companion injects +i18n (honoring the global Language). Each language has its own grammar — Romance +languages name the hour first (IL EST DIX HEURES ET QUART), Germanic ones lead +with the minutes (VIERTEL NACH ZEHN), and German/Dutch "half" points at the *next* +hour (HALB DREI = 2:30). Anything without a builder (or a bare host) falls back to +the original English behavior. +""" + +# Hour words 1..12 (index 0 unused) and minute-number words 1..29, accent-free to +# match the display's Windows-1252 rendering. Gender follows each language (es +# UNA/UNO for hour/minute, pt UMA/UM). +_HOURS = { + 'fr': ['', 'UNE', 'DEUX', 'TROIS', 'QUATRE', 'CINQ', 'SIX', 'SEPT', 'HUIT', 'NEUF', 'DIX', 'ONZE', 'DOUZE'], + 'de': ['', 'EINS', 'ZWEI', 'DREI', 'VIER', 'FUNF', 'SECHS', 'SIEBEN', 'ACHT', 'NEUN', 'ZEHN', 'ELF', 'ZWOLF'], + 'es': ['', 'UNA', 'DOS', 'TRES', 'CUATRO', 'CINCO', 'SEIS', 'SIETE', 'OCHO', 'NUEVE', 'DIEZ', 'ONCE', 'DOCE'], + 'it': ['', 'UNA', 'DUE', 'TRE', 'QUATTRO', 'CINQUE', 'SEI', 'SETTE', 'OTTO', 'NOVE', 'DIECI', 'UNDICI', 'DODICI'], + 'pt': ['', 'UMA', 'DUAS', 'TRES', 'QUATRO', 'CINCO', 'SEIS', 'SETE', 'OITO', 'NOVE', 'DEZ', 'ONZE', 'DOZE'], + 'nl': ['', 'EEN', 'TWEE', 'DRIE', 'VIER', 'VIJF', 'ZES', 'ZEVEN', 'ACHT', 'NEGEN', 'TIEN', 'ELF', 'TWAALF'], +} +_MINS = { + 'fr': ['', 'UNE', 'DEUX', 'TROIS', 'QUATRE', 'CINQ', 'SIX', 'SEPT', 'HUIT', 'NEUF', 'DIX', 'ONZE', 'DOUZE', + 'TREIZE', 'QUATORZE', 'QUINZE', 'SEIZE', 'DIX-SEPT', 'DIX-HUIT', 'DIX-NEUF', 'VINGT', 'VINGT ET UNE', + 'VINGT-DEUX', 'VINGT-TROIS', 'VINGT-QUATRE', 'VINGT-CINQ', 'VINGT-SIX', 'VINGT-SEPT', 'VINGT-HUIT', 'VINGT-NEUF'], + 'de': ['', 'EINS', 'ZWEI', 'DREI', 'VIER', 'FUNF', 'SECHS', 'SIEBEN', 'ACHT', 'NEUN', 'ZEHN', 'ELF', 'ZWOLF', + 'DREIZEHN', 'VIERZEHN', 'FUNFZEHN', 'SECHZEHN', 'SIEBZEHN', 'ACHTZEHN', 'NEUNZEHN', 'ZWANZIG', 'EINUNDZWANZIG', + 'ZWEIUNDZWANZIG', 'DREIUNDZWANZIG', 'VIERUNDZWANZIG', 'FUNFUNDZWANZIG', 'SECHSUNDZWANZIG', 'SIEBENUNDZWANZIG', + 'ACHTUNDZWANZIG', 'NEUNUNDZWANZIG'], + 'es': ['', 'UNO', 'DOS', 'TRES', 'CUATRO', 'CINCO', 'SEIS', 'SIETE', 'OCHO', 'NUEVE', 'DIEZ', 'ONCE', 'DOCE', + 'TRECE', 'CATORCE', 'QUINCE', 'DIECISEIS', 'DIECISIETE', 'DIECIOCHO', 'DIECINUEVE', 'VEINTE', 'VEINTIUNO', + 'VEINTIDOS', 'VEINTITRES', 'VEINTICUATRO', 'VEINTICINCO', 'VEINTISEIS', 'VEINTISIETE', 'VEINTIOCHO', 'VEINTINUEVE'], + 'it': ['', 'UNO', 'DUE', 'TRE', 'QUATTRO', 'CINQUE', 'SEI', 'SETTE', 'OTTO', 'NOVE', 'DIECI', 'UNDICI', 'DODICI', + 'TREDICI', 'QUATTORDICI', 'QUINDICI', 'SEDICI', 'DICIASSETTE', 'DICIOTTO', 'DICIANNOVE', 'VENTI', 'VENTUNO', + 'VENTIDUE', 'VENTITRE', 'VENTIQUATTRO', 'VENTICINQUE', 'VENTISEI', 'VENTISETTE', 'VENTOTTO', 'VENTINOVE'], + 'pt': ['', 'UM', 'DOIS', 'TRES', 'QUATRO', 'CINCO', 'SEIS', 'SETE', 'OITO', 'NOVE', 'DEZ', 'ONZE', 'DOZE', + 'TREZE', 'CATORZE', 'QUINZE', 'DEZESSEIS', 'DEZESSETE', 'DEZOITO', 'DEZENOVE', 'VINTE', 'VINTE E UM', + 'VINTE E DOIS', 'VINTE E TRES', 'VINTE E QUATRO', 'VINTE E CINCO', 'VINTE E SEIS', 'VINTE E SETE', + 'VINTE E OITO', 'VINTE E NOVE'], + 'nl': ['', 'EEN', 'TWEE', 'DRIE', 'VIER', 'VIJF', 'ZES', 'ZEVEN', 'ACHT', 'NEGEN', 'TIEN', 'ELF', 'TWAALF', + 'DERTIEN', 'VEERTIEN', 'VIJFTIEN', 'ZESTIEN', 'ZEVENTIEN', 'ACHTTIEN', 'NEGENTIEN', 'TWINTIG', 'EENENTWINTIG', + 'TWEEENTWINTIG', 'DRIEENTWINTIG', 'VIERENTWINTIG', 'VIJFENTWINTIG', 'ZESENTWINTIG', 'ZEVENENTWINTIG', + 'ACHTENTWINTIG', 'NEGENENTWINTIG'], +} + + +def _ctx(h): + """Displayed current hour (1..12) and next hour (1..12).""" h12 = h % 12 + disp = 12 if h12 == 0 else h12 + n12 = (h12 + 1) % 12 + dispn = 12 if n12 == 0 else n12 + return disp, dispn + + +def _b_fr(h, rounded): + if h == 0 and rounded == 0: + return ['IL', 'EST', 'MINUIT'] + if h == 12 and rounded == 0: + return ['IL', 'EST', 'MIDI'] + disp, dispn = _ctx(h) + H, M = _HOURS['fr'], _MINS['fr'] + heure = lambda d: 'HEURE' if d == 1 else 'HEURES' + if rounded == 0: + return ['IL', 'EST', H[disp], heure(disp)] + if rounded <= 30: + head = ['IL', 'EST', H[disp], heure(disp)] + if rounded == 15: + return head + ['ET', 'QUART'] + if rounded == 30: + return head + ['ET', 'DEMIE'] + return head + ['ET', M[rounded]] + mm = 60 - rounded + head = ['IL', 'EST', H[dispn], heure(dispn)] + if mm == 15: + return head + ['MOINS', 'LE', 'QUART'] + return head + ['MOINS', M[mm]] + + +def _b_de(h, rounded): + if h == 0 and rounded == 0: + return ['ES', 'IST', 'MITTERNACHT'] + if h == 12 and rounded == 0: + return ['ES', 'IST', 'MITTAG'] + disp, dispn = _ctx(h) + H, M = _HOURS['de'], _MINS['de'] + if rounded == 0: + return ['ES', 'IST', 'EIN' if disp == 1 else H[disp], 'UHR'] + if rounded <= 30: + if rounded == 15: + return ['ES', 'IST', 'VIERTEL', 'NACH', H[disp]] + if rounded == 30: + return ['ES', 'IST', 'HALB', H[dispn]] # halb points at the next hour + return ['ES', 'IST', M[rounded], 'NACH', H[disp]] + mm = 60 - rounded + if mm == 15: + return ['ES', 'IST', 'VIERTEL', 'VOR', H[dispn]] + return ['ES', 'IST', M[mm], 'VOR', H[dispn]] + + +def _b_es(h, rounded): + if h == 0 and rounded == 0: + return ['ES', 'MEDIANOCHE'] + if h == 12 and rounded == 0: + return ['ES', 'MEDIODIA'] + disp, dispn = _ctx(h) + H, M = _HOURS['es'], _MINS['es'] + pre = lambda d: ['ES', 'LA'] if d == 1 else ['SON', 'LAS'] + if rounded == 0: + return pre(disp) + [H[disp]] + if rounded <= 30: + head = pre(disp) + [H[disp]] + if rounded == 15: + return head + ['Y', 'CUARTO'] + if rounded == 30: + return head + ['Y', 'MEDIA'] + return head + ['Y', M[rounded]] + mm = 60 - rounded + head = pre(dispn) + [H[dispn]] + if mm == 15: + return head + ['MENOS', 'CUARTO'] + return head + ['MENOS', M[mm]] + + +def _b_it(h, rounded): + if h == 0 and rounded == 0: + return ["E'", 'MEZZANOTTE'] + if h == 12 and rounded == 0: + return ["E'", 'MEZZOGIORNO'] + disp, dispn = _ctx(h) + H, M = _HOURS['it'], _MINS['it'] + named = lambda d: ["E'", "L'UNA"] if d == 1 else ['SONO', 'LE', H[d]] + if rounded == 0: + return named(disp) + if rounded <= 30: + head = named(disp) + if rounded == 15: + return head + ['E', 'UN', 'QUARTO'] + if rounded == 30: + return head + ['E', 'MEZZA'] + return head + ['E', M[rounded]] + mm = 60 - rounded + head = named(dispn) + if mm == 15: + return head + ['MENO', 'UN', 'QUARTO'] + return head + ['MENO', M[mm]] + + +def _b_pt(h, rounded): + if h == 0 and rounded == 0: + return ["E'", 'MEIA-NOITE'] + if h == 12 and rounded == 0: + return ["E'", 'MEIO-DIA'] + disp, dispn = _ctx(h) + H, M = _HOURS['pt'], _MINS['pt'] + if rounded == 0: + return ["E'", 'UMA', 'HORA'] if disp == 1 else ['SAO', H[disp], 'HORAS'] + if rounded <= 30: + head = ["E'", 'UMA'] if disp == 1 else ['SAO', H[disp]] + if rounded == 15: + return head + ['E', 'QUINZE'] + if rounded == 30: + return head + ['E', 'MEIA'] + return head + ['E', M[rounded]] + mm = 60 - rounded + tail = 'QUINZE' if mm == 15 else M[mm] + if dispn == 1: + return [tail, 'PARA', 'A', 'UMA'] + return [tail, 'PARA', 'AS', H[dispn]] - interval = int(settings.get('interval', '5')) +def _b_nl(h, rounded): + if h == 0 and rounded == 0: + return ['HET', 'IS', 'MIDDERNACHT'] + if h == 12 and rounded == 0: + return ['HET', 'IS', 'MIDDAG'] + disp, dispn = _ctx(h) + H, M = _HOURS['nl'], _MINS['nl'] + if rounded == 0: + return ['HET', 'IS', H[disp], 'UUR'] + if rounded <= 30: + if rounded == 15: + return ['HET', 'IS', 'KWART', 'OVER', H[disp]] + if rounded == 30: + return ['HET', 'IS', 'HALF', H[dispn]] # half points at the next hour + return ['HET', 'IS', M[rounded], 'OVER', H[disp]] + mm = 60 - rounded + if mm == 15: + return ['HET', 'IS', 'KWART', 'VOOR', H[dispn]] + return ['HET', 'IS', M[mm], 'VOOR', H[dispn]] + + +_BUILDERS = {'fr': _b_fr, 'de': _b_de, 'es': _b_es, 'it': _b_it, 'pt': _b_pt, 'nl': _b_nl} + + +def _wrap(words, cols): + """Greedily pack words into lines no wider than the display.""" + lines, cur = [], '' + for w in words: + cand = w if not cur else f'{cur} {w}' + if len(cand) <= cols or not cur: + cur = cand + else: + lines.append(cur) + cur = w + if cur: + lines.append(cur) + return lines + + +def _fit(words, cols, rows): + lines = _wrap(words, cols) + if rows and rows >= 1 and len(lines) > rows: # collapse overflow into the last visible row + lines = lines[:rows - 1] + [' '.join(lines[rows - 1:])] + return lines + + +def _english(h, rounded, cols): + h12 = h % 12 hours = ['TWELVE', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'TEN', 'ELEVEN'] - - ones = ['', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', - 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'TEN', - 'ELEVEN', 'TWELVE', 'THIRTEEN', 'FOURTEEN', 'FIFTEEN', - 'SIXTEEN', 'SEVENTEEN', 'EIGHTEEN', 'NINETEEN'] + ones = ['', 'ONE', 'TWO', 'THREE', 'FOUR', 'FIVE', 'SIX', 'SEVEN', 'EIGHT', 'NINE', 'TEN', + 'ELEVEN', 'TWELVE', 'THIRTEEN', 'FOURTEEN', 'FIFTEEN', 'SIXTEEN', 'SEVENTEEN', 'EIGHTEEN', 'NINETEEN'] tens = ['', '', 'TWENTY', 'THIRTY', 'FORTY', 'FIFTY'] def minute_word(n): @@ -30,37 +235,52 @@ def minute_word(n): t, o = divmod(n, 10) return (tens[t] + ' ' + ones[o]).strip() if o else tens[t] - # Round to interval - rounded = round(m / interval) * interval - if rounded == 60: - rounded = 0 - h = (h + 1) % 24 - h12 = h % 12 - hour_word = hours[h12] next_word = hours[(h12 + 1) % 12] - cols = get_cols() - # Special cases for noon and midnight if h == 0 and rounded == 0: - return [format_lines("IT'S", 'MIDNIGHT', '')] + return ["IT'S", 'MIDNIGHT', ''] if h == 12 and rounded == 0: - return [format_lines("IT'S", 'NOON', '')] - + return ["IT'S", 'NOON', ''] if rounded == 0: - return [format_lines("IT'S", hour_word, "O'CLOCK")] - elif rounded <= 30: - mw = minute_word(rounded) - direction = 'PAST' - target = hour_word + return ["IT'S", hour_word, "O'CLOCK"] + if rounded <= 30: + mw, direction, target = minute_word(rounded), 'PAST', hour_word else: - mw = minute_word(60 - rounded) - direction = 'TO' - target = next_word + mw, direction, target = minute_word(60 - rounded), 'TO', next_word - # Fit into 3 lines: try "MW PAST" on line 2, else split combined = mw + ' ' + direction if len(combined) <= cols: - return [format_lines("IT'S", combined, target)] + return ["IT'S", combined, target] + return ["IT'S", mw, direction + ' ' + target] + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + from datetime import datetime + import pytz + try: + tz = pytz.timezone(settings.get('timezone', 'US/Eastern')) + except pytz.UnknownTimeZoneError: + tz = pytz.timezone('US/Eastern') + now = datetime.now(tz) + h, m = now.hour, now.minute + + try: + interval = int(settings.get('interval', '5')) + except (TypeError, ValueError): + interval = 5 + interval = max(1, min(30, interval)) + + rounded = round(m / interval) * interval + if rounded == 60: + rounded = 0 + h = (h + 1) % 24 + + cols, rows = get_cols(), get_rows() + lang = (i18n.lang if i18n is not None else 'en')[:2].lower() + + if lang in _BUILDERS: + lines = _fit(_BUILDERS[lang](h, rounded), cols, rows) else: - return [format_lines("IT'S", mw, direction + ' ' + target)] + lines = _english(h, rounded, cols) + return [format_lines(*lines)] diff --git a/apps/word-clock/manifest.json b/apps/word-clock/manifest.json index 0a915c5..769f69b 100644 --- a/apps/word-clock/manifest.json +++ b/apps/word-clock/manifest.json @@ -1,5 +1,6 @@ { "id": "word-clock", + "i18n": true, "name": "Word Clock", "icon": "🔤", "description": "Time as written phrase", diff --git a/apps/word-of-the-day/app.py b/apps/word-of-the-day/app.py index 28f3e47..cf9bc47 100644 --- a/apps/word-of-the-day/app.py +++ b/apps/word-of-the-day/app.py @@ -1,30 +1,75 @@ -"""Word of the Day plugin for Split-Flap Display.""" +"""Word of the Day — one characterful word, chosen by the date (no definition). -def fetch(settings, format_lines, get_rows, get_cols): - import urllib.request - import json - try: - url = "https://api.dictionaryapi.dev/api/v2/entries/en/random" - req = urllib.request.Request(url, headers={"User-Agent": "SplitFlap/1.0"}) - with urllib.request.urlopen(req, timeout=8) as resp: - data = json.loads(resp.read().decode()) - word = data[0]["word"].upper() - meaning = data[0]["meanings"][0]["definitions"][0]["definition"].upper() - return [ - format_lines("WORD OF THE DAY", word, ""), - format_lines(meaning[:get_cols()], meaning[get_cols():get_cols()*2], ""), - ] - except Exception: - import random - words = [ - ("EPHEMERAL", "LASTING A", "VERY SHORT TIME"), - ("UBIQUITOUS", "PRESENT OR", "FOUND EVERYWHERE"), - ("SERENDIPITY", "HAPPY ACCIDENT", "OR DISCOVERY"), - ("ELOQUENT", "FLUENT OR", "PERSUASIVE"), - ("RESILIENT", "ABLE TO RECOVER", "QUICKLY"), - ("PRAGMATIC", "DEALING WITH", "THINGS SENSIBLY"), - ("CANDOR", "THE QUALITY OF", "BEING OPEN"), - ("TENACIOUS", "HOLDING FIRMLY", "TO SOMETHING"), - ] - word, l2, l3 = random.choice(words) - return [format_lines("WORD OF THE DAY", word, ""), format_lines(l2, l3, "")] +Localized: when the companion injects i18n, the word is drawn from a curated list in +the current Language (falling back to English), and the header is translated. The +word is picked by the calendar day, so it's stable for the day and cycles over time. +""" + +# Accent-free (Windows-1252-safe) uppercase words, one evocative list per language. +WORDS_BY_LANG = { + "en": [ + "EPHEMERAL", "UBIQUITOUS", "SERENDIPITY", "ELOQUENT", "RESILIENT", + "PRAGMATIC", "CANDOR", "TENACIOUS", "MELLIFLUOUS", "LUMINOUS", + "QUINTESSENTIAL", "EFFERVESCENT", "PERSPICACIOUS", "SUCCINCT", "GREGARIOUS", + "INEFFABLE", "LABYRINTHINE", "MAGNANIMOUS", "NEBULOUS", "OBSTINATE", + "PANACEA", "QUERULOUS", "RESPLENDENT", "SANGUINE", "TACITURN", + "UMBRAGE", "VORACIOUS", "WISTFUL", "ZEALOUS", "AMBIVALENT", + "BENEVOLENT", "CACOPHONY", "DILIGENT", "ENIGMATIC", "FASTIDIOUS", + "GARRULOUS", "HALCYON", "IDIOSYNCRASY", "JUXTAPOSE", "LETHARGIC", + "MERCURIAL", "NONCHALANT", "OSTENTATIOUS", "PENCHANT", "QUIXOTIC", + "RECALCITRANT", "TRANQUIL", "VENERABLE", "WHIMSICAL", "ZENITH", + ], + "fr": [ + "FLANERIE", "DEPAYSEMENT", "RETROUVAILLES", "CREPUSCULE", "EBLOUISSANT", + "CHATOYANT", "INSOUCIANT", "MELANCOLIE", "QUIETUDE", "SAGACITE", + "PERSPICACE", "OPINIATRE", "LOQUACE", "VOLUBILE", "EPHEMERE", + "LUMINEUX", "RESILIENT", "TENACE", "SERENITE", "VENERABLE", + "NONCHALANT", "ENIGMATIQUE", "EXQUIS", "IMPROMPTU", + ], + "de": [ + "FERNWEH", "WALDEINSAMKEIT", "ZEITGEIST", "GEBORGENHEIT", "SEHNSUCHT", + "VERGAENGLICH", "LEUCHTEND", "BEHARRLICH", "SCHARFSINNIG", "WORTKARG", + "UEBERSCHWANG", "GEMUETLICH", "WEHMUT", "GELASSENHEIT", "EIGENSINNIG", + "BESONNEN", "VERWEGEN", "ANMUTIG", "UNERGRUENDLICH", "AUGENBLICK", + "DAEMMERUNG", "SCHWELGEN", "VERSCHMITZT", "EHRFURCHT", + ], + "es": [ + "EFIMERO", "INEFABLE", "SERENDIPIA", "ELOCUENTE", "RESILIENTE", + "LUMINOSO", "TENAZ", "PERSPICAZ", "LOCUAZ", "OBSTINADO", + "PANACEA", "RESPLANDECIENTE", "TRANQUILO", "VENERABLE", "SAGAZ", + "NOSTALGIA", "CREPUSCULO", "DESLUMBRANTE", "MELANCOLIA", "QUIETUD", + "SOSIEGO", "ENIGMATICO", "EXQUISITO", "IMPETU", + ], + "it": [ + "EFFIMERO", "INEFFABILE", "SERENDIPITA", "ELOQUENTE", "RESILIENTE", + "LUMINOSO", "TENACE", "PERSPICACE", "LOQUACE", "OSTINATO", + "PANACEA", "SPLENDENTE", "TRANQUILLO", "VENERABILE", "SAGACE", + "NOSTALGIA", "CREPUSCOLO", "ABBAGLIANTE", "MALINCONIA", "QUIETE", + "SERENITA", "ENIGMATICO", "SQUISITO", "IMPETO", + ], + "pt": [ + "EFEMERO", "INEFAVEL", "SERENDIPIA", "ELOQUENTE", "RESILIENTE", + "LUMINOSO", "TENAZ", "PERSPICAZ", "LOQUAZ", "OBSTINADO", + "PANACEIA", "RESPLANDECENTE", "TRANQUILO", "VENERAVEL", "SAGAZ", + "SAUDADE", "CREPUSCULO", "DESLUMBRANTE", "MELANCOLIA", "QUIETUDE", + "SOSSEGO", "ENIGMATICO", "REQUINTADO", "IMPETO", + ], + "nl": [ + "VLUCHTIG", "ONUITSPREKELIJK", "TIJDGEEST", "VEERKRACHTIG", "LICHTEND", + "VASTBERADEN", "SCHERPZINNIG", "WOORDKARIG", "KOPPIG", "WONDERMIDDEL", + "STRALEND", "SEREEN", "EERBIEDWAARDIG", "WIJSHEID", "WEEMOED", + "SCHEMERING", "OOGVERBLINDEND", "MELANCHOLIE", "GEZELLIG", "RAADSELACHTIG", + "VERRUKKELIJK", "ONSTUIMIG", "VOORBIJGAAND", "BEDACHTZAAM", + ], +} + + +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + from datetime import date + lang = i18n.lang_base if i18n is not None else "en" + words = WORDS_BY_LANG.get(lang) or WORDS_BY_LANG["en"] + word = words[date.today().toordinal() % len(words)] + header = i18n.t("WORD OF THE DAY", "vocab") if i18n is not None else "WORD OF THE DAY" + if get_rows() == 1: + return [format_lines(word)] + return [format_lines(header, word)] diff --git a/apps/word-of-the-day/manifest.json b/apps/word-of-the-day/manifest.json index 41cbbf6..884d705 100644 --- a/apps/word-of-the-day/manifest.json +++ b/apps/word-of-the-day/manifest.json @@ -1,5 +1,6 @@ { "id": "word-of-the-day", + "i18n": true, "name": "Word of the Day", "icon": "📖", "description": "Expand your vocabulary daily", @@ -8,18 +9,7 @@ "version": "1.0", "refresh_interval": 3600, "loop_delay": 10, - "settings": [ - { - "key": "loop_delay", - "label": "Delay Between Pages (seconds)", - "type": "number", - "default": "10", - "min": "2", - "max": "30", - "step": "1", - "stepper": true - } - ], - "min_rows": 3, - "min_cols": 10 -} \ No newline at end of file + "settings": [], + "min_rows": 2, + "min_cols": 15 +} diff --git a/apps/world_clock/app.py b/apps/world_clock/app.py index 8fb9128..e5034c4 100644 --- a/apps/world_clock/app.py +++ b/apps/world_clock/app.py @@ -1,14 +1,27 @@ -def fetch(settings, format_lines, get_rows, get_cols): +def fetch(settings, format_lines, get_rows, get_cols, i18n=None): from datetime import datetime import pytz - zones = [s.strip() for s in settings.get('world_clock_zones', 'US/Eastern,US/Pacific,Europe/London').split(',')] + cols = get_cols() + zones = [s.strip() for s in settings.get('world_clock_zones', 'US/Eastern,US/Pacific,Europe/London').split(',') if s.strip()] lines = [] for z in zones[:get_rows()]: - tz = pytz.timezone(z) + try: + tz = pytz.timezone(z) + except pytz.UnknownTimeZoneError: + continue now = datetime.now(tz) + # Compact time leaves room for the city; a long city is trimmed so the time + # is never cut off. AM/PM is an English convention — everyone else is 24h. + if i18n is not None: + t = i18n.time(now, ampm_space=False) + else: + t = now.strftime('%I:%M%p').lstrip('0') city = z.split('/')[-1].replace('_', ' ').upper() - lines.append(f'{city} {now.strftime("%I:%M %p")}') - lines += [''] * (get_rows() - len(lines)) + avail = max(1, cols - len(t) - 1) + lines.append(f'{city[:avail]} {t}') + if not lines: + lines = ['NO VALID', 'TIMEZONES'] + lines += [''] * max(0, get_rows() - len(lines)) return [format_lines(*lines)] diff --git a/apps/world_clock/manifest.json b/apps/world_clock/manifest.json index 3f762f8..84093bb 100644 --- a/apps/world_clock/manifest.json +++ b/apps/world_clock/manifest.json @@ -1,5 +1,6 @@ { "id": "world_clock", + "i18n": true, "name": "World Clock", "icon": "🌍", "description": "3 time zones", diff --git a/server/app.py b/server/app.py index d6ad81c..52717d4 100644 --- a/server/app.py +++ b/server/app.py @@ -11,11 +11,15 @@ import unicodedata import yfinance as yf import importlib.util +import inspect import urllib.request import shutil from datetime import datetime from flask import Flask, render_template, request, jsonify from tuning import build_tuning_adjust_commands +import i18n +import location +import weather from hardware.universal_firmware import ( UniversalFirmwareError, UniversalFirmwareManager, @@ -207,6 +211,9 @@ def load_settings(): "location_lon": "", "location_name": "", "timezone": sys_tz, + "i18n_enabled": False, + "language": "en-US", + "weather_provider": "openmeteo", "weather_api_key": "", "mbta_stop": "", "mbta_route": "", @@ -1369,6 +1376,69 @@ def _load_functional_module(app_id, app_dir): logging.error(f"Plugin {app_id}: error importing app.py: {e}") +def _fetch_accepts(fn, name): + """True if an app's fetch() declares a parameter called ``name`` (how an app + opts into an injected helper like ``i18n`` / ``get_weather`` / ``get_location``), + or accepts arbitrary keywords. Classic 4-arg apps accept neither and are called + unchanged, so this whole mechanism is fully backward compatible.""" + try: + params = inspect.signature(fn).parameters + except (TypeError, ValueError): + return False + return name in params or any(p.kind == p.VAR_KEYWORD for p in params.values()) + + +def _i18n_enabled(): + """Master switch for internationalization. Off by default: the display stays + English-only and looks exactly as it did before i18n existed. Should only be + turned on for modules whose firmware/character map can render accented glyphs.""" + return bool(settings.get("i18n_enabled", False)) + + +def _resolve_app_language(app_id): + """The Language an app should render in: a per-app override + (``plugin__language``) when set, otherwise the global Language. A blank or + unset override means "follow the global Language".""" + override = settings.get(f"plugin_{app_id}_language") + return override or settings.get("language", "en-US") + + +def _apply_location_override(plugin_settings, value): + """Fold a per-app Location override (a ``/location_search`` chip value, format + ``"lat,lon|name"``) into the ``location_*`` keys the location/weather helpers + read, so a per-app override is honored without touching the global location. + A blank/unset value leaves the global location in place.""" + if not value: + return + try: + coords, _, name = str(value).partition("|") + lat, _, lon = coords.partition(",") + lat, lon = lat.strip(), lon.strip() + if lat and lon: + plugin_settings["location_lat"] = lat + plugin_settings["location_lon"] = lon + plugin_settings["location_name"] = name.strip() or plugin_settings.get("location_name", "") + except Exception: + pass + + +def _plugin_fetch_kwargs(app_id, fetch_fn, plugin_settings): + """Optional keyword args a plugin's fetch() opted into by declaring them. Only + the helpers the signature names are built, so nothing is injected into apps that + don't ask for it.""" + kwargs = {} + if _fetch_accepts(fetch_fn, "get_weather"): + kwargs["get_weather"] = lambda s=None: weather.fetch_current( + s if s is not None else plugin_settings) + if _fetch_accepts(fetch_fn, "get_location"): + kwargs["get_location"] = lambda: location.resolve(plugin_settings) + # Only bind a Localizer when i18n is enabled; otherwise the app's i18n=None + # fallback runs and it renders exactly as it did before i18n existed (English). + if _i18n_enabled() and _fetch_accepts(fetch_fn, "i18n"): + kwargs["i18n"] = i18n.Localizer(_resolve_app_language(app_id)) + return kwargs + + def get_plugin_pages(app_id): manifest = _plugin_registry.get(app_id) if not manifest: @@ -1404,7 +1474,13 @@ def get_plugin_pages(app_id): else: key = f"plugin_{app_id}_{s['key']}" plugin_settings[s["key"]] = settings.get(key, s.get("default", "")) - pages = mod.fetch(plugin_settings, format_lines, get_rows, get_cols) + # A per-app Location override wins over the global location for this + # app's injected get_location / get_weather helpers (blank = follow global). + _apply_location_override(plugin_settings, settings.get(f"plugin_{app_id}_location")) + # Optional helpers (i18n / get_weather / get_location) are injected only + # when fetch() declares the matching parameter; 4-arg apps are unchanged. + kwargs = _plugin_fetch_kwargs(app_id, mod.fetch, plugin_settings) + pages = mod.fetch(plugin_settings, format_lines, get_rows, get_cols, **kwargs) if not isinstance(pages, list): pages = [str(pages)] _plugin_caches[app_id] = {"pages": pages, "fetched_at": now} @@ -1433,6 +1509,8 @@ def get_plugin_app_list(): "desc": manifest.get("description", "")[:30], "plugin": True, "plugin_id": app_id, + # 🌐 badge: the app adapts to Language AND i18n is globally enabled. + "i18n": bool(manifest.get("i18n")) and _i18n_enabled(), } if "min_rows" in manifest: entry["min_rows"] = manifest["min_rows"] @@ -1443,6 +1521,13 @@ def get_plugin_app_list(): return entries +# The languages an app can be localized into (the global Language select and every +# per-app Language override read from here). Defined once in server/i18n_data.json — +# only Windows-1252 (Western/Latin-1) languages, since the modules can't display +# Greek, Cyrillic, CJK, etc. +LANGUAGE_OPTIONS = i18n.LANGUAGE_OPTIONS + + _SETTING_PASSTHROUGH_KEYS = ( "size", "ph", @@ -1560,6 +1645,42 @@ def map_related_key(raw_related_key): return field +def _app_uses_location(app_id): + """True if the app's fetch() opts into the injected ``get_location`` helper.""" + mod = _plugin_modules.get(app_id) + return bool(mod) and _fetch_accepts(mod.fetch, "get_location") + + +def _auto_setting_fields(app_id, manifest, manifest_settings): + """Per-app override fields the runtime adds automatically (not in the manifest): + a Language override for any i18n app, and a Location override for any app that + reads the injected location. Each is stored under its own ``plugin__*`` key, + and a blank value means "follow the global setting".""" + declared = {s["key"] for s in manifest_settings} + fields = [] + if manifest.get("i18n") and _i18n_enabled() and "language" not in declared: + fields.append({ + "key": f"plugin_{app_id}_language", + "label": "Language", + "type": "select", + "opts": [{"value": "", "label": "Follow global"}] + LANGUAGE_OPTIONS, + "ph": "", + "note": "Override the global Language for this app only.", + }) + if _app_uses_location(app_id) and "location" not in declared: + fields.append({ + "key": f"plugin_{app_id}_location", + "label": "Location", + "type": "search_chips", + "searchUrl": "/location_search", + "resultKey": "results", + "maxItems": 1, + "ph": "", + "note": "Override the global Location for this app only (place search).", + }) + return fields + + def get_plugin_settings_config(): configs = {} for app_id, manifest in _plugin_registry.items(): @@ -1569,6 +1690,7 @@ def get_plugin_settings_config(): _build_plugin_setting_field(app_id, setting, resolved_keys) for setting in manifest_settings ] + fields += _auto_setting_fields(app_id, manifest, manifest_settings) configs[f"plugin_{app_id}"] = { "title": f"{manifest.get('icon', '🧩')} {manifest.get('name', app_id)}", @@ -2080,7 +2202,7 @@ def _trigger_loop(): @app.route('/') def index(): version = _read_version() - return render_template('index.html', version=version) + return render_template('index.html', version=version, language_options=LANGUAGE_OPTIONS) @app.route('/current_state') def current_state(): diff --git a/server/gateway_transport.py b/server/gateway_transport.py index 0bb1b3f..1634c98 100644 --- a/server/gateway_transport.py +++ b/server/gateway_transport.py @@ -151,7 +151,12 @@ def _on_message(self, client, userdata, msg): return # Re-append the newline the gateway stripped so downstream parsers that # look for '\n' terminators behave exactly as with raw serial. - data = frame.encode("utf-8", errors="ignore") + b"\n" + # Encode with latin-1 (not utf-8): the bus is single-byte cp1252, so a + # frame may carry raw high bytes (e.g. a module's A-command char map with + # 0xE9/0x80). latin-1 maps every code point 0x00-0xFF back to that exact + # byte, so downstream .decode('cp1252') sees the original bytes. utf-8 + # here would drop lone high bytes (errors="ignore") and corrupt the map. + data = frame.encode("latin-1", errors="ignore") + b"\n" with self._rx_lock: self._rx_buf.extend(data) @@ -162,8 +167,13 @@ def _extract_frame(payload): Accepts the gateway's JSON form ``{"command":"..."}`` and also a bare plain-text frame, for robustness against future gateway changes. """ + # Decode with latin-1, a transparent byte<->code-point codec: the bus is + # single-byte cp1252 and a frame (e.g. an A-command char-map response) can + # contain raw high bytes that are invalid standalone utf-8. latin-1 never + # raises and preserves every byte, so json.loads still parses the ASCII + # structure and the raw bytes survive to the caller (re-encoded latin-1). try: - text = payload.decode("utf-8", errors="ignore") + text = payload.decode("latin-1") except Exception: return None text = text.strip() diff --git a/server/i18n.py b/server/i18n.py new file mode 100644 index 0000000..e2807fc --- /dev/null +++ b/server/i18n.py @@ -0,0 +1,292 @@ +""" +i18n.py — shared localization for apps. + +Two pieces: + * CLDR-correct day / month names via babel — authoritative for every language. + * A curated table of the UI words apps show (SUNRISE, FULL MOON, DAYS …), + translated into the supported languages. Anything without an entry falls back to + the English key, so nothing breaks. + +All data — the selectable ``LANGUAGE_OPTIONS`` list, translations, and the default +currency/country per language — is loaded from ``i18n_data.json`` (see that file's +per-key context notes). Regional variants inherit their base language: ``pt-BR`` +reuses every ``pt`` translation but resolves to Brazil / BRL. + +The runtime binds this to the global Language setting and injects it into any app +whose ``fetch()`` declares an ``i18n`` parameter (like ``get_weather``); on a host +without the helper the app just falls back to English. Translations stay in one +place instead of being copied into every self-contained app. +""" + +from __future__ import annotations + +import json +import os + +# All localization data — the selectable language list, curated UI strings, +# duration-unit suffixes, holiday-name translations, and the default currency/country +# a language implies — lives in i18n_data.json so it can be edited, corrected, or +# extended with a whole new language without touching this module. A missing or +# invalid file degrades gracefully, so the lookups below just return their +# English/None defaults and apps keep working in English. +_DATA_PATH = os.path.join(os.path.dirname(__file__), "i18n_data.json") + +# Minimal fallback so the Language selector is never empty if the data file is +# missing/broken (the runtime still works, just English-only). +_DEFAULT_LANGUAGES = [{"value": "en-US", "label": "English (US)"}] + + +def _translations(section): + """Flatten a data section into the runtime ``{key: {lang: value}}`` lookup. Each + entry in the file is ``{"context": "...", "translations": {lang: value}}`` (the + context note is for translators only); a bare ``{lang: value}`` is also accepted.""" + out = {} + for key, entry in (section or {}).items(): + if isinstance(entry, dict) and "translations" in entry: + out[key] = entry["translations"] + elif isinstance(entry, dict): + out[key] = entry + return out + + +def _translations_by_domain(section): + """The ``strings`` section is grouped by context/domain + (``{domain: {NAME: {context, translations}}}``); flatten each domain to + ``{domain: {NAME: {lang: value}}}`` for lookup.""" + return {domain: _translations(entries) for domain, entries in (section or {}).items()} + + +def _load_i18n_data(): + try: + with open(_DATA_PATH, encoding="utf-8") as fh: + data = json.load(fh) + except (OSError, ValueError): + data = {} + return (_translations_by_domain(data.get("strings")), + _translations(data.get("holidays")), + data.get("base_currency", {}), + data.get("country", {}), + data.get("languages") or _DEFAULT_LANGUAGES) + + +(_STRINGS, _HOLIDAYS, _BASE_CURRENCY, _COUNTRY, + LANGUAGE_OPTIONS) = _load_i18n_data() + +# The compact duration-unit suffixes (D/H/M/S/Y) live in the shared 'time' domain, +# alongside the full-word forms (DAYS, HOURS, WEEKS, …) — one duration vocabulary. +_DURATION_UNITS = _STRINGS.get("time", {}) + + +def _base_lang(lang): + """The base language subtag: ``pt-BR`` / ``pt_BR`` -> ``pt``, ``de`` -> ``de``.""" + return str(lang or "").replace("_", "-").split("-")[0].lower() + + +def _localized(table, key, lang, default): + """Look up ``key`` in a ``{lang: value}`` table, trying the full language code + first and then its base subtag, so a regional variant (``pt-BR``) inherits the + base language (``pt``) wherever it has no entry of its own.""" + variants = table.get(key) + if not variants: + return default + code = str(lang or "").lower() + if code in variants: + return variants[code] + base = _base_lang(lang) + if base in variants: + return variants[base] + return default + + +def translate(text, lang, ctx="common"): + """English UI string -> localized for a given context/domain (``ctx``), like + gettext's ``pgettext``. The same English text can differ per context (weather + ``HIGH`` = a level, tides ``HIGH`` = high tide). Resolution order: the given + domain, then the shared ``common`` domain, then the English text itself — so an + unknown or English language always returns ``text`` and nothing breaks.""" + if not lang or _base_lang(lang) == "en": + return text + hit = _localized(_STRINGS.get(ctx) or {}, text, lang, None) + if hit is None and ctx != "common": + hit = _localized(_STRINGS.get("common") or {}, text, lang, None) + return text if hit is None else hit + + +def _babel_locale(lang): + """Our language code -> a babel locale id. English carries a region that changes + date order (US 'July 9' vs UK/AU '9 July'): 'en-GB' -> 'en_GB', 'en'/'en-US' -> + 'en_US'. Other languages just use their base code ('fr', 'de', …).""" + if not lang: + return "en_US" + parts = str(lang).replace("-", "_").split("_") + base = parts[0].lower() + if base == "en": + region = parts[1].upper() if len(parts) > 1 and parts[1] else "US" + return f"en_{region}" + return base + + +def _cldr(dt, fmt, lang): + try: + from babel.dates import format_date + return format_date(dt, fmt, locale=_babel_locale(lang)).upper() + except Exception: + return None + + +def weekday(dt, lang, short=False): + return _cldr(dt, "EEE" if short else "EEEE", lang) or dt.strftime("%a" if short else "%A").upper() + + +def month(dt, lang, short=False): + return _cldr(dt, "MMM" if short else "MMMM", lang) or dt.strftime("%b" if short else "%B").upper() + + +def date(dt, lang, short=False, year=False): + """Day + month (optionally year) in the locale's own order and wording: + ``JULY 9`` (en) but ``9 JUILLET`` (fr), ``9. JULI`` (de), ``9 DE JULIO`` (es).""" + skeleton = ("MMM" if short else "MMMM") + "d" + ("y" if year else "") + try: + from babel.dates import format_skeleton + return format_skeleton(skeleton, dt, locale=_babel_locale(lang)).upper() + except Exception: + base = f"{month(dt, lang, short)} {dt.day}" + return f"{base} {dt.year}" if year else base + + +def duration_unit(key, lang): + """Localized compact duration suffix (D/H/M/S/Y) -> e.g. J/H/M/S in French. The + duration vocabulary (abbreviations and full words) lives in the 'time' domain.""" + return translate(key, lang, "time") + + +def uses_24h(lang): + """AM/PM is essentially an English-language convention; everyone else is 24h.""" + return bool(lang) and _base_lang(lang) != "en" + + +# Non-ASCII group separators CLDR uses (French narrow/no-break spaces) — the flap +# display only speaks Windows-1252, so we fold them back to a plain space. +_GROUP_SPACES = ("\u202f", "\u00a0", "\u2009") + + +def number(value, lang, decimals=2, grouping=True): + """Format a number with the locale's own separators: 1,234.5 (en) vs 1.234,5 + (de/es/it/…) vs 1 234,5 (fr). Falls back to English grouping without babel.""" + try: + from babel.numbers import format_decimal + pattern = ("#,##0" if grouping else "0") + ("." + "0" * decimals if decimals > 0 else "") + s = format_decimal(float(value), format=pattern, locale=_babel_locale(lang)) + except Exception: + try: + s = f"{float(value):,.{decimals}f}" if grouping else f"{float(value):.{decimals}f}" + except Exception: + return str(value) + for ch in _GROUP_SPACES: + s = s.replace(ch, " ") + return s + + +def base_currency(lang): + """The "home" currency a language/region implies (the default base for FX): US -> + USD, UK -> GBP, Brazil -> BRL, the rest of Western Europe -> EUR. From + i18n_data.json; a regional variant (``pt-BR``) wins over its base (``pt``), and + unknown languages default to USD. Users can override explicitly.""" + code = str(lang or "en").lower() + return _BASE_CURRENCY.get(code) or _BASE_CURRENCY.get(_base_lang(lang or "en"), "USD") + + +def currency_symbol(code): + """Compact symbol for an ISO 4217 currency code ('EUR' -> '€', 'USD' -> '$', + 'GBP' -> '£') from babel, using a neutral (English) locale so it's the short + universal form — not a locale-disambiguated one like '$US'/'£GB'. Falls back to + the ISO code when the symbol has characters the flap display (Windows-1252) can't + render — ₹, ₩, ฿ -> 'INR'/'KRW'/'THB'.""" + if not code: + return "" + code = code.upper() + try: + from babel.numbers import get_currency_symbol + sym = get_currency_symbol(code, locale="en") or code + except Exception: + sym = {"USD": "$", "EUR": "€", "GBP": "£", "JPY": "¥"}.get(code, code) + try: + sym.encode("cp1252") + except UnicodeEncodeError: + return code + return sym + + +def country(lang): + """The country a language/region implies — for holidays (which calendar to show) + and other country-scoped data. Regional variants split by country (``pt-BR`` -> + BR, ``pt`` -> PT); from i18n_data.json, unknown languages default to US.""" + code = str(lang or "en").lower() + return _COUNTRY.get(code) or _COUNTRY.get(_base_lang(lang or "en"), "US") + + +def holiday(name, lang): + """Localized public-holiday name, or None if we have no translation (caller + then keeps the source's native name).""" + if not lang or not name: + return None + return _localized(_HOLIDAYS, str(name).strip().lower(), lang, None) + + +def clock(dt, lang, seconds=False, ampm_space=True): + """Locale-appropriate wall-clock time: ``3:48 PM`` in English, ``15:48`` elsewhere.""" + if uses_24h(lang): + return dt.strftime("%H:%M:%S" if seconds else "%H:%M") + body = dt.strftime("%I:%M:%S" if seconds else "%I:%M").lstrip("0") + sep = " " if ampm_space else "" + return f"{body}{sep}{dt.strftime('%p')}" + + +class Localizer: + """Language-bound convenience wrapper handed to apps as ``i18n``.""" + + def __init__(self, lang): + self.lang = (lang or "en").lower() + + @property + def is_24h(self): + return uses_24h(self.lang) + + def t(self, text, ctx="common"): + return translate(text, self.lang, ctx) + + def weekday(self, dt, short=False): + return weekday(dt, self.lang, short) + + def month(self, dt, short=False): + return month(dt, self.lang, short) + + def date(self, dt, short=False, year=False): + return date(dt, self.lang, short, year) + + def time(self, dt, seconds=False, ampm_space=True): + return clock(dt, self.lang, seconds, ampm_space) + + def unit(self, key): + return duration_unit(key, self.lang) + + def number(self, value, decimals=2, grouping=True): + return number(value, self.lang, decimals, grouping) + + def base_currency(self): + return base_currency(self.lang) + + def currency_symbol(self, code): + return currency_symbol(code) + + def country(self): + return country(self.lang) + + def holiday(self, name): + return holiday(name, self.lang_base) + + @property + def lang_base(self): + """The 2-letter language without region ('en-GB' -> 'en'), for APIs that + want a plain language code (Wikipedia editions, weather providers, …).""" + return self.lang.split("-")[0] diff --git a/server/i18n_data.json b/server/i18n_data.json new file mode 100644 index 0000000..ff03329 --- /dev/null +++ b/server/i18n_data.json @@ -0,0 +1,2628 @@ +{ + "_comment": "Localization data for i18n.py, loaded at import. 'languages' is the Language selector list. 'strings' groups translations by SEMANTIC context/domain (like gettext msgctxt): strings[domain][NAME] has a generic 'context' note and a language->text map. A domain is a MEANING, not an app — a word with one meaning lives in one domain (e.g. the shared 'time' vocab), and is duplicated only when its meaning differs by context (weather HIGH = a level, tides HIGH = high tide). Apps translate via the relevant domain; the 'common' domain (OFFLINE, ERROR, …) backs every context. A missing (domain, NAME, language) falls back to the English NAME, and a regional variant (pt-BR) inherits its base language (pt). 'duration_units' (D/H/M/S symbols) and 'holidays' stay flat; 'base_currency'/'country' are the default a language implies when no Location is set. Only Windows-1252 (Western/Latin-1) languages. Edit here to fix/add translations.", + "languages": [ + { + "value": "en-US", + "label": "English (US)" + }, + { + "value": "en-GB", + "label": "English (UK)" + }, + { + "value": "en-AU", + "label": "English (Australia)" + }, + { + "value": "en-CA", + "label": "English (Canada)" + }, + { + "value": "fr", + "label": "Français (French)" + }, + { + "value": "fr-CA", + "label": "Français (Canada)" + }, + { + "value": "fr-BE", + "label": "Français (Belgique)" + }, + { + "value": "fr-CH", + "label": "Français (Suisse)" + }, + { + "value": "de", + "label": "Deutsch (German)" + }, + { + "value": "de-AT", + "label": "Deutsch (Österreich)" + }, + { + "value": "de-CH", + "label": "Deutsch (Schweiz)" + }, + { + "value": "es", + "label": "Español (Spanish)" + }, + { + "value": "es-MX", + "label": "Español (México)" + }, + { + "value": "es-AR", + "label": "Español (Argentina)" + }, + { + "value": "it", + "label": "Italiano (Italian)" + }, + { + "value": "it-CH", + "label": "Italiano (Svizzera)" + }, + { + "value": "pt", + "label": "Português (Portugal)" + }, + { + "value": "pt-BR", + "label": "Português (Brasil)" + }, + { + "value": "nl", + "label": "Nederlands (Dutch)" + }, + { + "value": "nl-BE", + "label": "Nederlands (België)" + }, + { + "value": "da", + "label": "Dansk (Danish)" + }, + { + "value": "no", + "label": "Norsk (Norwegian)" + }, + { + "value": "sv", + "label": "Svenska (Swedish)" + }, + { + "value": "fi", + "label": "Suomi (Finnish)" + }, + { + "value": "is", + "label": "Íslenska (Icelandic)" + }, + { + "value": "ga", + "label": "Gaeilge (Irish)" + }, + { + "value": "ca", + "label": "Català (Catalan)" + }, + { + "value": "gl", + "label": "Galego (Galician)" + }, + { + "value": "eu", + "label": "Euskara (Basque)" + }, + { + "value": "et", + "label": "Eesti (Estonian)" + }, + { + "value": "af", + "label": "Afrikaans" + }, + { + "value": "id", + "label": "Bahasa Indonesia" + }, + { + "value": "ms", + "label": "Bahasa Melayu (Malay)" + }, + { + "value": "sw", + "label": "Kiswahili (Swahili)" + } + ], + "strings": { + "common": { + "OFFLINE": { + "context": "Status: the device/service is offline.", + "translations": { + "fr": "HORS LIGNE", + "de": "OFFLINE", + "es": "SIN CONEXION", + "it": "OFFLINE", + "pt": "OFFLINE", + "nl": "OFFLINE", + "da": "OFFLINE", + "no": "OFFLINE", + "sv": "OFFLINE" + } + }, + "NO DATA": { + "context": "Status: no data was returned.", + "translations": { + "fr": "PAS DE DONNEES", + "de": "KEINE DATEN", + "es": "SIN DATOS", + "it": "NESSUN DATO", + "pt": "SEM DADOS", + "nl": "GEEN DATA", + "da": "INGEN DATA", + "no": "INGEN DATA", + "sv": "INGEN DATA" + } + }, + "ERROR": { + "context": "Status: a generic error occurred.", + "translations": { + "fr": "ERREUR", + "de": "FEHLER", + "es": "ERROR", + "it": "ERRORE", + "pt": "ERRO", + "nl": "FOUT", + "da": "FEJL", + "no": "FEIL", + "sv": "FEL" + } + }, + "UNKNOWN": { + "context": "Value unknown / unavailable.", + "translations": { + "fr": "INCONNU", + "de": "UNBEKANNT", + "es": "DESCON.", + "it": "SCONOSC.", + "pt": "DESCON.", + "nl": "ONBEKEND", + "da": "UKENDT", + "no": "UKJENT", + "sv": "OKÄND" + } + }, + "INVALID DATE": { + "context": "A configured date could not be parsed.", + "translations": { + "fr": "DATE INVALIDE", + "de": "UNGULT. DATUM", + "es": "FECHA INVALIDA", + "it": "DATA NON VALIDA", + "pt": "DATA INVALIDA", + "nl": "ONGELDIGE DATUM" + } + }, + "API FAIL": { + "context": "Status: an upstream API call failed.", + "translations": { + "fr": "ECHEC API", + "de": "API-FEHLER", + "es": "FALLO API", + "it": "ERRORE API", + "pt": "FALHA API", + "nl": "API-FOUT", + "da": "API-FEJL", + "no": "API-FEIL", + "sv": "API-FEL" + } + }, + "CONFIGURE": { + "context": "Prompt to configure the app in Settings.", + "translations": { + "fr": "CONFIGURER", + "de": "EINRICHTEN", + "es": "CONFIGURAR", + "it": "CONFIGURA", + "pt": "CONFIGURAR", + "nl": "INSTELLEN", + "da": "OPSÆT", + "no": "SETT OPP", + "sv": "KONFIGURERA" + } + } + }, + "time": { + "DAYS": { + "context": "Duration unit word (plural): days.", + "translations": { + "fr": "JOURS", + "de": "TAGE", + "es": "DÍAS", + "it": "GIORNI", + "pt": "DIAS", + "nl": "DAGEN", + "da": "DAGE", + "no": "DAGER", + "sv": "DAGAR" + } + }, + "HOURS": { + "context": "Duration unit word (plural): hours.", + "translations": { + "fr": "HEURES", + "de": "STUNDEN", + "es": "HORAS", + "it": "ORE", + "pt": "HORAS", + "nl": "UREN", + "da": "TIMER", + "no": "TIMER", + "sv": "TIMMAR" + } + }, + "MINS": { + "context": "Time unit: minutes (abbreviated).", + "translations": { + "fr": "MIN", + "de": "MIN", + "es": "MIN", + "it": "MIN", + "pt": "MIN", + "nl": "MIN", + "da": "MIN", + "no": "MIN", + "sv": "MIN" + } + }, + "LEFT": { + "context": "Follows a remaining duration ('3D LEFT').", + "translations": { + "fr": "RESTE", + "de": "UBRIG", + "es": "QUEDAN", + "it": "MANCA", + "pt": "FALTAM", + "nl": "OVER", + "da": "TILBAGE", + "no": "IGJEN", + "sv": "KVAR" + } + }, + "REMAINING": { + "context": "Follows a duration to mean time remaining ('3D REMAINING').", + "translations": { + "fr": "RESTANT", + "de": "VERBLEIB.", + "es": "RESTANTE", + "it": "RIMANENTE", + "pt": "RESTANTE", + "nl": "RESTEREND", + "da": "TILBAGE", + "no": "GJENSTÅR", + "sv": "ÅTERSTÅR" + } + }, + "ARRIVED": { + "context": "Shown when an awaited moment has arrived.", + "translations": { + "fr": "ARRIVE", + "de": "DA", + "es": "LLEGO", + "it": "ARRIVATO", + "pt": "CHEGOU", + "nl": "AANGEKOMEN", + "da": "ANKOMMET", + "no": "ANKOMMET", + "sv": "ANLÄNT" + } + }, + "HERE": { + "context": "Short 'it's here' when an awaited moment arrives.", + "translations": { + "fr": "ICI", + "de": "HIER", + "es": "AQUI", + "it": "QUI", + "pt": "AQUI", + "nl": "HIER", + "da": "HER", + "no": "HER", + "sv": "HÄR" + } + }, + "CELEBRATE": { + "context": "Celebratory word shown when an event arrives.", + "translations": { + "fr": "FETEZ", + "de": "FEIERN", + "es": "CELEBRA", + "it": "FESTA", + "pt": "FESTA", + "nl": "VIER", + "da": "FEJR", + "no": "FEIRE", + "sv": "FIRA" + } + }, + "PARTY": { + "context": "Celebratory word shown when an event arrives.", + "translations": { + "fr": "FETE", + "de": "PARTY", + "es": "FIESTA", + "it": "FESTA", + "pt": "FESTA", + "nl": "FEEST", + "da": "FEST", + "no": "FEST", + "sv": "FEST" + } + }, + "TODAY": { + "context": "The word 'today'.", + "translations": { + "fr": "AUJOURDHUI", + "de": "HEUTE", + "es": "HOY", + "it": "OGGI", + "pt": "HOJE", + "nl": "VANDAAG", + "da": "I DAG", + "no": "I DAG", + "sv": "IDAG" + } + }, + "NOW": { + "context": "The word 'now'.", + "translations": { + "fr": "MAINTENANT", + "de": "JETZT", + "es": "AHORA", + "it": "ORA", + "pt": "AGORA", + "nl": "NU", + "da": "NU", + "no": "NÅ", + "sv": "NU" + } + }, + "IN": { + "context": "Connector before a duration: 'IN 3 DAYS'.", + "translations": { + "fr": "DANS", + "de": "IN", + "es": "EN", + "it": "TRA", + "pt": "EM", + "nl": "OVER", + "da": "OM", + "no": "OM", + "sv": "OM" + } + }, + "Y": { + "context": "Compact duration suffix for years (after a number, e.g. '2A').", + "translations": { + "fr": "A", + "de": "J", + "es": "A", + "it": "A", + "pt": "A", + "nl": "J", + "da": "Å", + "no": "Å", + "sv": "Å" + } + }, + "D": { + "context": "Compact duration suffix for days (e.g. '175D').", + "translations": { + "fr": "J", + "de": "T", + "es": "D", + "it": "G", + "pt": "D", + "nl": "D" + } + }, + "H": { + "context": "Compact duration suffix for hours.", + "translations": { + "fr": "H", + "de": "H", + "es": "H", + "it": "H", + "pt": "H", + "nl": "U", + "da": "T", + "no": "T", + "sv": "T" + } + }, + "M": { + "context": "Compact duration suffix for minutes.", + "translations": { + "fr": "M", + "de": "M", + "es": "M", + "it": "M", + "pt": "M", + "nl": "M" + } + }, + "S": { + "context": "Compact duration suffix for seconds.", + "translations": { + "fr": "S", + "de": "S", + "es": "S", + "it": "S", + "pt": "S", + "nl": "S" + } + }, + "YEARS": { + "context": "Duration unit word (plural): years.", + "translations": { + "fr": "ANS", + "de": "JAHRE", + "es": "AÑOS", + "it": "ANNI", + "pt": "ANOS", + "nl": "JAREN", + "da": "ÅR", + "no": "ÅR", + "sv": "ÅR" + } + }, + "MONTHS": { + "context": "Duration unit word (plural): months.", + "translations": { + "fr": "MOIS", + "de": "MONATE", + "es": "MESES", + "it": "MESI", + "pt": "MESES", + "nl": "MAANDEN", + "da": "MÅNEDER", + "no": "MÅNEDER", + "sv": "MÅNADER" + } + }, + "WEEKS": { + "context": "Duration unit word (plural): weeks.", + "translations": { + "fr": "SEMAINES", + "de": "WOCHEN", + "es": "SEMANAS", + "it": "SETTIMANE", + "pt": "SEMANAS", + "nl": "WEKEN", + "da": "UGER", + "no": "UKER", + "sv": "VECKOR" + } + }, + "MINUTES": { + "context": "Duration unit word (plural): minutes.", + "translations": { + "fr": "MINUTES", + "de": "MINUTEN", + "es": "MINUTOS", + "it": "MINUTI", + "pt": "MINUTOS", + "nl": "MINUTEN", + "da": "MINUTTER", + "no": "MINUTTER", + "sv": "MINUTER" + } + }, + "SECONDS": { + "context": "Duration unit word (plural): seconds.", + "translations": { + "fr": "SECONDES", + "de": "SEKUNDEN", + "es": "SEGUNDOS", + "it": "SECONDI", + "pt": "SEGUNDOS", + "nl": "SECONDEN", + "da": "SEKUNDER", + "no": "SEKUNDER", + "sv": "SEKUNDER" + } + }, + "TIME SINCE": { + "context": "'Time since ' label.", + "translations": { + "fr": "DEPUIS", + "de": "SEIT", + "es": "DESDE", + "it": "DA", + "pt": "DESDE", + "nl": "SINDS", + "da": "SIDEN", + "no": "SIDEN", + "sv": "SEDAN" + } + }, + "NOT YET": { + "context": "An awaited event is still in the future.", + "translations": { + "fr": "PAS ENCORE", + "de": "NOCH NICHT", + "es": "AUN NO", + "it": "NON ANCORA", + "pt": "AINDA NAO", + "nl": "NOG NIET", + "da": "IKKE ENDNU", + "no": "IKKE ENNÅ", + "sv": "INTE ÄNNU" + } + }, + "STARTED": { + "context": "An event has started / passed.", + "translations": { + "fr": "COMMENCE", + "de": "GESTARTET", + "es": "EMPEZADO", + "it": "INIZIATO", + "pt": "INICIADO", + "nl": "GESTART", + "da": "STARTET", + "no": "STARTET", + "sv": "STARTAT" + } + } + }, + "sun": { + "SUNRISE": { + "context": "The time the sun rises.", + "translations": { + "fr": "LEVER", + "de": "AUFGANG", + "es": "AMANECER", + "it": "ALBA", + "pt": "NASCER", + "nl": "OPKOMST", + "da": "SOLOPGANG", + "no": "SOLOPPGANG", + "sv": "SOLUPPGÅNG" + } + }, + "SUNSET": { + "context": "The time the sun sets.", + "translations": { + "fr": "COUCHER", + "de": "UNTERGANG", + "es": "OCASO", + "it": "TRAMONTO", + "pt": "OCASO", + "nl": "ONDERGANG", + "da": "SOLNEDGANG", + "no": "SOLNEDGANG", + "sv": "SOLNEDGÅNG" + } + }, + "DAYLIGHT": { + "context": "Total hours of daylight.", + "translations": { + "fr": "JOUR", + "de": "TAGESLICHT", + "es": "LUZ DIA", + "it": "LUCE", + "pt": "LUZ DIA", + "nl": "DAGLICHT", + "da": "DAGSLYS", + "no": "DAGSLYS", + "sv": "DAGSLJUS" + } + }, + "UP": { + "context": "Very short label for sunrise (sun is up).", + "translations": { + "fr": "LEV", + "de": "AUF", + "es": "SAL", + "it": "ALBA", + "pt": "NASC", + "nl": "OP" + } + }, + "DN": { + "context": "Very short label for sunset (sun is down).", + "translations": { + "fr": "COU", + "de": "UNT", + "es": "OCA", + "it": "TRAM", + "pt": "OCA", + "nl": "OND" + } + } + }, + "moon": { + "NEW MOON": { + "context": "Lunar phase: new moon.", + "translations": { + "fr": "NOUVELLE LUNE", + "de": "NEUMOND", + "es": "LUNA NUEVA", + "it": "LUNA NUOVA", + "pt": "LUA NOVA", + "nl": "NIEUWE MAAN", + "da": "NYMÅNE", + "no": "NYMÅNE", + "sv": "NYMÅNE" + } + }, + "FULL MOON": { + "context": "Lunar phase: full moon.", + "translations": { + "fr": "PLEINE LUNE", + "de": "VOLLMOND", + "es": "LUNA LLENA", + "it": "LUNA PIENA", + "pt": "LUA CHEIA", + "nl": "VOLLE MAAN", + "da": "FULDMÅNE", + "no": "FULLMÅNE", + "sv": "FULLMÅNE" + } + }, + "FIRST QUARTER": { + "context": "Lunar phase: first quarter (keep short).", + "translations": { + "fr": "1ER QUARTIER", + "de": "1. VIERTEL", + "es": "CUARTO CREC.", + "it": "PRIMO QUARTO", + "pt": "QUARTO CRESC.", + "nl": "EERSTE KWART." + } + }, + "LAST QUARTER": { + "context": "Lunar phase: last quarter (keep short).", + "translations": { + "fr": "DERN. QUARTIER", + "de": "LETZT. VIERTEL", + "es": "CUARTO MENG.", + "it": "ULTIMO QUARTO", + "pt": "QUARTO MING.", + "nl": "LAATSTE KWART." + } + }, + "WAXING CRESCENT": { + "context": "Lunar phase: waxing crescent (growing).", + "translations": { + "fr": "1ER CROISSANT", + "de": "ZUN. SICHEL", + "es": "CRECIENTE", + "it": "CRESCENTE", + "pt": "CRESCENTE", + "nl": "WASSEND" + } + }, + "WANING CRESCENT": { + "context": "Lunar phase: waning crescent (shrinking).", + "translations": { + "fr": "DERN. CROISSANT", + "de": "ABN. SICHEL", + "es": "MENGUANTE", + "it": "CALANTE", + "pt": "MINGUANTE", + "nl": "AFNEMEND" + } + }, + "WAXING GIBBOUS": { + "context": "Lunar phase: waxing gibbous (growing).", + "translations": { + "fr": "GIBBEUSE CROIS.", + "de": "ZUN. MOND", + "es": "GIBOSA CREC.", + "it": "GIBBOSA CRESC.", + "pt": "GIBOSA CRESC.", + "nl": "WASSEND" + } + }, + "WANING GIBBOUS": { + "context": "Lunar phase: waning gibbous (shrinking).", + "translations": { + "fr": "GIBBEUSE DECR.", + "de": "ABN. MOND", + "es": "GIBOSA MENG.", + "it": "GIBBOSA CAL.", + "pt": "GIBOSA MING.", + "nl": "AFNEMEND" + } + }, + "LIT": { + "context": "Precedes the percentage of a surface that is illuminated, e.g. '16% LIT'.", + "translations": { + "fr": "ECLAIRE", + "de": "HELL", + "es": "ILUM.", + "it": "ILLUM.", + "pt": "ILUM.", + "nl": "VERL.", + "da": "OPLYST", + "no": "OPPLYST", + "sv": "UPPLYST" + } + }, + "FULL IN": { + "context": "'FULL IN 3D' = time until something is full (e.g. the moon).", + "translations": { + "fr": "PLEINE DANS", + "de": "VOLL IN", + "es": "LLENA EN", + "it": "PIENA IN", + "pt": "CHEIA EM", + "nl": "VOL OVER", + "da": "FULD OM", + "no": "FULL OM", + "sv": "FULL OM" + } + }, + "NEW IN": { + "context": "'NEW IN 3D' = time until something is new (e.g. the moon).", + "translations": { + "fr": "NOUV. DANS", + "de": "NEU IN", + "es": "NUEVA EN", + "it": "NUOVA IN", + "pt": "NOVA EM", + "nl": "NIEUW OVER", + "da": "NY OM", + "no": "NY OM", + "sv": "NY OM" + } + } + }, + "weather": { + "CLEAR": { + "context": "Weather condition: clear sky.", + "translations": { + "fr": "DEGAGE", + "de": "KLAR", + "es": "DESPEJADO", + "it": "SERENO", + "pt": "LIMPO", + "nl": "HELDER", + "da": "KLART", + "no": "KLART", + "sv": "KLART" + } + }, + "MAINLY CLEAR": { + "context": "Weather condition: mostly clear sky.", + "translations": { + "fr": "PLUTOT CLAIR", + "de": "MEIST KLAR", + "es": "MAYORM. CLARO", + "it": "POCO NUVOLOSO", + "pt": "QUASE LIMPO", + "nl": "VNL. HELDER" + } + }, + "PARTLY CLOUDY": { + "context": "Weather condition: partly cloudy.", + "translations": { + "fr": "NUAGEUX", + "de": "TEILS WOLKIG", + "es": "PARC. NUBLADO", + "it": "POCO NUVOLOSO", + "pt": "PARC. NUBLADO", + "nl": "HALF BEWOLKT", + "da": "DELVIS SKYET", + "no": "DELVIS SKYET", + "sv": "DELVIS MOLNIGT" + } + }, + "OVERCAST": { + "context": "Weather condition: fully clouded over.", + "translations": { + "fr": "COUVERT", + "de": "BEDECKT", + "es": "CUBIERTO", + "it": "COPERTO", + "pt": "ENCOBERTO", + "nl": "BEWOLKT", + "da": "OVERSKYET", + "no": "OVERSKYET", + "sv": "MULET" + } + }, + "FOG": { + "context": "Weather condition: fog.", + "translations": { + "fr": "BROUILLARD", + "de": "NEBEL", + "es": "NIEBLA", + "it": "NEBBIA", + "pt": "NEVOEIRO", + "nl": "MIST", + "da": "TÅGE", + "no": "TÅKE", + "sv": "DIMMA" + } + }, + "RIME FOG": { + "context": "Weather condition: freezing/rime fog.", + "translations": { + "fr": "BRUME GIVRANTE", + "de": "RAUREIF", + "es": "NIEBLA HELADA", + "it": "NEBBIA GHIAC.", + "pt": "NEVOA GELADA", + "nl": "RIJP-MIST" + } + }, + "LIGHT DRIZZLE": { + "context": "Weather condition: light drizzle.", + "translations": { + "fr": "BRUINE LEGERE", + "de": "LEICHT NIESEL", + "es": "LLOVIZNA LEVE", + "it": "PIOVIGGINE", + "pt": "CHUVISCO FRACO", + "nl": "LICHTE MOTREG" + } + }, + "DRIZZLE": { + "context": "Weather condition: drizzle.", + "translations": { + "fr": "BRUINE", + "de": "NIESELN", + "es": "LLOVIZNA", + "it": "PIOVIGGINE", + "pt": "CHUVISCO", + "nl": "MOTREGEN" + } + }, + "HEAVY DRIZZLE": { + "context": "Weather condition: heavy drizzle.", + "translations": { + "fr": "BRUINE FORTE", + "de": "STARK. NIESEL", + "es": "LLOVIZNA FTE", + "it": "PIOVIGGINE FT", + "pt": "CHUVISCO FORTE", + "nl": "ZWARE MOTREG" + } + }, + "LIGHT RAIN": { + "context": "Weather condition: light rain.", + "translations": { + "fr": "PLUIE LEGERE", + "de": "LEICHT. REGEN", + "es": "LLUVIA LEVE", + "it": "PIOGGIA LEGG.", + "pt": "CHUVA FRACA", + "nl": "LICHTE REGEN", + "da": "LET REGN", + "no": "LETT REGN", + "sv": "LÄTT REGN" + } + }, + "RAIN": { + "context": "Weather condition: rain.", + "translations": { + "fr": "PLUIE", + "de": "REGEN", + "es": "LLUVIA", + "it": "PIOGGIA", + "pt": "CHUVA", + "nl": "REGEN", + "da": "REGN", + "no": "REGN", + "sv": "REGN" + } + }, + "HEAVY RAIN": { + "context": "Weather condition: heavy rain.", + "translations": { + "fr": "PLUIE FORTE", + "de": "STARKREGEN", + "es": "LLUVIA FUERTE", + "it": "PIOGGIA FORTE", + "pt": "CHUVA FORTE", + "nl": "ZWARE REGEN", + "da": "KRAFTIG REGN", + "no": "KRAFTIG REGN", + "sv": "KRAFTIGT REGN" + } + }, + "LIGHT FREEZING RAIN": { + "context": "Weather condition: light freezing rain.", + "translations": { + "fr": "PLUIE VERGLAC.", + "de": "L. GEFR. REGEN", + "es": "LLUVIA HELADA", + "it": "PIOGGIA GELATA", + "pt": "CHUVA GELADA", + "nl": "LICHTE IJZEL" + } + }, + "FREEZING RAIN": { + "context": "Weather condition: freezing rain.", + "translations": { + "fr": "PLUIE VERGLAC.", + "de": "GEFRIER-REGEN", + "es": "LLUVIA HELADA", + "it": "PIOGGIA GELATA", + "pt": "CHUVA GELADA", + "nl": "IJZEL" + } + }, + "LIGHT SNOW": { + "context": "Weather condition: light snow.", + "translations": { + "fr": "NEIGE LEGERE", + "de": "LEICHT SCHNEE", + "es": "NIEVE LEVE", + "it": "NEVE LEGGERA", + "pt": "NEVE FRACA", + "nl": "LICHTE SNEEUW", + "da": "LET SNE", + "no": "LETT SNØ", + "sv": "LÄTT SNÖ" + } + }, + "SNOW": { + "context": "Weather condition: snow.", + "translations": { + "fr": "NEIGE", + "de": "SCHNEE", + "es": "NIEVE", + "it": "NEVE", + "pt": "NEVE", + "nl": "SNEEUW", + "da": "SNE", + "no": "SNØ", + "sv": "SNÖ" + } + }, + "HEAVY SNOW": { + "context": "Weather condition: heavy snow.", + "translations": { + "fr": "NEIGE FORTE", + "de": "STARK. SCHNEE", + "es": "NIEVE FUERTE", + "it": "NEVE FORTE", + "pt": "NEVE FORTE", + "nl": "ZWARE SNEEUW", + "da": "KRAFTIG SNE", + "no": "KRAFTIG SNØ", + "sv": "KRAFTIGT SNÖ" + } + }, + "SNOW GRAINS": { + "context": "Weather condition: snow grains.", + "translations": { + "fr": "GRAINS NEIGE", + "de": "SCHNEEGRIESEL", + "es": "GRANIZO NIEVE", + "it": "NEVE GRANUL.", + "pt": "NEVE GRANULAR", + "nl": "KORRELSNEEUW" + } + }, + "RAIN SHOWERS": { + "context": "Weather condition: rain showers.", + "translations": { + "fr": "AVERSES", + "de": "REGENSCHAUER", + "es": "CHUBASCOS", + "it": "ROVESCI", + "pt": "AGUACEIROS", + "nl": "REGENBUIEN" + } + }, + "HEAVY SHOWERS": { + "context": "Weather condition: heavy rain showers.", + "translations": { + "fr": "AVERSES FORTES", + "de": "STARK. SCHAUER", + "es": "CHUBASCOS FTES", + "it": "ROVESCI FORTI", + "pt": "AGUAC. FORTES", + "nl": "ZWARE BUIEN" + } + }, + "SNOW SHOWERS": { + "context": "Weather condition: snow showers.", + "translations": { + "fr": "AVERSES NEIGE", + "de": "SCHNEESCHAUER", + "es": "CHUBASCOS NIEVE", + "it": "ROVESCI NEVE", + "pt": "AGUAC. NEVE", + "nl": "SNEEUWBUIEN" + } + }, + "HEAVY SNOW SHOWERS": { + "context": "Weather condition: heavy snow showers.", + "translations": { + "fr": "AVERSES NEIGE", + "de": "SCHNEESCHAUER", + "es": "CHUBASCOS NIEVE", + "it": "ROVESCI NEVE", + "pt": "AGUAC. NEVE", + "nl": "SNEEUWBUIEN" + } + }, + "THUNDERSTORM": { + "context": "Weather condition: thunderstorm.", + "translations": { + "fr": "ORAGE", + "de": "GEWITTER", + "es": "TORMENTA", + "it": "TEMPORALE", + "pt": "TROVOADA", + "nl": "ONWEER", + "da": "TORDENVEJR", + "no": "TORDENVÆR", + "sv": "ÅSKA" + } + }, + "THUNDER HAIL": { + "context": "Weather condition: thunderstorm with hail.", + "translations": { + "fr": "ORAGE GRELE", + "de": "GEWITTER HAGEL", + "es": "TORM. GRANIZO", + "it": "TEMP. GRANDINE", + "pt": "TROV. GRANIZO", + "nl": "ONWEER HAGEL" + } + }, + "SEVERE TSTORM": { + "context": "Weather condition: severe thunderstorm (abbreviated).", + "translations": { + "fr": "ORAGE VIOLENT", + "de": "SCHW. GEWITTER", + "es": "TORM. FUERTE", + "it": "TEMP. VIOLENTO", + "pt": "TROV. FORTE", + "nl": "ZWAAR ONWEER" + } + }, + "CURRENT CONDITIONS": { + "context": "Generic label for present weather conditions.", + "translations": { + "fr": "CONDITIONS", + "de": "WETTER", + "es": "TIEMPO", + "it": "METEO", + "pt": "TEMPO", + "nl": "WEER", + "da": "VEJR", + "no": "VÆR", + "sv": "VÄDER" + } + }, + "FEELS": { + "context": "Precedes the 'feels like' temperature.", + "translations": { + "fr": "RESSENTI", + "de": "GEFUHLT", + "es": "SENSAC.", + "it": "PERCEP.", + "pt": "SENSAC.", + "nl": "GEVOELD", + "da": "FØLES", + "no": "FØLES", + "sv": "KÄNNS" + } + }, + "FLS": { + "context": "Very short 'feels like' label.", + "translations": { + "fr": "RES", + "de": "GEF", + "es": "SEN", + "it": "PER", + "pt": "SEN", + "nl": "GVL" + } + }, + "AIR QUALITY": { + "context": "Air-quality label/heading.", + "translations": { + "fr": "QUALITE AIR", + "de": "LUFTQUALITAT", + "es": "CALIDAD AIRE", + "it": "QUALITA ARIA", + "pt": "QUALID. AR", + "nl": "LUCHTKWAL.", + "da": "LUFTKVALITET", + "no": "LUFTKVALITET", + "sv": "LUFTKVALITET" + } + }, + "SUN EXPOSURE": { + "context": "UV / sun-exposure label/heading.", + "translations": { + "fr": "EXPO SOLEIL", + "de": "UV-BELASTUNG", + "es": "EXPO SOLAR", + "it": "ESPOS. SOLE", + "pt": "EXPO SOLAR", + "nl": "ZONKRACHT" + } + }, + "SUN UV": { + "context": "Short 'sun UV' label.", + "translations": { + "fr": "UV SOLEIL", + "de": "SONNE UV", + "es": "UV SOLAR", + "it": "UV SOLE", + "pt": "UV SOLAR", + "nl": "ZON UV" + } + }, + "POLLEN": { + "context": "Pollen label/heading.", + "translations": { + "fr": "POLLEN", + "de": "POLLEN", + "es": "POLEN", + "it": "POLLINE", + "pt": "POLEN", + "nl": "POLLEN", + "da": "POLLEN", + "no": "POLLEN", + "sv": "POLLEN" + } + }, + "OVERALL": { + "context": "The 'overall' level in a breakdown.", + "translations": { + "fr": "GLOBAL", + "de": "GESAMT", + "es": "TOTAL", + "it": "TOTALE", + "pt": "GERAL", + "nl": "TOTAAL", + "da": "SAMLET", + "no": "SAMLET", + "sv": "TOTALT" + } + }, + "OVR": { + "context": "Very short 'overall'.", + "translations": { + "fr": "GLB", + "de": "GES", + "es": "TOT", + "it": "TOT", + "pt": "GER", + "nl": "TOT" + } + }, + "GRASS": { + "context": "Grass (e.g. grass pollen).", + "translations": { + "fr": "HERBE", + "de": "GRAS", + "es": "HIERBA", + "it": "ERBA", + "pt": "RELVA", + "nl": "GRAS", + "da": "GRÆS", + "no": "GRESS", + "sv": "GRÄS" + } + }, + "GRS": { + "context": "Very short 'grass'.", + "translations": { + "fr": "HRB", + "de": "GRA", + "es": "HIE", + "it": "ERB", + "pt": "REL", + "nl": "GRS" + } + }, + "TREE": { + "context": "Tree (e.g. tree pollen).", + "translations": { + "fr": "ARBRE", + "de": "BAUM", + "es": "ARBOL", + "it": "ALBERO", + "pt": "ARVORE", + "nl": "BOOM", + "da": "TRÆ", + "no": "TRE", + "sv": "TRÄD" + } + }, + "TRE": { + "context": "Very short 'tree'.", + "translations": { + "fr": "ARB", + "de": "BAU", + "es": "ARB", + "it": "ALB", + "pt": "ARV", + "nl": "BOM" + } + }, + "WEED": { + "context": "Weed (e.g. weed pollen).", + "translations": { + "fr": "HERBACEE", + "de": "UNKRAUT", + "es": "MALEZA", + "it": "ERBACCE", + "pt": "ERVAS", + "nl": "ONKRUID", + "da": "UKRUDT", + "no": "UGRESS", + "sv": "OGRÄS" + } + }, + "WED": { + "context": "Very short 'weed'.", + "translations": { + "fr": "HER", + "de": "UNK", + "es": "MAL", + "it": "ERB", + "pt": "ERV", + "nl": "ONK" + } + }, + "PROV": { + "context": "'Source/provider' label (which data provider).", + "translations": { + "fr": "SRCE", + "de": "QUELLE", + "es": "FUENTE", + "it": "FONTE", + "pt": "FONTE", + "nl": "BRON" + } + }, + "PRV": { + "context": "Very short 'provider'.", + "translations": { + "fr": "SRC", + "de": "QLE", + "es": "FTE", + "it": "FNT", + "pt": "FNT", + "nl": "BRN" + } + }, + "GOOD": { + "context": "Qualitative level: good.", + "translations": { + "fr": "BON", + "de": "GUT", + "es": "BUENA", + "it": "BUONA", + "pt": "BOA", + "nl": "GOED", + "da": "GOD", + "no": "GOD", + "sv": "BRA" + } + }, + "FAIR": { + "context": "Qualitative level: fair (between good and moderate).", + "translations": { + "fr": "CORRECT", + "de": "MASSIG", + "es": "ACEPTABLE", + "it": "DISCRETA", + "pt": "RAZOAVEL", + "nl": "REDELIJK" + } + }, + "MODERATE": { + "context": "Qualitative level: moderate.", + "translations": { + "fr": "MODERE", + "de": "MASSIG", + "es": "MODERADA", + "it": "MODERATA", + "pt": "MODERADA", + "nl": "MATIG", + "da": "MODERAT", + "no": "MODERAT", + "sv": "MÅTTLIG" + } + }, + "POOR": { + "context": "Qualitative level: poor.", + "translations": { + "fr": "MAUVAIS", + "de": "SCHLECHT", + "es": "MALA", + "it": "SCARSA", + "pt": "FRACA", + "nl": "SLECHT", + "da": "DÅRLIG", + "no": "DÅRLIG", + "sv": "DÅLIG" + } + }, + "V.POOR": { + "context": "Qualitative level: very poor (abbreviated).", + "translations": { + "fr": "TRES MAUVAIS", + "de": "SEHR SCHL.", + "es": "MUY MALA", + "it": "PESSIMA", + "pt": "MUITO FRACA", + "nl": "ZEER SLECHT" + } + }, + "MOD": { + "context": "Qualitative level: moderate (abbreviated).", + "translations": { + "fr": "MOYEN", + "de": "MITTEL", + "es": "MODER.", + "it": "MEDIO", + "pt": "MODER.", + "nl": "MATIG" + } + }, + "USG": { + "context": "Air quality 'unhealthy for sensitive groups' (abbreviated).", + "translations": { + "fr": "SENSIBLES", + "de": "EMPFINDL.", + "es": "SENSIBLES", + "it": "SENSIBILI", + "pt": "SENSIVEIS", + "nl": "GEVOELIG" + } + }, + "UNHEALTHY": { + "context": "Qualitative level: unhealthy.", + "translations": { + "fr": "MALSAIN", + "de": "UNGESUND", + "es": "INSALUBRE", + "it": "MALSANO", + "pt": "INSALUBRE", + "nl": "ONGEZOND" + } + }, + "V.UNHLTHY": { + "context": "Qualitative level: very unhealthy (abbreviated).", + "translations": { + "fr": "TRES MALSAIN", + "de": "SEHR UNGESUND", + "es": "MUY INSALUBRE", + "it": "MOLTO MALSANO", + "pt": "MUITO INSALUB", + "nl": "ZEER ONGEZOND" + } + }, + "HAZARDOUS": { + "context": "Qualitative level: hazardous (worst).", + "translations": { + "fr": "DANGEREUX", + "de": "GEFAHRLICH", + "es": "PELIGROSA", + "it": "PERICOLOSA", + "pt": "PERIGOSA", + "nl": "GEVAARLIJK" + } + }, + "LOW": { + "context": "Qualitative level: low.", + "translations": { + "fr": "FAIBLE", + "de": "NIEDRIG", + "es": "BAJO", + "it": "BASSO", + "pt": "BAIXO", + "nl": "LAAG", + "da": "LAV", + "no": "LAV", + "sv": "LÅG" + } + }, + "HIGH": { + "context": "Qualitative level: high.", + "translations": { + "fr": "ELEVE", + "de": "HOCH", + "es": "ALTO", + "it": "ALTO", + "pt": "ALTO", + "nl": "HOOG", + "da": "HØJ", + "no": "HØY", + "sv": "HÖG" + } + }, + "V.HIGH": { + "context": "Qualitative level: very high (abbreviated).", + "translations": { + "fr": "TRES ELEVE", + "de": "SEHR HOCH", + "es": "MUY ALTO", + "it": "MOLTO ALTO", + "pt": "MUITO ALTO", + "nl": "ZEER HOOG" + } + }, + "EXTREME": { + "context": "Qualitative level: extreme.", + "translations": { + "fr": "EXTREME", + "de": "EXTREM", + "es": "EXTREMO", + "it": "ESTREMO", + "pt": "EXTREMO", + "nl": "EXTREEM", + "da": "EKSTREM", + "no": "EKSTREM", + "sv": "EXTREM" + } + }, + "NONE": { + "context": "Level 'none' / zero.", + "translations": { + "fr": "AUCUN", + "de": "KEIN", + "es": "NINGUNO", + "it": "NESSUNO", + "pt": "NENHUM", + "nl": "GEEN", + "da": "INGEN", + "no": "INGEN", + "sv": "INGEN" + } + } + }, + "metals": { + "GOLD": { + "context": "Precious metal: gold.", + "translations": { + "fr": "OR", + "de": "GOLD", + "es": "ORO", + "it": "ORO", + "pt": "OURO", + "nl": "GOUD", + "da": "GULD", + "no": "GULL", + "sv": "GULD" + } + }, + "SILVER": { + "context": "Precious metal: silver.", + "translations": { + "fr": "ARGENT", + "de": "SILBER", + "es": "PLATA", + "it": "ARGENTO", + "pt": "PRATA", + "nl": "ZILVER", + "da": "SØLV", + "no": "SØLV", + "sv": "SILVER" + } + }, + "PLATINUM": { + "context": "Precious metal: platinum.", + "translations": { + "fr": "PLATINE", + "de": "PLATIN", + "es": "PLATINO", + "it": "PLATINO", + "pt": "PLATINA", + "nl": "PLATINA", + "da": "PLATIN", + "no": "PLATINA", + "sv": "PLATINA" + } + }, + "PALLADIUM": { + "context": "Precious metal: palladium.", + "translations": { + "fr": "PALLADIUM", + "de": "PALLADIUM", + "es": "PALADIO", + "it": "PALLADIO", + "pt": "PALADIO", + "nl": "PALLADIUM", + "da": "PALLADIUM", + "no": "PALLADIUM", + "sv": "PALLADIUM" + } + }, + "SPOT PRICE": { + "context": "Label for a current spot (market) price.", + "translations": { + "fr": "COURS", + "de": "KURS", + "es": "PRECIO", + "it": "PREZZO", + "pt": "PRECO", + "nl": "KOERS", + "da": "SPOTPRIS", + "no": "SPOTPRIS", + "sv": "SPOTPRIS" + } + } + }, + "tides": { + "TIDES": { + "context": "Tides heading.", + "translations": { + "fr": "MAREES", + "de": "GEZEITEN", + "es": "MAREAS", + "it": "MAREE", + "pt": "MARES", + "nl": "GETIJDEN", + "da": "TIDEVAND", + "no": "TIDEVANN", + "sv": "TIDVATTEN" + } + }, + "HIGH TIDE": { + "context": "High tide.", + "translations": { + "fr": "MAREE HAUTE", + "de": "FLUT", + "es": "PLEAMAR", + "it": "ALTA MAREA", + "pt": "PREIA-MAR", + "nl": "VLOED", + "da": "HØJVANDE", + "no": "HØYVANN", + "sv": "HÖGVATTEN" + } + }, + "LOW TIDE": { + "context": "Low tide.", + "translations": { + "fr": "MAREE BASSE", + "de": "EBBE", + "es": "BAJAMAR", + "it": "BASSA MAREA", + "pt": "BAIXA-MAR", + "nl": "EB", + "da": "LAVVANDE", + "no": "LAVVANN", + "sv": "LÅGVATTEN" + } + }, + "CHECK STATION": { + "context": "Prompt to pick/verify a measurement station.", + "translations": { + "fr": "VERIF STATION", + "de": "STATION PRUEF", + "es": "VER ESTACION", + "it": "VERIF STAZIONE", + "pt": "VER ESTACAO", + "nl": "STATION CHECK" + } + }, + "HIGH": { + "context": "High tide (short label).", + "translations": { + "fr": "HAUTE", + "de": "HOCH", + "es": "ALTA", + "it": "ALTA", + "pt": "ALTA", + "nl": "HOOG", + "da": "HØJ", + "no": "HØY", + "sv": "HÖG" + } + }, + "LOW": { + "context": "Low tide (short label).", + "translations": { + "fr": "BASSE", + "de": "NIEDRIG", + "es": "BAJA", + "it": "BASSA", + "pt": "BAIXA", + "nl": "LAAG", + "da": "LAV", + "no": "LAV", + "sv": "LÅG" + } + } + }, + "aurora": { + "AURORA": { + "context": "Aurora (northern/southern lights) heading.", + "translations": { + "fr": "AURORE", + "de": "POLARLICHT", + "es": "AURORA", + "it": "AURORA", + "pt": "AURORA", + "nl": "NOORDERLICHT" + } + }, + "QUIET": { + "context": "Activity level: quiet/calm.", + "translations": { + "fr": "CALME", + "de": "RUHIG", + "es": "TRANQUILO", + "it": "QUIETE", + "pt": "CALMO", + "nl": "RUSTIG" + } + }, + "UNSETTLED": { + "context": "Activity level: unsettled.", + "translations": { + "fr": "AGITE", + "de": "UNRUHIG", + "es": "INESTABLE", + "it": "INSTABILE", + "pt": "INSTAVEL", + "nl": "ONRUSTIG" + } + }, + "MINOR STORM": { + "context": "Storm level: minor.", + "translations": { + "fr": "ORAGE MINEUR", + "de": "KL. STURM", + "es": "TORM. MENOR", + "it": "TEMP. MINORE", + "pt": "TORM. MENOR", + "nl": "KL. STORM" + } + }, + "STRONG STORM": { + "context": "Storm level: strong.", + "translations": { + "fr": "ORAGE FORT", + "de": "STARK. STURM", + "es": "TORM. FUERTE", + "it": "TEMP. FORTE", + "pt": "TORM. FORTE", + "nl": "ZWARE STORM" + } + }, + "SEVERE STORM": { + "context": "Storm level: severe.", + "translations": { + "fr": "ORAGE SEVERE", + "de": "SCHW. STURM", + "es": "TORM. SEVERA", + "it": "TEMP. SEVERO", + "pt": "TORM. SEVERA", + "nl": "HEVIGE STORM" + } + } + }, + "space": { + "NEXT LAUNCH": { + "context": "'Next launch' label.", + "translations": { + "fr": "PROCH. LANCEMENT", + "de": "NAECHST. START", + "es": "PROX. LANZAMIENTO", + "it": "PROSS. LANCIO", + "pt": "PROX. LANCAMENTO", + "nl": "VOLGENDE START" + } + }, + "MISSION": { + "context": "'Mission' label (e.g. a mission name).", + "translations": { + "fr": "MISSION", + "de": "MISSION", + "es": "MISION", + "it": "MISSIONE", + "pt": "MISSAO", + "nl": "MISSIE", + "da": "MISSION", + "no": "OPPDRAG", + "sv": "UPPDRAG" + } + }, + "IMMINENT": { + "context": "About to happen (very soon).", + "translations": { + "fr": "IMMINENT", + "de": "UNMITTELBAR", + "es": "INMINENTE", + "it": "IMMINENTE", + "pt": "IMINENTE", + "nl": "OP KOMST", + "da": "SNART", + "no": "SNART", + "sv": "SNART" + } + }, + "SCHEDULED": { + "context": "Planned for a set time.", + "translations": { + "fr": "PREVU", + "de": "GEPLANT", + "es": "PROGRAMADO", + "it": "PREVISTO", + "pt": "AGENDADO", + "nl": "GEPLAND", + "da": "PLANLAGT", + "no": "PLANLAGT", + "sv": "PLANERAD" + } + }, + "NONE": { + "context": "No launch scheduled.", + "translations": { + "fr": "AUCUN", + "de": "KEIN", + "es": "NINGUNO", + "it": "NESSUNO", + "pt": "NENHUM", + "nl": "GEEN", + "da": "INGEN", + "no": "INGEN", + "sv": "INGEN" + } + }, + "IN SPACE": { + "context": "Suffix after a count: 'N people in space'.", + "translations": { + "fr": "DANS L'ESPACE", + "de": "IM WELTALL", + "es": "EN EL ESPACIO", + "it": "NELLO SPAZIO", + "pt": "NO ESPAÇO", + "nl": "IN DE RUIMTE", + "da": "I RUMMET", + "no": "I ROMMET", + "sv": "I RYMDEN" + } + } + }, + "sports": { + "NEXT GP": { + "context": "'Next Grand Prix' (short).", + "translations": { + "fr": "PROCHAIN GP", + "de": "NAECHSTER GP", + "es": "PROXIMO GP", + "it": "PROSSIMO GP", + "pt": "PROXIMO GP", + "nl": "VOLGENDE GP" + } + }, + "NEXT GRAND PRIX": { + "context": "'Next Grand Prix'.", + "translations": { + "fr": "PROCHAIN GP", + "de": "NAECHSTER GP", + "es": "PROXIMO GP", + "it": "PROSSIMO GP", + "pt": "PROXIMO GP", + "nl": "VOLGENDE GP" + } + }, + "RACE WEEKEND": { + "context": "'Race weekend' label.", + "translations": { + "fr": "WEEKEND COURSE", + "de": "RENN-WOCHENENDE", + "es": "FIN DE SEMANA", + "it": "WEEKEND GARA", + "pt": "FIM DE SEMANA", + "nl": "RACEWEEKEND" + } + }, + "SEASON": { + "context": "'Season' label (e.g. a sports season).", + "translations": { + "fr": "SAISON", + "de": "SAISON", + "es": "TEMPORADA", + "it": "STAGIONE", + "pt": "TEMPORADA", + "nl": "SEIZOEN", + "da": "SÆSON", + "no": "SESONG", + "sv": "SÄSONG" + } + }, + "OVER": { + "context": "Something has ended / is over.", + "translations": { + "fr": "TERMINEE", + "de": "VORBEI", + "es": "TERMINADA", + "it": "FINITA", + "pt": "TERMINADA", + "nl": "VOORBIJ", + "da": "SLUT", + "no": "OVER", + "sv": "SLUT" + } + }, + "CHAMPIONSHIP": { + "context": "'Championship' label.", + "translations": { + "fr": "CHAMPIONNAT", + "de": "MEISTERSCHAFT", + "es": "CAMPEONATO", + "it": "CAMPIONATO", + "pt": "CAMPEONATO", + "nl": "KAMPIOENSCHAP" + } + }, + "LEADER": { + "context": "The leader / person in first place.", + "translations": { + "fr": "LEADER", + "de": "FUEHRENDER", + "es": "LIDER", + "it": "LEADER", + "pt": "LIDER", + "nl": "LEIDER", + "da": "FØRER", + "no": "LEDER", + "sv": "LEDARE" + } + }, + "POINTS": { + "context": "'Points' (a score).", + "translations": { + "fr": "POINTS", + "de": "PUNKTE", + "es": "PUNTOS", + "it": "PUNTI", + "pt": "PONTOS", + "nl": "PUNTEN", + "da": "POINT", + "no": "POENG", + "sv": "POÄNG" + } + }, + "PTS": { + "context": "Abbreviation of 'points'.", + "translations": { + "fr": "PTS", + "de": "PKT", + "es": "PTS", + "it": "PTI", + "pt": "PTS", + "nl": "PNT" + } + }, + "FINAL": { + "context": "A finished game (final score).", + "translations": { + "fr": "TERMINÉ", + "de": "BEENDET", + "es": "FINAL", + "it": "FINALE", + "pt": "FINAL", + "nl": "AFGELOPEN", + "da": "SLUT", + "no": "SLUTT", + "sv": "SLUT" + } + }, + "LIVE": { + "context": "A game in progress.", + "translations": { + "fr": "EN DIRECT", + "de": "LIVE", + "es": "EN VIVO", + "it": "IN DIRETTA", + "pt": "AO VIVO", + "nl": "LIVE", + "da": "LIVE", + "no": "DIREKTE", + "sv": "DIREKT" + } + }, + "UPCOMING": { + "context": "A game not yet started.", + "translations": { + "fr": "À VENIR", + "de": "DEMNÄCHST", + "es": "PRÓXIMO", + "it": "IN ARRIVO", + "pt": "EM BREVE", + "nl": "BINNENKORT", + "da": "KOMMENDE", + "no": "KOMMENDE", + "sv": "KOMMANDE" + } + }, + "SCHEDULED": { + "context": "A game/event scheduled for later.", + "translations": { + "fr": "PRÉVU", + "de": "GEPLANT", + "es": "PROGRAMADO", + "it": "PREVISTO", + "pt": "AGENDADO", + "nl": "GEPLAND", + "da": "PLANLAGT", + "no": "PLANLAGT", + "sv": "PLANERAD" + } + }, + "NO GAMES": { + "context": "No games found.", + "translations": { + "fr": "AUCUN MATCH", + "de": "KEINE SPIELE", + "es": "SIN PARTIDOS", + "it": "NESSUNA PARTITA", + "pt": "SEM JOGOS", + "nl": "GEEN DUELS", + "da": "INGEN KAMPE", + "no": "INGEN KAMPER", + "sv": "INGA MATCHER" + } + }, + "NO TEAMS": { + "context": "No teams configured.", + "translations": { + "fr": "AUCUNE ÉQUIPE", + "de": "KEINE TEAMS", + "es": "SIN EQUIPOS", + "it": "NESSUNA SQUADRA", + "pt": "SEM EQUIPES", + "nl": "GEEN TEAMS", + "da": "INGEN HOLD", + "no": "INGEN LAG", + "sv": "INGA LAG" + } + }, + "NO EVENT": { + "context": "No event this week.", + "translations": { + "fr": "AUCUN EVENT", + "de": "KEIN EVENT", + "es": "SIN EVENTO", + "it": "NESSUN EVENTO", + "pt": "SEM EVENTO", + "nl": "GEEN EVENT", + "da": "INGEN EVENT", + "no": "INGEN EVENT", + "sv": "INGET EVENT" + } + }, + "NO LEADERS": { + "context": "No leaderboard available.", + "translations": { + "fr": "AUCUN LEADER", + "de": "KEINE FÜHRENDEN", + "es": "SIN LÍDERES", + "it": "NESSUN LEADER", + "pt": "SEM LÍDERES", + "nl": "GEEN LEIDERS", + "da": "INGEN LEDERE", + "no": "INGEN LEDERE", + "sv": "INGA LEDARE" + } + }, + "NO FIGHTS": { + "context": "No fights scheduled.", + "translations": { + "fr": "AUCUN COMBAT", + "de": "KEINE KÄMPFE", + "es": "SIN COMBATES", + "it": "NESSUN INCONTRO", + "pt": "SEM LUTAS", + "nl": "GEEN GEVECHTEN", + "da": "INGEN KAMPE", + "no": "INGEN KAMPER", + "sv": "INGA MATCHER" + } + }, + "CONFIGURED": { + "context": "'... configured' (paired with NO TEAMS).", + "translations": { + "fr": "CONFIGURÉE", + "de": "EINGERICHTET", + "es": "CONFIGURADO", + "it": "CONFIGURATO", + "pt": "CONFIGURADO", + "nl": "INGESTELD", + "da": "OPSAT", + "no": "SATT OPP", + "sv": "KONFIG." + } + }, + "FOUND": { + "context": "'... found' (paired with NO GAMES).", + "translations": { + "fr": "TROUVÉ", + "de": "GEFUNDEN", + "es": "ENCONTRADO", + "it": "TROVATO", + "pt": "ENCONTRADO", + "nl": "GEVONDEN", + "da": "FUNDET", + "no": "FUNNET", + "sv": "HITTAT" + } + }, + "THIS WEEK": { + "context": "'this week' timeframe.", + "translations": { + "fr": "CETTE SEMAINE", + "de": "DIESE WOCHE", + "es": "ESTA SEMANA", + "it": "QUESTA SETT.", + "pt": "ESTA SEMANA", + "nl": "DEZE WEEK", + "da": "DENNE UGE", + "no": "DENNE UKEN", + "sv": "DENNA VECKA" + } + }, + "ALL": { + "context": "Filter label: all games.", + "translations": { + "fr": "TOUS", + "de": "ALLE", + "es": "TODOS", + "it": "TUTTI", + "pt": "TODOS", + "nl": "ALLE", + "da": "ALLE", + "no": "ALLE", + "sv": "ALLA" + } + }, + "NOTHING": { + "context": "'nothing followed' empty state.", + "translations": { + "fr": "RIEN", + "de": "NICHTS", + "es": "NADA", + "it": "NIENTE", + "pt": "NADA", + "nl": "NIETS", + "da": "INTET", + "no": "INGENTING", + "sv": "INGET" + } + }, + "FOLLOWED": { + "context": "'... followed' (paired with NOTHING).", + "translations": { + "fr": "SUIVI", + "de": "GEFOLGT", + "es": "SEGUIDO", + "it": "SEGUITO", + "pt": "SEGUIDO", + "nl": "GEVOLGD", + "da": "FULGT", + "no": "FULGT", + "sv": "FÖLJT" + } + } + }, + "sentiment": { + "FEAR": { + "context": "Sentiment/index classification: fear.", + "translations": { + "fr": "PEUR", + "de": "ANGST", + "es": "MIEDO", + "it": "PAURA", + "pt": "MEDO", + "nl": "ANGST", + "da": "FRYGT", + "no": "FRYKT", + "sv": "RÄDSLA" + } + }, + "GREED": { + "context": "Sentiment/index classification: greed.", + "translations": { + "fr": "AVIDITE", + "de": "GIER", + "es": "CODICIA", + "it": "AVIDITA", + "pt": "GANANCIA", + "nl": "HEBZUCHT", + "da": "GRÅDIGHED", + "no": "GRÅDIGHET", + "sv": "GIRIGHET" + } + }, + "NEUTRAL": { + "context": "Sentiment/index classification: neutral.", + "translations": { + "fr": "NEUTRE", + "de": "NEUTRAL", + "es": "NEUTRAL", + "it": "NEUTRO", + "pt": "NEUTRO", + "nl": "NEUTRAAL", + "da": "NEUTRAL", + "no": "NØYTRAL", + "sv": "NEUTRAL" + } + }, + "EXTREME FEAR": { + "context": "Sentiment/index classification: extreme fear.", + "translations": { + "fr": "PEUR EXTREME", + "de": "EXTR. ANGST", + "es": "MIEDO EXTREMO", + "it": "PAURA ESTREMA", + "pt": "MEDO EXTREMO", + "nl": "EXTR. ANGST" + } + }, + "EXTREME GREED": { + "context": "Sentiment/index classification: extreme greed.", + "translations": { + "fr": "AVIDITE EXTREME", + "de": "EXTREME GIER", + "es": "CODICIA EXTREMA", + "it": "AVIDITA ESTREMA", + "pt": "GANANCIA EXTREMA", + "nl": "EXTREME HEBZUCHT" + } + } + }, + "crypto": { + "NO COINS": { + "context": "No cryptocurrencies configured.", + "translations": { + "fr": "AUCUNE CRYPTO", + "de": "KEINE COINS", + "es": "SIN MONEDAS", + "it": "NESSUNA CRIPTO", + "pt": "SEM MOEDAS", + "nl": "GEEN MUNTEN", + "da": "INGEN MØNTER", + "no": "INGEN MYNTER", + "sv": "INGA MYNT" + } + } + }, + "stocks": { + "NO TICKERS": { + "context": "No stock tickers configured.", + "translations": { + "fr": "AUCUN TITRE", + "de": "KEINE AKTIEN", + "es": "SIN VALORES", + "it": "NESSUN TITOLO", + "pt": "SEM AÇÕES", + "nl": "GEEN AANDELEN", + "da": "INGEN AKTIER", + "no": "INGEN AKSJER", + "sv": "INGA AKTIER" + } + } + }, + "holidays": { + "NEXT HOLIDAY": { + "context": "'Next holiday' label.", + "translations": { + "fr": "PROCHAIN CONGE", + "de": "NAECHSTER FEIERTAG", + "es": "PROX. FESTIVO", + "it": "PROSS. FESTA", + "pt": "PROX. FERIADO", + "nl": "VOLGENDE FEESTDAG", + "da": "NÆSTE HELLIGDAG", + "no": "NESTE HELLIGDAG", + "sv": "NÄSTA HELGDAG" + } + } + }, + "content": { + "FEATURED": { + "context": "'Featured' item label (e.g. a featured article).", + "translations": { + "fr": "A LA UNE", + "de": "ARTIKEL", + "es": "DESTACADO", + "it": "IN VETRINA", + "pt": "DESTAQUE", + "nl": "UITGELICHT", + "da": "FREMHÆVET", + "no": "FREMHEVET", + "sv": "UTVALD" + } + }, + "MOST READ": { + "context": "'Most read' item label.", + "translations": { + "fr": "TOP LUS", + "de": "MEISTGELESEN", + "es": "MAS LEIDO", + "it": "PIU LETTI", + "pt": "MAIS LIDO", + "nl": "MEEST GELEZEN", + "da": "MEST LÆST", + "no": "MEST LEST", + "sv": "MEST LÄST" + } + } + }, + "vocab": { + "WORD OF THE DAY": { + "context": "'Word of the day' heading.", + "translations": { + "fr": "MOT DU JOUR", + "de": "WORT DES TAGES", + "es": "PALABRA DEL DIA", + "it": "PAROLA DEL GIORNO", + "pt": "PALAVRA DO DIA", + "nl": "WOORD VAN DE DAG", + "da": "DAGENS ORD", + "no": "DAGENS ORD", + "sv": "DAGENS ORD" + } + } + } + }, + "holidays": { + "new year's day": { + "context": "Public-holiday name; shown when the source only provides English ('new year's day').", + "translations": { + "fr": "Jour de l'An", + "de": "Neujahr", + "es": "Año Nuevo", + "it": "Capodanno", + "pt": "Ano Novo", + "nl": "Nieuwjaar", + "da": "Nytårsdag", + "no": "Første nyttårsdag", + "sv": "Nyårsdagen" + } + }, + "epiphany": { + "context": "Public-holiday name; shown when the source only provides English ('epiphany').", + "translations": { + "fr": "Épiphanie", + "de": "Heilige Drei Könige", + "es": "Epifanía", + "it": "Epifania", + "pt": "Dia de Reis", + "nl": "Driekoningen", + "da": "Helligtrekonger", + "no": "Helligtrekongersdag", + "sv": "Trettondedag jul" + } + }, + "good friday": { + "context": "Public-holiday name; shown when the source only provides English ('good friday').", + "translations": { + "fr": "Vendredi Saint", + "de": "Karfreitag", + "es": "Viernes Santo", + "it": "Venerdì Santo", + "pt": "Sexta-feira Santa", + "nl": "Goede Vrijdag", + "da": "Langfredag", + "no": "Langfredag", + "sv": "Långfredagen" + } + }, + "easter sunday": { + "context": "Public-holiday name; shown when the source only provides English ('easter sunday').", + "translations": { + "fr": "Pâques", + "de": "Ostersonntag", + "es": "Domingo de Pascua", + "it": "Pasqua", + "pt": "Páscoa", + "nl": "Eerste Paasdag", + "da": "Påskedag", + "no": "Første påskedag", + "sv": "Påskdagen" + } + }, + "easter monday": { + "context": "Public-holiday name; shown when the source only provides English ('easter monday').", + "translations": { + "fr": "Lundi de Pâques", + "de": "Ostermontag", + "es": "Lunes de Pascua", + "it": "Lunedì dell'Angelo", + "pt": "Segunda de Páscoa", + "nl": "Tweede Paasdag", + "da": "2. påskedag", + "no": "Andre påskedag", + "sv": "Annandag påsk" + } + }, + "labour day": { + "context": "Public-holiday name; shown when the source only provides English ('labour day').", + "translations": { + "fr": "Fête du Travail", + "de": "Tag der Arbeit", + "es": "Día del Trabajo", + "it": "Festa del Lavoro", + "pt": "Dia do Trabalhador", + "nl": "Dag van de Arbeid", + "da": "1. maj", + "no": "Arbeidernes dag", + "sv": "Första maj" + } + }, + "labor day": { + "context": "Public-holiday name; shown when the source only provides English ('labor day').", + "translations": { + "fr": "Fête du Travail", + "de": "Tag der Arbeit", + "es": "Día del Trabajo", + "it": "Festa del Lavoro", + "pt": "Dia do Trabalhador", + "nl": "Dag van de Arbeid", + "da": "1. maj", + "no": "Arbeidernes dag", + "sv": "Första maj" + } + }, + "ascension day": { + "context": "Public-holiday name; shown when the source only provides English ('ascension day').", + "translations": { + "fr": "Ascension", + "de": "Christi Himmelfahrt", + "es": "Ascensión", + "it": "Ascensione", + "pt": "Ascensão", + "nl": "Hemelvaart", + "da": "Kristi himmelfartsdag", + "no": "Kristi himmelfartsdag", + "sv": "Kristi himmelsfärdsdag" + } + }, + "whit sunday": { + "context": "Public-holiday name; shown when the source only provides English ('whit sunday').", + "translations": { + "fr": "Pentecôte", + "de": "Pfingstsonntag", + "es": "Pentecostés", + "it": "Pentecoste", + "pt": "Pentecostes", + "nl": "Eerste Pinksterdag", + "da": "Pinsedag", + "no": "Første pinsedag", + "sv": "Pingstdagen" + } + }, + "whit monday": { + "context": "Public-holiday name; shown when the source only provides English ('whit monday').", + "translations": { + "fr": "Lundi de Pentecôte", + "de": "Pfingstmontag", + "es": "Lunes de Pentecostés", + "it": "Lunedì di Pentecoste", + "pt": "Segunda de Pentecostes", + "nl": "Tweede Pinksterdag", + "da": "2. pinsedag", + "no": "Andre pinsedag", + "sv": "Annandag pingst" + } + }, + "corpus christi": { + "context": "Public-holiday name; shown when the source only provides English ('corpus christi').", + "translations": { + "fr": "Fête-Dieu", + "de": "Fronleichnam", + "es": "Corpus Christi", + "it": "Corpus Domini", + "pt": "Corpo de Deus", + "nl": "Sacramentsdag" + } + }, + "assumption day": { + "context": "Public-holiday name; shown when the source only provides English ('assumption day').", + "translations": { + "fr": "Assomption", + "de": "Mariä Himmelfahrt", + "es": "Asunción", + "it": "Assunzione", + "pt": "Assunção", + "nl": "Maria-Tenhemelopneming" + } + }, + "all saints' day": { + "context": "Public-holiday name; shown when the source only provides English ('all saints' day').", + "translations": { + "fr": "Toussaint", + "de": "Allerheiligen", + "es": "Todos los Santos", + "it": "Ognissanti", + "pt": "Todos os Santos", + "nl": "Allerheiligen" + } + }, + "christmas day": { + "context": "Public-holiday name; shown when the source only provides English ('christmas day').", + "translations": { + "fr": "Noël", + "de": "Weihnachten", + "es": "Navidad", + "it": "Natale", + "pt": "Natal", + "nl": "Kerstmis", + "da": "Juledag", + "no": "Første juledag", + "sv": "Juldagen" + } + }, + "st. stephen's day": { + "context": "Public-holiday name; shown when the source only provides English ('st. stephen's day').", + "translations": { + "fr": "Saint-Étienne", + "de": "Stefanitag", + "es": "San Esteban", + "it": "Santo Stefano", + "pt": "Dia de Santo Estêvão", + "nl": "Tweede Kerstdag", + "da": "2. juledag", + "no": "Andre juledag", + "sv": "Annandag jul" + } + }, + "boxing day": { + "context": "Public-holiday name; shown when the source only provides English ('boxing day').", + "translations": { + "fr": "Lendemain de Noël", + "de": "Zweiter Weihnachtsfeiertag", + "es": "San Esteban", + "it": "Santo Stefano", + "pt": "Boxing Day", + "nl": "Tweede Kerstdag", + "da": "2. juledag", + "no": "Andre juledag", + "sv": "Annandag jul" + } + }, + "canada day": { + "context": "Public-holiday name; shown when the source only provides English ('canada day').", + "translations": { + "fr": "Fête du Canada" + } + }, + "victoria day": { + "context": "Public-holiday name; shown when the source only provides English ('victoria day').", + "translations": { + "fr": "Journée des Patriotes" + } + }, + "thanksgiving": { + "context": "Public-holiday name; shown when the source only provides English ('thanksgiving').", + "translations": { + "fr": "Action de grâce" + } + }, + "remembrance day": { + "context": "Public-holiday name; shown when the source only provides English ('remembrance day').", + "translations": { + "fr": "Jour du Souvenir" + } + }, + "family day": { + "context": "Public-holiday name; shown when the source only provides English ('family day').", + "translations": { + "fr": "Jour de la famille" + } + }, + "civic holiday": { + "context": "Public-holiday name; shown when the source only provides English ('civic holiday').", + "translations": { + "fr": "Congé civique" + } + }, + "national holiday": { + "context": "Public-holiday name; shown when the source only provides English ('national holiday').", + "translations": { + "fr": "Fête nationale" + } + }, + "national day for truth and reconciliation": { + "context": "Public-holiday name; shown when the source only provides English ('national day for truth and reconciliation').", + "translations": { + "fr": "Journée de la vérité et réconciliation" + } + }, + "saint-jean-baptiste day": { + "context": "Public-holiday name; shown when the source only provides English ('saint-jean-baptiste day').", + "translations": { + "fr": "Fête nationale du Québec" + } + } + }, + "base_currency": { + "en": "USD", + "en-us": "USD", + "en-gb": "GBP", + "en-au": "AUD", + "fr": "EUR", + "de": "EUR", + "es": "EUR", + "it": "EUR", + "pt": "EUR", + "nl": "EUR", + "da": "DKK", + "no": "NOK", + "sv": "SEK", + "fi": "EUR", + "is": "ISK", + "ga": "EUR", + "ca": "EUR", + "gl": "EUR", + "eu": "EUR", + "et": "EUR", + "af": "ZAR", + "id": "IDR", + "ms": "MYR", + "sw": "KES", + "en-ca": "CAD", + "fr-ca": "CAD", + "fr-be": "EUR", + "fr-ch": "CHF", + "de-at": "EUR", + "de-ch": "CHF", + "es-mx": "MXN", + "es-ar": "ARS", + "it-ch": "CHF", + "pt-br": "BRL", + "nl-be": "EUR" + }, + "country": { + "en": "US", + "en-us": "US", + "en-gb": "GB", + "en-au": "AU", + "fr": "FR", + "de": "DE", + "es": "ES", + "it": "IT", + "pt": "PT", + "nl": "NL", + "da": "DK", + "no": "NO", + "sv": "SE", + "fi": "FI", + "is": "IS", + "ga": "IE", + "ca": "ES", + "gl": "ES", + "eu": "ES", + "et": "EE", + "af": "ZA", + "id": "ID", + "ms": "MY", + "sw": "KE", + "en-ca": "CA", + "fr-ca": "CA", + "fr-be": "BE", + "fr-ch": "CH", + "de-at": "AT", + "de-ch": "CH", + "es-mx": "MX", + "es-ar": "AR", + "it-ch": "CH", + "pt-br": "BR", + "nl-be": "BE" + } +} diff --git a/server/location.py b/server/location.py new file mode 100644 index 0000000..c42599d --- /dev/null +++ b/server/location.py @@ -0,0 +1,111 @@ +"""Resolve the configured global location to coordinates, country and currency +(keyless: Nominatim). + +This is the single place the app geocodes the configured location. Both the weather +helper and the ``get_location`` helper need the *same* location, so both go through +``coordinates()`` here — cached, one Nominatim lookup instead of one per caller. It +lets currency/holiday apps key off *where you are* rather than your language (the +language can't tell France (EUR) from Canada (CAD) or Switzerland (CHF)). +""" + +import re + +# Catalog globals this helper draws on (named in the app dialog's "also uses" hint). +GLOBAL_KEYS = ["location_precise", "zip_code"] + +_UA = {"User-Agent": "splitflap-os/1.0"} +_geo_cache: dict = {} # rounded (lat, lon) -> {"country", "subdivision"} +_coord_cache: dict = {} # geocode query string -> (lat, lon, CITY) + + +def _currency_for(country): + """ISO 4217 currency for an ISO 3166 country, from babel's CLDR data (a project + dependency). Returns None if unknown — callers then fall back to the language's + default currency (i18n.base_currency).""" + if not country: + return None + try: + from babel.numbers import get_territory_currencies + cur = get_territory_currencies(country.upper()) # current tender per CLDR + return cur[0] if cur else None + except Exception: + return None + + +def coordinates(settings): + """``(lat, lon, CITY)`` for the configured location: the precise coordinates if + set, else a geocode of the ZIP/postcode/city. Returns ``None`` when nothing is + configured. The forward geocode is cached, so weather and get_location share it.""" + lat = str(settings.get("location_lat", "") or "").strip() + lon = str(settings.get("location_lon", "") or "").strip() + name = str(settings.get("location_name", "") or "").strip() + if lat and lon: + try: + city = name.split(",")[0].strip().upper() if name else "LOCATION" + return float(lat), float(lon), city + except ValueError: + pass + query = str(settings.get("zip_code", "") or "").strip() + if not query: + return None + if query in _coord_cache: + return _coord_cache[query] + try: + import requests + params = {"q": query, "format": "json", "limit": 1, "addressdetails": 1} + if re.fullmatch(r"\d{5}", query): # a US ZIP — 02118 also exists abroad + params["countrycodes"] = "us" + geo = requests.get("https://nominatim.openstreetmap.org/search", + params=params, headers=_UA, timeout=6).json() + if geo: + addr = geo[0].get("address", {}) + city = (addr.get("city") or addr.get("town") or addr.get("village") + or addr.get("municipality") or addr.get("county") + or geo[0].get("display_name", query).split(",")[0]).strip().upper() + result = (float(geo[0]["lat"]), float(geo[0]["lon"]), city) + _coord_cache[query] = result + return result + except Exception: + pass + return None + + +def _geo(settings): + """Reverse-geocode the configured location to ``{country, subdivision}``, cached. + subdivision is the ISO 3166-2 code (e.g. 'CA-QC' for Quebec) or None.""" + coords = coordinates(settings) + if not coords: + return {"country": None, "subdivision": None} + lat, lon, _city = coords + key = (round(lat, 2), round(lon, 2)) + if key in _geo_cache: + return _geo_cache[key] + out = {"country": None, "subdivision": None} + try: + import requests + r = requests.get("https://nominatim.openstreetmap.org/reverse", + params={"lat": lat, "lon": lon, "format": "json", "zoom": 5}, + headers=_UA, timeout=6).json() + addr = r.get("address") or {} + out["country"] = str(addr.get("country_code") or "").upper()[:2] or None + sub = str(addr.get("ISO3166-2-lvl4") or addr.get("ISO3166-2-lvl6") or "").upper() + out["subdivision"] = sub or None + if out["country"]: + _geo_cache[key] = out + except Exception: + pass + return out + + +def country(settings): + """ISO country code for the configured location (reverse-geocoded, cached).""" + return _geo(settings).get("country") + + +def resolve(settings) -> dict: + """{ok, country, subdivision, currency} for the configured location. ok is False + (values None) when there's no location set or the lookup failed.""" + g = _geo(settings) + cc = g.get("country") + return {"ok": bool(cc), "country": cc, "subdivision": g.get("subdivision"), + "currency": _currency_for(cc)} diff --git a/server/requirements.txt b/server/requirements.txt index 7904288..165f9de 100644 --- a/server/requirements.txt +++ b/server/requirements.txt @@ -4,3 +4,4 @@ requests pytz yfinance paho-mqtt +babel diff --git a/server/static/app.js b/server/static/app.js index d4d64e8..08d27a3 100644 --- a/server/static/app.js +++ b/server/static/app.js @@ -1052,6 +1052,7 @@ function buildAppCard(a, isPlugin) { ${hasCfg && compatible ? `` : ''} ${removable ? `` : ''} ${hasTrigger && compatible ? `` : ''} + ${a.i18n ? `🌐` : ''} ${icon} ${a.name} ${compatible ? a.desc : incompatibleReason}`; @@ -2072,6 +2073,11 @@ function loadSettingsData(){ // Currency symbol const currencyEl = document.getElementById('currencySymbol'); if(currencyEl) currencyEl.value = data.currency_symbol || '$'; + // Internationalization master toggle + display language + const i18nEl = document.getElementById('i18nEnabled'); + if(i18nEl) i18nEl.checked = !!data.i18n_enabled; + const langEl = document.getElementById('globalLanguage'); + if(langEl){ langEl.value = data.language || 'en-US'; langEl.disabled = !(i18nEl && i18nEl.checked); } // Character map const charMapEl = document.getElementById('charMapInput'); if(charMapEl) charMapEl.value = data.char_map || CHAR_MAP; @@ -2856,6 +2862,13 @@ document.addEventListener('DOMContentLoaded', ()=>{ }); }); +function onI18nToggle(){ + const on = document.getElementById('i18nEnabled').checked; + const langEl = document.getElementById('globalLanguage'); + if(langEl) langEl.disabled = !on; + setSettingsDirty(true); +} + function saveGlobal(){ const rows = parseInt(document.getElementById('simRows').value) || 3; const cols = parseInt(document.getElementById('simCols').value) || 15; @@ -2875,6 +2888,8 @@ function saveGlobal(){ sim_rows:rows, sim_cols:cols, global_loop_delay: globalDelay, timezone: tz, + i18n_enabled: document.getElementById('i18nEnabled')?.checked || false, + language: document.getElementById('globalLanguage')?.value || 'en-US', location_lat: locLat, location_lon: locLon, location_name: locName, diff --git a/server/templates/index.html b/server/templates/index.html index cd40ceb..06ca3ce 100644 --- a/server/templates/index.html +++ b/server/templates/index.html @@ -328,6 +328,20 @@

Settings

+
+
+ + Enable internationalization (non-English languages) +
+

⚠ Only turn this on if your modules run the Universal Firmware — a version with configurable character maps — and you've loaded a character map that includes the accented characters (é, ñ, ö, å, …) these languages use. Standard A–Z / 0–9 modules can't display those, so translated text would appear as blank or wrong flaps. Leave it off to keep everything in English; the display and app list stay exactly as they are today.

+
+
+ + +

Display language for apps that support it (look for the 🌐 badge): translates their words and sets date order, number format and 12h/24h. Any app can override this in its own settings. Only Western-European (Windows-1252) languages are listed — the modules can't show others.

+

Transition Style

diff --git a/server/weather.py b/server/weather.py new file mode 100644 index 0000000..d5d6fc1 --- /dev/null +++ b/server/weather.py @@ -0,0 +1,208 @@ +""" +weather.py — a shared current-conditions helper. + +Several apps want "the weather right now". Rather than each hardcoding a provider +and key, this resolves the *global* weather settings (provider + API key + +location) and returns one normalized current-conditions dict. The plugin runtime +injects it into any app whose ``fetch()`` opts in with a ``get_weather`` +parameter (see app.py); the app calls ``get_weather()`` and renders the +result, so switching providers is a global setting, not an app edit. + +Providers: Open-Meteo (keyless — the default, so weather works with no API key), +OpenWeather, WeatherAPI and QWeather (each keyed via the global weather_api_key). +Temperatures are normalized to Fahrenheit; the caller formats/converts. + +Uses the blocking ``requests`` library (already a project dependency); a small +client shim gives every request a default timeout. +""" + +from __future__ import annotations + +import logging +import time + +import requests + +import location + +log = logging.getLogger("splitflap.weather") + +# Short-TTL cache so the provider is hit at most once per location per window, +# regardless of how many apps call get_weather() or how often they refresh. +_CACHE_TTL = 600 # seconds +_cache: dict = {} # (provider, key, lat, lon) -> (fetched_at, data) + +# Global settings the helper consumes — so the UI can credit weather-using apps +# under these settings even though they read them via get_weather, not directly. +GLOBAL_KEYS = ("weather_provider", "weather_api_key", "zip_code", "location_precise") + +# Compact Open-Meteo WMO weather-code → text map (current conditions only). +_OPENMETEO_CODES = { + 0: "CLEAR", 1: "MAINLY CLEAR", 2: "PARTLY CLOUDY", 3: "OVERCAST", + 45: "FOG", 48: "RIME FOG", 51: "LIGHT DRIZZLE", 53: "DRIZZLE", 55: "HEAVY DRIZZLE", + 56: "FREEZING DRIZZLE", 57: "FREEZING DRIZZLE", 61: "LIGHT RAIN", 63: "RAIN", + 65: "HEAVY RAIN", 66: "FREEZING RAIN", 67: "FREEZING RAIN", 71: "LIGHT SNOW", + 73: "SNOW", 75: "HEAVY SNOW", 77: "SNOW GRAINS", 80: "RAIN SHOWERS", + 81: "RAIN SHOWERS", 82: "HEAVY SHOWERS", 85: "SNOW SHOWERS", 86: "HEAVY SNOW SHOWERS", + 95: "THUNDERSTORM", 96: "THUNDER HAIL", 99: "SEVERE TSTORM", +} + + +class _Client: + """Minimal requests-backed stand-in for httpx.Client: a session that applies a + default timeout to every ``get()`` so the provider helpers stay unchanged.""" + + def __init__(self, timeout=8.0): + self._session = requests.Session() + self._timeout = timeout + + def get(self, url, params=None, headers=None): + return self._session.get(url, params=params, headers=headers, timeout=self._timeout) + + def close(self): + self._session.close() + + def __enter__(self): + return self + + def __exit__(self, *exc): + self.close() + + +def _i(v): + try: + return int(round(float(v))) + except (TypeError, ValueError): + return None + + +# Boston, so weather always has something to show if no location is configured. +_FALLBACK_LOCATION = (42.3496, -71.0783, "BOSTON") + + +def _resolve_location(settings): + """(lat, lon, city) for the configured location via the shared geocoder in + location.py (cached, one Nominatim lookup for weather + get_location), with a + Boston fallback so weather is never blank.""" + return location.coordinates(settings) or _FALLBACK_LOCATION + + +def _openmeteo(client, lat, lon, city, _key): + d = client.get("https://api.open-meteo.com/v1/forecast", params={ + "latitude": lat, "longitude": lon, + "current": "temperature_2m,apparent_temperature,weather_code," + "relative_humidity_2m,wind_speed_10m,cloud_cover", + "daily": "temperature_2m_max,temperature_2m_min", + "temperature_unit": "fahrenheit", "wind_speed_unit": "mph", + "timezone": "auto", "forecast_days": 1, + }).json() + cur = d.get("current", {}) + daily = d.get("daily", {}) + hi = (daily.get("temperature_2m_max") or [cur.get("temperature_2m")])[0] + lo = (daily.get("temperature_2m_min") or [cur.get("temperature_2m")])[0] + code = cur.get("weather_code") + return { + "city": city, "temp_f": _i(cur.get("temperature_2m")), + "feels_like_f": _i(cur.get("apparent_temperature")), + "hi_f": _i(hi), "lo_f": _i(lo), + "desc": _OPENMETEO_CODES.get(code, "CURRENT CONDITIONS"), "code": code, + "humidity": _i(cur.get("relative_humidity_2m")), + "wind_mph": cur.get("wind_speed_10m"), "cloud_cover": _i(cur.get("cloud_cover")), + } + + +def _openweather(client, lat, lon, city, key): + d = client.get("https://api.openweathermap.org/data/2.5/weather", params={ + "lat": lat, "lon": lon, "appid": key, "units": "imperial", + }).json() + main = d.get("main", {}) + return { + "city": str(d.get("name", city)).upper(), "temp_f": _i(main.get("temp")), + "feels_like_f": _i(main.get("feels_like")), + "hi_f": _i(main.get("temp_max")), "lo_f": _i(main.get("temp_min")), + "desc": str((d.get("weather") or [{}])[0].get("main", "CURRENT CONDITIONS")).upper(), + "code": None, "humidity": _i(main.get("humidity")), + "wind_mph": (d.get("wind") or {}).get("speed"), + "cloud_cover": _i((d.get("clouds") or {}).get("all")), + } + + +def _weatherapi(client, lat, lon, city, key): + d = client.get("https://api.weatherapi.com/v1/forecast.json", params={ + "key": key, "q": f"{lat},{lon}", "days": 1, + }).json() + cur = d.get("current", {}) + day = ((d.get("forecast") or {}).get("forecastday") or [{}])[0].get("day", {}) + return { + "city": str((d.get("location") or {}).get("name", city)).upper(), + "temp_f": _i(cur.get("temp_f")), "feels_like_f": _i(cur.get("feelslike_f")), + "hi_f": _i(day.get("maxtemp_f")), "lo_f": _i(day.get("mintemp_f")), + "desc": str((cur.get("condition") or {}).get("text", "CURRENT CONDITIONS")).upper(), + "code": None, "humidity": _i(cur.get("humidity")), + "wind_mph": cur.get("wind_mph"), "cloud_cover": _i(cur.get("cloud")), + } + + +def _qweather(client, lat, lon, city, key): + loc = f"{lon:.2f},{lat:.2f}" + headers = {"Authorization": f"Bearer {key}"} + now = client.get("https://devapi.qweather.com/v7/weather/now", + params={"location": loc, "lang": "en", "unit": "i"}, + headers=headers).json().get("now", {}) + day = (client.get("https://devapi.qweather.com/v7/weather/3d", + params={"location": loc, "lang": "en", "unit": "i"}, + headers=headers).json().get("daily") or [{}])[0] + return { + "city": city, "temp_f": _i(now.get("temp")), + "feels_like_f": _i(now.get("feelsLike")), + "hi_f": _i(day.get("tempMax")), "lo_f": _i(day.get("tempMin")), + "desc": str(now.get("text", "CURRENT CONDITIONS")).upper(), "code": None, + "humidity": _i(now.get("humidity")), "wind_mph": now.get("windSpeed"), + "cloud_cover": _i(now.get("cloud")), + } + + +_PROVIDERS = { + "openmeteo": _openmeteo, "openweather": _openweather, + "weatherapi": _weatherapi, "qweather": _qweather, +} + + +def fetch_current(settings) -> dict: + """Current conditions for the global location via the global provider. Falls + back to keyless Open-Meteo when a keyed provider is missing its key OR fails / + returns an error body (bad key, rate-limited, outage). Returns + ``{ok: False, error, provider}`` only if Open-Meteo itself fails; never raises.""" + provider = str(settings.get("weather_provider", "openmeteo") or "openmeteo").lower() + key = str(settings.get("weather_api_key", "") or "").strip() + if provider not in _PROVIDERS or (provider != "openmeteo" and not key): + provider = "openmeteo" # keyless default — weather works with no key + lat, lon, city = _resolve_location(settings) + cache_key = (provider, key, round(lat, 3), round(lon, 3)) + hit = _cache.get(cache_key) + if hit and (time.time() - hit[0]) < _CACHE_TTL: + return hit[1] + try: + with _Client(timeout=8.0) as client: + data = None + if provider != "openmeteo": + try: + got = _PROVIDERS[provider](client, lat, lon, city, key) + # A keyed provider that 401s/429s still returns 200-ish JSON + # with no temperature: treat a missing temp as a failure. + if got.get("temp_f") is not None: + data = got + else: + log.warning("weather provider %s returned no data; using open-meteo", provider) + except Exception as e: # noqa: BLE001 + log.warning("weather provider %s failed (%s); using open-meteo", provider, e) + if data is None: + provider = "openmeteo" + if data is None: + data = _openmeteo(client, lat, lon, city, key) + data.update(ok=True, provider=provider, lat=lat, lon=lon) + _cache[cache_key] = (time.time(), data) # cache only successful fetches + return data + except Exception as e: # noqa: BLE001 + log.warning("weather fetch failed: %s", e) + return {"ok": False, "error": str(e), "provider": provider} diff --git a/tests/test_gateway_transport.py b/tests/test_gateway_transport.py new file mode 100644 index 0000000..eb949b9 --- /dev/null +++ b/tests/test_gateway_transport.py @@ -0,0 +1,65 @@ +"""Regression tests for GatewayTransport frame decoding. + +The RS485 bus is single-byte Windows-1252 (cp1252): one displayed glyph is one +byte. A frame read back from the gateway -- most importantly a module's +``A``-command character-map response -- can therefore carry raw high bytes +(0x80-0xFF) that are *invalid* standalone UTF-8. The RX path must preserve those +bytes verbatim so the downstream ``.decode('cp1252')`` in app.get_module_char_map +recovers the real characters. These tests lock in that byte-transparent behaviour +(previously the code decoded/re-encoded as UTF-8 with errors="ignore", which +silently dropped every extended character). +""" + +import pathlib +import sys +import unittest + + +SERVER_DIR = pathlib.Path(__file__).resolve().parents[1] / "server" +sys.path.insert(0, str(SERVER_DIR)) + +from gateway_transport import GatewayTransport # noqa: E402 + + +# A char map with real cp1252 extended glyphs (no " or \\, which the physical +# reel aliases to 'q' anyway and which would need JSON escaping). +CHAR_MAP = " ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789éöüàçñ€£¥" +FRAME = "m05A:64:" + CHAR_MAP # module's A-command response frame +FRAME_BYTES = FRAME.encode("cp1252") # the exact bytes on the bus + + +class ExtractFrameTests(unittest.TestCase): + def _recover(self, frame): + # Mirrors _on_message: what lands in the RX buffer is the frame encoded + # latin-1; get_module_char_map later slices it and decodes cp1252. + self.assertIsNotNone(frame) + return frame.encode("latin-1") + + def test_json_form_preserves_extended_bytes(self): + # The gateway's {"command": "..."} form with raw high bytes in the string. + payload = b'{"command": "' + FRAME_BYTES + b'"}' + recovered = self._recover(GatewayTransport._extract_frame(payload)) + self.assertEqual(recovered, FRAME_BYTES) + # Round-trips to the original characters via the downstream cp1252 decode. + self.assertEqual(recovered.decode("cp1252"), FRAME) + + def test_bare_frame_preserves_extended_bytes(self): + # Plain-text fallback (no JSON wrapper). + recovered = self._recover(GatewayTransport._extract_frame(FRAME_BYTES)) + self.assertEqual(recovered.decode("cp1252"), FRAME) + + def test_plain_ascii_unaffected(self): + payload = b'{"command": "m00-A"}' + self.assertEqual(GatewayTransport._extract_frame(payload), "m00-A") + + def test_utf8_would_have_corrupted(self): + # Documents the bug being fixed: the old utf-8/errors=ignore path drops + # the lone high bytes, losing every extended glyph. + lossy = FRAME_BYTES.decode("utf-8", errors="ignore") + self.assertLess(len(lossy), len(FRAME)) + self.assertNotIn("é", lossy) + self.assertNotIn("€", lossy) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_i18n.py b/tests/test_i18n.py new file mode 100644 index 0000000..8215d21 --- /dev/null +++ b/tests/test_i18n.py @@ -0,0 +1,289 @@ +import inspect +import pathlib +import sys +import unittest +from datetime import datetime + + +SERVER_DIR = pathlib.Path(__file__).resolve().parents[1] / "server" +sys.path.insert(0, str(SERVER_DIR)) + +import i18n # noqa: E402 + +try: + import babel # noqa: F401 + HAS_BABEL = True +except ImportError: + HAS_BABEL = False + +# A fixed date so assertions never depend on "today". 2026-07-10 is a Friday. +D = datetime(2026, 7, 10, 15, 48, 5) + + +class TranslateTests(unittest.TestCase): + def test_english_is_passthrough(self): + # No language, English, and any en-* region all return the text unchanged. + for lang in (None, "", "en", "en-US", "en-GB"): + self.assertEqual(i18n.translate("SUNSET", lang, "sun"), "SUNSET") + + def test_known_translation(self): + self.assertEqual(i18n.translate("SUNSET", "fr", "sun"), "COUCHER") + self.assertEqual(i18n.translate("FULL MOON", "de", "moon"), "VOLLMOND") + self.assertEqual(i18n.translate("GOLD", "nl", "metals"), "GOUD") + + def test_unknown_key_falls_back_to_english(self): + self.assertEqual(i18n.translate("TOTALLY UNKNOWN", "fr", "sun"), "TOTALLY UNKNOWN") + + def test_unknown_language_falls_back_to_english_key(self): + # A language we don't have a translation for keeps the English text. + self.assertEqual(i18n.translate("SUNSET", "sw", "sun"), "SUNSET") + + def test_wrong_context_does_not_leak(self): + # SUNSET lives in the 'sun' domain, so asking a different domain must not + # find it (it's not a 'common' word) -> English text. + self.assertEqual(i18n.translate("SUNSET", "fr", "weather"), "SUNSET") + + +class ContextKeyTests(unittest.TestCase): + """The same English word carries different translations per context/domain + (gettext msgctxt), and a shared 'common' domain backs every context.""" + + def test_homograph_splits_by_context(self): + # HIGH: a weather level vs a tide height -> different French words. + self.assertEqual(i18n.translate("HIGH", "fr", "weather"), "ELEVE") + self.assertEqual(i18n.translate("HIGH", "fr", "tides"), "HAUTE") + self.assertNotEqual(i18n.translate("HIGH", "fr", "weather"), + i18n.translate("HIGH", "fr", "tides")) + self.assertEqual(i18n.translate("LOW", "fr", "tides"), "BASSE") + + def test_shared_time_vocabulary_is_one_domain(self): + # DAYS/IN are one meaning shared by many apps -> a single 'time' domain, + # not duplicated per app. countdown/holidays/f1/rocket all use ctx='time'. + self.assertEqual(i18n.translate("DAYS", "fr", "time"), "JOURS") + self.assertEqual(i18n.translate("IN", "fr", "time"), "DANS") + self.assertEqual(i18n.translate("NOW", "de", "time"), "JETZT") + + def test_common_domain_fallback(self): + # 'OFFLINE' lives only in 'common'; any domain resolves it via fallback. + for ctx in ("aurora", "sentiment", "weather"): + self.assertEqual(i18n.translate("OFFLINE", "fr", ctx), "HORS LIGNE") + + def test_default_context_is_common(self): + self.assertEqual(i18n.translate("OFFLINE", "fr"), "HORS LIGNE") + # A domain-specific word is NOT found under the default (common) context. + self.assertEqual(i18n.translate("SUNSET", "fr"), "SUNSET") + + +class DurationAndClockTests(unittest.TestCase): + def test_duration_unit_localizes_day(self): + self.assertEqual(i18n.duration_unit("D", "fr"), "J") # jour + self.assertEqual(i18n.duration_unit("D", "de"), "T") # Tag + self.assertEqual(i18n.duration_unit("D", "it"), "G") # giorno + + def test_duration_unit_passthrough(self): + self.assertEqual(i18n.duration_unit("D", "en-US"), "D") + self.assertEqual(i18n.duration_unit("H", None), "H") + self.assertEqual(i18n.duration_unit("Z", "fr"), "Z") # unknown key + + def test_duration_lives_in_time_domain(self): + # Abbreviations and full-word forms are one duration vocabulary in 'time'. + self.assertEqual(i18n.duration_unit("D", "fr"), i18n.translate("D", "fr", "time")) + self.assertEqual(i18n.translate("WEEKS", "fr", "time"), "SEMAINES") + self.assertEqual(i18n.translate("YEARS", "de", "time"), "JAHRE") + self.assertEqual(i18n.translate("SECONDS", "es", "time"), "SEGUNDOS") + + def test_uses_24h(self): + self.assertFalse(i18n.uses_24h("en-US")) + self.assertFalse(i18n.uses_24h("en-GB")) + self.assertFalse(i18n.uses_24h(None)) + self.assertTrue(i18n.uses_24h("fr")) + self.assertTrue(i18n.uses_24h("de")) + + def test_clock_format_follows_language(self): + self.assertEqual(i18n.clock(D, "fr"), "15:48") + self.assertEqual(i18n.clock(D, "en-US"), "3:48 PM") + + +class CurrencyCountryHolidayTests(unittest.TestCase): + def test_base_currency(self): + self.assertEqual(i18n.base_currency("en-US"), "USD") + self.assertEqual(i18n.base_currency("en-GB"), "GBP") + self.assertEqual(i18n.base_currency("en-AU"), "AUD") + self.assertEqual(i18n.base_currency("fr"), "EUR") + self.assertEqual(i18n.base_currency("zz"), "USD") # unknown default + + def test_country(self): + self.assertEqual(i18n.country("nl"), "NL") + self.assertEqual(i18n.country("en-AU"), "AU") + self.assertEqual(i18n.country("zz"), "US") # unknown default + + def test_holiday_localization(self): + self.assertEqual(i18n.holiday("Christmas Day", "fr"), "Noël") + self.assertIsNone(i18n.holiday("Some Local Fete", "fr")) # no translation + self.assertIsNone(i18n.holiday("Christmas Day", None)) # no language + + +class LocalizerTests(unittest.TestCase): + def test_translate_and_flags(self): + fr = i18n.Localizer("fr") + self.assertEqual(fr.t("SUNSET", "sun"), "COUCHER") + self.assertTrue(fr.is_24h) + self.assertEqual(fr.unit("D"), "J") + + def test_english_localizer_is_noop(self): + en = i18n.Localizer("en-US") + self.assertEqual(en.t("SUNSET", "sun"), "SUNSET") + self.assertFalse(en.is_24h) + + def test_lang_base_strips_region(self): + self.assertEqual(i18n.Localizer("en-GB").lang_base, "en") + self.assertEqual(i18n.Localizer("fr").lang_base, "fr") + + def test_country_and_base_currency(self): + self.assertEqual(i18n.Localizer("en-GB").base_currency(), "GBP") + self.assertEqual(i18n.Localizer("nl").country(), "NL") + + +class BabelBackedTests(unittest.TestCase): + """Date/month/number use babel for CLDR output; every helper degrades to an + English-ish fallback without it, so we assert shape always and exact values + only when babel is installed (the production dependency).""" + + def test_weekday_month_are_uppercase_nonempty(self): + for lang in ("en-US", "fr", "de"): + self.assertTrue(i18n.weekday(D, lang).isupper()) + self.assertTrue(i18n.month(D, lang)) + + def test_date_order_is_locale_specific(self): + en = i18n.date(D, "en-US") + self.assertIn("JULY", en) + self.assertIn("10", en) + if HAS_BABEL: + # Romance/Germanic order: day precedes month. + self.assertEqual(i18n.date(D, "fr"), "10 JUILLET") + self.assertEqual(i18n.date(D, "en-US"), "JULY 10") + + def test_number_separators(self): + if HAS_BABEL: + self.assertEqual(i18n.number(1234.5, "en-US"), "1,234.50") + self.assertEqual(i18n.number(1234.5, "de"), "1.234,50") + self.assertEqual(i18n.number(1234.5, "fr"), "1 234,50") + else: + # Fallback still produces a parseable, non-empty string. + self.assertTrue(i18n.number(1234.5, "de")) + + +class LocalizationDataFileTests(unittest.TestCase): + """All localization data lives in i18n_data.json (loaded at import), not in code. + Lock that contract: the file is valid and populated, the loader fills the module + tables, and a missing file degrades to defaults instead of crashing.""" + + def test_data_file_is_valid_and_populated(self): + import json + path = pathlib.Path(i18n.__file__).with_name("i18n_data.json") + self.assertTrue(path.is_file(), "i18n_data.json must ship next to i18n.py") + data = json.loads(path.read_text(encoding="utf-8")) + for section in ("languages", "strings", "holidays", + "base_currency", "country"): + self.assertIn(section, data) + self.assertTrue(data[section], f"{section} should not be empty") + # 'strings' is grouped by context/domain; each entry uses the + # {context, translations} schema, with a translator context note. + for domain, entries in data["strings"].items(): + for key, entry in entries.items(): + self.assertIn("context", entry, f"{domain}.{key} missing context note") + self.assertIn("translations", entry) + self.assertEqual(data["strings"]["sun"]["SUNSET"]["translations"]["fr"], "COUCHER") + # The same word differs by domain (weather level vs tide height). + self.assertEqual(data["strings"]["weather"]["HIGH"]["translations"]["fr"], "ELEVE") + self.assertEqual(data["strings"]["tides"]["HIGH"]["translations"]["fr"], "HAUTE") + self.assertEqual(data["holidays"]["christmas day"]["translations"]["fr"], "Noël") + self.assertEqual(data["base_currency"]["en-gb"], "GBP") + self.assertEqual(data["country"]["nl"], "NL") + + def test_loader_populates_module_tables(self): + self.assertTrue(all([i18n._STRINGS, i18n._DURATION_UNITS, i18n._HOLIDAYS, + i18n._BASE_CURRENCY, i18n._COUNTRY, i18n.LANGUAGE_OPTIONS])) + # The loader flattens into {domain: {NAME: {lang: value}}}. + self.assertEqual(i18n._STRINGS["sun"]["SUNSET"]["fr"], "COUCHER") + + def test_missing_file_degrades_gracefully(self): + original = i18n._DATA_PATH + try: + i18n._DATA_PATH = original + ".does-not-exist" + strings, holidays, cur, country, langs = i18n._load_i18n_data() + self.assertEqual((strings, holidays, cur, country), ({}, {}, {}, {})) + # ...but the Language list still has at least English so the UI works. + self.assertTrue(langs and langs[0]["value"].startswith("en")) + finally: + i18n._DATA_PATH = original + + +class LanguageOptionsTests(unittest.TestCase): + def test_language_options_shape(self): + self.assertTrue(i18n.LANGUAGE_OPTIONS) + for opt in i18n.LANGUAGE_OPTIONS: + self.assertIn("value", opt) + self.assertIn("label", opt) + values = {o["value"] for o in i18n.LANGUAGE_OPTIONS} + self.assertIn("en-US", values) + self.assertIn("pt-BR", values) # a non-European regional variant + + +class RegionalVariantTests(unittest.TestCase): + """A region-tagged language inherits its base language's translations but keeps + its own currency/country (pt-BR reuses pt words but resolves to Brazil / BRL).""" + + def test_variant_inherits_base_translations(self): + self.assertEqual(i18n.translate("SUNSET", "pt-BR", "sun"), + i18n.translate("SUNSET", "pt", "sun")) + self.assertEqual(i18n.duration_unit("D", "pt-BR"), i18n.duration_unit("D", "pt")) + + def test_variant_currency_and_country_override_base(self): + self.assertEqual(i18n.base_currency("pt-BR"), "BRL") + self.assertEqual(i18n.country("pt-BR"), "BR") + self.assertEqual(i18n.base_currency("pt"), "EUR") # base unchanged + self.assertEqual(i18n.base_currency("es-MX"), "MXN") + self.assertEqual(i18n.country("fr-CA"), "CA") + self.assertEqual(i18n.base_currency("de-CH"), "CHF") + + def test_expanded_base_languages(self): + self.assertEqual(i18n.base_currency("da"), "DKK") + self.assertEqual(i18n.country("sv"), "SE") + self.assertEqual(i18n.base_currency("af"), "ZAR") + + def test_scandinavian_strings_present(self): + self.assertEqual(i18n.translate("SUNSET", "sv", "sun"), "SOLNEDGÅNG") + self.assertEqual(i18n.translate("SNOW", "da", "weather"), "SNE") + + +def _accepts(fn, name): + """The exact predicate app.py._fetch_accepts uses to decide whether to inject a + helper: the parameter is named, or the function takes **kwargs. Kept in lockstep + here so a Python signature-inspection change would surface in tests.""" + params = inspect.signature(fn).parameters + return name in params or any(p.kind == p.VAR_KEYWORD for p in params.values()) + + +class InjectionContractTests(unittest.TestCase): + def test_classic_four_arg_app_opts_into_nothing(self): + def fetch(settings, format_lines, get_rows, get_cols): + return [] + for helper in ("i18n", "get_weather", "get_location"): + self.assertFalse(_accepts(fetch, helper)) + + def test_declared_parameter_opts_in(self): + def fetch(settings, format_lines, get_rows, get_cols, i18n=None): + return [] + self.assertTrue(_accepts(fetch, "i18n")) + self.assertFalse(_accepts(fetch, "get_weather")) + + def test_var_keyword_opts_into_everything(self): + def fetch(settings, format_lines, get_rows, get_cols, **kw): + return [] + for helper in ("i18n", "get_weather", "get_location"): + self.assertTrue(_accepts(fetch, helper)) + + +if __name__ == "__main__": + unittest.main()