From 604bcb1878213142256332da3e0d37bb7c49da45 Mon Sep 17 00:00:00 2001 From: Lilleman auf Larv Date: Fri, 18 Sep 2026 23:10:05 +0200 Subject: [PATCH] Read misc.timezone from tzdb and misc.useragent from top-user-agents, and give misc.car its own rows file --- CHANGELOG.md | 8 + DATA-LICENSES.md | 3 + README.md | 23 ++- data-import/timezone.py | 105 ++++++++++ data-import/useragent.py | 55 ++++++ data/misc/car.json | 11 +- data/misc/car.tsv | 33 ++++ data/misc/timezone.json | 2 +- data/misc/timezone.tsv | 402 +++++++++++++++++++++++++++++++++++++++ data/misc/useragent.json | 2 +- data/misc/useragent.tsv | 97 ++++++++++ todo.md | 4 +- 12 files changed, 725 insertions(+), 20 deletions(-) create mode 100644 data-import/timezone.py create mode 100644 data-import/useragent.py create mode 100644 data/misc/car.tsv create mode 100644 data/misc/timezone.tsv create mode 100644 data/misc/useragent.tsv diff --git a/CHANGELOG.md b/CHANGELOG.md index 7815d75..fcc3113 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,14 @@ replacement, and each removed path, column or flag. code the IANA registry lists with a plain reason phrase; and `misc.mimetype` each type mime-db records as IANA-registered and gives a filename extension. `DATA-LICENSES.md` lists each source. +- `misc.timezone`, `misc.car` and `misc.useragent` are tables too. `misc.timezone` + is tzdb `zone.tab`'s zone for each shipped territory, with `offset` holding the + zone's standard UTC offset and `territory` linking to `misc.territory`, so + `misc.territory[SE].timezone` draws `Europe/Stockholm`; zones of a territory + `misc.territory` does not ship, Antarctica's among them, and the constant `UTC` + are gone. `misc.useragent` is the top-user-agents desktop and mobile lists with + `browser`, `device` and `os` columns. `misc.car` keeps its makes and models, with + `misc.car.maker` renamed `misc.car.make`. - `geo.SE` and `geo.US`: five linked tables per country, `region`, `municipality`, `locality`, `postal-code` and `street`, weighted by population and address counts and built from SCB, GeoNames, Trafikverket NVDB and the US Census Bureau, and an diff --git a/DATA-LICENSES.md b/DATA-LICENSES.md index 1a43fb0..64ac814 100644 --- a/DATA-LICENSES.md +++ b/DATA-LICENSES.md @@ -14,11 +14,14 @@ Every shipped dataset, its source, its licence and the attribution it asks for. | `sv_SE/first-name.tsv`, `last-name.tsv` | [SCB](https://www.scb.se/) names with at least two bearers, 31 December 2022 | CC0 1.0 | "Källa: SCB" | `data-import/names-se.py` | | `en_US/first-name.tsv` | [SSA](https://www.ssa.gov/oact/babynames/) baby names, births 1930 to 2020, through [hackerb9/ssa-baby-names](https://github.com/hackerb9/ssa-baby-names) | public domain | none required | `data-import/names-us.py` | | `en_US/last-name.tsv` | Census Bureau surnames occurring 100 or more times, 2010 | public domain | none required | `data-import/names-us.py` | +| `misc/car.tsv` | curated makes and models, pending an international source (goal 10) | — | — | — | | `sv_SE/sex.tsv`, `sv_SE/birth-number.tsv`, `sv_SE/title.tsv`, `en_US/sex.tsv`, `en_US/title.tsv` | curated (Skatteverket's test birth numbers are facts) | — | — | — | | `misc/territory.tsv` | [datasets/country-codes](https://github.com/datasets/country-codes) | [PDDL 1.0](https://opendatacommons.org/licenses/pddl/1-0/) | none required | `data-import/territory.py` | | `misc/currency.tsv` | [datasets/currency-codes](https://github.com/datasets/currency-codes); symbols from [Unicode CLDR](https://github.com/unicode-org/cldr) `en.xml` and `root.xml` | PDDL 1.0; [Unicode License v3](https://www.unicode.org/license.txt) | CLDR: "Copyright © 1991-2025 Unicode, Inc. Unicode and the Unicode Logo are registered trademarks of Unicode, Inc. in the United States and other countries." | `data-import/currency.py` | | `misc/httpstatus.tsv` | [IANA HTTP Status Code Registry](https://www.iana.org/assignments/http-status-codes/) | [public domain](https://www.iana.org/help/licensing-terms) | none required | `data-import/httpstatus.py` | | `misc/language.tsv` | [datasets/language-codes](https://github.com/datasets/language-codes), the [Library of Congress](https://www.loc.gov/standards/iso639-2/) ISO 639-2 register | [PDDL 1.0](https://opendatacommons.org/licenses/pddl/1-0/) | none required | `data-import/language.py` | | `misc/mimetype.tsv` | [mime-db](https://github.com/jshttp/mime-db), the IANA media type registry with filename extensions | [MIT](https://github.com/jshttp/mime-db/blob/master/LICENSE) | "Copyright (c) 2014 Jonathan Ong, Copyright (c) 2015-2022 Douglas Christopher Wilson" | `data-import/mimetype.py` | +| `misc/timezone.tsv` | [IANA tzdb](https://www.iana.org/time-zones) `zone.tab` and the standard offset of each zone | [public domain](https://data.iana.org/time-zones/tzdb/LICENSE) | none required | `data-import/timezone.py` | +| `misc/useragent.tsv` | [top-user-agents](https://github.com/microlinkhq/top-user-agents) desktop and mobile lists | [MIT](https://github.com/microlinkhq/top-user-agents/blob/master/LICENSE.md) | "Copyright © 2020 Kiko Beats" | `data-import/useragent.py` | Every other category is hand-written JSON under [`data/`](data), MIT like the code. diff --git a/README.md b/README.md index e532d17..9f940c6 100644 --- a/README.md +++ b/README.md @@ -165,11 +165,19 @@ carries `car`, `coordinate`, `creditcard` (Luhn-valid), `currency` (ISO 4217), `datetime` (RFC 3339), `emoji`, `httpstatus`, `language` (ISO 639-1, with its 639-2/T code), `mac`, `mimetype`, `objectid`, `territory` (ISO 3166-1), `timezone` (IANA), `useragent` and `uuid` (v4). Many carry sub-fields — `misc.currency.symbol`, -`misc.territory.alpha2`, `misc.httpstatus.code` — which `--list` shows. `currency`, -`httpstatus`, `language`, `mimetype` and `territory` are [tables](#table), so -`misc.territory[SE].capital` and `misc.currency[Euro].symbol` select a row; +`misc.territory.alpha2`, `misc.httpstatus.code` — which `--list` shows. `car`, +`currency`, `httpstatus`, `language`, `mimetype`, `territory`, `timezone` and +`useragent` are [tables](#table), so `misc.territory[SE].capital` and +`misc.currency[Euro].symbol` select a row; [`DATA-LICENSES.md`](DATA-LICENSES.md) names each table's source and licence. +`misc.timezone` is tzdb's zone for a territory, with the territory's code and the +zone's standard offset — not the offset in force on any given date, which a zone +name is what you store precisely to avoid. It links to `misc.territory`, so +`misc.territory[SE].timezone` is `Europe/Stockholm` and a drawn territory and zone +agree. `misc.useragent` carries `browser`, `device` and `os` beside the string, and +`misc.car` a `make` and a `model`. + ISO 3166-1 codes territories, not sovereign states, so that is what the table is called: Greenland and Åland have codes of their own, and `misc.territory.country` names the state each belongs to — `DK` for Greenland, `FI` for Åland, and its own @@ -1153,7 +1161,8 @@ App developers writing tests and fixtures, in Go and at a shell: import drops the child rows whose territory the set does not ship — 17 of `misc.timezone`'s, Antarctica's ten among them. Agreement across a record is worth more than the last rows of a table. Where no such link can hold the fact - stays a column. + stays a column. Layer your own `misc.territory` over the shipped one and you + must layer `misc.timezone` too, or the link fails at load naming the row. - **`misc.territory` names its sovereign in a column, and there is no `misc.country` table.** ISO 3166-1 codes territories, so `territory` is the honest name, and `is_independent` in the register gives each one's state. A second table of the 195 @@ -1248,15 +1257,17 @@ and `names-us.py` rejects a client for a while after a burst, so `--surnames` ta a copy of the surname file: ```sh -docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/territory.py docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/currency.py -docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/geo-us.py docker compose run --rm --user "$(id -u):$(id -g)" -e TRAFIKVERKET_API_KEY data-import data-import/geo-se.py +docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/geo-us.py docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/httpstatus.py docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/language.py docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/mimetype.py docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/names-se.py docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/names-us.py +docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/territory.py +docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/timezone.py +docker compose run --rm --user "$(id -u):$(id -g)" data-import data-import/useragent.py ``` To release, head `CHANGELOG.md` with the version's section in place of `Unreleased` diff --git a/data-import/timezone.py b/data-import/timezone.py new file mode 100644 index 0000000..868046f --- /dev/null +++ b/data-import/timezone.py @@ -0,0 +1,105 @@ +#!/usr/bin/env python3 +"""Rebuild data/misc/timezone.tsv from the IANA tzdb tarball (public domain). + + data-import/timezone.py [--source URL_OR_FILE] [--cache DIR] [--out FILE] [--territories FILE] + +zone.tab names one zone per territory, so Europe/Stockholm ships where zone1970.tab +would spell Sweden Europe/Berlin. The offset is the zone's standard offset, the first +field of its Zone rule's last continuation line, with a Link resolved to its target. +""" +import argparse +import csv +import io +import re +import sys +import tarfile +from pathlib import Path + +import source +import tsv + +SOURCE = "https://data.iana.org/time-zones/tzdata-latest.tar.gz" +OUT = Path(__file__).resolve().parent.parent / "data" / "misc" / "timezone.tsv" +TERRITORIES = Path(__file__).resolve().parent.parent / "data" / "misc" / "territory.tsv" +CACHE = Path(__file__).resolve().parent / "cache" +COLUMNS = ["offset", "territory", "zone"] +REGIONS = ["africa", "antarctica", "asia", "australasia", "backward", "etcetera", "europe", "northamerica", "southamerica"] + + +def offsets(tar): + """Every zone's standard offset, and every link's target.""" + std, links = {}, {} + for name in REGIONS: + zone = None + for raw in tar.extractfile(name).read().decode("utf-8").splitlines(): + line = raw.split("#")[0].rstrip() + if not line.strip(): + continue + if line.startswith("Zone"): + f = line.split() + zone, std[f[1]] = f[1], f[2] + elif line.startswith("Link"): + f = line.split() + links[f[2]], zone = f[1], None + elif line[0] in " \t" and zone: + std[zone] = line.split()[0] + else: + zone = None + return std, links + + +def resolve(zone, std, links): + for _ in range(10): + if zone in std: + return std[zone] + if zone not in links: + return None + zone = links[zone] + return None + + +def utc_offset(raw): + """±HH:MM from a tzdb STDOFF field; a zone still off by seconds is not one we can spell.""" + m = re.match(r"^(-)?(\d{1,2}):(\d{2})(?::(\d{2}))?$", raw) + if not m or (m.group(4) or "00") != "00": + return None + return f"{'-' if m.group(1) else '+'}{int(m.group(2)):02d}:{m.group(3)}" + + +def rows(tar, territories): + std, links = offsets(tar) + for line in tar.extractfile("zone.tab").read().decode("utf-8").splitlines(): + if line.startswith("#") or not line.strip(): + continue + territory, _, zone = line.split("\t")[:3] + if territory not in territories: + continue + raw = resolve(zone, std, links) + if raw is None: + sys.exit(f"{zone}: the tarball gives it no Zone rule and no Link to one") + offset = utc_offset(raw) + if offset is None: + sys.exit(f"{zone}: standard offset {raw!r} is not a whole number of minutes") + yield {"offset": offset, "territory": territory, "zone": zone} + + +def main(): + p = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + p.add_argument("--cache", default=str(CACHE)) + p.add_argument("--source", default=SOURCE) + p.add_argument("--out", default=str(OUT)) + p.add_argument("--territories", default=str(TERRITORIES)) + a = p.parse_args() + shipped = {r["alpha2"] for r in csv.DictReader(io.StringIO(Path(a.territories).read_text(encoding="utf-8")), delimiter="\t")} + body = source.fetch(a.source, a.cache, "tzdata-latest.tar.gz", magic=b"\x1f\x8b") + with tarfile.open(fileobj=io.BytesIO(body)) as tar: + table = sorted(rows(tar, shipped), key=lambda r: r["zone"]) + print(f"tzdb {tar.extractfile('version').read().decode('utf-8').strip()}", file=sys.stderr) + linked = {r["territory"] for r in table} + if missing := shipped - linked: + sys.exit(f"no zone for {sorted(missing)}; a parent row without a child is a load error") + tsv.write(a.out, COLUMNS, table) + + +if __name__ == "__main__": + main() diff --git a/data-import/useragent.py b/data-import/useragent.py new file mode 100644 index 0000000..9dddd94 --- /dev/null +++ b/data-import/useragent.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python3 +"""Rebuild data/misc/useragent.tsv from microlinkhq/top-user-agents (MIT). + + data-import/useragent.py [--source URL] [--cache DIR] [--out FILE] + +The desktop and mobile lists partition the whole, so `device` is read rather than +parsed. A row ships when the string names a browser and an operating system both. +""" +import argparse +import json +import re +from pathlib import Path + +import source +import tsv + +SOURCE = "https://raw.githubusercontent.com/microlinkhq/top-user-agents/master/src" +OUT = Path(__file__).resolve().parent.parent / "data" / "misc" / "useragent.tsv" +CACHE = Path(__file__).resolve().parent / "cache" +COLUMNS = ["browser", "device", "os", "ua"] +# First match wins: Edge, Opera and Samsung Internet all carry Chrome's token too, +# and an iPhone says "like Mac OS X". +BROWSERS = [("Edge", r"Edg(iOS)?/"), ("Opera", r"OPR/"), ("Samsung Internet", r"SamsungBrowser/"), + ("Chrome", r"(Chrome|CriOS)/"), ("Firefox", r"(Firefox|FxiOS)/"), ("Safari", r"Version/[\d.]+ .*Safari")] +SYSTEMS = [("iOS", r"iPhone|iPad|CPU OS "), ("Android", r"Android"), ("ChromeOS", r"CrOS"), + ("Windows", r"Windows NT"), ("macOS", r"Macintosh|Mac OS X"), ("Linux", r"X11.*Linux|Ubuntu")] + + +def named(table, ua): + for name, pattern in table: + if re.search(pattern, ua): + return name + return "" + + +def rows(desktop, mobile): + for device, uas in (("desktop", desktop), ("mobile", mobile)): + for ua in uas: + browser, os = named(BROWSERS, ua), named(SYSTEMS, ua) + if browser and os: + yield {"browser": browser, "device": device, "os": os, "ua": ua} + + +def main(): + p = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + p.add_argument("--cache", default=str(CACHE)) + p.add_argument("--source", default=SOURCE) + p.add_argument("--out", default=str(OUT)) + a = p.parse_args() + lists = [json.loads(source.fetch(f"{a.source}/{n}.json", a.cache, f"top-user-agents-{n}.json")) for n in ("desktop", "mobile")] + tsv.write(a.out, COLUMNS, sorted(rows(*lists), key=lambda r: (r["browser"], r["os"], r["ua"]))) + + +if __name__ == "__main__": + main() diff --git a/data/misc/car.json b/data/misc/car.json index 91886c6..d7a4a61 100644 --- a/data/misc/car.json +++ b/data/misc/car.json @@ -1,10 +1 @@ -[ - { "format": "{maker} {model}", "maker": "BMW", "model": ["3 Series", "5 Series", "X3", "X5"] }, - { "format": "{maker} {model}", "maker": "Ford", "model": ["Fiesta", "Focus", "Mustang", "Explorer"] }, - { "format": "{maker} {model}", "maker": "Honda", "model": ["Civic", "Accord", "CR-V", "Jazz"] }, - { "format": "{maker} {model}", "maker": "Mercedes-Benz", "model": ["A-Class", "C-Class", "E-Class", "GLC"] }, - { "format": "{maker} {model}", "maker": "Tesla", "model": ["Model 3", "Model S", "Model X", "Model Y"] }, - { "format": "{maker} {model}", "maker": "Toyota", "model": ["Corolla", "Camry", "RAV4", "Yaris"] }, - { "format": "{maker} {model}", "maker": "Volkswagen", "model": ["Golf", "Passat", "Polo", "Tiguan"] }, - { "format": "{maker} {model}", "maker": "Volvo", "model": ["XC40", "XC60", "XC90", "V60"] } -] +{ "format": "{make} {model}", "rows": "car.tsv" } diff --git a/data/misc/car.tsv b/data/misc/car.tsv new file mode 100644 index 0000000..9ddd75a --- /dev/null +++ b/data/misc/car.tsv @@ -0,0 +1,33 @@ +make model +BMW 3 Series +BMW 5 Series +BMW X3 +BMW X5 +Ford Explorer +Ford Fiesta +Ford Focus +Ford Mustang +Honda Accord +Honda CR-V +Honda Civic +Honda Jazz +Mercedes-Benz A-Class +Mercedes-Benz C-Class +Mercedes-Benz E-Class +Mercedes-Benz GLC +Tesla Model 3 +Tesla Model S +Tesla Model X +Tesla Model Y +Toyota Camry +Toyota Corolla +Toyota RAV4 +Toyota Yaris +Volkswagen Golf +Volkswagen Passat +Volkswagen Polo +Volkswagen Tiguan +Volvo V60 +Volvo XC40 +Volvo XC60 +Volvo XC90 diff --git a/data/misc/timezone.json b/data/misc/timezone.json index 5c14f62..6ed5e83 100644 --- a/data/misc/timezone.json +++ b/data/misc/timezone.json @@ -1 +1 @@ -["UTC", "Africa/Cairo", "Africa/Johannesburg", "America/Chicago", "America/Denver", "America/Los_Angeles", "America/Mexico_City", "America/New_York", "America/Sao_Paulo", "America/Toronto", "Asia/Dubai", "Asia/Hong_Kong", "Asia/Kolkata", "Asia/Shanghai", "Asia/Singapore", "Asia/Tokyo", "Australia/Sydney", "Europe/Amsterdam", "Europe/Berlin", "Europe/London", "Europe/Madrid", "Europe/Moscow", "Europe/Oslo", "Europe/Paris", "Europe/Stockholm", "Europe/Warsaw", "Pacific/Auckland"] +{ "format": "{zone}", "rows": "timezone.tsv", "key": "zone", "parent": "territory" } diff --git a/data/misc/timezone.tsv b/data/misc/timezone.tsv new file mode 100644 index 0000000..a5288ac --- /dev/null +++ b/data/misc/timezone.tsv @@ -0,0 +1,402 @@ +offset territory zone ++00:00 CI Africa/Abidjan ++00:00 GH Africa/Accra ++03:00 ET Africa/Addis_Ababa ++01:00 DZ Africa/Algiers ++03:00 ER Africa/Asmara ++00:00 ML Africa/Bamako ++01:00 CF Africa/Bangui ++00:00 GM Africa/Banjul ++00:00 GW Africa/Bissau ++02:00 MW Africa/Blantyre ++01:00 CG Africa/Brazzaville ++02:00 BI Africa/Bujumbura ++02:00 EG Africa/Cairo ++00:00 MA Africa/Casablanca ++01:00 ES Africa/Ceuta ++00:00 GN Africa/Conakry ++00:00 SN Africa/Dakar ++03:00 TZ Africa/Dar_es_Salaam ++03:00 DJ Africa/Djibouti ++01:00 CM Africa/Douala ++00:00 EH Africa/El_Aaiun ++00:00 SL Africa/Freetown ++02:00 BW Africa/Gaborone ++02:00 ZW Africa/Harare ++02:00 ZA Africa/Johannesburg ++02:00 SS Africa/Juba ++03:00 UG Africa/Kampala ++02:00 SD Africa/Khartoum ++02:00 RW Africa/Kigali ++01:00 CD Africa/Kinshasa ++01:00 NG Africa/Lagos ++01:00 GA Africa/Libreville ++00:00 TG Africa/Lome ++01:00 AO Africa/Luanda ++02:00 CD Africa/Lubumbashi ++02:00 ZM Africa/Lusaka ++01:00 GQ Africa/Malabo ++02:00 MZ Africa/Maputo ++02:00 LS Africa/Maseru ++02:00 SZ Africa/Mbabane ++03:00 SO Africa/Mogadishu ++00:00 LR Africa/Monrovia ++03:00 KE Africa/Nairobi ++01:00 TD Africa/Ndjamena ++01:00 NE Africa/Niamey ++00:00 MR Africa/Nouakchott ++00:00 BF Africa/Ouagadougou ++01:00 BJ Africa/Porto-Novo ++00:00 ST Africa/Sao_Tome ++02:00 LY Africa/Tripoli ++01:00 TN Africa/Tunis ++02:00 NA Africa/Windhoek +-10:00 US America/Adak +-09:00 US America/Anchorage +-04:00 AI America/Anguilla +-04:00 AG America/Antigua +-03:00 BR America/Araguaina +-03:00 AR America/Argentina/Buenos_Aires +-03:00 AR America/Argentina/Catamarca +-03:00 AR America/Argentina/Cordoba +-03:00 AR America/Argentina/Jujuy +-03:00 AR America/Argentina/La_Rioja +-03:00 AR America/Argentina/Mendoza +-03:00 AR America/Argentina/Rio_Gallegos +-03:00 AR America/Argentina/Salta +-03:00 AR America/Argentina/San_Juan +-03:00 AR America/Argentina/San_Luis +-03:00 AR America/Argentina/Tucuman +-03:00 AR America/Argentina/Ushuaia +-04:00 AW America/Aruba +-03:00 PY America/Asuncion +-05:00 CA America/Atikokan +-03:00 BR America/Bahia +-06:00 MX America/Bahia_Banderas +-04:00 BB America/Barbados +-03:00 BR America/Belem +-06:00 BZ America/Belize +-04:00 CA America/Blanc-Sablon +-04:00 BR America/Boa_Vista +-05:00 CO America/Bogota +-07:00 US America/Boise +-07:00 CA America/Cambridge_Bay +-04:00 BR America/Campo_Grande +-05:00 MX America/Cancun +-04:00 VE America/Caracas +-03:00 GF America/Cayenne +-05:00 KY America/Cayman +-06:00 US America/Chicago +-06:00 MX America/Chihuahua +-07:00 MX America/Ciudad_Juarez +-06:00 CR America/Costa_Rica +-03:00 CL America/Coyhaique +-07:00 CA America/Creston +-04:00 BR America/Cuiaba +-04:00 CW America/Curacao ++00:00 GL America/Danmarkshavn +-07:00 CA America/Dawson +-07:00 CA America/Dawson_Creek +-07:00 US America/Denver +-05:00 US America/Detroit +-04:00 DM America/Dominica +-06:00 CA America/Edmonton +-05:00 BR America/Eirunepe +-06:00 SV America/El_Salvador +-07:00 CA America/Fort_Nelson +-03:00 BR America/Fortaleza +-04:00 CA America/Glace_Bay +-04:00 CA America/Goose_Bay +-05:00 TC America/Grand_Turk +-04:00 GD America/Grenada +-04:00 GP America/Guadeloupe +-06:00 GT America/Guatemala +-05:00 EC America/Guayaquil +-04:00 GY America/Guyana +-04:00 CA America/Halifax +-05:00 CU America/Havana +-07:00 MX America/Hermosillo +-05:00 US America/Indiana/Indianapolis +-06:00 US America/Indiana/Knox +-05:00 US America/Indiana/Marengo +-05:00 US America/Indiana/Petersburg +-06:00 US America/Indiana/Tell_City +-05:00 US America/Indiana/Vevay +-05:00 US America/Indiana/Vincennes +-05:00 US America/Indiana/Winamac +-06:00 CA America/Inuvik +-05:00 CA America/Iqaluit +-05:00 JM America/Jamaica +-09:00 US America/Juneau +-05:00 US America/Kentucky/Louisville +-05:00 US America/Kentucky/Monticello +-04:00 BO America/La_Paz +-05:00 PE America/Lima +-08:00 US America/Los_Angeles +-04:00 SX America/Lower_Princes +-03:00 BR America/Maceio +-06:00 NI America/Managua +-04:00 BR America/Manaus +-04:00 MF America/Marigot +-04:00 MQ America/Martinique +-06:00 MX America/Matamoros +-07:00 MX America/Mazatlan +-06:00 US America/Menominee +-06:00 MX America/Merida +-09:00 US America/Metlakatla +-06:00 MX America/Mexico_City +-03:00 PM America/Miquelon +-04:00 CA America/Moncton +-06:00 MX America/Monterrey +-03:00 UY America/Montevideo +-04:00 MS America/Montserrat +-05:00 BS America/Nassau +-05:00 US America/New_York +-09:00 US America/Nome +-02:00 BR America/Noronha +-06:00 US America/North_Dakota/Beulah +-06:00 US America/North_Dakota/Center +-06:00 US America/North_Dakota/New_Salem +-02:00 GL America/Nuuk +-06:00 MX America/Ojinaga +-05:00 PA America/Panama +-03:00 SR America/Paramaribo +-07:00 US America/Phoenix +-05:00 HT America/Port-au-Prince +-04:00 TT America/Port_of_Spain +-04:00 BR America/Porto_Velho +-04:00 PR America/Puerto_Rico +-03:00 CL America/Punta_Arenas +-06:00 CA America/Rankin_Inlet +-03:00 BR America/Recife +-06:00 CA America/Regina +-06:00 CA America/Resolute +-05:00 BR America/Rio_Branco +-03:00 BR America/Santarem +-04:00 CL America/Santiago +-04:00 DO America/Santo_Domingo +-03:00 BR America/Sao_Paulo +-02:00 GL America/Scoresbysund +-09:00 US America/Sitka +-04:00 BL America/St_Barthelemy +-03:30 CA America/St_Johns +-04:00 KN America/St_Kitts +-04:00 LC America/St_Lucia +-04:00 VI America/St_Thomas +-04:00 VC America/St_Vincent +-06:00 CA America/Swift_Current +-06:00 HN America/Tegucigalpa +-04:00 GL America/Thule +-08:00 MX America/Tijuana +-05:00 CA America/Toronto +-04:00 VG America/Tortola +-07:00 CA America/Vancouver +-07:00 CA America/Whitehorse +-06:00 CA America/Winnipeg +-09:00 US America/Yakutat ++10:00 AU Antarctica/Macquarie ++01:00 SJ Arctic/Longyearbyen ++03:00 YE Asia/Aden ++05:00 KZ Asia/Almaty ++03:00 JO Asia/Amman ++12:00 RU Asia/Anadyr ++05:00 KZ Asia/Aqtau ++05:00 KZ Asia/Aqtobe ++05:00 TM Asia/Ashgabat ++05:00 KZ Asia/Atyrau ++03:00 IQ Asia/Baghdad ++03:00 BH Asia/Bahrain ++04:00 AZ Asia/Baku ++07:00 TH Asia/Bangkok ++07:00 RU Asia/Barnaul ++02:00 LB Asia/Beirut ++06:00 KG Asia/Bishkek ++08:00 BN Asia/Brunei ++09:00 RU Asia/Chita ++05:30 LK Asia/Colombo ++03:00 SY Asia/Damascus ++06:00 BD Asia/Dhaka ++09:00 TL Asia/Dili ++04:00 AE Asia/Dubai ++05:00 TJ Asia/Dushanbe ++02:00 CY Asia/Famagusta ++07:00 VN Asia/Ho_Chi_Minh ++08:00 HK Asia/Hong_Kong ++07:00 MN Asia/Hovd ++08:00 RU Asia/Irkutsk ++07:00 ID Asia/Jakarta ++09:00 ID Asia/Jayapura ++02:00 IL Asia/Jerusalem ++04:30 AF Asia/Kabul ++12:00 RU Asia/Kamchatka ++05:00 PK Asia/Karachi ++05:45 NP Asia/Kathmandu ++09:00 RU Asia/Khandyga ++05:30 IN Asia/Kolkata ++07:00 RU Asia/Krasnoyarsk ++08:00 MY Asia/Kuala_Lumpur ++08:00 MY Asia/Kuching ++03:00 KW Asia/Kuwait ++08:00 MO Asia/Macau ++11:00 RU Asia/Magadan ++08:00 ID Asia/Makassar ++08:00 PH Asia/Manila ++04:00 OM Asia/Muscat ++02:00 CY Asia/Nicosia ++07:00 RU Asia/Novokuznetsk ++07:00 RU Asia/Novosibirsk ++06:00 RU Asia/Omsk ++05:00 KZ Asia/Oral ++07:00 KH Asia/Phnom_Penh ++07:00 ID Asia/Pontianak ++09:00 KP Asia/Pyongyang ++03:00 QA Asia/Qatar ++05:00 KZ Asia/Qostanay ++05:00 KZ Asia/Qyzylorda ++03:00 SA Asia/Riyadh ++11:00 RU Asia/Sakhalin ++05:00 UZ Asia/Samarkand ++09:00 KR Asia/Seoul ++08:00 CN Asia/Shanghai ++08:00 SG Asia/Singapore ++11:00 RU Asia/Srednekolymsk ++08:00 TW Asia/Taipei ++05:00 UZ Asia/Tashkent ++04:00 GE Asia/Tbilisi ++03:30 IR Asia/Tehran ++06:00 BT Asia/Thimphu ++09:00 JP Asia/Tokyo ++07:00 RU Asia/Tomsk ++08:00 MN Asia/Ulaanbaatar ++06:00 CN Asia/Urumqi ++10:00 RU Asia/Ust-Nera ++07:00 LA Asia/Vientiane ++10:00 RU Asia/Vladivostok ++09:00 RU Asia/Yakutsk ++06:30 MM Asia/Yangon ++05:00 RU Asia/Yekaterinburg ++04:00 AM Asia/Yerevan +-01:00 PT Atlantic/Azores +-04:00 BM Atlantic/Bermuda ++00:00 ES Atlantic/Canary +-01:00 CV Atlantic/Cape_Verde ++00:00 FO Atlantic/Faroe ++00:00 PT Atlantic/Madeira ++00:00 IS Atlantic/Reykjavik ++00:00 SH Atlantic/St_Helena +-03:00 FK Atlantic/Stanley ++09:30 AU Australia/Adelaide ++10:00 AU Australia/Brisbane ++09:30 AU Australia/Broken_Hill ++09:30 AU Australia/Darwin ++08:45 AU Australia/Eucla ++10:00 AU Australia/Hobart ++10:00 AU Australia/Lindeman ++10:30 AU Australia/Lord_Howe ++10:00 AU Australia/Melbourne ++08:00 AU Australia/Perth ++10:00 AU Australia/Sydney ++01:00 NL Europe/Amsterdam ++01:00 AD Europe/Andorra ++04:00 RU Europe/Astrakhan ++02:00 GR Europe/Athens ++01:00 RS Europe/Belgrade ++01:00 DE Europe/Berlin ++01:00 SK Europe/Bratislava ++01:00 BE Europe/Brussels ++02:00 RO Europe/Bucharest ++01:00 HU Europe/Budapest ++01:00 DE Europe/Busingen ++02:00 MD Europe/Chisinau ++01:00 DK Europe/Copenhagen ++01:00 IE Europe/Dublin ++01:00 GI Europe/Gibraltar ++00:00 GG Europe/Guernsey ++02:00 FI Europe/Helsinki ++00:00 IM Europe/Isle_of_Man ++03:00 TR Europe/Istanbul ++00:00 JE Europe/Jersey ++02:00 RU Europe/Kaliningrad ++03:00 RU Europe/Kirov ++02:00 UA Europe/Kyiv ++00:00 PT Europe/Lisbon ++01:00 SI Europe/Ljubljana ++00:00 GB Europe/London ++01:00 LU Europe/Luxembourg ++01:00 ES Europe/Madrid ++01:00 MT Europe/Malta ++02:00 AX Europe/Mariehamn ++03:00 BY Europe/Minsk ++01:00 MC Europe/Monaco ++03:00 RU Europe/Moscow ++01:00 NO Europe/Oslo ++01:00 FR Europe/Paris ++01:00 ME Europe/Podgorica ++01:00 CZ Europe/Prague ++02:00 LV Europe/Riga ++01:00 IT Europe/Rome ++04:00 RU Europe/Samara ++01:00 SM Europe/San_Marino ++01:00 BA Europe/Sarajevo ++04:00 RU Europe/Saratov ++03:00 UA Europe/Simferopol ++01:00 MK Europe/Skopje ++02:00 BG Europe/Sofia ++01:00 SE Europe/Stockholm ++02:00 EE Europe/Tallinn ++01:00 AL Europe/Tirane ++04:00 RU Europe/Ulyanovsk ++01:00 LI Europe/Vaduz ++01:00 VA Europe/Vatican ++01:00 AT Europe/Vienna ++02:00 LT Europe/Vilnius ++03:00 RU Europe/Volgograd ++01:00 PL Europe/Warsaw ++01:00 HR Europe/Zagreb ++01:00 CH Europe/Zurich ++03:00 MG Indian/Antananarivo ++06:00 IO Indian/Chagos ++07:00 CX Indian/Christmas ++06:30 CC Indian/Cocos ++03:00 KM Indian/Comoro ++05:00 TF Indian/Kerguelen ++04:00 SC Indian/Mahe ++05:00 MV Indian/Maldives ++04:00 MU Indian/Mauritius ++03:00 YT Indian/Mayotte ++04:00 RE Indian/Reunion ++13:00 WS Pacific/Apia ++12:00 NZ Pacific/Auckland ++11:00 PG Pacific/Bougainville ++12:45 NZ Pacific/Chatham ++10:00 FM Pacific/Chuuk +-06:00 CL Pacific/Easter ++11:00 VU Pacific/Efate ++12:00 FJ Pacific/Fiji ++12:00 TV Pacific/Funafuti +-06:00 EC Pacific/Galapagos +-09:00 PF Pacific/Gambier ++11:00 SB Pacific/Guadalcanal ++10:00 GU Pacific/Guam +-10:00 US Pacific/Honolulu ++13:00 KI Pacific/Kanton ++14:00 KI Pacific/Kiritimati ++11:00 FM Pacific/Kosrae ++12:00 MH Pacific/Kwajalein ++12:00 MH Pacific/Majuro +-09:30 PF Pacific/Marquesas ++12:00 NR Pacific/Nauru +-11:00 NU Pacific/Niue ++11:00 NF Pacific/Norfolk ++11:00 NC Pacific/Noumea +-11:00 AS Pacific/Pago_Pago ++09:00 PW Pacific/Palau +-08:00 PN Pacific/Pitcairn ++11:00 FM Pacific/Pohnpei ++10:00 PG Pacific/Port_Moresby +-10:00 CK Pacific/Rarotonga ++10:00 MP Pacific/Saipan +-10:00 PF Pacific/Tahiti ++12:00 KI Pacific/Tarawa ++13:00 TO Pacific/Tongatapu ++12:00 WF Pacific/Wallis diff --git a/data/misc/useragent.json b/data/misc/useragent.json index e659a1b..85bb36b 100644 --- a/data/misc/useragent.json +++ b/data/misc/useragent.json @@ -1 +1 @@ -["Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36", "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:124.0) Gecko/20100101 Firefox/124.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:123.0) Gecko/20100101 Firefox/123.0", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15", "Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 Edg/124.0.0.0"] +{ "format": "{ua}", "rows": "useragent.tsv" } diff --git a/data/misc/useragent.tsv b/data/misc/useragent.tsv new file mode 100644 index 0000000..df968ff --- /dev/null +++ b/data/misc/useragent.tsv @@ -0,0 +1,97 @@ +browser device os ua +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Mobile Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Mobile Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Mobile Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Mobile Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Mobile Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Mobile Safari/537.36 +Chrome mobile Android Mozilla/5.0 (Linux; Android 12; Pixel 6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/114.0.0.0 Mobile Safari/537.36 +Chrome desktop ChromeOS Mozilla/5.0 (X11; CrOS x86_64 14541.0.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 +Chrome desktop Linux Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 +Chrome desktop Linux Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 +Chrome desktop Linux Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 +Chrome desktop Linux Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 +Chrome desktop Linux Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 +Chrome desktop Linux Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/109.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/117.0.5938.132 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/119.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/130.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/134.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/135.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/140.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 YaBrowser/26.8.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.7922.34 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 +Chrome desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36 +Chrome mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 26_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/152.0.7977.64 Mobile/15E148 Safari/604.1 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/116.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/137.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/138.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/139.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/144.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/145.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/146.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/147.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/148.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/149.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 +Chrome desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36 +Edge desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 Edg/151.0.0.0 +Edge desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 Edg/152.0.0.0 +Edge desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/153.0.0.0 Safari/537.36 Edg/153.0.0.0 +Edge desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/152.0.0.0 Safari/537.36 Edg/152.0.0.0 +Firefox desktop Linux Mozilla/5.0 (X11; Linux x86_64; rv:155.0) Gecko/20100101 Firefox/155.0 +Firefox desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:126.0) Gecko/20100101 Firefox/126.0 +Firefox desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:154.0) Gecko/20100101 Firefox/154.0 +Firefox desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:155.0) Gecko/20100101 Firefox/155.0 +Firefox desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:154.0) Gecko/20100101 Firefox/154.0 +Firefox desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:155.0) Gecko/20100101 Firefox/155.0 +Opera desktop Windows Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/151.0.0.0 Safari/537.36 OPR/135.0.0.0 +Opera desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/150.0.0.0 Safari/537.36 OPR/134.0.0.0 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.5 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.7.5 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.3 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5.2 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6.1 Mobile/15E148 Safari/604.1 +Safari mobile iOS Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/27.0 Mobile/15E148 Safari/604.1 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.6 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.2 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.5.2 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6.1 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.6.2 Safari/605.1.15 +Safari desktop macOS Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/27.0 Safari/605.1.15 +Samsung Internet mobile Android Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) SamsungBrowser/30.0 Chrome/143.0.0.0 Mobile Safari/537.36 diff --git a/todo.md b/todo.md index b833ae1..bd3cf0e 100644 --- a/todo.md +++ b/todo.md @@ -22,7 +22,7 @@ value is composed; TSV says which values exist. - In a data file, refuse a choice whose items are templates with one identical field set, naming the TSV to write; an inline template is exempt, having no file. A choice of strings stays a choice. -- Convert `misc.timezone`, `car` and `useragent` to tables. +- Convert `misc.timezone`, `car` and `useragent` to tables — done in step 4. - Let a path select a row by key or by name, `geo.SE.municipality[0180]` and `geo.SE.municipality[Stockholm]`, and descend to a linked table by name, `geo.SE.region[Skåne län].street`; a key or a linked table name may not equal @@ -137,7 +137,7 @@ ids. Shape: T = table, t = template, c = choice. | `timezone` zone, territory, offset | T | tzdb zone.tab | public domain | | `mimetype` type, extensions | T | IANA + mime-db | CC0, MIT | | `httpstatus`, `httpmethod`, `port`, `tld`, `protocol`, `loglevel` | T/c | IANA | CC0 | -| `useragent` per browser | T | top-user-agents | MIT | +| `useragent` browser, device, os; selection per browser once `browser` is a table | T | top-user-agents | MIT | | `ip` v4 documentation ranges, private, CIDR; `ipv6` `2001:db8::/32`; `mac` locally administered | t | RFC 5737, 1918, 9637 | facts | | `creditcard` per network: IIN, length, CVV, expiry | T+t | network rules, `{luhn()}` | facts | | `bic`, `iban` (exists), `isin`, `cusip` | t | structure rules | facts |