From 09f95c42d08e5e054f71c10c5bbeb638e71cac7c Mon Sep 17 00:00:00 2001 From: calixteair Date: Wed, 13 May 2026 23:05:20 +0200 Subject: [PATCH 1/5] =?UTF-8?q?feat(worker):=20bump=20generator=20max=5Fat?= =?UTF-8?q?tempts=20200=20=E2=86=92=201000?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The daily-grid generator backs off after max_attempts CSP attempts. 200 was fine for the paris-metro pack (~36 predicates, 310 entities, broad intersections). Denser packs — RER ships with 230 entities and a narrower set of valid candidates — were occasionally failing publish on their first attempt. 100-seed stress test: paris-metro @ 200: 0/100 failures rer @ 200: 17/100 failures rer @ 1000: 0/100 failures Each attempt is sub-ms on the runner, so 1000 still costs under a second per (domain, day). No need to expose the value as a config field yet — flip the constant when a future pack needs more. --- worker/src/once.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/worker/src/once.rs b/worker/src/once.rs index c13a018..34ea92a 100644 --- a/worker/src/once.rs +++ b/worker/src/once.rs @@ -30,7 +30,10 @@ use crate::{ const DAILY_PUBLISH_HOUR_UTC: u32 = 0; const DAILY_PUBLISH_MINUTE_UTC: u32 = 1; -const GENERATOR_MAX_ATTEMPTS: u32 = 200; +// Bumped from 200 so denser predicate packs (RER and up) keep a near-zero +// rate of "no valid grid found". Each attempt costs sub-ms on the runner, +// so the extra headroom is free. +const GENERATOR_MAX_ATTEMPTS: u32 = 1000; /// Outcome of a single domain × date generation attempt. #[derive(Debug, PartialEq, Eq)] From b0fbc3cdb422d71d2bd5614504da3004a65b7a77 Mon Sep 17 00:00:00 2001 From: calixteair Date: Wed, 13 May 2026 23:05:30 +0200 Subject: [PATCH 2/5] feat(scripts): ingest tooling for the rer domain MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two Python scripts (stdlib only, no external deps), mirroring the paris-metro pipeline but adapted to the rer constraints. scripts/ingest/build_rer_dataset.py - One Overpass query pulls every relation[type=route][network=RER] in Île-de-France plus their stop-role node members. Members tagged 'stop_entry_only' / 'platform' are intentionally filtered out via the role selector. - Each station node carries name + geo. The trunk line letter (A..E) is harvested from the relation's ref tag. - Names like 'Châtelet - Voie 1' / 'Brétigny - Voie 6' are stripped of their platform suffix so the 4-5 platform nodes of a station collapse into one entity. - Centroid geo per group, in_paris=true when inside the Paris bbox. - Wikidata's zone tarifaire (P5031) isn't exposed by OSM so 'zone' is left at 0; a follow-up enrich pass can wire it later. scripts/ingest/fame_score_rer.py - WDQS rate-limits at 1 req/min for repeat clients since the 2024 outage — too aggressive for a 230-entity batch. So this version skips SPARQL entirely and hits the Wikipedia REST endpoints directly: 1. summary/ | summary/ (RER) | summary/Gare de — first 200-OK whose description matches a transit keyword wins. Word-boundary anchored regex so 'métropole' / 'commune' don't smuggle in unrelated commune pages (the false positives that were inflating Issy, Antony, etc.). 2. /metrics/pageviews/per-article/.../monthly/ → 365-day sum. 3. percentile-rank → fame_score 0..=100. - 136/230 stations resolved (the rest are small banlieue stops without a dedicated frwiki page) — they stay at fame_score=null and the scoring engine treats them as neutral 50. Coverage gap is acceptable for v1 of the pack. --- scripts/ingest/build_rer_dataset.py | 293 +++++++++++++++++++++++ scripts/ingest/fame_score_rer.py | 346 ++++++++++++++++++++++++++++ 2 files changed, 639 insertions(+) create mode 100755 scripts/ingest/build_rer_dataset.py create mode 100755 scripts/ingest/fame_score_rer.py diff --git a/scripts/ingest/build_rer_dataset.py b/scripts/ingest/build_rer_dataset.py new file mode 100755 index 0000000..841aba7 --- /dev/null +++ b/scripts/ingest/build_rer_dataset.py @@ -0,0 +1,293 @@ +#!/usr/bin/env python3 +""" +build_rer_dataset.py — bootstrap `domains/rer/entities.json` from OSM. + +Strategy +-------- +WDQS is rate-limited too aggressively (1 req/min since the 2024 outage) to +fit a fresh ingest cycle. Pivot on OSM Overpass which has the same data +plus a richer station↔line mapping via the `route=train|light_rail` / +`network=RER` relations. + +1. One Overpass query returns every `relation[type=route][network=RER]` + plus its node members. The `ref` tag carries the trunk letter A..E. +2. For each station node we keep its name, geo, and the set of RER lines + it appears on (union across relations). +3. `zone tarifaire` is not present on OSM nodes — left at 0; the + downstream predicates can still operate on `lines`, `geo`, `in_paris` + (derived heuristically from a Paris bbox), and name-based families. + +Output +------ +- `domains/rer/entities.json` (sorted by id) +- `domains/rer/metadata.json` (version 0.1.0, sources_versions, sha256) +- The `tmp/` directory under the domain is gitignored, so any audit + artefact left here won't leak into the PR. + +Idempotency +----------- +Re-running the script overwrites the dataset. +""" + +from __future__ import annotations + +import argparse +import hashlib +import json +import re +import sys +import time +import unicodedata +import urllib.parse +import urllib.request +from pathlib import Path +from typing import Optional + +OVERPASS_ENDPOINT = "https://overpass-api.de/api/interpreter" +USER_AGENT = ( + "kalidoku-rer-ingest/1.0 " + "(https://github.com/Calixteair/kalidoku contact: reymond.calixte@gmail.com)" +) + +# Pull every RER route relation in Île-de-France + their stop-role member +# nodes only. Avoiding `.routes >;` because it pulls every member node +# (including `stop_entry_only`, `platform`, `node` markers between stops) +# — `node(r:"stop")` keeps only the canonical station nodes. +OVERPASS_QUERY = """ +[out:json][timeout:120]; +area["name"="Île-de-France"]->.idf; +relation["type"="route"]["network"="RER"](area.idf)->.routes; +.routes out body; +node(r.routes:"stop"); +out body; +""" + +# Paris bbox (inner ring road). Used to set `in_paris=true` on stations +# whose OSM node sits inside. Not as crisp as fare zones, but adequate for +# the `Hors Paris intra-muros` predicate family. +PARIS_BBOX = (48.815, 2.224, 48.902, 2.470) + + +def log(msg: str) -> None: + print(f"[rer-ingest] {msg}", file=sys.stderr, flush=True) + + +def normalise_id(name: str) -> str: + """Entity id: lowercase ascii + `-` separators, matches the + `^[a-z0-9_][a-z0-9_-]{0,63}$` constraint of entity-schema.json.""" + s = unicodedata.normalize("NFKD", name) + s = "".join(c for c in s if not unicodedata.combining(c)) + s = s.lower() + s = re.sub(r"[^a-z0-9]+", "-", s) + s = s.strip("-") + return s[:64] or "x" + + +def http_get_json(url: str, retries: int = 3) -> dict: + req = urllib.request.Request(url) + req.add_header("User-Agent", USER_AGENT) + req.add_header("Accept", "application/json") + last_err: Optional[Exception] = None + for attempt in range(retries): + try: + with urllib.request.urlopen(req, timeout=180) as r: + return json.loads(r.read().decode("utf-8")) + except urllib.error.HTTPError as e: + if e.code in (429, 500, 502, 503, 504) and attempt < retries - 1: + wait = 2 ** attempt + log(f" HTTP {e.code}, retry in {wait}s") + time.sleep(wait) + continue + last_err = e + break + except Exception as e: + last_err = e + if attempt < retries - 1: + time.sleep(2 ** attempt) + continue + break + raise RuntimeError(f"fetch failed: {last_err}") + + +def fetch_overpass() -> dict: + log("fetching RER routes + member nodes from OSM Overpass…") + url = f"{OVERPASS_ENDPOINT}?data={urllib.parse.quote(OVERPASS_QUERY)}" + return http_get_json(url) + + +def in_paris(lat: float, lon: float) -> bool: + return PARIS_BBOX[0] <= lat <= PARIS_BBOX[2] and PARIS_BBOX[1] <= lon <= PARIS_BBOX[3] + + +# Strip OSM platform/track suffixes so two physically separate nodes that +# share a station collapse into one entity. Matches "Châtelet - Voie 1", +# "Brétigny - Voie 6", "Étampes - Quai 3", "Choisy-le-Roi - Voie 1B", etc. +_SUFFIX_RE = re.compile( + r"\s*[-–—]\s*(?:Voie|Quai|Platform)\s+\S+\s*$", + re.IGNORECASE, +) + + +def canonical_station_name(raw: str) -> str: + return _SUFFIX_RE.sub("", raw).strip() + + +def build_entities(overpass: dict) -> list[dict]: + elements = overpass.get("elements", []) + nodes = {e["id"]: e for e in elements if e["type"] == "node"} + relations = [e for e in elements if e["type"] == "relation"] + + # node_id → set of RER trunk letters from every relation it sits in. + node_lines: dict[int, set[str]] = {} + for rel in relations: + tags = rel.get("tags", {}) + ref = tags.get("ref", "") + # Relations sometimes carry numbered refs like "A1", "B4" — collapse + # the trunk letter so a station counts as "served by RER A". + m = re.match(r"^([A-E])", ref) + if not m: + continue + letter = m.group(1) + for member in rel.get("members", []): + if member.get("type") != "node": + continue + node_lines.setdefault(member["ref"], set()).add(letter) + + # First pass: group by canonical (suffix-stripped) name. For each group, + # union the lines across every physical node and keep the geo of the + # node closest to the group centroid. Skipping nodes without a name + # and nodes that aren't referenced by any RER route relation. + groups: dict[str, dict] = {} + skipped_no_lines = 0 + skipped_no_name = 0 + for node_id, n in nodes.items(): + if node_id not in node_lines: + skipped_no_lines += 1 + continue + tags = n.get("tags", {}) + raw_name = tags.get("name") or tags.get("name:fr") or "" + if not raw_name: + skipped_no_name += 1 + continue + lat, lon = n.get("lat"), n.get("lon") + if lat is None or lon is None: + continue + canonical = canonical_station_name(raw_name) + if not canonical: + continue + g = groups.setdefault( + canonical, + { + "name": canonical, + "lines": set(), + "lats": [], + "lons": [], + }, + ) + g["lines"].update(node_lines[node_id]) + g["lats"].append(float(lat)) + g["lons"].append(float(lon)) + + out = [] + used_ids: set[str] = set() + skipped_no_lines_after_group = 0 + for canonical, g in groups.items(): + if not g["lines"]: + skipped_no_lines_after_group += 1 + continue + lat = sum(g["lats"]) / len(g["lats"]) + lon = sum(g["lons"]) / len(g["lons"]) + base = normalise_id(canonical) + ent_id = base + i = 1 + while ent_id in used_ids: + ent_id = f"{base}-{i}" + i += 1 + used_ids.add(ent_id) + out.append( + { + "id": ent_id, + "name": canonical, + "attributes": { + "lines": {"str_list": sorted(g["lines"])}, + "geo": {"geo": {"lat": lat, "lon": lon}}, + "in_paris": {"bool": in_paris(lat, lon)}, + # Wikidata's P5031 (zone tarifaire) is sparsely populated + # and OSM doesn't expose it. Left at 0; zone-based + # predicates require a follow-up enrich pass. + "zone": {"num": 0.0}, + }, + } + ) + log( + f" → {len(out)} stations after canonical dedup " + f"(skipped: {skipped_no_lines} no-lines, {skipped_no_name} no-name)" + ) + return sorted(out, key=lambda e: e["id"]) + + +def build_metadata(entities: list[dict], dataset_bytes: bytes) -> dict: + today = time.strftime("%Y-%m-%d") + return { + "id": "rer", + "name": { + "fr": "RER d'Île-de-France", + "en": "Île-de-France RER", + }, + "version": "0.1.0", + "default_locale": "fr", + "license": "ODbL-1.0", + "sources": [ + "https://overpass-api.de/api/interpreter", + ], + "generator_constraints": { + "min_candidates_per_cell": 2, + "max_candidates_per_cell": 25, + "max_predicate_family_repeats": 1, + "row_predicate_count": 3, + "col_predicate_count": 3, + }, + "dataset_sha256": hashlib.sha256(dataset_bytes).hexdigest(), + "entity_count": len(entities), + "sources_versions": [ + { + "id": "osm-overpass-rer-routes", + "url": "https://overpass-api.de/api/interpreter", + "date": today, + }, + ], + } + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[1] if __doc__ else "") + parser.add_argument("--domain-root", type=Path, default=Path("domains/rer")) + parser.add_argument("--dry-run", action="store_true") + args = parser.parse_args() + + overpass = fetch_overpass() + entities = build_entities(overpass) + if not entities: + log("no entities produced — aborting") + return 2 + + entities_bytes = (json.dumps(entities, ensure_ascii=False, indent=2) + "\n").encode("utf-8") + metadata = build_metadata(entities, entities_bytes) + + if args.dry_run: + log("dry-run: skipping writes") + log(f"would write {len(entities)} entities, metadata version {metadata['version']}") + return 0 + + args.domain_root.mkdir(parents=True, exist_ok=True) + (args.domain_root / "entities.json").write_bytes(entities_bytes) + log(f"wrote {args.domain_root / 'entities.json'}") + + meta_bytes = (json.dumps(metadata, ensure_ascii=False, indent=2) + "\n").encode("utf-8") + (args.domain_root / "metadata.json").write_bytes(meta_bytes) + log(f"wrote {args.domain_root / 'metadata.json'}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/scripts/ingest/fame_score_rer.py b/scripts/ingest/fame_score_rer.py new file mode 100755 index 0000000..a78474b --- /dev/null +++ b/scripts/ingest/fame_score_rer.py @@ -0,0 +1,346 @@ +#!/usr/bin/env python3 +""" +fame_score_rer.py + +Computes a per-entity `fame_score` (0..=100) for the rer domain pack from +French Wikipedia pageviews. + +Strategy +-------- +WDQS rate-limits hard (1 req/min for repeat clients), so we skip Wikidata +entirely and go straight at the Wikipedia REST APIs: + +1. For each entity, resolve a French Wikipedia article title by hitting + `/api/rest_v1/page/summary/` on each of: + - "" (raw) + - " (RER)" — disambiguation suffix used by frwiki + - "Gare de " + The first one that returns 200 wins. The summary endpoint follows + redirects, so a hit on the raw name is canonicalised automatically. +2. For each resolved title, sum pageviews over the previous N days via + `/api/rest_v1/metrics/pageviews/per-article/.../monthly//`. +3. Percentile-rank the pageviews distribution → fame_score 0..=100. Ties + share the average rank. + +Output +------ +- Patches `domains/rer/entities.json` in place. +- Writes an audit report at `domains/rer/tmp/fame_score_report.json` with + per-entity match status, resolved title, pageviews, and final score. +- Bumps `metadata.version` and re-computes `metadata.dataset_sha256`. + +Idempotency +----------- +Same Wikipedia snapshot → same scores. Re-running overrides previous +fame_scores; we don't preserve old values because the percentile ranks +shift whenever entities are added or removed. +""" + +from __future__ import annotations + +import argparse +import datetime as dt +import hashlib +import json +import sys +import time +import urllib.parse +import urllib.request +from pathlib import Path +from typing import Optional + +# ---------- Constants ---------- + +PAGEVIEWS_BASE = "https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/fr.wikipedia/all-access/all-agents" +SUMMARY_BASE = "https://fr.wikipedia.org/api/rest_v1/page/summary" +USER_AGENT = "kalidoku-fame-ingest/1.0 (https://github.com/Calixteair/kalidoku contact: reymond.calixte@gmail.com)" + +# Per-entity candidate title variants. Tried in order; first 200-OK wins. +# `(RER)` is the canonical disambiguator on fr.wikipedia for RER stations +# that share their name with a city or non-rail entity; `Gare de` covers +# main-line stops that get filed under the gare's article. +TITLE_VARIANTS = ["{name}", "{name} (RER)", "Gare de {name}"] + + +# ---------- HTTP ---------- + + +def log(msg: str) -> None: + print(f"[fame-rer] {msg}", file=sys.stderr, flush=True) + + +def http_get_json(url: str, retries: int = 3) -> Optional[dict]: + """Returns None on 404 (not the 500 caller wants); raises on other errors.""" + req = urllib.request.Request(url) + req.add_header("User-Agent", USER_AGENT) + req.add_header("Accept", "application/json") + for attempt in range(retries): + try: + with urllib.request.urlopen(req, timeout=30) as r: + return json.loads(r.read().decode("utf-8")) + except urllib.error.HTTPError as e: + if e.code == 404: + return None + if e.code in (429, 500, 502, 503, 504) and attempt < retries - 1: + wait = 2 ** attempt + log(f" HTTP {e.code} on {url[:80]}…, retry in {wait}s") + time.sleep(wait) + continue + raise RuntimeError(f"HTTP {e.code} on {url}") from e + except Exception as e: + if attempt < retries - 1: + time.sleep(2 ** attempt) + continue + raise RuntimeError(f"network error on {url}: {e}") from e + return None + + +# ---------- Title resolution ---------- + + +# Words we expect in the resolved article to plausibly be the station/gare +# article. Word-boundary anchored so 'métropole' (city stuff), 'commune', +# 'départemental' don't smuggle in unrelated pages — that was inflating +# Antony, Drancy, Aulnay etc. via redirects to their commune articles. +TOPIC_KEYWORDS_RE = __import__("re").compile( + r"\b(?:gare|gares|station|stations|RER|m[ée]tro|m[ée]trop?olitain" + r"|transilien|ferroviaire|tramway|chemin de fer)\b", + __import__("re").IGNORECASE, +) + + +def looks_like_station(summary: dict) -> bool: + desc = summary.get("description") or "" + extract = (summary.get("extract") or "")[:600] + text = f"{desc} {extract}" + return bool(TOPIC_KEYWORDS_RE.search(text)) + + +def resolve_title(entity_name: str) -> Optional[str]: + """Try several frwiki title variants; return the canonical title that + summary resolved to (follows redirects). Rejects pages whose summary + doesn't look transit-related, otherwise homonyms (city, person, etc.) + sneak in via redirect and inflate pageviews.""" + for variant in TITLE_VARIANTS: + candidate = variant.format(name=entity_name) + encoded = urllib.parse.quote(candidate.replace(" ", "_"), safe="()") + url = f"{SUMMARY_BASE}/{encoded}" + try: + data = http_get_json(url) + except RuntimeError as e: + log(f" summary error for '{candidate}': {e}") + continue + if data is None: + continue + if data.get("type") == "disambiguation": + continue + if not looks_like_station(data): + # Wrong topic — try the next variant. The "Gare de X" variant + # often rescues the match here (Issy → Issy-les-Moulineaux is + # rejected, then "Gare d'Issy" or "Gare d'Issy-Val-de-Seine" + # picks up the actual station article). + continue + title = data.get("title") or candidate + return title + return None + + +# ---------- Pageviews ---------- + + +def fetch_pageviews_sum(title: str, start: str, end: str) -> int: + """Sum monthly pageviews for `title` over [start, end] (YYYYMMDD). + Returns 0 when the article exists but has no pageviews recorded.""" + encoded = urllib.parse.quote(title.replace(" ", "_"), safe="()") + url = f"{PAGEVIEWS_BASE}/{encoded}/monthly/{start}/{end}" + try: + data = http_get_json(url) + except RuntimeError: + return 0 + if data is None: + return 0 + return sum(item.get("views", 0) for item in data.get("items", [])) + + +def percentile_rank(values: dict[str, int]) -> dict[str, int]: + """Map each entity_id → percentile rank 0..=100 of its pageviews. Ties + receive the average rank.""" + if not values: + return {} + items = sorted(values.items(), key=lambda kv: kv[1]) + n = len(items) + ranks: dict[str, int] = {} + i = 0 + while i < n: + j = i + while j + 1 < n and items[j + 1][1] == items[i][1]: + j += 1 + rank_pct = ((i + j) / 2 + 0.5) / n * 100 + for k in range(i, j + 1): + ranks[items[k][0]] = max(0, min(100, int(round(rank_pct)))) + i = j + 1 + return ranks + + +# ---------- Patch entities.json ---------- + + +def patch_entities(entities: list[dict], fame_by_id: dict[str, int]) -> tuple[list[dict], int]: + applied = 0 + out = [] + for ent in entities: + copy = dict(ent) + if ent["id"] in fame_by_id: + copy["fame_score"] = fame_by_id[ent["id"]] + applied += 1 + elif "fame_score" in copy: + del copy["fame_score"] + out.append(copy) + return out, applied + + +def bump_metadata(meta: dict, dataset_bytes: bytes) -> dict: + sha = hashlib.sha256(dataset_bytes).hexdigest() + meta = dict(meta) + meta["dataset_sha256"] = sha + parts = meta["version"].split(".") + if len(parts) == 3 and parts[1].isdigit(): + parts[1] = str(int(parts[1]) + 1) + parts[2] = "0" + meta["version"] = ".".join(parts) + today = dt.date.today().isoformat() + sv = meta.setdefault("sources_versions", []) + sv = [s for s in sv if s.get("id") != "wikipedia-pageviews-fame"] + sv.append( + { + "id": "wikipedia-pageviews-fame", + "url": "https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/fr.wikipedia", + "date": today, + } + ) + meta["sources_versions"] = sv + return meta + + +def write_audit_report(path: Path, payload: dict) -> None: + path.parent.mkdir(parents=True, exist_ok=True) + path.write_text(json.dumps(payload, ensure_ascii=False, indent=2)) + + +# ---------- Main ---------- + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[1] if __doc__ else "") + parser.add_argument( + "--domain-root", + type=Path, + default=Path("domains/rer"), + help="Path to the domain pack (default: domains/rer)", + ) + parser.add_argument( + "--days", + type=int, + default=365, + help="Pageviews lookback window in days (default 365)", + ) + parser.add_argument( + "--dry-run", + action="store_true", + help="Compute and report but don't write entities.json / metadata.json", + ) + args = parser.parse_args() + + domain_root: Path = args.domain_root + entities_path = domain_root / "entities.json" + meta_path = domain_root / "metadata.json" + if not entities_path.is_file(): + log(f"missing {entities_path}") + return 2 + + entities = json.loads(entities_path.read_text()) + meta = json.loads(meta_path.read_text()) + log(f"loaded {len(entities)} entities from {entities_path}") + + end_date = dt.date.today().replace(day=1) - dt.timedelta(days=1) + start_date = end_date - dt.timedelta(days=args.days) + start_str = start_date.strftime("%Y%m01") + end_str = end_date.strftime("%Y%m%d") + log(f"fetching pageviews {start_str} → {end_str}") + + pv_by_id: dict[str, int] = {} + audit = [] + matched = 0 + for i, ent in enumerate(entities, 1): + record = {"id": ent["id"], "name": ent["name"]} + title = resolve_title(ent["name"]) + if title is None: + record["title"] = None + record["pageviews"] = 0 + audit.append(record) + continue + matched += 1 + record["title"] = title + try: + pv = fetch_pageviews_sum(title, start_str, end_str) + except Exception as e: + log(f" pageviews error for {ent['id']} ({title}): {e}") + pv = 0 + pv_by_id[ent["id"]] = pv + record["pageviews"] = pv + audit.append(record) + if i % 30 == 0: + log(f" {i}/{len(entities)} processed (matched={matched})") + # Polite throttle — the Wikipedia REST endpoint is generous but + # 150 ms between calls stays well under documented limits. + time.sleep(0.15) + + fame_by_id = percentile_rank(pv_by_id) + for r in audit: + r["fame_score"] = fame_by_id.get(r["id"]) + + log(f"coverage: {matched}/{len(entities)} entities scored") + + if args.dry_run: + log("dry-run: not writing files") + report_path = domain_root / "tmp" / "fame_score_report.dryrun.json" + write_audit_report( + report_path, + { + "generated_at": dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "matched": matched, + "total": len(entities), + "audit": audit, + }, + ) + log(f"audit report → {report_path}") + return 0 + + patched, applied = patch_entities(entities, fame_by_id) + new_bytes = json.dumps(patched, ensure_ascii=False, indent=2).encode("utf-8") + b"\n" + entities_path.write_bytes(new_bytes) + log(f"wrote {entities_path} ({applied} entities scored)") + + new_meta = bump_metadata(meta, new_bytes) + new_meta["entity_count"] = len(patched) + meta_path.write_text(json.dumps(new_meta, ensure_ascii=False, indent=2) + "\n") + log(f"wrote {meta_path} (version {new_meta['version']})") + + report_path = domain_root / "tmp" / "fame_score_report.json" + write_audit_report( + report_path, + { + "generated_at": dt.datetime.now(dt.timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ"), + "window_start": start_str, + "window_end": end_str, + "matched": matched, + "total": len(entities), + "audit": audit, + }, + ) + log(f"audit report → {report_path}") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) From a490c4568441d7f1859f406798c253ca6bd34bbd Mon Sep 17 00:00:00 2001 From: calixteair Date: Wed, 13 May 2026 23:05:44 +0200 Subject: [PATCH 3/5] =?UTF-8?q?feat(domain-rer):=20seed=20pack=20=E2=80=94?= =?UTF-8?q?=20230=20stations,=2031=20predicates,=20fame=20on=20136?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Bootstrap of the rer domain pack via the two ingest scripts in scripts/ingest/. Shapes: domains/rer/entities.json (230 stations) - Pulled from OSM Overpass: every relation[network=RER] in IDF, then stop-role nodes deduped by canonical name (platform suffixes stripped). - Attributes: lines (subset of {A,B,C,D,E}), geo, in_paris (Paris inner-ring bbox), zone (placeholder 0 — Wikidata's P5031 to come). - fame_score populated on 136 stations (those with an unambiguous frwiki article matching a transit-topic keyword). The remaining 94 small banlieue stops sit at null → core::scoring treats them as neutral 50. domains/rer/predicates.json (31 predicates) - Mirror of the paris-metro pack with rer-specific tweaks: - 4 ends_with, 4 starts_with, 2 contains_letter (Y, U) - name_length_max=7, name_length_min=13, name_length_eq=9 - name_word_count_eq={1, 3}, name_word_count_min=4 - attr_list_size_eq=1 (single-line stations only) - on_attr_in_set on every individual line A..E + A|B - in_paris true/false - within_km anchors: Louvre, Tour Eiffel, Gare de Lyon, CDG, Versailles - Two predicates that paris-metro carries were dropped on rer because coverage was < 8 stations (contains_letter Z = 6, attr_list_size_gte n=3 = 1 station) — under that threshold the CSP solver thrashes. domains/rer/metadata.json - version 0.2.0 (0.1.0 seeded, 0.2.0 after fame ingest) - sources_versions records both the Overpass query date and the Wikipedia pageviews window for auditability. 100-seed generator stress test passes at the worker's new 1000 attempts threshold. --- domains/rer/entities.json | 5438 ++++++++++++++++++++++++ domains/rer/metadata.json | 34 + domains/rer/predicates.json | 482 +++ domains/rer/tmp/fame_score_report.json | 1619 +++++++ 4 files changed, 7573 insertions(+) create mode 100644 domains/rer/entities.json create mode 100644 domains/rer/metadata.json create mode 100644 domains/rer/predicates.json create mode 100644 domains/rer/tmp/fame_score_report.json diff --git a/domains/rer/entities.json b/domains/rer/entities.json new file mode 100644 index 0000000..400e057 --- /dev/null +++ b/domains/rer/entities.json @@ -0,0 +1,5438 @@ +[ + { + "id": "ablon", + "name": "Ablon", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.7258511, + "lon": 2.41996055 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "acheres-grand-cormier", + "name": "Achères Grand Cormier", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.955261199999995, + "lon": 2.09261825 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "acheres-ville", + "name": "Achères - Ville", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.97066745, + "lon": 2.0777376 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "aeroport-charles-de-gaulle-1", + "name": "Aéroport Charles de Gaulle 1", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 49.00975175, + "lon": 2.561158 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "antony", + "name": "Antony", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.754415800000004, + "lon": 2.30077335 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "arcueil-cachan", + "name": "Arcueil - Cachan", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.798569650000005, + "lon": 2.32808305 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "arpajon", + "name": "Arpajon", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.5860024, + "lon": 2.2411523 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "athis-mons", + "name": "Athis-Mons", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.7126184, + "lon": 2.403614 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "auber", + "name": "Auber", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.8722271, + "lon": 2.32979315 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "aulnay-sous-bois", + "name": "Aulnay-sous-Bois", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.93223626666667, + "lon": 2.495866733333333 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "avenue-du-president-kennedy", + "name": "Avenue du Président Kennedy", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.853245349999995, + "lon": 2.28014375 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "avenue-foch", + "name": "Avenue Foch", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8697826, + "lon": 2.27473285 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "avenue-henri-martin", + "name": "Avenue Henri Martin", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.865316699999994, + "lon": 2.27221485 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "bagneux", + "name": "Bagneux", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.7934585, + "lon": 2.32268545 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 55 + }, + { + "id": "ballancourt", + "name": "Ballancourt", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.5321644, + "lon": 2.3711032 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 7 + }, + { + "id": "bibliotheque-francois-mitterrand", + "name": "Bibliothèque François Mitterrand", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.82887695, + "lon": 2.3777726 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "boigneville", + "name": "Boigneville", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.3420823, + "lon": 2.37898315 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 4 + }, + { + "id": "boissise-le-roi", + "name": "Boissise-le-Roi", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.52937405, + "lon": 2.57295805 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 3 + }, + { + "id": "bondy", + "name": "Bondy", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.894008549999995, + "lon": 2.47938765 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 58 + }, + { + "id": "boulainvilliers", + "name": "Boulainvilliers", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8565634, + "lon": 2.2751605 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 76 + }, + { + "id": "bouray", + "name": "Bouray", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.533215049999995, + "lon": 2.29038025 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 19 + }, + { + "id": "bourg-la-reine", + "name": "Bourg-la-Reine", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.780187225, + "lon": 2.312010675 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 51 + }, + { + "id": "boussy-saint-antoine", + "name": "Boussy Saint-Antoine", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.68084335, + "lon": 2.53316635 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "boutigny", + "name": "Boutigny", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.43487945, + "lon": 2.3761951999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 0 + }, + { + "id": "bretigny", + "name": "Brétigny", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.606767225, + "lon": 2.302064675 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 81 + }, + { + "id": "breuillet-bruyeres-le-chatel", + "name": "Breuillet - Bruyères-le-Châtel", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.577411600000005, + "lon": 2.1918824 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 9 + }, + { + "id": "breuillet-village", + "name": "Breuillet - Village", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.5645033, + "lon": 2.1707676 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 11 + }, + { + "id": "brunoy", + "name": "Brunoy", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.699211250000005, + "lon": 2.5065716 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 28 + }, + { + "id": "bry-sur-marne", + "name": "Bry-sur-Marne", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.845183500000005, + "lon": 2.5256087999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 43 + }, + { + "id": "buno-gironville", + "name": "Buno - Gironville", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.3707407, + "lon": 2.3870702 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 2 + }, + { + "id": "bures-sur-yvette", + "name": "Bures-sur-Yvette", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.696142449999996, + "lon": 2.16461065 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 21 + }, + { + "id": "bussy-saint-georges", + "name": "Bussy-Saint-Georges", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.836651149999994, + "lon": 2.7098936499999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 56 + }, + { + "id": "cergy-prefecture", + "name": "Cergy Préfecture", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 49.036425449999996, + "lon": 2.07954285 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "cergy-saint-christophe", + "name": "Cergy - Saint-Christophe", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 49.04960685, + "lon": 2.0346672999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 81 + }, + { + "id": "cernay", + "name": "Cernay", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.98516825, + "lon": 2.25701275 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "cesson", + "name": "Cesson", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.56548705, + "lon": 2.5943254 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 20 + }, + { + "id": "chamarande", + "name": "Chamarande", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.51433165, + "lon": 2.2156396999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 17 + }, + { + "id": "champ-de-mars-tour-eiffel", + "name": "Champ de Mars - Tour Eiffel", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.856472999999994, + "lon": 2.2896661 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "chantilly-gouvieux", + "name": "Chantilly – Gouvieux", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.1870713, + "lon": 2.4594579999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "charles-de-gaulle-etoile-rer", + "name": "Charles de Gaulle — Étoile (RER)", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.87427245, + "lon": 2.2948715 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "chatelet-les-halles", + "name": "Châtelet - Les Halles", + "attributes": { + "lines": { + "str_list": [ + "A", + "B", + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.861495983333334, + "lon": 2.347111133333333 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 97 + }, + { + "id": "chatou-croissy", + "name": "Chatou - Croissy", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.88519905, + "lon": 2.15627435 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 46 + }, + { + "id": "chaville-velizy", + "name": "Chaville-Vélizy", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.799555749999996, + "lon": 2.1841012500000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "chemin-d-antony", + "name": "Chemin d'Antony", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.747943250000006, + "lon": 2.31274075 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 22 + }, + { + "id": "choisy-le-roi", + "name": "Choisy-le-Roi", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.764168375, + "lon": 2.411256125 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 66 + }, + { + "id": "cite-universitaire", + "name": "Cité Universitaire", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.8216566, + "lon": 2.3385724999999997 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 70 + }, + { + "id": "combs-la-ville-quincy", + "name": "Combs-la-Ville - Quincy", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.66778965, + "lon": 2.54758295 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 43 + }, + { + "id": "conflans-fin-d-oise", + "name": "Conflans-Fin-d'Oise", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.990456449999996, + "lon": 2.0740220000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 79 + }, + { + "id": "corbeil-essonnes", + "name": "Corbeil-Essonnes", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.61314084999999, + "lon": 2.4724201 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 86 + }, + { + "id": "courcelle-sur-yvette", + "name": "Courcelle-sur-Yvette", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.70139355, + "lon": 2.09754305 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 36 + }, + { + "id": "creteil-pompadour", + "name": "Créteil Pompadour", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.77160395, + "lon": 2.4354362 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "denfert-rochereau", + "name": "Denfert-Rochereau", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.83333725, + "lon": 2.3330997 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 85 + }, + { + "id": "dourdan", + "name": "Dourdan", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.533604999999994, + "lon": 2.0096158 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 44 + }, + { + "id": "dourdan-la-foret", + "name": "Dourdan - La Forêt", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.5353954, + "lon": 1.9957233 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 47 + }, + { + "id": "drancy", + "name": "Drancy", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.93275955, + "lon": 2.4547389500000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 48 + }, + { + "id": "egly", + "name": "Égly", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.5825162, + "lon": 2.22258535 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "emerainville-pontault-combault", + "name": "Émerainville Pontault-Combault", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.80583645, + "lon": 2.6192446 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "epinay-sur-orge", + "name": "Épinay-sur-Orge", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.66932095, + "lon": 2.3318318500000004 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "epinay-sur-seine", + "name": "Épinay-sur-Seine", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.953743700000004, + "lon": 2.30233475 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "ermont-eaubonne", + "name": "Ermont - Eaubonne", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.9805091, + "lon": 2.2723723 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "essonnes-robinson", + "name": "Essonnes Robinson", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.6056216, + "lon": 2.46262515 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "etampes", + "name": "Étampes", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.436977299999995, + "lon": 2.15947935 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "etrechy", + "name": "Étréchy", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.493664800000005, + "lon": 2.1945828499999998 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "evry-courcouronnes-centre", + "name": "Évry Courcouronnes-Centre", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.625907850000004, + "lon": 2.4299280999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "evry-val-de-seine", + "name": "Évry Val de Seine", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.6345059, + "lon": 2.45223525 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "fontaine-michalon", + "name": "Fontaine-Michalon", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.74310275, + "lon": 2.2958982 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "fontenay-aux-roses", + "name": "Fontenay-aux-Roses", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.7873985, + "lon": 2.2929925 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 25 + }, + { + "id": "fontenay-sous-bois", + "name": "Fontenay-sous-Bois", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.8436934, + "lon": 2.4637351499999998 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 37 + }, + { + "id": "franconville-le-plessis-bouchard", + "name": "Franconville – Le Plessis-Bouchard", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.993395750000005, + "lon": 2.2351256 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "gagny", + "name": "Gagny", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.883766800000004, + "lon": 2.5254399000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 54 + }, + { + "id": "gare-de-lyon", + "name": "Gare de Lyon", + "attributes": { + "lines": { + "str_list": [ + "A", + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.84349256666667, + "lon": 2.3742778666666666 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 99 + }, + { + "id": "garges-sarcelles", + "name": "Garges - Sarcelles", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.97651205, + "lon": 2.39011105 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 83 + }, + { + "id": "gennevilliers", + "name": "Gennevilliers", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.932888899999995, + "lon": 2.3079555999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 40 + }, + { + "id": "gentilly", + "name": "Gentilly", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.815180350000006, + "lon": 2.34075845 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 31 + }, + { + "id": "gif-sur-yvette", + "name": "Gif-sur-Yvette", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.6981854, + "lon": 2.1365512 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 16 + }, + { + "id": "goussainville", + "name": "Goussainville", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.02345805, + "lon": 2.46274425 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 41 + }, + { + "id": "grand-bourg", + "name": "Grand Bourg", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.6480665, + "lon": 2.43595425 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 14 + }, + { + "id": "gretz-armainvilliers", + "name": "Gretz-Armainvilliers", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.74629255, + "lon": 2.7273792500000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 35 + }, + { + "id": "grigny-centre", + "name": "Grigny-Centre", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.6542429, + "lon": 2.39638095 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 52 + }, + { + "id": "haussmann-saint-lazare", + "name": "Haussmann - Saint-Lazare", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.8750157, + "lon": 2.3286964 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 91 + }, + { + "id": "houilles-carrieres-sur-seine", + "name": "Houilles Carrières-sur-Seine", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.920226799999995, + "lon": 2.185352 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "issy", + "name": "Issy", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.819340100000005, + "lon": 2.25781515 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "issy-val-de-seine", + "name": "Issy Val de Seine", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.829860499999995, + "lon": 2.26349605 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "ivry-sur-seine", + "name": "Ivry-sur-Seine", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8144741, + "lon": 2.3912404499999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "javel", + "name": "Javel", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8468388, + "lon": 2.2776023 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 69 + }, + { + "id": "joinville-le-pont", + "name": "Joinville-le-Pont", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.820870049999996, + "lon": 2.4637851 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 50 + }, + { + "id": "juvisy-sur-orge", + "name": "Juvisy-sur-Orge", + "attributes": { + "lines": { + "str_list": [ + "C", + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.689638375, + "lon": 2.3832783749999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 93 + }, + { + "id": "la-borne-blanche", + "name": "La Borne Blanche", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.126813150000004, + "lon": 2.50607585 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 42 + }, + { + "id": "la-courneuve-aubervilliers", + "name": "La Courneuve - Aubervilliers", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.924379, + "lon": 2.3862190500000002 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 72 + }, + { + "id": "la-croix-de-berny", + "name": "La Croix de Berny", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.7615001, + "lon": 2.3041543 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 87 + }, + { + "id": "la-defense-grande-arche", + "name": "La Défense - Grande Arche", + "attributes": { + "lines": { + "str_list": [ + "A", + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.892192, + "lon": 2.238860025 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 94 + }, + { + "id": "la-ferte-alais", + "name": "La Ferté-Alais", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.4847658, + "lon": 2.3517665 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 15 + }, + { + "id": "la-hacquiniere", + "name": "La Hacquinière", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.695300700000004, + "lon": 2.15149335 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 23 + }, + { + "id": "la-norville-saint-germain-les-arpajon", + "name": "La Norville - Saint-Germain-lès-Arpajon", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.5914818, + "lon": 2.26698 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 13 + }, + { + "id": "la-plaine-stade-de-france", + "name": "La Plaine Stade de France", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.91816275, + "lon": 2.3625317 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "la-varenne-chennevieres", + "name": "La Varenne - Chennevières", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.79487295, + "lon": 2.5128806 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 75 + }, + { + "id": "laplace", + "name": "Laplace", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.80838695, + "lon": 2.3343824 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 64 + }, + { + "id": "lardy", + "name": "Lardy", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.520735900000005, + "lon": 2.2555125499999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 6 + }, + { + "id": "le-blanc-mesnil", + "name": "Le Blanc-Mesnil", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.93237535, + "lon": 2.47544805 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-bourget", + "name": "Le Bourget", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.93072805, + "lon": 2.4253042000000002 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-bras-de-fer", + "name": "Le Bras de Fer", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.6232962, + "lon": 2.45077085 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-chenay-gagny", + "name": "Le Chénay Gagny", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.877126149999995, + "lon": 2.5531413499999998 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-coudray-montceaux", + "name": "Le Coudray - Montceaux", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.566177249999996, + "lon": 2.4924723 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-guichet", + "name": "Le Guichet", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.705391399999996, + "lon": 2.1931488999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-mee", + "name": "Le Mée", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.53909205, + "lon": 2.6250405 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-parc-de-saint-maur", + "name": "Le Parc de Saint-Maur", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.80527145, + "lon": 2.48560135 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-plessis-chenet", + "name": "Le Plessis-Chenet", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.573567249999996, + "lon": 2.4795947 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-raincy-villemomble-montfermeil", + "name": "Le Raincy Villemomble Montfermeil", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.88889165, + "lon": 2.51297365 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-vert-de-maisons", + "name": "Le Vert de Maisons", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.78903455, + "lon": 2.4320316999999996 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-vesinet-centre", + "name": "Le Vésinet Centre", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.890155, + "lon": 2.1343715 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "le-vesinet-le-pecq", + "name": "Le Vésinet - Le Pecq", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.897897, + "lon": 2.1220736000000002 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-ardoines", + "name": "Les Ardoines", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.7829983, + "lon": 2.40945735 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-baconnets", + "name": "Les Baconnets", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.73983145, + "lon": 2.2880845 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-boullereaux-champigny", + "name": "Les Boullereaux - Champigny", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.82487195, + "lon": 2.51155695 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-gresillons", + "name": "Les Grésillons", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.92094025, + "lon": 2.3138 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-noues", + "name": "Les Noues", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.03251045, + "lon": 2.4768478 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-saules", + "name": "Les Saules", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.745472899999996, + "lon": 2.41757255 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "les-yvris-noisy-le-grand", + "name": "Les Yvris Noisy-le-Grand", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.82316625, + "lon": 2.5797944499999996 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "lieusaint-moissy", + "name": "Lieusaint - Moissy", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.628282150000004, + "lon": 2.56959175 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 60 + }, + { + "id": "lognes", + "name": "Lognes", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.8392491, + "lon": 2.6331170999999998 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 38 + }, + { + "id": "louvres", + "name": "Louvres", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.04958525, + "lon": 2.50210615 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 18 + }, + { + "id": "lozere", + "name": "Lozère", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.705839, + "lon": 2.21256435 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 53 + }, + { + "id": "luxembourg", + "name": "Luxembourg", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.84547225, + "lon": 2.33980775 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 86 + }, + { + "id": "magenta", + "name": "Magenta", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.880831799999996, + "lon": 2.35872015 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 94 + }, + { + "id": "maisons-alfort-alfortville", + "name": "Maisons-Alfort - Alfortville", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.80230215, + "lon": 2.4264766 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 61 + }, + { + "id": "maisons-laffitte", + "name": "Maisons-Laffitte", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.94558275, + "lon": 2.1449765000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 68 + }, + { + "id": "maisse", + "name": "Maisse", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.393674399999995, + "lon": 2.39344875 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 5 + }, + { + "id": "marolles-en-hurepoix", + "name": "Marolles-en-Hurepoix", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.56512635, + "lon": 2.2909645999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 10 + }, + { + "id": "massy-palaiseau", + "name": "Massy-Palaiseau", + "attributes": { + "lines": { + "str_list": [ + "B", + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.72538698333333, + "lon": 2.2592837833333337 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 96 + }, + { + "id": "massy-verrieres", + "name": "Massy - Verrières", + "attributes": { + "lines": { + "str_list": [ + "B", + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.734856775, + "lon": 2.27369105 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 53 + }, + { + "id": "mennecy", + "name": "Mennecy", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.57107055, + "lon": 2.43310955 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 8 + }, + { + "id": "meudon-val-fleury", + "name": "Meudon Val Fleury", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.807847100000004, + "lon": 2.2411656 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "mitry-claye", + "name": "Mitry - Claye", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.97594195, + "lon": 2.6422705 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 83 + }, + { + "id": "montgeron-crosne", + "name": "Montgeron - Crosne", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.70831185, + "lon": 2.46209065 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 33 + }, + { + "id": "montigny-beauchamp", + "name": "Montigny-Beauchamp", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 49.007375350000004, + "lon": 2.19760145 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "moulin-galant", + "name": "Moulin Galant", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.5863573, + "lon": 2.4734914999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "musee-d-orsay", + "name": "Musée d'Orsay", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.860533950000004, + "lon": 2.32608915 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 100 + }, + { + "id": "nanterre-la-folie", + "name": "Nanterre La Folie", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.8975295, + "lon": 2.2270234 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 92 + }, + { + "id": "nanterre-prefecture", + "name": "Nanterre-Préfecture", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.896481075, + "lon": 2.222339275 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 75 + }, + { + "id": "nanterre-universite", + "name": "Nanterre - Université", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.90101335, + "lon": 2.21361295 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 72 + }, + { + "id": "nanterre-ville", + "name": "Nanterre Ville", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.89502205, + "lon": 2.1950379 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "nation", + "name": "Nation", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.848275650000005, + "lon": 2.39583595 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 74 + }, + { + "id": "neuilly-plaisance", + "name": "Neuilly-Plaisance", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.853440250000006, + "lon": 2.5138327 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 65 + }, + { + "id": "neuilly-porte-maillot", + "name": "Neuilly - Porte Maillot", + "attributes": { + "lines": { + "str_list": [ + "C", + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.87842345, + "lon": 2.28403235 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 90 + }, + { + "id": "neuville-universite", + "name": "Neuville Université", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 49.013954299999995, + "lon": 2.0783215999999998 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "nogent-le-perreux", + "name": "Nogent - Le Perreux", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.83867215, + "lon": 2.49427405 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 58 + }, + { + "id": "nogent-sur-marne", + "name": "Nogent-sur-Marne", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.835198500000004, + "lon": 2.47181565 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 42 + }, + { + "id": "noisiel", + "name": "Noisiel", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.84350555, + "lon": 2.6166424499999996 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 49 + }, + { + "id": "noisy-champs", + "name": "Noisy-Champs", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.8428607, + "lon": 2.5798271 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 89 + }, + { + "id": "noisy-le-grand-mont-d-est", + "name": "Noisy-le-Grand - Mont d’Est", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.840769, + "lon": 2.54775505 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "noisy-le-sec", + "name": "Noisy-le-Sec", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.896659125, + "lon": 2.458669475 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 77 + }, + { + "id": "orangis-bois-de-l-epine", + "name": "Orangis - Bois de l'Épine", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.636350050000004, + "lon": 2.4077352 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "orly-ville", + "name": "Orly Ville", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.74187335, + "lon": 2.4028727 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "orry-la-ville-coye", + "name": "Orry-la-Ville - Coye", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.1383889, + "lon": 2.490182 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "orry-la-ville-coye-la-foret", + "name": "Orry-la-Ville - Coye-la-Forêt", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.1383073, + "lon": 2.4899737 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "orsay-ville", + "name": "Orsay-Ville", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.6974984, + "lon": 2.1806634000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "ozoir-la-ferriere", + "name": "Ozoir-la-Ferrière", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.77078655, + "lon": 2.6902621499999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "palaiseau", + "name": "Palaiseau", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.71656875, + "lon": 2.2453737 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 30 + }, + { + "id": "palaiseau-villebon", + "name": "Palaiseau - Villebon", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.708208400000004, + "lon": 2.2373585 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 26 + }, + { + "id": "pantin", + "name": "Pantin", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.8981589, + "lon": 2.4023564 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 56 + }, + { + "id": "parc-de-sceaux", + "name": "Parc de Sceaux", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.76957055, + "lon": 2.30982715 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "parc-des-expositions", + "name": "Parc des Expositions", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.97340165, + "lon": 2.5144466999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "paris-austerlitz", + "name": "Paris Austerlitz", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.84061425, + "lon": 2.36701695 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 97 + }, + { + "id": "paris-gare-du-nord", + "name": "Paris Gare du Nord", + "attributes": { + "lines": { + "str_list": [ + "B", + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.88140255, + "lon": 2.3574272 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 98 + }, + { + "id": "pereire-levallois", + "name": "Pereire - Levallois", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8858759, + "lon": 2.2989608 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 63 + }, + { + "id": "pierrefitte-stains", + "name": "Pierrefitte-Stains", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.962378650000005, + "lon": 2.36988585 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 82 + }, + { + "id": "pierrelaye", + "name": "Pierrelaye", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 49.01941875, + "lon": 2.15361365 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 11 + }, + { + "id": "pont-de-l-alma", + "name": "Pont de l'Alma", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.86254375, + "lon": 2.29996115 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "pont-de-rungis-aeroport-d-orly", + "name": "Pont de Rungis Aéroport d'Orly", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.7484174, + "lon": 2.3732246 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "pont-du-garigliano-hopital-europeen-georges-pompidou", + "name": "Pont du Garigliano - Hôpital Européen Georges-Pompidou", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8390808, + "lon": 2.27044845 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "ponthierry-pringy", + "name": "Ponthierry Pringy", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.5349812, + "lon": 2.5450101 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "porchefontaine", + "name": "Porchefontaine", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.79644625, + "lon": 2.15141455 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 32 + }, + { + "id": "port-royal", + "name": "Port Royal", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.840085599999995, + "lon": 2.337069 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "porte-de-clichy", + "name": "Porte de Clichy", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.89414885, + "lon": 2.31548165 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 36 + }, + { + "id": "ris-orangis", + "name": "Ris-Orangis", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.659306, + "lon": 2.4143371 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 14 + }, + { + "id": "robinson", + "name": "Robinson", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.78007855, + "lon": 2.28130495 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 78 + }, + { + "id": "roissy-en-brie", + "name": "Roissy-en-Brie", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.79565995, + "lon": 2.6503854000000002 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 29 + }, + { + "id": "rosa-parks", + "name": "Rosa Parks", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.89648665, + "lon": 2.37406875 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "rosny-bois-perrier", + "name": "Rosny - Bois-Perrier", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.88254115, + "lon": 2.48121005 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "rosny-sous-bois", + "name": "Rosny-sous-Bois", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.8703372, + "lon": 2.4858463 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 39 + }, + { + "id": "rueil-malmaison", + "name": "Rueil-Malmaison", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.88767325, + "lon": 2.17247705 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 59 + }, + { + "id": "rungis-la-fraternelle", + "name": "Rungis - La Fraternelle", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.7404177, + "lon": 2.3526369000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 39 + }, + { + "id": "saint-cheron", + "name": "Saint-Chéron", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.5510819, + "lon": 2.1256568 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 6 + }, + { + "id": "saint-cyr", + "name": "Saint-Cyr", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.79871795, + "lon": 2.07292055 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 73 + }, + { + "id": "saint-denis-l-ile-saint-denis", + "name": "Saint-Denis - L'Île-Saint-Denis", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.93450285, + "lon": 2.34572635 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 89 + }, + { + "id": "saint-fargeau", + "name": "Saint-Fargeau", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.5645034, + "lon": 2.5426532 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 8 + }, + { + "id": "saint-gratien", + "name": "Saint-Gratien", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.9636127, + "lon": 2.28588025 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 25 + }, + { + "id": "saint-martin-d-etampes", + "name": "Saint-Martin d'Étampes", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.4274433, + "lon": 2.1452258 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "saint-maur-champigny", + "name": "Saint-Maur – Champigny", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.80700185, + "lon": 2.5100316 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 12 + }, + { + "id": "saint-maur-creteil", + "name": "Saint-Maur Créteil", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.806387099999995, + "lon": 2.4722479 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "saint-michel-notre-dame", + "name": "Saint-Michel Notre-Dame", + "attributes": { + "lines": { + "str_list": [ + "B", + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8531851, + "lon": 2.3455406500000002 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "saint-michel-sur-orge", + "name": "Saint-Michel-sur-Orge", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.635689049999996, + "lon": 2.30680235 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 21 + }, + { + "id": "saint-ouen", + "name": "Saint-Ouen", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.90533275, + "lon": 2.3225177 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 57 + }, + { + "id": "saint-ouen-l-aumone", + "name": "Saint-Ouen-l'Aumône", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 49.0452727, + "lon": 2.1050072 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 31 + }, + { + "id": "saint-ouen-l-aumone-liesse", + "name": "Saint-Ouen-l'Aumône Liesse", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 49.03402935, + "lon": 2.1282488500000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "saint-quentin-en-yvelines", + "name": "Saint-Quentin-en-Yvelines", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.7873468, + "lon": 2.04447585 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 88 + }, + { + "id": "saint-remy-les-chevreuse", + "name": "Saint-Rémy-lès-Chevreuse", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.702732, + "lon": 2.0709586 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 67 + }, + { + "id": "sainte-genevieve-des-bois", + "name": "Sainte-Geneviève-des-Bois", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.65312295, + "lon": 2.3133034500000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 34 + }, + { + "id": "sartrouville", + "name": "Sartrouville", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.93775795, + "lon": 2.15703135 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 61 + }, + { + "id": "savigny-le-temple-nandy", + "name": "Savigny-le-Temple - Nandy", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.5955668, + "lon": 2.5839448 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 19 + }, + { + "id": "savigny-sur-orge", + "name": "Savigny-sur-Orge", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.67609804999999, + "lon": 2.3520803499999996 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 47 + }, + { + "id": "sceaux", + "name": "Sceaux", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.7813371, + "lon": 2.29810275 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 28 + }, + { + "id": "sermaise", + "name": "Sermaise", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.535515849999996, + "lon": 2.06880005 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 1 + }, + { + "id": "sevran-beaudottes", + "name": "Sevran - Beaudottes", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.94756605, + "lon": 2.52472275 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 64 + }, + { + "id": "sevran-livry", + "name": "Sevran - Livry", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.9364324, + "lon": 2.5351174 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 50 + }, + { + "id": "stade-de-france-saint-denis", + "name": "Stade de France - Saint-Denis", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.91787915, + "lon": 2.3504258 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "sucy-bonneuil", + "name": "Sucy - Bonneuil", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.7720759, + "lon": 2.5074870000000002 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 62 + }, + { + "id": "survilliers-fosses", + "name": "Survilliers - Fosses", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 49.0995767, + "lon": 2.5255327000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 71 + }, + { + "id": "torcy", + "name": "Torcy", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.839671, + "lon": 2.65523385 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 84 + }, + { + "id": "val-d-europe", + "name": "Val d'Europe", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.8548991, + "lon": 2.77256645 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "val-de-fontenay", + "name": "Val de Fontenay", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.854187249999995, + "lon": 2.489195 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 92 + }, + { + "id": "val-de-fontenay-rer-a", + "name": "Val-de-Fontenay (RER A)", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.854209600000004, + "lon": 2.48888605 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "versailles-chantiers", + "name": "Versailles-Chantiers", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.79531605, + "lon": 2.13553735 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 95 + }, + { + "id": "versailles-chateau-rive-gauche", + "name": "Versailles Château Rive Gauche", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8002522, + "lon": 2.12912155 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "vert-galant", + "name": "Vert Galant", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.944214099999996, + "lon": 2.5663885 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "vigneux-sur-seine", + "name": "Vigneux-sur-Seine", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.7083521, + "lon": 2.4143032 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 33 + }, + { + "id": "villabe", + "name": "Villabé", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.5928133, + "lon": 2.4615346000000002 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 3 + }, + { + "id": "villeneuve-le-roi", + "name": "Villeneuve-le-Roi", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.74024085, + "lon": 2.42621195 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 24 + }, + { + "id": "villeneuve-saint-georges", + "name": "Villeneuve-Saint-Georges", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.7301568, + "lon": 2.4461518 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 78 + }, + { + "id": "villeneuve-triage", + "name": "Villeneuve Triage", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.74466565, + "lon": 2.4385776000000003 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "villeparisis-mitry-le-neuf", + "name": "Villeparisis - Mitry le Neuf", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.95322205, + "lon": 2.6031590500000004 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "villepinte-parc-du-sausset", + "name": "Villepinte - Parc du Sausset", + "attributes": { + "lines": { + "str_list": [ + "B" + ] + }, + "geo": { + "geo": { + "lat": 48.96251235, + "lon": 2.5127708 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "villiers-le-bel-gonesse-arnouville", + "name": "Villiers-le-Bel - Gonesse - Arnouville", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.99399, + "lon": 2.41637485 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 69 + }, + { + "id": "villiers-sur-marne-le-plessis-trevise", + "name": "Villiers-sur-Marne - Le Plessis-Trévise", + "attributes": { + "lines": { + "str_list": [ + "E" + ] + }, + "geo": { + "geo": { + "lat": 48.8231869, + "lon": 2.5425505 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 67 + }, + { + "id": "vincennes", + "name": "Vincennes", + "attributes": { + "lines": { + "str_list": [ + "A" + ] + }, + "geo": { + "geo": { + "lat": 48.847345250000004, + "lon": 2.4324622 + } + }, + "in_paris": { + "bool": true + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 80 + }, + { + "id": "viroflay-rive-gauche", + "name": "Viroflay Rive Gauche", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8006869, + "lon": 2.17154165 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + }, + { + "id": "viry-chatillon", + "name": "Viry-Châtillon", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.6762224, + "lon": 2.3866237999999997 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 17 + }, + { + "id": "vitry-sur-seine", + "name": "Vitry-sur-Seine", + "attributes": { + "lines": { + "str_list": [ + "C" + ] + }, + "geo": { + "geo": { + "lat": 48.8006163, + "lon": 2.402478 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 45 + }, + { + "id": "vosves", + "name": "Vosves", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.515161899999995, + "lon": 2.59914605 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + }, + "fame_score": 27 + }, + { + "id": "yerres", + "name": "Yerres", + "attributes": { + "lines": { + "str_list": [ + "D" + ] + }, + "geo": { + "geo": { + "lat": 48.706480799999994, + "lon": 2.4834242 + } + }, + "in_paris": { + "bool": false + }, + "zone": { + "num": 0.0 + } + } + } +] diff --git a/domains/rer/metadata.json b/domains/rer/metadata.json new file mode 100644 index 0000000..02eb8d7 --- /dev/null +++ b/domains/rer/metadata.json @@ -0,0 +1,34 @@ +{ + "id": "rer", + "name": { + "fr": "RER d'Île-de-France", + "en": "Île-de-France RER" + }, + "version": "0.2.0", + "default_locale": "fr", + "license": "ODbL-1.0", + "sources": [ + "https://overpass-api.de/api/interpreter" + ], + "generator_constraints": { + "min_candidates_per_cell": 2, + "max_candidates_per_cell": 25, + "max_predicate_family_repeats": 1, + "row_predicate_count": 3, + "col_predicate_count": 3 + }, + "dataset_sha256": "8493880538ec9e67cee4ee0dc26e98fffba447de50e00faf738a689770cf559b", + "entity_count": 230, + "sources_versions": [ + { + "id": "osm-overpass-rer-routes", + "url": "https://overpass-api.de/api/interpreter", + "date": "2026-05-13" + }, + { + "id": "wikipedia-pageviews-fame", + "url": "https://wikimedia.org/api/rest_v1/metrics/pageviews/per-article/fr.wikipedia", + "date": "2026-05-13" + } + ] +} diff --git a/domains/rer/predicates.json b/domains/rer/predicates.json new file mode 100644 index 0000000..a896367 --- /dev/null +++ b/domains/rer/predicates.json @@ -0,0 +1,482 @@ +[ + { + "family": "ends_with", + "param": "s", + "labels": { + "fr": { + "text": "Termine par la lettre 'S'", + "help": "On compare la dernière lettre alphabétique du nom, accent ignoré." + }, + "en": { + "text": "Ends with the letter 'S'", + "help": "The comparison strips accents and matches the trailing letter." + } + }, + "tags": ["letters"] + }, + { + "family": "ends_with", + "param": "t", + "labels": { + "fr": { + "text": "Termine par la lettre 'T'", + "help": "On compare la dernière lettre alphabétique du nom." + }, + "en": { + "text": "Ends with the letter 'T'", + "help": "The comparison strips accents and matches the trailing letter." + } + }, + "tags": ["letters"] + }, + { + "family": "ends_with", + "param": "n", + "labels": { + "fr": { + "text": "Termine par la lettre 'N'", + "help": "On compare la dernière lettre alphabétique du nom." + }, + "en": { + "text": "Ends with the letter 'N'", + "help": "The comparison strips accents and matches the trailing letter." + } + }, + "tags": ["letters"] + }, + { + "family": "ends_with", + "param": "y", + "labels": { + "fr": { + "text": "Termine par la lettre 'Y'", + "help": "On compare la dernière lettre alphabétique du nom." + }, + "en": { + "text": "Ends with the letter 'Y'", + "help": "The comparison strips accents and matches the trailing letter." + } + }, + "tags": ["letters"] + }, + { + "family": "starts_with", + "param": "s", + "labels": { + "fr": { + "text": "Commence par la lettre 'S'", + "help": "On compare la première lettre du nom, accents ignorés." + }, + "en": { + "text": "Starts with the letter 'S'", + "help": "Accents are stripped before comparison." + } + }, + "tags": ["letters"] + }, + { + "family": "starts_with", + "param": "c", + "labels": { + "fr": { + "text": "Commence par la lettre 'C'", + "help": "On compare la première lettre du nom." + }, + "en": { + "text": "Starts with the letter 'C'", + "help": "Accents are stripped before comparison." + } + }, + "tags": ["letters"] + }, + { + "family": "starts_with", + "param": "v", + "labels": { + "fr": { + "text": "Commence par la lettre 'V'", + "help": "On compare la première lettre du nom." + }, + "en": { + "text": "Starts with the letter 'V'", + "help": "Accents are stripped before comparison." + } + }, + "tags": ["letters"] + }, + { + "family": "starts_with", + "param": "l", + "labels": { + "fr": { + "text": "Commence par la lettre 'L'", + "help": "On compare la première lettre du nom." + }, + "en": { + "text": "Starts with the letter 'L'", + "help": "Accents are stripped before comparison." + } + }, + "tags": ["letters"] + }, + { + "family": "contains_letter", + "param": "y", + "labels": { + "fr": { + "text": "Contient la lettre 'Y' dans son nom", + "help": "On cherche la lettre n'importe où, accents ignorés." + }, + "en": { + "text": "Contains the letter 'Y'", + "help": "Searches the whole name, accent-insensitive." + } + }, + "tags": ["letters"] + }, + { + "family": "contains_letter", + "param": "u", + "labels": { + "fr": { + "text": "Contient la lettre 'U' dans son nom", + "help": "On cherche la lettre n'importe où, accents ignorés." + }, + "en": { + "text": "Contains the letter 'U'", + "help": "Searches the whole name, accent-insensitive." + } + }, + "tags": ["letters"] + }, + { + "family": "name_length_max", + "param": 7, + "labels": { + "fr": { + "text": "A un nom de 7 lettres ou moins", + "help": "On compte uniquement les lettres alphabétiques." + }, + "en": { + "text": "Has a 7-letter name or shorter", + "help": "Only alphabetic characters are counted." + } + }, + "tags": ["letters"] + }, + { + "family": "name_length_min", + "param": 13, + "labels": { + "fr": { + "text": "A un nom de 13 lettres ou plus", + "help": "On compte uniquement les lettres alphabétiques." + }, + "en": { + "text": "Has a 13-letter name or longer", + "help": "Only alphabetic characters are counted." + } + }, + "tags": ["letters"] + }, + { + "family": "name_length_eq", + "param": 9, + "labels": { + "fr": { + "text": "A un nom de 9 lettres exactement", + "help": "On compte uniquement les lettres alphabétiques." + }, + "en": { + "text": "Has exactly a 9-letter name", + "help": "Only alphabetic characters are counted." + } + }, + "tags": ["letters"] + }, + { + "family": "name_word_count_eq", + "param": 1, + "labels": { + "fr": { + "text": "A un nom en un seul mot", + "help": "Trait d'union, apostrophe et tirets cassent en plusieurs mots." + }, + "en": { + "text": "Has a one-word name", + "help": "Hyphens and apostrophes split into multiple words." + } + }, + "tags": ["words"] + }, + { + "family": "name_word_count_eq", + "param": 3, + "labels": { + "fr": { + "text": "A un nom en trois mots", + "help": "Trait d'union, apostrophe et tirets cassent en plusieurs mots." + }, + "en": { + "text": "Has a three-word name", + "help": "Hyphens and apostrophes split into multiple words." + } + }, + "tags": ["words"] + }, + { + "family": "name_word_count_min", + "param": 4, + "labels": { + "fr": { + "text": "A un nom en quatre mots ou plus", + "help": "Trait d'union, apostrophe et tirets cassent en plusieurs mots." + }, + "en": { + "text": "Has a four-word name or longer", + "help": "Hyphens and apostrophes split into multiple words." + } + }, + "tags": ["words"] + }, + { + "family": "attr_list_size_eq", + "param": { "attr": "lines", "n": 1 }, + "labels": { + "fr": { + "text": "Desservie par une seule ligne", + "help": "Compte le nombre de lignes RER." + }, + "en": { + "text": "Served by a single line", + "help": "Counts the number of RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_in_set", + "param": { "attr": "lines", "values": ["A"] }, + "labels": { + "fr": { + "text": "Sur la ligne A", + "help": "Présent dans la liste des lignes desservies." + }, + "en": { + "text": "On line A", + "help": "Listed among the served RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_in_set", + "param": { "attr": "lines", "values": ["B"] }, + "labels": { + "fr": { + "text": "Sur la ligne B", + "help": "Présent dans la liste des lignes desservies." + }, + "en": { + "text": "On line B", + "help": "Listed among the served RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_in_set", + "param": { "attr": "lines", "values": ["C"] }, + "labels": { + "fr": { + "text": "Sur la ligne C", + "help": "Présent dans la liste des lignes desservies." + }, + "en": { + "text": "On line C", + "help": "Listed among the served RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_in_set", + "param": { "attr": "lines", "values": ["D"] }, + "labels": { + "fr": { + "text": "Sur la ligne D", + "help": "Présent dans la liste des lignes desservies." + }, + "en": { + "text": "On line D", + "help": "Listed among the served RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_in_set", + "param": { "attr": "lines", "values": ["E"] }, + "labels": { + "fr": { + "text": "Sur la ligne E", + "help": "Présent dans la liste des lignes desservies." + }, + "en": { + "text": "On line E", + "help": "Listed among the served RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_in_set", + "param": { "attr": "lines", "values": ["A", "B"] }, + "labels": { + "fr": { + "text": "Sur la ligne A ou B (axe Est-Ouest historique)", + "help": "Présent sur au moins une des deux lignes les plus anciennes du RER." + }, + "en": { + "text": "On line A or B (historic east-west axis)", + "help": "Listed on at least one of the two original RER lines." + } + }, + "tags": ["network"] + }, + { + "family": "on_attr_eq", + "param": { "attr": "in_paris", "value": false }, + "labels": { + "fr": { + "text": "Hors de Paris intra-muros", + "help": "Définie par la position géographique vs la boucle des boulevards." + }, + "en": { + "text": "Outside inner-Paris", + "help": "Defined by the geographic position vs the ring road bounds." + } + }, + "tags": ["geo"] + }, + { + "family": "on_attr_eq", + "param": { "attr": "in_paris", "value": true }, + "labels": { + "fr": { + "text": "Dans Paris intra-muros", + "help": "Définie par la position géographique vs la boucle des boulevards." + }, + "en": { + "text": "Inside inner-Paris", + "help": "Defined by the geographic position vs the ring road bounds." + } + }, + "tags": ["geo"] + }, + { + "family": "within_km", + "param": { + "attr": "geo", + "from": { "lat": 48.8606, "lon": 2.3376 }, + "km": 3.0, + "anchor_label_fr": "du Louvre", + "anchor_label_en": "of the Louvre" + }, + "labels": { + "fr": { + "text": "À moins de 3 km du Louvre", + "help": "Distance à vol d'oiseau." + }, + "en": { + "text": "Within 3 km of the Louvre", + "help": "Straight-line distance." + } + }, + "tags": ["geo"] + }, + { + "family": "within_km", + "param": { + "attr": "geo", + "from": { "lat": 48.8584, "lon": 2.2945 }, + "km": 3.0, + "anchor_label_fr": "de la Tour Eiffel", + "anchor_label_en": "of the Eiffel Tower" + }, + "labels": { + "fr": { + "text": "À moins de 3 km de la Tour Eiffel", + "help": "Distance à vol d'oiseau." + }, + "en": { + "text": "Within 3 km of the Eiffel Tower", + "help": "Straight-line distance." + } + }, + "tags": ["geo"] + }, + { + "family": "within_km", + "param": { + "attr": "geo", + "from": { "lat": 48.8443, "lon": 2.3739 }, + "km": 4.0, + "anchor_label_fr": "de la Gare de Lyon", + "anchor_label_en": "of Gare de Lyon" + }, + "labels": { + "fr": { + "text": "À moins de 4 km de la Gare de Lyon", + "help": "Distance à vol d'oiseau." + }, + "en": { + "text": "Within 4 km of Gare de Lyon", + "help": "Straight-line distance." + } + }, + "tags": ["geo"] + }, + { + "family": "within_km", + "param": { + "attr": "geo", + "from": { "lat": 49.0097, "lon": 2.5479 }, + "km": 10.0, + "anchor_label_fr": "de l'aéroport CDG", + "anchor_label_en": "of CDG airport" + }, + "labels": { + "fr": { + "text": "À moins de 10 km de l'aéroport Charles de Gaulle", + "help": "Distance à vol d'oiseau." + }, + "en": { + "text": "Within 10 km of Charles de Gaulle airport", + "help": "Straight-line distance." + } + }, + "tags": ["geo"] + }, + { + "family": "within_km", + "param": { + "attr": "geo", + "from": { "lat": 48.8053, "lon": 2.1204 }, + "km": 10.0, + "anchor_label_fr": "du château de Versailles", + "anchor_label_en": "of the Palace of Versailles" + }, + "labels": { + "fr": { + "text": "À moins de 10 km du château de Versailles", + "help": "Distance à vol d'oiseau." + }, + "en": { + "text": "Within 10 km of the Palace of Versailles", + "help": "Straight-line distance." + } + }, + "tags": ["geo"] + } +] diff --git a/domains/rer/tmp/fame_score_report.json b/domains/rer/tmp/fame_score_report.json new file mode 100644 index 0000000..4ee998d --- /dev/null +++ b/domains/rer/tmp/fame_score_report.json @@ -0,0 +1,1619 @@ +{ + "generated_at": "2026-05-13T21:02:39Z", + "window_start": "20250401", + "window_end": "20260430", + "matched": 136, + "total": 230, + "audit": [ + { + "id": "ablon", + "name": "Ablon", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "acheres-grand-cormier", + "name": "Achères Grand Cormier", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "acheres-ville", + "name": "Achères - Ville", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "aeroport-charles-de-gaulle-1", + "name": "Aéroport Charles de Gaulle 1", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "antony", + "name": "Antony", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "arcueil-cachan", + "name": "Arcueil - Cachan", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "arpajon", + "name": "Arpajon", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "athis-mons", + "name": "Athis-Mons", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "auber", + "name": "Auber", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "aulnay-sous-bois", + "name": "Aulnay-sous-Bois", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "avenue-du-president-kennedy", + "name": "Avenue du Président Kennedy", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "avenue-foch", + "name": "Avenue Foch", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "avenue-henri-martin", + "name": "Avenue Henri Martin", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "bagneux", + "name": "Bagneux", + "title": "Gare de Bagneux", + "pageviews": 3366, + "fame_score": 55 + }, + { + "id": "ballancourt", + "name": "Ballancourt", + "title": "Gare de Ballancourt", + "pageviews": 1452, + "fame_score": 7 + }, + { + "id": "bibliotheque-francois-mitterrand", + "name": "Bibliothèque François Mitterrand", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "boigneville", + "name": "Boigneville", + "title": "Gare de Boigneville", + "pageviews": 1261, + "fame_score": 4 + }, + { + "id": "boissise-le-roi", + "name": "Boissise-le-Roi", + "title": "Gare de Boissise-le-Roi", + "pageviews": 1142, + "fame_score": 3 + }, + { + "id": "bondy", + "name": "Bondy", + "title": "Gare de Bondy", + "pageviews": 3690, + "fame_score": 58 + }, + { + "id": "boulainvilliers", + "name": "Boulainvilliers", + "title": "Gare de Boulainvilliers", + "pageviews": 4828, + "fame_score": 76 + }, + { + "id": "bouray", + "name": "Bouray", + "title": "Gare de Bouray", + "pageviews": 1865, + "fame_score": 19 + }, + { + "id": "bourg-la-reine", + "name": "Bourg-la-Reine", + "title": "Gare de Bourg-la-Reine", + "pageviews": 3234, + "fame_score": 51 + }, + { + "id": "boussy-saint-antoine", + "name": "Boussy Saint-Antoine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "boutigny", + "name": "Boutigny", + "title": "Gare de Boutigny", + "pageviews": 1023, + "fame_score": 0 + }, + { + "id": "bretigny", + "name": "Brétigny", + "title": "Gare de Brétigny", + "pageviews": 5218, + "fame_score": 81 + }, + { + "id": "breuillet-bruyeres-le-chatel", + "name": "Breuillet - Bruyères-le-Châtel", + "title": "Gare de Breuillet - Bruyères-le-Châtel", + "pageviews": 1545, + "fame_score": 9 + }, + { + "id": "breuillet-village", + "name": "Breuillet - Village", + "title": "Gare de Breuillet-Village", + "pageviews": 1583, + "fame_score": 11 + }, + { + "id": "brunoy", + "name": "Brunoy", + "title": "Gare de Brunoy", + "pageviews": 2210, + "fame_score": 28 + }, + { + "id": "bry-sur-marne", + "name": "Bry-sur-Marne", + "title": "Gare de Bry-sur-Marne (RATP)", + "pageviews": 2936, + "fame_score": 43 + }, + { + "id": "buno-gironville", + "name": "Buno - Gironville", + "title": "Gare de Buno - Gironville", + "pageviews": 1041, + "fame_score": 2 + }, + { + "id": "bures-sur-yvette", + "name": "Bures-sur-Yvette", + "title": "Gare de Bures-sur-Yvette", + "pageviews": 1897, + "fame_score": 21 + }, + { + "id": "bussy-saint-georges", + "name": "Bussy-Saint-Georges", + "title": "Gare de Bussy-Saint-Georges", + "pageviews": 3499, + "fame_score": 56 + }, + { + "id": "cergy-prefecture", + "name": "Cergy Préfecture", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "cergy-saint-christophe", + "name": "Cergy - Saint-Christophe", + "title": "Gare de Cergy-Saint-Christophe", + "pageviews": 5399, + "fame_score": 81 + }, + { + "id": "cernay", + "name": "Cernay", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "cesson", + "name": "Cesson", + "title": "Gare de Cesson", + "pageviews": 1883, + "fame_score": 20 + }, + { + "id": "chamarande", + "name": "Chamarande", + "title": "Gare de Chamarande", + "pageviews": 1808, + "fame_score": 17 + }, + { + "id": "champ-de-mars-tour-eiffel", + "name": "Champ de Mars - Tour Eiffel", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "chantilly-gouvieux", + "name": "Chantilly – Gouvieux", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "charles-de-gaulle-etoile-rer", + "name": "Charles de Gaulle — Étoile (RER)", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "chatelet-les-halles", + "name": "Châtelet - Les Halles", + "title": "Gare de Châtelet - Les Halles", + "pageviews": 39607, + "fame_score": 97 + }, + { + "id": "chatou-croissy", + "name": "Chatou - Croissy", + "title": "Gare de Chatou - Croissy", + "pageviews": 3011, + "fame_score": 46 + }, + { + "id": "chaville-velizy", + "name": "Chaville-Vélizy", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "chemin-d-antony", + "name": "Chemin d'Antony", + "title": "Gare de Chemin d'Antony", + "pageviews": 1965, + "fame_score": 22 + }, + { + "id": "choisy-le-roi", + "name": "Choisy-le-Roi", + "title": "Gare de Choisy-le-Roi", + "pageviews": 4076, + "fame_score": 66 + }, + { + "id": "cite-universitaire", + "name": "Cité Universitaire", + "title": "Gare de Cité universitaire", + "pageviews": 4251, + "fame_score": 70 + }, + { + "id": "combs-la-ville-quincy", + "name": "Combs-la-Ville - Quincy", + "title": "Gare de Combs-la-Ville - Quincy", + "pageviews": 2936, + "fame_score": 43 + }, + { + "id": "conflans-fin-d-oise", + "name": "Conflans-Fin-d'Oise", + "title": "Gare de Conflans-Fin-d'Oise", + "pageviews": 5112, + "fame_score": 79 + }, + { + "id": "corbeil-essonnes", + "name": "Corbeil-Essonnes", + "title": "Gare de Corbeil-Essonnes", + "pageviews": 6359, + "fame_score": 86 + }, + { + "id": "courcelle-sur-yvette", + "name": "Courcelle-sur-Yvette", + "title": "Gare de Courcelle-sur-Yvette", + "pageviews": 2596, + "fame_score": 36 + }, + { + "id": "creteil-pompadour", + "name": "Créteil Pompadour", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "denfert-rochereau", + "name": "Denfert-Rochereau", + "title": "Gare de Denfert-Rochereau", + "pageviews": 6199, + "fame_score": 85 + }, + { + "id": "dourdan", + "name": "Dourdan", + "title": "Gare de Dourdan", + "pageviews": 2958, + "fame_score": 44 + }, + { + "id": "dourdan-la-foret", + "name": "Dourdan - La Forêt", + "title": "Gare de Dourdan - La Forêt", + "pageviews": 3041, + "fame_score": 47 + }, + { + "id": "drancy", + "name": "Drancy", + "title": "Gare de Drancy", + "pageviews": 3111, + "fame_score": 48 + }, + { + "id": "egly", + "name": "Égly", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "emerainville-pontault-combault", + "name": "Émerainville Pontault-Combault", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "epinay-sur-orge", + "name": "Épinay-sur-Orge", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "epinay-sur-seine", + "name": "Épinay-sur-Seine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "ermont-eaubonne", + "name": "Ermont - Eaubonne", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "essonnes-robinson", + "name": "Essonnes Robinson", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "etampes", + "name": "Étampes", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "etrechy", + "name": "Étréchy", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "evry-courcouronnes-centre", + "name": "Évry Courcouronnes-Centre", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "evry-val-de-seine", + "name": "Évry Val de Seine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "fontaine-michalon", + "name": "Fontaine-Michalon", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "fontenay-aux-roses", + "name": "Fontenay-aux-Roses", + "title": "Gare de Fontenay-aux-Roses", + "pageviews": 2020, + "fame_score": 25 + }, + { + "id": "fontenay-sous-bois", + "name": "Fontenay-sous-Bois", + "title": "Gare de Fontenay-sous-Bois", + "pageviews": 2613, + "fame_score": 37 + }, + { + "id": "franconville-le-plessis-bouchard", + "name": "Franconville – Le Plessis-Bouchard", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "gagny", + "name": "Gagny", + "title": "Gare de Gagny", + "pageviews": 3364, + "fame_score": 54 + }, + { + "id": "gare-de-lyon", + "name": "Gare de Lyon", + "title": "Paris-Gare-de-Lyon", + "pageviews": 68996, + "fame_score": 99 + }, + { + "id": "garges-sarcelles", + "name": "Garges - Sarcelles", + "title": "Gare de Garges - Sarcelles", + "pageviews": 5483, + "fame_score": 83 + }, + { + "id": "gennevilliers", + "name": "Gennevilliers", + "title": "Gare de Gennevilliers", + "pageviews": 2839, + "fame_score": 40 + }, + { + "id": "gentilly", + "name": "Gentilly", + "title": "Gare de Gentilly", + "pageviews": 2428, + "fame_score": 31 + }, + { + "id": "gif-sur-yvette", + "name": "Gif-sur-Yvette", + "title": "Gare de Gif-sur-Yvette", + "pageviews": 1792, + "fame_score": 16 + }, + { + "id": "goussainville", + "name": "Goussainville", + "title": "Gare de Goussainville", + "pageviews": 2863, + "fame_score": 41 + }, + { + "id": "grand-bourg", + "name": "Grand Bourg", + "title": "Gare de Grand Bourg", + "pageviews": 1738, + "fame_score": 14 + }, + { + "id": "gretz-armainvilliers", + "name": "Gretz-Armainvilliers", + "title": "Gare de Gretz-Armainvilliers", + "pageviews": 2574, + "fame_score": 35 + }, + { + "id": "grigny-centre", + "name": "Grigny-Centre", + "title": "Gare de Grigny-Centre", + "pageviews": 3264, + "fame_score": 52 + }, + { + "id": "haussmann-saint-lazare", + "name": "Haussmann - Saint-Lazare", + "title": "Gare d'Haussmann - Saint-Lazare", + "pageviews": 9026, + "fame_score": 91 + }, + { + "id": "houilles-carrieres-sur-seine", + "name": "Houilles Carrières-sur-Seine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "issy", + "name": "Issy", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "issy-val-de-seine", + "name": "Issy Val de Seine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "ivry-sur-seine", + "name": "Ivry-sur-Seine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "javel", + "name": "Javel", + "title": "Gare de Javel", + "pageviews": 4249, + "fame_score": 69 + }, + { + "id": "joinville-le-pont", + "name": "Joinville-le-Pont", + "title": "Gare de Joinville-le-Pont", + "pageviews": 3156, + "fame_score": 50 + }, + { + "id": "juvisy-sur-orge", + "name": "Juvisy-sur-Orge", + "title": "Gare de Juvisy", + "pageviews": 11351, + "fame_score": 93 + }, + { + "id": "la-borne-blanche", + "name": "La Borne Blanche", + "title": "Gare de La Borne Blanche", + "pageviews": 2879, + "fame_score": 42 + }, + { + "id": "la-courneuve-aubervilliers", + "name": "La Courneuve - Aubervilliers", + "title": "Gare de La Courneuve - Aubervilliers", + "pageviews": 4466, + "fame_score": 72 + }, + { + "id": "la-croix-de-berny", + "name": "La Croix de Berny", + "title": "Gare de La Croix de Berny", + "pageviews": 6465, + "fame_score": 87 + }, + { + "id": "la-defense-grande-arche", + "name": "La Défense - Grande Arche", + "title": "Gare de la Défense", + "pageviews": 14485, + "fame_score": 94 + }, + { + "id": "la-ferte-alais", + "name": "La Ferté-Alais", + "title": "Gare de La Ferté-Alais", + "pageviews": 1778, + "fame_score": 15 + }, + { + "id": "la-hacquiniere", + "name": "La Hacquinière", + "title": "Gare de La Hacquinière", + "pageviews": 1977, + "fame_score": 23 + }, + { + "id": "la-norville-saint-germain-les-arpajon", + "name": "La Norville - Saint-Germain-lès-Arpajon", + "title": "Gare de La Norville - Saint-Germain-lès-Arpajon", + "pageviews": 1736, + "fame_score": 13 + }, + { + "id": "la-plaine-stade-de-france", + "name": "La Plaine Stade de France", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "la-varenne-chennevieres", + "name": "La Varenne - Chennevières", + "title": "Gare de La Varenne - Chennevières", + "pageviews": 4784, + "fame_score": 75 + }, + { + "id": "laplace", + "name": "Laplace", + "title": "Gare de Laplace", + "pageviews": 3931, + "fame_score": 64 + }, + { + "id": "lardy", + "name": "Lardy", + "title": "Gare de Lardy", + "pageviews": 1368, + "fame_score": 6 + }, + { + "id": "le-blanc-mesnil", + "name": "Le Blanc-Mesnil", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-bourget", + "name": "Le Bourget", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-bras-de-fer", + "name": "Le Bras de Fer", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-chenay-gagny", + "name": "Le Chénay Gagny", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-coudray-montceaux", + "name": "Le Coudray - Montceaux", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-guichet", + "name": "Le Guichet", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-mee", + "name": "Le Mée", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-parc-de-saint-maur", + "name": "Le Parc de Saint-Maur", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-plessis-chenet", + "name": "Le Plessis-Chenet", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-raincy-villemomble-montfermeil", + "name": "Le Raincy Villemomble Montfermeil", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-vert-de-maisons", + "name": "Le Vert de Maisons", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-vesinet-centre", + "name": "Le Vésinet Centre", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "le-vesinet-le-pecq", + "name": "Le Vésinet - Le Pecq", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-ardoines", + "name": "Les Ardoines", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-baconnets", + "name": "Les Baconnets", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-boullereaux-champigny", + "name": "Les Boullereaux - Champigny", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-gresillons", + "name": "Les Grésillons", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-noues", + "name": "Les Noues", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-saules", + "name": "Les Saules", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "les-yvris-noisy-le-grand", + "name": "Les Yvris Noisy-le-Grand", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "lieusaint-moissy", + "name": "Lieusaint - Moissy", + "title": "Gare de Lieusaint - Moissy", + "pageviews": 3823, + "fame_score": 60 + }, + { + "id": "lognes", + "name": "Lognes", + "title": "Gare de Lognes", + "pageviews": 2715, + "fame_score": 38 + }, + { + "id": "louvres", + "name": "Louvres", + "title": "Gare de Louvres", + "pageviews": 1818, + "fame_score": 18 + }, + { + "id": "lozere", + "name": "Lozère", + "title": "Gare de Lozère", + "pageviews": 3354, + "fame_score": 53 + }, + { + "id": "luxembourg", + "name": "Luxembourg", + "title": "Gare du Luxembourg", + "pageviews": 6334, + "fame_score": 86 + }, + { + "id": "magenta", + "name": "Magenta", + "title": "Gare de Magenta", + "pageviews": 12959, + "fame_score": 94 + }, + { + "id": "maisons-alfort-alfortville", + "name": "Maisons-Alfort - Alfortville", + "title": "Gare de Maisons-Alfort - Alfortville", + "pageviews": 3836, + "fame_score": 61 + }, + { + "id": "maisons-laffitte", + "name": "Maisons-Laffitte", + "title": "Gare de Maisons-Laffitte", + "pageviews": 4147, + "fame_score": 68 + }, + { + "id": "maisse", + "name": "Maisse", + "title": "Gare de Maisse", + "pageviews": 1278, + "fame_score": 5 + }, + { + "id": "marolles-en-hurepoix", + "name": "Marolles-en-Hurepoix", + "title": "Gare de Marolles-en-Hurepoix", + "pageviews": 1575, + "fame_score": 10 + }, + { + "id": "massy-palaiseau", + "name": "Massy-Palaiseau", + "title": "Gare de Massy - Palaiseau", + "pageviews": 21272, + "fame_score": 96 + }, + { + "id": "massy-verrieres", + "name": "Massy - Verrières", + "title": "Gare de Massy - Verrières", + "pageviews": 3302, + "fame_score": 53 + }, + { + "id": "mennecy", + "name": "Mennecy", + "title": "Gare de Mennecy", + "pageviews": 1516, + "fame_score": 8 + }, + { + "id": "meudon-val-fleury", + "name": "Meudon Val Fleury", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "mitry-claye", + "name": "Mitry - Claye", + "title": "Gare de Mitry - Claye", + "pageviews": 5567, + "fame_score": 83 + }, + { + "id": "montgeron-crosne", + "name": "Montgeron - Crosne", + "title": "Gare de Montgeron - Crosne", + "pageviews": 2553, + "fame_score": 33 + }, + { + "id": "montigny-beauchamp", + "name": "Montigny-Beauchamp", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "moulin-galant", + "name": "Moulin Galant", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "musee-d-orsay", + "name": "Musée d'Orsay", + "title": "Musée d'Orsay", + "pageviews": 153660, + "fame_score": 100 + }, + { + "id": "nanterre-la-folie", + "name": "Nanterre La Folie", + "title": "Nanterre La Folie (métro de Paris)", + "pageviews": 10087, + "fame_score": 92 + }, + { + "id": "nanterre-prefecture", + "name": "Nanterre-Préfecture", + "title": "Gare de Nanterre-Préfecture", + "pageviews": 4796, + "fame_score": 75 + }, + { + "id": "nanterre-universite", + "name": "Nanterre - Université", + "title": "Gare de Nanterre-Université", + "pageviews": 4480, + "fame_score": 72 + }, + { + "id": "nanterre-ville", + "name": "Nanterre Ville", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "nation", + "name": "Nation", + "title": "Gare de Nation", + "pageviews": 4730, + "fame_score": 74 + }, + { + "id": "neuilly-plaisance", + "name": "Neuilly-Plaisance", + "title": "Gare de Neuilly-Plaisance", + "pageviews": 3940, + "fame_score": 65 + }, + { + "id": "neuilly-porte-maillot", + "name": "Neuilly - Porte Maillot", + "title": "Gare de Neuilly - Porte Maillot", + "pageviews": 7913, + "fame_score": 90 + }, + { + "id": "neuville-universite", + "name": "Neuville Université", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "nogent-le-perreux", + "name": "Nogent - Le Perreux", + "title": "Gare de Nogent - Le Perreux", + "pageviews": 3637, + "fame_score": 58 + }, + { + "id": "nogent-sur-marne", + "name": "Nogent-sur-Marne", + "title": "Gare de Nogent-sur-Marne", + "pageviews": 2906, + "fame_score": 42 + }, + { + "id": "noisiel", + "name": "Noisiel", + "title": "Gare de Noisiel", + "pageviews": 3124, + "fame_score": 49 + }, + { + "id": "noisy-champs", + "name": "Noisy-Champs", + "title": "Gare de Noisy - Champs", + "pageviews": 7534, + "fame_score": 89 + }, + { + "id": "noisy-le-grand-mont-d-est", + "name": "Noisy-le-Grand - Mont d’Est", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "noisy-le-sec", + "name": "Noisy-le-Sec", + "title": "Gare de Noisy-le-Sec", + "pageviews": 4955, + "fame_score": 77 + }, + { + "id": "orangis-bois-de-l-epine", + "name": "Orangis - Bois de l'Épine", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "orly-ville", + "name": "Orly Ville", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "orry-la-ville-coye", + "name": "Orry-la-Ville - Coye", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "orry-la-ville-coye-la-foret", + "name": "Orry-la-Ville - Coye-la-Forêt", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "orsay-ville", + "name": "Orsay-Ville", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "ozoir-la-ferriere", + "name": "Ozoir-la-Ferrière", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "palaiseau", + "name": "Palaiseau", + "title": "Gare de Palaiseau", + "pageviews": 2283, + "fame_score": 30 + }, + { + "id": "palaiseau-villebon", + "name": "Palaiseau - Villebon", + "title": "Gare de Palaiseau - Villebon", + "pageviews": 2082, + "fame_score": 26 + }, + { + "id": "pantin", + "name": "Pantin", + "title": "Gare de Pantin", + "pageviews": 3376, + "fame_score": 56 + }, + { + "id": "parc-de-sceaux", + "name": "Parc de Sceaux", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "parc-des-expositions", + "name": "Parc des Expositions", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "paris-austerlitz", + "name": "Paris Austerlitz", + "title": "Gare de Paris-Austerlitz", + "pageviews": 52850, + "fame_score": 97 + }, + { + "id": "paris-gare-du-nord", + "name": "Paris Gare du Nord", + "title": "Gare de Paris-Nord", + "pageviews": 68935, + "fame_score": 98 + }, + { + "id": "pereire-levallois", + "name": "Pereire - Levallois", + "title": "Gare de Pereire - Levallois", + "pageviews": 3881, + "fame_score": 63 + }, + { + "id": "pierrefitte-stains", + "name": "Pierrefitte-Stains", + "title": "Gare de Pierrefitte - Stains", + "pageviews": 5433, + "fame_score": 82 + }, + { + "id": "pierrelaye", + "name": "Pierrelaye", + "title": "Gare de Pierrelaye", + "pageviews": 1610, + "fame_score": 11 + }, + { + "id": "pont-de-l-alma", + "name": "Pont de l'Alma", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "pont-de-rungis-aeroport-d-orly", + "name": "Pont de Rungis Aéroport d'Orly", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "pont-du-garigliano-hopital-europeen-georges-pompidou", + "name": "Pont du Garigliano - Hôpital Européen Georges-Pompidou", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "ponthierry-pringy", + "name": "Ponthierry Pringy", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "porchefontaine", + "name": "Porchefontaine", + "title": "Gare de Porchefontaine", + "pageviews": 2448, + "fame_score": 32 + }, + { + "id": "port-royal", + "name": "Port Royal", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "porte-de-clichy", + "name": "Porte de Clichy", + "title": "Gare de la Porte de Clichy", + "pageviews": 2611, + "fame_score": 36 + }, + { + "id": "ris-orangis", + "name": "Ris-Orangis", + "title": "Gare de Ris-Orangis", + "pageviews": 1744, + "fame_score": 14 + }, + { + "id": "robinson", + "name": "Robinson", + "title": "Gare de Robinson", + "pageviews": 5054, + "fame_score": 78 + }, + { + "id": "roissy-en-brie", + "name": "Roissy-en-Brie", + "title": "Gare de Roissy-en-Brie", + "pageviews": 2253, + "fame_score": 29 + }, + { + "id": "rosa-parks", + "name": "Rosa Parks", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "rosny-bois-perrier", + "name": "Rosny - Bois-Perrier", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "rosny-sous-bois", + "name": "Rosny-sous-Bois", + "title": "Gare de Rosny-sous-Bois", + "pageviews": 2725, + "fame_score": 39 + }, + { + "id": "rueil-malmaison", + "name": "Rueil-Malmaison", + "title": "Gare de Rueil-Malmaison", + "pageviews": 3755, + "fame_score": 59 + }, + { + "id": "rungis-la-fraternelle", + "name": "Rungis - La Fraternelle", + "title": "Gare de Rungis - La Fraternelle", + "pageviews": 2798, + "fame_score": 39 + }, + { + "id": "saint-cheron", + "name": "Saint-Chéron", + "title": "Gare de Saint-Chéron", + "pageviews": 1381, + "fame_score": 6 + }, + { + "id": "saint-cyr", + "name": "Saint-Cyr", + "title": "Gare de Saint-Cyr", + "pageviews": 4613, + "fame_score": 73 + }, + { + "id": "saint-denis-l-ile-saint-denis", + "name": "Saint-Denis - L'Île-Saint-Denis", + "title": "Gare de Saint-Denis", + "pageviews": 7471, + "fame_score": 89 + }, + { + "id": "saint-fargeau", + "name": "Saint-Fargeau", + "title": "Gare de Saint-Fargeau", + "pageviews": 1508, + "fame_score": 8 + }, + { + "id": "saint-gratien", + "name": "Saint-Gratien", + "title": "Gare de Saint-Gratien", + "pageviews": 2070, + "fame_score": 25 + }, + { + "id": "saint-martin-d-etampes", + "name": "Saint-Martin d'Étampes", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "saint-maur-champigny", + "name": "Saint-Maur – Champigny", + "title": "Gare de Saint-Maur - Champigny", + "pageviews": 1656, + "fame_score": 12 + }, + { + "id": "saint-maur-creteil", + "name": "Saint-Maur Créteil", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "saint-michel-notre-dame", + "name": "Saint-Michel Notre-Dame", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "saint-michel-sur-orge", + "name": "Saint-Michel-sur-Orge", + "title": "Gare de Saint-Michel-sur-Orge", + "pageviews": 1897, + "fame_score": 21 + }, + { + "id": "saint-ouen", + "name": "Saint-Ouen", + "title": "Gare de Saint-Ouen", + "pageviews": 3551, + "fame_score": 57 + }, + { + "id": "saint-ouen-l-aumone", + "name": "Saint-Ouen-l'Aumône", + "title": "Gare de Saint-Ouen-l'Aumône", + "pageviews": 2445, + "fame_score": 31 + }, + { + "id": "saint-ouen-l-aumone-liesse", + "name": "Saint-Ouen-l'Aumône Liesse", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "saint-quentin-en-yvelines", + "name": "Saint-Quentin-en-Yvelines", + "title": "Gare de Saint-Quentin-en-Yvelines - Montigny-le-Bretonneux", + "pageviews": 6638, + "fame_score": 88 + }, + { + "id": "saint-remy-les-chevreuse", + "name": "Saint-Rémy-lès-Chevreuse", + "title": "Gare de Saint-Rémy-lès-Chevreuse", + "pageviews": 4096, + "fame_score": 67 + }, + { + "id": "sainte-genevieve-des-bois", + "name": "Sainte-Geneviève-des-Bois", + "title": "Gare de Sainte-Geneviève-des-Bois", + "pageviews": 2568, + "fame_score": 34 + }, + { + "id": "sartrouville", + "name": "Sartrouville", + "title": "Gare de Sartrouville", + "pageviews": 3824, + "fame_score": 61 + }, + { + "id": "savigny-le-temple-nandy", + "name": "Savigny-le-Temple - Nandy", + "title": "Gare de Savigny-le-Temple - Nandy", + "pageviews": 1878, + "fame_score": 19 + }, + { + "id": "savigny-sur-orge", + "name": "Savigny-sur-Orge", + "title": "Gare de Savigny-sur-Orge", + "pageviews": 3087, + "fame_score": 47 + }, + { + "id": "sceaux", + "name": "Sceaux", + "title": "Gare de Sceaux", + "pageviews": 2193, + "fame_score": 28 + }, + { + "id": "sermaise", + "name": "Sermaise", + "title": "Gare de Sermaise", + "pageviews": 1032, + "fame_score": 1 + }, + { + "id": "sevran-beaudottes", + "name": "Sevran - Beaudottes", + "title": "Gare de Sevran - Beaudottes", + "pageviews": 3916, + "fame_score": 64 + }, + { + "id": "sevran-livry", + "name": "Sevran - Livry", + "title": "Gare de Sevran - Livry", + "pageviews": 3198, + "fame_score": 50 + }, + { + "id": "stade-de-france-saint-denis", + "name": "Stade de France - Saint-Denis", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "sucy-bonneuil", + "name": "Sucy - Bonneuil", + "title": "Gare de Sucy - Bonneuil", + "pageviews": 3860, + "fame_score": 62 + }, + { + "id": "survilliers-fosses", + "name": "Survilliers - Fosses", + "title": "Gare de Survilliers - Fosses", + "pageviews": 4376, + "fame_score": 71 + }, + { + "id": "torcy", + "name": "Torcy", + "title": "Gare de Torcy", + "pageviews": 6142, + "fame_score": 84 + }, + { + "id": "val-d-europe", + "name": "Val d'Europe", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "val-de-fontenay", + "name": "Val de Fontenay", + "title": "Gare du Val de Fontenay", + "pageviews": 11330, + "fame_score": 92 + }, + { + "id": "val-de-fontenay-rer-a", + "name": "Val-de-Fontenay (RER A)", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "versailles-chantiers", + "name": "Versailles-Chantiers", + "title": "Gare de Versailles-Chantiers", + "pageviews": 18379, + "fame_score": 95 + }, + { + "id": "versailles-chateau-rive-gauche", + "name": "Versailles Château Rive Gauche", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "vert-galant", + "name": "Vert Galant", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "vigneux-sur-seine", + "name": "Vigneux-sur-Seine", + "title": "Gare de Vigneux-sur-Seine", + "pageviews": 2498, + "fame_score": 33 + }, + { + "id": "villabe", + "name": "Villabé", + "title": "Gare de Villabé", + "pageviews": 1223, + "fame_score": 3 + }, + { + "id": "villeneuve-le-roi", + "name": "Villeneuve-le-Roi", + "title": "Gare de Villeneuve-le-Roi", + "pageviews": 1992, + "fame_score": 24 + }, + { + "id": "villeneuve-saint-georges", + "name": "Villeneuve-Saint-Georges", + "title": "Gare de Villeneuve-Saint-Georges", + "pageviews": 5043, + "fame_score": 78 + }, + { + "id": "villeneuve-triage", + "name": "Villeneuve Triage", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "villeparisis-mitry-le-neuf", + "name": "Villeparisis - Mitry le Neuf", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "villepinte-parc-du-sausset", + "name": "Villepinte - Parc du Sausset", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "villiers-le-bel-gonesse-arnouville", + "name": "Villiers-le-Bel - Gonesse - Arnouville", + "title": "Gare de Villiers-le-Bel - Gonesse - Arnouville", + "pageviews": 4220, + "fame_score": 69 + }, + { + "id": "villiers-sur-marne-le-plessis-trevise", + "name": "Villiers-sur-Marne - Le Plessis-Trévise", + "title": "Gare de Villiers-sur-Marne - Le Plessis-Trévise", + "pageviews": 4142, + "fame_score": 67 + }, + { + "id": "vincennes", + "name": "Vincennes", + "title": "Gare de Vincennes", + "pageviews": 5208, + "fame_score": 80 + }, + { + "id": "viroflay-rive-gauche", + "name": "Viroflay Rive Gauche", + "title": null, + "pageviews": 0, + "fame_score": null + }, + { + "id": "viry-chatillon", + "name": "Viry-Châtillon", + "title": "Gare de Viry-Châtillon", + "pageviews": 1814, + "fame_score": 17 + }, + { + "id": "vitry-sur-seine", + "name": "Vitry-sur-Seine", + "title": "Gare de Vitry-sur-Seine", + "pageviews": 3003, + "fame_score": 45 + }, + { + "id": "vosves", + "name": "Vosves", + "title": "Gare de Vosves", + "pageviews": 2160, + "fame_score": 27 + }, + { + "id": "yerres", + "name": "Yerres", + "title": null, + "pageviews": 0, + "fame_score": null + } + ] +} \ No newline at end of file From d72101d1970ede935ad61e34a5b4ca938cf2ef1b Mon Sep 17 00:00:00 2001 From: calixteair Date: Wed, 13 May 2026 23:05:49 +0200 Subject: [PATCH 4/5] feat(server,web): register rer domain + i18n labels MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit server: - main.rs declares rer in active_domains so /api/domains lists it and the start_game / solo / duel endpoints accept domain='rer'. The Dockerfile already COPYs domains/* into the image; the worker auto-discovers any subdirectory of domains/, so once this PR ships the next daily run produces a rer grid automatically. - paris-metro version field bumped 0.3.0 → 0.4.0 to match the fame score patch from #57, and 'duel' added to its available_modes (was missing since #55 made duels free). web: - grid_domain_rer i18n key in fr + en. The Grid component reads the active domain label from this key; the rest of the UI is domain-agnostic, so no other change is needed. A domain picker on the home page isn't part of this PR — the URL still hardcodes paris-metro on /. Multi-domain selection will land as a follow-up once we have at least two playable domains in prod. --- server/src/main.rs | 15 +++++++++++++-- web/messages/en.json | 1 + web/messages/fr.json | 1 + 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/server/src/main.rs b/server/src/main.rs index 6d81175..d16d8a9 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -39,9 +39,20 @@ async fn main() -> Result<()> { id: "paris-metro".into(), name_fr: "Métro de Paris".into(), name_en: "Paris Metro".into(), - version: "0.3.0".into(), + version: "0.4.0".into(), description: None, - available_modes: vec!["daily".into(), "solo".into()], + available_modes: vec!["daily".into(), "solo".into(), "duel".into()], + }, + ); + active_domains.insert( + "rer".to_string(), + DomainSummary { + id: "rer".into(), + name_fr: "RER d'Île-de-France".into(), + name_en: "Île-de-France RER".into(), + version: "0.2.0".into(), + description: None, + available_modes: vec!["daily".into(), "solo".into(), "duel".into()], }, ); let mut state = AppState::new(cfg.clone()).with_domains(active_domains); diff --git a/web/messages/en.json b/web/messages/en.json index bd578b5..fcb8602 100644 --- a/web/messages/en.json +++ b/web/messages/en.json @@ -5,6 +5,7 @@ "site_lede": "One grid of knowledge, every day. Three rows, three columns, nine cells to fill.", "grid_today": "Today's grid", "grid_domain_paris_metro": "Paris Metro", + "grid_domain_rer": "Île-de-France RER", "score": "Score", "errors": "Mistakes", "abandon_button": "Give up and see the solutions", diff --git a/web/messages/fr.json b/web/messages/fr.json index 1c54029..a058220 100644 --- a/web/messages/fr.json +++ b/web/messages/fr.json @@ -5,6 +5,7 @@ "site_lede": "Une grille de connaissance, chaque jour. Trois lignes, trois colonnes, neuf cases à remplir.", "grid_today": "Grille du jour", "grid_domain_paris_metro": "Métro de Paris", + "grid_domain_rer": "RER d'Île-de-France", "score": "Score", "errors": "Erreurs", "abandon_button": "Abandonner et voir les solutions", From 97a43e50ed7c0e4586b4304b5714ff325537f068 Mon Sep 17 00:00:00 2001 From: calixteair Date: Wed, 13 May 2026 23:06:15 +0200 Subject: [PATCH 5/5] chore: generalise tmp/ gitignore to every domain pack domains/paris-metro/tmp/ was the original local-only scratch dir for ingest audit reports. The rer domain reuses the same convention so the ignore rule should match any domain. Also drops the accidentally committed domains/rer/tmp/fame_score_report.json (the audit output, not a build artefact). --- .gitignore | 2 +- domains/rer/tmp/fame_score_report.json | 1619 ------------------------ 2 files changed, 1 insertion(+), 1620 deletions(-) delete mode 100644 domains/rer/tmp/fame_score_report.json diff --git a/.gitignore b/.gitignore index 228d84a..8dbec7f 100644 --- a/.gitignore +++ b/.gitignore @@ -64,7 +64,7 @@ www/ # Screenshots de référence (gardés en local, pas commités) brave_screenshot_*.png google -domains/paris-metro/tmp/ +domains/*/tmp/ domains/paris-metro/scripts/node_modules/ # Python ingest scripts diff --git a/domains/rer/tmp/fame_score_report.json b/domains/rer/tmp/fame_score_report.json deleted file mode 100644 index 4ee998d..0000000 --- a/domains/rer/tmp/fame_score_report.json +++ /dev/null @@ -1,1619 +0,0 @@ -{ - "generated_at": "2026-05-13T21:02:39Z", - "window_start": "20250401", - "window_end": "20260430", - "matched": 136, - "total": 230, - "audit": [ - { - "id": "ablon", - "name": "Ablon", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "acheres-grand-cormier", - "name": "Achères Grand Cormier", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "acheres-ville", - "name": "Achères - Ville", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "aeroport-charles-de-gaulle-1", - "name": "Aéroport Charles de Gaulle 1", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "antony", - "name": "Antony", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "arcueil-cachan", - "name": "Arcueil - Cachan", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "arpajon", - "name": "Arpajon", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "athis-mons", - "name": "Athis-Mons", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "auber", - "name": "Auber", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "aulnay-sous-bois", - "name": "Aulnay-sous-Bois", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "avenue-du-president-kennedy", - "name": "Avenue du Président Kennedy", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "avenue-foch", - "name": "Avenue Foch", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "avenue-henri-martin", - "name": "Avenue Henri Martin", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "bagneux", - "name": "Bagneux", - "title": "Gare de Bagneux", - "pageviews": 3366, - "fame_score": 55 - }, - { - "id": "ballancourt", - "name": "Ballancourt", - "title": "Gare de Ballancourt", - "pageviews": 1452, - "fame_score": 7 - }, - { - "id": "bibliotheque-francois-mitterrand", - "name": "Bibliothèque François Mitterrand", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "boigneville", - "name": "Boigneville", - "title": "Gare de Boigneville", - "pageviews": 1261, - "fame_score": 4 - }, - { - "id": "boissise-le-roi", - "name": "Boissise-le-Roi", - "title": "Gare de Boissise-le-Roi", - "pageviews": 1142, - "fame_score": 3 - }, - { - "id": "bondy", - "name": "Bondy", - "title": "Gare de Bondy", - "pageviews": 3690, - "fame_score": 58 - }, - { - "id": "boulainvilliers", - "name": "Boulainvilliers", - "title": "Gare de Boulainvilliers", - "pageviews": 4828, - "fame_score": 76 - }, - { - "id": "bouray", - "name": "Bouray", - "title": "Gare de Bouray", - "pageviews": 1865, - "fame_score": 19 - }, - { - "id": "bourg-la-reine", - "name": "Bourg-la-Reine", - "title": "Gare de Bourg-la-Reine", - "pageviews": 3234, - "fame_score": 51 - }, - { - "id": "boussy-saint-antoine", - "name": "Boussy Saint-Antoine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "boutigny", - "name": "Boutigny", - "title": "Gare de Boutigny", - "pageviews": 1023, - "fame_score": 0 - }, - { - "id": "bretigny", - "name": "Brétigny", - "title": "Gare de Brétigny", - "pageviews": 5218, - "fame_score": 81 - }, - { - "id": "breuillet-bruyeres-le-chatel", - "name": "Breuillet - Bruyères-le-Châtel", - "title": "Gare de Breuillet - Bruyères-le-Châtel", - "pageviews": 1545, - "fame_score": 9 - }, - { - "id": "breuillet-village", - "name": "Breuillet - Village", - "title": "Gare de Breuillet-Village", - "pageviews": 1583, - "fame_score": 11 - }, - { - "id": "brunoy", - "name": "Brunoy", - "title": "Gare de Brunoy", - "pageviews": 2210, - "fame_score": 28 - }, - { - "id": "bry-sur-marne", - "name": "Bry-sur-Marne", - "title": "Gare de Bry-sur-Marne (RATP)", - "pageviews": 2936, - "fame_score": 43 - }, - { - "id": "buno-gironville", - "name": "Buno - Gironville", - "title": "Gare de Buno - Gironville", - "pageviews": 1041, - "fame_score": 2 - }, - { - "id": "bures-sur-yvette", - "name": "Bures-sur-Yvette", - "title": "Gare de Bures-sur-Yvette", - "pageviews": 1897, - "fame_score": 21 - }, - { - "id": "bussy-saint-georges", - "name": "Bussy-Saint-Georges", - "title": "Gare de Bussy-Saint-Georges", - "pageviews": 3499, - "fame_score": 56 - }, - { - "id": "cergy-prefecture", - "name": "Cergy Préfecture", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "cergy-saint-christophe", - "name": "Cergy - Saint-Christophe", - "title": "Gare de Cergy-Saint-Christophe", - "pageviews": 5399, - "fame_score": 81 - }, - { - "id": "cernay", - "name": "Cernay", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "cesson", - "name": "Cesson", - "title": "Gare de Cesson", - "pageviews": 1883, - "fame_score": 20 - }, - { - "id": "chamarande", - "name": "Chamarande", - "title": "Gare de Chamarande", - "pageviews": 1808, - "fame_score": 17 - }, - { - "id": "champ-de-mars-tour-eiffel", - "name": "Champ de Mars - Tour Eiffel", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "chantilly-gouvieux", - "name": "Chantilly – Gouvieux", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "charles-de-gaulle-etoile-rer", - "name": "Charles de Gaulle — Étoile (RER)", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "chatelet-les-halles", - "name": "Châtelet - Les Halles", - "title": "Gare de Châtelet - Les Halles", - "pageviews": 39607, - "fame_score": 97 - }, - { - "id": "chatou-croissy", - "name": "Chatou - Croissy", - "title": "Gare de Chatou - Croissy", - "pageviews": 3011, - "fame_score": 46 - }, - { - "id": "chaville-velizy", - "name": "Chaville-Vélizy", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "chemin-d-antony", - "name": "Chemin d'Antony", - "title": "Gare de Chemin d'Antony", - "pageviews": 1965, - "fame_score": 22 - }, - { - "id": "choisy-le-roi", - "name": "Choisy-le-Roi", - "title": "Gare de Choisy-le-Roi", - "pageviews": 4076, - "fame_score": 66 - }, - { - "id": "cite-universitaire", - "name": "Cité Universitaire", - "title": "Gare de Cité universitaire", - "pageviews": 4251, - "fame_score": 70 - }, - { - "id": "combs-la-ville-quincy", - "name": "Combs-la-Ville - Quincy", - "title": "Gare de Combs-la-Ville - Quincy", - "pageviews": 2936, - "fame_score": 43 - }, - { - "id": "conflans-fin-d-oise", - "name": "Conflans-Fin-d'Oise", - "title": "Gare de Conflans-Fin-d'Oise", - "pageviews": 5112, - "fame_score": 79 - }, - { - "id": "corbeil-essonnes", - "name": "Corbeil-Essonnes", - "title": "Gare de Corbeil-Essonnes", - "pageviews": 6359, - "fame_score": 86 - }, - { - "id": "courcelle-sur-yvette", - "name": "Courcelle-sur-Yvette", - "title": "Gare de Courcelle-sur-Yvette", - "pageviews": 2596, - "fame_score": 36 - }, - { - "id": "creteil-pompadour", - "name": "Créteil Pompadour", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "denfert-rochereau", - "name": "Denfert-Rochereau", - "title": "Gare de Denfert-Rochereau", - "pageviews": 6199, - "fame_score": 85 - }, - { - "id": "dourdan", - "name": "Dourdan", - "title": "Gare de Dourdan", - "pageviews": 2958, - "fame_score": 44 - }, - { - "id": "dourdan-la-foret", - "name": "Dourdan - La Forêt", - "title": "Gare de Dourdan - La Forêt", - "pageviews": 3041, - "fame_score": 47 - }, - { - "id": "drancy", - "name": "Drancy", - "title": "Gare de Drancy", - "pageviews": 3111, - "fame_score": 48 - }, - { - "id": "egly", - "name": "Égly", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "emerainville-pontault-combault", - "name": "Émerainville Pontault-Combault", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "epinay-sur-orge", - "name": "Épinay-sur-Orge", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "epinay-sur-seine", - "name": "Épinay-sur-Seine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "ermont-eaubonne", - "name": "Ermont - Eaubonne", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "essonnes-robinson", - "name": "Essonnes Robinson", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "etampes", - "name": "Étampes", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "etrechy", - "name": "Étréchy", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "evry-courcouronnes-centre", - "name": "Évry Courcouronnes-Centre", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "evry-val-de-seine", - "name": "Évry Val de Seine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "fontaine-michalon", - "name": "Fontaine-Michalon", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "fontenay-aux-roses", - "name": "Fontenay-aux-Roses", - "title": "Gare de Fontenay-aux-Roses", - "pageviews": 2020, - "fame_score": 25 - }, - { - "id": "fontenay-sous-bois", - "name": "Fontenay-sous-Bois", - "title": "Gare de Fontenay-sous-Bois", - "pageviews": 2613, - "fame_score": 37 - }, - { - "id": "franconville-le-plessis-bouchard", - "name": "Franconville – Le Plessis-Bouchard", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "gagny", - "name": "Gagny", - "title": "Gare de Gagny", - "pageviews": 3364, - "fame_score": 54 - }, - { - "id": "gare-de-lyon", - "name": "Gare de Lyon", - "title": "Paris-Gare-de-Lyon", - "pageviews": 68996, - "fame_score": 99 - }, - { - "id": "garges-sarcelles", - "name": "Garges - Sarcelles", - "title": "Gare de Garges - Sarcelles", - "pageviews": 5483, - "fame_score": 83 - }, - { - "id": "gennevilliers", - "name": "Gennevilliers", - "title": "Gare de Gennevilliers", - "pageviews": 2839, - "fame_score": 40 - }, - { - "id": "gentilly", - "name": "Gentilly", - "title": "Gare de Gentilly", - "pageviews": 2428, - "fame_score": 31 - }, - { - "id": "gif-sur-yvette", - "name": "Gif-sur-Yvette", - "title": "Gare de Gif-sur-Yvette", - "pageviews": 1792, - "fame_score": 16 - }, - { - "id": "goussainville", - "name": "Goussainville", - "title": "Gare de Goussainville", - "pageviews": 2863, - "fame_score": 41 - }, - { - "id": "grand-bourg", - "name": "Grand Bourg", - "title": "Gare de Grand Bourg", - "pageviews": 1738, - "fame_score": 14 - }, - { - "id": "gretz-armainvilliers", - "name": "Gretz-Armainvilliers", - "title": "Gare de Gretz-Armainvilliers", - "pageviews": 2574, - "fame_score": 35 - }, - { - "id": "grigny-centre", - "name": "Grigny-Centre", - "title": "Gare de Grigny-Centre", - "pageviews": 3264, - "fame_score": 52 - }, - { - "id": "haussmann-saint-lazare", - "name": "Haussmann - Saint-Lazare", - "title": "Gare d'Haussmann - Saint-Lazare", - "pageviews": 9026, - "fame_score": 91 - }, - { - "id": "houilles-carrieres-sur-seine", - "name": "Houilles Carrières-sur-Seine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "issy", - "name": "Issy", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "issy-val-de-seine", - "name": "Issy Val de Seine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "ivry-sur-seine", - "name": "Ivry-sur-Seine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "javel", - "name": "Javel", - "title": "Gare de Javel", - "pageviews": 4249, - "fame_score": 69 - }, - { - "id": "joinville-le-pont", - "name": "Joinville-le-Pont", - "title": "Gare de Joinville-le-Pont", - "pageviews": 3156, - "fame_score": 50 - }, - { - "id": "juvisy-sur-orge", - "name": "Juvisy-sur-Orge", - "title": "Gare de Juvisy", - "pageviews": 11351, - "fame_score": 93 - }, - { - "id": "la-borne-blanche", - "name": "La Borne Blanche", - "title": "Gare de La Borne Blanche", - "pageviews": 2879, - "fame_score": 42 - }, - { - "id": "la-courneuve-aubervilliers", - "name": "La Courneuve - Aubervilliers", - "title": "Gare de La Courneuve - Aubervilliers", - "pageviews": 4466, - "fame_score": 72 - }, - { - "id": "la-croix-de-berny", - "name": "La Croix de Berny", - "title": "Gare de La Croix de Berny", - "pageviews": 6465, - "fame_score": 87 - }, - { - "id": "la-defense-grande-arche", - "name": "La Défense - Grande Arche", - "title": "Gare de la Défense", - "pageviews": 14485, - "fame_score": 94 - }, - { - "id": "la-ferte-alais", - "name": "La Ferté-Alais", - "title": "Gare de La Ferté-Alais", - "pageviews": 1778, - "fame_score": 15 - }, - { - "id": "la-hacquiniere", - "name": "La Hacquinière", - "title": "Gare de La Hacquinière", - "pageviews": 1977, - "fame_score": 23 - }, - { - "id": "la-norville-saint-germain-les-arpajon", - "name": "La Norville - Saint-Germain-lès-Arpajon", - "title": "Gare de La Norville - Saint-Germain-lès-Arpajon", - "pageviews": 1736, - "fame_score": 13 - }, - { - "id": "la-plaine-stade-de-france", - "name": "La Plaine Stade de France", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "la-varenne-chennevieres", - "name": "La Varenne - Chennevières", - "title": "Gare de La Varenne - Chennevières", - "pageviews": 4784, - "fame_score": 75 - }, - { - "id": "laplace", - "name": "Laplace", - "title": "Gare de Laplace", - "pageviews": 3931, - "fame_score": 64 - }, - { - "id": "lardy", - "name": "Lardy", - "title": "Gare de Lardy", - "pageviews": 1368, - "fame_score": 6 - }, - { - "id": "le-blanc-mesnil", - "name": "Le Blanc-Mesnil", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-bourget", - "name": "Le Bourget", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-bras-de-fer", - "name": "Le Bras de Fer", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-chenay-gagny", - "name": "Le Chénay Gagny", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-coudray-montceaux", - "name": "Le Coudray - Montceaux", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-guichet", - "name": "Le Guichet", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-mee", - "name": "Le Mée", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-parc-de-saint-maur", - "name": "Le Parc de Saint-Maur", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-plessis-chenet", - "name": "Le Plessis-Chenet", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-raincy-villemomble-montfermeil", - "name": "Le Raincy Villemomble Montfermeil", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-vert-de-maisons", - "name": "Le Vert de Maisons", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-vesinet-centre", - "name": "Le Vésinet Centre", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "le-vesinet-le-pecq", - "name": "Le Vésinet - Le Pecq", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-ardoines", - "name": "Les Ardoines", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-baconnets", - "name": "Les Baconnets", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-boullereaux-champigny", - "name": "Les Boullereaux - Champigny", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-gresillons", - "name": "Les Grésillons", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-noues", - "name": "Les Noues", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-saules", - "name": "Les Saules", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "les-yvris-noisy-le-grand", - "name": "Les Yvris Noisy-le-Grand", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "lieusaint-moissy", - "name": "Lieusaint - Moissy", - "title": "Gare de Lieusaint - Moissy", - "pageviews": 3823, - "fame_score": 60 - }, - { - "id": "lognes", - "name": "Lognes", - "title": "Gare de Lognes", - "pageviews": 2715, - "fame_score": 38 - }, - { - "id": "louvres", - "name": "Louvres", - "title": "Gare de Louvres", - "pageviews": 1818, - "fame_score": 18 - }, - { - "id": "lozere", - "name": "Lozère", - "title": "Gare de Lozère", - "pageviews": 3354, - "fame_score": 53 - }, - { - "id": "luxembourg", - "name": "Luxembourg", - "title": "Gare du Luxembourg", - "pageviews": 6334, - "fame_score": 86 - }, - { - "id": "magenta", - "name": "Magenta", - "title": "Gare de Magenta", - "pageviews": 12959, - "fame_score": 94 - }, - { - "id": "maisons-alfort-alfortville", - "name": "Maisons-Alfort - Alfortville", - "title": "Gare de Maisons-Alfort - Alfortville", - "pageviews": 3836, - "fame_score": 61 - }, - { - "id": "maisons-laffitte", - "name": "Maisons-Laffitte", - "title": "Gare de Maisons-Laffitte", - "pageviews": 4147, - "fame_score": 68 - }, - { - "id": "maisse", - "name": "Maisse", - "title": "Gare de Maisse", - "pageviews": 1278, - "fame_score": 5 - }, - { - "id": "marolles-en-hurepoix", - "name": "Marolles-en-Hurepoix", - "title": "Gare de Marolles-en-Hurepoix", - "pageviews": 1575, - "fame_score": 10 - }, - { - "id": "massy-palaiseau", - "name": "Massy-Palaiseau", - "title": "Gare de Massy - Palaiseau", - "pageviews": 21272, - "fame_score": 96 - }, - { - "id": "massy-verrieres", - "name": "Massy - Verrières", - "title": "Gare de Massy - Verrières", - "pageviews": 3302, - "fame_score": 53 - }, - { - "id": "mennecy", - "name": "Mennecy", - "title": "Gare de Mennecy", - "pageviews": 1516, - "fame_score": 8 - }, - { - "id": "meudon-val-fleury", - "name": "Meudon Val Fleury", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "mitry-claye", - "name": "Mitry - Claye", - "title": "Gare de Mitry - Claye", - "pageviews": 5567, - "fame_score": 83 - }, - { - "id": "montgeron-crosne", - "name": "Montgeron - Crosne", - "title": "Gare de Montgeron - Crosne", - "pageviews": 2553, - "fame_score": 33 - }, - { - "id": "montigny-beauchamp", - "name": "Montigny-Beauchamp", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "moulin-galant", - "name": "Moulin Galant", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "musee-d-orsay", - "name": "Musée d'Orsay", - "title": "Musée d'Orsay", - "pageviews": 153660, - "fame_score": 100 - }, - { - "id": "nanterre-la-folie", - "name": "Nanterre La Folie", - "title": "Nanterre La Folie (métro de Paris)", - "pageviews": 10087, - "fame_score": 92 - }, - { - "id": "nanterre-prefecture", - "name": "Nanterre-Préfecture", - "title": "Gare de Nanterre-Préfecture", - "pageviews": 4796, - "fame_score": 75 - }, - { - "id": "nanterre-universite", - "name": "Nanterre - Université", - "title": "Gare de Nanterre-Université", - "pageviews": 4480, - "fame_score": 72 - }, - { - "id": "nanterre-ville", - "name": "Nanterre Ville", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "nation", - "name": "Nation", - "title": "Gare de Nation", - "pageviews": 4730, - "fame_score": 74 - }, - { - "id": "neuilly-plaisance", - "name": "Neuilly-Plaisance", - "title": "Gare de Neuilly-Plaisance", - "pageviews": 3940, - "fame_score": 65 - }, - { - "id": "neuilly-porte-maillot", - "name": "Neuilly - Porte Maillot", - "title": "Gare de Neuilly - Porte Maillot", - "pageviews": 7913, - "fame_score": 90 - }, - { - "id": "neuville-universite", - "name": "Neuville Université", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "nogent-le-perreux", - "name": "Nogent - Le Perreux", - "title": "Gare de Nogent - Le Perreux", - "pageviews": 3637, - "fame_score": 58 - }, - { - "id": "nogent-sur-marne", - "name": "Nogent-sur-Marne", - "title": "Gare de Nogent-sur-Marne", - "pageviews": 2906, - "fame_score": 42 - }, - { - "id": "noisiel", - "name": "Noisiel", - "title": "Gare de Noisiel", - "pageviews": 3124, - "fame_score": 49 - }, - { - "id": "noisy-champs", - "name": "Noisy-Champs", - "title": "Gare de Noisy - Champs", - "pageviews": 7534, - "fame_score": 89 - }, - { - "id": "noisy-le-grand-mont-d-est", - "name": "Noisy-le-Grand - Mont d’Est", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "noisy-le-sec", - "name": "Noisy-le-Sec", - "title": "Gare de Noisy-le-Sec", - "pageviews": 4955, - "fame_score": 77 - }, - { - "id": "orangis-bois-de-l-epine", - "name": "Orangis - Bois de l'Épine", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "orly-ville", - "name": "Orly Ville", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "orry-la-ville-coye", - "name": "Orry-la-Ville - Coye", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "orry-la-ville-coye-la-foret", - "name": "Orry-la-Ville - Coye-la-Forêt", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "orsay-ville", - "name": "Orsay-Ville", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "ozoir-la-ferriere", - "name": "Ozoir-la-Ferrière", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "palaiseau", - "name": "Palaiseau", - "title": "Gare de Palaiseau", - "pageviews": 2283, - "fame_score": 30 - }, - { - "id": "palaiseau-villebon", - "name": "Palaiseau - Villebon", - "title": "Gare de Palaiseau - Villebon", - "pageviews": 2082, - "fame_score": 26 - }, - { - "id": "pantin", - "name": "Pantin", - "title": "Gare de Pantin", - "pageviews": 3376, - "fame_score": 56 - }, - { - "id": "parc-de-sceaux", - "name": "Parc de Sceaux", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "parc-des-expositions", - "name": "Parc des Expositions", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "paris-austerlitz", - "name": "Paris Austerlitz", - "title": "Gare de Paris-Austerlitz", - "pageviews": 52850, - "fame_score": 97 - }, - { - "id": "paris-gare-du-nord", - "name": "Paris Gare du Nord", - "title": "Gare de Paris-Nord", - "pageviews": 68935, - "fame_score": 98 - }, - { - "id": "pereire-levallois", - "name": "Pereire - Levallois", - "title": "Gare de Pereire - Levallois", - "pageviews": 3881, - "fame_score": 63 - }, - { - "id": "pierrefitte-stains", - "name": "Pierrefitte-Stains", - "title": "Gare de Pierrefitte - Stains", - "pageviews": 5433, - "fame_score": 82 - }, - { - "id": "pierrelaye", - "name": "Pierrelaye", - "title": "Gare de Pierrelaye", - "pageviews": 1610, - "fame_score": 11 - }, - { - "id": "pont-de-l-alma", - "name": "Pont de l'Alma", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "pont-de-rungis-aeroport-d-orly", - "name": "Pont de Rungis Aéroport d'Orly", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "pont-du-garigliano-hopital-europeen-georges-pompidou", - "name": "Pont du Garigliano - Hôpital Européen Georges-Pompidou", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "ponthierry-pringy", - "name": "Ponthierry Pringy", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "porchefontaine", - "name": "Porchefontaine", - "title": "Gare de Porchefontaine", - "pageviews": 2448, - "fame_score": 32 - }, - { - "id": "port-royal", - "name": "Port Royal", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "porte-de-clichy", - "name": "Porte de Clichy", - "title": "Gare de la Porte de Clichy", - "pageviews": 2611, - "fame_score": 36 - }, - { - "id": "ris-orangis", - "name": "Ris-Orangis", - "title": "Gare de Ris-Orangis", - "pageviews": 1744, - "fame_score": 14 - }, - { - "id": "robinson", - "name": "Robinson", - "title": "Gare de Robinson", - "pageviews": 5054, - "fame_score": 78 - }, - { - "id": "roissy-en-brie", - "name": "Roissy-en-Brie", - "title": "Gare de Roissy-en-Brie", - "pageviews": 2253, - "fame_score": 29 - }, - { - "id": "rosa-parks", - "name": "Rosa Parks", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "rosny-bois-perrier", - "name": "Rosny - Bois-Perrier", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "rosny-sous-bois", - "name": "Rosny-sous-Bois", - "title": "Gare de Rosny-sous-Bois", - "pageviews": 2725, - "fame_score": 39 - }, - { - "id": "rueil-malmaison", - "name": "Rueil-Malmaison", - "title": "Gare de Rueil-Malmaison", - "pageviews": 3755, - "fame_score": 59 - }, - { - "id": "rungis-la-fraternelle", - "name": "Rungis - La Fraternelle", - "title": "Gare de Rungis - La Fraternelle", - "pageviews": 2798, - "fame_score": 39 - }, - { - "id": "saint-cheron", - "name": "Saint-Chéron", - "title": "Gare de Saint-Chéron", - "pageviews": 1381, - "fame_score": 6 - }, - { - "id": "saint-cyr", - "name": "Saint-Cyr", - "title": "Gare de Saint-Cyr", - "pageviews": 4613, - "fame_score": 73 - }, - { - "id": "saint-denis-l-ile-saint-denis", - "name": "Saint-Denis - L'Île-Saint-Denis", - "title": "Gare de Saint-Denis", - "pageviews": 7471, - "fame_score": 89 - }, - { - "id": "saint-fargeau", - "name": "Saint-Fargeau", - "title": "Gare de Saint-Fargeau", - "pageviews": 1508, - "fame_score": 8 - }, - { - "id": "saint-gratien", - "name": "Saint-Gratien", - "title": "Gare de Saint-Gratien", - "pageviews": 2070, - "fame_score": 25 - }, - { - "id": "saint-martin-d-etampes", - "name": "Saint-Martin d'Étampes", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "saint-maur-champigny", - "name": "Saint-Maur – Champigny", - "title": "Gare de Saint-Maur - Champigny", - "pageviews": 1656, - "fame_score": 12 - }, - { - "id": "saint-maur-creteil", - "name": "Saint-Maur Créteil", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "saint-michel-notre-dame", - "name": "Saint-Michel Notre-Dame", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "saint-michel-sur-orge", - "name": "Saint-Michel-sur-Orge", - "title": "Gare de Saint-Michel-sur-Orge", - "pageviews": 1897, - "fame_score": 21 - }, - { - "id": "saint-ouen", - "name": "Saint-Ouen", - "title": "Gare de Saint-Ouen", - "pageviews": 3551, - "fame_score": 57 - }, - { - "id": "saint-ouen-l-aumone", - "name": "Saint-Ouen-l'Aumône", - "title": "Gare de Saint-Ouen-l'Aumône", - "pageviews": 2445, - "fame_score": 31 - }, - { - "id": "saint-ouen-l-aumone-liesse", - "name": "Saint-Ouen-l'Aumône Liesse", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "saint-quentin-en-yvelines", - "name": "Saint-Quentin-en-Yvelines", - "title": "Gare de Saint-Quentin-en-Yvelines - Montigny-le-Bretonneux", - "pageviews": 6638, - "fame_score": 88 - }, - { - "id": "saint-remy-les-chevreuse", - "name": "Saint-Rémy-lès-Chevreuse", - "title": "Gare de Saint-Rémy-lès-Chevreuse", - "pageviews": 4096, - "fame_score": 67 - }, - { - "id": "sainte-genevieve-des-bois", - "name": "Sainte-Geneviève-des-Bois", - "title": "Gare de Sainte-Geneviève-des-Bois", - "pageviews": 2568, - "fame_score": 34 - }, - { - "id": "sartrouville", - "name": "Sartrouville", - "title": "Gare de Sartrouville", - "pageviews": 3824, - "fame_score": 61 - }, - { - "id": "savigny-le-temple-nandy", - "name": "Savigny-le-Temple - Nandy", - "title": "Gare de Savigny-le-Temple - Nandy", - "pageviews": 1878, - "fame_score": 19 - }, - { - "id": "savigny-sur-orge", - "name": "Savigny-sur-Orge", - "title": "Gare de Savigny-sur-Orge", - "pageviews": 3087, - "fame_score": 47 - }, - { - "id": "sceaux", - "name": "Sceaux", - "title": "Gare de Sceaux", - "pageviews": 2193, - "fame_score": 28 - }, - { - "id": "sermaise", - "name": "Sermaise", - "title": "Gare de Sermaise", - "pageviews": 1032, - "fame_score": 1 - }, - { - "id": "sevran-beaudottes", - "name": "Sevran - Beaudottes", - "title": "Gare de Sevran - Beaudottes", - "pageviews": 3916, - "fame_score": 64 - }, - { - "id": "sevran-livry", - "name": "Sevran - Livry", - "title": "Gare de Sevran - Livry", - "pageviews": 3198, - "fame_score": 50 - }, - { - "id": "stade-de-france-saint-denis", - "name": "Stade de France - Saint-Denis", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "sucy-bonneuil", - "name": "Sucy - Bonneuil", - "title": "Gare de Sucy - Bonneuil", - "pageviews": 3860, - "fame_score": 62 - }, - { - "id": "survilliers-fosses", - "name": "Survilliers - Fosses", - "title": "Gare de Survilliers - Fosses", - "pageviews": 4376, - "fame_score": 71 - }, - { - "id": "torcy", - "name": "Torcy", - "title": "Gare de Torcy", - "pageviews": 6142, - "fame_score": 84 - }, - { - "id": "val-d-europe", - "name": "Val d'Europe", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "val-de-fontenay", - "name": "Val de Fontenay", - "title": "Gare du Val de Fontenay", - "pageviews": 11330, - "fame_score": 92 - }, - { - "id": "val-de-fontenay-rer-a", - "name": "Val-de-Fontenay (RER A)", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "versailles-chantiers", - "name": "Versailles-Chantiers", - "title": "Gare de Versailles-Chantiers", - "pageviews": 18379, - "fame_score": 95 - }, - { - "id": "versailles-chateau-rive-gauche", - "name": "Versailles Château Rive Gauche", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "vert-galant", - "name": "Vert Galant", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "vigneux-sur-seine", - "name": "Vigneux-sur-Seine", - "title": "Gare de Vigneux-sur-Seine", - "pageviews": 2498, - "fame_score": 33 - }, - { - "id": "villabe", - "name": "Villabé", - "title": "Gare de Villabé", - "pageviews": 1223, - "fame_score": 3 - }, - { - "id": "villeneuve-le-roi", - "name": "Villeneuve-le-Roi", - "title": "Gare de Villeneuve-le-Roi", - "pageviews": 1992, - "fame_score": 24 - }, - { - "id": "villeneuve-saint-georges", - "name": "Villeneuve-Saint-Georges", - "title": "Gare de Villeneuve-Saint-Georges", - "pageviews": 5043, - "fame_score": 78 - }, - { - "id": "villeneuve-triage", - "name": "Villeneuve Triage", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "villeparisis-mitry-le-neuf", - "name": "Villeparisis - Mitry le Neuf", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "villepinte-parc-du-sausset", - "name": "Villepinte - Parc du Sausset", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "villiers-le-bel-gonesse-arnouville", - "name": "Villiers-le-Bel - Gonesse - Arnouville", - "title": "Gare de Villiers-le-Bel - Gonesse - Arnouville", - "pageviews": 4220, - "fame_score": 69 - }, - { - "id": "villiers-sur-marne-le-plessis-trevise", - "name": "Villiers-sur-Marne - Le Plessis-Trévise", - "title": "Gare de Villiers-sur-Marne - Le Plessis-Trévise", - "pageviews": 4142, - "fame_score": 67 - }, - { - "id": "vincennes", - "name": "Vincennes", - "title": "Gare de Vincennes", - "pageviews": 5208, - "fame_score": 80 - }, - { - "id": "viroflay-rive-gauche", - "name": "Viroflay Rive Gauche", - "title": null, - "pageviews": 0, - "fame_score": null - }, - { - "id": "viry-chatillon", - "name": "Viry-Châtillon", - "title": "Gare de Viry-Châtillon", - "pageviews": 1814, - "fame_score": 17 - }, - { - "id": "vitry-sur-seine", - "name": "Vitry-sur-Seine", - "title": "Gare de Vitry-sur-Seine", - "pageviews": 3003, - "fame_score": 45 - }, - { - "id": "vosves", - "name": "Vosves", - "title": "Gare de Vosves", - "pageviews": 2160, - "fame_score": 27 - }, - { - "id": "yerres", - "name": "Yerres", - "title": null, - "pageviews": 0, - "fame_score": null - } - ] -} \ No newline at end of file