diff --git a/data/datasets/aemet-cap-warnings.yaml b/data/datasets/aemet-cap-warnings.yaml new file mode 100644 index 0000000..8b1ceac --- /dev/null +++ b/data/datasets/aemet-cap-warnings.yaml @@ -0,0 +1,76 @@ +id: aemet-cap-warnings +name: AEMET Spain CAP Warnings +description: > + Official Spanish adverse-weather CAP warning Atom feed from AEMET for + inspecting alert IDs, updates, and affected regions. +theme: Environment & Hazards +url: https://www.aemet.es/es/rss_info/avisos/esp +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - Atom + - CAP +license: AEMET public information may be reused commercially or noncommercially with attribution and integrity conditions. +license_url: https://www.aemet.es/es/nota_legal +url_checks: + source_marker: CAP_AFAE_ATOM.xml + license_marker: fines comerciales y no comerciales +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Spain +temporal_coverage: current adverse-weather alerts +update_frequency: near real time +provider: Agencia Estatal de Meteorología +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + AEMET publishes adverse-weather warnings through an Atom index with CAP + details. Start with five current Atom entries, preserving IDs and update + times. The legal notice requires source attribution and forbids distorting + technical meaning; verify official area and validity before display. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read AEMET's CAP feed page and legal reuse conditions. + - Fetch the national Atom index and inspect at most five entries. + - Use linked CAP details for severity, affected area, and expiry. + python: + packages: + - requests + code: | + import xml.etree.ElementTree as ET + import requests + + response = requests.get( + "https://www.aemet.es/documentos_d/eltiempo/prediccion/avisos/rss/" + "CAP_AFAE_ATOM.xml", timeout=30, + ) + response.raise_for_status() + root = ET.fromstring(response.content) + atom = "{http://www.w3.org/2005/Atom}" + print(root.findtext(f"{atom}updated")) + for entry in root.findall(f"{atom}entry")[:5]: + print(entry.findtext(f"{atom}id"), entry.findtext(f"{atom}title")) + first_project: + title: Inspect Spanish CAP Publications + goal: Test the official warning index for a bounded Spanish alert card. + steps: + - Keep AEMET IDs, update timestamps, and CAP detail links. + - Check whether each CAP message is current and applies to the intended area. + - Explain why Atom publication alone cannot establish local warning coverage. diff --git a/data/datasets/arc-appalachian-counties.yaml b/data/datasets/arc-appalachian-counties.yaml new file mode 100644 index 0000000..0145d6d --- /dev/null +++ b/data/datasets/arc-appalachian-counties.yaml @@ -0,0 +1,61 @@ +id: arc-appalachian-counties +name: ARC Appalachian Counties +description: > + The Appalachian Regional Commission's maintained county membership list for building regional comparison and eligibility tools. +theme: Demographics & Development +url: https://www.arc.gov/appalachian-counties-served-by-arc/ +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [HTML, XLSX] +license: ARC-produced material is public domain; cite ARC and check linked third-party materials separately. +license_url: https://www.arc.gov/arc-web-and-privacy-policy/ +url_checks: + source_marker: Appalachian Counties Served by ARC + license_marker: Material provided on this website and produced by ARC is not copyrighted +domains: [Demographics] +data_types: [Tabular] +tasks: [Community Comparison] +difficulty: beginner +geography: [United States counties] +temporal_coverage: current ARC county membership; check the fiscal-year caveats +update_frequency: annual +provider: Appalachian Regional Commission +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + ARC maintains a public county list and notes fiscal-year exceptions, including Schoharie County for FY 2026. + Start with Alabama's 37 named counties. Names alone do not give a county FIPS code or prove grant eligibility. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the official county list and its fiscal-year notes. + - Fetch the Alabama row from the ARC-maintained page. + - Join to an authoritative FIPS table before a county-level analysis. + python: + packages: [requests] + code: | + import html + import re + import requests + + url = "https://www.arc.gov/appalachian-counties-served-by-arc/" + response = requests.get(url, timeout=20) + response.raise_for_status() + match = re.search( + r'Alabama.*?(.*?)

', + response.text, re.S, + ) + if not match: + raise ValueError("ARC Alabama county list not found") + names = html.unescape(re.sub(r"<[^>]+>", "", match.group(1))).strip() + print(names[:160]) + first_project: + title: Compare ARC County Membership + goal: Show which sampled counties are within the ARC region while retaining the fiscal-year caveat. + steps: + - Extract county names for one state from the ARC list. + - Resolve names to state-qualified county FIPS identifiers. + - Explain why ARC membership does not by itself establish current grant eligibility. diff --git a/data/datasets/arso-current-hydrology.yaml b/data/datasets/arso-current-hydrology.yaml new file mode 100644 index 0000000..b3431b1 --- /dev/null +++ b/data/datasets/arso-current-hydrology.yaml @@ -0,0 +1,67 @@ +id: arso-current-hydrology +name: ARSO Current Hydrology +description: Slovenian river and lake station measurements for building a local water-level conditions + display. +theme: Environment & Hazards +url: https://www.arso.gov.si/xml/vode/hidro_podatki_zadnji.xml +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.005 +formats: +- XML +license: ARSO permits public-information reuse for commercial and noncommercial analysis with source citation. +license_url: https://kazalci.arso.gov.si/en/content/legal-note +url_checks: + source_marker: Agencija RS za okolje + license_marker: reuse of public information for commercial or non-commercial purposes +domains: +- Water Resources +data_types: +- Time Series +tasks: +- Monitoring +difficulty: beginner +geography: +- Slovenia +temporal_coverage: current observations or notices +update_frequency: near real time +provider: Slovenian Environment Agency +source_type: government +last_verified: '2026-09-28' +getting_started: + overview: The official Slovenian Environment Agency feed supplies current public data. Start with two + current Slovenian stations; a provisional station level is not a flood warning or a destination-wide + measurement. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official data documentation and reuse terms. + - Fetch the small official feed and inspect two records. + - Preserve source timestamps and locations before mapping results. + python: + packages: + - requests + code: | + import requests + from xml.etree import ElementTree as ET + + url = "https://www.arso.gov.si/xml/vode/hidro_podatki_zadnji.xml" + response = requests.get(url, timeout=20) + response.raise_for_status() + root = ET.fromstring(response.content) + print("Prepared", root.findtext("datum_priprave")) + for station in root.findall("postaja")[:2]: + print(station.get("sifra"), station.findtext("reka"), + station.findtext("vodostaj"), station.findtext("datum_cet")) + first_project: + title: Inspect Dated Local Conditions + goal: Inspect two current Slovenian stations with source timestamps. + steps: + - Fetch the official source and retain its update time. + - Show two records with their station or notice identifiers. + - Explain why these records are context rather than complete hazard coverage. diff --git a/data/datasets/at-alert-public-warnings.yaml b/data/datasets/at-alert-public-warnings.yaml new file mode 100644 index 0000000..56b161a --- /dev/null +++ b/data/datasets/at-alert-public-warnings.yaml @@ -0,0 +1,76 @@ +id: at-alert-public-warnings +name: Austria AT-Alert Public Warnings +description: > + Official Austrian civil-emergency alerts from the AT-Alert public API for + reviewing affected polygons, alert levels, and validity intervals. +theme: Environment & Hazards +url: https://warnung.at-alert.at/de +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Official public warnings under Austrian free-works terms; credit the issuing authority. +license_url: https://www.rtr.at/rtr/service/opendata/OD_Nutzungsbedingungen.de.html +url_checks: + source_marker: Aktuelle Warnungen + license_marker: keinen urheberrechtlichen Schutz +domains: + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Austria +temporal_coverage: current official civil alerts +update_frequency: near real time +provider: Austrian Federal Ministry of the Interior +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + AT-Alert lists current public warnings through a JSON RPC POST endpoint. + Start with at most five production alert records; an empty response is + possible. Preserve official polygons, severity, and begin/end times, and + exclude tests before presenting any warning. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official AT-Alert site and public-data reuse terms. + - POST a five-record request for production alert levels. + - Check alert identifier, validity, level, and geography. + python: + packages: + - requests + code: | + import requests + + response = requests.post( + "https://warnung.at-alert.at/api/rpc/alert/list", + json={"json": {"limit": 5, "offset": 0, + "alertLevels": ["AlertLevel1", "AlertLevel2", + "AlertLevel3", "AlertLevel4"]}}, + timeout=30, + ) + response.raise_for_status() + payload = response.json()["json"] + print(f"{payload['totalCount']} production alerts in this response") + for alert in payload["alerts"][:5]: + print(alert.get("consolidation_identifier"), alert.get("alert_level"), + alert.get("begin_date"), alert.get("end_date")) + first_project: + title: Inspect Austrian Civil Alerts + goal: Check a bounded AT-Alert response for region-specific warning review. + steps: + - Keep issuer, alert ID, severity, validity, and official polygons. + - Reject test messages and handle updates and expirations. + - Explain why no returned records do not establish an all-clear. diff --git a/data/datasets/avalanche-report-bulletins.yaml b/data/datasets/avalanche-report-bulletins.yaml new file mode 100644 index 0000000..081cb4b --- /dev/null +++ b/data/datasets/avalanche-report-bulletins.yaml @@ -0,0 +1,55 @@ +id: avalanche-report-bulletins +name: Avalanche.report Regional Bulletins +description: > + European regional avalanche bulletins published as CAAML JSON for building a dated mountain hazard view. +theme: Environment & Hazards +url: https://static.avalanche.report/eaws_bulletins/2026-01-31/2026-01-31-AT-02.json +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: CC BY 4.0 for Avalanche.report data; credit the issuing regional warning service and Avalanche.report. +license_url: https://avalanche.report/more/open-data +url_checks: + source_marker: avalancheActivity + license_marker: All data provided, such as the avalanche report +domains: [Natural Hazards] +data_types: [Event Data, Geospatial] +tasks: [Monitoring, Mapping] +difficulty: beginner +geography: [Europe] +temporal_coverage: seasonal daily avalanche bulletins +update_frequency: daily +provider: Avalanche.report +source_type: nonprofit +last_verified: 2026-09-28 +getting_started: + overview: > + Avalanche.report publishes daily regional CAAML JSON partitions, including + AT-02 used by TravelCanary. Start with two archived January 2026 bulletin + records; an archived bulletin is not a current warning, and no bulletin + may be published outside its season. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the official open-data licence and CAAML access description. + - Fetch one dated regional bulletin file. + - Inspect two bulletin IDs and their validity periods. + python: + packages: [requests] + code: | + import requests + + url = "https://static.avalanche.report/eaws_bulletins/2026-01-31/2026-01-31-AT-02.json" + response = requests.get(url, timeout=20) + response.raise_for_status() + for bulletin in response.json()["bulletins"][:2]: + print(bulletin["bulletinID"], bulletin.get("validTime")) + first_project: + title: Review Regional Avalanche Bulletins + goal: Inspect two dated CAAML bulletins before mapping warning regions. + steps: + - Fetch one regional partition and retain its publication time. + - Match its region identifiers to the official EAWS geometry. + - Explain why an archived bulletin does not describe today's mountain hazard. diff --git a/data/datasets/awc-metar-stations.yaml b/data/datasets/awc-metar-stations.yaml new file mode 100644 index 0000000..85fca69 --- /dev/null +++ b/data/datasets/awc-metar-stations.yaml @@ -0,0 +1,80 @@ +id: awc-metar-stations +name: Aviation Weather Center METAR and Stations +description: > + Current airport METAR observations and station metadata from NOAA's Aviation + Weather Center for checking representative weather conditions near destinations. +theme: Environment & Hazards +url: https://aviationweather.gov/data/api/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON + - CSV +license: U.S. government public information; credit NOAA and check third-party notices. +license_url: https://sos.noaa.gov/copyright/ +url_checks: + source_marker: METARs are found + license_marker: digital media created by NOAA is not copyrighted +domains: + - Weather + - Transportation +data_types: + - Time Series + - Tabular +tasks: + - Monitoring + - Operational Planning +difficulty: beginner +geography: + - Global participating airports +temporal_coverage: current METARs and maintained station metadata +update_frequency: continuous +provider: NOAA Aviation Weather Center +source_type: government +last_verified: 2026-09-28 +access_profile: + friction: low + setup_minutes: 5 + registration_required: false + rate_limit_notes: AWC limits requests to 100 per minute; match the product cadence. +getting_started: + overview: > + AWC serves airport observations and station metadata through one documented + API family. Start with a single airport's METAR and station record. A + nearby airport is only a proxy for destination conditions, and this feed + does not provide official destination-wide weather warnings. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the AWC API request limits and NOAA public-information terms. + - Select one airport ICAO code and request its latest METAR. + - Query the same station ID and retain its coordinates with the reading. + python: + packages: + - requests + code: | + import requests + + headers = {"User-Agent": "TrilemmaDataCatalogExample/1.0 (https://data.trilemma.foundation)"} + base = "https://aviationweather.gov/api/data" + params = {"ids": "EIDW", "format": "json"} + metar = requests.get(f"{base}/metar", params=params, headers=headers, timeout=30) + metar.raise_for_status() + station = requests.get(f"{base}/stationinfo", params=params, headers=headers, timeout=30) + station.raise_for_status() + if metar.json() and station.json(): + print(metar.json()[0]["icaoId"], metar.json()[0]["reportTime"], + station.json()[0]["lat"], station.json()[0]["lon"]) + first_project: + title: Check One Airport Observation + goal: Assess whether one METAR and station coordinate can support local weather context. + steps: + - Keep station ID, coordinates, report time, and observed units. + - Compare the reading age with the intended display freshness. + - Explain why airport conditions cannot prove destination-wide safety. diff --git a/data/datasets/bc-unverified-hourly-pm25.yaml b/data/datasets/bc-unverified-hourly-pm25.yaml new file mode 100644 index 0000000..6456558 --- /dev/null +++ b/data/datasets/bc-unverified-hourly-pm25.yaml @@ -0,0 +1,74 @@ +id: bc-unverified-hourly-pm25 +name: British Columbia Hourly PM2.5 +description: > + Preliminary British Columbia fine-particle station readings for inspecting + hourly particulate concentrations and their observation times. +theme: Environment & Hazards +url: https://open.canada.ca/data/en/dataset/01867404-ba2a-470e-94b7-0604607cfa30 +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - CSV +license: > + B.C. Open Government Licence 2.0 with provincial attribution. These hourly + values are unverified and exclude Metro Vancouver and Fraser Valley data. +license_url: https://open.canada.ca/data/en/dataset/01867404-ba2a-470e-94b7-0604607cfa30 +url_checks: + source_marker: Unverified Hourly Air Quality and Meteorological Data + license_marker: Open Government Licence - British Columbia +domains: + - Public Health + - Weather +data_types: + - Time Series +tasks: + - Monitoring +difficulty: beginner +geography: + - British Columbia +temporal_coverage: recent unverified hourly PM2.5 readings +update_frequency: near real time +provider: Government of British Columbia +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + B.C. publishes an unverified PM2.5 CSV and a station metadata CSV. Start + with five lines from the current pollutant file using a streaming read; + the full file is several megabytes. The catalog record confirms its OGL-BC + licence and warns that Metro Vancouver and Fraser Valley readings are + excluded. These concentrations are not provider-reported AQI values. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the B.C. catalog record, geographic exclusions, and licence. + - Stream the official PM2.5 CSV and inspect five data rows. + - Join station names to official station metadata before mapping. + python: + packages: + - requests + code: | + import csv + import itertools + import requests + + url = ("https://www.env.gov.bc.ca/epd/bcairquality/aqo/csv/" + "Hourly_Raw_Air_Data/Air_Quality/PM25.csv") + with requests.get(url, stream=True, timeout=30) as response: + response.raise_for_status() + rows = csv.DictReader(response.iter_lines(decode_unicode=True)) + for row in itertools.islice(rows, 5): + print(row["STATION_NAME"], row["DATE_PST"], row["RAW_VALUE"], row["UNITS"]) + first_project: + title: Inspect B.C. Hourly PM2.5 + goal: Review five preliminary observations before station mapping. + steps: + - Keep station ID or name, timestamp, unit, and concentration. + - Check quality and coverage before deriving a local AQI estimate. + - Explain why a missing station is not evidence of clean air. diff --git a/data/datasets/bea-regional-price-parities.yaml b/data/datasets/bea-regional-price-parities.yaml new file mode 100644 index 0000000..86c9474 --- /dev/null +++ b/data/datasets/bea-regional-price-parities.yaml @@ -0,0 +1,77 @@ +id: bea-regional-price-parities +name: BEA Regional Price Parities +description: > + BEA state and metropolitan Regional Price Parity archives for comparing + relative consumer price levels across U.S. regions. +theme: Markets & Economics +url: https://www.bea.gov/data/prices-inflation/regional-price-parities-state-and-metro-area +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - CSV + - ZIP +license: BEA information is public domain unless stated otherwise; cite BEA as source. +license_url: https://www.bea.gov/help/faq/147 +url_checks: + source_marker: Regional Price Parities + license_marker: information posted on this web site is in the public domain +domains: + - Regional Economics + - Inflation +data_types: + - Tabular + - Time Series +tasks: + - Regional Comparison + - Market Sizing +difficulty: intermediate +geography: + - United States states and metropolitan areas +temporal_coverage: 2008-2024 in the current MARPP and SARPP archives +update_frequency: annual +provider: U.S. Bureau of Economic Analysis +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + BEA provides separate metropolitan MARPP and state SARPP archives. Start + with five rows of the all-items metropolitan table from its versioned ZIP. + An RPP is a relative price index, not a household budget or county-level + cost measurement; state and metro values should not be mixed as one grain. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official BEA RPP page and public-domain reuse guidance. + - Download the MARPP archive and identify its metropolitan CSV member. + - Keep the table, unit, geography, and year when interpreting values. + python: + packages: + - requests + code: | + import csv + import io + import itertools + from zipfile import ZipFile + import requests + + response = requests.get("https://apps.bea.gov/regional/zip/MARPP.zip", timeout=30) + response.raise_for_status() + archive = ZipFile(io.BytesIO(response.content)) + with archive.open("MARPP_MSA_2008_2024.csv") as member: + rows = csv.DictReader(io.TextIOWrapper(member, encoding="utf-8-sig")) + metros = (row for row in rows if "Metropolitan Statistical Area" in row["GeoName"]) + for row in itertools.islice(metros, 5): + print(row["GeoFIPS"].strip(), row["GeoName"], row["Description"], row["2024"]) + first_project: + title: Inspect Metropolitan Price Parities + goal: Check one published RPP year for a regional cost comparison. + steps: + - Filter to all-items index rows and retain BEA metropolitan identifiers. + - Compare two metros using the same year and table line. + - Explain why the index is not a direct household cost estimate. diff --git a/data/datasets/binance-bitcoin-ticker.yaml b/data/datasets/binance-bitcoin-ticker.yaml new file mode 100644 index 0000000..ecf1df6 --- /dev/null +++ b/data/datasets/binance-bitcoin-ticker.yaml @@ -0,0 +1,64 @@ +id: binance-bitcoin-ticker +name: Binance Bitcoin Ticker +description: Binance BTC/USDT exchange quotes for a private Bitcoin market comparison where service is + available with explicit provider provenance and retrieval time. +theme: Markets & Economics +url: https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- JSON +license: Binance service terms limit this example to noncommercial personal or internal analysis; regional + restrictions apply. +license_url: https://www.binance.com/en/terms +url_checks: + source_marker: '"symbol":"BTCUSDT"' + license_marker: non-commercial personal or internal business use +domains: +- Capital Markets +data_types: +- Tabular +tasks: +- Market Monitoring +difficulty: beginner +geography: +- Global +temporal_coverage: current BTC spot quote +update_frequency: near real time +provider: Binance +source_type: company +last_verified: '2026-09-28' +getting_started: + overview: The Binance public endpoint returns one current Bitcoin quote. Start with one response and + record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. + Follow the provider usage limits above. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official Binance API and data-use terms. + - Fetch one Bitcoin quote from the documented public endpoint. + - Keep the pair, retrieval time, and provider name separate from other exchanges. + python: + packages: + - requests + code: | + import requests + + url = 'https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT' + response = requests.get(url, timeout=20) + response.raise_for_status() + quote = response.json() + print(quote["symbol"], quote["price"]) + first_project: + title: Compare One Bitcoin Quote + goal: Inspect a single provider quote without treating it as an investment signal. + steps: + - Fetch a single response and retain its pair identifier. + - Record the retrieval time and label the provider. + - Explain why exchange quotes differ and cannot stand in for historical returns. diff --git a/data/datasets/bitstamp-bitcoin-ticker.yaml b/data/datasets/bitstamp-bitcoin-ticker.yaml new file mode 100644 index 0000000..d4f899d --- /dev/null +++ b/data/datasets/bitstamp-bitcoin-ticker.yaml @@ -0,0 +1,64 @@ +id: bitstamp-bitcoin-ticker +name: Bitstamp Bitcoin Ticker +description: Bitstamp BTC/USD exchange ticker fields for a private Bitcoin market comparison with explicit + provider provenance and retrieval time. +theme: Markets & Economics +url: https://www.bitstamp.net/api/v2/ticker/btcusd/ +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- JSON +license: Bitstamp public API terms allow personal analysis; commercial exchange-data use needs a separate + licence. +license_url: https://www.bitstamp.net/api/ +url_checks: + source_marker: '"percent_change_24"' + license_marker: Commercial Use of Bitstamp +domains: +- Capital Markets +data_types: +- Tabular +tasks: +- Market Monitoring +difficulty: beginner +geography: +- Global +temporal_coverage: current BTC spot quote +update_frequency: near real time +provider: Bitstamp +source_type: company +last_verified: '2026-09-28' +getting_started: + overview: The Bitstamp public endpoint returns one current Bitcoin quote. Start with one response and + record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. + Follow the provider usage limits above. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official Bitstamp API and data-use terms. + - Fetch one Bitcoin quote from the documented public endpoint. + - Keep the pair, retrieval time, and provider name separate from other exchanges. + python: + packages: + - requests + code: | + import requests + + url = 'https://www.bitstamp.net/api/v2/ticker/btcusd/' + response = requests.get(url, timeout=20) + response.raise_for_status() + quote = response.json() + print(quote["timestamp"], quote["last"], quote["volume"]) + first_project: + title: Compare One Bitcoin Quote + goal: Inspect a single provider quote without treating it as an investment signal. + steps: + - Fetch a single response and retain its pair identifier. + - Record the retrieval time and label the provider. + - Explain why exchange quotes differ and cannot stand in for historical returns. diff --git a/data/datasets/bls-qcew-county-high-level.yaml b/data/datasets/bls-qcew-county-high-level.yaml new file mode 100644 index 0000000..c651c9f --- /dev/null +++ b/data/datasets/bls-qcew-county-high-level.yaml @@ -0,0 +1,63 @@ +id: bls-qcew-county-high-level +name: BLS QCEW County High-Level Archives +description: > + BLS county employment and wage annual-average archives for comparing local labor-market conditions. +theme: Markets & Economics +url: https://www.bls.gov/cew/downloadable-data-files.htm +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.03 +size_gb_max: 0.05 +formats: [ZIP, XLSX] +license: BLS publications are public domain; cite BLS and keep the release year and industry classification. +license_url: https://www.bls.gov/bls/linksite.htm +url_checks: + source_marker: County High-Level + license_marker: everything that we publish, both in hard copy and electronically, is in the public domain +domains: [Labor Economics] +data_types: [Tabular] +tasks: [Community Comparison] +difficulty: intermediate +geography: [United States counties] +temporal_coverage: annual QCEW county averages; HouseHunter pins final 2024 and 2025 archives +update_frequency: quarterly +provider: U.S. Bureau of Labor Statistics +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + BLS publishes County High-Level Excel ZIPs apart from its Public Data API. + Start with one row from the 2025 annual-average workbook; HouseHunter also + pins 2024. QCEW covers jobs subject to unemployment-insurance laws, not + every worker or current job openings. + prerequisites: [Python 3.10 or newer, An internet connection, The requests and openpyxl Python packages] + access_steps: + - Read the QCEW file layout and BLS public-domain notice. + - Download the exact 2025 County High-Level annual archive. + - Inspect the area, ownership, industry, employment, and wage columns. + python: + packages: [requests, openpyxl] + code: | + import io + import itertools + import zipfile + import requests + from openpyxl import load_workbook + + url = "https://data.bls.gov/cew/data/files/2025/xls/2025_all_county_high_level.zip" + response = requests.get(url, timeout=60) + response.raise_for_status() + with zipfile.ZipFile(io.BytesIO(response.content)) as archive: + name = next(n for n in archive.namelist() if n.endswith("allhlcn25.xlsx")) + workbook = load_workbook(io.BytesIO(archive.read(name)), read_only=True, data_only=True) + for row in itertools.islice(workbook.active.values, 3): + print(row[:6]) + workbook.close() + first_project: + title: Compare County Employment + goal: Compare fixed-year county employment and wages at one ownership and industry grain. + steps: + - Select one county and industry from the high-level workbook. + - Compare annual-average employment and wages at the same grain. + - Explain which workers the QCEW coverage omits. diff --git a/data/datasets/catalonia-civil-protection-plans.yaml b/data/datasets/catalonia-civil-protection-plans.yaml new file mode 100644 index 0000000..a5b0b52 --- /dev/null +++ b/data/datasets/catalonia-civil-protection-plans.yaml @@ -0,0 +1,73 @@ +id: catalonia-civil-protection-plans +name: Catalonia Civil Protection Plans +description: > + Current Catalan civil-protection plan activations and phases for reviewing + regional emergency context and official CECAT updates. +theme: Environment & Hazards +url: https://analisi.transparenciacatalunya.cat/api/views/wj9c-j6vf +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + Generalitat of Catalonia open-information licence; cite the department, + preserve meaning and latest update, and follow any dataset-specific notice. +license_url: https://web.gencat.cat/ca/generalitat/dades-indicadors/dades-obertes/llicencies +url_checks: + source_marker: Civil protection plans currently in the pre-alert + license_marker: La reutilització de la informació +domains: + - Emergency Management +data_types: + - Event Data +tasks: + - Monitoring + - Alerting +difficulty: beginner +geography: + - Catalonia +temporal_coverage: current plan phases and official update links +update_frequency: occasional +provider: Generalitat de Catalunya Civil Protection +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The Generalitat publishes the current pre-alert, alert, and emergency + phases of Catalan civil-protection plans through one Socrata dataset. + Start with five records. A plan phase is regional context and must not be + treated as a destination-specific evacuation order. Attribute the agency, + preserve meaning, and show the last update date. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the exact dataset metadata and Catalan reuse conditions. + - Request five current plan rows from the official dataset API. + - Inspect acronym, phase, activation flag, and phase timestamp. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://analisi.transparenciacatalunya.cat/resource/wj9c-j6vf.json", + params={"$limit": 5}, timeout=30, + ) + response.raise_for_status() + for plan in response.json(): + print(plan.get("plaacronim"), plan.get("plafase"), + plan.get("plaactivat"), plan.get("fasedatahora")) + first_project: + title: Inspect Current Catalan Plan Phases + goal: Review five official plan records for regional emergency context. + steps: + - Keep plan acronym, phase, activation flag, and update timestamp. + - Link the official CECAT communication when one is supplied. + - Explain why a regional plan phase is not a local restriction or order. diff --git a/data/datasets/census-acs-2024-table-summary.yaml b/data/datasets/census-acs-2024-table-summary.yaml new file mode 100644 index 0000000..f3613e4 --- /dev/null +++ b/data/datasets/census-acs-2024-table-summary.yaml @@ -0,0 +1,60 @@ +id: census-acs-2024-table-summary +name: Census ACS 2024 Five-Year Table Summary Files +description: > + Census Bureau table-based ACS estimate and margin files for building tract and county housing-context tools. +theme: Demographics & Development +url: https://www.census.gov/programs-surveys/acs/data/summary-file.2024.html +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.01 +size_gb_max: 0.1 +formats: [DAT] +license: U.S. Census Bureau public-use statistics; cite the ACS release and retain margins of error. +license_url: https://www.census.gov/about/policies/citation.html +url_checks: + source_marker: 2024 ACS 5-year Estimates + license_marker: Public-Use Statement +domains: [Housing] +data_types: [Tabular, Survey Estimates] +tasks: [Community Comparison] +difficulty: beginner +geography: [United States counties, United States Census tracts] +temporal_coverage: 2020-2024 ACS five-year estimates +update_frequency: annual +provider: U.S. Census Bureau +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The 2024 table-based Summary File publishes each detailed table as a pipe-delimited + .dat file with estimates and margins. HouseHunter pins B25034, B25035, B25103, + B25077, and B08303. Start with one bounded read of B25103; a table value is a + survey estimate, and a GEO_ID must be joined to its geography label. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the Census table-based Summary File instructions and citation guidance. + - Request the first complete records from one pinned 2024 five-year table. + - Inspect the GEO_ID, estimate, and margin fields before a geography join. + python: + packages: [requests] + code: | + import csv + import io + import requests + + url = ("https://www2.census.gov/programs-surveys/acs/summary_file/2024/" + "table-based-SF/data/5YRData/acsdt5y2024-b25103.dat") + response = requests.get(url, headers={"Range": "bytes=0-2047"}, timeout=30) + response.raise_for_status() + lines = response.text.splitlines() + rows = csv.DictReader(io.StringIO("\n".join(lines[:-1])), delimiter="|") + for row in list(rows)[:2]: + print(row["GEO_ID"], row["B25103_E001"], row["B25103_M001"]) + first_project: + title: Inspect ACS Housing Estimates + goal: Compare a small set of housing estimates with their margins of error. + steps: + - Read B25103 estimates and margins for two geographies. + - Join GEO_ID to the matching ACS geography labels. + - Explain why a five-year survey estimate is not a current property count. diff --git a/data/datasets/census-geocoder.yaml b/data/datasets/census-geocoder.yaml new file mode 100644 index 0000000..2c54f18 --- /dev/null +++ b/data/datasets/census-geocoder.yaml @@ -0,0 +1,74 @@ +id: census-geocoder +name: Census Geocoder Address Lookup +description: > + U.S. Census Bureau address-to-tract geocoding responses for assigning a + user-entered address to its reviewed Census geography. +theme: Geospatial & Infrastructure +url: https://geocoding.geo.census.gov/geocoder/Geocoding_Services_API.html +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + Census API terms permit search and analysis; identify the Census source and + state that Census does not endorse or certify the resulting application. +license_url: https://www.census.gov/data/developers/about/terms-of-service.html +url_checks: + source_marker: Single Record Geocoding Service Requests + license_marker: not endorsed or certified by the Census Bureau +domains: + - Geography +data_types: + - Geospatial +tasks: + - Geographic Analysis +difficulty: beginner +geography: + - United States +temporal_coverage: current address-range benchmark with selectable geography vintage +update_frequency: occasional +provider: U.S. Census Bureau +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The Census Geocoder returns address matches and Census tract geography + for one submitted U.S. address. Start with the Census Bureau's own public + example address and request the current 2020 geography vintage. Do not + send confidential addresses in a tutorial; an approximate range match + needs review before it is used as a property location. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official geocoding request format and API terms. + - Request one public example address with an explicit benchmark and vintage. + - Inspect the returned tract identifier and match quality. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://geocoding.geo.census.gov/geocoder/geographies/onelineaddress", + params={"address": "4600 Silver Hill Rd, Washington, DC 20233", + "benchmark": "Public_AR_Current", "vintage": "Census2020_Current", + "format": "json"}, timeout=30, + ) + response.raise_for_status() + for match in response.json()["result"]["addressMatches"][:5]: + tracts = match["geographies"].get("Census Tracts", []) + print(match["matchedAddress"], [tract["GEOID"] for tract in tracts]) + first_project: + title: Check a Census Tract Match + goal: Inspect a public example address before using geocoding in a local lookup. + steps: + - Keep the matched address, coordinates, benchmark, vintage, and tract GEOID. + - Handle zero or multiple matches without silently choosing one. + - Explain why address-range coordinates can differ from a parcel location. diff --git a/data/datasets/census-pep-county-totals.yaml b/data/datasets/census-pep-county-totals.yaml new file mode 100644 index 0000000..b3e2f47 --- /dev/null +++ b/data/datasets/census-pep-county-totals.yaml @@ -0,0 +1,75 @@ +id: census-pep-county-totals +name: Census PEP County Population Totals +description: > + Vintage 2025 county population estimates from the U.S. Census Bureau for + comparing county sizes and applying population-based eligibility thresholds. +theme: Demographics & Development +url: https://www.census.gov/data/datasets/time-series/demo/popest/2020s-counties-total.html +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0.001 +size_gb_max: 0.01 +formats: + - CSV +license: U.S. government published statistics; cite the Census Bureau and retain vintage. +license_url: https://www.census.gov/about/policies/citation.html +url_checks: + source_marker: CO-EST2025-alldata + license_marker: Public-Use Statement +domains: + - Demographics + - Population +data_types: + - Tabular + - Survey Estimates +tasks: + - Community Comparison + - Market Sizing +difficulty: beginner +geography: + - United States counties +temporal_coverage: 2020-2025 annual estimates, vintage 2025 +update_frequency: annual +provider: U.S. Census Bureau +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The Census Population Estimates Program publishes a versioned county CSV. + Start with five rows from the Vintage 2025 all-data file and retain the + year and county FIPS components. Estimates can be revised in later vintages + and do not measure the population of a neighborhood or tract. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official Vintage 2025 county data page and citation guidance. + - Download the county totals CSV and inspect its FIPS and population columns. + - Keep the vintage fixed when comparing or ranking counties. + python: + packages: + - requests + code: | + import csv + import io + import itertools + import requests + + response = requests.get( + "https://www2.census.gov/programs-surveys/popest/datasets/" + "2020-2025/counties/totals/co-est2025-alldata.csv", timeout=30, + ) + response.raise_for_status() + rows = csv.DictReader(io.StringIO(response.text)) + for row in itertools.islice((row for row in rows if row["COUNTY"] != "000"), 5): + print(row["STATE"], row["COUNTY"], row["CTYNAME"], row["POPESTIMATE2025"]) + first_project: + title: Inspect Five County Estimates + goal: Test a fixed-vintage population floor for a county comparison tool. + steps: + - Join state and county FIPS components without dropping leading zeroes. + - Count which sampled counties exceed a chosen population threshold. + - Explain why later estimates may differ from this pinned vintage. diff --git a/data/datasets/chmi-current-hydrology.yaml b/data/datasets/chmi-current-hydrology.yaml new file mode 100644 index 0000000..b14d4b9 --- /dev/null +++ b/data/datasets/chmi-current-hydrology.yaml @@ -0,0 +1,71 @@ +id: chmi-current-hydrology +name: CHMI Current Hydrology Stations +description: > + Current Czech hydrological station series from CHMI for checking measured + water levels against separately documented local thresholds. +theme: Environment & Hazards +url: https://opendata.chmi.cz/hydrology/now/data/ +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: CC BY 4.0 with CHMI attribution. +license_url: https://www.chmi.cz/-/jak-mohu-pou%C5%BE%C3%ADvat-otev%C5%99en%C3%A1-data-%C4%8Dhm%C3%BA- +url_checks: + source_marker: Index of /hydrology/now/data/ + license_marker: Creative Commons BY 4.0 +domains: + - Hydrology + - Emergency Management +data_types: + - Time Series +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Czechia +temporal_coverage: current station observations +update_frequency: near real time +provider: Czech Hydrometeorological Institute +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + CHMI publishes per-station current H and Q time series as small JSON files. + Start with one station used by TravelCanary. Station observations are not + official warnings by themselves; check timestamps and separately sourced + flood thresholds before interpreting a value. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the CHMI open-data licence and current hydrology documentation. + - Fetch one station JSON file from the current-data directory. + - Inspect series type, unit, and the latest observation time. + python: + packages: + - requests + code: | + import requests + + url = "https://opendata.chmi.cz/hydrology/now/data/0-203-1-244000.json" + response = requests.get(url, timeout=30) + response.raise_for_status() + station = response.json()["objList"][0] + for series in [row for row in station["tsList"] + if row["tsConID"] in ("H", "Q")][:2]: + print(station["objID"], series["tsConID"], series.get("unit"), + series["tsData"][-1] if series.get("tsData") else None) + first_project: + title: Inspect One Czech River Station + goal: Review one bounded current observation before flood-threshold use. + steps: + - Keep station ID, series type, unit, and measurement time. + - Check the observation age and applicable station threshold metadata. + - Explain why a measured stage alone is not an official flood warning. diff --git a/data/datasets/chmi-flash-flood-risk.yaml b/data/datasets/chmi-flash-flood-risk.yaml new file mode 100644 index 0000000..a3ca7e3 --- /dev/null +++ b/data/datasets/chmi-flash-flood-risk.yaml @@ -0,0 +1,74 @@ +id: chmi-flash-flood-risk +name: CHMI Flash-Flood Risk Product +description: > + Official Czech flash-flood risk classes for administrative areas from + CHMI for reviewing local short-term flooding risk. +theme: Environment & Hazards +url: https://opendata.chmi.cz/hydrology/product/data/flash_flood/risk_FF_web.json +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: CC BY 4.0 with CHMI attribution. +license_url: https://www.chmi.cz/-/jak-mohu-pou%C5%BE%C3%ADvat-otev%C5%99en%C3%A1-data-%C4%8Dhm%C3%BA- +url_checks: + source_marker: povodne_orp_risk_ff + license_marker: Creative Commons BY 4.0 +domains: + - Hydrology + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Czechia +temporal_coverage: current ORP flash-flood risk product +update_frequency: near real time +provider: Czech Hydrometeorological Institute +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + CHMI publishes a dated flash-flood risk JSON product by Czech ORP area. + Start with one response and inspect at most five areas if present. A + response with only report metadata means no listed risk areas; it does not + replace current station observations or general flood guidance. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read CHMI's risk-class metadata and CC BY 4.0 condition. + - Fetch the current risk product once. + - Keep creation time, ORP code, and resulting risk class. + python: + packages: + - requests + code: | + import requests + + url = "https://opendata.chmi.cz/hydrology/product/data/flash_flood/risk_FF_web.json" + response = requests.get(url, timeout=30) + response.raise_for_status() + product = response.json() + print(product["datumVytvoreni"]) + for key, areas in product["data"].items(): + if key == "report": + continue + for area in areas[:5]: + print(area.get("kod_orp_ruian"), area.get("riziko_vysledne")) + first_project: + title: Inspect Czech Flash-Flood Areas + goal: Review official nonzero risk classes against one mapped locality. + steps: + - Keep the issue time, ORP identifier, and forecast risk class. + - Distinguish forecast risk from measured water levels. + - Explain why no listed areas do not imply permanent or nationwide safety. diff --git a/data/datasets/chrr-community-conditions-2025.yaml b/data/datasets/chrr-community-conditions-2025.yaml new file mode 100644 index 0000000..5c11bec --- /dev/null +++ b/data/datasets/chrr-community-conditions-2025.yaml @@ -0,0 +1,58 @@ +id: chrr-community-conditions-2025 +name: CHR&R 2025 Community Conditions +description: > + County Health Rankings 2025 county community-condition measures for building a noncommercial county context comparison. +theme: Health, Food & Safety +url: https://p3eplmys2rvchkjx.svcs.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/County%20Health%20Rankings%202025/FeatureServer/2?f=pjson +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [JSON, GeoJSON] +license: CHR&R permits personal and nonprofit analysis with attribution; commercial use requires prior written consent. +license_url: https://www.countyhealthrankings.org/terms-use +url_checks: + source_marker: fed47aeb4d334339a73e20088181e544 + license_marker: personal or non-profit purposes +domains: [Public Health] +data_types: [Geospatial] +tasks: [Community Comparison, Mapping] +difficulty: intermediate +geography: [United States] +temporal_coverage: 2025 annual county release +update_frequency: annual +provider: County Health Rankings & Roadmaps +source_type: academic +last_verified: 2026-09-28 +getting_started: + overview: > + The official CHR&R 2025 ArcGIS county layer includes community-condition + measures used by HouseHunter. Start with one county's attributes; + measure periods and coverage differ, so the layer is not a current + measurement of every county condition. Nonprofit or personal use only. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read CHR&R's 2025 documentation and noncommercial terms. + - Query one county feature from the official 2025 layer. + - Check measure definitions and years before comparing counties. + python: + packages: [requests] + code: | + import requests + + url = ("https://p3eplmys2rvchkjx.svcs.arcgis.com/" + "P3ePLMYs2RVChkJx/arcgis/rest/services/" + "County%20Health%20Rankings%202025/FeatureServer/2/query") + response = requests.get(url, params={"where": "1=1", "outFields": "*", + "resultRecordCount": 1, "f": "json"}, timeout=20) + response.raise_for_status() + row = response.json()["features"][0]["attributes"] + print(row.get("statecode"), row.get("countycode"), len(row)) + first_project: + title: Compare County Conditions + goal: Inspect the source and vintage of one 2025 county record. + steps: + - Query one county feature and retain its FIPS identifiers. + - Look up the selected measure's definition and measurement year. + - Explain that different measure vintages limit direct comparisons. diff --git a/data/datasets/chrr-mental-health-supplement-2025.yaml b/data/datasets/chrr-mental-health-supplement-2025.yaml new file mode 100644 index 0000000..3170508 --- /dev/null +++ b/data/datasets/chrr-mental-health-supplement-2025.yaml @@ -0,0 +1,59 @@ +id: chrr-mental-health-supplement-2025 +name: CHR&R 2025 Mental Health Supplement +description: > + County Health Rankings supplemental county provider counts for building a noncommercial mental-health access comparison. +theme: Health, Food & Safety +url: https://www.countyhealthrankings.org/health-data/methodology-and-sources/data-documentation +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.01 +size_gb_max: 0.02 +formats: [CSV] +license: CHR&R permits personal and nonprofit analysis with attribution; commercial use requires prior written consent. +license_url: https://www.countyhealthrankings.org/terms-use +url_checks: + source_marker: SUPPLEMENTAL DATA RELEASE + license_marker: personal or non-profit purposes +domains: [Public Health] +data_types: [Tabular] +tasks: [Community Comparison] +difficulty: intermediate +geography: [United States] +temporal_coverage: 2025 provider input in the March 2026 supplement +update_frequency: annual +provider: County Health Rankings & Roadmaps +source_type: academic +last_verified: 2026-09-28 +getting_started: + overview: > + The March 2026 CHR&R supplemental CSV includes 2025 NPPES-derived county + mental-health provider measures. Start with two rows and the v062 fields; + provider counts indicate listed supply, not appointment access. + Nonprofit or personal use only. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the CHR&R supplement documentation and noncommercial terms. + - Stream two county rows from the official supplemental CSV. + - Review the v062 numerator with the published denominator definition. + python: + packages: [requests] + code: | + import csv + import itertools + import requests + + url = ("https://www.countyhealthrankings.org/sites/default/files/" + "media/document/analytic_supplement_20260325%5B1%5D.csv") + with requests.get(url, stream=True, timeout=30) as response: + response.raise_for_status() + lines = (line.decode("utf-8-sig") for line in response.iter_lines()) + for row in itertools.islice(csv.DictReader(lines), 2): + print(row["fipscode"], row["v062_numerator"], row["v062_denominator"]) + first_project: + title: Inspect Mental Health Provider Supply + goal: Show two county provider-supply records with the published measure definition. + steps: + - Stream two rows and retain their county FIPS codes. + - Calculate a rate only with the documented denominator. + - Explain why provider listings are not verified care availability. diff --git a/data/datasets/coinbase-bitcoin-spot-price.yaml b/data/datasets/coinbase-bitcoin-spot-price.yaml new file mode 100644 index 0000000..d959d7d --- /dev/null +++ b/data/datasets/coinbase-bitcoin-spot-price.yaml @@ -0,0 +1,64 @@ +id: coinbase-bitcoin-spot-price +name: Coinbase Bitcoin Spot Price +description: Coinbase Bitcoin-to-USD spot quotes for a private, personal research comparison with explicit + provider provenance and retrieval time. +theme: Markets & Economics +url: https://api.coinbase.com/v2/prices/BTC-USD/spot +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- JSON +license: Coinbase Market Data Terms allow personal or internal research only; external app display and + redistribution require permission. +license_url: https://www.coinbase.com/legal/market_data +url_checks: + source_marker: '"base":"BTC","currency":"USD"' + license_marker: personal or research purposes +domains: +- Capital Markets +data_types: +- Tabular +tasks: +- Market Monitoring +difficulty: beginner +geography: +- Global +temporal_coverage: current BTC spot quote +update_frequency: near real time +provider: Coinbase +source_type: company +last_verified: '2026-09-28' +getting_started: + overview: The Coinbase public endpoint returns one current Bitcoin quote. Start with one response and + record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. + Follow the provider usage limits above. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official Coinbase API and data-use terms. + - Fetch one Bitcoin quote from the documented public endpoint. + - Keep the pair, retrieval time, and provider name separate from other exchanges. + python: + packages: + - requests + code: | + import requests + + url = 'https://api.coinbase.com/v2/prices/BTC-USD/spot' + response = requests.get(url, timeout=20) + response.raise_for_status() + quote = response.json()["data"] + print(quote["base"], quote["currency"], quote["amount"]) + first_project: + title: Compare One Bitcoin Quote + goal: Inspect a single provider quote without treating it as an investment signal. + steps: + - Fetch a single response and retain its pair identifier. + - Record the retrieval time and label the provider. + - Explain why exchange quotes differ and cannot stand in for historical returns. diff --git a/data/datasets/coingecko-bitcoin-price.yaml b/data/datasets/coingecko-bitcoin-price.yaml new file mode 100644 index 0000000..635844a --- /dev/null +++ b/data/datasets/coingecko-bitcoin-price.yaml @@ -0,0 +1,64 @@ +id: coingecko-bitcoin-price +name: CoinGecko Bitcoin Spot Price +description: CoinGecko Bitcoin-to-USD spot quotes for a personal, dated Bitcoin price comparison with + explicit provider provenance and retrieval time. +theme: Markets & Economics +url: https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- JSON +license: CoinGecko API terms permit contracted API use subject to attribution and plan limits; public + endpoints offer no redistribution rights. +license_url: https://www.coingecko.com/en/api_terms +url_checks: + source_marker: '"bitcoin":{"usd":' + license_marker: CoinGecko API Terms of Service +domains: +- Capital Markets +data_types: +- Tabular +tasks: +- Market Monitoring +difficulty: beginner +geography: +- Global +temporal_coverage: current BTC spot quote +update_frequency: near real time +provider: CoinGecko +source_type: company +last_verified: '2026-09-28' +getting_started: + overview: The CoinGecko public endpoint returns one current Bitcoin quote. Start with one response and + record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. + Follow the provider usage limits above. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official CoinGecko API and data-use terms. + - Fetch one Bitcoin quote from the documented public endpoint. + - Keep the pair, retrieval time, and provider name separate from other exchanges. + python: + packages: + - requests + code: | + import requests + + url = 'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd' + response = requests.get(url, timeout=20) + response.raise_for_status() + bitcoin = response.json()["bitcoin"] + print("USD", bitcoin["usd"]) + first_project: + title: Compare One Bitcoin Quote + goal: Inspect a single provider quote without treating it as an investment signal. + steps: + - Fetch a single response and retain its pair identifier. + - Record the retrieval time and label the provider. + - Explain why exchange quotes differ and cannot stand in for historical returns. diff --git a/data/datasets/copernicus-edo-drought-indicator.yaml b/data/datasets/copernicus-edo-drought-indicator.yaml new file mode 100644 index 0000000..d417444 --- /dev/null +++ b/data/datasets/copernicus-edo-drought-indicator.yaml @@ -0,0 +1,71 @@ +id: copernicus-edo-drought-indicator +name: Copernicus EDO Drought Indicator +description: > + Dekadal European Combined Drought Indicator rasters for agricultural and ecosystem drought context tools. +theme: Environment & Hazards +url: https://drought.emergency.copernicus.eu/data/wcs-service +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0.002 +size_gb_max: 0.01 +formats: [GeoTIFF] +license: > + CEMS EDO data permit reproduction, distribution, and adaptation with source and modification notices; some restricted products require registration. +license_url: https://drought.emergency.copernicus.eu/terms%26conditions +url_checks: + source_marker: Combined Drought Indicator (CDI) v4.1 + license_marker: the data of the CEMS EDO and GDO early warning and monitoring systems +domains: [Climate] +data_types: [Raster] +tasks: [Monitoring] +difficulty: intermediate +geography: [Europe] +temporal_coverage: dated dekadal CDI product vintages +update_frequency: occasional +provider: Copernicus Emergency Management Service +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + EDO publishes the cdiad Combined Drought Indicator through its WCS with a dated configuration record. + Start with the latest available GeoTIFF; agricultural drought context is not an immediate emergency warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the CDI WCS documentation and CEMS reuse terms. + - Find the current cdiad end date in the EDO configuration. + - Download that dated WCS GeoTIFF and retain its product date. + python: + packages: [requests] + code: | + import requests + + root = "https://drought.emergency.copernicus.eu" + config = requests.get(root + "/services/config?appCode=edo_map", timeout=25) + config.raise_for_status() + def cdi_date(node): + if isinstance(node, dict): + if node.get("code") == "cdiad": + return node["endDay"] + return next((day for value in node.values() if (day := cdi_date(value))), None) + if isinstance(node, list): + return next((day for value in node if (day := cdi_date(value))), None) + return None + day = cdi_date(config.json()) + assert day, "No CDI product date" + response = requests.get( + root + "/api/wcs", + params={"map": "DO_WCS", "SERVICE": "WCS", "VERSION": "2.0.0", + "REQUEST": "GetCoverage", "coverageID": "cdiad", "CRS": "EPSG:4326", + "format": "GEOTIFF", "TIME": day}, timeout=40, + ) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*"), "Expected GeoTIFF" + print(day, "EDO CDI bytes:", len(response.content)) + first_project: + title: Inspect One Drought Product + goal: Display the latest CDI product vintage with its interpretation limit. + steps: + - Read the current cdiad product date from EDO. + - Fetch the matching WCS raster and label that date. + - Explain that stale or absent pixels cannot be read as a current all-clear. diff --git a/data/datasets/copernicus-gfm-flood-layers.yaml b/data/datasets/copernicus-gfm-flood-layers.yaml new file mode 100644 index 0000000..f23bc04 --- /dev/null +++ b/data/datasets/copernicus-gfm-flood-layers.yaml @@ -0,0 +1,61 @@ +id: copernicus-gfm-flood-layers +name: Copernicus Global Flood Monitoring Layers +description: > + Satellite observed flood extent, likelihood, and advisory-flag rasters for corroborating possible flood events. +theme: Environment & Hazards +url: https://confluence.ecmwf.int/spaces/CEMS/pages/242067378/Web%2BLayers +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GeoTIFF] +license: > + CEMS early-warning data permit reproduction, distribution, and adaptation with source and modification notices; some restricted products require registration. +license_url: https://drought.emergency.copernicus.eu/terms%26conditions +url_checks: + source_marker: Observed Flood Extent + license_marker: Global Flood Monitoring product +domains: [Water Resources] +data_types: [Raster] +tasks: [Monitoring] +difficulty: intermediate +geography: [Global] +temporal_coverage: recent Sentinel-1 flood-monitoring layers +update_frequency: near real time +provider: Copernicus Emergency Management Service +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + GFM serves observed_flood_extent, uncertainty_values, and advisory_flags as related WMS raster layers. + Start with a small observed-extent tile; satellite coverage and uncertainty must be checked before inferring flooding. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the GFM product, layer definitions, and CEMS reuse conditions. + - Request a bounded observed_flood_extent GeoTIFF from the public WMS. + - Check matching uncertainty_values and advisory_flags before interpreting pixels. + python: + packages: [requests] + code: | + from datetime import datetime, timezone + import requests + + valid_day = datetime.now(timezone.utc).strftime("%Y-%m-%dT00:00:00.000Z") + response = requests.get( + "https://geoserver.gfm.eodc.eu/geoserver/gfm/wms", + params={"SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetMap", + "LAYERS": "observed_flood_extent", "STYLES": "", "SRS": "EPSG:4326", + "BBOX": "5,45,5.1,45.1", "WIDTH": 32, "HEIGHT": 32, + "FORMAT": "image/geotiff", "TIME": valid_day}, timeout=20, + ) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*"), "Expected GeoTIFF" + print(valid_day, "GFM extent bytes:", len(response.content)) + first_project: + title: Inspect a Flood-Extent Tile + goal: Display a dated, bounded GFM tile with its uncertainty caveat. + steps: + - Fetch one observed_flood_extent tile. + - Record its bounds and valid date with the matching quality-layer names. + - Explain that absent satellite pixels are not an all-clear. diff --git a/data/datasets/copernicus-glofas-flood-outlook.yaml b/data/datasets/copernicus-glofas-flood-outlook.yaml new file mode 100644 index 0000000..75675ac --- /dev/null +++ b/data/datasets/copernicus-glofas-flood-outlook.yaml @@ -0,0 +1,61 @@ +id: copernicus-glofas-flood-outlook +name: Copernicus GloFAS Flood Outlook +description: > + Global flood-forecast summary maps for selecting areas needing closer satellite or local-authority checks. +theme: Environment & Hazards +url: https://ows.globalfloods.eu/glofas-ows/ows.py?service=WMS&request=GetCapabilities +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GeoTIFF] +license: > + CEMS early-warning information permits reuse with source and modification notices; it is informational and not an official local warning. +license_url: https://drought.emergency.copernicus.eu/terms%26conditions +url_checks: + source_marker: Flood summary for days 1-3 + license_marker: Global Flood Monitoring product +domains: [Water Resources] +data_types: [Raster] +tasks: [Monitoring] +difficulty: intermediate +geography: [Global] +temporal_coverage: dated days-one-to-three flood forecast summary +update_frequency: daily +provider: Copernicus Emergency Management Service +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + GloFAS publishes the sumAL41EGE forecast-summary WMS layer used to target follow-up checks. + Start with a small current-day tile; a forecast is not observed flooding or a local warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the GloFAS WMS capabilities and CEMS reuse terms. + - Fetch a small dated sumAL41EGE tile. + - Compare any forecast signal with independent observed and official information. + python: + packages: [requests] + code: | + from datetime import datetime, timezone + import requests + + valid_day = datetime.now(timezone.utc).strftime("%Y-%m-%dT00:00Z") + response = requests.get( + "https://ows.globalfloods.eu/glofas-ows/ows.py", + params={"SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetMap", + "LAYERS": "sumAL41EGE", "STYLES": "default", "SRS": "EPSG:4326", + "BBOX": "5,45,5.1,45.1", "WIDTH": 32, "HEIGHT": 32, + "FORMAT": "image/tiff", "TIME": valid_day}, timeout=20, + ) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*"), "Expected GeoTIFF" + print(valid_day, "GloFAS forecast bytes:", len(response.content)) + first_project: + title: Inspect a Flood-Outlook Tile + goal: Display a small forecast-summary tile with its date and bounds. + steps: + - Fetch the current-day GloFAS WMS tile. + - Label its forecast date and map extent. + - Explain that a forecast alone does not establish current local flooding. diff --git a/data/datasets/copernicus-rapid-mapping-activations.yaml b/data/datasets/copernicus-rapid-mapping-activations.yaml new file mode 100644 index 0000000..de8c8e3 --- /dev/null +++ b/data/datasets/copernicus-rapid-mapping-activations.yaml @@ -0,0 +1,56 @@ +id: copernicus-rapid-mapping-activations +name: Copernicus Rapid Mapping Activations +description: > + Public emergency-mapping activation metadata and product references for dated disaster-response context tools. +theme: Environment & Hazards +url: https://mapping.emergency.copernicus.eu/about/how-to-harvest-cems-mapping-data/emergency-response-data/ +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: > + Public CEMS mapping information may be reused with source and modification attribution; sensitive activations can be restricted. +license_url: https://mapping.emergency.copernicus.eu/terms-and-conditions/ +url_checks: + source_marker: Copernicus EMS Rapid Mapping API provides a programmatic interface + license_marker: free, full and open access to Copernicus Service Information +domains: [Emergency Management] +data_types: [Events] +tasks: [Monitoring] +difficulty: beginner +geography: [Global] +temporal_coverage: public emergency mapping activations and product metadata +update_frequency: near real time +provider: Copernicus Emergency Management Service +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + The public Rapid Mapping API lists activations and offers detail records and product links. + Start with one activation; its existence does not establish current warning coverage at a location. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the public activation API documentation and CEMS reuse terms. + - Request one activation from the public listing. + - Keep event and update timestamps separate from present hazard status. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://rapidmapping.emergency.copernicus.eu/backend/dashboard-api/public-activations-info/", + params={"limit": 1, "offset": 0}, timeout=25, + ) + response.raise_for_status() + for activation in response.json()["results"]: + print(activation["code"], activation["name"], activation["eventTime"]) + first_project: + title: Inspect a Public Activation + goal: Display one mapped emergency event with its activation identifier and event time. + steps: + - Fetch one public activation record. + - Show the identifier, event date, and affected country. + - Explain that an activation is not a current local warning. diff --git a/data/datasets/cwfif-active-wildland-fires.yaml b/data/datasets/cwfif-active-wildland-fires.yaml new file mode 100644 index 0000000..1d47142 --- /dev/null +++ b/data/datasets/cwfif-active-wildland-fires.yaml @@ -0,0 +1,76 @@ +id: cwfif-active-wildland-fires +name: CWFIF Active Wildland Fires +description: > + Canadian active-wildfire records from NRCan CWFIF for inspecting fire + identifiers, status, size, and reported location. +theme: Environment & Hazards +url: https://geoserver.cwfif.nrcan.gc.ca/geoserver/wfs?service=WFS&version=2.0.0&request=GetCapabilities +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON +license: Open Government Licence Canada 2.0 with Natural Resources Canada attribution. +license_url: https://open.canada.ca/en/open-government-licence-canada +url_checks: + source_marker: cwfif_national_activefires + license_marker: Open Government Licence +domains: + - Natural Hazards + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Mapping +difficulty: beginner +geography: + - Canada +temporal_coverage: active wildland fires since 2010 +update_frequency: near real time +provider: Natural Resources Canada CWFIF +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + NRCan's current CWFIF WFS offers active wildland-fire features under + public:cwfif_national_activefires. Start with three GeoJSON features + in EPSG:4326. A reported active-fire point is context; it does not by + itself prove smoke origin, local exposure, or an evacuation area. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official WFS capabilities and Canadian licence. + - Request three active-fire features with explicit geographic coordinates. + - Inspect fire ID, prescribed status, and report time. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://geoserver.cwfif.nrcan.gc.ca/geoserver/wfs", + params={"service": "WFS", "version": "2.0.0", "request": "GetFeature", + "typeNames": "public:cwfif_national_activefires", + "outputFormat": "application/json", "srsName": "EPSG:4326", "count": 3}, + timeout=30, + ) + response.raise_for_status() + for fire in response.json()["features"][:3]: + row = fire["properties"] + print(row.get("national_fire_id"), row.get("fire_size"), + row.get("fire_was_prescribed")) + first_project: + title: Inspect Canadian Active Fires + goal: Review three official fire records before regional context mapping. + steps: + - Keep fire ID, report time, size, and prescribed-fire flag. + - Check freshness and geometry before mapping incidents. + - Explain why an active-fire record is not a smoke-source attribution. diff --git a/data/datasets/cwfis-m3-perimeter-estimates.yaml b/data/datasets/cwfis-m3-perimeter-estimates.yaml new file mode 100644 index 0000000..c015f1a --- /dev/null +++ b/data/datasets/cwfis-m3-perimeter-estimates.yaml @@ -0,0 +1,73 @@ +id: cwfis-m3-perimeter-estimates +name: CWFIS M3 Perimeter Estimates +description: > + Canadian M3 estimated wildfire perimeters from NRCan CWFIS for showing + approximate fire-footprint context. +theme: Environment & Hazards +url: https://cwfis.cfs.nrcan.gc.ca/geoserver/public/ows?service=WFS&version=2.0.0&request=GetCapabilities +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON +license: Open Government Licence Canada 2.0 with Natural Resources Canada attribution. +license_url: https://open.canada.ca/en/open-government-licence-canada +url_checks: + source_marker: public:m3polygons + license_marker: Open Government Licence +domains: + - Natural Hazards + - Emergency Management +data_types: + - Geospatial +tasks: + - Mapping + - Monitoring +difficulty: beginner +geography: + - Canada +temporal_coverage: M3 fire-perimeter estimates since 2003 +update_frequency: daily +provider: Natural Resources Canada CWFIS +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The legacy CWFIS WFS serves public:m3polygons, an M3 perimeter-estimate + layer distinct from reported incident points and authoritative evacuation + boundaries. Start with three GeoJSON features and retain their estimated + dates. NRCan's 2026 service placemat identifies this layer by name. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official CWFIS service catalogue and Canadian open licence. + - Request three M3 polygon features from the named WFS layer. + - Inspect estimate dates and geometry before rendering. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://cwfis.cfs.nrcan.gc.ca/geoserver/public/ows", + params={"service": "WFS", "version": "2.0.0", "request": "GetFeature", + "typeNames": "public:m3polygons", "outputFormat": "application/json", + "srsName": "EPSG:4326", "count": 3}, timeout=30, + ) + response.raise_for_status() + for estimate in response.json()["features"][:3]: + row = estimate["properties"] + print(row.get("uid"), row.get("lastdate"), row.get("area")) + first_project: + title: Inspect Canadian M3 Footprints + goal: Review three estimated fire footprints before map rendering. + steps: + - Keep polygon ID, estimate date, and stated area. + - Compare footprint age with current incident reports. + - Explain why an M3 estimate is not a surveyed perimeter or evacuation map. diff --git a/data/datasets/dhmz-cap-warnings.yaml b/data/datasets/dhmz-cap-warnings.yaml new file mode 100644 index 0000000..5bcfb14 --- /dev/null +++ b/data/datasets/dhmz-cap-warnings.yaml @@ -0,0 +1,71 @@ +id: dhmz-cap-warnings +name: DHMZ Croatia CAP Warnings +description: > + Croatian weather warnings published as CAP XML by DHMZ for reading official + warning severity, geography, and validity. +theme: Environment & Hazards +url: https://meteo.hr/proizvodi.php?section=podaci¶m=xml_korisnici +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - XML +license: Croatian Open Licence; DHMZ attribution is required. +license_url: https://meteo.hr/proizvodi.php?section=podaci¶m=xml_korisnici +url_checks: + source_marker: cap_hr_today.xml + license_marker: Otvorenom dozvolom +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Croatia +temporal_coverage: current daily CAP warning files +update_frequency: daily +provider: Croatian Meteorological and Hydrological Service +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + DHMZ lists freely reusable Croatian CAP warning files with attribution. + Start with today's CAP XML file and inspect its message ID, status and + issue time. A feed may contain updates or cancellations; check validity + and mapped area before displaying any warning. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official DHMZ XML file list and open-licence statement. + - Download today's CAP file, retaining its source URL and retrieval time. + - Inspect CAP status and geography before treating it as a current warning. + python: + packages: + - requests + code: | + import xml.etree.ElementTree as ET + import requests + + response = requests.get("https://meteo.hr/upozorenja/cap_hr_today.xml", timeout=30) + response.raise_for_status() + root = ET.fromstring(response.content) + cap = "{urn:oasis:names:tc:emergency:cap:1.2}" + print(root.findtext(f"{cap}identifier"), root.findtext(f"{cap}status"), + root.findtext(f"{cap}sent")) + first_project: + title: Inspect One Croatian CAP Message + goal: Check an official warning file for a small regional alert display. + steps: + - Keep CAP identifier, issue time, status, type, and affected area. + - Account for update and cancel messages before displaying severity. + - Explain why a downloaded CAP message alone does not prove local applicability. diff --git a/data/datasets/dpc-italy-flood-bulletins.yaml b/data/datasets/dpc-italy-flood-bulletins.yaml new file mode 100644 index 0000000..fedba57 --- /dev/null +++ b/data/datasets/dpc-italy-flood-bulletins.yaml @@ -0,0 +1,82 @@ +id: dpc-italy-flood-bulletins +name: Italian DPC Flood-Criticality Bulletins +description: > + Daily national hydrogeological and hydraulic criticality bulletins from + Italy's Civil Protection Department for mapped alert-zone context. +theme: Environment & Hazards +url: https://github.com/pcm-dpc/DPC-Bollettini-Criticita-Idrogeologica-Idraulica +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - TopoJSON +license: CC BY 4.0 with Italian Civil Protection Department attribution. +license_url: https://github.com/pcm-dpc/DPC-Bollettini-Criticita-Idrogeologica-Idraulica/blob/master/LICENSE +url_checks: + source_marker: Bollettini di Criticità Idrogeologica e Idraulica Nazionale + license_marker: Creative Commons Attribution 4.0 +domains: + - Hydrology + - Emergency Management +data_types: + - Geospatial + - Event Data +tasks: + - Mapping + - Alerting +difficulty: intermediate +geography: + - Italy +temporal_coverage: daily today and tomorrow bulletins with revisions +update_frequency: daily +provider: Italian Civil Protection Department +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The DPC GitHub repository publishes a national criticality bulletin daily + and can add corrections. Start with one current today/tomorrow TopoJSON + file from the latest bulletin commit. A forecast criticality zone is not + a point flood measurement; retain issue and revision context. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the DPC repository's update schedule and CC BY licence. + - Find the latest commit touching the topojson bulletin directory. + - Fetch one current bulletin file from that exact commit. + python: + packages: + - requests + code: | + import re + import requests + + repo = "https://api.github.com/repos/pcm-dpc/DPC-Bollettini-Criticita-Idrogeologica-Idraulica" + headers = {"User-Agent": "TrilemmaDataCatalogExample/1.0"} + commits = requests.get(f"{repo}/commits", params={"path": "files/topojson", "per_page": 1}, + headers=headers, timeout=30) + commits.raise_for_status() + sha = commits.json()[0]["sha"] + detail = requests.get(f"{repo}/commits/{sha}", headers=headers, timeout=30) + detail.raise_for_status() + files = [item["filename"] for item in detail.json()["files"] + if item["status"] != "removed" and re.fullmatch( + r"files/topojson/\d{8}_\d{4}_(today|tomorrow)\.json", item["filename"])] + if not files: + raise RuntimeError("Latest bulletin commit has no current TopoJSON file") + url = f"https://raw.githubusercontent.com/pcm-dpc/DPC-Bollettini-Criticita-Idrogeologica-Idraulica/{sha}/{files[0]}" + bulletin = requests.get(url, timeout=30) + bulletin.raise_for_status() + print(files[0], list(bulletin.json().get("objects", {}))[:5]) + first_project: + title: Inspect One Italian Criticality Bulletin + goal: Check one official daily zone artifact before local hazard matching. + steps: + - Retain commit SHA, bulletin filename, publication date, and zone IDs. + - Prefer later corrections to earlier files for the same validity day. + - Explain why forecast zones do not confirm a flood at a destination. diff --git a/data/datasets/dwd-cap-warnings.yaml b/data/datasets/dwd-cap-warnings.yaml new file mode 100644 index 0000000..b0c5268 --- /dev/null +++ b/data/datasets/dwd-cap-warnings.yaml @@ -0,0 +1,75 @@ +id: dwd-cap-warnings +name: DWD Germany CAP Warnings +description: > + Official German weather-warning CAP files from DWD for monitoring current + municipal alert status and affected area. +theme: Environment & Hazards +url: https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_EVENT_STAT/ +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - ZIP + - XML +license: CC BY 4.0 with Deutscher Wetterdienst attribution. +license_url: https://www.dwd.de/EN/service/legal_notice/legal_notice_node.html +url_checks: + source_marker: Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMEVENT_COMMUNEUNION_EN.zip + license_marker: Creative Commons licence conditions +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Germany +temporal_coverage: current CAP warning status snapshots +update_frequency: near real time +provider: Deutscher Wetterdienst +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + DWD publishes versioned and latest CAP ZIP snapshots for German municipal + warnings. Start with one latest English status ZIP and list at most five + contained files. An empty ZIP is a valid current state, not a provider + outage or a general all-clear outside the product's reviewed coverage. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read DWD's CAP directory, profile documentation, and attribution terms. + - Download one latest English status ZIP. + - Inspect CAP status, revision, and geometry before any alert display. + python: + packages: + - requests + code: | + from io import BytesIO + from zipfile import ZipFile + import requests + + url = ("https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_EVENT_STAT/" + "Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMEVENT_COMMUNEUNION_EN.zip") + response = requests.get(url, timeout=30) + response.raise_for_status() + with ZipFile(BytesIO(response.content)) as archive: + names = archive.namelist() + print(f"{len(names)} CAP files in the current status ZIP") + print(names[:5]) + first_project: + title: Inspect German CAP Status + goal: Check a bounded official warning snapshot before local matching. + steps: + - Retain CAP identifiers, message status, update references, and regions. + - Handle cancellations and empty current snapshots correctly. + - Explain why a snapshot does not cover every kind of civil emergency. diff --git a/data/datasets/eaws-avalanche-regions.yaml b/data/datasets/eaws-avalanche-regions.yaml new file mode 100644 index 0000000..7bc4ed9 --- /dev/null +++ b/data/datasets/eaws-avalanche-regions.yaml @@ -0,0 +1,55 @@ +id: eaws-avalanche-regions +name: EAWS Avalanche Microregions +description: > + European avalanche warning-region polygons for matching mountain destinations to regional bulletins across published areas. +theme: Geospatial & Infrastructure +url: https://eaws.gitlab.io/eaws-regions/micro-regions/AT-02_micro-regions.geojson.json +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.02 +formats: [GeoJSON] +license: CC0 1.0 Universal; the EAWS source still merits attribution when combining its geometry with a bulletin. +license_url: https://gitlab.com/api/v4/projects/eaws%2Feaws-regions/repository/files/LICENSE/raw?ref=master +url_checks: + source_marker: AT-02_micro-regions + license_marker: CC0 1.0 Universal +domains: [Natural Hazards] +data_types: [Geospatial] +tasks: [Mapping] +difficulty: beginner +geography: [Europe] +temporal_coverage: current EAWS warning-region boundaries +update_frequency: occasional +provider: European Avalanche Warning Services +source_type: nonprofit +last_verified: 2026-09-28 +getting_started: + overview: > + EAWS publishes a maintained composite GeoJSON and smaller country or + subregion partitions. Start with the AT-02 partition and two polygons; + matching a destination to a polygon does not establish that a bulletin + is active or applicable at its exact location. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the EAWS geometry index and source-repository CC0 licence. + - Download one bounded microregion partition. + - Inspect feature IDs and geometry before joining to bulletins. + python: + packages: [requests] + code: | + import requests + + url = "https://eaws.gitlab.io/eaws-regions/micro-regions/AT-02_micro-regions.geojson.json" + response = requests.get(url, timeout=20) + response.raise_for_status() + for region in response.json()["features"][:2]: + print(region["properties"].get("id"), region["geometry"]["type"]) + first_project: + title: Match Avalanche Regions + goal: Inspect two EAWS microregions before joining bulletin coverage. + steps: + - Download one partition and retain its region IDs. + - Compare a destination coordinate with candidate polygons. + - Explain why a geometry match is not a current avalanche warning. diff --git a/data/datasets/eccc-aqhi-observations.yaml b/data/datasets/eccc-aqhi-observations.yaml new file mode 100644 index 0000000..13843f4 --- /dev/null +++ b/data/datasets/eccc-aqhi-observations.yaml @@ -0,0 +1,72 @@ +id: eccc-aqhi-observations +name: ECCC Air Quality Health Index +description: > + Real-time Canadian AQHI observations from ECCC for reviewing health-risk + index readings at reporting regions and stations. +theme: Environment & Hazards +url: https://api.weather.gc.ca/collections/aqhi-observations-realtime?f=json +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON +license: Open Government Licence Canada 2.0 with Environment and Climate Change Canada attribution. +license_url: https://open.canada.ca/en/open-government-licence-canada +url_checks: + source_marker: aqhi-observations-realtime + license_marker: Open Government Licence +domains: + - Public Health + - Weather +data_types: + - Geospatial + - Time Series +tasks: + - Monitoring +difficulty: beginner +geography: + - Canada +temporal_coverage: current preliminary AQHI observations +update_frequency: near real time +provider: Environment and Climate Change Canada +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + ECCC's GeoMet collection exposes preliminary AQHI observations as + GeoJSON. Start with five latest features, retaining their observation + times and AQHI scale. AQHI is a Canadian health-risk index and is not + interchangeable with a U.S. EPA AQI or an individual pollutant value. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official AQHI collection description and Canadian open licence. + - Request five latest GeoJSON items in one call. + - Inspect observation time, geometry, and AQHI property. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://api.weather.gc.ca/collections/aqhi-observations-realtime/items", + params={"f": "json", "latest": "true", "limit": 5}, timeout=30, + ) + response.raise_for_status() + data = response.json() + for item in data["features"][:5]: + print(item["id"], item["properties"].get("aqhi"), + item["properties"].get("observation_datetime")) + first_project: + title: Inspect Canadian AQHI Readings + goal: Review five reported index features before local display. + steps: + - Keep feature ID, AQHI scale value, location, and observation time. + - Check freshness and regional scope before matching a destination. + - Explain why AQHI cannot be relabeled as U.S. AQI. diff --git a/data/datasets/eccc-firework-smoke.yaml b/data/datasets/eccc-firework-smoke.yaml new file mode 100644 index 0000000..15fe05a --- /dev/null +++ b/data/datasets/eccc-firework-smoke.yaml @@ -0,0 +1,60 @@ +id: eccc-firework-smoke +name: ECCC FireWork Smoke Forecast +description: > + Environment and Climate Change Canada's wildfire-smoke concentration forecast for dated regional smoke-context tools. +theme: Environment & Hazards +url: https://www.weather.gc.ca/firework/index_e.html +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 1 +formats: [GeoTIFF] +license: Open Government Licence Canada; credit Environment and Climate Change Canada and retain forecast time. +license_url: https://open.canada.ca/en/open-government-licence-canada +url_checks: + source_marker: Wildfire smoke fine particulate matter + license_marker: Open Government Licence - Canada +domains: [Air Quality] +data_types: [Geospatial, Time Series] +tasks: [Monitoring] +difficulty: intermediate +geography: [North America] +temporal_coverage: current dated smoke forecast cycles +update_frequency: near real time +provider: Environment and Climate Change Canada +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + GeoMet WCS serves FireWork's RAQDPS surface wildfire-smoke PM2.5 layer as GeoTIFF. + Start with a one-degree coverage request. Values are modeled mass concentrations + in kg/m3, not observed AQI; retain the valid and model-run times for decisions. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read ECCC's FireWork forecast and Open Government Licence pages. + - Request a small GeoTIFF coverage for the exact wildfire-smoke layer. + - Inspect the model units and dated WCS dimensions before displaying values. + python: + packages: [requests] + code: | + import requests + + params = [ + ("SERVICE", "WCS"), ("VERSION", "2.0.1"), + ("REQUEST", "GetCoverage"), + ("COVERAGEID", "RAQDPS.Sfc_PM2.5-WildfireSmokePlume"), + ("FORMAT", "image/tiff"), ("SUBSETTINGCRS", "EPSG:4326"), + ("SUBSET", "x(-76,-75)"), ("SUBSET", "y(45,46)"), + ] + response = requests.get("https://geo.weather.gc.ca/geomet", params=params, timeout=30) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*") + print("FireWork GeoTIFF bytes:", len(response.content)) + first_project: + title: Inspect a FireWork Smoke Coverage + goal: Show a small, dated FireWork smoke-model view with clear units and provenance. + steps: + - Request one GeoTIFF coverage over a small area. + - Read its model and valid times before comparing forecast values. + - Explain why modeled PM2.5 cannot be labeled as a local monitor observation. diff --git a/data/datasets/eea-air-quality-index-stations.yaml b/data/datasets/eea-air-quality-index-stations.yaml new file mode 100644 index 0000000..7f2db5c --- /dev/null +++ b/data/datasets/eea-air-quality-index-stations.yaml @@ -0,0 +1,64 @@ +id: eea-air-quality-index-stations +name: EEA Air Quality Index Stations +description: > + European Environment Agency hourly station AQI details for building a measured air-quality context view. +theme: Environment & Hazards +url: https://dis2datalake.blob.core.windows.net/airquality-derivated/AQI-noRunningMeans/current/AT60118.json +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.003 +formats: [JSON] +license: EEA material is CC BY with EEA attribution; check station-level third-party notices and do not distort values. +license_url: https://www.eea.europa.eu/en/legal-notice +url_checks: + source_marker: '"modelled_O3":0,"modelled_NO2":0' + license_marker: EEA materials are published under the CC-BY license +domains: [Air Quality] +data_types: [Time Series] +tasks: [Monitoring] +difficulty: beginner +geography: [Europe] +temporal_coverage: recent hourly station observations and model context +update_frequency: near real time +provider: European Environment Agency +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + The EEA Air Quality Index publishes a station metadata index, hourly map, + and per-station detail JSON. Start with one reviewed Austrian station and + two hours; modeled gap fills must not be presented as measurements, and + one station does not establish destination-wide air quality. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the EEA AQI methodology and legal notice. + - Fetch one station-detail artifact from the official AQI data lake. + - Inspect the observation and modeled flags for two hourly records. + python: + packages: [requests] + code: | + import requests + from datetime import datetime, timezone + + url = ("https://dis2datalake.blob.core.windows.net/airquality-derivated/" + "AQI-noRunningMeans/current/AT60118.json") + response = requests.get(url, timeout=20) + response.raise_for_status() + now = datetime.now(timezone.utc) + observed = [] + for hour, row in response.json().items(): + pollutant = row.get("culprit") + if (pollutant and datetime.fromisoformat(hour.replace("Z", "+00:00")) <= now + and row.get(f"modelled_{pollutant}") == 0): + observed.append((hour, row)) + for hour, row in sorted(observed)[-2:]: + print(hour, row.get("aqi"), row.get("culprit")) + first_project: + title: Inspect Station AQI Context + goal: Compare two station hours while retaining modeled-value provenance. + steps: + - Fetch one station's dated hourly values. + - Display the culprit pollutant and model flag beside AQI. + - Explain why a modeled fill or one station is not a local measurement. diff --git a/data/datasets/effis-active-fire-hotspots.yaml b/data/datasets/effis-active-fire-hotspots.yaml new file mode 100644 index 0000000..30df176 --- /dev/null +++ b/data/datasets/effis-active-fire-hotspots.yaml @@ -0,0 +1,60 @@ +id: effis-active-fire-hotspots +name: EFFIS Active Fire Hotspots +description: > + Filtered MODIS and VIIRS thermal-detection layers for current European wildfire discovery and corroboration. +theme: Environment & Hazards +url: https://forest-fire.emergency.copernicus.eu/about-effis/technical-background/active-fire-detection +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GeoTIFF] +license: > + EFFIS EU-owned presentation and filtering are CC BY 4.0 unless marked otherwise; underlying NASA FIRMS detections require their own source credit. +license_url: https://forest-fire.emergency.copernicus.eu/about-effis/data-license +url_checks: + source_marker: EFFIS uses the active fire detection provided by the NASA FIRMS + license_marker: Creative Commons Attribution 4.0 International +domains: [Wildfires] +data_types: [Raster] +tasks: [Monitoring] +difficulty: intermediate +geography: [Europe] +temporal_coverage: recent filtered satellite thermal detections +update_frequency: near real time +provider: Copernicus Emergency Management Service EFFIS +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + EFFIS filters FIRMS thermal detections into its all.hs active-fire WMS layer. + Start with a small map tile; a hotspot may be another heat source and is not a confirmed perimeter. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read EFFIS's detection methodology and credit both EFFIS and FIRMS. + - Request a small all.hs image from the public WMS. + - Keep sensor, time, and false-positive limits visible when interpreting hotspots. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://maps.effis.emergency.copernicus.eu/effis", + params={"SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetMap", + "LAYERS": "all.hs", "STYLES": "default", "SRS": "EPSG:4326", + "BBOX": "5,45,6,46", "WIDTH": 32, "HEIGHT": 32, + "FORMAT": "image/tiff"}, + timeout=25, + ) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*"), "Expected GeoTIFF" + print("EFFIS hotspot GeoTIFF bytes:", len(response.content)) + first_project: + title: Inspect an Active-Fire Layer + goal: Display a bounded thermal-detection tile as discovery context. + steps: + - Fetch one all.hs WMS tile. + - Label the geographic bounds and EFFIS/FIRMS attribution. + - Explain detection delays and why a thermal anomaly is not a verified wildfire. diff --git a/data/datasets/effis-burned-area-perimeters.yaml b/data/datasets/effis-burned-area-perimeters.yaml new file mode 100644 index 0000000..d739256 --- /dev/null +++ b/data/datasets/effis-burned-area-perimeters.yaml @@ -0,0 +1,59 @@ +id: effis-burned-area-perimeters +name: EFFIS Burned-Area Perimeters +description: > + Near-real-time European burned-area polygons for corroborating recent wildfire detections against mapped perimeters. +theme: Environment & Hazards +url: https://forest-fire.emergency.copernicus.eu/applications/data-and-services +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GML] +license: > + EU-owned EFFIS content is CC BY 4.0 unless marked otherwise; credit EFFIS and any identified underlying provider. +license_url: https://forest-fire.emergency.copernicus.eu/about-effis/data-license +url_checks: + source_marker: real-time updated Burnt Areas database + license_marker: Creative Commons Attribution 4.0 International +domains: [Wildfires] +data_types: [Geospatial] +tasks: [Monitoring] +difficulty: intermediate +geography: [Europe] +temporal_coverage: recent EFFIS mapped burned areas +update_frequency: near real time +provider: Copernicus Emergency Management Service EFFIS +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + EFFIS exposes effis.nrt.ba.poly polygons through its WFS, separately from thermal-detection points. + Start with one bounded feature request; an empty result is not proof of no fires. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review EFFIS's burned-area service and attribution rules. + - Request at most one effis.nrt.ba.poly feature in a small bounding box. + - Keep mapping time and spatial coverage distinct from active-fire detections. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://maps.effis.emergency.copernicus.eu/effis", + params={"service": "WFS", "version": "1.1.0", "request": "GetFeature", + "typeName": "effis.nrt.ba.poly", "maxFeatures": 1, + "bbox": "5,45,6,46,EPSG:4326"}, + timeout=25, + ) + response.raise_for_status() + assert b"FeatureCollection" in response.content[:4096] + print("EFFIS perimeter response bytes:", len(response.content)) + first_project: + title: Inspect a Recent Perimeter Query + goal: Query a bounded recent burned-area polygon layer. + steps: + - Request one feature at most in a small European bounding box. + - Record whether a polygon was returned and its geographic bounds. + - Explain that an empty query cannot establish an all-clear. diff --git a/data/datasets/effis-fire-danger-forecast.yaml b/data/datasets/effis-fire-danger-forecast.yaml new file mode 100644 index 0000000..72a6ded --- /dev/null +++ b/data/datasets/effis-fire-danger-forecast.yaml @@ -0,0 +1,61 @@ +id: effis-fire-danger-forecast +name: EFFIS Fire Danger Forecast +description: > + European Fire Weather Index forecast rasters for regional fire-danger context and dated hazard displays. +theme: Environment & Hazards +url: https://forest-fire.emergency.copernicus.eu/about-effis/technical-background/fire-danger-forecast +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GeoTIFF] +license: > + EU-owned EFFIS content is CC BY 4.0 unless individually marked otherwise; credit EFFIS and indicate changes. +license_url: https://forest-fire.emergency.copernicus.eu/about-effis/data-license +url_checks: + source_marker: fire danger forecast module of EFFIS + license_marker: Creative Commons Attribution 4.0 International +domains: [Wildfires] +data_types: [Raster] +tasks: [Monitoring] +difficulty: intermediate +geography: [Europe] +temporal_coverage: dated daily model forecasts +update_frequency: daily +provider: Copernicus Emergency Management Service EFFIS +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + EFFIS serves the modeled Fire Weather Index through the mf010.fwi WMS layer. + Start with a one-degree dated GeoTIFF; danger is a forecast, not evidence of an active fire. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review EFFIS's forecast methodology, web-service instructions, and reuse terms. + - Request a small dated mf010.fwi WMS image. + - Keep the requested date and geographic bounds with the raster. + python: + packages: [requests] + code: | + from datetime import date, timedelta + import requests + + response = requests.get( + "https://maps.effis.emergency.copernicus.eu/effis", + params={"SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetMap", + "LAYERS": "mf010.fwi", "STYLES": "default", "SRS": "EPSG:4326", + "BBOX": "5,45,6,46", "WIDTH": 32, "HEIGHT": 32, + "FORMAT": "image/tiff", "TIME": str(date.today() - timedelta(days=1))}, + timeout=25, + ) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*"), "Expected GeoTIFF" + print("EFFIS fire-danger GeoTIFF bytes:", len(response.content)) + first_project: + title: Show a Dated Fire-Danger Tile + goal: Display a small forecast tile with its date and bounds. + steps: + - Fetch one daily Fire Weather Index tile. + - Label the forecast date and geographic extent. + - Explain that a high index does not confirm an active fire. diff --git a/data/datasets/ehyd-current-flood-stages.yaml b/data/datasets/ehyd-current-flood-stages.yaml new file mode 100644 index 0000000..bd6dc80 --- /dev/null +++ b/data/datasets/ehyd-current-flood-stages.yaml @@ -0,0 +1,60 @@ +id: ehyd-current-flood-stages +name: eHYD Current Flood Stages +description: > + Austrian hydrographic station levels and stage codes for bounded, dated flood-context checks. +theme: Environment & Hazards +url: https://gis.lfrz.gv.at/api/geodata/i000501/ogc/features/v1/collections/i000501:pegel_aktuell?f=application%2Fjson +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GeoJSON] +license: > + The official eHYD OGC collection links to CC BY 4.0; credit the Austrian hydrographic service and note any changes. +license_url: https://creativecommons.org/licenses/by/4.0/ +url_checks: + source_marker: i000501:pegel_aktuell + license_marker: Attribution 4.0 International +domains: [Water Resources] +data_types: [Geospatial, Time Series] +tasks: [Monitoring] +difficulty: beginner +geography: [Austria] +temporal_coverage: current Austrian surface-water station values +update_frequency: near real time +provider: Austria eHYD Hydrographic Service +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + eHYD's pegel_aktuell collection publishes current station values and stage codes. + Start with one water-level feature; a raw level without its station-specific threshold is not a warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the eHYD OGC collection and its linked CC BY 4.0 licence. + - Request one water-level feature using the parameter filter. + - Keep its station, unit, timestamp, and code together. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://gis.lfrz.gv.at/api/geodata/i000501/ogc/features/v1/collections/i000501:pegel_aktuell/items", + params={"f": "application/geo+json", "limit": 1, + "filter-lang": "cql2-text", "filter": "parameter = 'W'"}, + timeout=20, + ) + response.raise_for_status() + for feature in response.json()["features"]: + station = feature["properties"] + print(station["messstelle"], station["wert"], station["einheit"], + station["zeitpunkt"], station["gesamtcode"]) + first_project: + title: Inspect One Austrian Gauge + goal: Display one dated water-level observation with its stage code. + steps: + - Fetch one W-parameter gauge feature. + - Show its value, unit, observation time, and stage code. + - Explain that local thresholds are needed to interpret the stage. diff --git a/data/datasets/emsc-earthquake-events.yaml b/data/datasets/emsc-earthquake-events.yaml new file mode 100644 index 0000000..c92e236 --- /dev/null +++ b/data/datasets/emsc-earthquake-events.yaml @@ -0,0 +1,74 @@ +id: emsc-earthquake-events +name: EMSC Seismic Portal Events +description: > + Preliminary EMSC earthquake event records through the FDSN service for + seismic discovery and comparison with other official event feeds. +theme: Environment & Hazards +url: https://seismicportal.eu/fdsn-wsevent.html +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON + - CSV +license: FDSN event service data are CC BY 4.0 with source attribution. +license_url: https://seismicportal.eu/fdsn-wsevent.html +url_checks: + source_marker: FDSN WS-EVENT API demonstration + license_marker: Creative Commons Attribution 4.0 International +domains: + - Seismology + - Emergency Management +data_types: + - Geospatial + - Time Series +tasks: + - Monitoring + - Risk Mapping +difficulty: intermediate +geography: + - Global +temporal_coverage: current and historical event catalogue +update_frequency: near real time +provider: European-Mediterranean Seismological Centre +source_type: nonprofit +last_verified: 2026-09-28 +getting_started: + overview: > + The EMSC FDSN event endpoint returns recent earthquakes as GeoJSON. Start + with only two events to inspect the event time, magnitude, and revision time. + Preliminary events can be corrected; they do not replace local intensity + products or establish comprehensive warning coverage. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the FDSN event service documentation and its CC BY licence statement. + - Request a bounded recent event sample in JSON format. + - Preserve event identifiers and last-update time when comparing revisions. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://www.seismicportal.eu/fdsnws/event/1/query", + params={"format": "json", "limit": 2}, timeout=30, + ) + response.raise_for_status() + for event in response.json()["features"]: + details = event["properties"] + print(event["id"], details["time"], details["mag"], + details["lastupdate"]) + first_project: + title: Compare Two Recent Earthquake Reports + goal: Test a bounded seismic-event fallback without treating it as an intensity forecast. + steps: + - Keep each event ID, source agency, event time, and last-update time. + - Compare locations and magnitudes with the primary USGS feed when available. + - Explain preliminary corrections and EMSC attribution requirements. diff --git a/data/datasets/england-flood-warnings.yaml b/data/datasets/england-flood-warnings.yaml new file mode 100644 index 0000000..fbf75d7 --- /dev/null +++ b/data/datasets/england-flood-warnings.yaml @@ -0,0 +1,72 @@ +id: england-flood-warnings +name: Environment Agency Flood Warnings +description: > + Current Environment Agency flood alerts and warnings for England for + mapping affected flood areas and monitoring official severity changes. +theme: Environment & Hazards +url: https://environment.data.gov.uk/flood-monitoring/doc/reference +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Open Government Licence v3.0 with Environment Agency attribution. +license_url: https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/ +url_checks: + source_marker: Environment Agency Real Time flood-monitoring API + license_marker: Open Government Licence +domains: + - Hydrology + - Emergency Management +data_types: + - Geospatial + - Event Data +tasks: + - Monitoring + - Alerting +difficulty: beginner +geography: + - England +temporal_coverage: current official flood alerts and warnings +update_frequency: near real time +provider: Environment Agency +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The Environment Agency's flood API lists current official alerts and + warnings, refreshed about every fifteen minutes. Start with five records + from one response and preserve severity and flood-area identifiers. + Warning geography is not equivalent to a nearby gauge measurement. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official API reference and Open Government Licence attribution. + - Fetch the current flood-warning list once. + - Inspect severity and flood-area IDs before mapping warnings. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://environment.data.gov.uk/flood-monitoring/id/floods", + timeout=30, + ) + response.raise_for_status() + for warning in response.json()["items"][:5]: + print(warning["floodAreaID"], warning["severity"], + warning.get("timeMessageChanged")) + first_project: + title: Inspect Current Flood Severities + goal: Check whether current warnings support a region-specific alert card. + steps: + - Keep flood-area identifiers, warning IDs, severity, and change times. + - Distinguish current warnings from withdrawn warnings and river readings. + - Explain why an empty feed does not establish safety outside a reviewed flood area. diff --git a/data/datasets/epa-cws-service-areas-v2-1.yaml b/data/datasets/epa-cws-service-areas-v2-1.yaml new file mode 100644 index 0000000..35b1ca0 --- /dev/null +++ b/data/datasets/epa-cws-service-areas-v2-1.yaml @@ -0,0 +1,63 @@ +id: epa-cws-service-areas-v2-1 +name: EPA Community Water Service Areas Version 2.1 +description: > + EPA's pinned community-water-system boundaries and census-block allocations for local drinking-water coverage analysis. +theme: Geospatial & Infrastructure +url: https://www.epa.gov/ground-water-and-drinking-water/public-water-system-service-areas +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.4 +size_gb_max: 1.1 +formats: [GeoPackage, CSV] +license: > + EPA-produced data are public domain unless otherwise specified; check source metadata + for state-supplied boundary limitations and cite EPA. Modeled areas are estimates. +license_url: https://edg.epa.gov/epa_data_license.html +url_checks: + source_marker: Public Water System Service Areas + license_marker: all data produced by the U.S EPA is by default in the public domain +domains: [Water Resources, Public Safety] +data_types: [Geospatial, Tabular] +tasks: [Mapping, Monitoring] +difficulty: intermediate +geography: [United States] +temporal_coverage: version 2.1 pinned by HouseHunter, released November 2025 +update_frequency: occasional +provider: U.S. Environmental Protection Agency +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + HouseHunter pins EPA's version 2.1 GeoPackage and matching 2020 Census block + allocation table from the EPA model's version history. Read only a few + allocation rows with an HTTP byte range. Version 3 is now current, so do + not silently mix it with the pinned version 2.1 or interpret modeled + boundaries as exact household service. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the EPA service-area documentation and public-domain notice. + - Fetch the beginning of the exact version 2.1 block allocation CSV. + - Keep the version 2.1 GeoPackage and block table together for full analysis. + python: + packages: [requests] + code: | + import csv + import io + import requests + + url = ("https://media.githubusercontent.com/media/USEPA/ORD_SAB_Model/" + "main/Version_History/2_1/Census_Tables/Blocks_V_2_1.csv") + response = requests.get(url, headers={"Range": "bytes=0-8191"}, timeout=30) + response.raise_for_status() + assert response.status_code == 206, "Server did not honor bounded byte range" + rows = csv.DictReader(io.StringIO(response.content.decode("utf-8", errors="ignore"))) + for row in list(rows)[:3]: + print(row["GEOID20"], row["PWSID"], row["Pop20_AW"]) + first_project: + title: Inspect One Water Service Allocation + goal: Identify the population allocation attached to a water system and census block. + steps: + - Read a few pinned version 2.1 block rows and retain their PWSIDs. + - Compare the matching boundary provenance before using the allocation. + - Explain why modeled service areas do not establish an exact household provider. diff --git a/data/datasets/epa-sdwis-bulk-submission.yaml b/data/datasets/epa-sdwis-bulk-submission.yaml new file mode 100644 index 0000000..b151841 --- /dev/null +++ b/data/datasets/epa-sdwis-bulk-submission.yaml @@ -0,0 +1,70 @@ +id: epa-sdwis-bulk-submission +name: EPA SDWIS Bulk Submission Archive +description: > + EPA Safe Drinking Water Act public-system and violation bulk tables for reproducible compliance analysis. +theme: Health, Food & Safety +url: https://echo.epa.gov/tools/data-downloads/sdwa-download-summary +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.3 +size_gb_max: 5.2 +formats: [ZIP, CSV] +license: > + EPA-produced data are public domain unless otherwise specified; cite EPA and + preserve submission-quarter, system, reporting, and data-quality limitations. +license_url: https://edg.epa.gov/epa_data_license.html +url_checks: + source_marker: SDWA_PUB_WATER_SYSTEMS.csv + license_marker: all data produced by the U.S EPA is by default in the public domain +domains: [Water Resources, Public Safety] +data_types: [Tabular, Time Series] +tasks: [Monitoring] +difficulty: intermediate +geography: [United States] +temporal_coverage: quarterly submissions, with HouseHunter pinned to 2026Q2 +update_frequency: quarterly +provider: U.S. Environmental Protection Agency +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + HouseHunter pins EPA's 2026Q2 SDWIS bulk ZIP, not the ECHO web-service + response. Start with a bounded byte range from the current official archive + to verify its ZIP member and submission quarter. The current URL may advance; + do not use a later quarter as if it were HouseHunter's pinned input. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read EPA's bulk-download dictionary and public-domain notice. + - Fetch a bounded first range of the official ZIP and inspect its first member. + - Download and pin the full archive only when you need to join system and violation tables. + python: + packages: [requests] + code: | + import csv + import io + import struct + import zlib + import requests + + response = requests.get( + "https://echo.epa.gov/files/echodownloads/SDWA_latest_downloads.zip", + headers={"Range": "bytes=0-131071"}, timeout=30, + ) + response.raise_for_status() + assert response.status_code == 206, "Server did not honor bounded byte range" + chunk = response.content + header = struct.unpack_from(" + Official 2024 NUTS regional polygons from Eurostat GISCO for mapping + statistical regions to geographic destinations under noncommercial terms. +theme: Geospatial & Infrastructure +url: https://ec.europa.eu/eurostat/web/gisco/geodata/statistical-units/territorial-units-statistics +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0.001 +size_gb_max: 0.1 +formats: + - GeoJSON + - Shapefile +license: Noncommercial use only, with GISCO and EuroGeographics boundary attribution. +license_url: https://ec.europa.eu/eurostat/web/gisco/geodata/statistical-units +url_checks: + source_marker: Territorial units for statistics + license_marker: the data will not be used for commercial purposes +domains: + - Geography + - Demographics +data_types: + - Geospatial + - Vector Data +tasks: + - Mapping + - Spatial Analysis +difficulty: intermediate +geography: + - Europe +temporal_coverage: 2024 NUTS reference geometry +update_frequency: occasional +provider: Eurostat GISCO +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + GISCO publishes versioned NUTS polygons, including the 2024 reference year. + The downloadable boundary data are licensed for noncommercial use only and + require GISCO and EuroGeographics attribution. Start with level-two region + identifiers from the 20M GeoJSON; polygons do not prove warning coverage. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the GISCO NUTS download rules and noncommercial licence conditions. + - Download the 2024 NUTS regional GeoJSON at 20M scale. + - Filter to level-two regions before intersecting destinations. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://gisco-services.ec.europa.eu/distribution/v2/nuts/geojson/" + "NUTS_RG_20M_2024_4326.geojson", timeout=30, + ) + response.raise_for_status() + regions = [ + item["properties"]["NUTS_ID"] for item in response.json()["features"] + if item["properties"]["LEVL_CODE"] == 2 + ] + print(regions[:5], len(regions)) + first_project: + title: Check Level-Two Regional Identifiers + goal: Evaluate noncommercial regional matching for a destination map. + steps: + - Keep the NUTS reference year, region ID, scale, and download date. + - Check one destination against the relevant level-two polygon. + - Add the required boundary attribution and avoid treating regions as warning footprints. diff --git a/data/datasets/fbi-cde-agency-summaries.yaml b/data/datasets/fbi-cde-agency-summaries.yaml new file mode 100644 index 0000000..b648aca --- /dev/null +++ b/data/datasets/fbi-cde-agency-summaries.yaml @@ -0,0 +1,61 @@ +id: fbi-cde-agency-summaries +name: FBI CDE Agency Crime Summaries +description: > + FBI Crime Data Explorer agency-level offense and reporting-population responses for cautious local safety comparisons. +theme: Government & Policy +url: https://cde.ucr.cjis.gov/LATEST/agency/byStateAbbr/RI +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.003 +formats: [JSON] +license: Publicly released FBI UCR data are public domain; cite the FBI and preserve agency reporting coverage. +license_url: https://ucr.fbi.gov/data_quality_guidelines +url_checks: + source_marker: '"ori":"RI0020100"' + license_marker: publicly-released UCR crime data are considered public domain +domains: [Crime, Public Safety] +data_types: [Time Series] +tasks: [Agency Comparison] +difficulty: intermediate +geography: [United States] +temporal_coverage: agency summaries for 2023-2025 in HouseHunter's pinned manifest +update_frequency: annual +provider: Federal Bureau of Investigation +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The CDE's agency catalog and summarized agency/offense endpoint are distinct + from the key-gated FBI state-estimates API. Start with one Rhode Island ORI + and one offense family. Participation and suppression can make agency or + county comparisons incomplete; a missing value is not zero crime. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the FBI CDE methodology and public-domain guidance. + - Fetch a small state agency catalog and choose one ORI. + - Inspect a dated offense summary and its reporting-population fields. + python: + packages: [requests] + code: | + import requests + + base = "https://cde.ucr.cjis.gov/LATEST" + catalog = requests.get(f"{base}/agency/byStateAbbr/RI", timeout=20) + catalog.raise_for_status() + agency = catalog.json()["KENT"][0] + summary = requests.get( + f"{base}/summarized/agency/{agency['ori']}/violent-crime", + params={"from": "01-2023", "to": "12-2025", "type": "totals"}, timeout=20, + ) + summary.raise_for_status() + series = next(iter(summary.json()["offenses"]["actuals"].values())) + print(agency["ori"], agency["agency_name"], series.get("01-2025")) + first_project: + title: Inspect Agency Crime Coverage + goal: Compare agency offense counts while retaining reporting coverage. + steps: + - Fetch one ORI and its dated violent-crime summary. + - Inspect the corresponding population and submission fields. + - Explain why voluntary reporting prevents treating null or suppressed counts as zero. diff --git a/data/datasets/fcc-bdc-county-fixed-summary.yaml b/data/datasets/fcc-bdc-county-fixed-summary.yaml new file mode 100644 index 0000000..785f665 --- /dev/null +++ b/data/datasets/fcc-bdc-county-fixed-summary.yaml @@ -0,0 +1,68 @@ +id: fcc-bdc-county-fixed-summary +name: FCC BDC County Fixed Broadband Summary +description: > + FCC Broadband Data Collection county-level fixed-availability summary tables for local service-coverage comparisons. +theme: Geospatial & Infrastructure +url: https://help.bdc.fcc.gov/hc/en-us/articles/10467446103579-How-to-Use-the-FCC-s-National-Broadband-Map +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.1 +formats: [ZIP, CSV] +license: > + FCC government works are not subject to domestic copyright protection and + the FCC requests credit; this public aggregate excludes restricted Location + Fabric records. Preserve the filing vintage and residential/technology filters. +license_url: https://opendata.fcc.gov/Wireline/Geography-Lookup-Table/v5vt-e7vw +url_checks: + source_marker: availability data for fixed broadband services + license_marker: proper credit be given +domains: [Infrastructure] +data_types: [Tabular] +tasks: [Mapping] +difficulty: intermediate +geography: [United States] +temporal_coverage: December 2025 filing pinned by HouseHunter; later filings are separate vintages +update_frequency: occasional +provider: Federal Communications Commission +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + HouseHunter pins the FCC's December 2025 Fixed Broadband Summary by + Geography Type for county 100/20 availability shares. Download that public + ZIP from the map's Data Download page, then read only a few rows locally. + Its share describes reported serviceable locations, not actual subscriptions, + performance, affordability, or all residents. + prerequisites: [Python 3.10 or newer, The pandas Python package, The public FCC December 2025 summary ZIP] + access_steps: + - Review the FCC's map download instructions and attribution notice. + - Download the December 2025 Fixed Broadband Summary by Geography Type ZIP from https://broadbandmap.fcc.gov/data-download and retain its dated filename. + - Keep the ZIP beside the Python script and inspect county rows without loading the whole file. + python: + packages: [pandas] + code: | + from pathlib import Path + from zipfile import ZipFile + import pandas as pd + + archive_path = Path("bdc_us_fixed_broadband_summary_by_geography_D25_03sep2026.zip") + with ZipFile(archive_path) as archive: + csv_name = next(name for name in archive.namelist() if name.endswith(".csv")) + with archive.open(csv_name) as stream: + for chunk in pd.read_csv(stream, chunksize=5000): + counties = chunk.loc[ + chunk["geography_type"].eq("County") & chunk["biz_res"].eq("R"), + ["geography_id", "technology", "speed_100_20"], + ] + if not counties.empty: + print(counties.head(3).to_string(index=False)) + break + first_project: + title: Inspect County Broadband Availability + goal: Read a few residential county 100/20 shares from the pinned FCC filing. + steps: + - Download and retain the dated December 2025 summary ZIP. + - Compare county rows only within the same residential and technology category. + - Explain why reported availability is not measured service quality or subscriptions. diff --git a/data/datasets/fcdo-travel-advice.yaml b/data/datasets/fcdo-travel-advice.yaml new file mode 100644 index 0000000..789ab49 --- /dev/null +++ b/data/datasets/fcdo-travel-advice.yaml @@ -0,0 +1,55 @@ +id: fcdo-travel-advice +name: FCDO Foreign Travel Advice +description: > + Published UK government country travel advice for building a destination briefing with dated safety context. +theme: Government & Policy +url: https://www.gov.uk/api/content/foreign-travel-advice/switzerland +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: Open Government Licence v3.0; acknowledge Crown copyright and check third-party material. +license_url: https://www.gov.uk/help/reuse-govuk-content +url_checks: + source_marker: FCDO travel advice for Switzerland + license_marker: Open Government Licence +domains: [Public Policy] +data_types: [Text] +tasks: [Monitoring] +difficulty: beginner +geography: [Global] +temporal_coverage: current country advice +update_frequency: occasional +provider: UK Foreign, Commonwealth & Development Office +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The GOV.UK Content API returns structured advice for one country path. + Start with Switzerland and inspect its update date; advice is not a + guarantee of safety or a substitute for the full official notice. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read GOV.UK's Content API documentation and reuse terms. + - Fetch one country's published advice by its GOV.UK path. + - Inspect the publication date and link to the complete advice. + python: + packages: [requests] + code: | + import requests + + url = "https://www.gov.uk/api/content/foreign-travel-advice/switzerland" + response = requests.get(url, timeout=20) + response.raise_for_status() + advice = response.json() + print(advice["title"], advice.get("public_updated_at")) + print("https://www.gov.uk" + advice["base_path"]) + first_project: + title: Build a Dated Country Briefing + goal: Show a country advice link and its latest publication timestamp. + steps: + - Fetch one country record and keep its source path. + - Display its update date beside a link to the full advice. + - Explain that official advice can change after the cached snapshot. diff --git a/data/datasets/fema-national-risk-index.yaml b/data/datasets/fema-national-risk-index.yaml new file mode 100644 index 0000000..b85c198 --- /dev/null +++ b/data/datasets/fema-national-risk-index.yaml @@ -0,0 +1,87 @@ +id: fema-national-risk-index +name: FEMA National Risk Index +description: > + FEMA tract and county natural-hazard risk and annualized-loss layers for comparing + residential hazard context and screening locations with consistent geographic units. +theme: Environment & Hazards +url: https://services.arcgis.com/XG15cJAlne2vxtgt/arcgis/rest/services/National_Risk_Index_Census_Tracts/FeatureServer +access_type: + - api + - download +api_key_required: false +free_to_access: true +size_gb_min: 0.000001 +size_gb_max: 5 +formats: + - JSON + - CSV + - GeoPackage +license: U.S. Government public data / federal copyright guidance +license_url: https://www.usa.gov/government-copyright +url_checks: + source_marker: National_Risk_Index_Census_Tracts (FeatureServer) + license_marker: federal government materials +domains: + - Natural Hazards + - Housing +data_types: + - Geospatial + - Numeric Data +tasks: + - Risk Assessment + - Mapping +difficulty: intermediate +geography: + - United States +temporal_coverage: periodically revised FEMA risk-model releases +update_frequency: occasional +provider: Federal Emergency Management Agency +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + FEMA publishes separate tract and county National Risk Index layers. Start + with five tract records from the official ArcGIS service and keep the NRI + version. The composite building-loss rate is modeled, not a prediction for an individual home. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Open FEMA's National Risk Index data resources and distinguish its tract and county layers. + - Query a bounded sample of the tract FeatureServer layer without geometry. + - Keep tract identifiers and the model version when comparing risk fields. + python: + packages: + - requests + code: | + import requests + + url = ( + "https://services.arcgis.com/XG15cJAlne2vxtgt/arcgis/rest/services/" + "National_Risk_Index_Census_Tracts/FeatureServer/0/query" + ) + response = requests.get( + url, + params={ + "where": "1=1", + "outFields": "TRACTFIPS,ALR_VALB,NRI_VER", + "returnGeometry": "false", + "resultRecordCount": 5, + "f": "json", + }, + timeout=30, + ) + response.raise_for_status() + result = response.json() + if "error" in result: + raise RuntimeError(result["error"]) + for feature in result["features"]: + print(feature["attributes"]) + first_project: + title: Compare Tract Hazard Context + goal: Test whether a bounded tract sample supports a location-screening prototype. + steps: + - Read the tract identifier, model version, and composite building-loss rate field. + - Compare only tracts from the same NRI version and keep missing values distinct from zero. + - Explain why a modeled tract loss rate cannot estimate the risk or insurance cost of a particular home. diff --git a/data/datasets/fintraffic-digitraffic-road-messages.yaml b/data/datasets/fintraffic-digitraffic-road-messages.yaml new file mode 100644 index 0000000..19664eb --- /dev/null +++ b/data/datasets/fintraffic-digitraffic-road-messages.yaml @@ -0,0 +1,74 @@ +id: fintraffic-digitraffic-road-messages +name: Fintraffic Digitraffic Road Messages +description: > + Current Finnish road-traffic announcements from Fintraffic for inspecting + accident-related closures and other mapped road disruptions. +theme: Geospatial & Infrastructure +url: https://www.digitraffic.fi/en/road-traffic/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.1 +formats: + - GeoJSON +license: CC BY 4.0; credit Fintraffic and preserve its required attribution and notices. +license_url: https://www.digitraffic.fi/en/terms-of-service/ +url_checks: + source_marker: Traffic messages + license_marker: Creative Commons 4.0 By license +domains: + - Transportation + - Infrastructure +data_types: + - Geospatial + - Real-Time Data +tasks: + - Monitoring + - Mapping +difficulty: intermediate +geography: + - Finland +temporal_coverage: current road traffic announcements +update_frequency: near real time +provider: Fintraffic +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + Digitraffic returns current road messages with mapped geometry. Begin by + counting a few announcement categories from one snapshot. The feed is not + complete route advice; inspect event type, validity, and geometry before + associating a closure with a destination. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Review the road-traffic documentation and CC BY attribution terms. + - Fetch one current v2 traffic-announcement GeoJSON response. + - Inspect event categories before filtering to accident-related closures. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://tie.digitraffic.fi/api/traffic-message/v2/traffic-announcements", + timeout=30, + ) + response.raise_for_status() + features = response.json()["features"] + for item in features[:5]: + properties = item["properties"] + print(properties["situationId"], properties["situationType"], + properties["releaseTime"]) + first_project: + title: Inspect Finnish Road Message Types + goal: Identify which live message categories could support a local disruption card. + steps: + - Count current messages by situation type and retain update timestamps. + - Check geometry and validity before labeling a message as local. + - Credit Fintraffic and explain why the feed is not complete routing advice. diff --git a/data/datasets/fmi-cap-warnings.yaml b/data/datasets/fmi-cap-warnings.yaml new file mode 100644 index 0000000..f109254 --- /dev/null +++ b/data/datasets/fmi-cap-warnings.yaml @@ -0,0 +1,71 @@ +id: fmi-cap-warnings +name: Finnish Meteorological Institute CAP Warnings +description: > + FMI weather-warning RSS and linked CAP messages for monitoring official + Finnish alert publications and validity. +theme: Environment & Hazards +url: https://alerts.fmi.fi/cap/profile/current/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - RSS + - CAP +license: Finnish Meteorological Institute open data under CC BY 4.0 attribution. +license_url: https://en.ilmatieteenlaitos.fi/open-data-licence +url_checks: + source_marker: FMI CAP Profile Version + license_marker: Creative Commons Attribution 4.0 +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Finland +temporal_coverage: current official alert publications +update_frequency: near real time +provider: Finnish Meteorological Institute +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + FMI provides a CAP-backed RSS feed of current Finnish warnings. Start with + one English feed response and inspect its channel update time and up to + five entries. An empty feed is not proof that every location is safe. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read FMI's CAP profile and CC BY open-data licence. + - Fetch the English RSS feed once and record its publication time. + - Follow a linked CAP message for full event, area, and validity details. + python: + packages: + - requests + code: | + import xml.etree.ElementTree as ET + import requests + + response = requests.get("https://alerts.fmi.fi/cap/feed/rss_en-GB.rss", timeout=30) + response.raise_for_status() + channel = ET.fromstring(response.content).find("channel") + print(channel.findtext("pubDate"), len(channel.findall("item"))) + for item in channel.findall("item")[:5]: + print(item.findtext("title"), item.findtext("link")) + first_project: + title: Inspect Current Finnish Warning Entries + goal: Test a small official warning index before mapping CAP areas. + steps: + - Keep feed publication time and each item's official CAP link. + - Check CAP issue, expiry, and affected geometry before display. + - Explain why the RSS index is not a complete local all-clear. diff --git a/data/datasets/foen-flood-warning-map.yaml b/data/datasets/foen-flood-warning-map.yaml new file mode 100644 index 0000000..099ccc5 --- /dev/null +++ b/data/datasets/foen-flood-warning-map.yaml @@ -0,0 +1,60 @@ +id: foen-flood-warning-map +name: FOEN National Flood Warning Map +description: > + Swiss federal flood-warning map layer for checking official warning levels near mapped destinations. +theme: Environment & Hazards +url: https://opendata.swiss/en/dataset/hochwasserwarnkarte +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [GeoTIFF] +license: > + The Swiss catalog marks this layer for unrestricted open use, including commercial analysis; source credit is recommended and geo.admin fair-use limits apply. +license_url: https://opendata.swiss/terms-of-use#terms_open +url_checks: + source_marker: ch.bafu.hydroweb-warnkarte_national + license_marker: diesen Datensatz für kommerzielle Zwecke nutzen +domains: [Water Resources] +data_types: [Raster] +tasks: [Monitoring] +difficulty: intermediate +geography: [Switzerland] +temporal_coverage: current national flood-warning map +update_frequency: near real time +provider: Swiss Federal Office for the Environment +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + FOEN publishes the ch.bafu.hydroweb-warnkarte_national layer through the federal WMS. + Start with a small map image; its warning colors are not direct gauge measurements. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the official flood-map catalog record and open-use condition. + - Request a bounded WMS image of the exact FOEN warning layer. + - Read its legend before assigning meanings to colors. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://wms.geo.admin.ch/", + params={"SERVICE": "WMS", "VERSION": "1.1.1", "REQUEST": "GetMap", + "LAYERS": "ch.bafu.hydroweb-warnkarte_national", + "STYLES": "default", "SRS": "EPSG:4326", + "BBOX": "5.9,45.8,10.6,47.9", "WIDTH": 64, "HEIGHT": 32, + "FORMAT": "image/tiff"}, timeout=25, + ) + response.raise_for_status() + assert response.content[:4] in (b"II*\x00", b"MM\x00*"), "Expected GeoTIFF" + print("FOEN warning-map bytes:", len(response.content)) + first_project: + title: Inspect a Swiss Flood-Warning Tile + goal: Display a small official warning-map image with its source and extent. + steps: + - Fetch the named FOEN WMS layer. + - Show its map bounds and official legend link. + - Explain that colors represent warnings, not measured water height. diff --git a/data/datasets/geofabrik-osm-extracts.yaml b/data/datasets/geofabrik-osm-extracts.yaml new file mode 100644 index 0000000..f06484b --- /dev/null +++ b/data/datasets/geofabrik-osm-extracts.yaml @@ -0,0 +1,86 @@ +id: geofabrik-osm-extracts +name: Geofabrik OpenStreetMap Extracts +description: > + Daily regional OpenStreetMap PBF extracts from Geofabrik for building local + place search, road networks, and other geographic products. +theme: Geospatial & Infrastructure +url: https://download.geofabrik.de/north-america/canada/prince-edward-island.html +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0.01 +size_gb_max: 100 +formats: + - PBF +license: OpenStreetMap contributors under the Open Database License 1.0; attribution and share-alike duties apply. +license_url: https://www.openstreetmap.org/copyright +url_checks: + source_marker: Download OpenStreetMap data for this region + license_marker: Open Data Commons Open Database License +domains: + - Geography + - Transportation +data_types: + - Geospatial + - Vector Data +tasks: + - Mapping + - Routing Analysis +difficulty: intermediate +geography: + - Global +temporal_coverage: current regional extracts with dated archives +update_frequency: daily +provider: Geofabrik GmbH and OpenStreetMap contributors +source_type: community +last_verified: 2026-09-28 +getting_started: + overview: > + Geofabrik republishes regional OpenStreetMap extracts as PBF files. Start + with Prince Edward Island rather than a national file and count road ways. + The extract is a dated community map, not a complete or authoritative road inventory. + prerequisites: + - Python 3.10 or newer + - An internet connection and about 20 MB of free disk space + - The requests and osmium Python packages + access_steps: + - Open the official Prince Edward Island extract page and note its update time. + - Download the latest PBF while preserving OpenStreetMap attribution and ODbL terms. + - Count a small class of features before building a local graph or search index. + python: + packages: + - requests + - osmium + code: | + from pathlib import Path + import osmium + import requests + + url = "https://download.geofabrik.de/north-america/canada/prince-edward-island-latest.osm.pbf" + path = Path("prince-edward-island-latest.osm.pbf") + with requests.get(url, stream=True, timeout=60) as response: + response.raise_for_status() + with path.open("wb") as output: + for chunk in response.iter_content(chunk_size=1024 * 1024): + output.write(chunk) + + class RoadCounter(osmium.SimpleHandler): + def __init__(self): + super().__init__() + self.count = 0 + + def way(self, way): + if "highway" in way.tags: + self.count += 1 + + roads = RoadCounter() + roads.apply_file(str(path)) + print(f"{roads.count} mapped road ways in this dated extract") + first_project: + title: Scope a Local Road Dataset + goal: Check whether one small OSM extract can support a local route-planning prototype. + steps: + - Record the extract's download time, region, file size, and required attribution. + - Count road ways and inspect which highway tags appear in the region. + - Explain why mapped ways are not proof of current road access or complete routing coverage. diff --git a/data/datasets/geonames-daily-gazetteer.yaml b/data/datasets/geonames-daily-gazetteer.yaml new file mode 100644 index 0000000..e70e378 --- /dev/null +++ b/data/datasets/geonames-daily-gazetteer.yaml @@ -0,0 +1,74 @@ +id: geonames-daily-gazetteer +name: GeoNames Daily Gazetteer Dumps +description: > + Daily place-name and coordinate dumps from GeoNames for building searchable + destination gazetteers with source attribution. +theme: Geospatial & Infrastructure +url: https://www.geonames.org/export/ +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0.001 +size_gb_max: 1 +formats: + - TSV + - ZIP +license: GeoNames attribution licence; credit GeoNames and review any source-specific restrictions. +license_url: https://www.geonames.org/export/ +url_checks: + source_marker: daily GeoNames database extract + license_marker: commercial usage is allowed +domains: + - Geography + - Places +data_types: + - Geospatial + - Tabular +tasks: + - Mapping + - Search +difficulty: intermediate +geography: + - Global +temporal_coverage: current gazetteer with daily dump updates +update_frequency: daily +provider: GeoNames +source_type: community +last_verified: 2026-09-28 +getting_started: + overview: > + GeoNames publishes daily place-name dumps. Start with the small Andorra + country archive and retain its attribution. Place names and representative + coordinates are imperfect and do not define exact administrative boundaries. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Review the official export terms and source attribution requirements. + - Download one small country archive rather than the global dump. + - Inspect the tab-separated place records and retain their GeoNames IDs. + python: + packages: + - requests + code: | + import csv + import io + from zipfile import ZipFile + import requests + + response = requests.get("https://download.geonames.org/export/dump/AD.zip", timeout=30) + response.raise_for_status() + archive = ZipFile(io.BytesIO(response.content)) + with archive.open("AD.txt") as file: + rows = csv.reader(io.TextIOWrapper(file, encoding="utf-8"), delimiter="\t") + for row in list(rows)[:5]: + print(row[0], row[1], row[4], row[5]) + first_project: + title: Inspect an Andorran Place Index + goal: Evaluate a bounded place-name dump for a destination search prototype. + steps: + - Keep GeoNames identifiers, names, coordinates, and download date. + - Compare the first five rows with their official GeoNames pages. + - Explain attribution duties and why point coordinates are not exact boundaries. diff --git a/data/datasets/hrsa-ahrf-county.yaml b/data/datasets/hrsa-ahrf-county.yaml new file mode 100644 index 0000000..1695dfa --- /dev/null +++ b/data/datasets/hrsa-ahrf-county.yaml @@ -0,0 +1,60 @@ +id: hrsa-ahrf-county +name: HRSA Area Health Resources Files County Data +description: > + HRSA's annually refreshed county health-resource archive for comparing clinician supply and health-system capacity. +theme: Health, Food & Safety +url: https://data.hrsa.gov/data/download?AHRF=&data=AHRF +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.02 +size_gb_max: 0.04 +formats: [ZIP, CSV] +license: HRSA lists no AHRF usage limitations; cite HRSA and check the variable definitions and source years. +license_url: https://data.hrsa.gov/data/data-sources?tab=DataUsage +url_checks: + source_marker: Area Health Resources Files (AHRF) + license_marker: National Center for Health Workforce Analysis (NCHWA) +domains: [Health Care] +data_types: [Tabular] +tasks: [Community Comparison] +difficulty: beginner +geography: [United States counties] +temporal_coverage: 2024-2025 AHRF release; variables have distinct source years +update_frequency: annual +provider: Health Resources and Services Administration +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + HRSA publishes a county CSV archive and records no usage limitation. Start with one + county row and a named clinician variable from the 2024-2025 release. The release + year is not every variable's measurement year, and supply does not prove access to care. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read HRSA's annual release details, data dictionary, and usage terms. + - Download the 2024-2025 county CSV archive from HRSA. + - Inspect the county identifier and one clinician-supply field. + python: + packages: [requests] + code: | + import csv + import io + import zipfile + import requests + + url = "https://data.hrsa.gov/DataDownload/AHRF/AHRF_2024-2025_CSV.zip" + response = requests.get(url, timeout=60) + response.raise_for_status() + with zipfile.ZipFile(io.BytesIO(response.content)) as archive: + name = next(n for n in archive.namelist() if n.endswith("AHRF2025.csv")) + with archive.open(name) as file: + row = next(csv.DictReader(io.TextIOWrapper(file, encoding="utf-8-sig"))) + print(row["fips_st_cnty"], row["phys_nf_prim_care_pc_exc_rsdt_23"]) + first_project: + title: Compare County Clinician Supply + goal: Compare one documented provider-supply variable across counties using a fixed AHRF release. + steps: + - Select the county FIPS and provider field from the release dictionary. + - Compare the same variable and measurement year across two counties. + - Explain why clinician counts do not establish appointment availability. diff --git a/data/datasets/ign-spain-earthquake-rss.yaml b/data/datasets/ign-spain-earthquake-rss.yaml new file mode 100644 index 0000000..5ad5b14 --- /dev/null +++ b/data/datasets/ign-spain-earthquake-rss.yaml @@ -0,0 +1,61 @@ +id: ign-spain-earthquake-rss +name: IGN Spain Earthquake RSS +description: > + Spain's official IGN earthquake event headlines and coordinates for regional seismic context tools. +theme: Environment & Hazards +url: https://www.ign.es/web/social-rss +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [XML] +license: > + IGN's public-sector information reuse terms permit reuse with attribution, + preserved update dates and metadata, and no distortion or implied endorsement; + geographic IGN products and services follow its CC BY-compatible user license. +license_url: https://www.ign.es/web/en/ign/portal/info-aviso-legal +url_checks: + source_marker: Información de terremotos + license_marker: Re-use of Public Sector Information +domains: [Earth Science, Emergency Management] +data_types: [Event Data, Geospatial] +tasks: [Monitoring] +difficulty: beginner +geography: [Spain] +temporal_coverage: recent official seismic notices +update_frequency: near real time +provider: Instituto Geográfico Nacional de España +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + IGN lists a public earthquake RSS feed in its own RSS directory. Fetch one + feed and inspect a few items; RSS headlines are regional event context, not + a complete alert lifecycle or proof that a destination is safe. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read IGN's RSS directory and public-sector reuse terms. + - Fetch the earthquake RSS feed once. + - Preserve each event's link, publication time, and any location metadata. + python: + packages: [requests] + code: | + import xml.etree.ElementTree as ET + import requests + + response = requests.get( + "https://www.ign.es/ign/RssTools/sismologia.xml", timeout=20, + ) + response.raise_for_status() + root = ET.fromstring(response.content) + for item in root.findall("./channel/item")[:3]: + print(item.findtext("title"), item.findtext("pubDate"), + item.findtext("link")) + first_project: + title: Review Recent Spanish Earthquakes + goal: Show a few dated IGN earthquake notices with source links. + steps: + - Fetch and parse the official RSS feed. + - Show the publication time and original IGN event link. + - Explain why a headline feed does not establish local warning coverage. diff --git a/data/datasets/imgw-current-hydrology.yaml b/data/datasets/imgw-current-hydrology.yaml new file mode 100644 index 0000000..205f036 --- /dev/null +++ b/data/datasets/imgw-current-hydrology.yaml @@ -0,0 +1,71 @@ +id: imgw-current-hydrology +name: IMGW Poland Current Hydrology +description: > + Current Polish river-station observations and official thresholds from IMGW + for checking stage exceedance at reviewed gauges. +theme: Environment & Hazards +url: https://danepubliczne.imgw.pl/api/data/hydro/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + Free public access for qualifying noncommercial analysis; commercial and + specified sectoral uses may require an IMGW agreement and payment. +license_url: https://danepubliczne.imgw.pl/ +url_checks: + source_marker: stan_ostrzegawczy + license_marker: REGULAMIN UDOSTĘPNIANIA DANYCH +domains: + - Hydrology + - Emergency Management +data_types: + - Time Series +tasks: + - Monitoring + - Alerting +difficulty: beginner +geography: + - Poland +temporal_coverage: current river-stage station observations +update_frequency: near real time +provider: Institute of Meteorology and Water Management +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + IMGW's public API returns river-stage measurements with official warning + and alarm thresholds. Free access is limited to qualifying noncommercial + analysis; commercial and specified sectoral uses can require a separate + agreement and payment. Start with five stations from one response. A + threshold crossing at one station is not a published area-wide warning. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read IMGW's current access regulation before reusing observations. + - Fetch one current hydrology API response. + - Inspect station ID, measurement time, stage, and warning threshold. + python: + packages: + - requests + code: | + import requests + + response = requests.get("https://danepubliczne.imgw.pl/api/data/hydro/", timeout=30) + response.raise_for_status() + for station in response.json()[:5]: + print(station.get("id_stacji"), station.get("stan_wody"), + station.get("stan_ostrzegawczy"), station.get("stan_wody_data_pomiaru")) + first_project: + title: Inspect Polish River Thresholds + goal: Review five official station readings before local stage matching. + steps: + - Keep station ID, river, reading time, units, and both thresholds. + - Reject stale, missing, or malformed readings before comparison. + - Explain why a station reading does not equal an official area warning. diff --git a/data/datasets/imgw-hydrological-bulletins.yaml b/data/datasets/imgw-hydrological-bulletins.yaml new file mode 100644 index 0000000..870159f --- /dev/null +++ b/data/datasets/imgw-hydrological-bulletins.yaml @@ -0,0 +1,83 @@ +id: imgw-hydrological-bulletins +name: IMGW Poland Hydrological Bulletins +description: > + Current official Polish hydrological warning bulletins from IMGW for + reviewing affected regions, severity, and validity windows. +theme: Environment & Hazards +url: https://danepubliczne.imgw.pl/data/current/ost_hydro/ +access_type: + - download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - TXT +license: > + Free public access for qualifying noncommercial analysis; commercial and + specified sectoral uses may require an IMGW agreement and payment. +license_url: https://danepubliczne.imgw.pl/ +url_checks: + source_marker: Index of /data/current/ost_hydro + license_marker: REGULAMIN UDOSTĘPNIANIA DANYCH +domains: + - Hydrology + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Poland +temporal_coverage: current official hydrological warnings +update_frequency: near real time +provider: Institute of Meteorology and Water Management +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + IMGW publishes current hydrological bulletins as separate text files. + Free access is limited to qualifying noncommercial analysis; commercial + and specified sectoral uses can require an agreement and payment. Start + with at most five listed bulletins and preserve issue and validity times. + TravelCanary uses flood warnings and excludes drought notices in this + shared directory. An empty directory is not the same as an API failure. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read IMGW's access regulation and official current-bulletin listing. + - Find one TXT bulletin in the current directory. + - Inspect issue time, warning degree, affected region, and validity. + python: + packages: + - requests + code: | + import re + import requests + + base = "https://danepubliczne.imgw.pl/data/current/ost_hydro/" + listing = requests.get(base, timeout=30) + listing.raise_for_status() + names = sorted(set(re.findall(r'href="([A-Za-z0-9_-]+\.TXT)"', listing.text))) + print(f"{len(names)} current bulletin files") + for name in names[:5]: + bulletin = requests.get(base + name, timeout=30) + bulletin.raise_for_status() + text = bulletin.content.decode("utf-8", errors="replace") + if "susza hydrologiczna" not in text.lower(): + print(name, text[:400]) + break + else: + print("No flood bulletin among the first five listed files") + first_project: + title: Inspect a Polish Hydrological Warning + goal: Review one official text bulletin before region matching. + steps: + - Keep bulletin name, issue time, degree, region, and validity period. + - Detect revised and cancelled bulletins before current display. + - Explain why an absent bulletin is not a statement of future safety. diff --git a/data/datasets/ipma-seismic-observations.yaml b/data/datasets/ipma-seismic-observations.yaml new file mode 100644 index 0000000..3d83a97 --- /dev/null +++ b/data/datasets/ipma-seismic-observations.yaml @@ -0,0 +1,56 @@ +id: ipma-seismic-observations +name: IPMA Regional Seismic Observations +description: > + Portuguese regional earthquake records for building a dated seismic context view around travel destinations. +theme: Environment & Hazards +url: https://api.ipma.pt/open-data/observation/seismic/3.json +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: IPMA permits free personal or public noncommercial use with source attribution; commercial use is excluded. +license_url: https://api.ipma.pt/ +url_checks: + source_marker: lastSismicActivityDate + license_marker: Condições de Utilização +domains: [Natural Hazards] +data_types: [Event Data, Geospatial] +tasks: [Monitoring, Mapping] +difficulty: beginner +geography: [Portugal] +temporal_coverage: recent regional seismic observations +update_frequency: near real time +provider: Instituto Português do Mar e da Atmosfera +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + IPMA publishes regional seismic JSON files, including areas 3 and 7 used + by TravelCanary. Start with area 3 and inspect two records; a reported + earthquake is contextual information, not an active hazard warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read IPMA's regional seismic API description and noncommercial terms. + - Fetch the area 3 file and check its update date. + - Inspect two earthquake records before applying a time or magnitude filter. + python: + packages: [requests] + code: | + import requests + + url = "https://api.ipma.pt/open-data/observation/seismic/3.json" + response = requests.get(url, timeout=20) + response.raise_for_status() + feed = response.json() + print(feed["idArea"], feed.get("updateDate")) + for event in feed["data"][:2]: + print(event.get("time"), event.get("magnitud")) + first_project: + title: Review Regional Seismic Context + goal: Show two dated earthquake records from an official IPMA region. + steps: + - Fetch one area and retain its update timestamp. + - Display event time and magnitude beside the region ID. + - Explain that a past event does not establish current local risk. diff --git a/data/datasets/ipma-weather-station-observations.yaml b/data/datasets/ipma-weather-station-observations.yaml new file mode 100644 index 0000000..c90db53 --- /dev/null +++ b/data/datasets/ipma-weather-station-observations.yaml @@ -0,0 +1,55 @@ +id: ipma-weather-station-observations +name: IPMA Weather Station Observations +description: > + Portuguese hourly station weather observations for building a local conditions display with explicit station context. +theme: Environment & Hazards +url: https://api.ipma.pt/open-data/observation/meteorology/stations/obs-surface.geojson +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.002 +formats: [GeoJSON] +license: IPMA permits free personal or public noncommercial use with source attribution; commercial use is excluded. +license_url: https://api.ipma.pt/ +url_checks: + source_marker: FeatureCollection + license_marker: Condições de Utilização +domains: [Weather] +data_types: [Geospatial, Time Series] +tasks: [Monitoring, Mapping] +difficulty: beginner +geography: [Portugal] +temporal_coverage: latest hourly station observations +update_frequency: near real time +provider: Instituto Português do Mar e da Atmosfera +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + IPMA publishes a GeoJSON file of recent Portuguese weather station readings. + Start with two features and preserve their timestamps and station IDs; + a station reading is not a destination-wide measurement or warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the IPMA API documentation and noncommercial reuse conditions. + - Download the current GeoJSON station observations. + - Inspect two station readings and their observation times. + python: + packages: [requests] + code: | + import requests + + url = "https://api.ipma.pt/open-data/observation/meteorology/stations/obs-surface.geojson" + response = requests.get(url, timeout=20) + response.raise_for_status() + for station in response.json()["features"][:2]: + row = station["properties"] + print(row.get("idEstacao"), row.get("time"), row.get("temperatura")) + first_project: + title: Show Nearby Station Weather + goal: Present two current IPMA station readings with timestamps. + steps: + - Select stations by their reviewed coordinates and IDs. + - Display temperature with its station name and observation time. + - Explain that station conditions can differ from a travel destination. diff --git a/data/datasets/ipma-weather-warnings.yaml b/data/datasets/ipma-weather-warnings.yaml new file mode 100644 index 0000000..2eeb4a1 --- /dev/null +++ b/data/datasets/ipma-weather-warnings.yaml @@ -0,0 +1,72 @@ +id: ipma-weather-warnings +name: IPMA Portuguese Weather Warnings +description: > + Official Portuguese weather-warning JSON from IPMA for reviewing affected + forecast areas, severity levels, and warning validity. +theme: Environment & Hazards +url: https://api.ipma.pt/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Free public IPMA data for noncommercial analysis; read IPMA conditions before reuse. +license_url: https://api.ipma.pt/ +url_checks: + source_marker: Avisos Meteorológicos até 3 dias + license_marker: condições de utilização +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Time Series +tasks: + - Monitoring + - Alerting +difficulty: beginner +geography: + - Portugal +temporal_coverage: current warnings up to three days +update_frequency: near real time +provider: Instituto Português do Mar e da Atmosfera +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + IPMA publishes area-based weather warnings as JSON. Start with five entries + and preserve area code, start/end time, and awareness level. The public + service is documented for noncommercial use; confirm the IPMA conditions + before wider reuse. Green entries are not proof of no other hazards. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read IPMA's API documentation and linked conditions of use. + - Fetch the current warning JSON once. + - Inspect each warning's area code and validity window. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://api.ipma.pt/open-data/forecast/warnings/warnings_www.json", + timeout=30, + ) + response.raise_for_status() + for warning in response.json()[:5]: + print(warning["idAreaAviso"], warning["awarenessLevelID"], + warning["startTime"], warning["endTime"]) + first_project: + title: Inspect Five IPMA Warnings + goal: Check whether IPMA warnings can support a bounded area warning card. + steps: + - Keep official area IDs and the full validity interval. + - Treat each category and severity separately before displaying it. + - Explain IPMA's noncommercial-use limit and why these entries do not imply a local all-clear. diff --git a/data/datasets/kraken-bitcoin-ticker.yaml b/data/datasets/kraken-bitcoin-ticker.yaml new file mode 100644 index 0000000..fa51d43 --- /dev/null +++ b/data/datasets/kraken-bitcoin-ticker.yaml @@ -0,0 +1,66 @@ +id: kraken-bitcoin-ticker +name: Kraken Bitcoin Ticker +description: Kraken XBT/USD exchange ticker fields for a private Bitcoin market comparison with explicit + provider provenance and retrieval time. +theme: Markets & Economics +url: https://api.kraken.com/0/public/Ticker?pair=XBTUSD +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- JSON +license: Kraken public market-data API permits personal use under Kraken terms; nonpersonal commercial + use requires a data licence. +license_url: https://docs.kraken.com/api/docs/rest-api/get-ticker-information/ +url_checks: + source_marker: '"result":{"XXBTZUSD"' + license_marker: Get Ticker Information +domains: +- Capital Markets +data_types: +- Tabular +tasks: +- Market Monitoring +difficulty: beginner +geography: +- Global +temporal_coverage: current BTC spot quote +update_frequency: near real time +provider: Kraken +source_type: company +last_verified: '2026-09-28' +getting_started: + overview: The Kraken public endpoint returns one current Bitcoin quote. Start with one response and + record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. + Follow the provider usage limits above. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official Kraken API and data-use terms. + - Fetch one Bitcoin quote from the documented public endpoint. + - Keep the pair, retrieval time, and provider name separate from other exchanges. + python: + packages: + - requests + code: | + import requests + + url = 'https://api.kraken.com/0/public/Ticker?pair=XBTUSD' + response = requests.get(url, timeout=20) + response.raise_for_status() + feed = response.json() + assert not feed["error"], feed["error"] + quote = next(iter(feed["result"].values())) + print("XBT/USD last trade", quote["c"][0]) + first_project: + title: Compare One Bitcoin Quote + goal: Inspect a single provider quote without treating it as an investment signal. + steps: + - Fetch a single response and retain its pair identifier. + - Record the retrieval time and label the provider. + - Explain why exchange quotes differ and cannot stand in for historical returns. diff --git a/data/datasets/krisinformation-news.yaml b/data/datasets/krisinformation-news.yaml new file mode 100644 index 0000000..9b069b2 --- /dev/null +++ b/data/datasets/krisinformation-news.yaml @@ -0,0 +1,64 @@ +id: krisinformation-news +name: Krisinformation News Feed +description: Swedish official crisis and infrastructure news for building a dated local-disruption context + view. +theme: Government & Policy +url: https://api.krisinformation.se/v3/news?format=json&allcounties=true&days=365 +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.005 +formats: +- JSON +license: Krisinformation open API permits reuse with visible source attribution and original notice links. +license_url: https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/ +url_checks: + source_marker: '"ContentTypeName": "newspage"' + license_marker: Ursprungsmärkning +domains: +- Public Safety +data_types: +- Event Data +tasks: +- Monitoring +difficulty: beginner +geography: +- Sweden +temporal_coverage: current observations or notices +update_frequency: near real time +provider: Krisinformation.se +source_type: government +last_verified: '2026-09-28' +getting_started: + overview: The official Krisinformation.se feed supplies current public data. Start with two recent official + news records; a regional notice does not prove a destination-wide infrastructure outage. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official data documentation and reuse terms. + - Fetch the small official feed and inspect two records. + - Preserve source timestamps and locations before mapping results. + python: + packages: + - requests + code: | + import requests + + url = "https://api.krisinformation.se/v3/news" + response = requests.get(url, params={"format": "json", "allcounties": "true", + "days": 365}, timeout=20) + response.raise_for_status() + for notice in response.json()[:2]: + print(notice.get("Identifier"), notice.get("Headline"), + notice.get("Updated")) + first_project: + title: Inspect Dated Local Conditions + goal: Inspect two recent official news records with source timestamps. + steps: + - Fetch the official source and retain its update time. + - Show two records with their station or notice identifiers. + - Explain why these records are context rather than complete hazard coverage. diff --git a/data/datasets/krisinformation-vma.yaml b/data/datasets/krisinformation-vma.yaml new file mode 100644 index 0000000..a8351ec --- /dev/null +++ b/data/datasets/krisinformation-vma.yaml @@ -0,0 +1,73 @@ +id: krisinformation-vma +name: Krisinformation Sweden VMA Alerts +description: > + Official Swedish important-public-announcement records from the + Krisinformation open API for reviewing current local emergency warnings. +theme: Environment & Hazards +url: https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Open API for public and commercial applications; cite Krisinformation.se as the source. +license_url: https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/ +url_checks: + source_marker: Krisinformations API + license_marker: Ursprungsmärkning +domains: + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: beginner +geography: + - Sweden +temporal_coverage: current official VMA announcements +update_frequency: near real time +provider: Swedish Civil Defence and Resilience Agency +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + Krisinformation.se exposes current VMA public announcements through its + version 3 API. Start with one request and read up to five current records; + an empty response says only + that this scoped endpoint returned none. Attribute any displayed message + and check location and validity before treating it as a local warning. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official open-data description and attribution rule. + - Request the version 3 VMA endpoint once. + - Inspect region, issue time, and status of any returned announcement. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://api.krisinformation.se/v3/vmas", + params={"allCounties": "true", "language": "en"}, timeout=30, + ) + response.raise_for_status() + alerts = response.json() + print(f"{len(alerts)} VMA records returned") + for alert in alerts[:5]: + print(alert.get("Identifier"), alert.get("Updated"), alert.get("Counties")) + first_project: + title: Inspect Current Swedish VMA Alerts + goal: Check a scoped official response before local alert matching. + steps: + - Preserve announcement identifiers, region, issue time, and updates. + - Link to Krisinformation.se and credit the source. + - Do not infer nationwide safety from an empty response. diff --git a/data/datasets/lhp-germany-flood-warnings.yaml b/data/datasets/lhp-germany-flood-warnings.yaml new file mode 100644 index 0000000..6d35142 --- /dev/null +++ b/data/datasets/lhp-germany-flood-warnings.yaml @@ -0,0 +1,73 @@ +id: lhp-germany-flood-warnings +name: German LHP Flood Warnings +description: > + Current state flood-warning alerts from Germany's interregional LHP portal + for reviewing official flood areas and update times. +theme: Environment & Hazards +url: https://www.hochwasserzentralen.de/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON +license: CC BY 4.0 with Länderübergreifendes Hochwasserportal attribution. +license_url: https://creativecommons.org/licenses/by/4.0/ +url_checks: + source_marker: Aktuelle Hochwasser + license_marker: Attribution 4.0 International +domains: + - Hydrology + - Emergency Management +data_types: + - Geospatial + - Event Data +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Germany +temporal_coverage: current regional flood warnings +update_frequency: near real time +provider: Länderübergreifendes Hochwasserportal +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The LHP public API returns current regional flood alerts as GeoJSON with + update metadata and a CC BY licence link. Start with one response and + inspect at most five features. An empty regional result must not be + interpreted as a comprehensive flood all-clear. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read LHP's official portal and the licence advertised by its API. + - Fetch a single current GeoJSON response. + - Keep update time and geographic scope when showing an alert. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://api.hochwasserzentralen.de/public/v1/data/alerts", + params={"format": "geojson", "lang": "en"}, timeout=30, + ) + response.raise_for_status() + data = response.json() + print(data["updated"], len(data["features"])) + for feature in data["features"][:5]: + print(feature.get("properties", {})) + first_project: + title: Inspect Regional Flood Alerts + goal: Test the official alert snapshot for a small German flood map. + steps: + - Keep the snapshot update time, alert identifier, and geometry. + - Compare empty and populated states without inferring safety from either. + - Explain why official warnings differ from raw gauge levels and require attribution. diff --git a/data/datasets/lu-alert-cap.yaml b/data/datasets/lu-alert-cap.yaml new file mode 100644 index 0000000..6ff0087 --- /dev/null +++ b/data/datasets/lu-alert-cap.yaml @@ -0,0 +1,76 @@ +id: lu-alert-cap +name: Luxembourg LU-Alert CAP Messages +description: > + Official Luxembourg civil-alert messages published as CAP-LU files through + the national open-data portal for tracking current civil emergencies. +theme: Environment & Hazards +url: https://data.public.lu/api/1/datasets/alertes-du-systeme-lu-alert/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - XML +license: CC BY 4.0; identify LU-Alert as the source of each alert. +license_url: https://creativecommons.org/licenses/by/4.0/ +url_checks: + source_marker: alertes-du-systeme-lu-alert + license_marker: Attribution 4.0 International +domains: + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Luxembourg +temporal_coverage: current and archived CAP-LU alert files +update_frequency: near real time +provider: Luxembourg Government LU-Alert +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + LU-Alert publishes issuer messages as CAP-LU XML resources in one portal + dataset. Start with resource metadata from the first API page; inspect + message status, validity, and cancellation before presenting an alert. + Credit LU-Alert and retain the source resource URL. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the LU-Alert dataset licence and CAP-LU documentation. + - Fetch the dataset API metadata once and inspect one recent XML resource. + - Keep issuer, event, message status, issue time, and affected area. + python: + packages: + - requests + code: | + import xml.etree.ElementTree as ET + import requests + + url = "https://data.public.lu/api/1/datasets/alertes-du-systeme-lu-alert/" + response = requests.get(url, timeout=30) + response.raise_for_status() + resources = [r for r in response.json()["resources"] + if r.get("format", "").lower() == "xml"] + resource = resources[0] + alert = requests.get(resource["url"], timeout=30) + alert.raise_for_status() + root = ET.fromstring(alert.content) + namespace = root.tag.split("}")[0] + "}" + print(resource["title"], root.findtext(f"{namespace}identifier"), + root.findtext(f"{namespace}status"), root.findtext(f"{namespace}sent")) + first_project: + title: Inspect Official Luxembourg Alerts + goal: Find recent CAP-LU resources for a bounded official alert review. + steps: + - Retain the source resource URL, update timestamp, and CAP identifier. + - Handle tests, updates, and cancellations before displaying a warning. + - Attribute each displayed message to LU-Alert. diff --git a/data/datasets/lvgmc-hydrometeorological-warnings.yaml b/data/datasets/lvgmc-hydrometeorological-warnings.yaml new file mode 100644 index 0000000..ef359fa --- /dev/null +++ b/data/datasets/lvgmc-hydrometeorological-warnings.yaml @@ -0,0 +1,86 @@ +id: lvgmc-hydrometeorological-warnings +name: Latvia Hydrometeorological Warnings +description: > + Official Latvian weather and hydrological warning resources published by + the Latvian Environment, Geology and Meteorology Centre for local alert review. +theme: Environment & Hazards +url: https://data.gov.lv/dati/eng/dataset/hidrometeorologiskie-bridinajumi +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON + - CSV +license: CC0 1.0 for the named portal dataset; retain the originating authority and issue context. +license_url: https://data.gov.lv/dati/eng/dataset/hidrometeorologiskie-bridinajumi +url_checks: + source_marker: Hidrometeoroloģiskie brīdinājumi + license_marker: property="dc:rights">CC0-1.0 +domains: + - Weather + - Hydrology + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Latvia +temporal_coverage: current and published warning resources +update_frequency: near real time +provider: Latvian Environment, Geology and Meteorology Centre +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The Latvian open-data package lists maintained hydrometeorological warning + resources. Start with one package metadata response and inspect five + warning resource URLs; + Riga warnings may be separate from wider regional warnings. A package + listing alone is not a current warning. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official package description, resource list, and CC0 terms. + - Query the bounded CKAN package metadata endpoint once. + - Fetch five warning metadata records from the exact named resource. + - Match issue time, hazard, and locality in any current record. + python: + packages: + - requests + code: | + import requests + + url = "https://data.gov.lv/dati/api/3/action/package_show" + response = requests.get(url, params={"id": "hidrometeorologiskie-bridinajumi"}, timeout=30) + response.raise_for_status() + package = response.json()["result"] + print(package["title"]) + warnings = next(r for r in package["resources"] + if r["id"] == "59c111fb-8c9a-4a63-8284-0a64a2920681") + records = requests.get( + "https://data.gov.lv/dati/api/3/action/datastore_search", + params={"resource_id": warnings["id"], "limit": 5}, timeout=30, + ) + records.raise_for_status() + rows = [row for row in records.json()["result"]["records"] + if row.get("WEATHER_WARNING_EV_ID")] + print(f"{len(rows)} warning metadata rows in this page") + for row in rows: + print(row.get("WEATHER_WARNING_EV_ID"), row.get("PARADIBA_EN"), + row.get("TIME_FROM"), row.get("TIME_TILL")) + first_project: + title: Inspect Latvian Warning Resources + goal: Identify the official resources and their geographic coverage. + steps: + - Keep resource IDs, warning issue times, and affected area names. + - Check Riga separately from regional notices when appropriate. + - Explain why metadata refresh is not itself a current warning event. diff --git a/data/datasets/met-eireann-warnings.yaml b/data/datasets/met-eireann-warnings.yaml new file mode 100644 index 0000000..8490498 --- /dev/null +++ b/data/datasets/met-eireann-warnings.yaml @@ -0,0 +1,71 @@ +id: met-eireann-warnings +name: Met Eireann Weather Warnings +description: > + Official Irish weather-warning JSON from Met Éireann for checking county + regions, severity, and validity intervals. +theme: Environment & Hazards +url: https://www.met.ie/about-us/specialised-services/open-data +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Open data with Met Éireann attribution; warning properties and expiry must remain intact. +license_url: https://www.met.ie/about-us/specialised-services/widgets +url_checks: + source_marker: Weather Warnings + license_marker: Weather Warnings must be kept up to date +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: beginner +geography: + - Ireland +temporal_coverage: current official weather warnings +update_frequency: near real time +provider: Met Éireann +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + Met Éireann exposes current warnings as JSON with CAP IDs, regions, and + issue/onset/expiry times. Start with five records. Its reuse terms require + attribution and preserving warning meaning; remove expired warnings and + do not treat an empty list as a general safety statement. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read Met Éireann's open-data and weather-warning reuse conditions. + - Fetch the national JSON warning list once. + - Retain region IDs and full validity intervals when displaying warnings. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://www.met.ie/Open_Data/json/warning_IRELAND.json", timeout=30, + ) + response.raise_for_status() + for warning in response.json()[:5]: + print(warning["capId"], warning["level"], warning["regions"], + warning["onset"], warning["expiry"]) + first_project: + title: Inspect Current Irish Weather Warnings + goal: Evaluate a county-matched alert card using official warning records. + steps: + - Keep CAP IDs, county regions, severity, and issue/onset/expiry times. + - Remove expired and superseded warnings before display. + - Explain why these region warnings do not imply an all-clear elsewhere. diff --git a/data/datasets/met-norway-metalerts.yaml b/data/datasets/met-norway-metalerts.yaml new file mode 100644 index 0000000..746727e --- /dev/null +++ b/data/datasets/met-norway-metalerts.yaml @@ -0,0 +1,74 @@ +id: met-norway-metalerts +name: MET Norway MetAlerts +description: > + Official Norwegian weather warnings from MET Norway's MetAlerts service + for reviewing affected areas and alert validity. +theme: Environment & Hazards +url: https://api.met.no/weatherapi/metalerts/2.0/documentation +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON + - CAP +license: NLOD 2.0 and CC BY 4.0 with MET Norway attribution. +license_url: https://api.met.no/doc/License +url_checks: + source_marker: Weather alerts from the Norwegian Meteorological Institute + license_marker: Norwegian Licence for Open Government Data +domains: + - Weather + - Emergency Management +data_types: + - Geospatial + - Event Data +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Norway +temporal_coverage: current official weather alerts +update_frequency: near real time +provider: Norwegian Meteorological Institute +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + MetAlerts publishes official weather warnings in CAP and beta GeoJSON. + Start with five features from the current GeoJSON endpoint. Preserve CAP + IDs, updates and cancellations when building an alert timeline, and use a + distinct client User-Agent. Weather alerts differ from Locationforecast. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the MetAlerts documentation and MET Norway attribution policy. + - Set an identifying User-Agent and request current GeoJSON warnings. + - Inspect area, event, and validity before using an alert in a product. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://api.met.no/weatherapi/metalerts/2.0/current.json", + headers={"User-Agent": "TrilemmaDataCatalogExample/1.0 (https://data.trilemma.foundation)"}, + timeout=30, + ) + response.raise_for_status() + for warning in response.json()["features"][:5]: + details = warning["properties"] + print(details.get("id"), details.get("event"), details.get("area")) + first_project: + title: Inspect Norwegian Weather Alerts + goal: Test whether current alert geometry supports a local warning card. + steps: + - Keep alert ID, event, severity, geometry, and validity interval. + - Account for CAP updates and cancellations before retaining a warning. + - Attribute MET Norway and avoid equating an empty sample with safety. diff --git a/data/datasets/meteo-lt-hydrology-observations.yaml b/data/datasets/meteo-lt-hydrology-observations.yaml new file mode 100644 index 0000000..755c467 --- /dev/null +++ b/data/datasets/meteo-lt-hydrology-observations.yaml @@ -0,0 +1,58 @@ +id: meteo-lt-hydrology-observations +name: Meteo LT Hydrology Observations +description: > + Lithuanian river-station water levels and temperatures for dated local hydrology context tools. +theme: Environment & Hazards +url: https://api.meteo.lt/ +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: > + The Lithuanian Hydrometeorological Service publishes API data under CC BY-SA 4.0 unless marked otherwise; attribute the source and share adapted data under compatible terms. +license_url: https://api.meteo.lt/ +url_checks: + source_marker: /hydro-stations/{station-code}/observations/measured/{date} + license_marker: Creative Commons Attribution-ShareAlike 4.0 +domains: [Water Resources] +data_types: [Time Series] +tasks: [Monitoring] +difficulty: beginner +geography: [Lithuania] +temporal_coverage: current and recent station observations +update_frequency: near real time +provider: Lithuanian Hydrometeorological Service +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + Meteo LT publishes current measured water levels at named hydro-stations in centimeters. + Start with one documented station; a water level without a station datum or official threshold is not a flood warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the hydro-station endpoint documentation and CC BY-SA terms. + - Fetch the latest observations for one documented station. + - Keep its UTC observation time, station name, and water-level unit together. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://api.meteo.lt/v1/hydro-stations/nemajunu-vms/observations/measured/latest", + timeout=20, + ) + response.raise_for_status() + data = response.json() + for observation in data["observations"][-2:]: + print(data["station"]["name"], observation["observationTimeUtc"], + observation["waterLevel"], "cm") + first_project: + title: Inspect One River Station + goal: Show one recent Lithuanian station water level with its time and unit. + steps: + - Fetch the documented station's latest measured observations. + - Display its station name, UTC time, and centimeter level. + - Explain why the value cannot be treated as an official flood warning. diff --git a/data/datasets/meteoalarm-atom-warnings.yaml b/data/datasets/meteoalarm-atom-warnings.yaml new file mode 100644 index 0000000..030f772 --- /dev/null +++ b/data/datasets/meteoalarm-atom-warnings.yaml @@ -0,0 +1,77 @@ +id: meteoalarm-atom-warnings +name: MeteoAlarm Country Atom Warnings +description: > + Country Atom feeds of European weather warnings from MeteoAlarm for + checking official alert publications and their validity windows. +theme: Environment & Hazards +url: https://feeds.meteoalarm.org/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - Atom +license: CC BY 4.0-equivalent warning feed with additional redistribution conditions; analytical use requires attribution. +license_url: https://www.meteoalarm.org/en/live/terms-and-conditions/ +url_checks: + source_marker: Legacy RSS Feeds Have Been Sunset + license_marker: Terms and Conditions +domains: + - Weather + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Alerting +difficulty: intermediate +geography: + - Europe +temporal_coverage: current published country warnings +update_frequency: near real time +provider: MeteoAlarm / EUMETNET +source_type: intergovernmental +last_verified: 2026-09-28 +getting_started: + overview: > + MeteoAlarm maintains country Atom feeds; its old RSS feeds stopped updating + in 2026. Start with one small country feed and inspect entry titles and + update timestamps. Read the additional redistribution conditions before + republishing warning content. An empty feed is not an all-clear elsewhere. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the MeteoAlarm feed list and terms, including redistribution requirements. + - Fetch one country Atom feed rather than the Europe-wide feed. + - Inspect each entry's issue and update metadata before mapping it to a place. + python: + packages: + - requests + code: | + import xml.etree.ElementTree as ET + import requests + + response = requests.get( + "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-andorra", + timeout=30, + ) + response.raise_for_status() + root = ET.fromstring(response.content) + namespace = {"atom": "http://www.w3.org/2005/Atom"} + entries = root.findall("atom:entry", namespace) + print(f"{len(entries)} current Andorra feed entries") + for entry in entries[:5]: + print(entry.findtext("atom:title", default="", namespaces=namespace), + entry.findtext("atom:updated", default="", namespaces=namespace)) + first_project: + title: Inspect One Country Warning Feed + goal: Check Atom publication metadata for a bounded warning display. + steps: + - Keep feed country, entry identifiers, update times, and official links. + - Verify warning geometry and validity before showing local coverage. + - Explain why warning content needs MeteoAlarm attribution and an extra redistribution review. diff --git a/data/datasets/nasa-eonet-events.yaml b/data/datasets/nasa-eonet-events.yaml new file mode 100644 index 0000000..687909a --- /dev/null +++ b/data/datasets/nasa-eonet-events.yaml @@ -0,0 +1,76 @@ +id: nasa-eonet-events +name: NASA EONET Natural Events +description: > + Curated NASA EONET natural-event metadata for reviewing wildfire, volcano, + storm, and other recent event context. +theme: Environment & Hazards +url: https://eonet.gsfc.nasa.gov/docs/v3 +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + NASA EONET metadata is publicly accessible for analysis; cite EONET and + check separately linked source rights. Event extents are informational, + approximate, and not official emergency boundaries. +license_url: https://eonet.gsfc.nasa.gov/what-is-eonet +url_checks: + source_marker: Version 3 Documentation + license_marker: visualization and general information purposes only +domains: + - Climate + - Emergency Management +data_types: + - Event Data + - Geospatial +tasks: + - Monitoring + - Mapping +difficulty: beginner +geography: + - Global +temporal_coverage: recent natural-event metadata +update_frequency: near real time +provider: NASA Earth Observatory Natural Event Tracker +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + EONET curates recent natural-event metadata from multiple sources. Start + with three open events and inspect IDs, categories, and source links. + NASA warns that event extents are approximate and not official; the + rights of separately linked source observations must be reviewed before + republishing those observations. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the EONET v3 API documentation and event disclaimer. + - Request three open events in one bounded call. + - Keep event IDs and source links separate from local warning evidence. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://eonet.gsfc.nasa.gov/api/v3/events", + params={"limit": 3, "status": "open"}, timeout=30, + ) + response.raise_for_status() + for event in response.json()["events"][:3]: + print(event["id"], event["title"], + [category["id"] for category in event["categories"]]) + first_project: + title: Inspect Recent Natural Events + goal: Review a small EONET response as contextual discovery data. + steps: + - Keep event ID, categories, source URLs, and geometry dates. + - Verify independent official sources before local hazard conclusions. + - Explain why an EONET event extent is not an official warning area. diff --git a/data/datasets/natural-earth.yaml b/data/datasets/natural-earth.yaml index 6698e4b..3e245fe 100644 --- a/data/datasets/natural-earth.yaml +++ b/data/datasets/natural-earth.yaml @@ -52,33 +52,30 @@ last_verified: 2026-09-27 getting_started: overview: > Natural Earth provides compact, public-domain layers designed for clear - small-scale maps. Start with the 1:110m country boundaries to learn - attributes, coordinate systems, and thematic mapping. These generalized - boundaries are not authoritative for precise local or legal analysis. + small-scale maps. Start with the 1:50m ocean mask and 1:10m populated places + used as geography inputs by TitanSkies. These generalized layers are not + authoritative for precise local boundaries or current population counts. prerequisites: - Python 3.10 or newer - A notebook environment such as Jupyter or Google Colab - - A Python environment where GeoPandas and Matplotlib can be installed + - A Python environment where GeoPandas can be installed access_steps: - - Open the official Natural Earth site and select the 1:110m Admin 0 Countries layer. - - Download the layer and extract the shapefile beside your notebook. + - Open the official Natural Earth site and select the 1:50m Ocean and 1:10m Populated Places layers. + - Download both ZIP files and place them beside your notebook. python: packages: - geopandas - - matplotlib code: | import geopandas as gpd - import matplotlib.pyplot as plt - countries = gpd.read_file("ne_110m_admin_0_countries.shp") - print(countries[["ADMIN", "CONTINENT", "geometry"]].head()) - countries.plot(column="CONTINENT", legend=True, figsize=(12, 6)) - plt.axis("off") - plt.show() + ocean = gpd.read_file("ne_50m_ocean.zip") + places = gpd.read_file("ne_10m_populated_places.zip") + print(f"{len(ocean)} ocean polygons; {len(places)} populated places") + print(places[["NAME", "POP_MAX"]].head()) first_project: - title: Compare World Regions on One Map - goal: Build a continent map and explain how geometry and projection choices affect its interpretation. + title: Map Ocean Coverage and Populated Places + goal: Test whether generalized ocean and city layers can support a regional map. steps: - - Inspect the layer's geometry type and coordinate reference system. - - Check for missing continent or geometry values. - - Create the map and explain how generalized boundaries and the chosen projection limit its use. + - Inspect each layer's geometry type and coordinate reference system. + - Filter populated places to one region and check for missing names or population estimates. + - Create the map and explain why generalized oceans and place estimates cannot establish exact local coverage. diff --git a/data/datasets/ndw-road-closures.yaml b/data/datasets/ndw-road-closures.yaml new file mode 100644 index 0000000..4ba8f08 --- /dev/null +++ b/data/datasets/ndw-road-closures.yaml @@ -0,0 +1,73 @@ +id: ndw-road-closures +name: NDW Road Events and Closures +description: Dutch compressed road-closure and safety-message records for building a dated traffic-disruption + map. +theme: Geospatial & Infrastructure +url: https://opendata.ndw.nu/ +access_type: +- download +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.005 +formats: +- XML +license: NDW open-data content is CC0 unless a specific file states otherwise. +license_url: https://english.ndw.nu/service/copyright +url_checks: + source_marker: tijdelijke_verkeersmaatregelen_afsluitingen.xml.gz + license_marker: CC0 (Creative Commons Zero) +domains: +- Transportation +data_types: +- Event Data +- Geospatial +tasks: +- Monitoring +- Mapping +difficulty: beginner +geography: +- Netherlands +temporal_coverage: current observations or notices +update_frequency: near real time +provider: Nationaal Dataportaal Wegverkeer +source_type: government +last_verified: '2026-09-28' +getting_started: + overview: The official NDW index publishes separate closure and safety-message DATEX files. Start with + two Dutch closure records; a listed restriction is not a complete route planner or safety instruction. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official data documentation and reuse terms. + - Fetch the small official feed and inspect two records. + - Preserve source timestamps and locations before mapping results. + python: + packages: + - requests + code: | + import gzip + import io + import itertools + import requests + from xml.etree import ElementTree as ET + + url = "https://opendata.ndw.nu/tijdelijke_verkeersmaatregelen_afsluitingen.xml.gz" + response = requests.get(url, timeout=20) + response.raise_for_status() + assert len(response.content) < 1_000_000 + xml = gzip.decompress(response.content) + assert len(xml) < 5_000_000 + records = (element for _, element in ET.iterparse(io.BytesIO(xml), events=("end",)) + if element.tag.endswith("}situationRecord")) + for record in itertools.islice(records, 2): + print(record.get("id"), record.get("version")) + first_project: + title: Inspect Dated Local Conditions + goal: Inspect two Dutch closure records with source timestamps. + steps: + - Fetch the official source and retain its update time. + - Show two records with their station or notice identifiers. + - Explain why these records are context rather than complete hazard coverage. diff --git a/data/datasets/noaa-hrrr-smoke.yaml b/data/datasets/noaa-hrrr-smoke.yaml new file mode 100644 index 0000000..12d8b82 --- /dev/null +++ b/data/datasets/noaa-hrrr-smoke.yaml @@ -0,0 +1,65 @@ +id: noaa-hrrr-smoke +name: NOAA HRRR-Smoke Forecast +description: > + NOAA's operational high-resolution smoke-concentration forecast for building dated regional exposure context tools. +theme: Environment & Hazards +url: https://rapidrefresh.noaa.gov/hrrr/HRRRsmoke/ +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 2 +formats: [GRIB2] +license: NOAA-produced data are U.S. public-domain material; cite NOAA and do not imply endorsement. +license_url: https://gml.noaa.gov/about/disclaimer.html +url_checks: + source_marker: HRRR-Smoke Graphics + license_marker: information on government servers are in the public domain +domains: [Air Quality] +data_types: [Geospatial, Time Series] +tasks: [Monitoring] +difficulty: intermediate +geography: [United States] +temporal_coverage: hourly forecast cycles with dated forecast hours +update_frequency: near real time +provider: National Oceanic and Atmospheric Administration +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + NOAA publishes HRRR-Smoke MASSDEN at 8 m above ground in GRIB2 through NOMADS. + Start with a one-degree area and one completed cycle. This is modeled smoke mass + concentration, not a monitor reading, and the GRIB values need unit conversion. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read NOAA's HRRR-Smoke model page and public-domain notice. + - Select a completed model cycle and request only MASSDEN at 8 m for a small area. + - Inspect the GRIB field before interpreting smoke concentrations. + python: + packages: [requests] + code: | + from datetime import datetime, timedelta, timezone + import requests + + run = datetime.now(timezone.utc) - timedelta(hours=5) + day, hour = run.strftime("%Y%m%d"), run.strftime("%H") + params = { + "file": f"hrrr.t{hour}z.wrfsfcf00.grib2", + "lev_8_m_above_ground": "on", "var_MASSDEN": "on", + "subregion": "", "leftlon": "-106", "rightlon": "-105", + "toplat": "40", "bottomlat": "39", "dir": f"/hrrr.{day}/conus", + } + response = requests.get( + "https://nomads.ncep.noaa.gov/cgi-bin/filter_hrrr_2d.pl", + params=params, timeout=30, + ) + response.raise_for_status() + assert response.content.startswith(b"GRIB") + print(day, hour, len(response.content), "GRIB2 bytes") + first_project: + title: Inspect a Smoke Forecast Field + goal: Inspect one forecast cycle before displaying model smoke context. + steps: + - Request a bounded MASSDEN GRIB field for one cycle. + - Decode and convert its kg/m3 mass density to micrograms per cubic meter. + - Explain why a model forecast cannot be presented as a current monitor observation. diff --git a/data/datasets/noaa-us-climate-normals-stations.yaml b/data/datasets/noaa-us-climate-normals-stations.yaml new file mode 100644 index 0000000..c9034b8 --- /dev/null +++ b/data/datasets/noaa-us-climate-normals-stations.yaml @@ -0,0 +1,62 @@ +id: noaa-us-climate-normals-stations +name: NOAA U.S. Climate Normals Station Archives +description: > + NOAA's maintained 1991-2020 station climate-normal archives for comparing typical local temperature and precipitation. +theme: Environment & Hazards +url: https://www.ncei.noaa.gov/products/land-based-station/us-climate-normals +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.02 +size_gb_max: 0.06 +formats: [TAR.GZ, CSV] +license: NOAA-produced station normals are public domain; cite NCEI and retain period and release version. +license_url: https://gml.noaa.gov/about/disclaimer.html +url_checks: + source_marker: 1991–2020 U.S. Climate Normals + license_marker: information on government servers are in the public domain +domains: [Climate] +data_types: [Tabular] +tasks: [Community Comparison] +difficulty: intermediate +geography: [United States] +temporal_coverage: 1991-2020 thirty-year station normals, release v1.0.1 +update_frequency: occasional +provider: NOAA National Centers for Environmental Information +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + NCEI publishes annual/seasonal and monthly v1.0.1 station TAR.GZ archives. + Start with the Central Park monthly station CSV from the exact archive HouseHunter pins. + A 30-year station normal is a climatological baseline, not a current forecast, + and a station may not represent a whole county. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read NCEI's Climate Normals product description and NOAA reuse notice. + - Download the versioned monthly station archive. + - Inspect one station's normal values and quality flags. + python: + packages: [requests] + code: | + import csv + import io + import tarfile + import requests + + url = ("https://www.ncei.noaa.gov/data/normals-monthly/1991-2020/archive/" + "us-climate-normals_1991-2020_v1.0.1_monthly_multivariate_by-station_c20230404.tar.gz") + response = requests.get(url, timeout=90) + response.raise_for_status() + with tarfile.open(fileobj=io.BytesIO(response.content), mode="r:gz") as archive: + station = "USW00094728.csv" + with archive.extractfile(station) as file: + row = next(csv.DictReader(io.TextIOWrapper(file, encoding="utf-8"))) + print(row["STATION"], row["month"], row["MLY-TAVG-NORMAL"].strip(), "°F") + first_project: + title: Inspect a Station Climate Normal + goal: Compare one fixed-period station normal with a current condition without confusing them. + steps: + - Read a station's monthly temperature normal. + - Record the 1991-2020 period and v1.0.1 release. + - Explain why a station normal is neither a current observation nor a county average. diff --git a/data/datasets/nve-flood-warnings.yaml b/data/datasets/nve-flood-warnings.yaml new file mode 100644 index 0000000..f2d0093 --- /dev/null +++ b/data/datasets/nve-flood-warnings.yaml @@ -0,0 +1,75 @@ +id: nve-flood-warnings +name: NVE Norway Flood Warnings +description: > + Official regional flood-warning records from Norway's NVE for inspecting + affected municipalities, dates, and assessed activity levels. +theme: Environment & Hazards +url: https://api.nve.no/doc/flomvarsling/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Free warning-data use with full-bulletin and Varsom attribution conditions. +license_url: https://api.nve.no/doc/flomvarsling/ +url_checks: + source_marker: Warning/{ + NVE publishes dated flood warnings through a versioned REST endpoint. + Start with today's and tomorrow's English Warning records; an empty list + means no qualifying entries returned for that scope, not an all-clear. + NVE asks reusers to present complete bulletin context and credit Varsom. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the NVE flood API and full-bulletin attribution conditions. + - Request a two-day date interval with the English language key. + - Preserve warning validity and municipality context with any result. + python: + packages: + - requests + code: | + from datetime import date, timedelta + import requests + + today = date.today() + tomorrow = today + timedelta(days=1) + url = ("https://api01.nve.no/hydrology/forecast/flood/v1.0.10/api/" + f"Warning/2/{today.isoformat()}/{tomorrow.isoformat()}") + response = requests.get(url, timeout=30) + response.raise_for_status() + warnings = response.json() + print(f"{len(warnings)} regional flood warnings in this two-day response") + for warning in warnings[:5]: + print(warning.get("Id"), warning.get("ActivityLevel")) + first_project: + title: Inspect Two Days of Flood Warnings + goal: Check a bounded regional warning response before local matching. + steps: + - Keep warning identifiers, date range, municipality IDs, and revisions. + - Read full bulletins rather than inferring meaning from one activity number. + - Explain why an empty list cannot establish nationwide safety. diff --git a/data/datasets/open-meteo-air-quality.yaml b/data/datasets/open-meteo-air-quality.yaml new file mode 100644 index 0000000..da457fa --- /dev/null +++ b/data/datasets/open-meteo-air-quality.yaml @@ -0,0 +1,77 @@ +id: open-meteo-air-quality +name: Open-Meteo Air Quality Forecast +description: > + Modeled European air-quality forecasts served by Open-Meteo for inspecting + point-level AQI context under noncommercial free API terms. +theme: Environment & Hazards +url: https://open-meteo.com/en/docs/air-quality-api +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Free API is for noncommercial use only, with CC BY 4.0 attribution and rate limits; acknowledge CAMS model data where used. +license_url: https://open-meteo.com/en/terms +url_checks: + source_marker: European Air Quality Index + license_marker: You may only use the free API services for non-commercial purposes +domains: + - Air Quality + - Forecasting +data_types: + - Time Series + - Forecast Data +tasks: + - Forecasting + - Risk Mapping +difficulty: beginner +geography: + - Europe +temporal_coverage: current hourly forecasts +update_frequency: continuous +provider: Open-Meteo with Copernicus Atmosphere Monitoring Service model data +source_type: company +last_verified: 2026-09-28 +access_profile: + friction: low + setup_minutes: 5 + registration_required: false + rate_limit_notes: Free noncommercial API permits fewer than 10000 calls per day. +getting_started: + overview: > + Start with one point and one day. The free Open-Meteo air-quality endpoint permits noncommercial use only; + commercial services need separate paid access. It serves modeled CAMS + air-quality context, not a direct station observation or health all-clear. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read Open-Meteo's noncommercial service terms and CAMS attribution guidance. + - Request one point and one day of European AQI forecasts. + - Preserve the model label and timestamps with displayed values. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://air-quality-api.open-meteo.com/v1/air-quality", + params={"latitude": 52.52, "longitude": 13.41, + "hourly": "european_aqi", "forecast_days": 1}, + timeout=30, + ) + response.raise_for_status() + hourly = response.json()["hourly"] + print(list(zip(hourly["time"], hourly["european_aqi"]))[:5]) + first_project: + title: Inspect a Modeled AQI Day + goal: Assess whether one forecast series supports noncommercial air-quality context. + steps: + - Keep the model source, units, and issue context with hourly values. + - Inspect missing values before displaying an AQI badge. + - Explain the noncommercial API limit and why modeled AQI is not a station reading. diff --git a/data/datasets/open-meteo-marine.yaml b/data/datasets/open-meteo-marine.yaml new file mode 100644 index 0000000..f279950 --- /dev/null +++ b/data/datasets/open-meteo-marine.yaml @@ -0,0 +1,77 @@ +id: open-meteo-marine +name: Open-Meteo Marine Forecast +description: > + Hourly offshore marine forecasts from Open-Meteo for coastal planning context + under the free API's noncommercial use limit. +theme: Environment & Hazards +url: https://open-meteo.com/en/docs/marine-weather-api +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Free API is for noncommercial use only, with CC BY 4.0 attribution and rate limits. +license_url: https://open-meteo.com/en/terms +url_checks: + source_marker: Marine Weather API + license_marker: You may only use the free API services for non-commercial purposes +domains: + - Weather + - Forecasting +data_types: + - Time Series + - Forecast Data +tasks: + - Forecasting + - Operational Planning +difficulty: beginner +geography: + - Global coastlines +temporal_coverage: current hourly forecasts +update_frequency: continuous +provider: Open-Meteo +source_type: company +last_verified: 2026-09-28 +access_profile: + friction: low + setup_minutes: 5 + registration_required: false + rate_limit_notes: Free noncommercial API permits fewer than 10000 calls per day. +getting_started: + overview: > + Start with one offshore point and one forecast day. The free Open-Meteo marine endpoint permits noncommercial use only; + commercial services need separate paid access. Query a reviewed offshore + point; a returned model cell is not beach, navigation, or ferry safety advice. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the free API noncommercial terms and marine model limitations. + - Choose a suitable offshore point and request one day of wave forecasts. + - Check that the returned grid cell and wave values apply to that point. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://marine-api.open-meteo.com/v1/marine", + params={"latitude": 53.208336, "longitude": -9.2916565, + "hourly": "wave_height", "forecast_days": 1}, + timeout=30, + ) + response.raise_for_status() + hourly = response.json()["hourly"] + print(list(zip(hourly["time"], hourly["wave_height"]))[:5]) + first_project: + title: Inspect One Offshore Wave Forecast + goal: Assess one wave-height series as noncommercial coastal context. + steps: + - Verify the returned point is offshore and inspect missing wave values. + - Record the time, unit, and model source for each displayed value. + - Explain the noncommercial API limit and why forecasts are not marine safety advice. diff --git a/data/datasets/open-meteo-weather-forecast.yaml b/data/datasets/open-meteo-weather-forecast.yaml new file mode 100644 index 0000000..95837ce --- /dev/null +++ b/data/datasets/open-meteo-weather-forecast.yaml @@ -0,0 +1,77 @@ +id: open-meteo-weather-forecast +name: Open-Meteo Weather Forecast +description: > + Hourly point weather forecasts from Open-Meteo for planning location-specific + conditions panels, subject to noncommercial free API terms. +theme: Environment & Hazards +url: https://open-meteo.com/en/docs +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: Free API is for noncommercial use only, with CC BY 4.0 attribution and rate limits. +license_url: https://open-meteo.com/en/terms +url_checks: + source_marker: Weather Forecast API + license_marker: You may only use the free API services for non-commercial purposes +domains: + - Weather + - Forecasting +data_types: + - Time Series + - Forecast Data +tasks: + - Forecasting + - Operational Planning +difficulty: beginner +geography: + - Global +temporal_coverage: current hourly forecasts +update_frequency: continuous +provider: Open-Meteo +source_type: company +last_verified: 2026-09-28 +access_profile: + friction: low + setup_minutes: 5 + registration_required: false + rate_limit_notes: Free noncommercial API permits fewer than 10000 calls per day. +getting_started: + overview: > + The free Open-Meteo weather endpoint permits noncommercial use only; commercial + services need separate paid access. Start with one point and one forecast day. + Model output is not a local observation or official weather warning. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the free API noncommercial terms and attribution requirements. + - Choose one coordinate and limit the forecast to one day. + - Compare the hourly timestamps with the location's time zone before display. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://api.open-meteo.com/v1/forecast", + params={"latitude": 52.52, "longitude": 13.41, + "hourly": "temperature_2m", "forecast_days": 1}, + timeout=30, + ) + response.raise_for_status() + hourly = response.json()["hourly"] + print(list(zip(hourly["time"], hourly["temperature_2m"]))[:5]) + first_project: + title: Inspect a One-Day Weather Forecast + goal: Check whether hourly temperatures support a noncommercial local conditions card. + steps: + - Keep the returned units and forecast timestamps with each value. + - Display five hourly temperatures for the selected point. + - Explain the noncommercial API limit and why a forecast is not an official warning. diff --git a/data/datasets/opw-ireland-water-levels.yaml b/data/datasets/opw-ireland-water-levels.yaml new file mode 100644 index 0000000..88d3bf6 --- /dev/null +++ b/data/datasets/opw-ireland-water-levels.yaml @@ -0,0 +1,74 @@ +id: opw-ireland-water-levels +name: OPW Ireland Water Levels +description: > + Provisional Irish gauge-level observations from the Office of Public Works + for local river context and station monitoring. +theme: Environment & Hazards +url: https://waterlevel.ie/page/api/ +access_type: + - both +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - GeoJSON + - CSV +license: CC BY 4.0 for eligible station numbers 00001-41000; attribute the Office of Public Works. +license_url: https://waterlevel.ie/page/api/ +url_checks: + source_marker: Geojson file with latest readings + license_marker: Only monitoring stations with reference numbers between 00001 and 41000 +domains: + - Hydrology + - Emergency Management +data_types: + - Geospatial + - Time Series +tasks: + - Monitoring + - Operational Planning +difficulty: intermediate +geography: + - Ireland +temporal_coverage: recent provisional gauge readings +update_frequency: near real time +provider: Ireland Office of Public Works +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + OPW publishes a pre-generated GeoJSON snapshot of latest readings. Start with five eligible readings. Use that + file for automated access and restrict republication to eligible station + numbers 00001-41000. Measurements are provisional, relative to station + gauge zero, and are not official flood warnings. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official API page, station eligibility rule, and CC BY terms. + - Fetch the pre-generated latest-readings GeoJSON at a sensible interval. + - Filter to eligible station numbers before using or republishing values. + python: + packages: + - requests + code: | + import requests + + response = requests.get("https://waterlevel.ie/geojson/latest/", timeout=30) + response.raise_for_status() + features = response.json()["features"] + eligible = [ + item["properties"] for item in features + if 1 <= int(item["properties"]["station_ref"]) <= 41000 + ] + for item in eligible[:5]: + print(item["station_ref"], item["datetime"], item["value"]) + first_project: + title: Check Recent Eligible Gauge Readings + goal: Assess whether a small set of current gauges supports a factual river-level panel. + steps: + - Retain station and sensor IDs, timestamps, quality codes, and gauge units. + - Exclude out-of-range station references from republication. + - State that provisional gauge readings are not official flood warnings. diff --git a/data/datasets/osm-nominatim-search.yaml b/data/datasets/osm-nominatim-search.yaml new file mode 100644 index 0000000..b4a2fe3 --- /dev/null +++ b/data/datasets/osm-nominatim-search.yaml @@ -0,0 +1,76 @@ +id: osm-nominatim-search +name: OpenStreetMap Nominatim Search +description: > + Public Nominatim place-search responses derived from OpenStreetMap for + checking one user-requested address or road candidate. +theme: Geospatial & Infrastructure +url: https://nominatim.org/release-docs/latest/api/Search/ +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + ODbL 1.0 data with OpenStreetMap attribution. Public service allows at most + one request per second per application, requires an identifying User-Agent, + forbids autocomplete and systematic queries, and may withdraw access. +license_url: https://operations.osmfoundation.org/policies/nominatim/ +url_checks: + source_marker: Search - Nominatim + license_marker: maximum of 1 request per second +domains: + - Geography +data_types: + - Geospatial +tasks: + - Search +difficulty: beginner +geography: + - Global +temporal_coverage: current OpenStreetMap search index +update_frequency: near real time +provider: OpenStreetMap Foundation +source_type: community +last_verified: 2026-09-28 +getting_started: + overview: > + Read the public Nominatim usage policy before calling this shared service: + at most one request per second per application, a distinct identifying + User-Agent, attribution, caching, no autocomplete, and no systematic or + bulk queries. Start with one public landmark address. ODbL share-alike + applies to the OSM-derived data; keep a provider switch available if the + public service withdraws access. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the Nominatim policy and ODbL conditions in full. + - Search one public landmark address with an identifying User-Agent. + - Inspect the returned location and OSM attribution. + python: + packages: + - requests + code: | + import requests + + response = requests.get( + "https://nominatim.openstreetmap.org/search", + params={"q": "1600 Pennsylvania Avenue NW, Washington, DC", + "format": "jsonv2", "limit": 1}, + headers={"User-Agent": "TrilemmaDataCatalogExample/1.0 (https://data.trilemma.foundation/)"}, + timeout=30, + ) + response.raise_for_status() + for place in response.json(): + print(place["display_name"], place["lat"], place["lon"]) + first_project: + title: Inspect One Public Place Match + goal: Check one user-triggered place candidate with the shared Nominatim API. + steps: + - Display OpenStreetMap attribution with the result. + - Require user confirmation before treating a road match as a property. + - Explain why a public demo service is unsuitable for bulk geocoding. diff --git a/data/datasets/photon-geocoding.yaml b/data/datasets/photon-geocoding.yaml new file mode 100644 index 0000000..6a8d279 --- /dev/null +++ b/data/datasets/photon-geocoding.yaml @@ -0,0 +1,59 @@ +id: photon-geocoding +name: Photon Place Search +description: > + OpenStreetMap-based Photon place-search results for adding small-scale geocoding to a map application. +theme: Geospatial & Infrastructure +url: https://photon.komoot.io/api/?q=Zurich&limit=2 +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [GeoJSON] +license: > + Komoot permits reasonable free use of its public demo without uptime guarantees; + OpenStreetMap-derived data requires ODbL attribution and share-alike compliance. +license_url: https://github.com/komoot/photon/blob/master/README.md +url_checks: + source_marker: '"name":"Zurich","' + license_marker: number of requests stay in a reasonable +domains: [Geography] +data_types: [Geospatial] +tasks: [Search, Mapping] +difficulty: beginner +geography: [Global] +temporal_coverage: current Photon search index +update_frequency: occasional +provider: Komoot Photon +source_type: company +last_verified: 2026-09-28 +getting_started: + overview: > + Komoot's public Photon demo answers small place searches without a key. + Start with one query and two results; the demo may throttle heavy use and + has no availability guarantee, while OpenStreetMap attribution still applies. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read the Photon public demo policy and OpenStreetMap data terms. + - Search for one place with a two-result limit. + - Inspect each candidate's name and coordinates before using it. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://photon.komoot.io/api/", + params={"q": "Zurich", "limit": 2}, + headers={"User-Agent": "TrilemmaDataCatalog/1.0"}, timeout=20, + ) + response.raise_for_status() + for place in response.json()["features"]: + print(place["properties"].get("name"), place["geometry"]["coordinates"]) + first_project: + title: Search for Map Destinations + goal: Show two geocoding candidates with their source coordinates. + steps: + - Query one place name with a bounded result count. + - Display candidate labels and coordinates for user selection. + - Explain that similarly named places require location confirmation. diff --git a/data/datasets/pse-energy-compass.yaml b/data/datasets/pse-energy-compass.yaml new file mode 100644 index 0000000..878f4bd --- /dev/null +++ b/data/datasets/pse-energy-compass.yaml @@ -0,0 +1,60 @@ +id: pse-energy-compass +name: PSE Energy Compass Advisories +description: > + Polish grid operator PSE's hourly national electricity-use recommendations for building dated system-context tools. +theme: Geospatial & Infrastructure +url: https://api.raporty.pse.pl/api/pdgsz?$filter=is_active%20eq%20true&$orderby=dtime_utc%20desc&$first=48 +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: > + PSE permits free commercial and noncommercial public-information reuse with source/date attribution, + removal of the PSE logo, and clear labeling of processed results. +license_url: https://www.pse.pl/bip/ponowne-wykorzystanie-informacji-publicznej +url_checks: + source_marker: '"publication_ts_utc"' + license_marker: ponownego wykorzystywania informacji sektora publicznego +domains: [Energy] +data_types: [Time Series] +tasks: [Monitoring] +difficulty: beginner +geography: [Poland] +temporal_coverage: current and near-future national hourly advisories +update_frequency: near real time +provider: Polskie Sieci Elektroenergetyczne +source_type: company +last_verified: 2026-09-28 +getting_started: + overview: > + PSE publishes the Energy Compass forecast through its official reports API. + Start with the first active hourly row, keeping its UTC time and publication + time. The advice describes Poland-wide electricity-system conditions and + cannot establish a local power outage. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Read PSE's Energy Compass explanation and public-information reuse conditions. + - Fetch a bounded set of active hourly recommendations. + - Record the publication time, valid hour, and usage forecast code. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://api.raporty.pse.pl/api/pdgsz", + params={"$filter": "is_active eq true", "$orderby": "dtime_utc desc", "$first": 48}, + timeout=20, + ) + response.raise_for_status() + for row in response.json()["value"][:2]: + print(row["dtime_utc"], row["usage_fcst"], row["publication_ts_utc"]) + first_project: + title: Inspect National Grid Advice + goal: Display one hourly recommendation with its publication time and national scope. + steps: + - Fetch the latest active Energy Compass rows. + - Label the UTC valid hour and publication time. + - Explain why a country-wide advisory does not report a local interruption. diff --git a/data/datasets/rijkswaterstaat-current-water-levels.yaml b/data/datasets/rijkswaterstaat-current-water-levels.yaml new file mode 100644 index 0000000..7f0bb3d --- /dev/null +++ b/data/datasets/rijkswaterstaat-current-water-levels.yaml @@ -0,0 +1,69 @@ +id: rijkswaterstaat-current-water-levels +name: Rijkswaterstaat Current Water Levels +description: > + Current Dutch river and coastal station observations with quality and NAP-datum metadata for local water-level context tools. +theme: Environment & Hazards +url: https://rijkswaterstaatdata.nl/waterdata/ +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [JSON] +license: > + Rijkswaterstaat applies CC0 to WaterWebservices content, except where an individual component says otherwise; fair-use limits apply. +license_url: https://rijkswaterstaatdata.nl/waterdata/ +url_checks: + source_marker: OphalenLaatsteWaarnemingen + license_marker: Creative Commons zero verklaring +domains: [Water Resources] +data_types: [Time Series] +tasks: [Monitoring] +difficulty: intermediate +geography: [Netherlands] +temporal_coverage: current observations at named stations +update_frequency: near real time +provider: Rijkswaterstaat +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + Rijkswaterstaat's operational WaterWebservices publish the latest reading for a named station. + Start with one station and retain its quality code, observation time, and NAP datum; + a water-level measurement is not a flood warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the current WaterWebservices documentation and CC0 scope. + - Request one station's latest OW water-height measurement in centimeters relative to NAP. + - Check the timestamp and quality code before interpreting the value. + python: + packages: [requests] + code: | + import requests + + url = "https://ddapi20-waterwebservices.rijkswaterstaat.nl/ONLINEWAARNEMINGENSERVICES/OphalenLaatsteWaarnemingen" + payload = { + "LocatieLijst": [{"Code": "amsterdam.surinamekade"}], + "AquoPlusWaarnemingMetadataLijst": [{ + "AquoMetadata": { + "Compartiment": {"Code": "OW"}, "Grootheid": {"Code": "WATHTE"}, + "Eenheid": {"Code": "cm"}, "Hoedanigheid": {"Code": "NAP"}, + "ProcesType": "meting", + }, + "WaarnemingMetadata": {"KwaliteitswaardecodeLijst": ["00", "10", "20", "25", "30", "40"]}, + }], + } + response = requests.post(url, json=payload, timeout=20) + response.raise_for_status() + for station in response.json()["WaarnemingenLijst"][:1]: + for reading in station["MetingenLijst"][:1]: + print(station["Locatie"]["Naam"], reading["Tijdstip"], + reading["Meetwaarde"]["Waarde_Numeriek"], + reading["WaarnemingMetadata"]["Kwaliteitswaardecode"]) + first_project: + title: Inspect One Water-Level Reading + goal: Display a dated, quality-labeled observation at a named Dutch station. + steps: + - Fetch the latest observation for one mapped station. + - Show its time, quality code, and centimeter value relative to NAP. + - Explain that the reading does not establish an official flood warning. diff --git a/data/datasets/slf-avalanche-bulletins.yaml b/data/datasets/slf-avalanche-bulletins.yaml new file mode 100644 index 0000000..ae6f8ba --- /dev/null +++ b/data/datasets/slf-avalanche-bulletins.yaml @@ -0,0 +1,66 @@ +id: slf-avalanche-bulletins +name: SLF Avalanche Bulletins +description: Swiss official avalanche bulletin GeoJSON for building a dated mountain hazard context map. +theme: Environment & Hazards +url: https://aws.slf.ch/api/bulletin/caaml/v4/en/geojson?activeAt=2026-01-11T11%3A30Z +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- GeoJSON +license: CC BY 4.0; visibly attribute WSL Institute for Snow and Avalanche Research SLF and link its digital + source. +license_url: https://www.slf.ch/en/services-and-products/slf-data-service/ +url_checks: + source_marker: '"validTime":{"startTime"' + license_marker: The data is subject to the licence +domains: +- Natural Hazards +data_types: +- Event Data +- Geospatial +tasks: +- Monitoring +- Mapping +difficulty: beginner +geography: +- Switzerland +temporal_coverage: seasonal or current official warnings +update_frequency: near real time +provider: WSL Institute for Snow and Avalanche Research SLF +source_type: academic +last_verified: '2026-09-28' +getting_started: + overview: The official WSL Institute for Snow and Avalanche Research SLF feed supports regional hazard + context. Start with two archived January 2026 bulletin regions; an archived bulletin is not a current + avalanche warning and off-season responses can be empty. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official feed documentation and reuse terms. + - Fetch one bounded official response. + - Inspect two records and retain their validity period. + python: + packages: + - requests + code: | + import requests + + url = "https://aws.slf.ch/api/bulletin/caaml/v4/en/geojson" + response = requests.get(url, params={"activeAt": "2026-01-11T11:30:00Z"}, timeout=20) + response.raise_for_status() + for region in response.json()["features"][:2]: + props = region["properties"] + print(props.get("bulletinID"), props.get("validTime")) + first_project: + title: Map Dated Regional Warnings + goal: Inspect two archived January 2026 bulletin regions with official validity and source links. + steps: + - Fetch one official response and retain its issue time. + - Display two region or river records with their source links. + - Explain why coverage and validity cannot be inferred beyond the named area. diff --git a/data/datasets/smhi-water-shortage-messages.yaml b/data/datasets/smhi-water-shortage-messages.yaml new file mode 100644 index 0000000..b8f4e6f --- /dev/null +++ b/data/datasets/smhi-water-shortage-messages.yaml @@ -0,0 +1,67 @@ +id: smhi-water-shortage-messages +name: SMHI Water Shortage Messages +description: > + Official Swedish water-shortage information messages from the impact-based + warning API, with dated affected-area and validity metadata for local water-risk review. +theme: Environment & Hazards +url: https://opendata-download-warnings.smhi.se/ibww/api/version/1 +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: [JSON] +license: > + SMHI warnings and messages may be used for commercial or noncommercial purposes, + but their information must not be altered; always attribute SMHI and heed all + validity times. These special warning terms override the general CC BY data terms. +license_url: https://www.smhi.se/data/om-smhis-data/villkor-for-anvandning +url_checks: + source_marker: SMHI Impact Based Weather Warnings Download + license_marker: Informationen får inte ändras +domains: [Water Resources, Emergency Management] +data_types: [Event Data, Geospatial] +tasks: [Monitoring, Alerting] +difficulty: beginner +geography: [Sweden] +temporal_coverage: current official information messages +update_frequency: near real time +provider: Swedish Meteorological and Hydrological Institute +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The documented SMHI impact-based warning API also publishes official + water-shortage information messages. Start with one current warning list, + filter by the documented event code, and keep message text and its timing intact; + a message without valid time and area context is not a local warning. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the official API entry and the special warning and message terms. + - Request the current warning JSON once and select WATER_SHORTAGE events. + - Check affected areas and validity before displaying an unchanged message. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://opendata-download-warnings.smhi.se/ibww/api/version/1/warning.json", + timeout=20, + ) + response.raise_for_status() + messages = [warning for warning in response.json() + if warning.get("event", {}).get("code") == "WATER_SHORTAGE"] + print(f"{len(messages)} current water-shortage messages") + for message in messages[:3]: + for area in message.get("warningAreas", [])[:2]: + name = area.get("areaName", {}) + print(message["id"], name.get("en") or name.get("sv"), + area.get("published"), area.get("approximateStart")) + first_project: + title: Review Current Water Shortage Information + goal: List a few official messages with their affected areas and publication times. + steps: + - Preserve the source message and event code without changing its wording. + - Show affected areas and validity alongside every message. + - Cite SMHI and refresh before presenting current conditions. diff --git a/data/datasets/syke-hydrology-water-levels.yaml b/data/datasets/syke-hydrology-water-levels.yaml new file mode 100644 index 0000000..fd4fa08 --- /dev/null +++ b/data/datasets/syke-hydrology-water-levels.yaml @@ -0,0 +1,57 @@ +id: syke-hydrology-water-levels +name: SYKE Hydrology Water Levels +description: > + Finnish environmental OData water-level measurements for station-based hydrology monitoring and comparison across basins. +theme: Environment & Hazards +url: https://www.syke.fi/en/environmental-data/open-web-services/environmental-data-apis +access_type: [api] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: [JSON] +license: > + Finnish Environment Institute open data are CC BY 4.0; name SYKE and the hydrology dataset when reusing values. +license_url: https://www.syke.fi/en/environmental-data/use-license-and-responsibilities +url_checks: + source_marker: The interface for hydrology provides spatial and temporal information + license_marker: licenced under Creative Commons Attribution 4.0 International licence +domains: [Water Resources] +data_types: [Time Series] +tasks: [Monitoring] +difficulty: intermediate +geography: [Finland] +temporal_coverage: observed Finnish station water levels and historical records +update_frequency: near real time +provider: Finnish Environment Institute +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + SYKE's Hydrologiarajapinta OData service exposes Vedenkorkeus water-level observations and separate datum metadata. + Start with one recent value; a level cannot be compared across stations without reference-system and quality checks. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the SYKE hydrology OData entities and CC BY licence. + - Request one latest Vedenkorkeus row. + - Keep its place ID, timestamp, value, and quality flag for later station-metadata lookup. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://rajapinnat.ymparisto.fi/api/Hydrologiarajapinta/1.2/odata/Vedenkorkeus", + params={"$top": 1, "$orderby": "Aika desc"}, + headers={"Accept": "application/json"}, timeout=25, + ) + response.raise_for_status() + for row in response.json()["value"]: + print(row["Paikka_Id"], row["Aika"], row["Arvo"], row["Lippu_id"]) + first_project: + title: Inspect One Finnish Water Level + goal: Display one dated OData measurement with its station and quality identifiers. + steps: + - Fetch one recent Vedenkorkeus record. + - Show its place ID, date, value, and quality-flag ID. + - Explain that a datum lookup is needed before cross-station comparison. diff --git a/data/datasets/treasury-yield-curve.yaml b/data/datasets/treasury-yield-curve.yaml new file mode 100644 index 0000000..da09127 --- /dev/null +++ b/data/datasets/treasury-yield-curve.yaml @@ -0,0 +1,80 @@ +id: treasury-yield-curve +name: U.S. Treasury Daily Yield Curve +description: > + Official daily U.S. Treasury par yield curve rates in XML for building + dated fixed-income context and comparing interest-rate terms. +theme: Markets & Economics +url: https://home.treasury.gov/treasury-daily-interest-rate-xml-feed +access_type: + - api + - download +api_key_required: false +free_to_access: true +size_gb_min: 0.000001 +size_gb_max: 0.1 +formats: + - XML +license: U.S. Government public data / federal copyright guidance +license_url: https://www.usa.gov/government-copyright +url_checks: + source_marker: Treasury Daily Interest Rate XML Feed + license_marker: federal government materials +domains: + - Fixed Income + - Macroeconomics +data_types: + - Time Series + - Numeric Data +tasks: + - Economic Monitoring + - Trend Analysis +difficulty: intermediate +geography: + - United States +temporal_coverage: daily par yield curve rates from 1990 to present +update_frequency: daily +provider: U.S. Department of the Treasury +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + Treasury publishes daily par yield curves through a dated XML feed. Start + with the current month and the 10-year tenor, retaining the observation date. + A par yield is not a real-time trade quote or an option's realized return. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Open Treasury's XML feed documentation and choose the daily par yield curve dataset. + - Request only the current month using its YYYYMM parameter. + - Read the observation date and tenor field without mixing rates from different dates. + python: + packages: + - requests + code: | + from datetime import date + import xml.etree.ElementTree as ET + import requests + + month = date.today().strftime("%Y%m") + response = requests.get( + "https://home.treasury.gov/resource-center/data-chart-center/interest-rates/pages/xml", + params={ + "data": "daily_treasury_yield_curve", + "field_tdr_date_value_month": month, + }, + timeout=30, + ) + response.raise_for_status() + root = ET.fromstring(response.content) + for entry in list(root)[-5:]: + fields = {node.tag.rsplit("}", 1)[-1]: node.text for node in entry.iter()} + print(fields.get("NEW_DATE", "")[:10], fields.get("BC_10YEAR")) + first_project: + title: Track a Dated Treasury Tenor + goal: Test whether a short yield-curve series supports a fixed-income context panel. + steps: + - Retrieve the current month and retain the date alongside each 10-year par yield. + - Compare the available business-day observations without filling weekends with invented rates. + - Explain why par yields and dated official releases are not live market quotes. diff --git a/data/datasets/usgs-3dep-one-arc-second.yaml b/data/datasets/usgs-3dep-one-arc-second.yaml new file mode 100644 index 0000000..d4d713d --- /dev/null +++ b/data/datasets/usgs-3dep-one-arc-second.yaml @@ -0,0 +1,56 @@ +id: usgs-3dep-one-arc-second +name: USGS 3DEP One Arc-Second Elevation +description: > + USGS one arc-second elevation GeoTIFF tiles for measuring terrain relief and ruggedness across mapped regions. +theme: Geospatial & Infrastructure +url: https://www.usgs.gov/3d-elevation-program/about-3dep-products-services +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.0003 +size_gb_max: 100 +formats: [GeoTIFF] +license: USGS 3DEP elevation data are public domain; cite the tile vintage and retain vertical-datum metadata. +license_url: https://www.usa.gov/government-copyright +url_checks: + source_marker: 1 arc-second dataset. Ground spacing is approximately 30 meters + license_marker: federal government materials +domains: [Natural Hazards] +data_types: [Raster] +tasks: [Mapping] +difficulty: intermediate +geography: [United States] +temporal_coverage: current and historical one arc-second tile vintages +update_frequency: occasional +provider: U.S. Geological Survey +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The National Map stages 3DEP one arc-second GeoTIFF tiles, including historical versions pinned by HouseHunter. + Start with one small coastal tile; a bare raster value cannot be interpreted without no-data, unit, and datum metadata. + prerequisites: [Python 3.10 or newer, An internet connection, The requests and rasterio Python packages] + access_steps: + - Review the official 3DEP resolution and vertical-datum documentation. + - Download one pinned one arc-second GeoTIFF tile. + - Inspect its bounds, no-data value, and a small overview before comparing terrain. + python: + packages: [requests, rasterio] + code: | + import requests + from rasterio.io import MemoryFile + + url = "https://prd-tnm.s3.amazonaws.com/StagedProducts/Elevation/1/TIFF/historical/n32w081/USGS_1_n32w081_20220725.tif" + response = requests.get(url, timeout=35) + response.raise_for_status() + with MemoryFile(response.content) as memory: + with memory.open() as tile: + overview = tile.read(1, out_shape=(36, 36), masked=True) + print(tile.bounds, tile.nodata, float(overview.min()), float(overview.max())) + first_project: + title: Inspect One Elevation Tile + goal: Show a tile's geographic bounds and the range of sampled elevation values. + steps: + - Download one small official 3DEP GeoTIFF. + - Display its bounds, no-data marker, and overview value range. + - Explain why different vintages and vertical references must be reconciled before comparison. diff --git a/data/datasets/usgs-national-trails-geopackage.yaml b/data/datasets/usgs-national-trails-geopackage.yaml new file mode 100644 index 0000000..d2315fd --- /dev/null +++ b/data/datasets/usgs-national-trails-geopackage.yaml @@ -0,0 +1,63 @@ +id: usgs-national-trails-geopackage +name: USGS National Trails GeoPackages +description: > + State-level National Transportation Database trail segments for measuring mapped outdoor access and trail density. +theme: Geospatial & Infrastructure +url: https://www.usgs.gov/national-digital-trails/how-access-or-view-usgs-trails-dataset +access_type: [download] +api_key_required: false +free_to_access: true +size_gb_min: 0.006 +size_gb_max: 2 +formats: [ZIP, GeoPackage] +license: U.S. Geological Survey National Transportation Database trail data are public domain; cite the source and preserve the product date. +license_url: https://www.usa.gov/government-copyright +url_checks: + source_marker: trails dataset is a feature class in the USGS National Transportation Database + license_marker: federal government materials +domains: [Transportation] +data_types: [Geospatial] +tasks: [Mapping] +difficulty: intermediate +geography: [United States] +temporal_coverage: periodically refreshed state and District of Columbia trail extracts +update_frequency: occasional +provider: U.S. Geological Survey +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + USGS stages state-level transportation GeoPackages containing Trans_TrailSegment. + Start with the 5.8 MB District of Columbia archive; mapped segments do not prove legal public access or trail condition. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the USGS National Trails download instructions and staged-product update policy. + - Download one small state GeoPackage ZIP. + - Query a single Trans_TrailSegment row while retaining the archive date. + python: + packages: [requests] + code: | + import io + import sqlite3 + import tempfile + import zipfile + from pathlib import Path + import requests + + url = "https://prd-tnm.s3.amazonaws.com/StagedProducts/Tran/GPKG/TRAN_District_of_Columbia_State_GPKG.zip" + response = requests.get(url, timeout=35) + response.raise_for_status() + with zipfile.ZipFile(io.BytesIO(response.content)) as archive: + member = next(name for name in archive.namelist() if name.endswith(".gpkg")) + with tempfile.TemporaryDirectory() as directory: + path = Path(directory) / "trails.gpkg" + path.write_bytes(archive.read(member)) + with sqlite3.connect(path) as db: + print(db.execute("SELECT name, lengthmiles FROM Trans_TrailSegment LIMIT 1").fetchone()) + first_project: + title: Inspect a Trail Segment + goal: Display one dated USGS trail record and its mapped length. + steps: + - Download one small official state archive. + - Read a Trans_TrailSegment row from its GeoPackage. + - Explain that the mapped line does not establish access rights or current trail condition. diff --git a/data/datasets/usgs-pad-us-4-1.yaml b/data/datasets/usgs-pad-us-4-1.yaml new file mode 100644 index 0000000..37a051e --- /dev/null +++ b/data/datasets/usgs-pad-us-4-1.yaml @@ -0,0 +1,57 @@ +id: usgs-pad-us-4-1 +name: USGS PAD-US 4.1 Public Access +description: > + USGS protected-area polygons and public-access attributes for measuring nearby open-land context in residential comparisons. +theme: Geospatial & Infrastructure +url: https://edits.nationalmap.gov/arcgis/rest/services/PAD-US/PAD_US_gaz_combined/MapServer/0?f=json +access_type: [api, download] +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 20 +formats: [JSON, Geodatabase] +license: U.S. Geological Survey PAD-US data are public domain; cite the 4.1 release and retain access-status definitions. +license_url: https://www.usa.gov/government-copyright +url_checks: + source_marker: PADUS4_1Combined + license_marker: federal government materials +domains: [Natural Hazards] +data_types: [Geospatial] +tasks: [Mapping] +difficulty: intermediate +geography: [United States] +temporal_coverage: PAD-US version 4.1, maintained as an official USGS release +update_frequency: occasional +provider: U.S. Geological Survey +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + The official PAD-US 4.1 combined MapServer publishes ownership and public-access attributes. + Start with one feature; a protected designation alone does not mean public access. + prerequisites: [Python 3.10 or newer, An internet connection, The requests Python package] + access_steps: + - Review the USGS PAD-US 4.1 release and public-access field definitions. + - Query one feature from the combined MapServer layer. + - Keep the access code separate from the protected-area category. + python: + packages: [requests] + code: | + import requests + + response = requests.get( + "https://edits.nationalmap.gov/arcgis/rest/services/PAD-US/PAD_US_gaz_combined/MapServer/0/query", + params={"where": "1=1", "outFields": "OBJECTID,Unit_Nm,Pub_Access", + "returnGeometry": "false", "resultRecordCount": 1, "f": "json"}, + timeout=25, + ) + response.raise_for_status() + for feature in response.json()["features"]: + print(feature["attributes"]) + first_project: + title: Inspect Protected-Area Access + goal: Show one PAD-US unit and its published public-access code. + steps: + - Fetch one PAD-US 4.1 feature. + - Display its unit name and access code. + - Explain why unknown access cannot be counted as freely accessible land. diff --git a/data/datasets/vigicrues-flood-vigilance-rss.yaml b/data/datasets/vigicrues-flood-vigilance-rss.yaml new file mode 100644 index 0000000..19f5e61 --- /dev/null +++ b/data/datasets/vigicrues-flood-vigilance-rss.yaml @@ -0,0 +1,65 @@ +id: vigicrues-flood-vigilance-rss +name: Vigicrues Flood Vigilance RSS +description: French river flood-vigilance RSS items for building a dated regional river-warning view. +theme: Environment & Hazards +url: https://www.vigicrues.gouv.fr/territoire/rss +access_type: +- api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.001 +formats: +- RSS +license: Public Vigicrues content is reusable under the French Etalab Open Licence with source and update-date + attribution; third-party map content has separate rights. +license_url: https://www.vigicrues.gouv.fr/categorie/2 +url_checks: + source_marker: 'Vigicrues : Tronçon(s) de cours' + license_marker: librement et gratuitement +domains: +- Natural Hazards +data_types: +- Event Data +- Geospatial +tasks: +- Monitoring +- Mapping +difficulty: beginner +geography: +- France +temporal_coverage: seasonal or current official warnings +update_frequency: near real time +provider: Vigicrues +source_type: government +last_verified: '2026-09-28' +getting_started: + overview: The official Vigicrues feed supports regional hazard context. Start with two French river-vigilance + items; a feed item covers its named river segment, not every nearby location. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the official feed documentation and reuse terms. + - Fetch one bounded official response. + - Inspect two records and retain their validity period. + python: + packages: + - requests + code: | + import requests + from xml.etree import ElementTree as ET + + response = requests.get("https://www.vigicrues.gouv.fr/territoire/rss", timeout=20) + response.raise_for_status() + root = ET.fromstring(response.content) + for item in root.findall("./channel/item")[:2]: + print(item.findtext("title"), item.findtext("pubDate"), item.findtext("link")) + first_project: + title: Map Dated Regional Warnings + goal: Inspect two French river-vigilance items with official validity and source links. + steps: + - Fetch one official response and retain its issue time. + - Display two region or river records with their source links. + - Explain why coverage and validity cannot be inferred beyond the named area. diff --git a/data/datasets/wfigs-current-incidents.yaml b/data/datasets/wfigs-current-incidents.yaml new file mode 100644 index 0000000..5be55f0 --- /dev/null +++ b/data/datasets/wfigs-current-incidents.yaml @@ -0,0 +1,76 @@ +id: wfigs-current-incidents +name: WFIGS Current Wildfire Incidents +description: > + Agency-reported U.S. current wildfire incident points from NIFC for + inspecting incident identity, location, size, and update time. +theme: Environment & Hazards +url: https://www.arcgis.com/sharing/rest/content/items/4181a117dc9e43db8598533e29972015?f=json +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + Public federal wildfire information with NIFC and contributing-agency + attribution; item-specific accuracy and non-legal-use notices apply. +license_url: https://www.arcgis.com/sharing/rest/content/items/4181a117dc9e43db8598533e29972015?f=json +url_checks: + source_marker: Current Wildland Fire Incident Locations + license_marker: The National Interagency Fire Center shall not be held liable +domains: + - Natural Hazards + - Emergency Management +data_types: + - Geospatial + - Event Data +tasks: + - Mapping + - Monitoring +difficulty: beginner +geography: + - United States +temporal_coverage: current agency-reported wildfire incidents +update_frequency: near real time +provider: National Interagency Fire Center +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + WFIGS publishes a current incident-point layer derived from agency fire + reports. Start with three features from the public ArcGIS layer. Incident + locations are approximate, dynamic, and not legal boundaries; cite NIFC + and contributing agencies and keep the update timestamp. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the exact ArcGIS item and its item-specific use notice. + - Query three current incident records from the feature layer. + - Inspect incident name, size, and modification time. + python: + packages: + - requests + code: | + import requests + + url = ("https://services3.arcgis.com/T4QMspbfLg3qTGWY/arcgis/rest/services/" + "WFIGS_Incident_Locations_Current/FeatureServer/0/query") + response = requests.get( + url, params={"where": "IncidentTypeCategory='WF'", "outFields": "OBJECTID,IrwinID,IncidentName,IncidentSize,ModifiedOnDateTime_dt", + "returnGeometry": "false", "resultRecordCount": 3, "f": "json"}, timeout=30, + ) + response.raise_for_status() + for feature in response.json()["features"][:3]: + row = feature["attributes"] + print(row["IrwinID"], row["IncidentName"], row["ModifiedOnDateTime_dt"]) + first_project: + title: Inspect Current U.S. Wildfire Points + goal: Review three agency incidents before mapping wildfire context. + steps: + - Keep the IRWIN ID, incident type, update time, and source agency. + - Check freshness and exclude prescribed fires when needed. + - Explain why a point does not identify a smoke plume's origin. diff --git a/data/datasets/wfigs-current-perimeters.yaml b/data/datasets/wfigs-current-perimeters.yaml new file mode 100644 index 0000000..cdbd4ec --- /dev/null +++ b/data/datasets/wfigs-current-perimeters.yaml @@ -0,0 +1,75 @@ +id: wfigs-current-perimeters +name: WFIGS Current Wildfire Perimeters +description: > + Agency-reported U.S. wildfire perimeter polygons from NIFC for mapping + approximate current fire footprints. +theme: Environment & Hazards +url: https://www.arcgis.com/sharing/rest/content/items/d1c32af3212341869b3c810f1a215824?f=json +access_type: + - api +api_key_required: false +free_to_access: true +size_gb_min: 0 +size_gb_max: 0.01 +formats: + - JSON +license: > + Public federal wildfire information with NIFC and contributing-agency + attribution; item-specific accuracy and non-legal-use notices apply. +license_url: https://www.arcgis.com/sharing/rest/content/items/d1c32af3212341869b3c810f1a215824?f=json +url_checks: + source_marker: WFIGS Current Interagency Fire Perimeters + license_marker: The National Interagency Fire Center shall not be held liable +domains: + - Natural Hazards + - Emergency Management +data_types: + - Geospatial +tasks: + - Mapping + - Monitoring +difficulty: beginner +geography: + - United States +temporal_coverage: current agency-reported wildfire perimeters +update_frequency: near real time +provider: National Interagency Fire Center +source_type: government +last_verified: 2026-09-28 +getting_started: + overview: > + WFIGS publishes a separate current perimeter layer for agency-reported + wildfire footprints. Start with three bounded feature records and keep + polygon date and incident name. Perimeters can lag a moving fire and are + not evacuation or legal boundary maps. + prerequisites: + - Python 3.10 or newer + - An internet connection + - The requests Python package + access_steps: + - Read the perimeter item's official notice and update context. + - Query three current perimeter records from its feature layer. + - Inspect polygon date and incident identity before mapping. + python: + packages: + - requests + code: | + import requests + + url = ("https://services3.arcgis.com/T4QMspbfLg3qTGWY/arcgis/rest/services/" + "WFIGS_Interagency_Perimeters_Current/FeatureServer/0/query") + response = requests.get( + url, params={"where": "attr_IncidentTypeCategory='WF'", "outFields": "OBJECTID,poly_IncidentName,poly_PolygonDateTime", + "returnGeometry": "false", "resultRecordCount": 3, "f": "json"}, timeout=30, + ) + response.raise_for_status() + for feature in response.json()["features"][:3]: + row = feature["attributes"] + print(row["OBJECTID"], row["poly_IncidentName"], row["poly_PolygonDateTime"]) + first_project: + title: Inspect Current U.S. Fire Perimeters + goal: Review three reported fire polygons before map rendering. + steps: + - Keep object ID, polygon date, incident association, and attribution. + - Filter prescribed or superseded features when building a current map. + - Explain why a perimeter does not establish evacuation status. diff --git a/docs/apps-source-coverage.md b/docs/apps-source-coverage.md new file mode 100644 index 0000000..83c48c8 --- /dev/null +++ b/docs/apps-source-coverage.md @@ -0,0 +1,51 @@ +# Apps source coverage review + +Reviewed 2026-09-28 against the six product revisions recorded in +[`src/content/apps/other.ts`](../src/content/apps/other.ts) and +[`src/content/apps/travelcanary.ts`](../src/content/apps/travelcanary.ts). +Those revisions, rather than whatever a product checkout later points to, define +this snapshot. TravelCanary's country partitions and their named warning systems +are recorded in [`national-warning-systems.json`](../src/content/apps/national-warning-systems.json). + +| App | Source families outside country partitions | Exact guide links | Exclusions | +| --- | ---: | ---: | ---: | +| TitanSkies | 9 | 8 | 1 | +| HyperOptions | 4 | 2 | 2 | +| TravelCanary | 45 | 38 | 7 | +| HouseHunter | 21 | 19 | 2 | +| RockyRoad | 3 | 2 | 1 | +| StackingSats | 6 | 5 | 1 | +| **Total** | **88** | **74** | **14** | + +TravelCanary also has 45 country coverage rows. Expanding them yields 83 named +warning-system entries (67 distinct system IDs): 27 entries have exact guide +links and 56 have a specific exclusion reason. Country rows are display +partitions, not datasets. Across all apps, 101 distinct exact guide IDs are +referenced; 92 guides were added in this review and nine were already active. + +Each linked [guide](../data/datasets) records the official source and reuse +URLs, update frequency or maintenance program, access steps, interpretation +limits, and a Python starting example. The source snapshot records the role, +availability, and exact guide relationship. A source or national system without +a qualifying guide retains its official link and a specific `noGuideReason`. +Restricted personal imports, project-authored rules, and StackingSats' pinned +historical parquet remain cited without a new dataset guide. Bitview is linked +as related current data, not as the historical parquet's exact match. + +Guide identity was checked against the feed or artifact used by the pinned +product. In particular, HouseHunter's FEMA National Risk Index is separate +from FEMA's flood layers; RockyRoad's Geofabrik extract is separate from OSM +Overpass; HouseHunter's EPA water-system tables, FCC county summary, and NOAA +station normals retain their pinned vintages. TravelCanary's warning-system +links are per system, including multi-feed country partitions. A guide link +does not assert that a configured, gated, blocked, pinned, or historical source +is currently live in the app. + +The exclusions follow the catalog policy in [`CONTRIBUTING.md`](../CONTRIBUTING.md): +an exact source needs verified access, maintenance, permitted analysis, and a +runnable example. Lack of an approved automated feed, unpublished reuse terms, +unavailable credentials, and broken exact endpoints are reasons to keep a +source citation without adding a guide. Free noncommercial sources qualify +when their published terms permit the guide's analysis; their limits are stated +in the guide. Review the source snapshot and its recorded revision whenever a +product's feeds change and at least every 90 days. diff --git a/e2e/apps.spec.ts b/e2e/apps.spec.ts index 95190b5..9fcb4a6 100644 --- a/e2e/apps.spec.ts +++ b/e2e/apps.spec.ts @@ -199,8 +199,23 @@ test("source links distinguish matching guides from official sources", async ({ await page.goto("/apps/househunter"); const nri = page.getByRole("listitem").filter({ has: page.getByRole("heading", { name: "FEMA National Risk Index" }) }); - await expect(nri.getByRole("link", { name: /Dataset Guide/ })).toHaveCount(0); - await expect(nri).toContainText("FEMA National Flood Hazard Layer is a different dataset"); + await expect(nri.getByRole("link", { name: /Dataset Guide/ })).toHaveAttribute("href", "/datasets/fema-national-risk-index"); + await page.goto("/apps/rockyroad"); + const geofabrik = page.getByRole("listitem").filter({ has: page.getByRole("heading", { name: "OpenStreetMap regional extracts via Geofabrik" }) }); + await expect(geofabrik.getByRole("link", { name: /Dataset Guide/ })).toHaveAttribute("href", "/datasets/geofabrik-osm-extracts"); +}); + +test("country warning partitions show separate guide decisions for each system", async ({ page }) => { + await page.goto("/apps/travelcanary"); + const germany = page.getByRole("listitem").filter({ has: page.getByRole("heading", { name: "Germany (DE) warning systems" }) }); + await germany.locator("summary").click(); + const systems = germany.locator("details > ul > li"); + await expect(systems).toHaveCount(3); + await expect(systems.filter({ hasText: "LHP flood warnings" }).getByRole("link", { name: /Data guide/ })).toHaveAttribute("href", "/datasets/lhp-germany-flood-warnings"); + const bbk = systems.filter({ hasText: "BBK civil-protection RSS" }); + await expect(bbk.getByRole("link", { name: /Data guide/ })).toHaveCount(0); + await expect(bbk).toContainText("state/municipal issuer rights"); + await expect(systems.filter({ hasText: "DWD direct CAP recovery" }).getByRole("link", { name: /Data guide/ })).toHaveAttribute("href", "/datasets/dwd-cap-warnings"); }); test("Bitview is discoverable as a dataset guide with a runnable notebook", async ({ page }) => { diff --git a/e2e/design-experience.spec.ts b/e2e/design-experience.spec.ts index bc07e50..6aa09b9 100644 --- a/e2e/design-experience.spec.ts +++ b/e2e/design-experience.spec.ts @@ -30,7 +30,7 @@ test('TravelCanary source list remains readable at narrow and desktop widths and for (const width of [320, 390, 1280]) { await page.setViewportSize({ width, height: 900 }); await page.goto('/apps/travelcanary'); - const sources = page.locator('main section[aria-labelledby="app-sources-title"] li'); + const sources = page.locator('main section[aria-labelledby="app-sources-title"] > section > ul > li'); expect(await sources.count()).toBeGreaterThan(20); await sources.last().scrollIntoViewIfNeeded(); await expect(sources.last()).toBeVisible(); diff --git a/e2e/discovery.spec.ts b/e2e/discovery.spec.ts index 575308f..7acd495 100644 --- a/e2e/discovery.spec.ts +++ b/e2e/discovery.spec.ts @@ -9,6 +9,7 @@ import { tableCopy, } from "../src/content/site-copy"; import { getActiveDatasets, getAllDatasets, getCatalogDatasets } from "../src/lib/datasets"; +import { getAllCollections, STARTER_COLLECTION_ID } from "../src/lib/collections"; import { CATALOG_PAGE_SIZE, EMPTY_FILTERS, deriveCatalogPage, filterDatasets } from "../src/lib/search"; import { getVocabulary, toVocabularySnapshot } from "../src/lib/vocabulary"; import { @@ -22,6 +23,20 @@ const CATALOG_PAGES = Math.ceil(DATASET_COUNT / CATALOG_PAGE_SIZE); const LAST_PAGE_ITEMS = DATASET_COUNT % CATALOG_PAGE_SIZE || CATALOG_PAGE_SIZE; const FIRST_CATALOG_NAME = deriveCatalogPage(getCatalogDatasets(), EMPTY_FILTERS, null, 1) .paginated.items[0]!.name; +const FIRST_GEOTIFF_NAME = deriveCatalogPage( + getCatalogDatasets(), { ...EMPTY_FILTERS, query: "GeoTIFF" }, null, 1, +).paginated.items[0]!.name; +const FIRST_WILDFIRE_NAME = deriveCatalogPage( + getCatalogDatasets(), { ...EMPTY_FILTERS, query: "wildfire" }, null, 1, +).paginated.items[0]!.name; +const FIRST_FILINGS_NAME = deriveCatalogPage( + getCatalogDatasets(), { ...EMPTY_FILTERS, query: "company filings" }, null, 1, +).paginated.items[0]!.name; +const STARTER_PAGE = Math.floor( + getCatalogDatasets().findIndex(({ id }) => + getAllCollections().find(({ id }) => id === STARTER_COLLECTION_ID)?.dataset_ids.includes(id), + ) / CATALOG_PAGE_SIZE, +) + 1; const EARTHQUAKE_HAZARD_COUNT = filterDatasets( getCatalogDatasets(), { ...EMPTY_FILTERS, query: "earthquake", domains: ["Natural Hazards"] }, @@ -56,16 +71,16 @@ test("search preserves typed spaces and finds dataset formats", async ({ page }) await expect(search).toHaveValue("world development"); await search.fill("GeoTIFF"); - await expect(page.getByRole("link", { name: "Natural Earth" })).toBeVisible(); + await expect(page.getByRole("link", { name: FIRST_GEOTIFF_NAME })).toBeVisible(); await expect( page.getByRole("button", { name: filterCopy.moreFiltersLabel, exact: true }), ).toBeVisible(); await page.goto("/?q=wildfire"); - await expect(page.getByRole("link", { name: "NASA FIRMS Active Fire Data" })).toBeVisible(); + await expect(page.getByRole("link", { name: FIRST_WILDFIRE_NAME })).toBeVisible(); await page.goto("/?q=company+filings"); await expect( - page.getByRole("link", { name: "SEC EDGAR Submissions and Company Facts" }), + page.getByRole("link", { name: FIRST_FILINGS_NAME }), ).toBeVisible(); }); @@ -111,7 +126,7 @@ test("the hero title leads into build paths without a jump CTA", async ({ page } }); test("starter highlighting stays on the unfiltered catalog", async ({ page }) => { - await page.goto("/"); + await page.goto(`/?page=${STARTER_PAGE}`); await expect( page.getByText(datasetCardCopy.goodFirstBuildLabel).filter({ visible: true }).first(), ).toBeVisible(); @@ -417,21 +432,21 @@ test("desktop sorting is shareable, reversible, and restores the promoted order" await page.goto("/"); const table = page.getByRole("table", { name: tableCopy.caption }); const firstDataRow = () => table.getByRole("row").nth(1); - await expect(firstDataRow()).toContainText("American Community Survey 5-Year Estimates"); + await expect(firstDataRow()).toContainText(FIRST_CATALOG_NAME); await page.getByRole("button", { name: tableCopy.sortBy("Dataset", false) }).click(); await expect(page).toHaveURL((url) => url.searchParams.get("sort") === "name" && url.searchParams.get("order") === "asc", ); - await expect(firstDataRow()).toContainText("American Community Survey 5-Year Estimates"); + await expect(firstDataRow()).toContainText(FIRST_CATALOG_NAME); await page.getByRole("button", { name: tableCopy.sortBy("Dataset", "asc") }).click(); await expect(page).toHaveURL((url) => url.searchParams.get("order") === "desc"); - await expect(firstDataRow()).not.toContainText("American Community Survey 5-Year Estimates"); + await expect(firstDataRow()).not.toContainText(FIRST_CATALOG_NAME); await page.getByRole("button", { name: tableCopy.sortBy("Dataset", "desc") }).click(); await expect(page).toHaveURL((url) => !url.searchParams.has("sort")); - await expect(firstDataRow()).toContainText("American Community Survey 5-Year Estimates"); + await expect(firstDataRow()).toContainText(FIRST_CATALOG_NAME); await page.goto("/?sort=updates&order=asc"); const sortedFirst = firstDataRow().getByRole("link").first(); diff --git a/e2e/performance.spec.ts b/e2e/performance.spec.ts index 3a9a311..0d714fc 100644 --- a/e2e/performance.spec.ts +++ b/e2e/performance.spec.ts @@ -22,7 +22,8 @@ const BUDGETS = { gzipCode: 360_000, analytics: 40_000, notebooks: 8_000_000, - catalogJson: 250_000, + // Catalog search data grows with each independently searchable guide. + catalogJson: 5_000 + addedDatasets * 1_600, }; async function initialCodeBytes(page: Page, path: string) { diff --git a/public/notebooks/arc-appalachian-counties.ipynb b/public/notebooks/arc-appalachian-counties.ipynb new file mode 100644 index 0000000..fa3094c --- /dev/null +++ b/public/notebooks/arc-appalachian-counties.ipynb @@ -0,0 +1,128 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "arc-appalachian-counties", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ARC Appalachian Counties\n", + "\n", + "The Appalachian Regional Commission's maintained county membership list for building regional comparison and eligibility tools.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/arc-appalachian-counties\n", + "- Official source: https://www.arc.gov/appalachian-counties-served-by-arc/\n", + "- Data terms: https://www.arc.gov/arc-web-and-privacy-policy/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "ARC maintains a public county list and notes fiscal-year exceptions, including Schoharie County for FY 2026. Start with Alabama's 37 named counties. Names alone do not give a county FIPS code or prove grant eligibility." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official county list and its fiscal-year notes.\n", + "2. Fetch the Alabama row from the ARC-maintained page.\n", + "3. Join to an authoritative FIPS table before a county-level analysis." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import html\n", + "import re\n", + "import requests\n", + "\n", + "url = \"https://www.arc.gov/appalachian-counties-served-by-arc/\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "match = re.search(\n", + " r'Alabama.*?(.*?)

',\n", + " response.text, re.S,\n", + ")\n", + "if not match:\n", + " raise ValueError(\"ARC Alabama county list not found\")\n", + "names = html.unescape(re.sub(r\"<[^>]+>\", \"\", match.group(1))).strip()\n", + "print(names[:160])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare ARC County Membership\n", + "\n", + "Show which sampled counties are within the ARC region while retaining the fiscal-year caveat.\n", + "\n", + "1. Extract county names for one state from the ARC list.\n", + "2. Resolve names to state-qualified county FIPS identifiers.\n", + "3. Explain why ARC membership does not by itself establish current grant eligibility." + ] + } + ] +} diff --git a/public/notebooks/arso-current-hydrology.ipynb b/public/notebooks/arso-current-hydrology.ipynb new file mode 100644 index 0000000..4f3fe33 --- /dev/null +++ b/public/notebooks/arso-current-hydrology.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "arso-current-hydrology", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ARSO Current Hydrology\n", + "\n", + "Slovenian river and lake station measurements for building a local water-level conditions display.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/arso-current-hydrology\n", + "- Official source: https://www.arso.gov.si/xml/vode/hidro_podatki_zadnji.xml\n", + "- Data terms: https://kazalci.arso.gov.si/en/content/legal-note\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The official Slovenian Environment Agency feed supplies current public data. Start with two current Slovenian stations; a provisional station level is not a flood warning or a destination-wide measurement." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official data documentation and reuse terms.\n", + "2. Fetch the small official feed and inspect two records.\n", + "3. Preserve source timestamps and locations before mapping results." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "from xml.etree import ElementTree as ET\n", + "\n", + "url = \"https://www.arso.gov.si/xml/vode/hidro_podatki_zadnji.xml\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "root = ET.fromstring(response.content)\n", + "print(\"Prepared\", root.findtext(\"datum_priprave\"))\n", + "for station in root.findall(\"postaja\")[:2]:\n", + " print(station.get(\"sifra\"), station.findtext(\"reka\"),\n", + " station.findtext(\"vodostaj\"), station.findtext(\"datum_cet\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Dated Local Conditions\n", + "\n", + "Inspect two current Slovenian stations with source timestamps.\n", + "\n", + "1. Fetch the official source and retain its update time.\n", + "2. Show two records with their station or notice identifiers.\n", + "3. Explain why these records are context rather than complete hazard coverage." + ] + } + ] +} diff --git a/public/notebooks/avalanche-report-bulletins.ipynb b/public/notebooks/avalanche-report-bulletins.ipynb new file mode 100644 index 0000000..46815af --- /dev/null +++ b/public/notebooks/avalanche-report-bulletins.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "avalanche-report-bulletins", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Avalanche.report Regional Bulletins\n", + "\n", + "European regional avalanche bulletins published as CAAML JSON for building a dated mountain hazard view.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/avalanche-report-bulletins\n", + "- Official source: https://static.avalanche.report/eaws_bulletins/2026-01-31/2026-01-31-AT-02.json\n", + "- Data terms: https://avalanche.report/more/open-data\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Avalanche.report publishes daily regional CAAML JSON partitions, including AT-02 used by TravelCanary. Start with two archived January 2026 bulletin records; an archived bulletin is not a current warning, and no bulletin may be published outside its season." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official open-data licence and CAAML access description.\n", + "2. Fetch one dated regional bulletin file.\n", + "3. Inspect two bulletin IDs and their validity periods." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://static.avalanche.report/eaws_bulletins/2026-01-31/2026-01-31-AT-02.json\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "for bulletin in response.json()[\"bulletins\"][:2]:\n", + " print(bulletin[\"bulletinID\"], bulletin.get(\"validTime\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Review Regional Avalanche Bulletins\n", + "\n", + "Inspect two dated CAAML bulletins before mapping warning regions.\n", + "\n", + "1. Fetch one regional partition and retain its publication time.\n", + "2. Match its region identifiers to the official EAWS geometry.\n", + "3. Explain why an archived bulletin does not describe today's mountain hazard." + ] + } + ] +} diff --git a/public/notebooks/awc-metar-stations.ipynb b/public/notebooks/awc-metar-stations.ipynb new file mode 100644 index 0000000..2509108 --- /dev/null +++ b/public/notebooks/awc-metar-stations.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "awc-metar-stations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Aviation Weather Center METAR and Stations\n", + "\n", + "Current airport METAR observations and station metadata from NOAA's Aviation Weather Center for checking representative weather conditions near destinations.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/awc-metar-stations\n", + "- Official source: https://aviationweather.gov/data/api/\n", + "- Data terms: https://sos.noaa.gov/copyright/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "AWC serves airport observations and station metadata through one documented API family. Start with a single airport's METAR and station record. A nearby airport is only a proxy for destination conditions, and this feed does not provide official destination-wide weather warnings." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the AWC API request limits and NOAA public-information terms.\n", + "2. Select one airport ICAO code and request its latest METAR.\n", + "3. Query the same station ID and retain its coordinates with the reading." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "headers = {\"User-Agent\": \"TrilemmaDataCatalogExample/1.0 (https://data.trilemma.foundation)\"}\n", + "base = \"https://aviationweather.gov/api/data\"\n", + "params = {\"ids\": \"EIDW\", \"format\": \"json\"}\n", + "metar = requests.get(f\"{base}/metar\", params=params, headers=headers, timeout=30)\n", + "metar.raise_for_status()\n", + "station = requests.get(f\"{base}/stationinfo\", params=params, headers=headers, timeout=30)\n", + "station.raise_for_status()\n", + "if metar.json() and station.json():\n", + " print(metar.json()[0][\"icaoId\"], metar.json()[0][\"reportTime\"],\n", + " station.json()[0][\"lat\"], station.json()[0][\"lon\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Check One Airport Observation\n", + "\n", + "Assess whether one METAR and station coordinate can support local weather context.\n", + "\n", + "1. Keep station ID, coordinates, report time, and observed units.\n", + "2. Compare the reading age with the intended display freshness.\n", + "3. Explain why airport conditions cannot prove destination-wide safety." + ] + } + ] +} diff --git a/public/notebooks/bc-unverified-hourly-pm25.ipynb b/public/notebooks/bc-unverified-hourly-pm25.ipynb new file mode 100644 index 0000000..f80e011 --- /dev/null +++ b/public/notebooks/bc-unverified-hourly-pm25.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "bc-unverified-hourly-pm25", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# British Columbia Hourly PM2.5\n", + "\n", + "Preliminary British Columbia fine-particle station readings for inspecting hourly particulate concentrations and their observation times.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/bc-unverified-hourly-pm25\n", + "- Official source: https://open.canada.ca/data/en/dataset/01867404-ba2a-470e-94b7-0604607cfa30\n", + "- Data terms: https://open.canada.ca/data/en/dataset/01867404-ba2a-470e-94b7-0604607cfa30\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "B.C. publishes an unverified PM2.5 CSV and a station metadata CSV. Start with five lines from the current pollutant file using a streaming read; the full file is several megabytes. The catalog record confirms its OGL-BC licence and warns that Metro Vancouver and Fraser Valley readings are excluded. These concentrations are not provider-reported AQI values." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the B.C. catalog record, geographic exclusions, and licence.\n", + "2. Stream the official PM2.5 CSV and inspect five data rows.\n", + "3. Join station names to official station metadata before mapping." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import itertools\n", + "import requests\n", + "\n", + "url = (\"https://www.env.gov.bc.ca/epd/bcairquality/aqo/csv/\"\n", + " \"Hourly_Raw_Air_Data/Air_Quality/PM25.csv\")\n", + "with requests.get(url, stream=True, timeout=30) as response:\n", + " response.raise_for_status()\n", + " rows = csv.DictReader(response.iter_lines(decode_unicode=True))\n", + " for row in itertools.islice(rows, 5):\n", + " print(row[\"STATION_NAME\"], row[\"DATE_PST\"], row[\"RAW_VALUE\"], row[\"UNITS\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect B.C. Hourly PM2.5\n", + "\n", + "Review five preliminary observations before station mapping.\n", + "\n", + "1. Keep station ID or name, timestamp, unit, and concentration.\n", + "2. Check quality and coverage before deriving a local AQI estimate.\n", + "3. Explain why a missing station is not evidence of clean air." + ] + } + ] +} diff --git a/public/notebooks/binance-bitcoin-ticker.ipynb b/public/notebooks/binance-bitcoin-ticker.ipynb new file mode 100644 index 0000000..f5a6e5d --- /dev/null +++ b/public/notebooks/binance-bitcoin-ticker.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "binance-bitcoin-ticker", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Binance Bitcoin Ticker\n", + "\n", + "Binance BTC/USDT exchange quotes for a private Bitcoin market comparison where service is available with explicit provider provenance and retrieval time.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/binance-bitcoin-ticker\n", + "- Official source: https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT\n", + "- Data terms: https://www.binance.com/en/terms\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Binance public endpoint returns one current Bitcoin quote. Start with one response and record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. Follow the provider usage limits above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official Binance API and data-use terms.\n", + "2. Fetch one Bitcoin quote from the documented public endpoint.\n", + "3. Keep the pair, retrieval time, and provider name separate from other exchanges." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = 'https://api.binance.com/api/v3/ticker/price?symbol=BTCUSDT'\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "quote = response.json()\n", + "print(quote[\"symbol\"], quote[\"price\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare One Bitcoin Quote\n", + "\n", + "Inspect a single provider quote without treating it as an investment signal.\n", + "\n", + "1. Fetch a single response and retain its pair identifier.\n", + "2. Record the retrieval time and label the provider.\n", + "3. Explain why exchange quotes differ and cannot stand in for historical returns." + ] + } + ] +} diff --git a/public/notebooks/bitstamp-bitcoin-ticker.ipynb b/public/notebooks/bitstamp-bitcoin-ticker.ipynb new file mode 100644 index 0000000..d734be2 --- /dev/null +++ b/public/notebooks/bitstamp-bitcoin-ticker.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "bitstamp-bitcoin-ticker", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Bitstamp Bitcoin Ticker\n", + "\n", + "Bitstamp BTC/USD exchange ticker fields for a private Bitcoin market comparison with explicit provider provenance and retrieval time.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/bitstamp-bitcoin-ticker\n", + "- Official source: https://www.bitstamp.net/api/v2/ticker/btcusd/\n", + "- Data terms: https://www.bitstamp.net/api/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Bitstamp public endpoint returns one current Bitcoin quote. Start with one response and record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. Follow the provider usage limits above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official Bitstamp API and data-use terms.\n", + "2. Fetch one Bitcoin quote from the documented public endpoint.\n", + "3. Keep the pair, retrieval time, and provider name separate from other exchanges." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = 'https://www.bitstamp.net/api/v2/ticker/btcusd/'\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "quote = response.json()\n", + "print(quote[\"timestamp\"], quote[\"last\"], quote[\"volume\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare One Bitcoin Quote\n", + "\n", + "Inspect a single provider quote without treating it as an investment signal.\n", + "\n", + "1. Fetch a single response and retain its pair identifier.\n", + "2. Record the retrieval time and label the provider.\n", + "3. Explain why exchange quotes differ and cannot stand in for historical returns." + ] + } + ] +} diff --git a/public/notebooks/catalonia-civil-protection-plans.ipynb b/public/notebooks/catalonia-civil-protection-plans.ipynb new file mode 100644 index 0000000..859719d --- /dev/null +++ b/public/notebooks/catalonia-civil-protection-plans.ipynb @@ -0,0 +1,123 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "catalonia-civil-protection-plans", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Catalonia Civil Protection Plans\n", + "\n", + "Current Catalan civil-protection plan activations and phases for reviewing regional emergency context and official CECAT updates.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/catalonia-civil-protection-plans\n", + "- Official source: https://analisi.transparenciacatalunya.cat/api/views/wj9c-j6vf\n", + "- Data terms: https://web.gencat.cat/ca/generalitat/dades-indicadors/dades-obertes/llicencies\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Generalitat publishes the current pre-alert, alert, and emergency phases of Catalan civil-protection plans through one Socrata dataset. Start with five records. A plan phase is regional context and must not be treated as a destination-specific evacuation order. Attribute the agency, preserve meaning, and show the last update date." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the exact dataset metadata and Catalan reuse conditions.\n", + "2. Request five current plan rows from the official dataset API.\n", + "3. Inspect acronym, phase, activation flag, and phase timestamp." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://analisi.transparenciacatalunya.cat/resource/wj9c-j6vf.json\",\n", + " params={\"$limit\": 5}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for plan in response.json():\n", + " print(plan.get(\"plaacronim\"), plan.get(\"plafase\"),\n", + " plan.get(\"plaactivat\"), plan.get(\"fasedatahora\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Current Catalan Plan Phases\n", + "\n", + "Review five official plan records for regional emergency context.\n", + "\n", + "1. Keep plan acronym, phase, activation flag, and update timestamp.\n", + "2. Link the official CECAT communication when one is supplied.\n", + "3. Explain why a regional plan phase is not a local restriction or order." + ] + } + ] +} diff --git a/public/notebooks/census-acs-2024-table-summary.ipynb b/public/notebooks/census-acs-2024-table-summary.ipynb new file mode 100644 index 0000000..0011065 --- /dev/null +++ b/public/notebooks/census-acs-2024-table-summary.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "census-acs-2024-table-summary", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Census ACS 2024 Five-Year Table Summary Files\n", + "\n", + "Census Bureau table-based ACS estimate and margin files for building tract and county housing-context tools.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/census-acs-2024-table-summary\n", + "- Official source: https://www.census.gov/programs-surveys/acs/data/summary-file.2024.html\n", + "- Data terms: https://www.census.gov/about/policies/citation.html\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The 2024 table-based Summary File publishes each detailed table as a pipe-delimited .dat file with estimates and margins. HouseHunter pins B25034, B25035, B25103, B25077, and B08303. Start with one bounded read of B25103; a table value is a survey estimate, and a GEO_ID must be joined to its geography label." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the Census table-based Summary File instructions and citation guidance.\n", + "2. Request the first complete records from one pinned 2024 five-year table.\n", + "3. Inspect the GEO_ID, estimate, and margin fields before a geography join." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import io\n", + "import requests\n", + "\n", + "url = (\"https://www2.census.gov/programs-surveys/acs/summary_file/2024/\"\n", + " \"table-based-SF/data/5YRData/acsdt5y2024-b25103.dat\")\n", + "response = requests.get(url, headers={\"Range\": \"bytes=0-2047\"}, timeout=30)\n", + "response.raise_for_status()\n", + "lines = response.text.splitlines()\n", + "rows = csv.DictReader(io.StringIO(\"\\n\".join(lines[:-1])), delimiter=\"|\")\n", + "for row in list(rows)[:2]:\n", + " print(row[\"GEO_ID\"], row[\"B25103_E001\"], row[\"B25103_M001\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect ACS Housing Estimates\n", + "\n", + "Compare a small set of housing estimates with their margins of error.\n", + "\n", + "1. Read B25103 estimates and margins for two geographies.\n", + "2. Join GEO_ID to the matching ACS geography labels.\n", + "3. Explain why a five-year survey estimate is not a current property count." + ] + } + ] +} diff --git a/public/notebooks/census-geocoder.ipynb b/public/notebooks/census-geocoder.ipynb new file mode 100644 index 0000000..53ffae6 --- /dev/null +++ b/public/notebooks/census-geocoder.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "census-geocoder", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Census Geocoder Address Lookup\n", + "\n", + "U.S. Census Bureau address-to-tract geocoding responses for assigning a user-entered address to its reviewed Census geography.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/census-geocoder\n", + "- Official source: https://geocoding.geo.census.gov/geocoder/Geocoding_Services_API.html\n", + "- Data terms: https://www.census.gov/data/developers/about/terms-of-service.html\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Census Geocoder returns address matches and Census tract geography for one submitted U.S. address. Start with the Census Bureau's own public example address and request the current 2020 geography vintage. Do not send confidential addresses in a tutorial; an approximate range match needs review before it is used as a property location." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official geocoding request format and API terms.\n", + "2. Request one public example address with an explicit benchmark and vintage.\n", + "3. Inspect the returned tract identifier and match quality." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://geocoding.geo.census.gov/geocoder/geographies/onelineaddress\",\n", + " params={\"address\": \"4600 Silver Hill Rd, Washington, DC 20233\",\n", + " \"benchmark\": \"Public_AR_Current\", \"vintage\": \"Census2020_Current\",\n", + " \"format\": \"json\"}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for match in response.json()[\"result\"][\"addressMatches\"][:5]:\n", + " tracts = match[\"geographies\"].get(\"Census Tracts\", [])\n", + " print(match[\"matchedAddress\"], [tract[\"GEOID\"] for tract in tracts])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Check a Census Tract Match\n", + "\n", + "Inspect a public example address before using geocoding in a local lookup.\n", + "\n", + "1. Keep the matched address, coordinates, benchmark, vintage, and tract GEOID.\n", + "2. Handle zero or multiple matches without silently choosing one.\n", + "3. Explain why address-range coordinates can differ from a parcel location." + ] + } + ] +} diff --git a/public/notebooks/census-pep-county-totals.ipynb b/public/notebooks/census-pep-county-totals.ipynb new file mode 100644 index 0000000..79c7c40 --- /dev/null +++ b/public/notebooks/census-pep-county-totals.ipynb @@ -0,0 +1,126 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "census-pep-county-totals", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Census PEP County Population Totals\n", + "\n", + "Vintage 2025 county population estimates from the U.S. Census Bureau for comparing county sizes and applying population-based eligibility thresholds.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/census-pep-county-totals\n", + "- Official source: https://www.census.gov/data/datasets/time-series/demo/popest/2020s-counties-total.html\n", + "- Data terms: https://www.census.gov/about/policies/citation.html\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Census Population Estimates Program publishes a versioned county CSV. Start with five rows from the Vintage 2025 all-data file and retain the year and county FIPS components. Estimates can be revised in later vintages and do not measure the population of a neighborhood or tract." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official Vintage 2025 county data page and citation guidance.\n", + "2. Download the county totals CSV and inspect its FIPS and population columns.\n", + "3. Keep the vintage fixed when comparing or ranking counties." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import io\n", + "import itertools\n", + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://www2.census.gov/programs-surveys/popest/datasets/\"\n", + " \"2020-2025/counties/totals/co-est2025-alldata.csv\", timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "rows = csv.DictReader(io.StringIO(response.text))\n", + "for row in itertools.islice((row for row in rows if row[\"COUNTY\"] != \"000\"), 5):\n", + " print(row[\"STATE\"], row[\"COUNTY\"], row[\"CTYNAME\"], row[\"POPESTIMATE2025\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Five County Estimates\n", + "\n", + "Test a fixed-vintage population floor for a county comparison tool.\n", + "\n", + "1. Join state and county FIPS components without dropping leading zeroes.\n", + "2. Count which sampled counties exceed a chosen population threshold.\n", + "3. Explain why later estimates may differ from this pinned vintage." + ] + } + ] +} diff --git a/public/notebooks/coinbase-bitcoin-spot-price.ipynb b/public/notebooks/coinbase-bitcoin-spot-price.ipynb new file mode 100644 index 0000000..49a7769 --- /dev/null +++ b/public/notebooks/coinbase-bitcoin-spot-price.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "coinbase-bitcoin-spot-price", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Coinbase Bitcoin Spot Price\n", + "\n", + "Coinbase Bitcoin-to-USD spot quotes for a private, personal research comparison with explicit provider provenance and retrieval time.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/coinbase-bitcoin-spot-price\n", + "- Official source: https://api.coinbase.com/v2/prices/BTC-USD/spot\n", + "- Data terms: https://www.coinbase.com/legal/market_data\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Coinbase public endpoint returns one current Bitcoin quote. Start with one response and record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. Follow the provider usage limits above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official Coinbase API and data-use terms.\n", + "2. Fetch one Bitcoin quote from the documented public endpoint.\n", + "3. Keep the pair, retrieval time, and provider name separate from other exchanges." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = 'https://api.coinbase.com/v2/prices/BTC-USD/spot'\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "quote = response.json()[\"data\"]\n", + "print(quote[\"base\"], quote[\"currency\"], quote[\"amount\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare One Bitcoin Quote\n", + "\n", + "Inspect a single provider quote without treating it as an investment signal.\n", + "\n", + "1. Fetch a single response and retain its pair identifier.\n", + "2. Record the retrieval time and label the provider.\n", + "3. Explain why exchange quotes differ and cannot stand in for historical returns." + ] + } + ] +} diff --git a/public/notebooks/coingecko-bitcoin-price.ipynb b/public/notebooks/coingecko-bitcoin-price.ipynb new file mode 100644 index 0000000..195da59 --- /dev/null +++ b/public/notebooks/coingecko-bitcoin-price.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "coingecko-bitcoin-price", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CoinGecko Bitcoin Spot Price\n", + "\n", + "CoinGecko Bitcoin-to-USD spot quotes for a personal, dated Bitcoin price comparison with explicit provider provenance and retrieval time.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/coingecko-bitcoin-price\n", + "- Official source: https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd\n", + "- Data terms: https://www.coingecko.com/en/api_terms\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The CoinGecko public endpoint returns one current Bitcoin quote. Start with one response and record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. Follow the provider usage limits above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official CoinGecko API and data-use terms.\n", + "2. Fetch one Bitcoin quote from the documented public endpoint.\n", + "3. Keep the pair, retrieval time, and provider name separate from other exchanges." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = 'https://api.coingecko.com/api/v3/simple/price?ids=bitcoin&vs_currencies=usd'\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "bitcoin = response.json()[\"bitcoin\"]\n", + "print(\"USD\", bitcoin[\"usd\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare One Bitcoin Quote\n", + "\n", + "Inspect a single provider quote without treating it as an investment signal.\n", + "\n", + "1. Fetch a single response and retain its pair identifier.\n", + "2. Record the retrieval time and label the provider.\n", + "3. Explain why exchange quotes differ and cannot stand in for historical returns." + ] + } + ] +} diff --git a/public/notebooks/copernicus-rapid-mapping-activations.ipynb b/public/notebooks/copernicus-rapid-mapping-activations.ipynb new file mode 100644 index 0000000..0d30f5b --- /dev/null +++ b/public/notebooks/copernicus-rapid-mapping-activations.ipynb @@ -0,0 +1,122 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "copernicus-rapid-mapping-activations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Copernicus Rapid Mapping Activations\n", + "\n", + "Public emergency-mapping activation metadata and product references for dated disaster-response context tools.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/copernicus-rapid-mapping-activations\n", + "- Official source: https://mapping.emergency.copernicus.eu/about/how-to-harvest-cems-mapping-data/emergency-response-data/\n", + "- Data terms: https://mapping.emergency.copernicus.eu/terms-and-conditions/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The public Rapid Mapping API lists activations and offers detail records and product links. Start with one activation; its existence does not establish current warning coverage at a location." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Review the public activation API documentation and CEMS reuse terms.\n", + "2. Request one activation from the public listing.\n", + "3. Keep event and update timestamps separate from present hazard status." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://rapidmapping.emergency.copernicus.eu/backend/dashboard-api/public-activations-info/\",\n", + " params={\"limit\": 1, \"offset\": 0}, timeout=25,\n", + ")\n", + "response.raise_for_status()\n", + "for activation in response.json()[\"results\"]:\n", + " print(activation[\"code\"], activation[\"name\"], activation[\"eventTime\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect a Public Activation\n", + "\n", + "Display one mapped emergency event with its activation identifier and event time.\n", + "\n", + "1. Fetch one public activation record.\n", + "2. Show the identifier, event date, and affected country.\n", + "3. Explain that an activation is not a current local warning." + ] + } + ] +} diff --git a/public/notebooks/cwfif-active-wildland-fires.ipynb b/public/notebooks/cwfif-active-wildland-fires.ipynb new file mode 100644 index 0000000..f3263c4 --- /dev/null +++ b/public/notebooks/cwfif-active-wildland-fires.ipynb @@ -0,0 +1,127 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "cwfif-active-wildland-fires", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CWFIF Active Wildland Fires\n", + "\n", + "Canadian active-wildfire records from NRCan CWFIF for inspecting fire identifiers, status, size, and reported location.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/cwfif-active-wildland-fires\n", + "- Official source: https://geoserver.cwfif.nrcan.gc.ca/geoserver/wfs?service=WFS&version=2.0.0&request=GetCapabilities\n", + "- Data terms: https://open.canada.ca/en/open-government-licence-canada\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "NRCan's current CWFIF WFS offers active wildland-fire features under public:cwfif_national_activefires. Start with three GeoJSON features in EPSG:4326. A reported active-fire point is context; it does not by itself prove smoke origin, local exposure, or an evacuation area." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official WFS capabilities and Canadian licence.\n", + "2. Request three active-fire features with explicit geographic coordinates.\n", + "3. Inspect fire ID, prescribed status, and report time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://geoserver.cwfif.nrcan.gc.ca/geoserver/wfs\",\n", + " params={\"service\": \"WFS\", \"version\": \"2.0.0\", \"request\": \"GetFeature\",\n", + " \"typeNames\": \"public:cwfif_national_activefires\",\n", + " \"outputFormat\": \"application/json\", \"srsName\": \"EPSG:4326\", \"count\": 3},\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for fire in response.json()[\"features\"][:3]:\n", + " row = fire[\"properties\"]\n", + " print(row.get(\"national_fire_id\"), row.get(\"fire_size\"),\n", + " row.get(\"fire_was_prescribed\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Canadian Active Fires\n", + "\n", + "Review three official fire records before regional context mapping.\n", + "\n", + "1. Keep fire ID, report time, size, and prescribed-fire flag.\n", + "2. Check freshness and geometry before mapping incidents.\n", + "3. Explain why an active-fire record is not a smoke-source attribution." + ] + } + ] +} diff --git a/public/notebooks/cwfis-m3-perimeter-estimates.ipynb b/public/notebooks/cwfis-m3-perimeter-estimates.ipynb new file mode 100644 index 0000000..05f9316 --- /dev/null +++ b/public/notebooks/cwfis-m3-perimeter-estimates.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "cwfis-m3-perimeter-estimates", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# CWFIS M3 Perimeter Estimates\n", + "\n", + "Canadian M3 estimated wildfire perimeters from NRCan CWFIS for showing approximate fire-footprint context.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/cwfis-m3-perimeter-estimates\n", + "- Official source: https://cwfis.cfs.nrcan.gc.ca/geoserver/public/ows?service=WFS&version=2.0.0&request=GetCapabilities\n", + "- Data terms: https://open.canada.ca/en/open-government-licence-canada\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The legacy CWFIS WFS serves public:m3polygons, an M3 perimeter-estimate layer distinct from reported incident points and authoritative evacuation boundaries. Start with three GeoJSON features and retain their estimated dates. NRCan's 2026 service placemat identifies this layer by name." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official CWFIS service catalogue and Canadian open licence.\n", + "2. Request three M3 polygon features from the named WFS layer.\n", + "3. Inspect estimate dates and geometry before rendering." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://cwfis.cfs.nrcan.gc.ca/geoserver/public/ows\",\n", + " params={\"service\": \"WFS\", \"version\": \"2.0.0\", \"request\": \"GetFeature\",\n", + " \"typeNames\": \"public:m3polygons\", \"outputFormat\": \"application/json\",\n", + " \"srsName\": \"EPSG:4326\", \"count\": 3}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for estimate in response.json()[\"features\"][:3]:\n", + " row = estimate[\"properties\"]\n", + " print(row.get(\"uid\"), row.get(\"lastdate\"), row.get(\"area\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Canadian M3 Footprints\n", + "\n", + "Review three estimated fire footprints before map rendering.\n", + "\n", + "1. Keep polygon ID, estimate date, and stated area.\n", + "2. Compare footprint age with current incident reports.\n", + "3. Explain why an M3 estimate is not a surveyed perimeter or evacuation map." + ] + } + ] +} diff --git a/public/notebooks/eaws-avalanche-regions.ipynb b/public/notebooks/eaws-avalanche-regions.ipynb new file mode 100644 index 0000000..b48b22d --- /dev/null +++ b/public/notebooks/eaws-avalanche-regions.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "eaws-avalanche-regions", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# EAWS Avalanche Microregions\n", + "\n", + "European avalanche warning-region polygons for matching mountain destinations to regional bulletins across published areas.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/eaws-avalanche-regions\n", + "- Official source: https://eaws.gitlab.io/eaws-regions/micro-regions/AT-02_micro-regions.geojson.json\n", + "- Data terms: https://gitlab.com/api/v4/projects/eaws%2Feaws-regions/repository/files/LICENSE/raw?ref=master\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "EAWS publishes a maintained composite GeoJSON and smaller country or subregion partitions. Start with the AT-02 partition and two polygons; matching a destination to a polygon does not establish that a bulletin is active or applicable at its exact location." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the EAWS geometry index and source-repository CC0 licence.\n", + "2. Download one bounded microregion partition.\n", + "3. Inspect feature IDs and geometry before joining to bulletins." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://eaws.gitlab.io/eaws-regions/micro-regions/AT-02_micro-regions.geojson.json\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "for region in response.json()[\"features\"][:2]:\n", + " print(region[\"properties\"].get(\"id\"), region[\"geometry\"][\"type\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Match Avalanche Regions\n", + "\n", + "Inspect two EAWS microregions before joining bulletin coverage.\n", + "\n", + "1. Download one partition and retain its region IDs.\n", + "2. Compare a destination coordinate with candidate polygons.\n", + "3. Explain why a geometry match is not a current avalanche warning." + ] + } + ] +} diff --git a/public/notebooks/eccc-aqhi-observations.ipynb b/public/notebooks/eccc-aqhi-observations.ipynb new file mode 100644 index 0000000..7ef4483 --- /dev/null +++ b/public/notebooks/eccc-aqhi-observations.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "eccc-aqhi-observations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# ECCC Air Quality Health Index\n", + "\n", + "Real-time Canadian AQHI observations from ECCC for reviewing health-risk index readings at reporting regions and stations.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/eccc-aqhi-observations\n", + "- Official source: https://api.weather.gc.ca/collections/aqhi-observations-realtime?f=json\n", + "- Data terms: https://open.canada.ca/en/open-government-licence-canada\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "ECCC's GeoMet collection exposes preliminary AQHI observations as GeoJSON. Start with five latest features, retaining their observation times and AQHI scale. AQHI is a Canadian health-risk index and is not interchangeable with a U.S. EPA AQI or an individual pollutant value." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official AQHI collection description and Canadian open licence.\n", + "2. Request five latest GeoJSON items in one call.\n", + "3. Inspect observation time, geometry, and AQHI property." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://api.weather.gc.ca/collections/aqhi-observations-realtime/items\",\n", + " params={\"f\": \"json\", \"latest\": \"true\", \"limit\": 5}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "data = response.json()\n", + "for item in data[\"features\"][:5]:\n", + " print(item[\"id\"], item[\"properties\"].get(\"aqhi\"),\n", + " item[\"properties\"].get(\"observation_datetime\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Canadian AQHI Readings\n", + "\n", + "Review five reported index features before local display.\n", + "\n", + "1. Keep feature ID, AQHI scale value, location, and observation time.\n", + "2. Check freshness and regional scope before matching a destination.\n", + "3. Explain why AQHI cannot be relabeled as U.S. AQI." + ] + } + ] +} diff --git a/public/notebooks/eea-air-quality-index-stations.ipynb b/public/notebooks/eea-air-quality-index-stations.ipynb new file mode 100644 index 0000000..48e41d6 --- /dev/null +++ b/public/notebooks/eea-air-quality-index-stations.ipynb @@ -0,0 +1,129 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "eea-air-quality-index-stations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# EEA Air Quality Index Stations\n", + "\n", + "European Environment Agency hourly station AQI details for building a measured air-quality context view.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/eea-air-quality-index-stations\n", + "- Official source: https://dis2datalake.blob.core.windows.net/airquality-derivated/AQI-noRunningMeans/current/AT60118.json\n", + "- Data terms: https://www.eea.europa.eu/en/legal-notice\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The EEA Air Quality Index publishes a station metadata index, hourly map, and per-station detail JSON. Start with one reviewed Austrian station and two hours; modeled gap fills must not be presented as measurements, and one station does not establish destination-wide air quality." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the EEA AQI methodology and legal notice.\n", + "2. Fetch one station-detail artifact from the official AQI data lake.\n", + "3. Inspect the observation and modeled flags for two hourly records." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "from datetime import datetime, timezone\n", + "\n", + "url = (\"https://dis2datalake.blob.core.windows.net/airquality-derivated/\"\n", + " \"AQI-noRunningMeans/current/AT60118.json\")\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "now = datetime.now(timezone.utc)\n", + "observed = []\n", + "for hour, row in response.json().items():\n", + " pollutant = row.get(\"culprit\")\n", + " if (pollutant and datetime.fromisoformat(hour.replace(\"Z\", \"+00:00\")) <= now\n", + " and row.get(f\"modelled_{pollutant}\") == 0):\n", + " observed.append((hour, row))\n", + "for hour, row in sorted(observed)[-2:]:\n", + " print(hour, row.get(\"aqi\"), row.get(\"culprit\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Station AQI Context\n", + "\n", + "Compare two station hours while retaining modeled-value provenance.\n", + "\n", + "1. Fetch one station's dated hourly values.\n", + "2. Display the culprit pollutant and model flag beside AQI.\n", + "3. Explain why a modeled fill or one station is not a local measurement." + ] + } + ] +} diff --git a/public/notebooks/ehyd-current-flood-stages.ipynb b/public/notebooks/ehyd-current-flood-stages.ipynb new file mode 100644 index 0000000..86f8026 --- /dev/null +++ b/public/notebooks/ehyd-current-flood-stages.ipynb @@ -0,0 +1,126 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "ehyd-current-flood-stages", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# eHYD Current Flood Stages\n", + "\n", + "Austrian hydrographic station levels and stage codes for bounded, dated flood-context checks.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/ehyd-current-flood-stages\n", + "- Official source: https://gis.lfrz.gv.at/api/geodata/i000501/ogc/features/v1/collections/i000501:pegel_aktuell?f=application%2Fjson\n", + "- Data terms: https://creativecommons.org/licenses/by/4.0/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "eHYD's pegel_aktuell collection publishes current station values and stage codes. Start with one water-level feature; a raw level without its station-specific threshold is not a warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Review the eHYD OGC collection and its linked CC BY 4.0 licence.\n", + "2. Request one water-level feature using the parameter filter.\n", + "3. Keep its station, unit, timestamp, and code together." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://gis.lfrz.gv.at/api/geodata/i000501/ogc/features/v1/collections/i000501:pegel_aktuell/items\",\n", + " params={\"f\": \"application/geo+json\", \"limit\": 1,\n", + " \"filter-lang\": \"cql2-text\", \"filter\": \"parameter = 'W'\"},\n", + " timeout=20,\n", + ")\n", + "response.raise_for_status()\n", + "for feature in response.json()[\"features\"]:\n", + " station = feature[\"properties\"]\n", + " print(station[\"messstelle\"], station[\"wert\"], station[\"einheit\"],\n", + " station[\"zeitpunkt\"], station[\"gesamtcode\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect One Austrian Gauge\n", + "\n", + "Display one dated water-level observation with its stage code.\n", + "\n", + "1. Fetch one W-parameter gauge feature.\n", + "2. Show its value, unit, observation time, and stage code.\n", + "3. Explain that local thresholds are needed to interpret the stage." + ] + } + ] +} diff --git a/public/notebooks/england-flood-warnings.ipynb b/public/notebooks/england-flood-warnings.ipynb new file mode 100644 index 0000000..146a009 --- /dev/null +++ b/public/notebooks/england-flood-warnings.ipynb @@ -0,0 +1,123 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "england-flood-warnings", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Environment Agency Flood Warnings\n", + "\n", + "Current Environment Agency flood alerts and warnings for England for mapping affected flood areas and monitoring official severity changes.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/england-flood-warnings\n", + "- Official source: https://environment.data.gov.uk/flood-monitoring/doc/reference\n", + "- Data terms: https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Environment Agency's flood API lists current official alerts and warnings, refreshed about every fifteen minutes. Start with five records from one response and preserve severity and flood-area identifiers. Warning geography is not equivalent to a nearby gauge measurement." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official API reference and Open Government Licence attribution.\n", + "2. Fetch the current flood-warning list once.\n", + "3. Inspect severity and flood-area IDs before mapping warnings." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://environment.data.gov.uk/flood-monitoring/id/floods\",\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for warning in response.json()[\"items\"][:5]:\n", + " print(warning[\"floodAreaID\"], warning[\"severity\"],\n", + " warning.get(\"timeMessageChanged\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Current Flood Severities\n", + "\n", + "Check whether current warnings support a region-specific alert card.\n", + "\n", + "1. Keep flood-area identifiers, warning IDs, severity, and change times.\n", + "2. Distinguish current warnings from withdrawn warnings and river readings.\n", + "3. Explain why an empty feed does not establish safety outside a reviewed flood area." + ] + } + ] +} diff --git a/public/notebooks/fcdo-travel-advice.ipynb b/public/notebooks/fcdo-travel-advice.ipynb new file mode 100644 index 0000000..2a6cfc5 --- /dev/null +++ b/public/notebooks/fcdo-travel-advice.ipynb @@ -0,0 +1,121 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "fcdo-travel-advice", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# FCDO Foreign Travel Advice\n", + "\n", + "Published UK government country travel advice for building a destination briefing with dated safety context.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/fcdo-travel-advice\n", + "- Official source: https://www.gov.uk/api/content/foreign-travel-advice/switzerland\n", + "- Data terms: https://www.gov.uk/help/reuse-govuk-content\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The GOV.UK Content API returns structured advice for one country path. Start with Switzerland and inspect its update date; advice is not a guarantee of safety or a substitute for the full official notice." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read GOV.UK's Content API documentation and reuse terms.\n", + "2. Fetch one country's published advice by its GOV.UK path.\n", + "3. Inspect the publication date and link to the complete advice." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://www.gov.uk/api/content/foreign-travel-advice/switzerland\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "advice = response.json()\n", + "print(advice[\"title\"], advice.get(\"public_updated_at\"))\n", + "print(\"https://www.gov.uk\" + advice[\"base_path\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Build a Dated Country Briefing\n", + "\n", + "Show a country advice link and its latest publication timestamp.\n", + "\n", + "1. Fetch one country record and keep its source path.\n", + "2. Display its update date beside a link to the full advice.\n", + "3. Explain that official advice can change after the cached snapshot." + ] + } + ] +} diff --git a/public/notebooks/hrsa-ahrf-county.ipynb b/public/notebooks/hrsa-ahrf-county.ipynb new file mode 100644 index 0000000..dc697fd --- /dev/null +++ b/public/notebooks/hrsa-ahrf-county.ipynb @@ -0,0 +1,126 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "hrsa-ahrf-county", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# HRSA Area Health Resources Files County Data\n", + "\n", + "HRSA's annually refreshed county health-resource archive for comparing clinician supply and health-system capacity.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/hrsa-ahrf-county\n", + "- Official source: https://data.hrsa.gov/data/download?AHRF=&data=AHRF\n", + "- Data terms: https://data.hrsa.gov/data/data-sources?tab=DataUsage\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "HRSA publishes a county CSV archive and records no usage limitation. Start with one county row and a named clinician variable from the 2024-2025 release. The release year is not every variable's measurement year, and supply does not prove access to care." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read HRSA's annual release details, data dictionary, and usage terms.\n", + "2. Download the 2024-2025 county CSV archive from HRSA.\n", + "3. Inspect the county identifier and one clinician-supply field." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import csv\n", + "import io\n", + "import zipfile\n", + "import requests\n", + "\n", + "url = \"https://data.hrsa.gov/DataDownload/AHRF/AHRF_2024-2025_CSV.zip\"\n", + "response = requests.get(url, timeout=60)\n", + "response.raise_for_status()\n", + "with zipfile.ZipFile(io.BytesIO(response.content)) as archive:\n", + " name = next(n for n in archive.namelist() if n.endswith(\"AHRF2025.csv\"))\n", + " with archive.open(name) as file:\n", + " row = next(csv.DictReader(io.TextIOWrapper(file, encoding=\"utf-8-sig\")))\n", + "print(row[\"fips_st_cnty\"], row[\"phys_nf_prim_care_pc_exc_rsdt_23\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare County Clinician Supply\n", + "\n", + "Compare one documented provider-supply variable across counties using a fixed AHRF release.\n", + "\n", + "1. Select the county FIPS and provider field from the release dictionary.\n", + "2. Compare the same variable and measurement year across two counties.\n", + "3. Explain why clinician counts do not establish appointment availability." + ] + } + ] +} diff --git a/public/notebooks/ign-spain-earthquake-rss.ipynb b/public/notebooks/ign-spain-earthquake-rss.ipynb new file mode 100644 index 0000000..00762be --- /dev/null +++ b/public/notebooks/ign-spain-earthquake-rss.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "ign-spain-earthquake-rss", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IGN Spain Earthquake RSS\n", + "\n", + "Spain's official IGN earthquake event headlines and coordinates for regional seismic context tools.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/ign-spain-earthquake-rss\n", + "- Official source: https://www.ign.es/web/social-rss\n", + "- Data terms: https://www.ign.es/web/en/ign/portal/info-aviso-legal\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "IGN lists a public earthquake RSS feed in its own RSS directory. Fetch one feed and inspect a few items; RSS headlines are regional event context, not a complete alert lifecycle or proof that a destination is safe." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read IGN's RSS directory and public-sector reuse terms.\n", + "2. Fetch the earthquake RSS feed once.\n", + "3. Preserve each event's link, publication time, and any location metadata." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import xml.etree.ElementTree as ET\n", + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://www.ign.es/ign/RssTools/sismologia.xml\", timeout=20,\n", + ")\n", + "response.raise_for_status()\n", + "root = ET.fromstring(response.content)\n", + "for item in root.findall(\"./channel/item\")[:3]:\n", + " print(item.findtext(\"title\"), item.findtext(\"pubDate\"),\n", + " item.findtext(\"link\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Review Recent Spanish Earthquakes\n", + "\n", + "Show a few dated IGN earthquake notices with source links.\n", + "\n", + "1. Fetch and parse the official RSS feed.\n", + "2. Show the publication time and original IGN event link.\n", + "3. Explain why a headline feed does not establish local warning coverage." + ] + } + ] +} diff --git a/public/notebooks/imgw-current-hydrology.ipynb b/public/notebooks/imgw-current-hydrology.ipynb new file mode 100644 index 0000000..1905346 --- /dev/null +++ b/public/notebooks/imgw-current-hydrology.ipynb @@ -0,0 +1,120 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "imgw-current-hydrology", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IMGW Poland Current Hydrology\n", + "\n", + "Current Polish river-station observations and official thresholds from IMGW for checking stage exceedance at reviewed gauges.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/imgw-current-hydrology\n", + "- Official source: https://danepubliczne.imgw.pl/api/data/hydro/\n", + "- Data terms: https://danepubliczne.imgw.pl/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "IMGW's public API returns river-stage measurements with official warning and alarm thresholds. Free access is limited to qualifying noncommercial analysis; commercial and specified sectoral uses can require a separate agreement and payment. Start with five stations from one response. A threshold crossing at one station is not a published area-wide warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read IMGW's current access regulation before reusing observations.\n", + "2. Fetch one current hydrology API response.\n", + "3. Inspect station ID, measurement time, stage, and warning threshold." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\"https://danepubliczne.imgw.pl/api/data/hydro/\", timeout=30)\n", + "response.raise_for_status()\n", + "for station in response.json()[:5]:\n", + " print(station.get(\"id_stacji\"), station.get(\"stan_wody\"),\n", + " station.get(\"stan_ostrzegawczy\"), station.get(\"stan_wody_data_pomiaru\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Polish River Thresholds\n", + "\n", + "Review five official station readings before local stage matching.\n", + "\n", + "1. Keep station ID, river, reading time, units, and both thresholds.\n", + "2. Reject stale, missing, or malformed readings before comparison.\n", + "3. Explain why a station reading does not equal an official area warning." + ] + } + ] +} diff --git a/public/notebooks/ipma-seismic-observations.ipynb b/public/notebooks/ipma-seismic-observations.ipynb new file mode 100644 index 0000000..95dd2f9 --- /dev/null +++ b/public/notebooks/ipma-seismic-observations.ipynb @@ -0,0 +1,122 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "ipma-seismic-observations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IPMA Regional Seismic Observations\n", + "\n", + "Portuguese regional earthquake records for building a dated seismic context view around travel destinations.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/ipma-seismic-observations\n", + "- Official source: https://api.ipma.pt/open-data/observation/seismic/3.json\n", + "- Data terms: https://api.ipma.pt/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "IPMA publishes regional seismic JSON files, including areas 3 and 7 used by TravelCanary. Start with area 3 and inspect two records; a reported earthquake is contextual information, not an active hazard warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read IPMA's regional seismic API description and noncommercial terms.\n", + "2. Fetch the area 3 file and check its update date.\n", + "3. Inspect two earthquake records before applying a time or magnitude filter." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://api.ipma.pt/open-data/observation/seismic/3.json\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "feed = response.json()\n", + "print(feed[\"idArea\"], feed.get(\"updateDate\"))\n", + "for event in feed[\"data\"][:2]:\n", + " print(event.get(\"time\"), event.get(\"magnitud\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Review Regional Seismic Context\n", + "\n", + "Show two dated earthquake records from an official IPMA region.\n", + "\n", + "1. Fetch one area and retain its update timestamp.\n", + "2. Display event time and magnitude beside the region ID.\n", + "3. Explain that a past event does not establish current local risk." + ] + } + ] +} diff --git a/public/notebooks/ipma-weather-station-observations.ipynb b/public/notebooks/ipma-weather-station-observations.ipynb new file mode 100644 index 0000000..3184c60 --- /dev/null +++ b/public/notebooks/ipma-weather-station-observations.ipynb @@ -0,0 +1,121 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "ipma-weather-station-observations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IPMA Weather Station Observations\n", + "\n", + "Portuguese hourly station weather observations for building a local conditions display with explicit station context.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/ipma-weather-station-observations\n", + "- Official source: https://api.ipma.pt/open-data/observation/meteorology/stations/obs-surface.geojson\n", + "- Data terms: https://api.ipma.pt/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "IPMA publishes a GeoJSON file of recent Portuguese weather station readings. Start with two features and preserve their timestamps and station IDs; a station reading is not a destination-wide measurement or warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the IPMA API documentation and noncommercial reuse conditions.\n", + "2. Download the current GeoJSON station observations.\n", + "3. Inspect two station readings and their observation times." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://api.ipma.pt/open-data/observation/meteorology/stations/obs-surface.geojson\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "for station in response.json()[\"features\"][:2]:\n", + " row = station[\"properties\"]\n", + " print(row.get(\"idEstacao\"), row.get(\"time\"), row.get(\"temperatura\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Show Nearby Station Weather\n", + "\n", + "Present two current IPMA station readings with timestamps.\n", + "\n", + "1. Select stations by their reviewed coordinates and IDs.\n", + "2. Display temperature with its station name and observation time.\n", + "3. Explain that station conditions can differ from a travel destination." + ] + } + ] +} diff --git a/public/notebooks/ipma-weather-warnings.ipynb b/public/notebooks/ipma-weather-warnings.ipynb new file mode 100644 index 0000000..eb3ba95 --- /dev/null +++ b/public/notebooks/ipma-weather-warnings.ipynb @@ -0,0 +1,123 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "ipma-weather-warnings", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# IPMA Portuguese Weather Warnings\n", + "\n", + "Official Portuguese weather-warning JSON from IPMA for reviewing affected forecast areas, severity levels, and warning validity.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/ipma-weather-warnings\n", + "- Official source: https://api.ipma.pt/\n", + "- Data terms: https://api.ipma.pt/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "IPMA publishes area-based weather warnings as JSON. Start with five entries and preserve area code, start/end time, and awareness level. The public service is documented for noncommercial use; confirm the IPMA conditions before wider reuse. Green entries are not proof of no other hazards." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read IPMA's API documentation and linked conditions of use.\n", + "2. Fetch the current warning JSON once.\n", + "3. Inspect each warning's area code and validity window." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://api.ipma.pt/open-data/forecast/warnings/warnings_www.json\",\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for warning in response.json()[:5]:\n", + " print(warning[\"idAreaAviso\"], warning[\"awarenessLevelID\"],\n", + " warning[\"startTime\"], warning[\"endTime\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Five IPMA Warnings\n", + "\n", + "Check whether IPMA warnings can support a bounded area warning card.\n", + "\n", + "1. Keep official area IDs and the full validity interval.\n", + "2. Treat each category and severity separately before displaying it.\n", + "3. Explain IPMA's noncommercial-use limit and why these entries do not imply a local all-clear." + ] + } + ] +} diff --git a/public/notebooks/kraken-bitcoin-ticker.ipynb b/public/notebooks/kraken-bitcoin-ticker.ipynb new file mode 100644 index 0000000..39cd4e3 --- /dev/null +++ b/public/notebooks/kraken-bitcoin-ticker.ipynb @@ -0,0 +1,122 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "kraken-bitcoin-ticker", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Kraken Bitcoin Ticker\n", + "\n", + "Kraken XBT/USD exchange ticker fields for a private Bitcoin market comparison with explicit provider provenance and retrieval time.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/kraken-bitcoin-ticker\n", + "- Official source: https://api.kraken.com/0/public/Ticker?pair=XBTUSD\n", + "- Data terms: https://docs.kraken.com/api/docs/rest-api/get-ticker-information/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The Kraken public endpoint returns one current Bitcoin quote. Start with one response and record its retrieval time; a snapshot is neither a historical series nor an investment recommendation. Follow the provider usage limits above." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official Kraken API and data-use terms.\n", + "2. Fetch one Bitcoin quote from the documented public endpoint.\n", + "3. Keep the pair, retrieval time, and provider name separate from other exchanges." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = 'https://api.kraken.com/0/public/Ticker?pair=XBTUSD'\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "feed = response.json()\n", + "assert not feed[\"error\"], feed[\"error\"]\n", + "quote = next(iter(feed[\"result\"].values()))\n", + "print(\"XBT/USD last trade\", quote[\"c\"][0])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Compare One Bitcoin Quote\n", + "\n", + "Inspect a single provider quote without treating it as an investment signal.\n", + "\n", + "1. Fetch a single response and retain its pair identifier.\n", + "2. Record the retrieval time and label the provider.\n", + "3. Explain why exchange quotes differ and cannot stand in for historical returns." + ] + } + ] +} diff --git a/public/notebooks/krisinformation-news.ipynb b/public/notebooks/krisinformation-news.ipynb new file mode 100644 index 0000000..4feda09 --- /dev/null +++ b/public/notebooks/krisinformation-news.ipynb @@ -0,0 +1,122 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "krisinformation-news", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Krisinformation News Feed\n", + "\n", + "Swedish official crisis and infrastructure news for building a dated local-disruption context view.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/krisinformation-news\n", + "- Official source: https://api.krisinformation.se/v3/news?format=json&allcounties=true&days=365\n", + "- Data terms: https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The official Krisinformation.se feed supplies current public data. Start with two recent official news records; a regional notice does not prove a destination-wide infrastructure outage." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official data documentation and reuse terms.\n", + "2. Fetch the small official feed and inspect two records.\n", + "3. Preserve source timestamps and locations before mapping results." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://api.krisinformation.se/v3/news\"\n", + "response = requests.get(url, params={\"format\": \"json\", \"allcounties\": \"true\",\n", + " \"days\": 365}, timeout=20)\n", + "response.raise_for_status()\n", + "for notice in response.json()[:2]:\n", + " print(notice.get(\"Identifier\"), notice.get(\"Headline\"),\n", + " notice.get(\"Updated\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Dated Local Conditions\n", + "\n", + "Inspect two recent official news records with source timestamps.\n", + "\n", + "1. Fetch the official source and retain its update time.\n", + "2. Show two records with their station or notice identifiers.\n", + "3. Explain why these records are context rather than complete hazard coverage." + ] + } + ] +} diff --git a/public/notebooks/krisinformation-vma.ipynb b/public/notebooks/krisinformation-vma.ipynb new file mode 100644 index 0000000..4ec394b --- /dev/null +++ b/public/notebooks/krisinformation-vma.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "krisinformation-vma", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Krisinformation Sweden VMA Alerts\n", + "\n", + "Official Swedish important-public-announcement records from the Krisinformation open API for reviewing current local emergency warnings.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/krisinformation-vma\n", + "- Official source: https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/\n", + "- Data terms: https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Krisinformation.se exposes current VMA public announcements through its version 3 API. Start with one request and read up to five current records; an empty response says only that this scoped endpoint returned none. Attribute any displayed message and check location and validity before treating it as a local warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official open-data description and attribution rule.\n", + "2. Request the version 3 VMA endpoint once.\n", + "3. Inspect region, issue time, and status of any returned announcement." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://api.krisinformation.se/v3/vmas\",\n", + " params={\"allCounties\": \"true\", \"language\": \"en\"}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "alerts = response.json()\n", + "print(f\"{len(alerts)} VMA records returned\")\n", + "for alert in alerts[:5]:\n", + " print(alert.get(\"Identifier\"), alert.get(\"Updated\"), alert.get(\"Counties\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Current Swedish VMA Alerts\n", + "\n", + "Check a scoped official response before local alert matching.\n", + "\n", + "1. Preserve announcement identifiers, region, issue time, and updates.\n", + "2. Link to Krisinformation.se and credit the source.\n", + "3. Do not infer nationwide safety from an empty response." + ] + } + ] +} diff --git a/public/notebooks/met-eireann-warnings.ipynb b/public/notebooks/met-eireann-warnings.ipynb new file mode 100644 index 0000000..c3f152c --- /dev/null +++ b/public/notebooks/met-eireann-warnings.ipynb @@ -0,0 +1,122 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "met-eireann-warnings", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Met Eireann Weather Warnings\n", + "\n", + "Official Irish weather-warning JSON from Met Éireann for checking county regions, severity, and validity intervals.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/met-eireann-warnings\n", + "- Official source: https://www.met.ie/about-us/specialised-services/open-data\n", + "- Data terms: https://www.met.ie/about-us/specialised-services/widgets\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Met Éireann exposes current warnings as JSON with CAP IDs, regions, and issue/onset/expiry times. Start with five records. Its reuse terms require attribution and preserving warning meaning; remove expired warnings and do not treat an empty list as a general safety statement." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read Met Éireann's open-data and weather-warning reuse conditions.\n", + "2. Fetch the national JSON warning list once.\n", + "3. Retain region IDs and full validity intervals when displaying warnings." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://www.met.ie/Open_Data/json/warning_IRELAND.json\", timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for warning in response.json()[:5]:\n", + " print(warning[\"capId\"], warning[\"level\"], warning[\"regions\"],\n", + " warning[\"onset\"], warning[\"expiry\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Current Irish Weather Warnings\n", + "\n", + "Evaluate a county-matched alert card using official warning records.\n", + "\n", + "1. Keep CAP IDs, county regions, severity, and issue/onset/expiry times.\n", + "2. Remove expired and superseded warnings before display.\n", + "3. Explain why these region warnings do not imply an all-clear elsewhere." + ] + } + ] +} diff --git a/public/notebooks/meteo-lt-hydrology-observations.ipynb b/public/notebooks/meteo-lt-hydrology-observations.ipynb new file mode 100644 index 0000000..37a458d --- /dev/null +++ b/public/notebooks/meteo-lt-hydrology-observations.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "meteo-lt-hydrology-observations", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Meteo LT Hydrology Observations\n", + "\n", + "Lithuanian river-station water levels and temperatures for dated local hydrology context tools.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/meteo-lt-hydrology-observations\n", + "- Official source: https://api.meteo.lt/\n", + "- Data terms: https://api.meteo.lt/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Meteo LT publishes current measured water levels at named hydro-stations in centimeters. Start with one documented station; a water level without a station datum or official threshold is not a flood warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the hydro-station endpoint documentation and CC BY-SA terms.\n", + "2. Fetch the latest observations for one documented station.\n", + "3. Keep its UTC observation time, station name, and water-level unit together." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://api.meteo.lt/v1/hydro-stations/nemajunu-vms/observations/measured/latest\",\n", + " timeout=20,\n", + ")\n", + "response.raise_for_status()\n", + "data = response.json()\n", + "for observation in data[\"observations\"][-2:]:\n", + " print(data[\"station\"][\"name\"], observation[\"observationTimeUtc\"],\n", + " observation[\"waterLevel\"], \"cm\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect One River Station\n", + "\n", + "Show one recent Lithuanian station water level with its time and unit.\n", + "\n", + "1. Fetch the documented station's latest measured observations.\n", + "2. Display its station name, UTC time, and centimeter level.\n", + "3. Explain why the value cannot be treated as an official flood warning." + ] + } + ] +} diff --git a/public/notebooks/nasa-eonet-events.ipynb b/public/notebooks/nasa-eonet-events.ipynb new file mode 100644 index 0000000..8c9df0b --- /dev/null +++ b/public/notebooks/nasa-eonet-events.ipynb @@ -0,0 +1,123 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "nasa-eonet-events", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# NASA EONET Natural Events\n", + "\n", + "Curated NASA EONET natural-event metadata for reviewing wildfire, volcano, storm, and other recent event context.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/nasa-eonet-events\n", + "- Official source: https://eonet.gsfc.nasa.gov/docs/v3\n", + "- Data terms: https://eonet.gsfc.nasa.gov/what-is-eonet\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "EONET curates recent natural-event metadata from multiple sources. Start with three open events and inspect IDs, categories, and source links. NASA warns that event extents are approximate and not official; the rights of separately linked source observations must be reviewed before republishing those observations." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the EONET v3 API documentation and event disclaimer.\n", + "2. Request three open events in one bounded call.\n", + "3. Keep event IDs and source links separate from local warning evidence." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://eonet.gsfc.nasa.gov/api/v3/events\",\n", + " params={\"limit\": 3, \"status\": \"open\"}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for event in response.json()[\"events\"][:3]:\n", + " print(event[\"id\"], event[\"title\"],\n", + " [category[\"id\"] for category in event[\"categories\"]])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Recent Natural Events\n", + "\n", + "Review a small EONET response as contextual discovery data.\n", + "\n", + "1. Keep event ID, categories, source URLs, and geometry dates.\n", + "2. Verify independent official sources before local hazard conclusions.\n", + "3. Explain why an EONET event extent is not an official warning area." + ] + } + ] +} diff --git a/public/notebooks/ndw-road-closures.ipynb b/public/notebooks/ndw-road-closures.ipynb new file mode 100644 index 0000000..0a2d42d --- /dev/null +++ b/public/notebooks/ndw-road-closures.ipynb @@ -0,0 +1,129 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "ndw-road-closures", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# NDW Road Events and Closures\n", + "\n", + "Dutch compressed road-closure and safety-message records for building a dated traffic-disruption map.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/ndw-road-closures\n", + "- Official source: https://opendata.ndw.nu/\n", + "- Data terms: https://english.ndw.nu/service/copyright\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The official NDW index publishes separate closure and safety-message DATEX files. Start with two Dutch closure records; a listed restriction is not a complete route planner or safety instruction." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official data documentation and reuse terms.\n", + "2. Fetch the small official feed and inspect two records.\n", + "3. Preserve source timestamps and locations before mapping results." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import gzip\n", + "import io\n", + "import itertools\n", + "import requests\n", + "from xml.etree import ElementTree as ET\n", + "\n", + "url = \"https://opendata.ndw.nu/tijdelijke_verkeersmaatregelen_afsluitingen.xml.gz\"\n", + "response = requests.get(url, timeout=20)\n", + "response.raise_for_status()\n", + "assert len(response.content) < 1_000_000\n", + "xml = gzip.decompress(response.content)\n", + "assert len(xml) < 5_000_000\n", + "records = (element for _, element in ET.iterparse(io.BytesIO(xml), events=(\"end\",))\n", + " if element.tag.endswith(\"}situationRecord\"))\n", + "for record in itertools.islice(records, 2):\n", + " print(record.get(\"id\"), record.get(\"version\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Dated Local Conditions\n", + "\n", + "Inspect two Dutch closure records with source timestamps.\n", + "\n", + "1. Fetch the official source and retain its update time.\n", + "2. Show two records with their station or notice identifiers.\n", + "3. Explain why these records are context rather than complete hazard coverage." + ] + } + ] +} diff --git a/public/notebooks/open-meteo-air-quality.ipynb b/public/notebooks/open-meteo-air-quality.ipynb new file mode 100644 index 0000000..f285d20 --- /dev/null +++ b/public/notebooks/open-meteo-air-quality.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "open-meteo-air-quality", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Open-Meteo Air Quality Forecast\n", + "\n", + "Modeled European air-quality forecasts served by Open-Meteo for inspecting point-level AQI context under noncommercial free API terms.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/open-meteo-air-quality\n", + "- Official source: https://open-meteo.com/en/docs/air-quality-api\n", + "- Data terms: https://open-meteo.com/en/terms\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Start with one point and one day. The free Open-Meteo air-quality endpoint permits noncommercial use only; commercial services need separate paid access. It serves modeled CAMS air-quality context, not a direct station observation or health all-clear." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read Open-Meteo's noncommercial service terms and CAMS attribution guidance.\n", + "2. Request one point and one day of European AQI forecasts.\n", + "3. Preserve the model label and timestamps with displayed values." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://air-quality-api.open-meteo.com/v1/air-quality\",\n", + " params={\"latitude\": 52.52, \"longitude\": 13.41,\n", + " \"hourly\": \"european_aqi\", \"forecast_days\": 1},\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "hourly = response.json()[\"hourly\"]\n", + "print(list(zip(hourly[\"time\"], hourly[\"european_aqi\"]))[:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect a Modeled AQI Day\n", + "\n", + "Assess whether one forecast series supports noncommercial air-quality context.\n", + "\n", + "1. Keep the model source, units, and issue context with hourly values.\n", + "2. Inspect missing values before displaying an AQI badge.\n", + "3. Explain the noncommercial API limit and why modeled AQI is not a station reading." + ] + } + ] +} diff --git a/public/notebooks/open-meteo-marine.ipynb b/public/notebooks/open-meteo-marine.ipynb new file mode 100644 index 0000000..0f71055 --- /dev/null +++ b/public/notebooks/open-meteo-marine.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "open-meteo-marine", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Open-Meteo Marine Forecast\n", + "\n", + "Hourly offshore marine forecasts from Open-Meteo for coastal planning context under the free API's noncommercial use limit.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/open-meteo-marine\n", + "- Official source: https://open-meteo.com/en/docs/marine-weather-api\n", + "- Data terms: https://open-meteo.com/en/terms\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Start with one offshore point and one forecast day. The free Open-Meteo marine endpoint permits noncommercial use only; commercial services need separate paid access. Query a reviewed offshore point; a returned model cell is not beach, navigation, or ferry safety advice." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the free API noncommercial terms and marine model limitations.\n", + "2. Choose a suitable offshore point and request one day of wave forecasts.\n", + "3. Check that the returned grid cell and wave values apply to that point." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://marine-api.open-meteo.com/v1/marine\",\n", + " params={\"latitude\": 53.208336, \"longitude\": -9.2916565,\n", + " \"hourly\": \"wave_height\", \"forecast_days\": 1},\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "hourly = response.json()[\"hourly\"]\n", + "print(list(zip(hourly[\"time\"], hourly[\"wave_height\"]))[:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect One Offshore Wave Forecast\n", + "\n", + "Assess one wave-height series as noncommercial coastal context.\n", + "\n", + "1. Verify the returned point is offshore and inspect missing wave values.\n", + "2. Record the time, unit, and model source for each displayed value.\n", + "3. Explain the noncommercial API limit and why forecasts are not marine safety advice." + ] + } + ] +} diff --git a/public/notebooks/open-meteo-weather-forecast.ipynb b/public/notebooks/open-meteo-weather-forecast.ipynb new file mode 100644 index 0000000..e912021 --- /dev/null +++ b/public/notebooks/open-meteo-weather-forecast.ipynb @@ -0,0 +1,124 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "open-meteo-weather-forecast", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Open-Meteo Weather Forecast\n", + "\n", + "Hourly point weather forecasts from Open-Meteo for planning location-specific conditions panels, subject to noncommercial free API terms.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/open-meteo-weather-forecast\n", + "- Official source: https://open-meteo.com/en/docs\n", + "- Data terms: https://open-meteo.com/en/terms\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The free Open-Meteo weather endpoint permits noncommercial use only; commercial services need separate paid access. Start with one point and one forecast day. Model output is not a local observation or official weather warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the free API noncommercial terms and attribution requirements.\n", + "2. Choose one coordinate and limit the forecast to one day.\n", + "3. Compare the hourly timestamps with the location's time zone before display." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://api.open-meteo.com/v1/forecast\",\n", + " params={\"latitude\": 52.52, \"longitude\": 13.41,\n", + " \"hourly\": \"temperature_2m\", \"forecast_days\": 1},\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "hourly = response.json()[\"hourly\"]\n", + "print(list(zip(hourly[\"time\"], hourly[\"temperature_2m\"]))[:5])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect a One-Day Weather Forecast\n", + "\n", + "Check whether hourly temperatures support a noncommercial local conditions card.\n", + "\n", + "1. Keep the returned units and forecast timestamps with each value.\n", + "2. Display five hourly temperatures for the selected point.\n", + "3. Explain the noncommercial API limit and why a forecast is not an official warning." + ] + } + ] +} diff --git a/public/notebooks/osm-nominatim-search.ipynb b/public/notebooks/osm-nominatim-search.ipynb new file mode 100644 index 0000000..39fd662 --- /dev/null +++ b/public/notebooks/osm-nominatim-search.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "osm-nominatim-search", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# OpenStreetMap Nominatim Search\n", + "\n", + "Public Nominatim place-search responses derived from OpenStreetMap for checking one user-requested address or road candidate.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/osm-nominatim-search\n", + "- Official source: https://nominatim.org/release-docs/latest/api/Search/\n", + "- Data terms: https://operations.osmfoundation.org/policies/nominatim/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Read the public Nominatim usage policy before calling this shared service: at most one request per second per application, a distinct identifying User-Agent, attribution, caching, no autocomplete, and no systematic or bulk queries. Start with one public landmark address. ODbL share-alike applies to the OSM-derived data; keep a provider switch available if the public service withdraws access." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the Nominatim policy and ODbL conditions in full.\n", + "2. Search one public landmark address with an identifying User-Agent.\n", + "3. Inspect the returned location and OSM attribution." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://nominatim.openstreetmap.org/search\",\n", + " params={\"q\": \"1600 Pennsylvania Avenue NW, Washington, DC\",\n", + " \"format\": \"jsonv2\", \"limit\": 1},\n", + " headers={\"User-Agent\": \"TrilemmaDataCatalogExample/1.0 (https://data.trilemma.foundation/)\"},\n", + " timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for place in response.json():\n", + " print(place[\"display_name\"], place[\"lat\"], place[\"lon\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect One Public Place Match\n", + "\n", + "Check one user-triggered place candidate with the shared Nominatim API.\n", + "\n", + "1. Display OpenStreetMap attribution with the result.\n", + "2. Require user confirmation before treating a road match as a property.\n", + "3. Explain why a public demo service is unsuitable for bulk geocoding." + ] + } + ] +} diff --git a/public/notebooks/photon-geocoding.ipynb b/public/notebooks/photon-geocoding.ipynb new file mode 100644 index 0000000..4259546 --- /dev/null +++ b/public/notebooks/photon-geocoding.ipynb @@ -0,0 +1,123 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "photon-geocoding", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Photon Place Search\n", + "\n", + "OpenStreetMap-based Photon place-search results for adding small-scale geocoding to a map application.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/photon-geocoding\n", + "- Official source: https://photon.komoot.io/api/?q=Zurich&limit=2\n", + "- Data terms: https://github.com/komoot/photon/blob/master/README.md\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "Komoot's public Photon demo answers small place searches without a key. Start with one query and two results; the demo may throttle heavy use and has no availability guarantee, while OpenStreetMap attribution still applies." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the Photon public demo policy and OpenStreetMap data terms.\n", + "2. Search for one place with a two-result limit.\n", + "3. Inspect each candidate's name and coordinates before using it." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://photon.komoot.io/api/\",\n", + " params={\"q\": \"Zurich\", \"limit\": 2},\n", + " headers={\"User-Agent\": \"TrilemmaDataCatalog/1.0\"}, timeout=20,\n", + ")\n", + "response.raise_for_status()\n", + "for place in response.json()[\"features\"]:\n", + " print(place[\"properties\"].get(\"name\"), place[\"geometry\"][\"coordinates\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Search for Map Destinations\n", + "\n", + "Show two geocoding candidates with their source coordinates.\n", + "\n", + "1. Query one place name with a bounded result count.\n", + "2. Display candidate labels and coordinates for user selection.\n", + "3. Explain that similarly named places require location confirmation." + ] + } + ] +} diff --git a/public/notebooks/pse-energy-compass.ipynb b/public/notebooks/pse-energy-compass.ipynb new file mode 100644 index 0000000..f28942a --- /dev/null +++ b/public/notebooks/pse-energy-compass.ipynb @@ -0,0 +1,123 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "pse-energy-compass", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# PSE Energy Compass Advisories\n", + "\n", + "Polish grid operator PSE's hourly national electricity-use recommendations for building dated system-context tools.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/pse-energy-compass\n", + "- Official source: https://api.raporty.pse.pl/api/pdgsz?$filter=is_active%20eq%20true&$orderby=dtime_utc%20desc&$first=48\n", + "- Data terms: https://www.pse.pl/bip/ponowne-wykorzystanie-informacji-publicznej\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "PSE publishes the Energy Compass forecast through its official reports API. Start with the first active hourly row, keeping its UTC time and publication time. The advice describes Poland-wide electricity-system conditions and cannot establish a local power outage." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read PSE's Energy Compass explanation and public-information reuse conditions.\n", + "2. Fetch a bounded set of active hourly recommendations.\n", + "3. Record the publication time, valid hour, and usage forecast code." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://api.raporty.pse.pl/api/pdgsz\",\n", + " params={\"$filter\": \"is_active eq true\", \"$orderby\": \"dtime_utc desc\", \"$first\": 48},\n", + " timeout=20,\n", + ")\n", + "response.raise_for_status()\n", + "for row in response.json()[\"value\"][:2]:\n", + " print(row[\"dtime_utc\"], row[\"usage_fcst\"], row[\"publication_ts_utc\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect National Grid Advice\n", + "\n", + "Display one hourly recommendation with its publication time and national scope.\n", + "\n", + "1. Fetch the latest active Energy Compass rows.\n", + "2. Label the UTC valid hour and publication time.\n", + "3. Explain why a country-wide advisory does not report a local interruption." + ] + } + ] +} diff --git a/public/notebooks/slf-avalanche-bulletins.ipynb b/public/notebooks/slf-avalanche-bulletins.ipynb new file mode 100644 index 0000000..ee576cd --- /dev/null +++ b/public/notebooks/slf-avalanche-bulletins.ipynb @@ -0,0 +1,121 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "slf-avalanche-bulletins", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SLF Avalanche Bulletins\n", + "\n", + "Swiss official avalanche bulletin GeoJSON for building a dated mountain hazard context map.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/slf-avalanche-bulletins\n", + "- Official source: https://aws.slf.ch/api/bulletin/caaml/v4/en/geojson?activeAt=2026-01-11T11%3A30Z\n", + "- Data terms: https://www.slf.ch/en/services-and-products/slf-data-service/\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The official WSL Institute for Snow and Avalanche Research SLF feed supports regional hazard context. Start with two archived January 2026 bulletin regions; an archived bulletin is not a current avalanche warning and off-season responses can be empty." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official feed documentation and reuse terms.\n", + "2. Fetch one bounded official response.\n", + "3. Inspect two records and retain their validity period." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = \"https://aws.slf.ch/api/bulletin/caaml/v4/en/geojson\"\n", + "response = requests.get(url, params={\"activeAt\": \"2026-01-11T11:30:00Z\"}, timeout=20)\n", + "response.raise_for_status()\n", + "for region in response.json()[\"features\"][:2]:\n", + " props = region[\"properties\"]\n", + " print(props.get(\"bulletinID\"), props.get(\"validTime\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Map Dated Regional Warnings\n", + "\n", + "Inspect two archived January 2026 bulletin regions with official validity and source links.\n", + "\n", + "1. Fetch one official response and retain its issue time.\n", + "2. Display two region or river records with their source links.\n", + "3. Explain why coverage and validity cannot be inferred beyond the named area." + ] + } + ] +} diff --git a/public/notebooks/smhi-water-shortage-messages.ipynb b/public/notebooks/smhi-water-shortage-messages.ipynb new file mode 100644 index 0000000..d1f24c5 --- /dev/null +++ b/public/notebooks/smhi-water-shortage-messages.ipynb @@ -0,0 +1,128 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "smhi-water-shortage-messages", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# SMHI Water Shortage Messages\n", + "\n", + "Official Swedish water-shortage information messages from the impact-based warning API, with dated affected-area and validity metadata for local water-risk review.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/smhi-water-shortage-messages\n", + "- Official source: https://opendata-download-warnings.smhi.se/ibww/api/version/1\n", + "- Data terms: https://www.smhi.se/data/om-smhis-data/villkor-for-anvandning\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The documented SMHI impact-based warning API also publishes official water-shortage information messages. Start with one current warning list, filter by the documented event code, and keep message text and its timing intact; a message without valid time and area context is not a local warning." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Review the official API entry and the special warning and message terms.\n", + "2. Request the current warning JSON once and select WATER_SHORTAGE events.\n", + "3. Check affected areas and validity before displaying an unchanged message." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "response = requests.get(\n", + " \"https://opendata-download-warnings.smhi.se/ibww/api/version/1/warning.json\",\n", + " timeout=20,\n", + ")\n", + "response.raise_for_status()\n", + "messages = [warning for warning in response.json()\n", + " if warning.get(\"event\", {}).get(\"code\") == \"WATER_SHORTAGE\"]\n", + "print(f\"{len(messages)} current water-shortage messages\")\n", + "for message in messages[:3]:\n", + " for area in message.get(\"warningAreas\", [])[:2]:\n", + " name = area.get(\"areaName\", {})\n", + " print(message[\"id\"], name.get(\"en\") or name.get(\"sv\"),\n", + " area.get(\"published\"), area.get(\"approximateStart\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Review Current Water Shortage Information\n", + "\n", + "List a few official messages with their affected areas and publication times.\n", + "\n", + "1. Preserve the source message and event code without changing its wording.\n", + "2. Show affected areas and validity alongside every message.\n", + "3. Cite SMHI and refresh before presenting current conditions." + ] + } + ] +} diff --git a/public/notebooks/vigicrues-flood-vigilance-rss.ipynb b/public/notebooks/vigicrues-flood-vigilance-rss.ipynb new file mode 100644 index 0000000..d1cdefb --- /dev/null +++ b/public/notebooks/vigicrues-flood-vigilance-rss.ipynb @@ -0,0 +1,121 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "vigicrues-flood-vigilance-rss", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Vigicrues Flood Vigilance RSS\n", + "\n", + "French river flood-vigilance RSS items for building a dated regional river-warning view.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/vigicrues-flood-vigilance-rss\n", + "- Official source: https://www.vigicrues.gouv.fr/territoire/rss\n", + "- Data terms: https://www.vigicrues.gouv.fr/categorie/2\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "The official Vigicrues feed supports regional hazard context. Start with two French river-vigilance items; a feed item covers its named river segment, not every nearby location." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the official feed documentation and reuse terms.\n", + "2. Fetch one bounded official response.\n", + "3. Inspect two records and retain their validity period." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "from xml.etree import ElementTree as ET\n", + "\n", + "response = requests.get(\"https://www.vigicrues.gouv.fr/territoire/rss\", timeout=20)\n", + "response.raise_for_status()\n", + "root = ET.fromstring(response.content)\n", + "for item in root.findall(\"./channel/item\")[:2]:\n", + " print(item.findtext(\"title\"), item.findtext(\"pubDate\"), item.findtext(\"link\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Map Dated Regional Warnings\n", + "\n", + "Inspect two French river-vigilance items with official validity and source links.\n", + "\n", + "1. Fetch one official response and retain its issue time.\n", + "2. Display two region or river records with their source links.\n", + "3. Explain why coverage and validity cannot be inferred beyond the named area." + ] + } + ] +} diff --git a/public/notebooks/wfigs-current-incidents.ipynb b/public/notebooks/wfigs-current-incidents.ipynb new file mode 100644 index 0000000..3bc6fda --- /dev/null +++ b/public/notebooks/wfigs-current-incidents.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "wfigs-current-incidents", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# WFIGS Current Wildfire Incidents\n", + "\n", + "Agency-reported U.S. current wildfire incident points from NIFC for inspecting incident identity, location, size, and update time.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/wfigs-current-incidents\n", + "- Official source: https://www.arcgis.com/sharing/rest/content/items/4181a117dc9e43db8598533e29972015?f=json\n", + "- Data terms: https://www.arcgis.com/sharing/rest/content/items/4181a117dc9e43db8598533e29972015?f=json\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "WFIGS publishes a current incident-point layer derived from agency fire reports. Start with three features from the public ArcGIS layer. Incident locations are approximate, dynamic, and not legal boundaries; cite NIFC and contributing agencies and keep the update timestamp." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the exact ArcGIS item and its item-specific use notice.\n", + "2. Query three current incident records from the feature layer.\n", + "3. Inspect incident name, size, and modification time." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = (\"https://services3.arcgis.com/T4QMspbfLg3qTGWY/arcgis/rest/services/\"\n", + " \"WFIGS_Incident_Locations_Current/FeatureServer/0/query\")\n", + "response = requests.get(\n", + " url, params={\"where\": \"IncidentTypeCategory='WF'\", \"outFields\": \"OBJECTID,IrwinID,IncidentName,IncidentSize,ModifiedOnDateTime_dt\",\n", + " \"returnGeometry\": \"false\", \"resultRecordCount\": 3, \"f\": \"json\"}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for feature in response.json()[\"features\"][:3]:\n", + " row = feature[\"attributes\"]\n", + " print(row[\"IrwinID\"], row[\"IncidentName\"], row[\"ModifiedOnDateTime_dt\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Current U.S. Wildfire Points\n", + "\n", + "Review three agency incidents before mapping wildfire context.\n", + "\n", + "1. Keep the IRWIN ID, incident type, update time, and source agency.\n", + "2. Check freshness and exclude prescribed fires when needed.\n", + "3. Explain why a point does not identify a smoke plume's origin." + ] + } + ] +} diff --git a/public/notebooks/wfigs-current-perimeters.ipynb b/public/notebooks/wfigs-current-perimeters.ipynb new file mode 100644 index 0000000..b9d7d2b --- /dev/null +++ b/public/notebooks/wfigs-current-perimeters.ipynb @@ -0,0 +1,125 @@ +{ + "nbformat": 4, + "nbformat_minor": 5, + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python" + }, + "trilemma": { + "dataset_id": "wfigs-current-perimeters", + "last_verified": "2026-09-28", + "generated": true + } + }, + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# WFIGS Current Wildfire Perimeters\n", + "\n", + "Agency-reported U.S. wildfire perimeter polygons from NIFC for mapping approximate current fire footprints.\n", + "\n", + "- Guide: https://data.trilemma.foundation/datasets/wfigs-current-perimeters\n", + "- Official source: https://www.arcgis.com/sharing/rest/content/items/d1c32af3212341869b3c810f1a215824?f=json\n", + "- Data terms: https://www.arcgis.com/sharing/rest/content/items/d1c32af3212341869b3c810f1a215824?f=json\n", + "- Last verified: 2026-09-28" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Overview\n", + "\n", + "WFIGS publishes a separate current perimeter layer for agency-reported wildfire footprints. Start with three bounded feature records and keep polygon date and incident name. Perimeters can lag a moving fire and are not evacuation or legal boundary maps." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Prerequisites\n", + "\n", + "- Python 3.10 or newer\n", + "- An internet connection\n", + "- The requests Python package" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Access the Data\n", + "\n", + "1. Read the perimeter item's official notice and update context.\n", + "2. Query three current perimeter records from its feature layer.\n", + "3. Inspect polygon date and incident identity before mapping." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Install Packages\n", + "\n", + "Run this cell first." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# %pip install requests\n", + "%pip install requests" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Python Example" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import requests\n", + "\n", + "url = (\"https://services3.arcgis.com/T4QMspbfLg3qTGWY/arcgis/rest/services/\"\n", + " \"WFIGS_Interagency_Perimeters_Current/FeatureServer/0/query\")\n", + "response = requests.get(\n", + " url, params={\"where\": \"attr_IncidentTypeCategory='WF'\", \"outFields\": \"OBJECTID,poly_IncidentName,poly_PolygonDateTime\",\n", + " \"returnGeometry\": \"false\", \"resultRecordCount\": 3, \"f\": \"json\"}, timeout=30,\n", + ")\n", + "response.raise_for_status()\n", + "for feature in response.json()[\"features\"][:3]:\n", + " row = feature[\"attributes\"]\n", + " print(row[\"OBJECTID\"], row[\"poly_IncidentName\"], row[\"poly_PolygonDateTime\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## First Project: Inspect Current U.S. Fire Perimeters\n", + "\n", + "Review three reported fire polygons before map rendering.\n", + "\n", + "1. Keep object ID, polygon date, incident association, and attribution.\n", + "2. Filter prescribed or superseded features when building a current map.\n", + "3. Explain why a perimeter does not establish evacuation status." + ] + } + ] +} diff --git a/src/app/apps/[slug]/page.tsx b/src/app/apps/[slug]/page.tsx index 65d0581..8dafd2b 100644 --- a/src/app/apps/[slug]/page.tsx +++ b/src/app/apps/[slug]/page.tsx @@ -70,6 +70,26 @@ export default async function AppDetailPage({ params }: { params: Promise<{ slug

{appsCopy.sourceAvailabilityLabel}: {source.availability}

{source.coverage &&

{appsCopy.sourceCoverageLabel}: {source.coverage}

} {source.details &&

{source.details}

} + {source.systems && ( +
+ Review {source.systems.length} named warning {source.systems.length === 1 ? "system" : "systems"} + +
+ )}
{appsCopy.officialSourceLabel} for {source.name} (opens in a new tab) @@ -89,6 +109,11 @@ export default async function AppDetailPage({ params }: { params: Promise<{ slug {appsCopy.guideLabel} for {source.name} )} + {source.guideIds?.map((guide) => ( + + {guide.label} guide for {source.name} + + ))} {source.relatedGuideId && ( {appsCopy.relatedGuideLabel} for {source.name} diff --git a/src/content/apps.test.ts b/src/content/apps.test.ts index 925bb2d..2890f1b 100644 --- a/src/content/apps.test.ts +++ b/src/content/apps.test.ts @@ -1,5 +1,6 @@ import { describe, expect, it } from "vitest"; import { apps, getAppBySlug } from "./apps"; +import nationalWarningSystems from "./apps/national-warning-systems.json"; import { getActiveDatasets } from "../lib/datasets"; const expectedApps = [ @@ -60,10 +61,33 @@ describe("reviewed app catalog", () => { expectHttps(source.officialUrl); if (source.evidenceUrl) expectHttps(source.evidenceUrl); for (const { href } of source.additionalUrls ?? []) expectHttps(href); - expect(Boolean(source.guideId), `${app.slug}: ${source.name}`).not.toBe(Boolean(source.noGuideReason)); + expect([source.guideId, source.guideIds, source.noGuideReason, source.systems].filter(Boolean), `${app.slug}: ${source.name}`).toHaveLength(1); if (source.guideId) expect(activeGuideIds.has(source.guideId), `${app.slug}: ${source.name}`).toBe(true); + for (const guide of source.guideIds ?? []) { + expect(activeGuideIds.has(guide.id), `${app.slug}: ${source.name}: ${guide.label}`).toBe(true); + } if (source.relatedGuideId) expect(activeGuideIds.has(source.relatedGuideId), `${app.slug}: ${source.name}`).toBe(true); - if (source.noGuideReason) expect(source.noGuideReason.trim().length, `${app.slug}: ${source.name}`).toBeGreaterThan(10); + if (source.noGuideReason) { + expect(source.noGuideReason.trim().length, `${app.slug}: ${source.name}`).toBeGreaterThan(25); + expect(source.noGuideReason, `${app.slug}: ${source.name}`).not.toMatch(/no guide yet|not in the catalog|to be added|\bTBD\b/i); + } + if (source.systems) { + expect(source.systems.length, source.name).toBeGreaterThan(0); + for (const system of source.systems) { + expectHttps(system.officialUrl); + if (system.accessUrl) expectHttps(system.accessUrl); + if (system.termsUrl) expectHttps(system.termsUrl); + expect([system.guideId, system.guideIds, system.noGuideReason].filter(Boolean), `${source.name}: ${system.name}`).toHaveLength(1); + if (system.guideId) expect(activeGuideIds.has(system.guideId), `${source.name}: ${system.name}`).toBe(true); + for (const guide of system.guideIds ?? []) { + expect(activeGuideIds.has(guide.id), `${source.name}: ${system.name}: ${guide.label}`).toBe(true); + } + if (system.noGuideReason) { + expect(system.noGuideReason.trim().length, `${source.name}: ${system.name}`).toBeGreaterThan(25); + expect(system.noGuideReason, `${source.name}: ${system.name}`).not.toMatch(/no guide yet|not in the catalog|to be added|\bTBD\b/i); + } + } + } } } }); @@ -75,25 +99,50 @@ describe("reviewed app catalog", () => { ["travelcanary", /GDACS/i, "gdacs-disaster-alerts"], ["househunter", /TIGER\/Line/i, "census-tiger-line"], ["hyperoptions", /SEC EDGAR/i, "sec-edgar-apis"], + ["househunter", /FEMA National Risk Index/i, "fema-national-risk-index"], + ["rockyroad", /Geofabrik/i, "geofabrik-osm-extracts"], + ["hyperoptions", /Treasury interest rates/i, "treasury-yield-curve"], + ["titanskies", /Natural Earth oceans/i, "natural-earth"], + ["househunter", /FCC Broadband Data Collection/i, "fcc-bdc-county-fixed-summary"], + ["househunter", /EPA Safe Drinking Water/i, "epa-sdwis-bulk-submission"], + ["househunter", /EPA Community Water System/i, "epa-cws-service-areas-v2-1"], + ["travelcanary", /SMHI water-shortage/i, "smhi-water-shortage-messages"], + ["travelcanary", /IGN regional earthquakes/i, "ign-spain-earthquake-rss"], ] as const) { const source = getAppBySlug(slug)?.sources.find(({ name }) => sourceName.test(name)); expect(source, `${slug}: ${sourceName}`).toBeDefined(); expect(source?.guideId, `${slug}: ${sourceName}`).toBe(guideId); } - for (const [slug, name] of [ - ["househunter", "FEMA National Risk Index"], - ["rockyroad", "OpenStreetMap regional extracts via Geofabrik"], - ] as const) { - const source = getAppBySlug(slug)?.sources.find((entry) => entry.name === name); - expect(source, `${slug}: ${name}`).toBeDefined(); - expect(source?.guideId, `${slug}: ${name}`).toBeUndefined(); - expect(source?.noGuideReason, `${slug}: ${name}`).toMatch(/different|does not cover/i); - } expect(getAppBySlug("stackingsats")?.sourceIntro).toMatch(/historical|archiv/i); const brk = getAppBySlug("stackingsats")?.sources.find(({ name }) => name === "Bitcoin Research Kit merged metrics"); expect(brk?.guideId).toBeUndefined(); expect(brk?.relatedGuideId).toBe("bitview-bitcoin-series"); expect(brk?.noGuideReason).toMatch(/not this pinned historical parquet/i); + const effis = getAppBySlug("travelcanary")?.sources.find(({ name }) => name === "Copernicus EFFIS"); + expect(effis?.guideIds?.map(({ id }) => id)).toEqual([ + "effis-fire-danger-forecast", "effis-active-fire-hotspots", "effis-burned-area-perimeters", + ]); + const flood = getAppBySlug("travelcanary")?.sources.find(({ name }) => name === "Copernicus Global Flood Monitoring"); + expect(flood?.guideIds?.map(({ id }) => id)).toEqual([ + "copernicus-gfm-flood-layers", "copernicus-glofas-flood-outlook", + ]); expect(getAppBySlug("travelcanary")?.sources.length).toBeGreaterThan(20); }); + + it("keeps the 45 country partitions and all 83 named national warning systems", () => { + const travelCanary = getAppBySlug("travelcanary")!; + expect(nationalWarningSystems.sourceRevision).toBe(travelCanary.sourceRevision); + expect(nationalWarningSystems.reviewedAt).toBe(travelCanary.reviewedAt); + const countries = travelCanary.sources.filter(({ group }) => group === "National warnings"); + expect(countries).toHaveLength(45); + expect(countries.flatMap(({ systems }) => systems ?? [])).toHaveLength(83); + expect(countries.flatMap(({ systems }) => systems?.map(({ id }) => id) ?? []).sort()).toEqual( + Object.values(nationalWarningSystems.countries).flat().map(({ id }) => id).sort(), + ); + for (const country of countries) { + expect(country.availability).toMatch(/partition/); + expect(country.details).toBeTruthy(); + expect(country.systems?.length).toBeGreaterThan(0); + } + }); }); diff --git a/src/content/apps.ts b/src/content/apps.ts index c000f9f..34316f0 100644 --- a/src/content/apps.ts +++ b/src/content/apps.ts @@ -1,6 +1,19 @@ import { otherApps } from "./apps/other"; import { travelCanary } from "./apps/travelcanary"; +export type NationalWarningSystem = { + id: string; + name: string; + status: string; + officialUrl: string; + accessUrl?: string | null; + termsUrl?: string | null; +} & ( + | { guideId: string; guideIds?: never; noGuideReason?: never } + | { guideId?: never; guideIds: readonly { id: string; label: string }[]; noGuideReason?: never } + | { guideId?: never; guideIds?: never; noGuideReason: string } +); + export type AppSource = { name: string; group?: string; @@ -13,8 +26,10 @@ export type AppSource = { details?: string; relatedGuideId?: string; } & ( - | { guideId: string; noGuideReason?: never } - | { guideId?: never; noGuideReason: string } + | { guideId: string; guideIds?: never; noGuideReason?: never; systems?: never } + | { guideId?: never; guideIds: readonly { id: string; label: string }[]; noGuideReason?: never; systems?: never } + | { guideId?: never; guideIds?: never; noGuideReason: string; systems?: never } + | { guideId?: never; guideIds?: never; noGuideReason?: never; systems: readonly NationalWarningSystem[] } ); export type AppEntry = { diff --git a/src/content/apps/national-warning-systems.json b/src/content/apps/national-warning-systems.json new file mode 100644 index 0000000..df9360d --- /dev/null +++ b/src/content/apps/national-warning-systems.json @@ -0,0 +1,861 @@ +{ + "sourceRevision": "1ff2fdfa06b38880175a03aed10cfe60352bd0f6", + "reviewedAt": "2026-09-28", + "countries": { + "AT": [ + { + "id": "at-alert", + "name": "AT-Alert", + "status": "active", + "officialUrl": "https://warnung.at-alert.at/", + "accessUrl": "https://warnung.at-alert.at/api/rpc/alert/list", + "termsUrl": "https://www.rtr.at/rtr/service/opendata/OD_Nutzungsbedingungen.de.html", + "guideId": "at-alert-public-warnings" + } + ], + "BE": [ + { + "id": "be-alert-cap", + "name": "BE-Alert", + "status": "evidence_gated", + "officialUrl": "https://www.be-alert.be/en/", + "accessUrl": "https://publicalerts.be/CapGateway/feed?outdated=false", + "termsUrl": null, + "noGuideReason": "Gateway is JSON discovery with linked CAP. A sampled Actual/Public Alert was registration confirmation (event Test, Unknown severity), not an emergency. Website terms do not establish all gateway issuer rights. Need real emergency taxonomy/geometry, updates/cancellations and complete-query semantics; do not publish registration prose." + } + ], + "BG": [ + { + "id": "bg-alert-web", + "name": "BG-ALERT", + "status": "evidence_gated", + "officialUrl": "https://bg-alert.bg/", + "accessUrl": "https://bg-alert.bg/", + "termsUrl": null, + "noGuideReason": "The reviewed BG-ALERT surface for BG does not publish both an approved automated event contract and reuse terms for the exact feed; a bounded Python reader cannot be verified." + } + ], + "HR": [ + { + "id": "hr-public-warning", + "name": "SRUUK", + "status": "blocked", + "officialUrl": "https://civilna-zastita.gov.hr/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed SRUUK authority page for HR does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + }, + { + "id": "dhmz-cap", + "name": "DHMZ direct CAP warnings", + "status": "active", + "officialUrl": "https://meteo.hr/proizvodi.php?section=podaci¶m=xml_korisnici", + "accessUrl": "https://meteo.hr/upozorenja/cap_hr_today.xml", + "termsUrl": "https://meteo.hr/proizvodi.php?section=podaci¶m=xml_korisnici", + "guideId": "dhmz-cap-warnings" + } + ], + "CY": [ + { + "id": "cy-alert-news", + "name": "Cyprus public warning system", + "status": "evidence_gated", + "officialUrl": "https://www.gov.cy/moi/en/civil-defence/", + "accessUrl": "https://www.gov.cy/moi/en/civil-defence/", + "termsUrl": null, + "noGuideReason": "The reviewed Cyprus public warning system surface for CY does not publish both an approved automated event contract and reuse terms for the exact feed; a bounded Python reader cannot be verified." + } + ], + "CZ": [ + { + "id": "chmi-hydrology", + "name": "CHMI hydrology and flash-flood risk", + "status": "active", + "officialUrl": "https://opendata.chmi.cz/hydrology/", + "accessUrl": "https://opendata.chmi.cz/hydrology/now/data/", + "termsUrl": "https://www.chmi.cz/-/jak-mohu-pou%C5%BE%C3%ADvat-otev%C5%99en%C3%A1-data-%C4%8Dhm%C3%BA-", + "guideIds": [ + { + "id": "chmi-current-hydrology", + "label": "Station observations" + }, + { + "id": "chmi-flash-flood-risk", + "label": "Flash-flood risk" + } + ] + } + ], + "DK": [ + { + "id": "dk-police-emergency-rss", + "name": "S!RENEN", + "status": "evidence_gated", + "officialUrl": "https://www.sirenen.dk/", + "accessUrl": "https://via.ritzau.dk/rss/short-messages/latest", + "termsUrl": null, + "noGuideReason": "The reviewed S!RENEN surface for DK does not publish both an approved automated event contract and reuse terms for the exact feed; a bounded Python reader cannot be verified." + } + ], + "EE": [ + { + "id": "ee-public-warning", + "name": "EE-ALARM", + "status": "blocked", + "officialUrl": "https://www.olevalmis.ee/en/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed EE-ALARM authority page for EE does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + } + ], + "FI": [ + { + "id": "fi-public-warning", + "name": "Finland public warning system", + "status": "blocked", + "officialUrl": "https://www.suomi.fi/guides/preparedness", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Finland public warning system authority page for FI does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + }, + { + "id": "fmi-cap", + "name": "FMI CAP warnings", + "status": "active", + "officialUrl": "https://alerts.fmi.fi/cap/profile/current/", + "accessUrl": "https://alerts.fmi.fi/cap/feed/rss_en-GB.rss", + "termsUrl": "https://en.ilmatieteenlaitos.fi/open-data-licence", + "guideId": "fmi-cap-warnings" + } + ], + "FR": [ + { + "id": "fr-alert", + "name": "FR-Alert", + "status": "active", + "officialUrl": "https://fr-alert.gouv.fr/les-alertes", + "accessUrl": "https://fr-alert.gouv.fr/les-alertes", + "termsUrl": "https://www.fr-alert.gouv.fr/mentions-legales", + "noGuideReason": "The official FR-Alert site and legal-terms page failed HTTPS certificate validation on 2026-09-28, so a supported live Python access path and current reuse terms could not be verified." + }, + { + "id": "meteofrance-vigilance", + "name": "Météo-France Vigilance API", + "status": "credential_gated", + "officialUrl": "https://www.data.gouv.fr/dataservices/api-bulletin-vigilance", + "accessUrl": "https://public-api.meteofrance.fr/public/DPVigilance/v1", + "termsUrl": null, + "noGuideReason": "Free registered API, but no credentials provisioned. Current subscription quota, token lifetime, departmental/coastal mappings and lifecycle fixtures must be verified before implementing a reader; no account creation is included." + } + ], + "DE": [ + { + "id": "lhp-flood", + "name": "LHP flood warnings", + "status": "active", + "officialUrl": "https://www.hochwasserzentralen.de/", + "accessUrl": "https://api.hochwasserzentralen.de/public/v1/data/alerts?format=geojson&lang=en", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "guideId": "lhp-germany-flood-warnings" + }, + { + "id": "bbk-mowas-rss", + "name": "BBK civil-protection RSS", + "status": "evidence_gated", + "officialUrl": "https://www.bbk.bund.de/DE/Warnung-Vorsorge/Warn-App-NINA/warn-app-nina_node.html", + "accessUrl": "https://warnung.bund.de/api31/mowas/rss/110000000000.rss", + "termsUrl": null, + "noGuideReason": "Official location RSS returned empty HTTP 200 feeds with old channel publication dates. Federal warning redistribution permits unchanged content, but state/municipal issuer rights and normalized presentation remain unverified. Need real emergency/update/cancel fixtures, exact district geometry, severity and complete-state withdrawal semantics." + }, + { + "id": "dwd-cap", + "name": "DWD direct CAP recovery", + "status": "active", + "officialUrl": "https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_EVENT_STAT/", + "accessUrl": "https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_EVENT_STAT/Z_CAP_C_EDZW_LATEST_PVW_STATUS_PREMIUMEVENT_COMMUNEUNION_EN.zip", + "termsUrl": "https://www.govdata.de/dl-de/by-2-0", + "guideId": "dwd-cap-warnings" + } + ], + "GR": [ + { + "id": "gr-112-news", + "name": "112 Greece", + "status": "evidence_gated", + "officialUrl": "https://civilprotection.gov.gr/", + "accessUrl": "https://civilprotection.gov.gr/", + "termsUrl": "https://civilprotection.gov.gr/oroi-xrisis", + "noGuideReason": "Official terms specify CC BY-NC-SA 4.0 plus unchanged content; normalized summaries need a compatible presentation contract. The old all-guidelines URL redirects to static protection guidance. Need a supported current machine-warning feed with exact affected areas, validity and cancellation." + } + ], + "HU": [ + { + "id": "hu-public-warning", + "name": "VÉSZ", + "status": "blocked", + "officialUrl": "https://www.katasztrofavedelem.hu/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed VÉSZ authority page for HU does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + } + ], + "IE": [ + { + "id": "ie-public-warning", + "name": "Ireland public warning system", + "status": "blocked", + "officialUrl": "https://www.gov.ie/en/department-of-defence/organisation-information/office-of-emergency-planning/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Ireland public warning system authority page for IE does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + }, + { + "id": "met-eireann-json", + "name": "Met Eireann warnings", + "status": "active", + "officialUrl": "https://www.met.ie/warnings-today.html", + "accessUrl": "https://www.met.ie/Open_Data/json/warning_IRELAND.json", + "termsUrl": "https://www.met.ie/about-us/specialised-services/widgets", + "guideId": "met-eireann-warnings" + } + ], + "IT": [ + { + "id": "it-public-warning", + "name": "IT-alert", + "status": "blocked", + "officialUrl": "https://www.it-alert.gov.it/en/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed IT-alert authority page for IT does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + }, + { + "id": "dpc-flood-bulletin", + "name": "National hydrogeological and hydraulic bulletin", + "status": "active", + "officialUrl": "https://mappe.protezionecivile.gov.it/it/mappe-rischi/bollettino-di-criticita/", + "accessUrl": "https://api.github.com/repos/pcm-dpc/DPC-Bollettini-Criticita-Idrogeologica-Idraulica/commits?path=files/topojson&per_page=1", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "guideId": "dpc-italy-flood-bulletins" + }, + { + "id": "dpc-volcanic-restrictions", + "name": "Italian volcanic warnings and restrictions", + "status": "evidence_gated", + "officialUrl": "https://rischi.protezionecivile.gov.it/it/vulcanico/vulcani-italia/stromboli/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "Official historical municipal ordinances include path/altitude restrictions and revocation, but no complete current inventory, bounded zone extraction or current reuse contract is established. Publication-end dates do not establish restriction expiry. DPC activity levels remain distinct from local emergency orders." + } + ], + "LV": [ + { + "id": "lv-112-active", + "name": "Latvia public warning system", + "status": "evidence_gated", + "officialUrl": "https://www.vugd.gov.lv/en", + "accessUrl": "https://www.112.lv/", + "termsUrl": null, + "noGuideReason": "The reviewed Latvia public warning system surface for LV does not publish both an approved automated event contract and reuse terms for the exact feed; a bounded Python reader cannot be verified." + }, + { + "id": "lvgmc-flood", + "name": "LVĢMC hydrological warnings", + "status": "active", + "officialUrl": "https://data.gov.lv/dati/dataset/hidrometeorologiskie-bridinajumi", + "accessUrl": "https://data.gov.lv/dati/api/3/action/package_show?id=hidrometeorologiskie-bridinajumi", + "termsUrl": "https://data.gov.lv/dati/dataset/hidrometeorologiskie-bridinajumi", + "guideId": "lvgmc-hydrometeorological-warnings" + } + ], + "LT": [ + { + "id": "lt72-sent-warnings", + "name": "LT72", + "status": "evidence_gated", + "officialUrl": "https://lt72.lt/", + "accessUrl": "https://lt72.lt/kategorija/pranesimai/", + "termsUrl": null, + "noGuideReason": "The reviewed LT72 surface for LT does not publish both an approved automated event contract and reuse terms for the exact feed; a bounded Python reader cannot be verified." + } + ], + "LU": [ + { + "id": "lu-alert", + "name": "LU-Alert", + "status": "active", + "officialUrl": "https://data.public.lu/fr/datasets/alertes-du-systeme-lu-alert/", + "accessUrl": "https://data.public.lu/api/1/datasets/alertes-du-systeme-lu-alert/", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "guideId": "lu-alert-cap" + } + ], + "MT": [ + { + "id": "mt-public-warning", + "name": "Malta public warning system", + "status": "blocked", + "officialUrl": "https://cps.gov.mt/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Malta public warning system authority page for MT does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + } + ], + "NL": [ + { + "id": "nl-alert-current", + "name": "NL-Alert", + "status": "evidence_gated", + "officialUrl": "https://www.nl-alert.nl/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The official website exposes current alerts, but its browser JSON transport is undocumented and not approved for automated reuse." + } + ], + "PL": [ + { + "id": "imgw-hydrology", + "name": "IMGW hydrology warnings", + "status": "active", + "officialUrl": "https://hydro.imgw.pl/", + "accessUrl": "https://danepubliczne.imgw.pl/api/data/hydro/", + "termsUrl": "https://danepubliczne.imgw.pl/", + "guideIds": [ + { + "id": "imgw-current-hydrology", + "label": "Station observations" + }, + { + "id": "imgw-hydrological-bulletins", + "label": "Hydrological bulletins" + } + ] + } + ], + "PT": [ + { + "id": "ipma-warnings-json", + "name": "IPMA weather warnings", + "status": "active", + "officialUrl": "https://www.ipma.pt/en/otempo/prev-sam/", + "accessUrl": "https://api.ipma.pt/open-data/forecast/warnings/warnings_www.json", + "termsUrl": "https://api.ipma.pt/", + "guideId": "ipma-weather-warnings" + }, + { + "id": "pt-public-warning", + "name": "PROCIV", + "status": "blocked", + "officialUrl": "https://prociv.gov.pt/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed PROCIV authority page for PT does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + }, + { + "id": "azores-civil-protection", + "name": "Azores Civil Protection alerts", + "status": "evidence_gated", + "officialUrl": "https://www.prociv.azores.gov.pt/alertas/", + "accessUrl": "https://prociv.azores.gov.pt/alertas/api?lang=en&limit_last_alerts=20", + "termsUrl": null, + "noGuideReason": "The official API is documented, but permission for automated republication has not been established, including for noncommercial use." + }, + { + "id": "anepc-incidents", + "name": "ANEPC operational incidents", + "status": "evidence_gated", + "officialUrl": "https://prociv.gov.pt/pt/ocorrencias/", + "accessUrl": "https://services-eu1.arcgis.com/VlrHb7fn5ewYhX6y/arcgis/rest/services/OcorrenciasSite/FeatureServer/0/query", + "termsUrl": null, + "noGuideReason": "Current official ArcGIS service has no licenseInfo/accessInformation; the legacy CC BY catalog points to unavailable SADO services. Need successor-service reuse, authoritative status/category codes and complete-query withdrawal. Current DataDosDados is dataset refresh, not incident onset. Points do not establish perimeters or evacuation zones." + } + ], + "RO": [ + { + "id": "ro-public-warning", + "name": "RO-ALERT", + "status": "blocked", + "officialUrl": "https://www.mai.gov.ro/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed RO-ALERT authority page for RO does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + } + ], + "SK": [ + { + "id": "sk-public-warning", + "name": "Slovakia public warning system", + "status": "blocked", + "officialUrl": "https://www.minv.sk/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Slovakia public warning system authority page for SK does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + }, + { + "id": "sk-crisis-rest", + "name": "Crisis-management REST service", + "status": "credential_gated", + "officialUrl": "https://portal.minv.sk/wps/esispz-api/docs/index.html", + "accessUrl": "https://portal.minv.sk/wps/esispz-api/", + "termsUrl": null, + "noGuideReason": "The documented reader API requires an authority-issued key and contract validation." + } + ], + "SI": [ + { + "id": "si-spin-incidents", + "name": "Slovenia public warning system", + "status": "evidence_gated", + "officialUrl": "https://www.gov.si/en/state-authorities/bodies-within-ministries/administration-for-civil-protection-and-disaster-relief/", + "accessUrl": "https://www.gov.si/en/state-authorities/bodies-within-ministries/administration-for-civil-protection-and-disaster-relief/", + "termsUrl": null, + "noGuideReason": "The reviewed Slovenia public warning system surface for SI does not publish both an approved automated event contract and reuse terms for the exact feed; a bounded Python reader cannot be verified." + } + ], + "ES": [ + { + "id": "catalonia-plans", + "name": "Catalonia civil-protection plans", + "status": "active", + "officialUrl": "https://interior.gencat.cat/ca/arees_dactuacio/proteccio_civil/", + "accessUrl": "https://analisi.transparenciacatalunya.cat/resource/wj9c-j6vf.json", + "termsUrl": "https://web.gencat.cat/ca/generalitat/dades-indicadors/dades-obertes/llicencies", + "guideId": "catalonia-civil-protection-plans" + }, + { + "id": "aemet-cap", + "name": "AEMET direct CAP warnings", + "status": "active", + "officialUrl": "https://www.aemet.es/es/rss_info/avisos/esp", + "accessUrl": "https://www.aemet.es/documentos_d/eltiempo/prediccion/avisos/rss/CAP_AFAE_ATOM.xml", + "termsUrl": "https://www.aemet.es/es/nota_legal", + "guideId": "aemet-cap-warnings" + } + ], + "SE": [ + { + "id": "krisinformation", + "name": "Krisinformation", + "status": "active", + "officialUrl": "https://www.krisinformation.se/en", + "accessUrl": "https://api.krisinformation.se/v3/vmas?allCounties=true&language=en", + "termsUrl": "https://www.krisinformation.se/om-krisinformation/for-myndigheter-och-andra-aktorer/oppen-data/", + "guideId": "krisinformation-vma" + }, + { + "id": "smhi-direct-warnings", + "name": "SMHI direct warnings", + "status": "evidence_gated", + "officialUrl": "https://opendata-download-warnings.smhi.se/ibww/api/version/1", + "accessUrl": "https://opendata-download-warnings.smhi.se/ibww/api/version/1/warning.json", + "termsUrl": null, + "noGuideReason": "Special terms require unchanged warning content, attribution and delivery within five minutes, never more than ten. The ten-minute collector plus publication/cache latency cannot meet this. A separately budgeted compliant delivery path is required." + } + ], + "CH": [ + { + "id": "ch-public-warning", + "name": "Alertswiss", + "status": "blocked", + "officialUrl": "https://www.alert.swiss/en/home.html", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Alertswiss authority page for CH does not document a reusable production event feed with geometry, updates, and cancellations; no exact runnable reader can be published." + } + ], + "AD": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "active", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-andorra", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "credential_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/AD", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "Optional authenticated recovery; catalog 3 launch and health rely on the keyless Atom primary, not this transport." + }, + { + "id": "ad-official-information", + "name": "Andorra weather alerts", + "status": "evidence_gated", + "officialUrl": "https://www.meteo.ad/en/Alerts", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Andorra weather alerts public-information page for AD exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "AL": [ + { + "id": "al-official-information", + "name": "Institute of Geosciences", + "status": "evidence_gated", + "officialUrl": "https://geo.edu.al/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Institute of Geosciences public-information page for AL exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "BA": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-bosnia-herzegovina", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/BA", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's BA EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "ba-official-information", + "name": "Federal Hydrometeorological Institute", + "status": "evidence_gated", + "officialUrl": "https://www.fhmzbih.gov.ba/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Federal Hydrometeorological Institute public-information page for BA exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "BY": [ + { + "id": "by-official-information", + "name": "Belhydromet weather information", + "status": "evidence_gated", + "officialUrl": "https://pogoda.by/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Belhydromet weather information public-information page for BY exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "GB": [ + { + "id": "ea-flood", + "name": "England flood warnings", + "status": "active", + "officialUrl": "https://check-for-flooding.service.gov.uk/", + "accessUrl": "https://environment.data.gov.uk/flood-monitoring/id/floods", + "termsUrl": "https://www.nationalarchives.gov.uk/doc/open-government-licence/version/3/", + "guideId": "england-flood-warnings" + }, + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-united-kingdom", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/UK", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's GB EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "gb-official-information", + "name": "Met Office UK weather warnings", + "status": "evidence_gated", + "officialUrl": "https://weather.metoffice.gov.uk/warnings-and-advice/uk-warnings", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Met Office UK weather warnings public-information page for GB exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + }, + { + "id": "met-office-nswws", + "name": "National Severe Weather Warning Service", + "status": "credential_gated", + "officialUrl": "https://www.metoffice.gov.uk/weather/warnings-and-advice/uk-warnings", + "accessUrl": "https://warnings.api.metoffice.gov.uk/", + "termsUrl": "https://www.metoffice.gov.uk/about-us/legal", + "noGuideReason": "Optional non-contributing enhancement; Met Office credentials are not provisioned for this release." + }, + { + "id": "nrw-flood", + "name": "Wales flood warnings", + "status": "credential_gated", + "officialUrl": "https://naturalresources.wales/flooding/check-flood-warnings/?lang=en", + "accessUrl": "https://api.naturalresources.wales/floodwarnings/", + "termsUrl": null, + "noGuideReason": "Optional enhancement; Wales remains authoritative-link coverage without credentials." + } + ], + "IS": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "active", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-iceland", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "credential_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/IS", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "Optional authenticated recovery; catalog 3 launch and health rely on the keyless Atom primary, not this transport." + }, + { + "id": "is-official-information", + "name": "Icelandic Met Office", + "status": "evidence_gated", + "officialUrl": "https://en.vedur.is/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Icelandic Met Office public-information page for IS exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "LI": [ + { + "id": "li-official-information", + "name": "Liechtenstein government information", + "status": "evidence_gated", + "officialUrl": "https://www.llv.li/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Liechtenstein government information public-information page for LI exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "MC": [ + { + "id": "mc-official-information", + "name": "Monaco government information", + "status": "evidence_gated", + "officialUrl": "https://www.gouv.mc/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Monaco government information public-information page for MC exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "MD": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-moldova", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/MD", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's MD EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "md-official-information", + "name": "Moldova weather warnings", + "status": "evidence_gated", + "officialUrl": "https://www.meteo.md/index.php/ro/weather/current-warnings/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Moldova weather warnings public-information page for MD exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "ME": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-montenegro", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/ME", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's ME EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "me-official-information", + "name": "Montenegro Hydrometeorological and Seismological Service", + "status": "evidence_gated", + "officialUrl": "https://www.meteo.co.me/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Montenegro Hydrometeorological and Seismological Service public-information page for ME exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "MK": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-republic-of-north-macedonia", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/MK", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's MK EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "mk-official-information", + "name": "North Macedonia Hydrometeorological Service", + "status": "evidence_gated", + "officialUrl": "https://uhmr.gov.mk/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed North Macedonia Hydrometeorological Service public-information page for MK exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "NO": [ + { + "id": "met-norway-alerts", + "name": "MET Norway MetAlerts", + "status": "active", + "officialUrl": "https://www.met.no/en/weather-and-climate/text-forecast-and-warnings", + "accessUrl": "https://api.met.no/weatherapi/metalerts/2.0/current.json", + "termsUrl": "https://api.met.no/doc/TermsOfService", + "guideId": "met-norway-metalerts" + }, + { + "id": "nve-flood", + "name": "NVE flood warnings", + "status": "active", + "officialUrl": "https://www.varsom.no/en/flood-and-landslide-warning-service/", + "accessUrl": "https://api01.nve.no/hydrology/forecast/flood/v1.0.10/Warning/en/", + "termsUrl": "https://www.nve.no/about-nve/privacy-policy/terms-of-use/", + "guideId": "nve-flood-warnings" + }, + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-norway", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/NO", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's NO EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "no-official-information", + "name": "Varsom natural hazard warnings", + "status": "evidence_gated", + "officialUrl": "https://www.varsom.no/en/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Varsom natural hazard warnings public-information page for NO exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "RS": [ + { + "id": "meteoalarm-atom", + "name": "MeteoAlarm keyless Atom warning feed", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://feeds.meteoalarm.org/feeds/meteoalarm-legacy-atom-serbia", + "termsUrl": "https://www.meteoalarm.org/en/live/terms-and-conditions/", + "guideId": "meteoalarm-atom-warnings" + }, + { + "id": "meteoalarm-edr", + "name": "MeteoAlarm authenticated EDR recovery", + "status": "evidence_gated", + "officialUrl": "https://www.meteoalarm.org/", + "accessUrl": "https://api.meteoalarm.org/edr/v1/collections/warnings/locations/RS", + "termsUrl": "https://creativecommons.org/licenses/by/4.0/", + "noGuideReason": "MeteoAlarm's RS EDR location endpoint requires authentication, and this partition lacks verified destination and hazard coverage; the keyless Atom guide does not describe this distinct EDR artifact." + }, + { + "id": "rs-official-information", + "name": "Serbia hydrometeorological warnings", + "status": "evidence_gated", + "officialUrl": "https://www.hidmet.gov.rs/latin/upozorenja/index.php", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Serbia hydrometeorological warnings public-information page for RS exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "SM": [ + { + "id": "sm-official-information", + "name": "San Marino civil protection orders", + "status": "evidence_gated", + "officialUrl": "https://www.gov.sm/pub1/GovSM/Circolari-e-Ordinanze/Ordinanze-Protezione-Civile.html", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed San Marino civil protection orders public-information page for SM exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "TR": [ + { + "id": "tr-official-information", + "name": "Türkiye meteorological information", + "status": "evidence_gated", + "officialUrl": "https://www.mgm.gov.tr/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Türkiye meteorological information public-information page for TR exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "VA": [ + { + "id": "va-official-information", + "name": "Vatican City State information", + "status": "evidence_gated", + "officialUrl": "https://www.vaticanstate.va/en/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Vatican City State information public-information page for VA exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ], + "XK": [ + { + "id": "xk-official-information", + "name": "Kosovo Hydrometeorological Institute", + "status": "evidence_gated", + "officialUrl": "https://ihmk-rks.net/", + "accessUrl": null, + "termsUrl": null, + "noGuideReason": "The reviewed Kosovo Hydrometeorological Institute public-information page for XK exposes no documented, reusable machine-warning feed or bounded Python access path; this is a source link, not monitored coverage." + } + ] + } +} diff --git a/src/content/apps/other.ts b/src/content/apps/other.ts index 7785c03..12655f8 100644 --- a/src/content/apps/other.ts +++ b/src/content/apps/other.ts @@ -19,7 +19,7 @@ export const otherApps = [ availability: "Configured public WCS forecast; a failed or stale run can retain a dated prior forecast.", officialUrl: "https://www.weather.gc.ca/firework/index_e.html", coverage: "Canada and adjoining areas covered by the FireWork model.", - noGuideReason: "A FireWork-specific guide has not passed the Data catalog review.", + guideId: "eccc-firework-smoke", }, { name: "NOAA HRRR-Smoke", @@ -28,7 +28,7 @@ export const otherApps = [ availability: "Configured public GRIB forecast; freshness and fallback are checked per run.", officialUrl: "https://rapidrefresh.noaa.gov/hrrr/HRRRsmoke/", coverage: "United States model domain.", - noGuideReason: "A HRRR-Smoke-specific guide has not passed the Data catalog review.", + guideId: "noaa-hrrr-smoke", }, { name: "EPA AirNow", @@ -46,7 +46,7 @@ export const otherApps = [ availability: "Configured public observation feed; stations and timestamps may be incomplete or stale.", officialUrl: "https://www2.gov.bc.ca/gov/content/environment/air-land-water/air/air-quality/current-air-quality-data", coverage: "British Columbia stations.", - noGuideReason: "A guide for this B.C. hourly feed has not passed catalog review.", + guideId: "bc-unverified-hourly-pm25", }, { name: "INECC SINAICA", @@ -55,7 +55,7 @@ export const otherApps = [ availability: "Gated by SINAICA_ENABLED; disabled sources and failed reads are reported as unavailable or dated.", officialUrl: "https://sinaica.inecc.gob.mx/", coverage: "Participating Mexico monitoring stations.", - noGuideReason: "A SINAICA-specific guide has not passed catalog review.", + noGuideReason: "SINAICA publishes preliminary hourly data, but the reviewed provider pages do not state terms permitting automated reuse of that exact feed; catalog reuse eligibility is unverified.", }, { name: "ECCC Air Quality Health Index", @@ -64,7 +64,7 @@ export const otherApps = [ availability: "Configured public feed; observations can be missing or stale.", officialUrl: "https://weather.gc.ca/airquality/pages/index_e.html", coverage: "Participating Canadian stations.", - noGuideReason: "An AQHI observation guide has not passed catalog review.", + guideId: "eccc-aqhi-observations", }, { name: "NIFC WFIGS", @@ -73,16 +73,22 @@ export const otherApps = [ availability: "Configured public service with per-run freshness checks and dated fallback.", officialUrl: "https://data-nifc.opendata.arcgis.com/", coverage: "United States incidents and perimeters.", - noGuideReason: "A WFIGS incident-layer guide has not passed catalog review.", + guideIds: [ + { id: "wfigs-current-incidents", label: "Incident locations" }, + { id: "wfigs-current-perimeters", label: "Fire perimeters" }, + ], }, { name: "NRCan CWFIS", group: "Wildfire context", - role: "Agency-reported Canadian wildfire incident points and perimeters.", + role: "Canadian wildfire incident records and NRCan M3 estimated fire-perimeter context.", availability: "Configured public service with per-run freshness checks and dated fallback.", officialUrl: "https://cwfis.cfs.nrcan.gc.ca/", coverage: "Canada incidents and perimeters.", - noGuideReason: "A CWFIS incident-layer guide has not passed catalog review.", + guideIds: [ + { id: "cwfif-active-wildland-fires", label: "Active wildfire records" }, + { id: "cwfis-m3-perimeter-estimates", label: "M3 perimeter estimates" }, + ], }, { name: "Natural Earth oceans and populated places", @@ -92,7 +98,7 @@ export const otherApps = [ officialUrl: "https://www.naturalearthdata.com/", evidenceUrl: "https://github.com/hypertrial/titanskies/blob/3cf6db94229dc8eb195f4caf662da01eb0e83691/scripts/generate_geo.py", coverage: "North America within the generated map and city catalog.", - noGuideReason: "The existing Natural Earth guide covers 110m country boundaries, not these 50m ocean and 10m populated-place artifacts.", + guideId: "natural-earth", }, ], }, @@ -113,7 +119,7 @@ export const otherApps = [ availability: "Enabled, unofficial public JSON access for personal local use; chain and new watches fail closed if the ticker universe cannot load.", officialUrl: "https://www.nasdaq.com/market-activity/stocks", evidenceUrl: "https://github.com/hypertrial/hyperoptions/blob/e23909d37cdf65f40967bc5c4194a8dcda967602/backend/src/options_api/nasdaq.py", - noGuideReason: "No Nasdaq option-chain guide has passed the Data catalog's access and reuse review.", + noGuideReason: "These unofficial Nasdaq site JSON endpoints have no published permission for automated option-chain reuse; Nasdaq's licensed Data Link products are different feeds, so catalog reuse eligibility is unverified.", }, { name: "Yahoo Finance", @@ -122,7 +128,7 @@ export const otherApps = [ availability: "Enabled through an unofficial client, with verified local caches. Training on Yahoo-derived histories is gated while rights remain unverified.", officialUrl: "https://finance.yahoo.com/", evidenceUrl: "https://github.com/hypertrial/hyperoptions/blob/e23909d37cdf65f40967bc5c4194a8dcda967602/docs/source-rights.md", - noGuideReason: "Automated history and option-quote reuse rights have not qualified for a Data guide.", + noGuideReason: "Yahoo's terms require prior permission for automated collection; this unofficial client has no verified grant for historical-price or option-quote analysis.", }, { name: "U.S. Treasury interest rates", @@ -131,7 +137,7 @@ export const otherApps = [ availability: "Configured public XML source; unavailable dates withhold dependent calculations.", officialUrl: "https://home.treasury.gov/resource-center/data-chart-center/interest-rates/pages/xml", evidenceUrl: "https://github.com/hypertrial/hyperoptions/blob/e23909d37cdf65f40967bc5c4194a8dcda967602/backend/src/options_api/market_sources.py", - noGuideReason: "The existing Treasury auctions guide covers a different data product; yield-curve guide review is pending.", + guideId: "treasury-yield-curve", }, { name: "SEC EDGAR submissions", @@ -166,7 +172,7 @@ export const otherApps = [ { label: "County layer", href: "https://www.arcgis.com/home/item.html?id=39485e8035d446a5bff03259508ae355&sublayer=0" }, ], coverage: "85,154 tracts and 3,232 counties/county equivalents in the pinned source layers.", - noGuideReason: "FEMA National Flood Hazard Layer is a different dataset; a National Risk Index guide has not passed review.", + guideId: "fema-national-risk-index", }, { name: "County Health Rankings & Roadmaps 2025", @@ -178,7 +184,10 @@ export const otherApps = [ { label: "Community Conditions county layer", href: "https://p3eplmys2rvchkjx.svcs.arcgis.com/P3ePLMYs2RVChkJx/arcgis/rest/services/County%20Health%20Rankings%202025/FeatureServer/2" }, { label: "Mental-health supplement", href: "https://www.countyhealthrankings.org/sites/default/files/media/document/analytic_supplement_20260325%5B1%5D.csv" }, ], - noGuideReason: "The NPPES registry guide does not cover these CHR&R published products; guide review is pending.", + guideIds: [ + { id: "chrr-community-conditions-2025", label: "2025 county conditions" }, + { id: "chrr-mental-health-supplement-2025", label: "2025 provider supplement" }, + ], }, { name: "BEA Regional Price Parities", @@ -190,7 +199,7 @@ export const otherApps = [ { label: "MSA archive", href: "https://apps.bea.gov/regional/zip/MARPP.zip" }, { label: "State archive", href: "https://apps.bea.gov/regional/zip/SARPP.zip" }, ], - noGuideReason: "The existing BEA GDP and income guide does not cover Regional Price Parities.", + guideId: "bea-regional-price-parities", }, { name: "Realtor.com Research Data", @@ -207,7 +216,7 @@ export const otherApps = [ availability: "Pinned 2025 county totals, acquired by maintainers and packaged only as derived county reference values.", officialUrl: "https://www.census.gov/programs-surveys/popest.html", additionalUrls: [{ label: "Pinned county file", href: "https://www2.census.gov/programs-surveys/popest/datasets/2020-2025/counties/totals/co-est2025-alldata.csv" }], - noGuideReason: "A Census PEP county-totals guide has not passed catalog review.", + guideId: "census-pep-county-totals", }, { name: "FBI Crime Data Explorer", @@ -216,7 +225,7 @@ export const otherApps = [ availability: "Pinned agency response manifest and manually staged reference archives; suppression and less than 90% coverage remain null.", officialUrl: "https://cde.ucr.cjis.gov/LATEST/webapp/", evidenceUrl: "https://github.com/hypertrial/househunter/blob/eea3dfffb5bd728afff4e63edda27959e7d86f97/config/ranking/source-lock-v2.json", - noGuideReason: "The existing FBI guide starts with state estimates, not this pinned agency response and archive contract.", + guideId: "fbi-cde-agency-summaries", }, { name: "EPA Safe Drinking Water Information System", @@ -224,7 +233,7 @@ export const otherApps = [ role: "Public-water-system inventory and violation records contributing to Safety Factors.", availability: "Pinned 2026Q2 bulk submission staged by maintainers; excludes private wells and is not real-time water-quality measurement.", officialUrl: "https://echo.epa.gov/tools/data-downloads/sdwa-download-summary", - noGuideReason: "The existing ECHO web-service guide is not the pinned SDWIS bulk archive used here.", + guideId: "epa-sdwis-bulk-submission", }, { name: "EPA Community Water System Service Areas", @@ -232,7 +241,7 @@ export const otherApps = [ role: "Modeled and supplied public-water boundaries allocated to 2020 Census block population for county coverage context.", availability: "Pinned version 2.1 GeoPackage and block table, acquired by maintainers; insufficient allocatable coverage remains null.", officialUrl: "https://www.epa.gov/ground-water-and-drinking-water/public-water-system-service-areas", - noGuideReason: "A guide for the service-area model and allocation table has not passed review.", + guideId: "epa-cws-service-areas-v2-1", }, { name: "HRSA Area Health Resources Files", @@ -240,7 +249,7 @@ export const otherApps = [ role: "2024–2025 county primary-care and dental provider supply for Health utility.", availability: "Pinned AHRF archive acquired by maintainers; provider counts are availability proxies.", officialUrl: "https://data.hrsa.gov/data/download", - noGuideReason: "An AHRF county guide has not passed catalog review.", + guideId: "hrsa-ahrf-county", }, { name: "Census ACS 2024 Five-Year Estimates", @@ -249,7 +258,7 @@ export const otherApps = [ availability: "Pinned table-based summary files B25034, B25035, B25103, B25077, and B08303; maintainer-generated housing-stock assets are bundled, not fetched at runtime.", officialUrl: "https://www.census.gov/programs-surveys/acs/data/summary-file.html", coverage: "Tract and county housing stock across the 50 states, DC, and Puerto Rico; separate county ranking inputs.", - noGuideReason: "The existing ACS guide starts from the Data API, not these pinned table-based Summary File artifacts.", + guideId: "census-acs-2024-table-summary", }, { name: "BLS Quarterly Census of Employment and Wages", @@ -257,7 +266,7 @@ export const otherApps = [ role: "County employment and wage context for Opportunity utility.", availability: "Pinned final 2024 and 2025 county high-level archives acquired by maintainers.", officialUrl: "https://www.bls.gov/cew/", - noGuideReason: "The BLS Public Data API guide covers a different access product; a QCEW archive guide is pending.", + guideId: "bls-qcew-county-high-level", }, { name: "FCC Broadband Data Collection", @@ -265,7 +274,7 @@ export const otherApps = [ role: "December 2025 terrestrial fixed 100/20 served share of broadband-serviceable locations for Opportunity utility.", availability: "Pinned county summary archive staged by maintainers; Location Fabric is denied and this is not population coverage.", officialUrl: "https://www.fcc.gov/BroadbandData", - noGuideReason: "The existing National Broadband Map guide uses the API, not the manually staged county summary archive.", + guideId: "fcc-bdc-county-fixed-summary", }, { name: "NOAA U.S. Climate Normals", @@ -273,7 +282,7 @@ export const otherApps = [ role: "1991–2020 annual and monthly in-county station climate values for optional filters.", availability: "Pinned v1.0.1 station archives acquired by maintainers; climate is null without a fully qualifying station.", officialUrl: "https://www.ncei.noaa.gov/products/land-based-station/us-climate-normals", - noGuideReason: "A Climate Normals station archive guide has not passed catalog review.", + guideId: "noaa-us-climate-normals-stations", }, { name: "Census TIGER/Line", @@ -291,7 +300,7 @@ export const otherApps = [ availability: "Pinned 1,645 reviewed 1-arc-second tiles; maintainer-only acquisition and no normal startup fetch.", officialUrl: "https://www.usgs.gov/3d-elevation-program", evidenceUrl: "https://github.com/hypertrial/househunter/blob/eea3dfffb5bd728afff4e63edda27959e7d86f97/config/mountain/source-lock-v2.json", - noGuideReason: "A 3DEP elevation-tile guide has not passed catalog review.", + guideId: "usgs-3dep-one-arc-second", }, { name: "USGS Protected Areas Database", @@ -300,7 +309,7 @@ export const otherApps = [ availability: "Pinned anonymous MapServer object inventory; maintainer-only capture.", officialUrl: "https://www.usgs.gov/programs/gap-analysis-project/science/pad-us-data-download", evidenceUrl: "https://github.com/hypertrial/househunter/blob/eea3dfffb5bd728afff4e63edda27959e7d86f97/config/mountain/source-lock-v2.json", - noGuideReason: "A PAD-US 4.1 layer guide has not passed catalog review.", + guideId: "usgs-pad-us-4-1", }, { name: "USGS National Transportation Database trails", @@ -309,7 +318,7 @@ export const otherApps = [ availability: "Pinned 51 state/DC GPKG extracts dated 2026-02-12; maintainer-only build input.", officialUrl: "https://www.usgs.gov/national-digital-trails/how-access-or-view-usgs-trails-dataset", evidenceUrl: "https://github.com/hypertrial/househunter/blob/eea3dfffb5bd728afff4e63edda27959e7d86f97/config/mountain/source-lock-v2.json", - noGuideReason: "A National Transportation Database trail-extract guide has not passed review.", + guideId: "usgs-national-trails-geopackage", }, { name: "Appalachian Regional Commission county list", @@ -318,7 +327,7 @@ export const otherApps = [ availability: "Reviewed 2026 county list packaged as a fixed FIPS reference.", officialUrl: "https://www.arc.gov/appalachian-counties-served-by-arc/", evidenceUrl: "https://github.com/hypertrial/househunter/blob/eea3dfffb5bd728afff4e63edda27959e7d86f97/config/ranking/appalachia-counties.json", - noGuideReason: "A guide for the ARC county list has not passed catalog review.", + guideId: "arc-appalachian-counties", }, { name: "State homeschool law references", @@ -339,7 +348,7 @@ export const otherApps = [ role: "Matches a user-entered address or fallback coordinates to its 2020 Census tract.", availability: "Called only on explicit lookup; a provider outage is not treated as an empty match.", officialUrl: "https://geocoding.geo.census.gov/geocoder/", - noGuideReason: "A Census Geocoder lookup guide has not passed catalog review.", + guideId: "census-geocoder", }, { name: "OpenStreetMap Nominatim", @@ -347,7 +356,7 @@ export const otherApps = [ role: "Fallback street search only when Census returns a valid empty address-match list; Census still supplies the tract ID.", availability: "Optional HTTPS endpoint, disableable by operator; approximate road matches require user confirmation.", officialUrl: "https://nominatim.openstreetmap.org/", - noGuideReason: "Nominatim address search is a different service from the existing OSM Overpass guide.", + guideId: "osm-nominatim-search", }, ], }, @@ -370,7 +379,7 @@ export const otherApps = [ officialUrl: "https://openrouteservice.org/", additionalUrls: [{ label: "Hosted optimization API", href: "https://api.heigit.org/vroom/v0/optimization" }], coverage: "Canada and United States within the hosted provider's route limits.", - noGuideReason: "A provider-specific directions and optimization guide has not passed catalog review.", + noGuideReason: "The hosted directions and VROOM responses are computed route services over OSM, not a separate source dataset; their free APIs require a key and no authorized key was available to verify a runnable exact-endpoint example. The local OSM extract has its own Geofabrik guide.", }, { name: "Photon", @@ -378,7 +387,7 @@ export const otherApps = [ role: "Place search and stop selection, with cached and deduplicated results.", availability: "Default hosted public demo service; usage limits and outages can interrupt search.", officialUrl: "https://photon.komoot.io/", - noGuideReason: "A Photon geocoding guide has not passed catalog review.", + guideId: "photon-geocoding", }, { name: "OpenStreetMap regional extracts via Geofabrik", @@ -389,7 +398,7 @@ export const otherApps = [ additionalUrls: [{ label: "OSM data and license", href: "https://www.openstreetmap.org/copyright" }], coverage: "PEI sample or Canada plus United States, depending on the selected extract profile.", evidenceUrl: "https://github.com/hypertrial/rockyroad/blob/5acf684a8de1ea0cdb85506ecda72dbe73e150b3/config/regions.yaml", - noGuideReason: "The existing OSM Overpass guide does not cover Geofabrik PBF extracts.", + guideId: "geofabrik-osm-extracts", }, ], }, @@ -427,7 +436,7 @@ export const otherApps = [ availability: "Optional network extra and explicit helper calls only; no archived-website feed.", officialUrl: "https://www.coingecko.com/en/api", evidenceUrl: "https://github.com/hypertrial/stacksats/blob/9ba73643c4478ddd92650557a90e91e64674f587/stacksats/data/btc_price_fetcher.py", - noGuideReason: "A CoinGecko price API guide has not passed catalog review.", + guideId: "coingecko-bitcoin-price", }, { name: "Coinbase", @@ -435,7 +444,7 @@ export const otherApps = [ role: "Fallback current BTC/USD spot quote for export helpers.", availability: "Optional network extra and explicit helper calls only; no archived-website feed.", officialUrl: "https://api.coinbase.com/v2/prices/BTC-USD/spot", - noGuideReason: "A Coinbase spot-price guide has not passed catalog review.", + guideId: "coinbase-bitcoin-spot-price", }, { name: "Bitstamp", @@ -443,7 +452,7 @@ export const otherApps = [ role: "Fallback current BTC/USD ticker price for export helpers.", availability: "Optional network extra and explicit helper calls only; no archived-website feed.", officialUrl: "https://www.bitstamp.net/api/", - noGuideReason: "A Bitstamp ticker guide has not passed catalog review.", + guideId: "bitstamp-bitcoin-ticker", }, { name: "Kraken", @@ -451,7 +460,7 @@ export const otherApps = [ role: "Fallback current BTC/USD ticker price for export helpers.", availability: "Optional network extra and explicit helper calls only; no archived-website feed.", officialUrl: "https://docs.kraken.com/api/docs/rest-api/get-ticker-information/", - noGuideReason: "A Kraken ticker guide has not passed catalog review.", + guideId: "kraken-bitcoin-ticker", }, { name: "Binance", @@ -459,7 +468,7 @@ export const otherApps = [ role: "Fallback current BTC/USDT price and historical kline lookup helper.", availability: "Optional network extra and explicit helper calls only; BTC/USDT is a proxy for USD, not the same quote.", officialUrl: "https://developers.binance.com/docs/binance-spot-api-docs/rest-api/market-data-endpoints", - noGuideReason: "A Binance market-data guide has not passed catalog review.", + guideId: "binance-bitcoin-ticker", }, ], }, diff --git a/src/content/apps/travelcanary.ts b/src/content/apps/travelcanary.ts index 7084191..578bd58 100644 --- a/src/content/apps/travelcanary.ts +++ b/src/content/apps/travelcanary.ts @@ -1,3 +1,5 @@ +import nationalWarningSystems from "./national-warning-systems.json"; + // Reviewed against TravelCanary's generated source inventory and its authored // source registries. This is a static editorial snapshot, not runtime health. export const travelCanary = { @@ -19,7 +21,7 @@ export const travelCanary = { availability: "Configured. Country and destination mappings vary; EDR recovery requires a token and does not add coverage independently.", coverage: "European member feeds; the country-by-country active and gated mappings are listed under National warnings.", officialUrl: "https://meteoalarm.org/", - noGuideReason: "No matching MeteoAlarm warning-feed guide is yet in the Data catalog.", + guideId: "meteoalarm-atom-warnings", }, { group: "Hazard and discovery feeds", @@ -35,7 +37,11 @@ export const travelCanary = { role: "Fire-danger forecasts and active-fire context; danger forecast does not confirm a fire.", availability: "Configured; active-fire detections and perimeters are complementary and do not establish official wildfire-warning coverage.", officialUrl: "https://forest-fire.emergency.copernicus.eu/", - noGuideReason: "No matching EFFIS fire-danger or active-fire guide is yet in the Data catalog.", + guideIds: [ + { id: "effis-fire-danger-forecast", label: "Fire danger forecast" }, + { id: "effis-active-fire-hotspots", label: "Active-fire hotspots" }, + { id: "effis-burned-area-perimeters", label: "Optional burned-area perimeters" }, + ], }, { group: "Hazard and discovery feeds", @@ -51,7 +57,7 @@ export const travelCanary = { role: "Complementary maps for wildfire, flood, industrial, and other emergency events.", availability: "Configured as non-blocking context; a Rapid Mapping activation is not current warning coverage.", officialUrl: "https://mapping.emergency.copernicus.eu/", - noGuideReason: "No matching Rapid Mapping activation guide is yet in the Data catalog.", + guideId: "copernicus-rapid-mapping-activations", }, { group: "Hazard and discovery feeds", @@ -67,7 +73,10 @@ export const travelCanary = { role: "Satellite flood corroboration.", availability: "Environment-gated and non-blocking; no official flood-warning coverage credit.", officialUrl: "https://global-flood.emergency.copernicus.eu/", - noGuideReason: "No matching Global Flood Monitoring guide is yet in the Data catalog.", + guideIds: [ + { id: "copernicus-gfm-flood-layers", label: "Satellite flood extent and quality" }, + { id: "copernicus-glofas-flood-outlook", label: "Optional GloFAS forecast targeting" }, + ], }, { group: "Hazard and discovery feeds", @@ -75,7 +84,7 @@ export const travelCanary = { role: "Preliminary earthquake fallback when primary USGS evidence is unavailable.", availability: "Configured as fallback; unmatched reports cannot replace ShakeMap intensity or establish monitoring coverage.", officialUrl: "https://www.seismicportal.eu/", - noGuideReason: "The USGS guide describes a different earthquake feed; an EMSC guide needs separate review.", + guideId: "emsc-earthquake-events", }, { group: "Hazard and discovery feeds", @@ -83,7 +92,7 @@ export const travelCanary = { role: "Official avalanche warnings for mapped Swiss bulletin regions.", availability: "Configured; limited to destinations intersecting reviewed bulletin geometry.", officialUrl: "https://www.slf.ch/en/avalanche-bulletin-and-snow-situation/", - noGuideReason: "No matching SLF bulletin guide is yet in the Data catalog.", + guideId: "slf-avalanche-bulletins", }, { group: "Hazard and discovery feeds", @@ -91,7 +100,7 @@ export const travelCanary = { role: "Official avalanche warnings for licensed, reviewed Alpine regions.", availability: "Configured only for mapped feed regions; additional region intersections remain gated pending bulletin verification.", officialUrl: "https://avalanche.report/", - noGuideReason: "No matching Avalanche.report bulletin guide is yet in the Data catalog.", + guideId: "avalanche-report-bulletins", }, { group: "Hazard and discovery feeds", @@ -99,7 +108,7 @@ export const travelCanary = { role: "Observed station pollutants and European AQI context.", availability: "Configured with partial monitoring only at mapped operational stations; modeled or gap-filled values cannot establish an all-clear.", officialUrl: "https://airindex.eea.europa.eu/", - noGuideReason: "No matching EEA station or AQI artifact guide is yet in the Data catalog.", + guideId: "eea-air-quality-index-stations", }, { group: "Hazard and discovery feeds", @@ -107,7 +116,7 @@ export const travelCanary = { role: "Corroborated civil-unrest and security news context.", availability: "Gated; requires three independently owned reviewed publishers and never establishes monitoring coverage.", officialUrl: "https://www.gdeltproject.org/", - noGuideReason: "No matching GDELT discovery-feed guide is yet in the Data catalog.", + noGuideReason: "The pinned GDELT Geo 2.0 API returned HTTP 404 for a bounded query on 2026-09-28; a runnable exact-feed example could not be verified.", }, { group: "Hazard and discovery feeds", @@ -115,7 +124,7 @@ export const travelCanary = { role: "Official French river-section flood warnings.", availability: "Configured; only destinations mapped to official river sections qualify.", officialUrl: "https://www.vigicrues.gouv.fr/", - noGuideReason: "No matching Vigicrues warning guide is yet in the Data catalog.", + guideId: "vigicrues-flood-vigilance-rss", }, { group: "Hazard and discovery feeds", @@ -123,7 +132,7 @@ export const travelCanary = { role: "Official Swiss flood-warning map sampled at destination geometry.", availability: "Configured for the mapped Swiss footprint; a warning-map pixel is not a local water-level measurement.", officialUrl: "https://www.hydrodaten.admin.ch/", - noGuideReason: "No matching FOEN warning-map guide is yet in the Data catalog.", + guideId: "foen-flood-warning-map", }, { group: "Hazard and discovery feeds", @@ -131,7 +140,7 @@ export const travelCanary = { role: "Official flood-warning stages at mapped hydrographic stations.", availability: "Configured; raw water levels do not score as warnings.", officialUrl: "https://ehyd.gv.at/", - noGuideReason: "No matching eHYD flood-stage guide is yet in the Data catalog.", + guideId: "ehyd-current-flood-stages", }, { group: "Hazard and discovery feeds", @@ -139,7 +148,7 @@ export const travelCanary = { role: "Recent wildfire and volcano event context.", availability: "Environment-gated, non-blocking, and not a local warning source.", officialUrl: "https://eonet.gsfc.nasa.gov/", - noGuideReason: "No matching NASA EONET guide is yet in the Data catalog.", + guideId: "nasa-eonet-events", }, { group: "Hazard and discovery feeds", @@ -147,7 +156,7 @@ export const travelCanary = { role: "Dekadal agricultural and ecosystem drought context.", availability: "Environment-gated; not an immediate emergency warning.", officialUrl: "https://drought.emergency.copernicus.eu/", - noGuideReason: "No matching EDO drought-indicator guide is yet in the Data catalog.", + guideId: "copernicus-edo-drought-indicator", }, { group: "Hazard and discovery feeds", @@ -155,17 +164,32 @@ export const travelCanary = { role: "Whole-country security and travel-advice context.", availability: "Environment-gated; the text does not imply sub-country warning geometry.", officialUrl: "https://www.gov.uk/foreign-travel-advice", - noGuideReason: "No matching FCDO advice guide is yet in the Data catalog.", + guideId: "fcdo-travel-advice", + }, + { + group: "Local conditions", + name: "Open-Meteo weather forecasts", + role: "Hourly modeled point-weather forecasts for local conditions.", + availability: "Configured but restricted to accepted noncommercial use and local-conditions activation; forecasts are not observations or warnings.", + officialUrl: "https://open-meteo.com/en/docs", + guideId: "open-meteo-weather-forecast", }, { group: "Local conditions", - name: "Open-Meteo forecasts and Copernicus CAMS", - role: "Hourly weather, modeled air-quality, dust and UV, plus nearby marine forecasts.", - availability: "Configured but restricted to accepted noncommercial use and local-conditions activation; forecasts are context, not observations or warnings.", - coverage: "Weather, air-quality, and marine products; marine applies only to reviewed coastal destinations.", - officialUrl: "https://open-meteo.com/", + name: "Open-Meteo air-quality forecasts and Copernicus CAMS", + role: "Modeled air-quality, dust, and UV context served by Open-Meteo using CAMS data.", + availability: "Configured but restricted to accepted noncommercial use and local-conditions activation; model values are not station observations.", + officialUrl: "https://open-meteo.com/en/docs/air-quality-api", additionalUrls: [{ label: "Copernicus Atmosphere Monitoring Service", href: "https://atmosphere.copernicus.eu/" }], - noGuideReason: "No matching Open-Meteo forecast guide is yet in the Data catalog; the CAMS model is accessed through Open-Meteo here.", + guideId: "open-meteo-air-quality", + }, + { + group: "Local conditions", + name: "Open-Meteo marine forecasts", + role: "Nearby offshore wave and marine forecasts for reviewed coastal destinations.", + availability: "Configured but restricted to accepted noncommercial use and local-conditions activation; unsupported coasts remain outside the mapped product.", + officialUrl: "https://open-meteo.com/en/docs/marine-weather-api", + guideId: "open-meteo-marine", }, { group: "Local conditions", @@ -183,7 +207,7 @@ export const travelCanary = { availability: "Configured when local conditions are activated; airport readings are not destination-wide weather conditions or aviation advice.", officialUrl: "https://aviationweather.gov/data/api/", additionalUrls: [{ label: "Aviation Weather Center", href: "https://aviationweather.gov/" }], - noGuideReason: "No matching Aviation Weather Center METAR or station-cache guide is yet in the Data catalog.", + guideId: "awc-metar-stations", }, { group: "Local conditions", @@ -191,7 +215,10 @@ export const travelCanary = { role: "Portuguese station observations and recent regional earthquake context.", availability: "Configured but restricted to accepted noncommercial use and local-conditions activation; measurements do not establish warning coverage.", officialUrl: "https://api.ipma.pt/", - noGuideReason: "No matching IPMA station or regional seismic guide is yet in the Data catalog.", + guideIds: [ + { id: "ipma-weather-station-observations", label: "Weather stations" }, + { id: "ipma-seismic-observations", label: "Regional earthquakes" }, + ], }, { group: "Local conditions", @@ -199,7 +226,7 @@ export const travelCanary = { role: "Candidate Spanish regional earthquake context.", availability: "Gated and not connected until RSS event time, corrections, and deletion lifecycle are verified.", officialUrl: "https://www.ign.es/web/social-rss", - noGuideReason: "Activation review is incomplete, so a matching guide is pending.", + guideId: "ign-spain-earthquake-rss", }, { group: "Local conditions", @@ -207,7 +234,7 @@ export const travelCanary = { role: "Provisional Slovenian river observations at reviewed stations.", availability: "Configured for local conditions; reference-level crossings are factual context, not official flood warnings.", officialUrl: "https://www.arso.gov.si/vode/podatki/hidro_podatki_xml.html", - noGuideReason: "No matching ARSO hydrology guide is yet in the Data catalog.", + guideId: "arso-current-hydrology", }, { group: "Local conditions", @@ -216,7 +243,7 @@ export const travelCanary = { availability: "Configured for local conditions; unchecked station data are not flood warnings.", officialUrl: "https://waterlevel.ie/page/api/", additionalUrls: [{ label: "OPW waterlevel.ie", href: "https://waterlevel.ie/" }], - noGuideReason: "No matching OPW water-level guide is yet in the Data catalog.", + guideId: "opw-ireland-water-levels", }, { group: "Local conditions", @@ -224,7 +251,7 @@ export const travelCanary = { role: "Dutch station water levels with quality-code and NAP-datum checks; pinned station metadata maps locations.", availability: "Configured for local conditions; observations are not flood warnings.", officialUrl: "https://rijkswaterstaatdata.nl/waterdata/", - noGuideReason: "No matching Rijkswaterstaat Waterdata guide is yet in the Data catalog.", + guideId: "rijkswaterstaat-current-water-levels", }, { group: "Local conditions", @@ -232,7 +259,7 @@ export const travelCanary = { role: "Candidate Belgian river-level observations.", availability: "Gated: reviewed live group yielded rainfall, while water-level groups, quality codes, mappings, and HIC access remain unapproved.", officialUrl: "https://www.waterinfo.vlaanderen.be/default.aspx?path=Public%2FOver+waterinfo%2FFAQ+open+data", - noGuideReason: "Activation and exact dataset review remain incomplete.", + noGuideReason: "Waterinfo says automated VMM requests require a dedicated token requested from the operator; no authorized water-level token or reviewed level group was available for an exact runnable example. The tested anonymous group contained rainfall, not this feed.", }, { group: "Local conditions", @@ -240,7 +267,7 @@ export const travelCanary = { role: "Candidate river and station observations.", availability: "Gated until exact station mappings and vertical-reference metadata are reviewed.", officialUrl: "https://api.meteo.lt/", - noGuideReason: "Activation and exact dataset review remain incomplete.", + guideId: "meteo-lt-hydrology-observations", }, { group: "Local conditions", @@ -248,7 +275,7 @@ export const travelCanary = { role: "Candidate hydrological station observations.", availability: "Gated pending OData fixture, quality flag, datum, and station-mapping review.", officialUrl: "https://www.syke.fi/en/environmental-data/open-web-services/environmental-data-apis", - noGuideReason: "Activation and exact dataset review remain incomplete.", + guideId: "syke-hydrology-water-levels", }, { group: "Local conditions", @@ -256,7 +283,7 @@ export const travelCanary = { role: "Candidate air-quality station observations.", availability: "Gated pending local-time, instrument-flag, and station-mapping review.", officialUrl: "https://www.airquality.dli.mlsi.gov.cy/", - noGuideReason: "Activation and exact dataset review remain incomplete.", + noGuideReason: "Cyprus publishes this feed under CC BY-SA, but its official all-stations JSON endpoints returned HTTP 403 to a bounded automated request on 2026-09-28; an exact runnable Python example could not be verified.", }, { group: "Local conditions", @@ -264,7 +291,7 @@ export const travelCanary = { role: "Candidate daily hydrological observations.", availability: "Gated pending timestamp, reuse, and station-area review; daily values cannot imply current flood warnings.", officialUrl: "https://info.meteo.bg/openData/", - noGuideReason: "Activation and exact dataset review remain incomplete.", + noGuideReason: "The official daily runoff CSV and Python access work, but NIMH's current open-data pages no longer expose the reuse conditions indexed in earlier copies; permitted analysis cannot be confirmed from a live source.", }, { group: "Local conditions", @@ -272,7 +299,7 @@ export const travelCanary = { role: "Current accident-associated road closures matched by official geometry.", availability: "Configured for local conditions; nearby context is not complete disruption coverage or route advice.", officialUrl: "https://www.digitraffic.fi/en/road-traffic/", - noGuideReason: "No matching Digitraffic traffic-announcement guide is yet in the Data catalog.", + guideId: "fintraffic-digitraffic-road-messages", }, { group: "Local conditions", @@ -280,7 +307,7 @@ export const travelCanary = { role: "Candidate Swedish water-shortage messages.", availability: "Gated until informational-message validity and reuse lifecycle fixtures pass review.", officialUrl: "https://opendata-download-warnings.smhi.se/ibww/api/version/1", - noGuideReason: "Activation and exact dataset review remain incomplete.", + guideId: "smhi-water-shortage-messages", }, { group: "Local conditions", @@ -288,7 +315,7 @@ export const travelCanary = { role: "Official Swedish infrastructure and crisis notices, reduced to fixed factual categories.", availability: "Configured for local conditions; regional notices do not prove a destination-wide interruption.", officialUrl: "https://www.krisinformation.se/", - noGuideReason: "No matching Krisinformation notice API guide is yet in the Data catalog.", + guideId: "krisinformation-news", }, { group: "Local conditions", @@ -296,7 +323,7 @@ export const travelCanary = { role: "Dutch serious road incidents and complete closures intersecting destinations.", availability: "Configured for local conditions; not route advice.", officialUrl: "https://opendata.ndw.nu/", - noGuideReason: "No matching NDW incident-feed guide is yet in the Data catalog.", + guideId: "ndw-road-closures", }, { group: "Local conditions", @@ -304,7 +331,7 @@ export const travelCanary = { role: "German motorway closures and warnings intersecting destinations.", availability: "Configured but restricted to accepted operator use and local-conditions activation; not complete transport monitoring.", officialUrl: "https://www.autobahn.de/", - noGuideReason: "No matching Autobahn traffic API guide is yet in the Data catalog.", + noGuideReason: "The operator's API portal requires an Autobahn employee ID; the community autobahn.api.bund.dev endpoint is not an operator-published reuse grant for the exact closure feed, so access and terms do not qualify.", }, { group: "Local conditions", @@ -312,7 +339,7 @@ export const travelCanary = { role: "Candidate current and scheduled power interruptions by district.", availability: "Gated: five public district pages exceeded the reviewed eight-second source budget.", officialUrl: "https://www.eac.com.cy/EN/RegulatedActivities/Distribution/PowerInterruptions/Pages/Faultsandscheduledinterruptions.aspx?District=0", - noGuideReason: "The product's source gate failed; an exact guide needs separate access review.", + noGuideReason: "The reviewed official district pages exceeded the product's eight-second source budget, and no official machine-readable outage contract or terms permitting automated analysis were verified for a runnable exact-feed guide.", }, { group: "Local conditions", @@ -320,7 +347,7 @@ export const travelCanary = { role: "Candidate Maltese current and planned electricity interruptions.", availability: "Gated: the official planned-outage response exceeded the approved 512 KiB limit.", officialUrl: "https://www.enemalta.com.mt/planned-power-cuts/", - noGuideReason: "The product's source gate failed; an exact guide needs separate access review.", + noGuideReason: "The official terms allow only personal, noncommercial reproduction of true copies and do not establish permission for transformed outage analysis; the planned-outage response also exceeded the product's 512 KiB gate.", }, { group: "Local conditions", @@ -328,7 +355,7 @@ export const travelCanary = { role: "Polish national electricity-use recommendations, not local outages.", availability: "Configured for local conditions; advice describes system-wide conditions only.", officialUrl: "https://www.energetycznykompas.pl/", - noGuideReason: "No matching PSE Energy Compass guide is yet in the Data catalog.", + guideId: "pse-energy-compass", }, { group: "Pinned inputs", @@ -337,7 +364,7 @@ export const travelCanary = { availability: "Pinned catalog input, not a live feed; regional matching areas are TravelCanary approximations.", officialUrl: "https://download.geonames.org/export/dump/", evidenceUrl: "https://github.com/hypertrial/travelcanary/blob/1ff2fdfa06b38880175a03aed10cfe60352bd0f6/data/review-inputs/europe-expansion-catalog.json", - noGuideReason: "No matching GeoNames dump guide is yet in the Data catalog.", + guideId: "geonames-daily-gazetteer", }, { group: "Pinned inputs", @@ -346,7 +373,7 @@ export const travelCanary = { availability: "Pinned geographic input; a regional polygon alone does not establish warning coverage.", officialUrl: "https://gisco-services.ec.europa.eu/distribution/v2/nuts/nuts-2024-files.html", evidenceUrl: "https://github.com/hypertrial/travelcanary/blob/1ff2fdfa06b38880175a03aed10cfe60352bd0f6/data/catalog-metadata.json", - noGuideReason: "The existing Eurostat statistics guide is a different product; no GISCO geometry guide is yet available.", + guideId: "eurostat-gisco-nuts-2024", }, { group: "Pinned inputs", @@ -355,7 +382,7 @@ export const travelCanary = { availability: "Pinned geographic review input; new region matches remain gated until bulletin and seasonal scope review.", officialUrl: "https://eaws.gitlab.io/eaws-regions/micro-regions.geojson", evidenceUrl: "https://github.com/hypertrial/travelcanary/blob/1ff2fdfa06b38880175a03aed10cfe60352bd0f6/data/review-inputs/eaws-expansion-review.json", - noGuideReason: "No matching EAWS regions guide is yet in the Data catalog.", + guideId: "eaws-avalanche-regions", }, { group: "Pinned inputs", @@ -378,7 +405,7 @@ export const travelCanary = { additionalUrls: [ { label: "Andorra weather alerts", href: "https://www.meteo.ad/en/Alerts" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.AD, }, { group: "National warnings", @@ -387,7 +414,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Institute of Geosciences (evidence-gated; official link/review only).", officialUrl: "https://geo.edu.al/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.AL, }, { group: "National warnings", @@ -396,7 +423,7 @@ export const travelCanary = { availability: "National civil-alert partition enabled; 1 active system listed.", details: "AT-Alert (active; national warning feed).", officialUrl: "https://warnung.at-alert.at/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.AT, }, { group: "National warnings", @@ -408,7 +435,7 @@ export const travelCanary = { additionalUrls: [ { label: "Federal Hydrometeorological Institute", href: "https://www.fhmzbih.gov.ba/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.BA, }, { group: "National warnings", @@ -417,7 +444,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "BE-Alert (evidence-gated; official link/review only).", officialUrl: "https://www.be-alert.be/en/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.BE, }, { group: "National warnings", @@ -426,7 +453,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "BG-ALERT (evidence-gated; official link/review only).", officialUrl: "https://bg-alert.bg/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.BG, }, { group: "National warnings", @@ -435,7 +462,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Belhydromet weather information (evidence-gated; official link/review only).", officialUrl: "https://pogoda.by/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.BY, }, { group: "National warnings", @@ -444,7 +471,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 blocked system listed.", details: "Alertswiss (blocked; official link/review only).", officialUrl: "https://www.alert.swiss/en/home.html", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.CH, }, { group: "National warnings", @@ -453,7 +480,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Cyprus public warning system (evidence-gated; official link/review only).", officialUrl: "https://www.gov.cy/moi/en/civil-defence/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.CY, }, { group: "National warnings", @@ -462,7 +489,7 @@ export const travelCanary = { availability: "National civil-alert partition enabled; 1 active system listed.", details: "CHMI hydrology and flash-flood risk (active; national warning feed).", officialUrl: "https://opendata.chmi.cz/hydrology/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.CZ, }, { group: "National warnings", @@ -475,7 +502,7 @@ export const travelCanary = { { label: "BBK civil-protection RSS", href: "https://www.bbk.bund.de/DE/Warnung-Vorsorge/Warn-App-NINA/warn-app-nina_node.html" }, { label: "DWD direct CAP recovery", href: "https://opendata.dwd.de/weather/alerts/cap/COMMUNEUNION_EVENT_STAT/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.DE, }, { group: "National warnings", @@ -484,7 +511,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "S!RENEN (evidence-gated; official link/review only).", officialUrl: "https://www.sirenen.dk/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.DK, }, { group: "National warnings", @@ -493,7 +520,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 blocked system listed.", details: "EE-ALARM (blocked; official link/review only).", officialUrl: "https://www.olevalmis.ee/en/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.EE, }, { group: "National warnings", @@ -505,7 +532,7 @@ export const travelCanary = { additionalUrls: [ { label: "AEMET direct CAP warnings", href: "https://www.aemet.es/es/rss_info/avisos/esp" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.ES, }, { group: "National warnings", @@ -517,7 +544,7 @@ export const travelCanary = { additionalUrls: [ { label: "FMI CAP warnings", href: "https://alerts.fmi.fi/cap/profile/current/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.FI, }, { group: "National warnings", @@ -529,7 +556,7 @@ export const travelCanary = { additionalUrls: [ { label: "Météo-France Vigilance API", href: "https://www.data.gouv.fr/dataservices/api-bulletin-vigilance" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.FR, }, { group: "National warnings", @@ -544,7 +571,7 @@ export const travelCanary = { { label: "National Severe Weather Warning Service", href: "https://www.metoffice.gov.uk/weather/warnings-and-advice/uk-warnings" }, { label: "Wales flood warnings", href: "https://naturalresources.wales/flooding/check-flood-warnings/?lang=en" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.GB, }, { group: "National warnings", @@ -553,7 +580,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "112 Greece (evidence-gated; official link/review only).", officialUrl: "https://civilprotection.gov.gr/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.GR, }, { group: "National warnings", @@ -565,7 +592,7 @@ export const travelCanary = { additionalUrls: [ { label: "DHMZ direct CAP warnings", href: "https://meteo.hr/proizvodi.php?section=podaci¶m=xml_korisnici" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.HR, }, { group: "National warnings", @@ -574,7 +601,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 blocked system listed.", details: "VÉSZ (blocked; official link/review only).", officialUrl: "https://www.katasztrofavedelem.hu/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.HU, }, { group: "National warnings", @@ -586,7 +613,7 @@ export const travelCanary = { additionalUrls: [ { label: "Met Eireann warnings", href: "https://www.met.ie/warnings-today.html" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.IE, }, { group: "National warnings", @@ -598,7 +625,7 @@ export const travelCanary = { additionalUrls: [ { label: "Icelandic Met Office", href: "https://en.vedur.is/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.IS, }, { group: "National warnings", @@ -611,7 +638,7 @@ export const travelCanary = { { label: "National hydrogeological and hydraulic bulletin", href: "https://mappe.protezionecivile.gov.it/it/mappe-rischi/bollettino-di-criticita/" }, { label: "Italian volcanic warnings and restrictions", href: "https://rischi.protezionecivile.gov.it/it/vulcanico/vulcani-italia/stromboli/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.IT, }, { group: "National warnings", @@ -620,7 +647,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Liechtenstein government information (evidence-gated; official link/review only).", officialUrl: "https://www.llv.li/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.LI, }, { group: "National warnings", @@ -629,7 +656,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "LT72 (evidence-gated; official link/review only).", officialUrl: "https://lt72.lt/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.LT, }, { group: "National warnings", @@ -638,7 +665,7 @@ export const travelCanary = { availability: "National civil-alert partition enabled; 1 active system listed.", details: "LU-Alert (active; national warning feed).", officialUrl: "https://data.public.lu/fr/datasets/alertes-du-systeme-lu-alert/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.LU, }, { group: "National warnings", @@ -650,7 +677,7 @@ export const travelCanary = { additionalUrls: [ { label: "LVĢMC hydrological warnings", href: "https://data.gov.lv/dati/dataset/hidrometeorologiskie-bridinajumi" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.LV, }, { group: "National warnings", @@ -659,7 +686,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Monaco government information (evidence-gated; official link/review only).", officialUrl: "https://www.gouv.mc/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.MC, }, { group: "National warnings", @@ -671,7 +698,7 @@ export const travelCanary = { additionalUrls: [ { label: "Moldova weather warnings", href: "https://www.meteo.md/index.php/ro/weather/current-warnings/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.MD, }, { group: "National warnings", @@ -683,7 +710,7 @@ export const travelCanary = { additionalUrls: [ { label: "Montenegro Hydrometeorological and Seismological Service", href: "https://www.meteo.co.me/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.ME, }, { group: "National warnings", @@ -695,7 +722,7 @@ export const travelCanary = { additionalUrls: [ { label: "North Macedonia Hydrometeorological Service", href: "https://uhmr.gov.mk/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.MK, }, { group: "National warnings", @@ -704,7 +731,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 blocked system listed.", details: "Malta public warning system (blocked; official link/review only).", officialUrl: "https://cps.gov.mt/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.MT, }, { group: "National warnings", @@ -713,7 +740,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "NL-Alert (evidence-gated; official link/review only).", officialUrl: "https://www.nl-alert.nl/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.NL, }, { group: "National warnings", @@ -727,7 +754,7 @@ export const travelCanary = { { label: "MeteoAlarm keyless Atom warning feed", href: "https://www.meteoalarm.org/" }, { label: "Varsom natural hazard warnings", href: "https://www.varsom.no/en/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.NO, }, { group: "National warnings", @@ -736,7 +763,7 @@ export const travelCanary = { availability: "National civil-alert partition enabled; 1 active system listed.", details: "IMGW hydrology warnings (active; national warning feed).", officialUrl: "https://hydro.imgw.pl/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.PL, }, { group: "National warnings", @@ -750,7 +777,7 @@ export const travelCanary = { { label: "Azores Civil Protection alerts", href: "https://www.prociv.azores.gov.pt/alertas/" }, { label: "ANEPC operational incidents", href: "https://prociv.gov.pt/pt/ocorrencias/" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.PT, }, { group: "National warnings", @@ -759,7 +786,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 blocked system listed.", details: "RO-ALERT (blocked; official link/review only).", officialUrl: "https://www.mai.gov.ro/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.RO, }, { group: "National warnings", @@ -771,7 +798,7 @@ export const travelCanary = { additionalUrls: [ { label: "Serbia hydrometeorological warnings", href: "https://www.hidmet.gov.rs/latin/upozorenja/index.php" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.RS, }, { group: "National warnings", @@ -783,7 +810,7 @@ export const travelCanary = { additionalUrls: [ { label: "SMHI direct warnings", href: "https://opendata-download-warnings.smhi.se/ibww/api/version/1" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.SE, }, { group: "National warnings", @@ -792,7 +819,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Slovenia public warning system (evidence-gated; official link/review only).", officialUrl: "https://www.gov.si/en/state-authorities/bodies-within-ministries/administration-for-civil-protection-and-disaster-relief/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.SI, }, { group: "National warnings", @@ -804,7 +831,7 @@ export const travelCanary = { additionalUrls: [ { label: "Crisis-management REST service", href: "https://portal.minv.sk/wps/esispz-api/docs/index.html" }, ], - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.SK, }, { group: "National warnings", @@ -813,7 +840,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "San Marino civil protection orders (evidence-gated; official link/review only).", officialUrl: "https://www.gov.sm/pub1/GovSM/Circolari-e-Ordinanze/Ordinanze-Protezione-Civile.html", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.SM, }, { group: "National warnings", @@ -822,7 +849,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Türkiye meteorological information (evidence-gated; official link/review only).", officialUrl: "https://www.mgm.gov.tr/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.TR, }, { group: "National warnings", @@ -831,7 +858,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Vatican City State information (evidence-gated; official link/review only).", officialUrl: "https://www.vaticanstate.va/en/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.VA, }, { group: "National warnings", @@ -840,7 +867,7 @@ export const travelCanary = { availability: "National civil-alert partition not enabled; 1 gated system listed.", details: "Kosovo Hydrometeorological Institute (evidence-gated; official link/review only).", officialUrl: "https://ihmk-rks.net/", - noGuideReason: "No matching national warning feed guide is yet in the Data catalog; each listed system has separate access and reuse terms.", + systems: nationalWarningSystems.countries.XK, }, ], } as const; diff --git a/src/lib/datasets.test.ts b/src/lib/datasets.test.ts index 3cc3263..2703361 100644 --- a/src/lib/datasets.test.ts +++ b/src/lib/datasets.test.ts @@ -88,14 +88,14 @@ describe("loadDatasets", () => { getAllDatasets().map((dataset) => [dataset.id, dataset.theme]), ); const groups = { - "Environment & Hazards": ["airnow-air-quality", "epa-airdata-daily-summaries", "epa-echo-drinking-water", "epa-toxics-release-inventory", "fema-national-flood-hazard-layer", "gdacs-disaster-alerts", "nasa-firms", "nasa-power-daily", "noaa-ibtracs", "noaa-swpc-space-weather", "nws-weather-api", "noaa-ncei-daily-summaries", "noaa-tides-currents", "openfema-disaster-declarations", "us-drought-monitor", "usgs-earthquakes", "usgs-water-data", "met-norway-locationforecast", "noaa-storm-events", "noaa-gml-co2", "nsidc-sea-ice-index", "noaa-ndbc-buoys", "epa-ghgrp", "fema-nfip-redacted-claims", "gfw-tree-cover-loss", "smithsonian-gvp-volcanoes", "copernicus-era5", "water-quality-portal", "openaq-air-quality", "vancouver-public-trees"], - "Government & Policy": ["congress-gov-legislation", "fec-campaign-finance", "federal-register-documents", "ofac-sdn-list", "open-states-legislation", "sam-gov-contract-opportunities", "usaspending-federal-awards", "legislation-gov-uk", "uk-police-street-crime", "fbi-crime-data-explorer", "nih-reporter-projects", "nsf-awards", "grants-gov-opportunities", "senate-lda-filings", "regulations-gov-dockets", "govinfo-uscourts", "medsl-county-returns", "un-sc-consolidated-list", "osha-enforcement", "eur-lex-cellar", "vancouver-311-service-requests", "vancouver-council-voting-records", "vancouver-parking-tickets"], - "Markets & Economics": ["bea-regional-gdp-income", "bitview-bitcoin-series", "bls-public-data-api", "census-international-trade", "cfpb-consumer-complaints", "eia-weekly-petroleum-status", "fhfa-house-price-index", "fred-economic-series", "hud-fair-market-rents", "imf-world-economic-outlook", "kalshi-market-data", "polymarket-markets", "sec-edgar-apis", "treasury-securities-auctions", "gleif-lei", "companies-house-uk", "fdic-bank-find", "cftc-commitment-of-traders", "census-county-business-patterns", "ecb-statistical-data-warehouse", "oecd-sdmx-statistics", "un-comtrade", "ilostat-labour-statistics", "irs-soi-tax-stats", "treasury-debt-to-the-penny", "hmda-loan-applications", "eia-weekly-natural-gas", "entsoe-transparency", "census-building-permits", "ember-electricity", "vancouver-business-licences", "vancouver-issued-building-permits", "vancouver-property-tax-report"], - "Health, Food & Safety": ["cdc-fluview-ilinet", "cdc-places", "clinicaltrials-studies", "cms-care-compare-hospitals", "cms-open-payments", "cpsc-product-recalls", "nhtsa-vehicle-recalls", "nppes-npi-registry", "openfda-drug-adverse-events", "openfda-food-enforcement", "usda-fooddata-central", "open-food-facts", "cms-nursing-homes", "cdc-social-vulnerability-index", "fda-orange-book", "nchs-provisional-mortality", "nhanes", "cdc-uscs-cancer-statistics", "nhtsa-fars", "openfda-device-events", "dailymed-drug-labels", "cdc-nwss-wastewater"], - "Geospatial & Infrastructure": ["bts-airline-on-time", "census-tiger-line", "eia-hourly-electric-grid", "fcc-national-broadband-map", "fhwa-national-bridge-inventory", "fta-ntd-monthly-ridership", "mobility-database-feeds", "natural-earth", "nrel-alt-fuel-stations", "overture-maps-places", "osm-overpass", "ourairports", "census-lehd-lodes", "ntsb-aviation-accidents", "vancouver-property-addresses", "vancouver-road-closures", "vancouver-zoning-districts"], + "Environment & Hazards": ["airnow-air-quality", "epa-airdata-daily-summaries", "epa-echo-drinking-water", "epa-toxics-release-inventory", "fema-national-flood-hazard-layer", "fema-national-risk-index", "gdacs-disaster-alerts", "nasa-firms", "nasa-power-daily", "noaa-ibtracs", "noaa-swpc-space-weather", "nws-weather-api", "noaa-ncei-daily-summaries", "noaa-tides-currents", "openfema-disaster-declarations", "us-drought-monitor", "usgs-earthquakes", "usgs-water-data", "met-norway-locationforecast", "noaa-storm-events", "noaa-gml-co2", "nsidc-sea-ice-index", "noaa-ndbc-buoys", "epa-ghgrp", "fema-nfip-redacted-claims", "gfw-tree-cover-loss", "smithsonian-gvp-volcanoes", "copernicus-era5", "water-quality-portal", "openaq-air-quality", "vancouver-public-trees", "open-meteo-weather-forecast", "open-meteo-air-quality", "open-meteo-marine", "opw-ireland-water-levels", "emsc-earthquake-events", "meteoalarm-atom-warnings", "england-flood-warnings", "met-norway-metalerts", "lhp-germany-flood-warnings", "ipma-weather-warnings", "awc-metar-stations", "dhmz-cap-warnings", "fmi-cap-warnings", "aemet-cap-warnings", "nve-flood-warnings", "met-eireann-warnings", "dpc-italy-flood-bulletins", "lu-alert-cap", "lvgmc-hydrometeorological-warnings", "krisinformation-vma", "at-alert-public-warnings", "chmi-current-hydrology", "chmi-flash-flood-risk", "dwd-cap-warnings", "imgw-current-hydrology", "imgw-hydrological-bulletins", "catalonia-civil-protection-plans", "nasa-eonet-events", "bc-unverified-hourly-pm25", "eccc-aqhi-observations", "wfigs-current-incidents", "wfigs-current-perimeters", "cwfif-active-wildland-fires", "cwfis-m3-perimeter-estimates", "ipma-weather-station-observations", "ipma-seismic-observations", "arso-current-hydrology", "vigicrues-flood-vigilance-rss", "slf-avalanche-bulletins", "avalanche-report-bulletins", "eea-air-quality-index-stations", "noaa-hrrr-smoke", "eccc-firework-smoke", "noaa-us-climate-normals-stations", "rijkswaterstaat-current-water-levels", "effis-fire-danger-forecast", "effis-active-fire-hotspots", "effis-burned-area-perimeters", "copernicus-rapid-mapping-activations", "copernicus-gfm-flood-layers", "copernicus-glofas-flood-outlook", "copernicus-edo-drought-indicator", "foen-flood-warning-map", "ehyd-current-flood-stages", "meteo-lt-hydrology-observations", "syke-hydrology-water-levels", "smhi-water-shortage-messages", "ign-spain-earthquake-rss"], + "Government & Policy": ["congress-gov-legislation", "fec-campaign-finance", "federal-register-documents", "ofac-sdn-list", "open-states-legislation", "sam-gov-contract-opportunities", "usaspending-federal-awards", "legislation-gov-uk", "uk-police-street-crime", "fbi-crime-data-explorer", "nih-reporter-projects", "nsf-awards", "grants-gov-opportunities", "senate-lda-filings", "regulations-gov-dockets", "govinfo-uscourts", "medsl-county-returns", "un-sc-consolidated-list", "osha-enforcement", "eur-lex-cellar", "vancouver-311-service-requests", "vancouver-council-voting-records", "vancouver-parking-tickets", "fcdo-travel-advice", "krisinformation-news", "fbi-cde-agency-summaries"], + "Markets & Economics": ["bea-regional-gdp-income", "bea-regional-price-parities", "bitview-bitcoin-series", "bls-public-data-api", "census-international-trade", "cfpb-consumer-complaints", "eia-weekly-petroleum-status", "fhfa-house-price-index", "fred-economic-series", "hud-fair-market-rents", "imf-world-economic-outlook", "kalshi-market-data", "polymarket-markets", "sec-edgar-apis", "treasury-securities-auctions", "treasury-yield-curve", "gleif-lei", "companies-house-uk", "fdic-bank-find", "cftc-commitment-of-traders", "census-county-business-patterns", "ecb-statistical-data-warehouse", "oecd-sdmx-statistics", "un-comtrade", "ilostat-labour-statistics", "irs-soi-tax-stats", "treasury-debt-to-the-penny", "hmda-loan-applications", "eia-weekly-natural-gas", "entsoe-transparency", "census-building-permits", "ember-electricity", "vancouver-business-licences", "vancouver-issued-building-permits", "vancouver-property-tax-report", "coingecko-bitcoin-price", "coinbase-bitcoin-spot-price", "bitstamp-bitcoin-ticker", "kraken-bitcoin-ticker", "binance-bitcoin-ticker", "bls-qcew-county-high-level"], + "Health, Food & Safety": ["cdc-fluview-ilinet", "cdc-places", "clinicaltrials-studies", "cms-care-compare-hospitals", "cms-open-payments", "cpsc-product-recalls", "nhtsa-vehicle-recalls", "nppes-npi-registry", "openfda-drug-adverse-events", "openfda-food-enforcement", "usda-fooddata-central", "open-food-facts", "cms-nursing-homes", "cdc-social-vulnerability-index", "fda-orange-book", "nchs-provisional-mortality", "nhanes", "cdc-uscs-cancer-statistics", "nhtsa-fars", "openfda-device-events", "dailymed-drug-labels", "cdc-nwss-wastewater", "chrr-community-conditions-2025", "chrr-mental-health-supplement-2025", "hrsa-ahrf-county", "epa-sdwis-bulk-submission"], + "Geospatial & Infrastructure": ["bts-airline-on-time", "census-tiger-line", "eia-hourly-electric-grid", "fcc-national-broadband-map", "fhwa-national-bridge-inventory", "fta-ntd-monthly-ridership", "geofabrik-osm-extracts", "mobility-database-feeds", "natural-earth", "nrel-alt-fuel-stations", "overture-maps-places", "osm-overpass", "ourairports", "census-lehd-lodes", "ntsb-aviation-accidents", "vancouver-property-addresses", "vancouver-road-closures", "vancouver-zoning-districts", "geonames-daily-gazetteer", "fintraffic-digitraffic-road-messages", "eurostat-gisco-nuts-2024", "census-geocoder", "osm-nominatim-search", "photon-geocoding", "ndw-road-closures", "eaws-avalanche-regions", "pse-energy-compass", "usgs-pad-us-4-1", "usgs-national-trails-geopackage", "usgs-3dep-one-arc-second", "epa-cws-service-areas-v2-1", "fcc-bdc-county-fixed-summary"], "Research & Reference": ["arxiv-preprints", "crossref-works", "gbif-species-occurrences", "openalex-scholarly-works", "pubmed-citations", "wikimedia-pageviews", "wikidata-query", "uspto-open-data-portal", "pubchem-compounds"], "Technology & Cybersecurity": ["cisa-known-exploited-vulnerabilities", "deps-dev-package-graph", "mitre-attack-enterprise", "nvd-cve", "osv-open-source-vulnerabilities", "first-epss", "openssf-scorecard", "github-archive", "chrome-ux-report", "certificate-transparency-crtsh", "ripe-stat"], - "Demographics & Development": ["acs-five-year-estimates", "college-scorecard", "eurostat-statistics", "nces-common-core-of-data", "unhcr-refugee-population", "usda-nass-quick-stats", "world-development-indicators", "onet-occupations", "worldpop-population", "who-gho-indicators", "faostat-food-agriculture", "ons-statistics", "statcan-web-data", "idmc-internal-displacement", "unesco-uis-statistics"], + "Demographics & Development": ["acs-five-year-estimates", "census-pep-county-totals", "arc-appalachian-counties", "census-acs-2024-table-summary", "college-scorecard", "eurostat-statistics", "nces-common-core-of-data", "unhcr-refugee-population", "usda-nass-quick-stats", "world-development-indicators", "onet-occupations", "worldpop-population", "who-gho-indicators", "faostat-food-agriculture", "ons-statistics", "statcan-web-data", "idmc-internal-displacement", "unesco-uis-statistics"], } as const; const grouped = Object.values(groups).flat(); expect([...Object.keys(themes)].sort()).toEqual([...grouped].sort()); diff --git a/src/lib/guide-validation.ts b/src/lib/guide-validation.ts index 3403c24..1cf9b05 100644 --- a/src/lib/guide-validation.ts +++ b/src/lib/guide-validation.ts @@ -232,17 +232,36 @@ const MULTI_LABEL_PUBLIC_SUFFIXES = new Set([ ]); const SOURCE_HOST_EXCEPTIONS: Partial> = { "certificate-transparency-crtsh": ["crt.sh"], + "bc-unverified-hourly-pm25": ["www.env.gov.bc.ca"], "chrome-ux-report": ["chromeuxreport.googleapis.com"], "college-scorecard": ["api.data.gov"], + "copernicus-gfm-flood-layers": ["geoserver.gfm.eodc.eu"], + "copernicus-rapid-mapping-activations": ["rapidmapping.emergency.copernicus.eu"], + "dpc-italy-flood-bulletins": ["api.github.com", "raw.githubusercontent.com"], + "eea-air-quality-index-stations": ["dis2datalake.blob.core.windows.net"], + "effis-active-fire-hotspots": ["maps.effis.emergency.copernicus.eu"], + "effis-burned-area-perimeters": ["maps.effis.emergency.copernicus.eu"], + "effis-fire-danger-forecast": ["maps.effis.emergency.copernicus.eu"], + "eccc-firework-smoke": ["geo.weather.gc.ca"], + "epa-cws-service-areas-v2-1": ["media.githubusercontent.com"], + "noaa-hrrr-smoke": ["nomads.ncep.noaa.gov"], "fbi-crime-data-explorer": ["api.usa.gov"], + "foen-flood-warning-map": ["wms.geo.admin.ch"], "hmda-loan-applications": ["ffiec.cfpb.gov"], "medsl-county-returns": ["dataverse.harvard.edu"], "mitre-attack-enterprise": ["raw.githubusercontent.com"], "nhtsa-fars": ["crashviewer.nhtsa.dot.gov"], + "osm-nominatim-search": ["nominatim.openstreetmap.org"], + "syke-hydrology-water-levels": ["rajapinnat.ymparisto.fi"], + "usgs-national-trails-geopackage": ["prd-tnm.s3.amazonaws.com"], + "usgs-3dep-one-arc-second": ["prd-tnm.s3.amazonaws.com"], + "rijkswaterstaat-current-water-levels": ["ddapi20-waterwebservices.rijkswaterstaat.nl"], "overture-maps-places": ["overturemapswestus2.blob.core.windows.net"], "regulations-gov-dockets": ["api.regulations.gov"], "sam-gov-contract-opportunities": ["api.sam.gov"], "un-comtrade": ["comtradeplus.un.org"], + "wfigs-current-incidents": ["services3.arcgis.com"], + "wfigs-current-perimeters": ["services3.arcgis.com"], }; function words(value: string): string[] { diff --git a/src/lib/url-validation.ts b/src/lib/url-validation.ts index a049e33..2b5f492 100644 --- a/src/lib/url-validation.ts +++ b/src/lib/url-validation.ts @@ -47,6 +47,74 @@ type UrlStatusException = { }; const STATUS_EXCEPTIONS = new Map([ + [ + "https://www.bls.gov/cew/downloadable-data-files.htm", + { + statuses: [403], + reason: "BLS blocks automated documentation requests; the official 2025 county high-level ZIP responded with a valid ranged ZIP header on 2026-09-28", + expires: "2026-11-12", + }, + ], + [ + "https://www.bls.gov/bls/linksite.htm", + { + statuses: [200, 403], + reason: "BLS serves its public-domain notice as an access-denied page to automated checks; official text was independently reviewed 2026-09-28", + expires: "2026-11-12", + skipIdentity: true, + }, + ], + [ + "https://ucr.fbi.gov/data_quality_guidelines", + { + statuses: [403], + reason: "FBI bot-protects its UCR public-domain guidance from automated validation; official text was independently reviewed 2026-09-28", + expires: "2026-11-12", + }, + ], + [ + "https://help.bdc.fcc.gov/hc/en-us/articles/10467446103579-How-to-Use-the-FCC-s-National-Broadband-Map", + { + statuses: [403], + reason: "FCC help pages block automated validation here; the official download instructions and exact December 2025 ZIP were independently reviewed 2026-09-28", + expires: "2026-11-12", + }, + ], + [ + "https://avalanche.report/more/open-data", + { + statuses: [200], + reason: "Avalanche.report serves a JavaScript shell to automated checks; official CC BY page independently reviewed 2026-09-28", + expires: "2026-11-12", + skipIdentity: true, + }, + ], + [ + "https://www.coinbase.com/legal/market_data", + { + statuses: [403], + reason: "Coinbase bot-protects its market-data terms; official page independently reviewed 2026-09-28", + expires: "2026-11-12", + }, + ], + [ + "https://www.bitstamp.net/api/", + { + statuses: [200], + reason: "Bitstamp API and commercial-data terms exceed the 1 MB validation cap; official page independently reviewed 2026-09-28", + expires: "2026-11-12", + skipIdentity: true, + }, + ], + [ + "https://www.binance.com/en/terms", + { + statuses: [202], + reason: "Binance serves an empty bot-challenge response to automated validation; official terms independently reviewed 2026-09-28", + expires: "2026-11-12", + skipIdentity: true, + }, + ], [ "https://kalshi.com/developer-agreement", {