diff --git a/backend/app/main.py b/backend/app/main.py index de8faef..bd1b1e9 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -89,6 +89,7 @@ async def lifespan(app: FastAPI): from backend.app.routes.gwas import router as gwas_router from backend.app.routes.starter_prompts import router as starter_prompts_router from backend.app.routes.export import router as export_router +from backend.app.routes.life_map import router as life_map_router app.include_router(snps_router) app.include_router(sessions_router) @@ -101,6 +102,7 @@ async def lifespan(app: FastAPI): app.include_router(gwas_router) app.include_router(starter_prompts_router) app.include_router(export_router) +app.include_router(life_map_router) @app.get("/api/health") @@ -109,7 +111,7 @@ async def health(): return {"status": "ok", "variants": stats["total"]} -ALL_VIEWS = ["snps", "mental-health", "pgx", "addiction", "risk"] +ALL_VIEWS = ["snps", "mental-health", "pgx", "addiction", "risk", "life-map"] @app.get("/api/settings/views") async def get_visible_views(): diff --git a/backend/app/routes/life_map.py b/backend/app/routes/life_map.py new file mode 100644 index 0000000..a90e6c5 --- /dev/null +++ b/backend/app/routes/life_map.py @@ -0,0 +1,28 @@ +"""Migrant Life-Map routes (#27). + +Serves the committed, version-stamped life-table data produced by +``scripts/fetch_life_expectancy.py``. Dumb data server — all blend logic lives in +the frontend (``lib/lifeBlend.ts``). The modifier catalogue is served via the +existing generic ``/api/config/{name}`` endpoint (``config/life-modifiers.yaml``). +""" +from __future__ import annotations + +import json +from pathlib import Path + +from fastapi import APIRouter, HTTPException + +router = APIRouter(prefix="/api/life-map", tags=["life-map"]) + +_DATA_FILE = Path(__file__).resolve().parents[3] / "config" / "life_tables.json" + + +@router.get("/life-tables") +async def get_life_tables() -> dict: + """Return the committed life-table dataset (countries x sex x age -> ex).""" + if not _DATA_FILE.exists(): + raise HTTPException(status_code=404, detail="Life tables not generated") + try: + return json.loads(_DATA_FILE.read_text()) + except Exception as exc: # noqa: BLE001 + raise HTTPException(status_code=500, detail=f"Failed to read life tables: {exc}") diff --git a/config/life-modifiers.yaml b/config/life-modifiers.yaml new file mode 100644 index 0000000..7ee010d --- /dev/null +++ b/config/life-modifiers.yaml @@ -0,0 +1,105 @@ +# Life-Map modifiers (#27, track F). +# +# Qualitative, supportive life-context factors layered onto the country anchors. +# They NEVER mutate the blended life-expectancy number. A wide, caveated *range* +# may be revealed (opt-in) ONLY for `evidence: strong` factors. Mental-health +# items are deliberately kept `evidence: weak` so they can never become a number — +# per the project's mental-health UX spec, the map must not greet someone with a +# scary subtraction. +# +# Fields: +# id kebab-case identifier +# category stress | mental-health | family-history +# label short display label +# qualitative supportive, non-alarming description +# actions list of things that move this factor +# evidence strong | moderate | weak (range allowed only when strong) +# range optional {lowYears, highYears} — honored only when evidence==strong + +modifiers: + - id: chronic-stress + category: stress + label: Chronic / unmanaged stress + qualitative: >- + Sustained high stress without recovery is a factor worth attention. It is + also one of the most movable — recovery, sleep, and connection shift it. + actions: + - Protect sleep and regular recovery + - Build in downshift routines (walks, breath, nature) + - Reduce avoidable chronic stressors where you can + evidence: moderate + + - id: relocation-adjustment + category: stress + label: Relocation / migration adjustment + qualitative: >- + Building a life in a new country carries real adjustment load — language, + systems, distance from old support. It tends to ease as roots deepen. + actions: + - Invest in local community and routine + - Keep ties to your origin culture and people + - Use local healthcare proactively, not only in crisis + evidence: weak + + - id: smoking + category: stress + label: Smoking + qualitative: >- + Smoking is the single most studied modifiable mortality factor — and + quitting at any age measurably changes the trajectory. + actions: + - Talk to a clinician about cessation support + - Nicotine replacement / medication options + evidence: strong + range: + lowYears: 5 + highYears: 10 + + - id: physical-inactivity + category: stress + label: Low physical activity + qualitative: >- + Regular movement is strongly tied to healthier later years. Even modest, + consistent activity counts. + actions: + - Aim for regular moderate activity you enjoy + - Add strength / mobility work over time + evidence: strong + range: + lowYears: 2 + highYears: 5 + + - id: anxiety-disorder + category: mental-health + label: Diagnosed anxiety disorder + qualitative: >- + Living with anxiety is a meaningful part of your health picture and worth + ongoing care — but population statistics about it are heavily confounded and + say little about any individual. This is context for support, not a verdict. + actions: + - Continue the care and tools that work for you + - Sleep, movement, and connection support nervous-system regulation + - Revisit treatment with your clinician as needs change + evidence: weak + + - id: family-mental-health + category: family-history + label: Family history of mental-health conditions + qualitative: >- + Family patterns can raise awareness of what to watch for and discuss with a + clinician. Awareness and early support are the actionable parts. + actions: + - Note relevant family history for your clinician + - Know your early-warning signs and supports + evidence: weak + + - id: family-cardiometabolic + category: family-history + label: Family history of heart / metabolic disease + qualitative: >- + A family history of cardiovascular or metabolic disease is a useful prompt + for earlier, more regular screening — where prevention does the most work. + actions: + - Discuss earlier screening (lipids, blood pressure, glucose) + - Prioritize the modifiable factors above + evidence: moderate diff --git a/config/life_tables.json b/config/life_tables.json new file mode 100644 index 0000000..154846b --- /dev/null +++ b/config/life_tables.json @@ -0,0 +1,4699 @@ +{ + "retrieved": "2026-05-30", + "countries": { + "AT": { + "name": "Austria", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 61.9, + "19": 60.9, + "20": 59.9, + "21": 59.0, + "22": 58.0, + "23": 57.0, + "24": 56.1, + "25": 55.1, + "26": 54.1, + "27": 53.1, + "28": 52.2, + "29": 51.2, + "30": 50.2, + "31": 49.3, + "32": 48.3, + "33": 47.3, + "34": 46.3, + "35": 45.4, + "36": 44.4, + "37": 43.5, + "38": 42.5, + "39": 41.5, + "40": 40.6, + "41": 39.6, + "42": 38.7, + "43": 37.7, + "44": 36.8, + "45": 35.9, + "46": 34.9, + "47": 34.0, + "48": 33.0, + "49": 32.1, + "50": 31.2, + "51": 30.3, + "52": 29.4, + "53": 28.5, + "54": 27.6, + "55": 26.7, + "56": 25.8, + "57": 25.0, + "58": 24.1, + "59": 23.2, + "60": 22.4, + "61": 21.5, + "62": 20.7, + "63": 19.9, + "64": 19.2, + "65": 18.4, + "66": 17.6, + "67": 16.9, + "68": 16.1, + "69": 15.4, + "70": 14.7, + "71": 14.0, + "72": 13.3, + "73": 12.6, + "74": 12.0, + "75": 11.3, + "76": 10.7, + "77": 10.1, + "78": 9.5, + "79": 8.9, + "80": 8.4, + "81": 7.8, + "82": 7.3, + "83": 6.7, + "84": 6.2, + "85": 5.7, + "86": 5.2, + "87": 4.8, + "88": 4.4, + "89": 4.1, + "90": 3.7 + }, + "female": { + "18": 66.5, + "19": 65.6, + "20": 64.6, + "21": 63.6, + "22": 62.6, + "23": 61.6, + "24": 60.6, + "25": 59.7, + "26": 58.7, + "27": 57.7, + "28": 56.7, + "29": 55.7, + "30": 54.7, + "31": 53.7, + "32": 52.7, + "33": 51.8, + "34": 50.8, + "35": 49.8, + "36": 48.8, + "37": 47.9, + "38": 46.9, + "39": 45.9, + "40": 44.9, + "41": 44.0, + "42": 43.0, + "43": 42.0, + "44": 41.0, + "45": 40.1, + "46": 39.1, + "47": 38.1, + "48": 37.2, + "49": 36.2, + "50": 35.3, + "51": 34.3, + "52": 33.4, + "53": 32.5, + "54": 31.5, + "55": 30.6, + "56": 29.6, + "57": 28.7, + "58": 27.8, + "59": 26.9, + "60": 26.0, + "61": 25.1, + "62": 24.2, + "63": 23.3, + "64": 22.4, + "65": 21.6, + "66": 20.7, + "67": 19.9, + "68": 19.0, + "69": 18.2, + "70": 17.4, + "71": 16.5, + "72": 15.7, + "73": 14.9, + "74": 14.2, + "75": 13.4, + "76": 12.7, + "77": 12.0, + "78": 11.2, + "79": 10.5, + "80": 9.9, + "81": 9.2, + "82": 8.6, + "83": 7.9, + "84": 7.3, + "85": 6.7, + "86": 6.2, + "87": 5.6, + "88": 5.2, + "89": 4.7, + "90": 4.3 + } + } + }, + "BE": { + "name": "Belgium", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 62.6, + "19": 61.6, + "20": 60.6, + "21": 59.7, + "22": 58.7, + "23": 57.7, + "24": 56.7, + "25": 55.7, + "26": 54.8, + "27": 53.8, + "28": 52.8, + "29": 51.9, + "30": 50.9, + "31": 49.9, + "32": 48.9, + "33": 48.0, + "34": 47.0, + "35": 46.0, + "36": 45.1, + "37": 44.1, + "38": 43.2, + "39": 42.2, + "40": 41.3, + "41": 40.3, + "42": 39.4, + "43": 38.4, + "44": 37.5, + "45": 36.6, + "46": 35.6, + "47": 34.7, + "48": 33.8, + "49": 32.9, + "50": 31.9, + "51": 31.0, + "52": 30.1, + "53": 29.2, + "54": 28.3, + "55": 27.4, + "56": 26.5, + "57": 25.7, + "58": 24.8, + "59": 23.9, + "60": 23.1, + "61": 22.2, + "62": 21.4, + "63": 20.6, + "64": 19.8, + "65": 19.0, + "66": 18.2, + "67": 17.5, + "68": 16.8, + "69": 16.0, + "70": 15.3, + "71": 14.6, + "72": 13.9, + "73": 13.2, + "74": 12.5, + "75": 11.8, + "76": 11.2, + "77": 10.5, + "78": 9.9, + "79": 9.3, + "80": 8.7, + "81": 8.2, + "82": 7.6, + "83": 7.1, + "84": 6.6, + "85": 6.1, + "86": 5.6, + "87": 5.2, + "88": 4.8, + "89": 4.4, + "90": 4.0 + }, + "female": { + "18": 66.7, + "19": 65.7, + "20": 64.7, + "21": 63.7, + "22": 62.7, + "23": 61.7, + "24": 60.7, + "25": 59.8, + "26": 58.8, + "27": 57.8, + "28": 56.8, + "29": 55.8, + "30": 54.8, + "31": 53.8, + "32": 52.9, + "33": 51.9, + "34": 50.9, + "35": 49.9, + "36": 48.9, + "37": 48.0, + "38": 47.0, + "39": 46.0, + "40": 45.0, + "41": 44.1, + "42": 43.1, + "43": 42.1, + "44": 41.2, + "45": 40.2, + "46": 39.3, + "47": 38.3, + "48": 37.4, + "49": 36.4, + "50": 35.5, + "51": 34.5, + "52": 33.6, + "53": 32.7, + "54": 31.8, + "55": 30.8, + "56": 29.9, + "57": 29.0, + "58": 28.1, + "59": 27.2, + "60": 26.3, + "61": 25.4, + "62": 24.5, + "63": 23.7, + "64": 22.8, + "65": 21.9, + "66": 21.1, + "67": 20.3, + "68": 19.5, + "69": 18.6, + "70": 17.8, + "71": 17.0, + "72": 16.2, + "73": 15.5, + "74": 14.7, + "75": 13.9, + "76": 13.2, + "77": 12.5, + "78": 11.7, + "79": 11.0, + "80": 10.4, + "81": 9.7, + "82": 9.0, + "83": 8.4, + "84": 7.8, + "85": 7.2, + "86": 6.7, + "87": 6.2, + "88": 5.7, + "89": 5.2, + "90": 4.8 + } + } + }, + "BG": { + "name": "Bulgaria", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 54.6, + "19": 53.7, + "20": 52.7, + "21": 51.7, + "22": 50.8, + "23": 49.8, + "24": 48.9, + "25": 47.9, + "26": 47.0, + "27": 46.0, + "28": 45.1, + "29": 44.1, + "30": 43.2, + "31": 42.2, + "32": 41.3, + "33": 40.4, + "34": 39.4, + "35": 38.5, + "36": 37.5, + "37": 36.6, + "38": 35.7, + "39": 34.8, + "40": 33.9, + "41": 33.0, + "42": 32.1, + "43": 31.2, + "44": 30.3, + "45": 29.4, + "46": 28.5, + "47": 27.7, + "48": 26.8, + "49": 26.0, + "50": 25.2, + "51": 24.3, + "52": 23.5, + "53": 22.7, + "54": 22.0, + "55": 21.2, + "56": 20.5, + "57": 19.8, + "58": 19.1, + "59": 18.4, + "60": 17.7, + "61": 17.0, + "62": 16.4, + "63": 15.7, + "64": 15.1, + "65": 14.5, + "66": 13.9, + "67": 13.4, + "68": 12.8, + "69": 12.3, + "70": 11.7, + "71": 11.2, + "72": 10.6, + "73": 10.1, + "74": 9.6, + "75": 9.1, + "76": 8.6, + "77": 8.2, + "78": 7.7, + "79": 7.3, + "80": 6.8, + "81": 6.4, + "82": 6.0, + "83": 5.6, + "84": 5.3, + "85": 4.9, + "86": 4.5, + "87": 4.2, + "88": 3.9, + "89": 3.6, + "90": 3.4 + }, + "female": { + "18": 62.1, + "19": 61.1, + "20": 60.1, + "21": 59.2, + "22": 58.2, + "23": 57.2, + "24": 56.2, + "25": 55.3, + "26": 54.3, + "27": 53.3, + "28": 52.3, + "29": 51.3, + "30": 50.4, + "31": 49.4, + "32": 48.4, + "33": 47.4, + "34": 46.5, + "35": 45.5, + "36": 44.5, + "37": 43.6, + "38": 42.6, + "39": 41.6, + "40": 40.7, + "41": 39.7, + "42": 38.8, + "43": 37.8, + "44": 36.9, + "45": 36.0, + "46": 35.0, + "47": 34.1, + "48": 33.2, + "49": 32.3, + "50": 31.4, + "51": 30.5, + "52": 29.6, + "53": 28.7, + "54": 27.9, + "55": 27.0, + "56": 26.1, + "57": 25.3, + "58": 24.4, + "59": 23.6, + "60": 22.7, + "61": 21.9, + "62": 21.1, + "63": 20.2, + "64": 19.4, + "65": 18.6, + "66": 17.9, + "67": 17.1, + "68": 16.3, + "69": 15.6, + "70": 14.8, + "71": 14.1, + "72": 13.4, + "73": 12.6, + "74": 11.9, + "75": 11.2, + "76": 10.6, + "77": 9.9, + "78": 9.3, + "79": 8.7, + "80": 8.1, + "81": 7.5, + "82": 7.0, + "83": 6.5, + "84": 6.0, + "85": 5.5, + "86": 5.1, + "87": 4.7, + "88": 4.3, + "89": 4.0, + "90": 3.7 + } + } + }, + "CH": { + "name": "Switzerland", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 64.6, + "19": 63.7, + "20": 62.7, + "21": 61.7, + "22": 60.7, + "23": 59.8, + "24": 58.8, + "25": 57.8, + "26": 56.8, + "27": 55.9, + "28": 54.9, + "29": 53.9, + "30": 52.9, + "31": 52.0, + "32": 51.0, + "33": 50.0, + "34": 49.0, + "35": 48.1, + "36": 47.1, + "37": 46.1, + "38": 45.1, + "39": 44.2, + "40": 43.2, + "41": 42.2, + "42": 41.3, + "43": 40.3, + "44": 39.3, + "45": 38.4, + "46": 37.4, + "47": 36.5, + "48": 35.5, + "49": 34.6, + "50": 33.6, + "51": 32.7, + "52": 31.8, + "53": 30.8, + "54": 29.9, + "55": 29.0, + "56": 28.1, + "57": 27.2, + "58": 26.3, + "59": 25.4, + "60": 24.5, + "61": 23.7, + "62": 22.8, + "63": 21.9, + "64": 21.1, + "65": 20.3, + "66": 19.4, + "67": 18.6, + "68": 17.8, + "69": 17.0, + "70": 16.3, + "71": 15.5, + "72": 14.7, + "73": 14.0, + "74": 13.2, + "75": 12.5, + "76": 11.8, + "77": 11.1, + "78": 10.4, + "79": 9.8, + "80": 9.2, + "81": 8.5, + "82": 7.9, + "83": 7.3, + "84": 6.8, + "85": 6.3, + "86": 5.7, + "87": 5.3, + "88": 4.8, + "89": 4.4, + "90": 4.0 + }, + "female": { + "18": 68.2, + "19": 67.2, + "20": 66.2, + "21": 65.2, + "22": 64.3, + "23": 63.3, + "24": 62.3, + "25": 61.3, + "26": 60.3, + "27": 59.3, + "28": 58.3, + "29": 57.3, + "30": 56.3, + "31": 55.4, + "32": 54.4, + "33": 53.4, + "34": 52.4, + "35": 51.4, + "36": 50.4, + "37": 49.4, + "38": 48.5, + "39": 47.5, + "40": 46.5, + "41": 45.5, + "42": 44.5, + "43": 43.6, + "44": 42.6, + "45": 41.6, + "46": 40.7, + "47": 39.7, + "48": 38.7, + "49": 37.7, + "50": 36.8, + "51": 35.8, + "52": 34.9, + "53": 33.9, + "54": 33.0, + "55": 32.0, + "56": 31.1, + "57": 30.2, + "58": 29.2, + "59": 28.3, + "60": 27.4, + "61": 26.4, + "62": 25.5, + "63": 24.6, + "64": 23.7, + "65": 22.8, + "66": 22.0, + "67": 21.1, + "68": 20.2, + "69": 19.3, + "70": 18.5, + "71": 17.7, + "72": 16.8, + "73": 16.0, + "74": 15.2, + "75": 14.4, + "76": 13.6, + "77": 12.8, + "78": 12.1, + "79": 11.3, + "80": 10.6, + "81": 9.9, + "82": 9.2, + "83": 8.5, + "84": 7.9, + "85": 7.3, + "86": 6.7, + "87": 6.2, + "88": 5.7, + "89": 5.2, + "90": 4.7 + } + } + }, + "CY": { + "name": "Cyprus", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.6, + "19": 62.7, + "20": 61.7, + "21": 60.7, + "22": 59.7, + "23": 58.8, + "24": 57.8, + "25": 56.9, + "26": 55.9, + "27": 54.9, + "28": 53.9, + "29": 53.0, + "30": 52.0, + "31": 51.0, + "32": 50.1, + "33": 49.1, + "34": 48.1, + "35": 47.1, + "36": 46.2, + "37": 45.2, + "38": 44.2, + "39": 43.3, + "40": 42.3, + "41": 41.3, + "42": 40.4, + "43": 39.4, + "44": 38.5, + "45": 37.5, + "46": 36.6, + "47": 35.7, + "48": 34.8, + "49": 33.9, + "50": 32.9, + "51": 32.0, + "52": 31.1, + "53": 30.2, + "54": 29.3, + "55": 28.4, + "56": 27.5, + "57": 26.6, + "58": 25.8, + "59": 24.9, + "60": 24.1, + "61": 23.2, + "62": 22.3, + "63": 21.4, + "64": 20.6, + "65": 19.8, + "66": 19.0, + "67": 18.2, + "68": 17.4, + "69": 16.6, + "70": 15.8, + "71": 15.0, + "72": 14.3, + "73": 13.6, + "74": 12.9, + "75": 12.2, + "76": 11.5, + "77": 10.9, + "78": 10.3, + "79": 9.7, + "80": 9.0, + "81": 8.4, + "82": 7.7, + "83": 7.1, + "84": 6.6, + "85": 6.1, + "86": 5.7, + "87": 5.2, + "88": 4.9, + "89": 4.7, + "90": 4.3 + }, + "female": { + "18": 67.3, + "19": 66.3, + "20": 65.3, + "21": 64.3, + "22": 63.4, + "23": 62.4, + "24": 61.4, + "25": 60.4, + "26": 59.4, + "27": 58.5, + "28": 57.5, + "29": 56.5, + "30": 55.5, + "31": 54.5, + "32": 53.6, + "33": 52.6, + "34": 51.6, + "35": 50.6, + "36": 49.6, + "37": 48.6, + "38": 47.7, + "39": 46.7, + "40": 45.7, + "41": 44.7, + "42": 43.7, + "43": 42.8, + "44": 41.8, + "45": 40.8, + "46": 39.8, + "47": 38.9, + "48": 37.9, + "49": 37.0, + "50": 36.0, + "51": 35.0, + "52": 34.1, + "53": 33.1, + "54": 32.2, + "55": 31.3, + "56": 30.3, + "57": 29.4, + "58": 28.5, + "59": 27.5, + "60": 26.6, + "61": 25.6, + "62": 24.7, + "63": 23.8, + "64": 22.9, + "65": 22.0, + "66": 21.1, + "67": 20.2, + "68": 19.3, + "69": 18.5, + "70": 17.6, + "71": 16.7, + "72": 15.9, + "73": 15.0, + "74": 14.2, + "75": 13.4, + "76": 12.6, + "77": 11.8, + "78": 11.0, + "79": 10.3, + "80": 9.6, + "81": 8.9, + "82": 8.1, + "83": 7.5, + "84": 6.9, + "85": 6.3, + "86": 5.7, + "87": 5.3, + "88": 4.8, + "89": 4.4, + "90": 3.9 + } + } + }, + "CZ": { + "name": "Czechia", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 59.2, + "19": 58.2, + "20": 57.2, + "21": 56.3, + "22": 55.3, + "23": 54.3, + "24": 53.4, + "25": 52.4, + "26": 51.5, + "27": 50.5, + "28": 49.5, + "29": 48.5, + "30": 47.6, + "31": 46.6, + "32": 45.7, + "33": 44.7, + "34": 43.8, + "35": 42.8, + "36": 41.9, + "37": 40.9, + "38": 40.0, + "39": 39.1, + "40": 38.1, + "41": 37.2, + "42": 36.2, + "43": 35.3, + "44": 34.4, + "45": 33.5, + "46": 32.5, + "47": 31.6, + "48": 30.7, + "49": 29.8, + "50": 28.9, + "51": 28.0, + "52": 27.1, + "53": 26.3, + "54": 25.4, + "55": 24.5, + "56": 23.7, + "57": 22.9, + "58": 22.1, + "59": 21.2, + "60": 20.5, + "61": 19.7, + "62": 18.9, + "63": 18.1, + "64": 17.4, + "65": 16.7, + "66": 16.0, + "67": 15.3, + "68": 14.6, + "69": 13.9, + "70": 13.3, + "71": 12.6, + "72": 12.0, + "73": 11.4, + "74": 10.8, + "75": 10.2, + "76": 9.6, + "77": 9.1, + "78": 8.5, + "79": 8.0, + "80": 7.5, + "81": 7.0, + "82": 6.5, + "83": 6.1, + "84": 5.7, + "85": 5.2, + "86": 4.9, + "87": 4.5, + "88": 4.1, + "89": 3.8, + "90": 3.5 + }, + "female": { + "18": 65.0, + "19": 64.0, + "20": 63.1, + "21": 62.1, + "22": 61.1, + "23": 60.1, + "24": 59.1, + "25": 58.1, + "26": 57.2, + "27": 56.2, + "28": 55.2, + "29": 54.2, + "30": 53.2, + "31": 52.2, + "32": 51.2, + "33": 50.3, + "34": 49.3, + "35": 48.3, + "36": 47.3, + "37": 46.4, + "38": 45.4, + "39": 44.4, + "40": 43.4, + "41": 42.5, + "42": 41.5, + "43": 40.5, + "44": 39.6, + "45": 38.6, + "46": 37.7, + "47": 36.7, + "48": 35.7, + "49": 34.8, + "50": 33.9, + "51": 32.9, + "52": 32.0, + "53": 31.0, + "54": 30.1, + "55": 29.2, + "56": 28.3, + "57": 27.4, + "58": 26.5, + "59": 25.6, + "60": 24.7, + "61": 23.8, + "62": 23.0, + "63": 22.1, + "64": 21.2, + "65": 20.4, + "66": 19.6, + "67": 18.7, + "68": 17.9, + "69": 17.1, + "70": 16.3, + "71": 15.5, + "72": 14.7, + "73": 14.0, + "74": 13.2, + "75": 12.5, + "76": 11.8, + "77": 11.1, + "78": 10.5, + "79": 9.8, + "80": 9.2, + "81": 8.5, + "82": 7.9, + "83": 7.4, + "84": 6.8, + "85": 6.3, + "86": 5.8, + "87": 5.3, + "88": 4.8, + "89": 4.4, + "90": 4.1 + } + } + }, + "DE": { + "name": "Germany", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 60.9, + "19": 60.0, + "20": 59.0, + "21": 58.0, + "22": 57.0, + "23": 56.1, + "24": 55.1, + "25": 54.1, + "26": 53.1, + "27": 52.1, + "28": 51.2, + "29": 50.2, + "30": 49.2, + "31": 48.2, + "32": 47.3, + "33": 46.3, + "34": 45.3, + "35": 44.4, + "36": 43.4, + "37": 42.4, + "38": 41.5, + "39": 40.5, + "40": 39.6, + "41": 38.6, + "42": 37.7, + "43": 36.7, + "44": 35.8, + "45": 34.9, + "46": 33.9, + "47": 33.0, + "48": 32.1, + "49": 31.2, + "50": 30.3, + "51": 29.4, + "52": 28.5, + "53": 27.6, + "54": 26.7, + "55": 25.8, + "56": 24.9, + "57": 24.1, + "58": 23.2, + "59": 22.4, + "60": 21.6, + "61": 20.8, + "62": 20.0, + "63": 19.2, + "64": 18.5, + "65": 17.7, + "66": 17.0, + "67": 16.3, + "68": 15.6, + "69": 14.9, + "70": 14.2, + "71": 13.5, + "72": 12.9, + "73": 12.2, + "74": 11.6, + "75": 11.0, + "76": 10.3, + "77": 9.8, + "78": 9.2, + "79": 8.6, + "80": 8.0, + "81": 7.5, + "82": 7.0, + "83": 6.5, + "84": 6.0, + "85": 5.5, + "86": 5.1, + "87": 4.6, + "88": 4.2, + "89": 3.9, + "90": 3.6 + }, + "female": { + "18": 65.6, + "19": 64.6, + "20": 63.6, + "21": 62.6, + "22": 61.7, + "23": 60.7, + "24": 59.7, + "25": 58.7, + "26": 57.7, + "27": 56.7, + "28": 55.7, + "29": 54.7, + "30": 53.7, + "31": 52.8, + "32": 51.8, + "33": 50.8, + "34": 49.8, + "35": 48.8, + "36": 47.9, + "37": 46.9, + "38": 45.9, + "39": 44.9, + "40": 44.0, + "41": 43.0, + "42": 42.0, + "43": 41.1, + "44": 40.1, + "45": 39.1, + "46": 38.2, + "47": 37.2, + "48": 36.3, + "49": 35.3, + "50": 34.4, + "51": 33.4, + "52": 32.5, + "53": 31.6, + "54": 30.6, + "55": 29.7, + "56": 28.8, + "57": 27.9, + "58": 27.0, + "59": 26.1, + "60": 25.2, + "61": 24.3, + "62": 23.5, + "63": 22.6, + "64": 21.8, + "65": 20.9, + "66": 20.1, + "67": 19.3, + "68": 18.5, + "69": 17.7, + "70": 16.9, + "71": 16.1, + "72": 15.3, + "73": 14.6, + "74": 13.8, + "75": 13.1, + "76": 12.3, + "77": 11.7, + "78": 10.9, + "79": 10.3, + "80": 9.6, + "81": 9.0, + "82": 8.3, + "83": 7.7, + "84": 7.1, + "85": 6.6, + "86": 6.0, + "87": 5.5, + "88": 5.1, + "89": 4.6, + "90": 4.2 + } + } + }, + "DK": { + "name": "Denmark", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 62.1, + "19": 61.1, + "20": 60.1, + "21": 59.2, + "22": 58.2, + "23": 57.2, + "24": 56.2, + "25": 55.2, + "26": 54.2, + "27": 53.3, + "28": 52.3, + "29": 51.3, + "30": 50.3, + "31": 49.4, + "32": 48.4, + "33": 47.4, + "34": 46.5, + "35": 45.5, + "36": 44.5, + "37": 43.6, + "38": 42.6, + "39": 41.6, + "40": 40.7, + "41": 39.7, + "42": 38.8, + "43": 37.8, + "44": 36.8, + "45": 35.9, + "46": 35.0, + "47": 34.0, + "48": 33.1, + "49": 32.1, + "50": 31.2, + "51": 30.3, + "52": 29.4, + "53": 28.5, + "54": 27.6, + "55": 26.7, + "56": 25.8, + "57": 24.9, + "58": 24.0, + "59": 23.2, + "60": 22.3, + "61": 21.5, + "62": 20.7, + "63": 19.9, + "64": 19.1, + "65": 18.3, + "66": 17.5, + "67": 16.8, + "68": 16.0, + "69": 15.3, + "70": 14.6, + "71": 13.9, + "72": 13.2, + "73": 12.5, + "74": 11.9, + "75": 11.2, + "76": 10.6, + "77": 10.0, + "78": 9.4, + "79": 8.8, + "80": 8.2, + "81": 7.7, + "82": 7.2, + "83": 6.6, + "84": 6.2, + "85": 5.7, + "86": 5.2, + "87": 4.8, + "88": 4.4, + "89": 4.1, + "90": 3.8 + }, + "female": { + "18": 66.0, + "19": 65.0, + "20": 64.0, + "21": 63.0, + "22": 62.0, + "23": 61.0, + "24": 60.0, + "25": 59.0, + "26": 58.0, + "27": 57.1, + "28": 56.1, + "29": 55.1, + "30": 54.1, + "31": 53.1, + "32": 52.1, + "33": 51.1, + "34": 50.1, + "35": 49.2, + "36": 48.2, + "37": 47.2, + "38": 46.2, + "39": 45.3, + "40": 44.3, + "41": 43.3, + "42": 42.3, + "43": 41.4, + "44": 40.4, + "45": 39.4, + "46": 38.4, + "47": 37.5, + "48": 36.5, + "49": 35.6, + "50": 34.6, + "51": 33.7, + "52": 32.7, + "53": 31.8, + "54": 30.9, + "55": 29.9, + "56": 29.0, + "57": 28.1, + "58": 27.2, + "59": 26.3, + "60": 25.4, + "61": 24.5, + "62": 23.6, + "63": 22.8, + "64": 21.9, + "65": 21.1, + "66": 20.2, + "67": 19.4, + "68": 18.6, + "69": 17.8, + "70": 17.0, + "71": 16.2, + "72": 15.5, + "73": 14.7, + "74": 13.9, + "75": 13.2, + "76": 12.5, + "77": 11.8, + "78": 11.1, + "79": 10.4, + "80": 9.7, + "81": 9.1, + "82": 8.5, + "83": 7.9, + "84": 7.3, + "85": 6.7, + "86": 6.2, + "87": 5.7, + "88": 5.2, + "89": 4.8, + "90": 4.4 + } + } + }, + "EE": { + "name": "Estonia", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 56.8, + "19": 55.9, + "20": 54.9, + "21": 54.0, + "22": 53.0, + "23": 52.1, + "24": 51.1, + "25": 50.2, + "26": 49.2, + "27": 48.2, + "28": 47.3, + "29": 46.3, + "30": 45.3, + "31": 44.4, + "32": 43.4, + "33": 42.5, + "34": 41.6, + "35": 40.7, + "36": 39.7, + "37": 38.8, + "38": 37.9, + "39": 36.9, + "40": 36.0, + "41": 35.1, + "42": 34.2, + "43": 33.4, + "44": 32.5, + "45": 31.6, + "46": 30.8, + "47": 29.9, + "48": 29.0, + "49": 28.1, + "50": 27.3, + "51": 26.5, + "52": 25.6, + "53": 24.8, + "54": 24.0, + "55": 23.2, + "56": 22.4, + "57": 21.6, + "58": 20.9, + "59": 20.1, + "60": 19.3, + "61": 18.7, + "62": 17.9, + "63": 17.2, + "64": 16.6, + "65": 15.9, + "66": 15.3, + "67": 14.7, + "68": 14.0, + "69": 13.4, + "70": 12.8, + "71": 12.2, + "72": 11.6, + "73": 11.1, + "74": 10.5, + "75": 10.0, + "76": 9.4, + "77": 8.8, + "78": 8.4, + "79": 8.0, + "80": 7.5, + "81": 7.0, + "82": 6.6, + "83": 6.1, + "84": 5.7, + "85": 5.3, + "86": 4.9, + "87": 4.6, + "88": 4.3, + "89": 4.0, + "90": 3.6 + }, + "female": { + "18": 65.4, + "19": 64.4, + "20": 63.4, + "21": 62.4, + "22": 61.4, + "23": 60.4, + "24": 59.4, + "25": 58.5, + "26": 57.5, + "27": 56.5, + "28": 55.5, + "29": 54.6, + "30": 53.6, + "31": 52.6, + "32": 51.6, + "33": 50.6, + "34": 49.7, + "35": 48.7, + "36": 47.7, + "37": 46.8, + "38": 45.8, + "39": 44.9, + "40": 43.9, + "41": 42.9, + "42": 42.0, + "43": 41.1, + "44": 40.1, + "45": 39.2, + "46": 38.2, + "47": 37.3, + "48": 36.3, + "49": 35.4, + "50": 34.5, + "51": 33.5, + "52": 32.6, + "53": 31.7, + "54": 30.8, + "55": 29.9, + "56": 29.0, + "57": 28.1, + "58": 27.2, + "59": 26.3, + "60": 25.4, + "61": 24.6, + "62": 23.7, + "63": 22.8, + "64": 22.0, + "65": 21.1, + "66": 20.3, + "67": 19.5, + "68": 18.7, + "69": 17.9, + "70": 17.1, + "71": 16.3, + "72": 15.5, + "73": 14.7, + "74": 14.0, + "75": 13.2, + "76": 12.5, + "77": 11.8, + "78": 11.1, + "79": 10.4, + "80": 9.8, + "81": 9.1, + "82": 8.5, + "83": 7.9, + "84": 7.4, + "85": 6.9, + "86": 6.3, + "87": 5.9, + "88": 5.4, + "89": 5.0, + "90": 4.5 + } + } + }, + "EL": { + "name": "Greece", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 61.6, + "19": 60.6, + "20": 59.6, + "21": 58.7, + "22": 57.7, + "23": 56.7, + "24": 55.8, + "25": 54.8, + "26": 53.8, + "27": 52.8, + "28": 51.9, + "29": 50.9, + "30": 50.0, + "31": 49.0, + "32": 48.0, + "33": 47.1, + "34": 46.1, + "35": 45.1, + "36": 44.2, + "37": 43.2, + "38": 42.3, + "39": 41.3, + "40": 40.4, + "41": 39.4, + "42": 38.5, + "43": 37.5, + "44": 36.6, + "45": 35.6, + "46": 34.7, + "47": 33.8, + "48": 32.9, + "49": 31.9, + "50": 31.0, + "51": 30.1, + "52": 29.2, + "53": 28.3, + "54": 27.5, + "55": 26.6, + "56": 25.8, + "57": 24.9, + "58": 24.1, + "59": 23.3, + "60": 22.4, + "61": 21.6, + "62": 20.8, + "63": 20.1, + "64": 19.3, + "65": 18.5, + "66": 17.8, + "67": 17.0, + "68": 16.3, + "69": 15.6, + "70": 14.9, + "71": 14.2, + "72": 13.5, + "73": 12.9, + "74": 12.2, + "75": 11.5, + "76": 10.9, + "77": 10.3, + "78": 9.7, + "79": 9.2, + "80": 8.6, + "81": 8.0, + "82": 7.5, + "83": 7.0, + "84": 6.5, + "85": 6.1, + "86": 5.6, + "87": 5.2, + "88": 4.8, + "89": 4.5, + "90": 4.2 + }, + "female": { + "18": 66.6, + "19": 65.6, + "20": 64.6, + "21": 63.6, + "22": 62.6, + "23": 61.7, + "24": 60.7, + "25": 59.7, + "26": 58.7, + "27": 57.7, + "28": 56.7, + "29": 55.7, + "30": 54.7, + "31": 53.8, + "32": 52.8, + "33": 51.8, + "34": 50.8, + "35": 49.8, + "36": 48.8, + "37": 47.9, + "38": 46.9, + "39": 45.9, + "40": 44.9, + "41": 43.9, + "42": 43.0, + "43": 42.0, + "44": 41.0, + "45": 40.1, + "46": 39.1, + "47": 38.1, + "48": 37.2, + "49": 36.2, + "50": 35.3, + "51": 34.3, + "52": 33.4, + "53": 32.5, + "54": 31.5, + "55": 30.6, + "56": 29.7, + "57": 28.8, + "58": 27.9, + "59": 27.0, + "60": 26.1, + "61": 25.2, + "62": 24.3, + "63": 23.4, + "64": 22.5, + "65": 21.6, + "66": 20.8, + "67": 19.9, + "68": 19.0, + "69": 18.2, + "70": 17.4, + "71": 16.5, + "72": 15.7, + "73": 14.9, + "74": 14.1, + "75": 13.3, + "76": 12.6, + "77": 11.8, + "78": 11.1, + "79": 10.4, + "80": 9.7, + "81": 9.1, + "82": 8.4, + "83": 7.8, + "84": 7.2, + "85": 6.7, + "86": 6.2, + "87": 5.7, + "88": 5.3, + "89": 4.9, + "90": 4.5 + } + } + }, + "ES": { + "name": "Spain", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.4, + "19": 62.5, + "20": 61.5, + "21": 60.5, + "22": 59.5, + "23": 58.5, + "24": 57.6, + "25": 56.6, + "26": 55.6, + "27": 54.6, + "28": 53.7, + "29": 52.7, + "30": 51.7, + "31": 50.7, + "32": 49.8, + "33": 48.8, + "34": 47.8, + "35": 46.8, + "36": 45.9, + "37": 44.9, + "38": 43.9, + "39": 43.0, + "40": 42.0, + "41": 41.0, + "42": 40.1, + "43": 39.1, + "44": 38.2, + "45": 37.2, + "46": 36.3, + "47": 35.3, + "48": 34.4, + "49": 33.4, + "50": 32.5, + "51": 31.6, + "52": 30.7, + "53": 29.8, + "54": 28.9, + "55": 28.0, + "56": 27.1, + "57": 26.2, + "58": 25.4, + "59": 24.5, + "60": 23.7, + "61": 22.8, + "62": 22.0, + "63": 21.2, + "64": 20.4, + "65": 19.6, + "66": 18.9, + "67": 18.1, + "68": 17.3, + "69": 16.6, + "70": 15.9, + "71": 15.1, + "72": 14.4, + "73": 13.7, + "74": 13.0, + "75": 12.3, + "76": 11.7, + "77": 11.0, + "78": 10.4, + "79": 9.8, + "80": 9.2, + "81": 8.6, + "82": 8.0, + "83": 7.4, + "84": 6.9, + "85": 6.4, + "86": 6.0, + "87": 5.5, + "88": 5.1, + "89": 4.7, + "90": 4.3 + }, + "female": { + "18": 68.7, + "19": 67.7, + "20": 66.7, + "21": 65.7, + "22": 64.7, + "23": 63.7, + "24": 62.7, + "25": 61.7, + "26": 60.8, + "27": 59.8, + "28": 58.8, + "29": 57.8, + "30": 56.8, + "31": 55.8, + "32": 54.8, + "33": 53.8, + "34": 52.8, + "35": 51.9, + "36": 50.9, + "37": 49.9, + "38": 48.9, + "39": 47.9, + "40": 47.0, + "41": 46.0, + "42": 45.0, + "43": 44.0, + "44": 43.1, + "45": 42.1, + "46": 41.1, + "47": 40.1, + "48": 39.2, + "49": 38.2, + "50": 37.3, + "51": 36.3, + "52": 35.4, + "53": 34.4, + "54": 33.5, + "55": 32.6, + "56": 31.6, + "57": 30.7, + "58": 29.8, + "59": 28.9, + "60": 28.0, + "61": 27.1, + "62": 26.2, + "63": 25.3, + "64": 24.4, + "65": 23.5, + "66": 22.6, + "67": 21.7, + "68": 20.9, + "69": 20.0, + "70": 19.2, + "71": 18.3, + "72": 17.5, + "73": 16.6, + "74": 15.8, + "75": 15.0, + "76": 14.2, + "77": 13.4, + "78": 12.6, + "79": 11.9, + "80": 11.1, + "81": 10.4, + "82": 9.7, + "83": 9.0, + "84": 8.4, + "85": 7.8, + "86": 7.2, + "87": 6.6, + "88": 6.1, + "89": 5.6, + "90": 5.2 + } + } + }, + "FI": { + "name": "Finland", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 61.3, + "19": 60.3, + "20": 59.4, + "21": 58.4, + "22": 57.5, + "23": 56.5, + "24": 55.6, + "25": 54.6, + "26": 53.7, + "27": 52.7, + "28": 51.8, + "29": 50.8, + "30": 49.8, + "31": 48.9, + "32": 47.9, + "33": 47.0, + "34": 46.0, + "35": 45.1, + "36": 44.1, + "37": 43.1, + "38": 42.2, + "39": 41.2, + "40": 40.3, + "41": 39.3, + "42": 38.4, + "43": 37.5, + "44": 36.5, + "45": 35.6, + "46": 34.7, + "47": 33.7, + "48": 32.8, + "49": 31.9, + "50": 31.0, + "51": 30.1, + "52": 29.2, + "53": 28.3, + "54": 27.4, + "55": 26.5, + "56": 25.7, + "57": 24.8, + "58": 24.0, + "59": 23.1, + "60": 22.3, + "61": 21.5, + "62": 20.6, + "63": 19.8, + "64": 19.0, + "65": 18.3, + "66": 17.5, + "67": 16.7, + "68": 16.0, + "69": 15.3, + "70": 14.5, + "71": 13.8, + "72": 13.1, + "73": 12.4, + "74": 11.8, + "75": 11.1, + "76": 10.5, + "77": 9.9, + "78": 9.3, + "79": 8.7, + "80": 8.1, + "81": 7.5, + "82": 7.0, + "83": 6.5, + "84": 6.0, + "85": 5.6, + "86": 5.1, + "87": 4.7, + "88": 4.3, + "89": 4.0, + "90": 3.7 + }, + "female": { + "18": 66.5, + "19": 65.5, + "20": 64.5, + "21": 63.6, + "22": 62.6, + "23": 61.6, + "24": 60.6, + "25": 59.7, + "26": 58.7, + "27": 57.7, + "28": 56.7, + "29": 55.7, + "30": 54.7, + "31": 53.7, + "32": 52.8, + "33": 51.8, + "34": 50.8, + "35": 49.8, + "36": 48.9, + "37": 47.9, + "38": 46.9, + "39": 45.9, + "40": 45.0, + "41": 44.0, + "42": 43.0, + "43": 42.1, + "44": 41.1, + "45": 40.1, + "46": 39.2, + "47": 38.2, + "48": 37.3, + "49": 36.3, + "50": 35.4, + "51": 34.4, + "52": 33.5, + "53": 32.5, + "54": 31.6, + "55": 30.7, + "56": 29.7, + "57": 28.8, + "58": 27.9, + "59": 27.0, + "60": 26.1, + "61": 25.2, + "62": 24.3, + "63": 23.4, + "64": 22.6, + "65": 21.7, + "66": 20.8, + "67": 20.0, + "68": 19.2, + "69": 18.3, + "70": 17.5, + "71": 16.7, + "72": 15.9, + "73": 15.1, + "74": 14.3, + "75": 13.5, + "76": 12.8, + "77": 12.0, + "78": 11.3, + "79": 10.6, + "80": 9.9, + "81": 9.3, + "82": 8.6, + "83": 8.0, + "84": 7.4, + "85": 6.9, + "86": 6.3, + "87": 5.8, + "88": 5.3, + "89": 4.9, + "90": 4.4 + } + } + }, + "FR": { + "name": "France", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 62.5, + "19": 61.6, + "20": 60.6, + "21": 59.6, + "22": 58.7, + "23": 57.7, + "24": 56.7, + "25": 55.8, + "26": 54.8, + "27": 53.8, + "28": 52.9, + "29": 51.9, + "30": 51.0, + "31": 50.0, + "32": 49.0, + "33": 48.1, + "34": 47.1, + "35": 46.2, + "36": 45.2, + "37": 44.3, + "38": 43.3, + "39": 42.4, + "40": 41.4, + "41": 40.5, + "42": 39.6, + "43": 38.6, + "44": 37.7, + "45": 36.8, + "46": 35.9, + "47": 34.9, + "48": 34.0, + "49": 33.1, + "50": 32.2, + "51": 31.3, + "52": 30.4, + "53": 29.6, + "54": 28.7, + "55": 27.8, + "56": 27.0, + "57": 26.1, + "58": 25.3, + "59": 24.5, + "60": 23.7, + "61": 22.9, + "62": 22.1, + "63": 21.3, + "64": 20.5, + "65": 19.7, + "66": 19.0, + "67": 18.3, + "68": 17.5, + "69": 16.8, + "70": 16.1, + "71": 15.4, + "72": 14.7, + "73": 14.0, + "74": 13.3, + "75": 12.6, + "76": 12.0, + "77": 11.3, + "78": 10.7, + "79": 10.1, + "80": 9.4, + "81": 8.8, + "82": 8.3, + "83": 7.7, + "84": 7.1, + "85": 6.6, + "86": 6.1, + "87": 5.7, + "88": 5.2, + "89": 4.8, + "90": 4.4 + }, + "female": { + "18": 68.1, + "19": 67.1, + "20": 66.2, + "21": 65.2, + "22": 64.2, + "23": 63.2, + "24": 62.2, + "25": 61.2, + "26": 60.2, + "27": 59.3, + "28": 58.3, + "29": 57.3, + "30": 56.3, + "31": 55.3, + "32": 54.3, + "33": 53.4, + "34": 52.4, + "35": 51.4, + "36": 50.4, + "37": 49.4, + "38": 48.5, + "39": 47.5, + "40": 46.5, + "41": 45.6, + "42": 44.6, + "43": 43.6, + "44": 42.7, + "45": 41.7, + "46": 40.8, + "47": 39.8, + "48": 38.9, + "49": 37.9, + "50": 37.0, + "51": 36.1, + "52": 35.1, + "53": 34.2, + "54": 33.3, + "55": 32.4, + "56": 31.5, + "57": 30.6, + "58": 29.7, + "59": 28.8, + "60": 27.9, + "61": 27.0, + "62": 26.1, + "63": 25.2, + "64": 24.4, + "65": 23.5, + "66": 22.7, + "67": 21.8, + "68": 21.0, + "69": 20.1, + "70": 19.3, + "71": 18.5, + "72": 17.7, + "73": 16.9, + "74": 16.0, + "75": 15.2, + "76": 14.5, + "77": 13.7, + "78": 12.9, + "79": 12.2, + "80": 11.4, + "81": 10.7, + "82": 10.0, + "83": 9.3, + "84": 8.7, + "85": 8.1, + "86": 7.5, + "87": 6.9, + "88": 6.4, + "89": 5.9, + "90": 5.4 + } + } + }, + "HR": { + "name": "Croatia", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 58.0, + "19": 57.0, + "20": 56.0, + "21": 55.0, + "22": 54.1, + "23": 53.1, + "24": 52.1, + "25": 51.2, + "26": 50.2, + "27": 49.3, + "28": 48.3, + "29": 47.3, + "30": 46.4, + "31": 45.4, + "32": 44.4, + "33": 43.5, + "34": 42.5, + "35": 41.5, + "36": 40.6, + "37": 39.6, + "38": 38.7, + "39": 37.7, + "40": 36.8, + "41": 35.8, + "42": 34.9, + "43": 33.9, + "44": 33.0, + "45": 32.1, + "46": 31.2, + "47": 30.3, + "48": 29.4, + "49": 28.5, + "50": 27.6, + "51": 26.8, + "52": 25.9, + "53": 25.0, + "54": 24.2, + "55": 23.4, + "56": 22.5, + "57": 21.8, + "58": 21.0, + "59": 20.2, + "60": 19.5, + "61": 18.8, + "62": 18.0, + "63": 17.3, + "64": 16.6, + "65": 15.9, + "66": 15.3, + "67": 14.6, + "68": 14.0, + "69": 13.3, + "70": 12.7, + "71": 12.1, + "72": 11.5, + "73": 10.9, + "74": 10.4, + "75": 9.8, + "76": 9.2, + "77": 8.7, + "78": 8.1, + "79": 7.6, + "80": 7.1, + "81": 6.7, + "82": 6.2, + "83": 5.8, + "84": 5.3, + "85": 4.9, + "86": 4.6, + "87": 4.2, + "88": 3.9, + "89": 3.6, + "90": 3.3 + }, + "female": { + "18": 64.1, + "19": 63.1, + "20": 62.1, + "21": 61.1, + "22": 60.1, + "23": 59.1, + "24": 58.1, + "25": 57.2, + "26": 56.2, + "27": 55.2, + "28": 54.2, + "29": 53.2, + "30": 52.2, + "31": 51.2, + "32": 50.2, + "33": 49.3, + "34": 48.3, + "35": 47.3, + "36": 46.3, + "37": 45.3, + "38": 44.4, + "39": 43.4, + "40": 42.4, + "41": 41.4, + "42": 40.5, + "43": 39.5, + "44": 38.6, + "45": 37.6, + "46": 36.7, + "47": 35.7, + "48": 34.8, + "49": 33.8, + "50": 32.9, + "51": 31.9, + "52": 31.0, + "53": 30.1, + "54": 29.2, + "55": 28.3, + "56": 27.4, + "57": 26.5, + "58": 25.6, + "59": 24.7, + "60": 23.8, + "61": 22.9, + "62": 22.1, + "63": 21.2, + "64": 20.3, + "65": 19.5, + "66": 18.7, + "67": 17.8, + "68": 17.0, + "69": 16.2, + "70": 15.4, + "71": 14.6, + "72": 13.8, + "73": 13.1, + "74": 12.3, + "75": 11.6, + "76": 10.9, + "77": 10.2, + "78": 9.5, + "79": 8.9, + "80": 8.2, + "81": 7.6, + "82": 7.1, + "83": 6.5, + "84": 6.0, + "85": 5.5, + "86": 5.1, + "87": 4.6, + "88": 4.3, + "89": 3.9, + "90": 3.6 + } + } + }, + "HU": { + "name": "Hungary", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 55.8, + "19": 54.9, + "20": 53.9, + "21": 52.9, + "22": 51.9, + "23": 51.0, + "24": 50.0, + "25": 49.0, + "26": 48.1, + "27": 47.1, + "28": 46.1, + "29": 45.2, + "30": 44.2, + "31": 43.2, + "32": 42.3, + "33": 41.3, + "34": 40.4, + "35": 39.4, + "36": 38.4, + "37": 37.5, + "38": 36.6, + "39": 35.6, + "40": 34.7, + "41": 33.7, + "42": 32.8, + "43": 31.9, + "44": 31.0, + "45": 30.0, + "46": 29.1, + "47": 28.2, + "48": 27.3, + "49": 26.4, + "50": 25.6, + "51": 24.7, + "52": 23.9, + "53": 23.0, + "54": 22.2, + "55": 21.4, + "56": 20.6, + "57": 19.9, + "58": 19.1, + "59": 18.4, + "60": 17.7, + "61": 17.0, + "62": 16.3, + "63": 15.7, + "64": 15.1, + "65": 14.5, + "66": 14.0, + "67": 13.4, + "68": 12.9, + "69": 12.3, + "70": 11.8, + "71": 11.3, + "72": 10.8, + "73": 10.2, + "74": 9.8, + "75": 9.3, + "76": 8.8, + "77": 8.3, + "78": 7.8, + "79": 7.3, + "80": 6.9, + "81": 6.5, + "82": 6.0, + "83": 5.6, + "84": 5.3, + "85": 4.9, + "86": 4.6, + "87": 4.3, + "88": 3.9, + "89": 3.7, + "90": 3.4 + }, + "female": { + "18": 62.2, + "19": 61.2, + "20": 60.2, + "21": 59.2, + "22": 58.2, + "23": 57.2, + "24": 56.2, + "25": 55.3, + "26": 54.3, + "27": 53.3, + "28": 52.3, + "29": 51.3, + "30": 50.3, + "31": 49.4, + "32": 48.4, + "33": 47.4, + "34": 46.4, + "35": 45.5, + "36": 44.5, + "37": 43.5, + "38": 42.6, + "39": 41.6, + "40": 40.6, + "41": 39.7, + "42": 38.7, + "43": 37.8, + "44": 36.8, + "45": 35.9, + "46": 34.9, + "47": 34.0, + "48": 33.0, + "49": 32.1, + "50": 31.2, + "51": 30.3, + "52": 29.4, + "53": 28.4, + "54": 27.6, + "55": 26.7, + "56": 25.8, + "57": 25.0, + "58": 24.1, + "59": 23.3, + "60": 22.4, + "61": 21.6, + "62": 20.8, + "63": 20.1, + "64": 19.3, + "65": 18.5, + "66": 17.7, + "67": 17.0, + "68": 16.3, + "69": 15.6, + "70": 14.8, + "71": 14.1, + "72": 13.4, + "73": 12.7, + "74": 12.1, + "75": 11.4, + "76": 10.7, + "77": 10.1, + "78": 9.5, + "79": 8.9, + "80": 8.3, + "81": 7.7, + "82": 7.2, + "83": 6.6, + "84": 6.2, + "85": 5.7, + "86": 5.3, + "87": 4.9, + "88": 4.5, + "89": 4.2, + "90": 3.9 + } + } + }, + "IE": { + "name": "Ireland", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.4, + "19": 62.4, + "20": 61.4, + "21": 60.4, + "22": 59.5, + "23": 58.5, + "24": 57.5, + "25": 56.5, + "26": 55.6, + "27": 54.6, + "28": 53.6, + "29": 52.7, + "30": 51.7, + "31": 50.7, + "32": 49.8, + "33": 48.8, + "34": 47.8, + "35": 46.8, + "36": 45.9, + "37": 44.9, + "38": 43.9, + "39": 43.0, + "40": 42.0, + "41": 41.0, + "42": 40.1, + "43": 39.1, + "44": 38.2, + "45": 37.2, + "46": 36.3, + "47": 35.3, + "48": 34.4, + "49": 33.5, + "50": 32.5, + "51": 31.6, + "52": 30.7, + "53": 29.8, + "54": 28.9, + "55": 28.0, + "56": 27.1, + "57": 26.2, + "58": 25.4, + "59": 24.5, + "60": 23.6, + "61": 22.7, + "62": 21.9, + "63": 21.1, + "64": 20.2, + "65": 19.4, + "66": 18.6, + "67": 17.8, + "68": 17.0, + "69": 16.2, + "70": 15.4, + "71": 14.7, + "72": 14.0, + "73": 13.2, + "74": 12.5, + "75": 11.8, + "76": 11.2, + "77": 10.5, + "78": 9.9, + "79": 9.3, + "80": 8.7, + "81": 8.1, + "82": 7.5, + "83": 7.0, + "84": 6.6, + "85": 6.1, + "86": 5.6, + "87": 5.2, + "88": 4.9, + "89": 4.7, + "90": 4.4 + }, + "female": { + "18": 66.8, + "19": 65.8, + "20": 64.8, + "21": 63.8, + "22": 62.8, + "23": 61.8, + "24": 60.9, + "25": 59.9, + "26": 58.9, + "27": 57.9, + "28": 56.9, + "29": 55.9, + "30": 54.9, + "31": 53.9, + "32": 52.9, + "33": 52.0, + "34": 51.0, + "35": 50.0, + "36": 49.0, + "37": 48.0, + "38": 47.1, + "39": 46.1, + "40": 45.1, + "41": 44.1, + "42": 43.1, + "43": 42.2, + "44": 41.2, + "45": 40.2, + "46": 39.3, + "47": 38.3, + "48": 37.4, + "49": 36.4, + "50": 35.5, + "51": 34.5, + "52": 33.6, + "53": 32.6, + "54": 31.7, + "55": 30.8, + "56": 29.9, + "57": 28.9, + "58": 28.0, + "59": 27.1, + "60": 26.2, + "61": 25.3, + "62": 24.4, + "63": 23.5, + "64": 22.7, + "65": 21.8, + "66": 21.0, + "67": 20.1, + "68": 19.3, + "69": 18.5, + "70": 17.6, + "71": 16.8, + "72": 16.0, + "73": 15.2, + "74": 14.4, + "75": 13.6, + "76": 12.9, + "77": 12.1, + "78": 11.4, + "79": 10.7, + "80": 10.1, + "81": 9.4, + "82": 8.8, + "83": 8.2, + "84": 7.6, + "85": 7.1, + "86": 6.6, + "87": 6.1, + "88": 5.7, + "89": 5.3, + "90": 5.0 + } + } + }, + "IS": { + "name": "Iceland", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.1, + "19": 62.2, + "20": 61.2, + "21": 60.2, + "22": 59.3, + "23": 58.3, + "24": 57.4, + "25": 56.4, + "26": 55.5, + "27": 54.5, + "28": 53.6, + "29": 52.6, + "30": 51.6, + "31": 50.7, + "32": 49.7, + "33": 48.7, + "34": 47.7, + "35": 46.8, + "36": 45.8, + "37": 44.8, + "38": 43.8, + "39": 42.9, + "40": 41.9, + "41": 41.0, + "42": 40.1, + "43": 39.2, + "44": 38.2, + "45": 37.3, + "46": 36.4, + "47": 35.5, + "48": 34.6, + "49": 33.6, + "50": 32.7, + "51": 31.8, + "52": 30.9, + "53": 30.0, + "54": 29.1, + "55": 28.3, + "56": 27.4, + "57": 26.5, + "58": 25.6, + "59": 24.8, + "60": 23.8, + "61": 23.0, + "62": 22.2, + "63": 21.3, + "64": 20.4, + "65": 19.6, + "66": 18.8, + "67": 18.0, + "68": 17.2, + "69": 16.4, + "70": 15.6, + "71": 14.8, + "72": 14.1, + "73": 13.4, + "74": 12.6, + "75": 11.8, + "76": 11.2, + "77": 10.4, + "78": 9.8, + "79": 9.1, + "80": 8.5, + "81": 8.0, + "82": 7.4, + "83": 6.7, + "84": 6.1, + "85": 5.7, + "86": 5.2, + "87": 4.9, + "88": 4.4, + "89": 4.1, + "90": 3.7 + }, + "female": { + "18": 66.5, + "19": 65.5, + "20": 64.5, + "21": 63.5, + "22": 62.6, + "23": 61.6, + "24": 60.6, + "25": 59.7, + "26": 58.7, + "27": 57.7, + "28": 56.7, + "29": 55.8, + "30": 54.8, + "31": 53.8, + "32": 52.8, + "33": 51.8, + "34": 50.9, + "35": 49.9, + "36": 48.9, + "37": 48.0, + "38": 47.0, + "39": 46.0, + "40": 45.1, + "41": 44.2, + "42": 43.2, + "43": 42.3, + "44": 41.3, + "45": 40.4, + "46": 39.4, + "47": 38.5, + "48": 37.5, + "49": 36.6, + "50": 35.7, + "51": 34.7, + "52": 33.8, + "53": 32.9, + "54": 31.9, + "55": 31.0, + "56": 30.0, + "57": 29.1, + "58": 28.2, + "59": 27.2, + "60": 26.3, + "61": 25.5, + "62": 24.6, + "63": 23.7, + "64": 22.8, + "65": 22.0, + "66": 21.1, + "67": 20.2, + "68": 19.3, + "69": 18.4, + "70": 17.7, + "71": 16.9, + "72": 16.1, + "73": 15.2, + "74": 14.4, + "75": 13.6, + "76": 12.8, + "77": 12.1, + "78": 11.3, + "79": 10.6, + "80": 9.9, + "81": 9.3, + "82": 8.8, + "83": 8.3, + "84": 7.6, + "85": 7.0, + "86": 6.5, + "87": 5.9, + "88": 5.5, + "89": 5.2, + "90": 4.8 + } + } + }, + "IT": { + "name": "Italy", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.5, + "19": 62.6, + "20": 61.6, + "21": 60.6, + "22": 59.6, + "23": 58.6, + "24": 57.7, + "25": 56.7, + "26": 55.7, + "27": 54.7, + "28": 53.8, + "29": 52.8, + "30": 51.8, + "31": 50.8, + "32": 49.9, + "33": 48.9, + "34": 47.9, + "35": 47.0, + "36": 46.0, + "37": 45.0, + "38": 44.0, + "39": 43.1, + "40": 42.1, + "41": 41.2, + "42": 40.2, + "43": 39.2, + "44": 38.3, + "45": 37.3, + "46": 36.4, + "47": 35.4, + "48": 34.5, + "49": 33.6, + "50": 32.6, + "51": 31.7, + "52": 30.8, + "53": 29.9, + "54": 29.0, + "55": 28.1, + "56": 27.2, + "57": 26.3, + "58": 25.4, + "59": 24.5, + "60": 23.7, + "61": 22.8, + "62": 22.0, + "63": 21.1, + "64": 20.3, + "65": 19.5, + "66": 18.7, + "67": 17.9, + "68": 17.1, + "69": 16.3, + "70": 15.6, + "71": 14.8, + "72": 14.1, + "73": 13.4, + "74": 12.7, + "75": 12.0, + "76": 11.3, + "77": 10.6, + "78": 10.0, + "79": 9.3, + "80": 8.7, + "81": 8.2, + "82": 7.6, + "83": 7.1, + "84": 6.5, + "85": 6.0, + "86": 5.6, + "87": 5.1, + "88": 4.7, + "89": 4.3, + "90": 4.0 + }, + "female": { + "18": 67.6, + "19": 66.6, + "20": 65.6, + "21": 64.6, + "22": 63.6, + "23": 62.6, + "24": 61.6, + "25": 60.7, + "26": 59.7, + "27": 58.7, + "28": 57.7, + "29": 56.7, + "30": 55.7, + "31": 54.7, + "32": 53.7, + "33": 52.7, + "34": 51.8, + "35": 50.8, + "36": 49.8, + "37": 48.8, + "38": 47.8, + "39": 46.8, + "40": 45.9, + "41": 44.9, + "42": 43.9, + "43": 42.9, + "44": 42.0, + "45": 41.0, + "46": 40.0, + "47": 39.1, + "48": 38.1, + "49": 37.2, + "50": 36.2, + "51": 35.3, + "52": 34.3, + "53": 33.4, + "54": 32.4, + "55": 31.5, + "56": 30.6, + "57": 29.6, + "58": 28.7, + "59": 27.8, + "60": 26.9, + "61": 26.0, + "62": 25.1, + "63": 24.2, + "64": 23.3, + "65": 22.4, + "66": 21.5, + "67": 20.7, + "68": 19.8, + "69": 19.0, + "70": 18.1, + "71": 17.3, + "72": 16.5, + "73": 15.6, + "74": 14.8, + "75": 14.0, + "76": 13.3, + "77": 12.5, + "78": 11.8, + "79": 11.0, + "80": 10.3, + "81": 9.7, + "82": 9.0, + "83": 8.4, + "84": 7.7, + "85": 7.2, + "86": 6.6, + "87": 6.1, + "88": 5.6, + "89": 5.1, + "90": 4.7 + } + } + }, + "LT": { + "name": "Lithuania", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 55.3, + "19": 54.3, + "20": 53.4, + "21": 52.4, + "22": 51.4, + "23": 50.5, + "24": 49.5, + "25": 48.5, + "26": 47.6, + "27": 46.6, + "28": 45.7, + "29": 44.7, + "30": 43.8, + "31": 42.8, + "32": 41.9, + "33": 40.9, + "34": 40.0, + "35": 39.1, + "36": 38.2, + "37": 37.3, + "38": 36.3, + "39": 35.4, + "40": 34.6, + "41": 33.7, + "42": 32.7, + "43": 31.9, + "44": 31.0, + "45": 30.2, + "46": 29.3, + "47": 28.5, + "48": 27.7, + "49": 26.9, + "50": 26.1, + "51": 25.3, + "52": 24.5, + "53": 23.7, + "54": 23.0, + "55": 22.2, + "56": 21.5, + "57": 20.8, + "58": 20.1, + "59": 19.3, + "60": 18.6, + "61": 17.9, + "62": 17.3, + "63": 16.6, + "64": 16.0, + "65": 15.4, + "66": 14.7, + "67": 14.2, + "68": 13.6, + "69": 13.0, + "70": 12.4, + "71": 11.9, + "72": 11.4, + "73": 10.8, + "74": 10.3, + "75": 9.8, + "76": 9.3, + "77": 8.8, + "78": 8.3, + "79": 7.9, + "80": 7.5, + "81": 7.1, + "82": 6.7, + "83": 6.2, + "84": 5.8, + "85": 5.4, + "86": 5.1, + "87": 4.7, + "88": 4.4, + "89": 4.1, + "90": 3.8 + }, + "female": { + "18": 64.1, + "19": 63.1, + "20": 62.1, + "21": 61.1, + "22": 60.1, + "23": 59.2, + "24": 58.2, + "25": 57.2, + "26": 56.2, + "27": 55.2, + "28": 54.2, + "29": 53.2, + "30": 52.2, + "31": 51.3, + "32": 50.3, + "33": 49.3, + "34": 48.4, + "35": 47.4, + "36": 46.5, + "37": 45.5, + "38": 44.5, + "39": 43.6, + "40": 42.7, + "41": 41.7, + "42": 40.8, + "43": 39.8, + "44": 38.9, + "45": 37.9, + "46": 37.0, + "47": 36.1, + "48": 35.2, + "49": 34.3, + "50": 33.4, + "51": 32.4, + "52": 31.5, + "53": 30.6, + "54": 29.8, + "55": 28.9, + "56": 28.0, + "57": 27.1, + "58": 26.3, + "59": 25.4, + "60": 24.5, + "61": 23.7, + "62": 22.8, + "63": 22.0, + "64": 21.2, + "65": 20.3, + "66": 19.5, + "67": 18.7, + "68": 17.9, + "69": 17.1, + "70": 16.3, + "71": 15.6, + "72": 14.8, + "73": 14.1, + "74": 13.3, + "75": 12.6, + "76": 11.8, + "77": 11.2, + "78": 10.5, + "79": 9.8, + "80": 9.2, + "81": 8.6, + "82": 8.0, + "83": 7.4, + "84": 6.8, + "85": 6.3, + "86": 5.8, + "87": 5.3, + "88": 4.9, + "89": 4.5, + "90": 4.1 + } + } + }, + "LU": { + "name": "Luxembourg", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.8, + "19": 62.8, + "20": 61.8, + "21": 60.9, + "22": 59.9, + "23": 58.9, + "24": 57.9, + "25": 56.9, + "26": 56.0, + "27": 55.0, + "28": 54.0, + "29": 53.0, + "30": 52.0, + "31": 51.1, + "32": 50.1, + "33": 49.1, + "34": 48.1, + "35": 47.1, + "36": 46.2, + "37": 45.2, + "38": 44.2, + "39": 43.2, + "40": 42.3, + "41": 41.4, + "42": 40.4, + "43": 39.4, + "44": 38.5, + "45": 37.5, + "46": 36.5, + "47": 35.6, + "48": 34.7, + "49": 33.7, + "50": 32.8, + "51": 31.8, + "52": 30.9, + "53": 30.0, + "54": 29.1, + "55": 28.2, + "56": 27.3, + "57": 26.4, + "58": 25.5, + "59": 24.6, + "60": 23.8, + "61": 23.0, + "62": 22.1, + "63": 21.3, + "64": 20.4, + "65": 19.6, + "66": 18.8, + "67": 18.0, + "68": 17.2, + "69": 16.4, + "70": 15.7, + "71": 14.9, + "72": 14.2, + "73": 13.5, + "74": 12.8, + "75": 12.1, + "76": 11.4, + "77": 10.8, + "78": 10.2, + "79": 9.6, + "80": 9.0, + "81": 8.4, + "82": 7.9, + "83": 7.4, + "84": 6.8, + "85": 6.3, + "86": 5.9, + "87": 5.6, + "88": 5.2, + "89": 4.7, + "90": 4.4 + }, + "female": { + "18": 67.4, + "19": 66.4, + "20": 65.4, + "21": 64.4, + "22": 63.4, + "23": 62.4, + "24": 61.4, + "25": 60.4, + "26": 59.4, + "27": 58.4, + "28": 57.4, + "29": 56.5, + "30": 55.5, + "31": 54.5, + "32": 53.5, + "33": 52.5, + "34": 51.5, + "35": 50.6, + "36": 49.6, + "37": 48.6, + "38": 47.6, + "39": 46.6, + "40": 45.6, + "41": 44.6, + "42": 43.7, + "43": 42.7, + "44": 41.7, + "45": 40.8, + "46": 39.8, + "47": 38.8, + "48": 37.8, + "49": 36.9, + "50": 35.9, + "51": 35.0, + "52": 34.0, + "53": 33.1, + "54": 32.1, + "55": 31.2, + "56": 30.3, + "57": 29.3, + "58": 28.4, + "59": 27.5, + "60": 26.6, + "61": 25.7, + "62": 24.8, + "63": 23.9, + "64": 23.1, + "65": 22.2, + "66": 21.3, + "67": 20.5, + "68": 19.6, + "69": 18.8, + "70": 17.9, + "71": 17.2, + "72": 16.4, + "73": 15.6, + "74": 14.8, + "75": 14.0, + "76": 13.2, + "77": 12.4, + "78": 11.6, + "79": 11.0, + "80": 10.3, + "81": 9.6, + "82": 8.9, + "83": 8.3, + "84": 7.7, + "85": 7.1, + "86": 6.6, + "87": 6.1, + "88": 5.5, + "89": 5.1, + "90": 4.6 + } + } + }, + "LV": { + "name": "Latvia", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 52.9, + "19": 51.9, + "20": 51.0, + "21": 50.0, + "22": 49.1, + "23": 48.1, + "24": 47.2, + "25": 46.2, + "26": 45.3, + "27": 44.3, + "28": 43.4, + "29": 42.5, + "30": 41.5, + "31": 40.6, + "32": 39.7, + "33": 38.8, + "34": 37.8, + "35": 37.0, + "36": 36.1, + "37": 35.2, + "38": 34.3, + "39": 33.4, + "40": 32.6, + "41": 31.8, + "42": 31.0, + "43": 30.2, + "44": 29.3, + "45": 28.5, + "46": 27.7, + "47": 26.9, + "48": 26.1, + "49": 25.3, + "50": 24.6, + "51": 23.8, + "52": 23.1, + "53": 22.3, + "54": 21.6, + "55": 20.9, + "56": 20.2, + "57": 19.5, + "58": 18.8, + "59": 18.1, + "60": 17.5, + "61": 16.8, + "62": 16.2, + "63": 15.6, + "64": 15.0, + "65": 14.4, + "66": 13.9, + "67": 13.3, + "68": 12.8, + "69": 12.3, + "70": 11.7, + "71": 11.2, + "72": 10.7, + "73": 10.3, + "74": 9.8, + "75": 9.3, + "76": 8.8, + "77": 8.3, + "78": 7.9, + "79": 7.5, + "80": 7.1, + "81": 6.7, + "82": 6.3, + "83": 5.9, + "84": 5.4, + "85": 5.1, + "86": 4.7, + "87": 4.4, + "88": 4.1, + "89": 3.7, + "90": 3.5 + }, + "female": { + "18": 62.9, + "19": 61.9, + "20": 60.9, + "21": 59.9, + "22": 58.9, + "23": 57.9, + "24": 57.0, + "25": 56.0, + "26": 55.0, + "27": 54.0, + "28": 53.0, + "29": 52.0, + "30": 51.1, + "31": 50.1, + "32": 49.1, + "33": 48.1, + "34": 47.2, + "35": 46.2, + "36": 45.3, + "37": 44.3, + "38": 43.4, + "39": 42.5, + "40": 41.5, + "41": 40.6, + "42": 39.6, + "43": 38.7, + "44": 37.8, + "45": 36.8, + "46": 35.9, + "47": 35.0, + "48": 34.1, + "49": 33.2, + "50": 32.3, + "51": 31.4, + "52": 30.5, + "53": 29.6, + "54": 28.7, + "55": 27.8, + "56": 26.9, + "57": 26.1, + "58": 25.2, + "59": 24.3, + "60": 23.5, + "61": 22.6, + "62": 21.8, + "63": 21.0, + "64": 20.2, + "65": 19.4, + "66": 18.6, + "67": 17.8, + "68": 17.0, + "69": 16.3, + "70": 15.5, + "71": 14.8, + "72": 14.1, + "73": 13.4, + "74": 12.7, + "75": 12.0, + "76": 11.3, + "77": 10.7, + "78": 10.0, + "79": 9.4, + "80": 8.8, + "81": 8.2, + "82": 7.6, + "83": 7.1, + "84": 6.5, + "85": 6.0, + "86": 5.6, + "87": 5.1, + "88": 4.7, + "89": 4.4, + "90": 4.1 + } + } + }, + "MT": { + "name": "Malta", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.8, + "19": 62.8, + "20": 61.9, + "21": 60.9, + "22": 59.9, + "23": 58.9, + "24": 57.9, + "25": 56.9, + "26": 55.9, + "27": 54.9, + "28": 54.0, + "29": 53.0, + "30": 52.0, + "31": 51.0, + "32": 50.0, + "33": 49.1, + "34": 48.1, + "35": 47.1, + "36": 46.1, + "37": 45.1, + "38": 44.1, + "39": 43.2, + "40": 42.2, + "41": 41.2, + "42": 40.3, + "43": 39.3, + "44": 38.3, + "45": 37.4, + "46": 36.4, + "47": 35.5, + "48": 34.5, + "49": 33.6, + "50": 32.6, + "51": 31.7, + "52": 30.8, + "53": 29.8, + "54": 28.9, + "55": 28.0, + "56": 27.2, + "57": 26.3, + "58": 25.4, + "59": 24.6, + "60": 23.7, + "61": 22.8, + "62": 22.0, + "63": 21.1, + "64": 20.3, + "65": 19.5, + "66": 18.7, + "67": 17.9, + "68": 17.1, + "69": 16.3, + "70": 15.6, + "71": 14.8, + "72": 14.0, + "73": 13.3, + "74": 12.5, + "75": 11.8, + "76": 11.1, + "77": 10.4, + "78": 9.7, + "79": 9.1, + "80": 8.5, + "81": 7.9, + "82": 7.3, + "83": 6.9, + "84": 6.4, + "85": 5.8, + "86": 5.4, + "87": 4.9, + "88": 4.5, + "89": 4.1, + "90": 3.8 + }, + "female": { + "18": 67.2, + "19": 66.2, + "20": 65.2, + "21": 64.2, + "22": 63.2, + "23": 62.2, + "24": 61.2, + "25": 60.2, + "26": 59.2, + "27": 58.2, + "28": 57.3, + "29": 56.3, + "30": 55.3, + "31": 54.3, + "32": 53.3, + "33": 52.3, + "34": 51.3, + "35": 50.4, + "36": 49.4, + "37": 48.4, + "38": 47.4, + "39": 46.4, + "40": 45.4, + "41": 44.4, + "42": 43.5, + "43": 42.5, + "44": 41.6, + "45": 40.6, + "46": 39.6, + "47": 38.6, + "48": 37.7, + "49": 36.7, + "50": 35.8, + "51": 34.8, + "52": 33.9, + "53": 32.9, + "54": 32.0, + "55": 31.0, + "56": 30.1, + "57": 29.1, + "58": 28.2, + "59": 27.3, + "60": 26.4, + "61": 25.4, + "62": 24.5, + "63": 23.7, + "64": 22.8, + "65": 21.9, + "66": 21.0, + "67": 20.2, + "68": 19.3, + "69": 18.5, + "70": 17.6, + "71": 16.8, + "72": 16.0, + "73": 15.2, + "74": 14.4, + "75": 13.6, + "76": 12.9, + "77": 12.1, + "78": 11.3, + "79": 10.6, + "80": 9.9, + "81": 9.2, + "82": 8.6, + "83": 8.0, + "84": 7.4, + "85": 6.9, + "86": 6.4, + "87": 5.9, + "88": 5.5, + "89": 5.0, + "90": 4.7 + } + } + }, + "NL": { + "name": "Netherlands", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 62.8, + "19": 61.8, + "20": 60.8, + "21": 59.9, + "22": 58.9, + "23": 57.9, + "24": 56.9, + "25": 55.9, + "26": 55.0, + "27": 54.0, + "28": 53.0, + "29": 52.0, + "30": 51.1, + "31": 50.1, + "32": 49.1, + "33": 48.1, + "34": 47.2, + "35": 46.2, + "36": 45.2, + "37": 44.3, + "38": 43.3, + "39": 42.3, + "40": 41.4, + "41": 40.4, + "42": 39.5, + "43": 38.5, + "44": 37.6, + "45": 36.6, + "46": 35.7, + "47": 34.7, + "48": 33.8, + "49": 32.8, + "50": 31.9, + "51": 31.0, + "52": 30.1, + "53": 29.1, + "54": 28.2, + "55": 27.3, + "56": 26.4, + "57": 25.5, + "58": 24.7, + "59": 23.8, + "60": 22.9, + "61": 22.1, + "62": 21.2, + "63": 20.4, + "64": 19.6, + "65": 18.8, + "66": 18.0, + "67": 17.2, + "68": 16.4, + "69": 15.6, + "70": 14.9, + "71": 14.1, + "72": 13.4, + "73": 12.7, + "74": 12.0, + "75": 11.3, + "76": 10.6, + "77": 10.0, + "78": 9.4, + "79": 8.8, + "80": 8.2, + "81": 7.6, + "82": 7.1, + "83": 6.5, + "84": 6.1, + "85": 5.6, + "86": 5.1, + "87": 4.7, + "88": 4.3, + "89": 3.9, + "90": 3.6 + }, + "female": { + "18": 65.7, + "19": 64.7, + "20": 63.7, + "21": 62.7, + "22": 61.8, + "23": 60.8, + "24": 59.8, + "25": 58.8, + "26": 57.8, + "27": 56.8, + "28": 55.8, + "29": 54.8, + "30": 53.9, + "31": 52.9, + "32": 51.9, + "33": 50.9, + "34": 49.9, + "35": 48.9, + "36": 48.0, + "37": 47.0, + "38": 46.0, + "39": 45.0, + "40": 44.1, + "41": 43.1, + "42": 42.1, + "43": 41.1, + "44": 40.2, + "45": 39.2, + "46": 38.3, + "47": 37.3, + "48": 36.3, + "49": 35.4, + "50": 34.4, + "51": 33.5, + "52": 32.6, + "53": 31.6, + "54": 30.7, + "55": 29.8, + "56": 28.9, + "57": 27.9, + "58": 27.0, + "59": 26.1, + "60": 25.2, + "61": 24.4, + "62": 23.5, + "63": 22.6, + "64": 21.8, + "65": 20.9, + "66": 20.1, + "67": 19.2, + "68": 18.4, + "69": 17.6, + "70": 16.8, + "71": 16.0, + "72": 15.3, + "73": 14.5, + "74": 13.7, + "75": 13.0, + "76": 12.2, + "77": 11.5, + "78": 10.8, + "79": 10.2, + "80": 9.5, + "81": 8.8, + "82": 8.2, + "83": 7.6, + "84": 7.1, + "85": 6.5, + "86": 6.0, + "87": 5.5, + "88": 5.0, + "89": 4.5, + "90": 4.1 + } + } + }, + "NO": { + "name": "Norway", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.8, + "19": 62.8, + "20": 61.8, + "21": 60.9, + "22": 59.9, + "23": 58.9, + "24": 58.0, + "25": 57.0, + "26": 56.0, + "27": 55.1, + "28": 54.1, + "29": 53.1, + "30": 52.1, + "31": 51.2, + "32": 50.2, + "33": 49.3, + "34": 48.3, + "35": 47.3, + "36": 46.4, + "37": 45.4, + "38": 44.4, + "39": 43.5, + "40": 42.5, + "41": 41.6, + "42": 40.6, + "43": 39.7, + "44": 38.7, + "45": 37.8, + "46": 36.8, + "47": 35.9, + "48": 35.0, + "49": 34.0, + "50": 33.1, + "51": 32.1, + "52": 31.2, + "53": 30.3, + "54": 29.4, + "55": 28.5, + "56": 27.5, + "57": 26.6, + "58": 25.7, + "59": 24.8, + "60": 24.0, + "61": 23.1, + "62": 22.2, + "63": 21.4, + "64": 20.5, + "65": 19.7, + "66": 18.9, + "67": 18.1, + "68": 17.3, + "69": 16.5, + "70": 15.7, + "71": 14.9, + "72": 14.2, + "73": 13.4, + "74": 12.7, + "75": 12.0, + "76": 11.3, + "77": 10.7, + "78": 10.0, + "79": 9.4, + "80": 8.8, + "81": 8.2, + "82": 7.6, + "83": 7.0, + "84": 6.5, + "85": 6.0, + "86": 5.5, + "87": 5.1, + "88": 4.7, + "89": 4.2, + "90": 3.9 + }, + "female": { + "18": 66.9, + "19": 65.9, + "20": 64.9, + "21": 63.9, + "22": 63.0, + "23": 62.0, + "24": 61.0, + "25": 60.0, + "26": 59.0, + "27": 58.0, + "28": 57.0, + "29": 56.1, + "30": 55.1, + "31": 54.1, + "32": 53.1, + "33": 52.1, + "34": 51.2, + "35": 50.2, + "36": 49.2, + "37": 48.2, + "38": 47.2, + "39": 46.3, + "40": 45.3, + "41": 44.3, + "42": 43.4, + "43": 42.4, + "44": 41.4, + "45": 40.5, + "46": 39.5, + "47": 38.5, + "48": 37.6, + "49": 36.6, + "50": 35.7, + "51": 34.7, + "52": 33.8, + "53": 32.8, + "54": 31.9, + "55": 30.9, + "56": 30.0, + "57": 29.1, + "58": 28.2, + "59": 27.3, + "60": 26.4, + "61": 25.5, + "62": 24.6, + "63": 23.7, + "64": 22.8, + "65": 21.9, + "66": 21.0, + "67": 20.2, + "68": 19.3, + "69": 18.5, + "70": 17.7, + "71": 16.8, + "72": 16.0, + "73": 15.2, + "74": 14.4, + "75": 13.7, + "76": 12.9, + "77": 12.2, + "78": 11.5, + "79": 10.8, + "80": 10.1, + "81": 9.4, + "82": 8.8, + "83": 8.1, + "84": 7.6, + "85": 7.0, + "86": 6.4, + "87": 5.9, + "88": 5.5, + "89": 5.0, + "90": 4.6 + } + } + }, + "PL": { + "name": "Poland", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 57.0, + "19": 56.0, + "20": 55.1, + "21": 54.1, + "22": 53.1, + "23": 52.2, + "24": 51.2, + "25": 50.3, + "26": 49.3, + "27": 48.4, + "28": 47.4, + "29": 46.5, + "30": 45.5, + "31": 44.6, + "32": 43.7, + "33": 42.7, + "34": 41.8, + "35": 40.9, + "36": 39.9, + "37": 39.0, + "38": 38.1, + "39": 37.2, + "40": 36.3, + "41": 35.4, + "42": 34.5, + "43": 33.6, + "44": 32.7, + "45": 31.8, + "46": 30.9, + "47": 30.0, + "48": 29.2, + "49": 28.3, + "50": 27.5, + "51": 26.6, + "52": 25.8, + "53": 25.0, + "54": 24.2, + "55": 23.4, + "56": 22.6, + "57": 21.8, + "58": 21.1, + "59": 20.3, + "60": 19.6, + "61": 18.8, + "62": 18.1, + "63": 17.5, + "64": 16.8, + "65": 16.1, + "66": 15.5, + "67": 14.9, + "68": 14.3, + "69": 13.7, + "70": 13.1, + "71": 12.6, + "72": 12.0, + "73": 11.4, + "74": 10.9, + "75": 10.3, + "76": 9.8, + "77": 9.3, + "78": 8.8, + "79": 8.3, + "80": 7.9, + "81": 7.4, + "82": 6.9, + "83": 6.5, + "84": 6.1, + "85": 5.7, + "86": 5.4, + "87": 5.0, + "88": 4.7, + "89": 4.4, + "90": 4.2 + }, + "female": { + "18": 64.4, + "19": 63.4, + "20": 62.4, + "21": 61.4, + "22": 60.5, + "23": 59.5, + "24": 58.5, + "25": 57.5, + "26": 56.5, + "27": 55.5, + "28": 54.6, + "29": 53.6, + "30": 52.6, + "31": 51.6, + "32": 50.6, + "33": 49.7, + "34": 48.7, + "35": 47.7, + "36": 46.7, + "37": 45.8, + "38": 44.8, + "39": 43.8, + "40": 42.9, + "41": 41.9, + "42": 40.9, + "43": 40.0, + "44": 39.0, + "45": 38.1, + "46": 37.1, + "47": 36.2, + "48": 35.2, + "49": 34.3, + "50": 33.4, + "51": 32.4, + "52": 31.5, + "53": 30.6, + "54": 29.7, + "55": 28.8, + "56": 27.9, + "57": 27.0, + "58": 26.1, + "59": 25.2, + "60": 24.4, + "61": 23.5, + "62": 22.7, + "63": 21.8, + "64": 21.0, + "65": 20.2, + "66": 19.4, + "67": 18.6, + "68": 17.8, + "69": 17.1, + "70": 16.3, + "71": 15.6, + "72": 14.8, + "73": 14.1, + "74": 13.4, + "75": 12.7, + "76": 12.0, + "77": 11.3, + "78": 10.7, + "79": 10.0, + "80": 9.4, + "81": 8.8, + "82": 8.2, + "83": 7.7, + "84": 7.2, + "85": 6.6, + "86": 6.2, + "87": 5.7, + "88": 5.3, + "89": 4.9, + "90": 4.5 + } + } + }, + "PT": { + "name": "Portugal", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 61.8, + "19": 60.8, + "20": 59.8, + "21": 58.9, + "22": 57.9, + "23": 56.9, + "24": 56.0, + "25": 55.0, + "26": 54.0, + "27": 53.1, + "28": 52.1, + "29": 51.1, + "30": 50.2, + "31": 49.2, + "32": 48.2, + "33": 47.3, + "34": 46.3, + "35": 45.3, + "36": 44.4, + "37": 43.4, + "38": 42.5, + "39": 41.5, + "40": 40.5, + "41": 39.6, + "42": 38.6, + "43": 37.7, + "44": 36.8, + "45": 35.8, + "46": 34.9, + "47": 34.0, + "48": 33.1, + "49": 32.2, + "50": 31.3, + "51": 30.4, + "52": 29.5, + "53": 28.6, + "54": 27.8, + "55": 26.9, + "56": 26.1, + "57": 25.3, + "58": 24.5, + "59": 23.7, + "60": 22.9, + "61": 22.1, + "62": 21.3, + "63": 20.5, + "64": 19.8, + "65": 19.0, + "66": 18.3, + "67": 17.5, + "68": 16.8, + "69": 16.1, + "70": 15.4, + "71": 14.7, + "72": 14.0, + "73": 13.3, + "74": 12.6, + "75": 11.9, + "76": 11.2, + "77": 10.6, + "78": 9.9, + "79": 9.3, + "80": 8.7, + "81": 8.2, + "82": 7.6, + "83": 7.0, + "84": 6.5, + "85": 6.0, + "86": 5.6, + "87": 5.1, + "88": 4.7, + "89": 4.3, + "90": 4.0 + }, + "female": { + "18": 67.4, + "19": 66.4, + "20": 65.4, + "21": 64.4, + "22": 63.4, + "23": 62.4, + "24": 61.4, + "25": 60.4, + "26": 59.5, + "27": 58.5, + "28": 57.5, + "29": 56.5, + "30": 55.5, + "31": 54.5, + "32": 53.6, + "33": 52.6, + "34": 51.6, + "35": 50.6, + "36": 49.6, + "37": 48.7, + "38": 47.7, + "39": 46.7, + "40": 45.7, + "41": 44.8, + "42": 43.8, + "43": 42.8, + "44": 41.9, + "45": 40.9, + "46": 40.0, + "47": 39.0, + "48": 38.0, + "49": 37.1, + "50": 36.2, + "51": 35.2, + "52": 34.3, + "53": 33.4, + "54": 32.4, + "55": 31.5, + "56": 30.6, + "57": 29.7, + "58": 28.7, + "59": 27.8, + "60": 26.9, + "61": 26.0, + "62": 25.1, + "63": 24.2, + "64": 23.4, + "65": 22.5, + "66": 21.6, + "67": 20.7, + "68": 19.9, + "69": 19.0, + "70": 18.1, + "71": 17.3, + "72": 16.5, + "73": 15.6, + "74": 14.8, + "75": 14.0, + "76": 13.2, + "77": 12.5, + "78": 11.7, + "79": 11.0, + "80": 10.2, + "81": 9.6, + "82": 8.9, + "83": 8.3, + "84": 7.7, + "85": 7.1, + "86": 6.6, + "87": 6.0, + "88": 5.6, + "89": 5.1, + "90": 4.7 + } + } + }, + "RO": { + "name": "Romania", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 55.2, + "19": 54.3, + "20": 53.3, + "21": 52.3, + "22": 51.4, + "23": 50.4, + "24": 49.5, + "25": 48.5, + "26": 47.5, + "27": 46.6, + "28": 45.6, + "29": 44.6, + "30": 43.7, + "31": 42.7, + "32": 41.8, + "33": 40.8, + "34": 39.9, + "35": 38.9, + "36": 38.0, + "37": 37.1, + "38": 36.1, + "39": 35.2, + "40": 34.3, + "41": 33.4, + "42": 32.5, + "43": 31.6, + "44": 30.7, + "45": 29.8, + "46": 28.9, + "47": 28.1, + "48": 27.2, + "49": 26.4, + "50": 25.6, + "51": 24.8, + "52": 24.0, + "53": 23.2, + "54": 22.4, + "55": 21.7, + "56": 20.9, + "57": 20.2, + "58": 19.5, + "59": 18.8, + "60": 18.1, + "61": 17.5, + "62": 16.8, + "63": 16.2, + "64": 15.6, + "65": 15.0, + "66": 14.4, + "67": 13.8, + "68": 13.3, + "69": 12.7, + "70": 12.2, + "71": 11.6, + "72": 11.1, + "73": 10.6, + "74": 10.1, + "75": 9.6, + "76": 9.1, + "77": 8.6, + "78": 8.1, + "79": 7.6, + "80": 7.2, + "81": 6.8, + "82": 6.3, + "83": 5.9, + "84": 5.6, + "85": 5.2, + "86": 4.9, + "87": 4.6, + "88": 4.3, + "89": 4.1, + "90": 3.8 + }, + "female": { + "18": 62.8, + "19": 61.8, + "20": 60.8, + "21": 59.9, + "22": 58.9, + "23": 57.9, + "24": 56.9, + "25": 55.9, + "26": 54.9, + "27": 54.0, + "28": 53.0, + "29": 52.0, + "30": 51.0, + "31": 50.0, + "32": 49.0, + "33": 48.1, + "34": 47.1, + "35": 46.1, + "36": 45.2, + "37": 44.2, + "38": 43.2, + "39": 42.3, + "40": 41.3, + "41": 40.3, + "42": 39.4, + "43": 38.4, + "44": 37.5, + "45": 36.6, + "46": 35.6, + "47": 34.7, + "48": 33.8, + "49": 32.8, + "50": 31.9, + "51": 31.0, + "52": 30.1, + "53": 29.2, + "54": 28.3, + "55": 27.4, + "56": 26.5, + "57": 25.7, + "58": 24.8, + "59": 23.9, + "60": 23.1, + "61": 22.2, + "62": 21.4, + "63": 20.6, + "64": 19.8, + "65": 19.0, + "66": 18.2, + "67": 17.4, + "68": 16.6, + "69": 15.8, + "70": 15.0, + "71": 14.3, + "72": 13.6, + "73": 12.8, + "74": 12.1, + "75": 11.5, + "76": 10.8, + "77": 10.1, + "78": 9.5, + "79": 8.9, + "80": 8.3, + "81": 7.7, + "82": 7.2, + "83": 6.7, + "84": 6.3, + "85": 5.8, + "86": 5.4, + "87": 5.0, + "88": 4.7, + "89": 4.4, + "90": 4.1 + } + } + }, + "SE": { + "name": "Sweden", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 63.9, + "19": 62.9, + "20": 62.0, + "21": 61.0, + "22": 60.0, + "23": 59.1, + "24": 58.1, + "25": 57.1, + "26": 56.1, + "27": 55.2, + "28": 54.2, + "29": 53.2, + "30": 52.3, + "31": 51.3, + "32": 50.3, + "33": 49.4, + "34": 48.4, + "35": 47.5, + "36": 46.5, + "37": 45.5, + "38": 44.5, + "39": 43.6, + "40": 42.6, + "41": 41.7, + "42": 40.7, + "43": 39.7, + "44": 38.8, + "45": 37.8, + "46": 36.9, + "47": 35.9, + "48": 35.0, + "49": 34.0, + "50": 33.1, + "51": 32.1, + "52": 31.2, + "53": 30.3, + "54": 29.3, + "55": 28.4, + "56": 27.5, + "57": 26.6, + "58": 25.7, + "59": 24.8, + "60": 23.9, + "61": 23.1, + "62": 22.2, + "63": 21.3, + "64": 20.5, + "65": 19.7, + "66": 18.8, + "67": 18.1, + "68": 17.2, + "69": 16.5, + "70": 15.7, + "71": 14.9, + "72": 14.2, + "73": 13.5, + "74": 12.7, + "75": 12.0, + "76": 11.3, + "77": 10.7, + "78": 10.0, + "79": 9.4, + "80": 8.7, + "81": 8.1, + "82": 7.6, + "83": 7.0, + "84": 6.5, + "85": 5.9, + "86": 5.5, + "87": 5.0, + "88": 4.6, + "89": 4.2, + "90": 3.9 + }, + "female": { + "18": 67.2, + "19": 66.2, + "20": 65.2, + "21": 64.2, + "22": 63.2, + "23": 62.3, + "24": 61.3, + "25": 60.3, + "26": 59.3, + "27": 58.3, + "28": 57.3, + "29": 56.3, + "30": 55.3, + "31": 54.4, + "32": 53.4, + "33": 52.4, + "34": 51.4, + "35": 50.4, + "36": 49.5, + "37": 48.5, + "38": 47.5, + "39": 46.5, + "40": 45.6, + "41": 44.6, + "42": 43.6, + "43": 42.6, + "44": 41.7, + "45": 40.7, + "46": 39.7, + "47": 38.7, + "48": 37.8, + "49": 36.8, + "50": 35.9, + "51": 34.9, + "52": 34.0, + "53": 33.0, + "54": 32.1, + "55": 31.1, + "56": 30.2, + "57": 29.3, + "58": 28.4, + "59": 27.4, + "60": 26.5, + "61": 25.6, + "62": 24.7, + "63": 23.8, + "64": 22.9, + "65": 22.1, + "66": 21.2, + "67": 20.3, + "68": 19.5, + "69": 18.7, + "70": 17.9, + "71": 17.0, + "72": 16.2, + "73": 15.4, + "74": 14.6, + "75": 13.9, + "76": 13.1, + "77": 12.4, + "78": 11.7, + "79": 11.0, + "80": 10.3, + "81": 9.6, + "82": 9.0, + "83": 8.3, + "84": 7.7, + "85": 7.2, + "86": 6.6, + "87": 6.1, + "88": 5.6, + "89": 5.1, + "90": 4.7 + } + } + }, + "SI": { + "name": "Slovenia", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 61.3, + "19": 60.3, + "20": 59.3, + "21": 58.4, + "22": 57.4, + "23": 56.4, + "24": 55.4, + "25": 54.5, + "26": 53.5, + "27": 52.5, + "28": 51.5, + "29": 50.6, + "30": 49.6, + "31": 48.6, + "32": 47.7, + "33": 46.7, + "34": 45.7, + "35": 44.7, + "36": 43.8, + "37": 42.8, + "38": 41.9, + "39": 40.9, + "40": 39.9, + "41": 39.0, + "42": 38.0, + "43": 37.1, + "44": 36.1, + "45": 35.2, + "46": 34.3, + "47": 33.3, + "48": 32.4, + "49": 31.5, + "50": 30.6, + "51": 29.7, + "52": 28.8, + "53": 27.9, + "54": 27.0, + "55": 26.2, + "56": 25.3, + "57": 24.4, + "58": 23.6, + "59": 22.8, + "60": 22.0, + "61": 21.2, + "62": 20.4, + "63": 19.6, + "64": 18.8, + "65": 18.1, + "66": 17.3, + "67": 16.6, + "68": 15.9, + "69": 15.1, + "70": 14.5, + "71": 13.8, + "72": 13.1, + "73": 12.5, + "74": 11.8, + "75": 11.2, + "76": 10.6, + "77": 10.0, + "78": 9.3, + "79": 8.7, + "80": 8.2, + "81": 7.6, + "82": 7.1, + "83": 6.6, + "84": 6.2, + "85": 5.8, + "86": 5.3, + "87": 4.9, + "88": 4.6, + "89": 4.2, + "90": 3.9 + }, + "female": { + "18": 66.9, + "19": 65.9, + "20": 64.9, + "21": 63.9, + "22": 62.9, + "23": 62.0, + "24": 61.0, + "25": 60.0, + "26": 59.0, + "27": 58.0, + "28": 57.0, + "29": 56.1, + "30": 55.1, + "31": 54.1, + "32": 53.1, + "33": 52.1, + "34": 51.1, + "35": 50.1, + "36": 49.2, + "37": 48.2, + "38": 47.2, + "39": 46.2, + "40": 45.2, + "41": 44.3, + "42": 43.3, + "43": 42.3, + "44": 41.3, + "45": 40.4, + "46": 39.4, + "47": 38.4, + "48": 37.5, + "49": 36.5, + "50": 35.6, + "51": 34.7, + "52": 33.7, + "53": 32.8, + "54": 31.8, + "55": 30.9, + "56": 30.0, + "57": 29.0, + "58": 28.1, + "59": 27.2, + "60": 26.3, + "61": 25.4, + "62": 24.5, + "63": 23.6, + "64": 22.7, + "65": 21.8, + "66": 21.0, + "67": 20.1, + "68": 19.3, + "69": 18.4, + "70": 17.6, + "71": 16.8, + "72": 16.0, + "73": 15.2, + "74": 14.4, + "75": 13.6, + "76": 12.9, + "77": 12.1, + "78": 11.4, + "79": 10.7, + "80": 10.0, + "81": 9.3, + "82": 8.7, + "83": 8.1, + "84": 7.5, + "85": 6.9, + "86": 6.3, + "87": 5.8, + "88": 5.3, + "89": 4.9, + "90": 4.5 + } + } + }, + "SK": { + "name": "Slovakia", + "source": "Eurostat demo_mlexpec", + "ex_by_age": { + "male": { + "18": 57.5, + "19": 56.6, + "20": 55.6, + "21": 54.6, + "22": 53.6, + "23": 52.7, + "24": 51.7, + "25": 50.8, + "26": 49.8, + "27": 48.8, + "28": 47.9, + "29": 46.9, + "30": 46.0, + "31": 45.0, + "32": 44.1, + "33": 43.1, + "34": 42.2, + "35": 41.2, + "36": 40.3, + "37": 39.3, + "38": 38.4, + "39": 37.5, + "40": 36.5, + "41": 35.6, + "42": 34.7, + "43": 33.8, + "44": 32.9, + "45": 32.0, + "46": 31.1, + "47": 30.2, + "48": 29.3, + "49": 28.5, + "50": 27.6, + "51": 26.8, + "52": 25.9, + "53": 25.1, + "54": 24.2, + "55": 23.4, + "56": 22.6, + "57": 21.8, + "58": 21.1, + "59": 20.3, + "60": 19.5, + "61": 18.8, + "62": 18.1, + "63": 17.3, + "64": 16.7, + "65": 16.0, + "66": 15.4, + "67": 14.7, + "68": 14.1, + "69": 13.5, + "70": 12.9, + "71": 12.2, + "72": 11.7, + "73": 11.1, + "74": 10.6, + "75": 10.1, + "76": 9.6, + "77": 9.1, + "78": 8.6, + "79": 8.1, + "80": 7.7, + "81": 7.3, + "82": 6.9, + "83": 6.6, + "84": 6.2, + "85": 5.9, + "86": 5.6, + "87": 5.4, + "88": 5.2, + "89": 5.2, + "90": 5.1 + }, + "female": { + "18": 63.9, + "19": 62.9, + "20": 61.9, + "21": 60.9, + "22": 60.0, + "23": 59.0, + "24": 58.0, + "25": 57.0, + "26": 56.0, + "27": 55.0, + "28": 54.1, + "29": 53.1, + "30": 52.1, + "31": 51.1, + "32": 50.1, + "33": 49.2, + "34": 48.2, + "35": 47.2, + "36": 46.2, + "37": 45.3, + "38": 44.3, + "39": 43.3, + "40": 42.4, + "41": 41.4, + "42": 40.4, + "43": 39.5, + "44": 38.5, + "45": 37.6, + "46": 36.6, + "47": 35.7, + "48": 34.7, + "49": 33.8, + "50": 32.9, + "51": 32.0, + "52": 31.0, + "53": 30.1, + "54": 29.2, + "55": 28.3, + "56": 27.4, + "57": 26.5, + "58": 25.6, + "59": 24.8, + "60": 23.9, + "61": 23.0, + "62": 22.2, + "63": 21.3, + "64": 20.5, + "65": 19.7, + "66": 18.8, + "67": 18.0, + "68": 17.2, + "69": 16.4, + "70": 15.7, + "71": 14.9, + "72": 14.2, + "73": 13.4, + "74": 12.7, + "75": 12.0, + "76": 11.3, + "77": 10.6, + "78": 10.0, + "79": 9.4, + "80": 8.8, + "81": 8.2, + "82": 7.6, + "83": 7.1, + "84": 6.6, + "85": 6.1, + "86": 5.7, + "87": 5.2, + "88": 4.9, + "89": 4.6, + "90": 4.3 + } + } + }, + "RU": { + "name": "Russia", + "source": "WHO GHO life tables", + "ex_by_age": { + "male": { + "0": 65.6, + "60": 14.2 + }, + "female": { + "0": 74.3, + "60": 19.0 + } + } + } + } +} \ No newline at end of file diff --git a/docs/superpowers/plans/2026-05-30-migrant-life-map.md b/docs/superpowers/plans/2026-05-30-migrant-life-map.md new file mode 100644 index 0000000..8bf858b --- /dev/null +++ b/docs/superpowers/plans/2026-05-30-migrant-life-map.md @@ -0,0 +1,434 @@ +# Migrant Life-Map Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** A standalone `#/life-map` view that blends multiple countries' life expectancy (Eurostat EU + WHO Russia) as side-by-side anchors plus a clearly-labeled heuristic migration marker, with evidence-gated qualitative stress/mental-health/family modifiers. + +**Architecture:** Pure TS blend logic (`lib/lifeBlend.ts`) over a committed, version-stamped life-table JSON produced by a reproducible Python fetch script. A dumb backend endpoint serves the data; React hooks (localStorage-backed input + data fetch) feed a focused set of components. No network at runtime; no genetic data in this MVP. + +**Tech Stack:** FastAPI + aiosqlite (backend), React 18 + TypeScript + Vite + Vitest (frontend), Python + httpx (fetch script), Eurostat JSON-stat REST + WHO GHO OData. + +--- + +### Task 1: `lifeBlend.ts` pure module (the contract) + +**Files:** +- Create: `frontend/src/lib/lifeBlend.ts` +- Test: `frontend/src/lib/__tests__/lifeBlend.test.ts` + +- [ ] **Step 1: Write the failing test** + +```ts +import { describe, it, expect } from 'vitest' +import { lifeExpectancyAtAge, countryAnchors, blendMarker } from '../lifeBlend' + +const TABLE = { + retrieved: '2026-05-30', + countries: { + DE: { name: 'Germany', source: 'Eurostat', ex_by_age: { male: { '38': 41.9 }, female: { '38': 45.6 } } }, + RU: { name: 'Russia', source: 'WHO', ex_by_age: { male: { '35': 33.0, '40': 29.0 }, female: { '38': 38.0 } } }, + }, +} + +describe('lifeExpectancyAtAge', () => { + it('returns exact-age ex', () => { + expect(lifeExpectancyAtAge(TABLE, 'DE', 'male', 38)).toBe(41.9) + }) + it('maps to nearest available bracket when exact age missing', () => { + expect(lifeExpectancyAtAge(TABLE, 'RU', 'male', 38)).toBe(29.0) // nearest of 35/40 -> 40 + }) + it('returns null for unknown country', () => { + expect(lifeExpectancyAtAge(TABLE, 'XX', 'male', 38)).toBeNull() + }) +}) + +describe('countryAnchors', () => { + it('builds target age = age + ex per residence country', () => { + const a = countryAnchors(TABLE, [{ country: 'DE', years: 5 }, { country: 'RU', years: 33 }], 'male', 38) + expect(a).toEqual([ + { country: 'DE', name: 'Germany', exAtAge: 41.9, targetAge: 79.9 }, + { country: 'RU', name: 'Russia', exAtAge: 29.0, targetAge: 67.0 }, + ]) + }) + it('skips unknown countries', () => { + const a = countryAnchors(TABLE, [{ country: 'XX', years: 5 }], 'male', 38) + expect(a).toEqual([]) + }) +}) + +describe('blendMarker', () => { + const anchors = [ + { country: 'DE', name: 'Germany', exAtAge: 41.9, targetAge: 79.9 }, + { country: 'RU', name: 'Russia', exAtAge: 29.0, targetAge: 67.0 }, + ] + it('years-weights with current-residence emphasis and reports spread', () => { + // years RU=33, DE=5; current=DE emphasis x2 => weights DE=10, RU=33 -> blend below midpoint + const m = blendMarker(anchors, [{ country: 'DE', years: 5 }, { country: 'RU', years: 33 }], 'DE') + expect(m.heuristic).toBe(true) + expect(m.spread).toEqual({ min: 67.0, max: 79.9 }) + expect(m.targetAge).toBeGreaterThan(67.0) + expect(m.targetAge).toBeLessThan(79.9) + }) + it('single country returns that anchor with no emphasis effect', () => { + const m = blendMarker([anchors[0]], [{ country: 'DE', years: 5 }], 'DE') + expect(m.targetAge).toBe(79.9) + }) + it('zero total years falls back to current country anchor', () => { + const m = blendMarker(anchors, [{ country: 'DE', years: 0 }, { country: 'RU', years: 0 }], 'DE') + expect(m.targetAge).toBe(79.9) + }) +}) +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `cd frontend && npx vitest run src/lib/__tests__/lifeBlend.test.ts` +Expected: FAIL — module `../lifeBlend` not found. + +- [ ] **Step 3: Write minimal implementation** + +```ts +// frontend/src/lib/lifeBlend.ts +export type Sex = 'male' | 'female' +export interface Residence { country: string; years: number } +export interface LifeTable { + retrieved: string + countries: Record> }> +} +export interface CountryAnchor { country: string; name: string; exAtAge: number; targetAge: number } +export interface BlendMarker { targetAge: number; spread: { min: number; max: number }; heuristic: true } + +const CURRENT_EMPHASIS = 2 // current residence weighted x2 (heuristic) + +export function lifeExpectancyAtAge(table: LifeTable, country: string, sex: Sex, age: number): number | null { + const c = table.countries[country] + if (!c) return null + const ages = c.ex_by_age[sex] + if (!ages) return null + if (ages[String(age)] != null) return ages[String(age)] + const keys = Object.keys(ages).map(Number) + if (keys.length === 0) return null + const nearest = keys.reduce((best, k) => (Math.abs(k - age) < Math.abs(best - age) ? k : best), keys[0]) + return ages[String(nearest)] +} + +export function countryAnchors(table: LifeTable, residences: Residence[], sex: Sex, age: number): CountryAnchor[] { + const out: CountryAnchor[] = [] + for (const r of residences) { + const ex = lifeExpectancyAtAge(table, r.country, sex, age) + if (ex == null) continue + out.push({ country: r.country, name: table.countries[r.country].name, exAtAge: ex, targetAge: round1(age + ex) }) + } + return out +} + +export function blendMarker(anchors: CountryAnchor[], residences: Residence[], currentCountry: string): BlendMarker { + const targets = anchors.map(a => a.targetAge) + const spread = { min: Math.min(...targets), max: Math.max(...targets) } + if (anchors.length === 1) return { targetAge: anchors[0].targetAge, spread, heuristic: true } + const yearsBy = new Map(residences.map(r => [r.country, r.years])) + let wsum = 0, acc = 0 + for (const a of anchors) { + let w = yearsBy.get(a.country) ?? 0 + if (a.country === currentCountry) w *= CURRENT_EMPHASIS + wsum += w; acc += w * a.targetAge + } + if (wsum === 0) { + const cur = anchors.find(a => a.country === currentCountry) ?? anchors[0] + return { targetAge: cur.targetAge, spread, heuristic: true } + } + return { targetAge: round1(acc / wsum), spread, heuristic: true } +} + +const round1 = (n: number) => Math.round(n * 10) / 10 +``` + +- [ ] **Step 4: Run test to verify it passes** + +Run: `cd frontend && npx vitest run src/lib/__tests__/lifeBlend.test.ts` +Expected: PASS (all assertions). + +- [ ] **Step 5: Commit** + +```bash +git add frontend/src/lib/lifeBlend.ts frontend/src/lib/__tests__/lifeBlend.test.ts +git commit -m "feat(life-map): pure country-blend life-expectancy module (#27)" +``` + +--- + +### Task 2: Life-table fetch script + committed data file + +**Files:** +- Create: `scripts/fetch_life_expectancy.py` +- Create: `backend/app/data/life_tables.json` (generated) +- Test: `tests/test_fetch_life_expectancy.py` +- Test fixtures: `tests/fixtures/eurostat_demo_mlexpec.json`, `tests/fixtures/who_ru_lifetable.json` + +- [ ] **Step 1: Write the failing test** (parse recorded fixtures into the expected shape — no live HTTP) + +```python +# tests/test_fetch_life_expectancy.py +import json +from pathlib import Path +from scripts.fetch_life_expectancy import parse_eurostat, parse_who, build_life_tables + +FIX = Path(__file__).parent / "fixtures" + +def test_parse_eurostat_extracts_ex_by_age(): + raw = json.loads((FIX / "eurostat_demo_mlexpec.json").read_text()) + out = parse_eurostat(raw) + assert out["DE"]["name"] == "Germany" + assert out["DE"]["ex_by_age"]["male"]["38"] > 0 + +def test_parse_who_russia(): + raw = json.loads((FIX / "who_ru_lifetable.json").read_text()) + out = parse_who(raw) + assert "RU" in out + assert out["RU"]["ex_by_age"]["female"] + +def test_build_life_tables_has_retrieved_and_sources(): + eu = json.loads((FIX / "eurostat_demo_mlexpec.json").read_text()) + who = json.loads((FIX / "who_ru_lifetable.json").read_text()) + tables = build_life_tables(parse_eurostat(eu), parse_who(who), retrieved="2026-05-30") + assert tables["retrieved"] == "2026-05-30" + assert tables["countries"]["DE"]["source"].startswith("Eurostat") + assert tables["countries"]["RU"]["source"].startswith("WHO") +``` + +- [ ] **Step 2: Run test to verify it fails** + +Run: `cd /Users/glebkalinin/genome-toolkit && python -m pytest tests/test_fetch_life_expectancy.py -v` +Expected: FAIL — module/fixtures missing. + +- [ ] **Step 3: Create fixtures + implement parsers** + +Create trimmed fixtures (hand-built minimal JSON-stat + WHO OData shapes covering DE male/female age 38 and RU male/female). Then implement `scripts/fetch_life_expectancy.py` with: +- `parse_eurostat(raw)` — decode JSON-stat dimension indices (`geo`, `sex`, `age`) into `{CC: {name, source:"Eurostat demo_mlexpec", ex_by_age:{male/female:{age:ex}}}}`. +- `parse_who(raw)` — decode WHO OData rows into `{RU: {name:"Russia", source:"WHO GHO life tables", ex_by_age:{...}}}`. +- `build_life_tables(eu, who, retrieved)` — merge + stamp. +- `fetch_eurostat()` / `fetch_who()` using `httpx` (live), guarded under `if __name__ == "__main__":` which writes `backend/app/data/life_tables.json`. + +- [ ] **Step 4: Run tests to verify they pass** + +Run: `python -m pytest tests/test_fetch_life_expectancy.py -v` +Expected: PASS. + +- [ ] **Step 5: Generate the committed data file (live, once)** + +Run: `python scripts/fetch_life_expectancy.py` (network). Verify `backend/app/data/life_tables.json` has DE/NL/RU + others, sex×age coverage, `retrieved` date. If network unavailable, document and seed from fixtures with an explicit partial-coverage note. + +- [ ] **Step 6: Commit** + +```bash +git add scripts/fetch_life_expectancy.py backend/app/data/life_tables.json tests/test_fetch_life_expectancy.py tests/fixtures/ +git commit -m "feat(life-map): reproducible Eurostat+WHO life-table fetch script + data (#27)" +``` + +--- + +### Task 3: Backend endpoint + view registration + +**Files:** +- Create: `backend/app/routes/life_map.py` +- Modify: `backend/app/main.py` (include router; add `life-map` to `ALL_VIEWS`) +- Create: `config/life-modifiers.yaml` +- Test: `tests/test_life_map_routes.py` + +- [ ] **Step 1: Write the failing test** + +```python +# tests/test_life_map_routes.py +from fastapi.testclient import TestClient +from backend.app.main import app + +client = TestClient(app) + +def test_life_tables_endpoint_returns_countries(): + r = client.get("/api/life-map/life-tables") + assert r.status_code == 200 + body = r.json() + assert "retrieved" in body and "countries" in body + assert "DE" in body["countries"] + +def test_life_modifiers_config_served(): + r = client.get("/api/config/life-modifiers") + assert r.status_code == 200 + assert "modifiers" in r.json() +``` + +- [ ] **Step 2: Run to verify fail** + +Run: `python -m pytest tests/test_life_map_routes.py -v` → FAIL (404). + +- [ ] **Step 3: Implement** + +`life_map.py`: `APIRouter(prefix="/api/life-map")` with `GET /life-tables` reading `backend/app/data/life_tables.json`. Register in `main.py`; add `"life-map"` to `ALL_VIEWS`. Create `config/life-modifiers.yaml` with at least one `stress`, one `mental-health` (evidence: weak), one `family-history` entry per the spec schema. + +- [ ] **Step 4: Run to verify pass** → PASS. + +- [ ] **Step 5: Commit** + +```bash +git add backend/app/routes/life_map.py backend/app/main.py config/life-modifiers.yaml tests/test_life_map_routes.py +git commit -m "feat(life-map): backend life-tables endpoint + view registration (#27)" +``` + +--- + +### Task 4: `useResidenceHistory` + `useLifeMap` hooks + +**Files:** +- Create: `frontend/src/hooks/useResidenceHistory.ts` +- Create: `frontend/src/hooks/useLifeMap.ts` +- Test: `frontend/src/__tests__/useResidenceHistory.test.ts`, `frontend/src/__tests__/useLifeMap.test.ts` + +- [ ] **Step 1: Write failing tests** + +```ts +// useResidenceHistory.test.ts — mirrors useMyMedications localStorage pattern +import { renderHook, act } from '@testing-library/react' +import { useResidenceHistory } from '../hooks/useResidenceHistory' + +beforeEach(() => localStorage.clear()) + +it('defaults to empty residences with sane sex/age', () => { + const { result } = renderHook(() => useResidenceHistory()) + expect(result.current.state.residences).toEqual([]) + expect(result.current.state.sex).toBe('male') +}) +it('adds/updates/removes and persists', () => { + const { result } = renderHook(() => useResidenceHistory()) + act(() => result.current.addResidence({ country: 'RU', years: 33 })) + act(() => result.current.setCurrentCountry('DE')) + expect(JSON.parse(localStorage.getItem('genome_residence_history')!).currentCountry).toBe('DE') +}) +it('recovers from malformed JSON', () => { + localStorage.setItem('genome_residence_history', '{not json') + const { result } = renderHook(() => useResidenceHistory()) + expect(result.current.state.residences).toEqual([]) +}) +``` + +```ts +// useLifeMap.test.ts — mock fetch for life-tables + modifiers +import { renderHook, waitFor } from '@testing-library/react' +import { vi } from 'vitest' +import { useLifeMap } from '../hooks/useLifeMap' + +it('computes anchors + blend marker from fetched table', async () => { + global.fetch = vi.fn((url: string) => + Promise.resolve({ ok: true, json: () => Promise.resolve( + String(url).includes('life-tables') + ? { retrieved: 'x', countries: { DE: { name: 'Germany', source: 'Eurostat', ex_by_age: { male: { '38': 41.9 }, female: {} } } } } + : { modifiers: [] }) }) as any) as any + const { result } = renderHook(() => useLifeMap({ residences: [{ country: 'DE', years: 5 }], currentCountry: 'DE', sex: 'male', age: 38 })) + await waitFor(() => expect(result.current.loading).toBe(false)) + expect(result.current.anchors[0].targetAge).toBe(79.9) +}) +``` + +- [ ] **Step 2: Run to verify fail** → `cd frontend && npx vitest run src/__tests__/useResidenceHistory.test.ts src/__tests__/useLifeMap.test.ts` → FAIL. + +- [ ] **Step 3: Implement hooks** — `useResidenceHistory` (localStorage key `genome_residence_history`, shape `{residences, currentCountry, sex, age}`, try/catch load like `useMyMedications`). `useLifeMap(input)` fetches `/api/life-map/life-tables` + `/api/config/life-modifiers` once, memoizes `countryAnchors`/`blendMarker` over `input`. + +- [ ] **Step 4: Run to verify pass** → PASS. + +- [ ] **Step 5: Commit** + +```bash +git add frontend/src/hooks/useResidenceHistory.ts frontend/src/hooks/useLifeMap.ts frontend/src/__tests__/useResidenceHistory.test.ts frontend/src/__tests__/useLifeMap.test.ts +git commit -m "feat(life-map): residence-history + life-map data hooks (#27)" +``` + +--- + +### Task 5: `LifeMap` view + sub-components + nav wiring + +**Files:** +- Create: `frontend/src/components/lifemap/LifeMap.tsx`, `ResidenceHistoryInput.tsx`, `CountryAnchors.tsx`, `MigrationContextMarker.tsx` +- Modify: `frontend/src/App.tsx` (route `#/life-map` + nav entry) +- Test: `frontend/src/__tests__/LifeMap.test.tsx` + +- [ ] **Step 1: Write failing test** + +```tsx +import { render, screen } from '@testing-library/react' +import { LifeMap } from '../components/lifemap/LifeMap' +// mock useLifeMap to return DE+RU anchors + a blend marker +it('renders country anchors as primary truth and a labeled heuristic marker', () => { + render() + expect(screen.getByText(/Germany/)).toBeInTheDocument() + expect(screen.getByText(/heuristic/i)).toBeInTheDocument() // marker caveat + expect(screen.getByText(/period life expectancy/i)).toBeInTheDocument() // disclaimer +}) +``` + +- [ ] **Step 2: Run to verify fail** → FAIL. + +- [ ] **Step 3: Implement** components using existing theme tokens (no CSS framework); `ResidenceHistoryInput` fully labeled (`