Files
worldmonitor/scripts/data/country-codes.json
Elie Habib 45f5e5a457 feat(forecast): AI Forecasts prediction module (#1579)
* feat(forecast): add AI Forecasts prediction module (Pro-tier)

MiroFish-inspired prediction engine that generates structured forecasts
across 6 domains (conflict, market, supply chain, political, military,
infrastructure) using existing WorldMonitor data streams.

- Proto definitions for ForecastService with GetForecasts RPC
- Dedicated seed script (seed-forecasts.mjs) with 6 domain detectors,
  cross-domain cascade resolver, prediction market calibration, and
  trend detection via prior snapshot comparison
- Premium-gated RPC handler (PREMIUM_RPC_PATHS enforcement)
- Lazy-loaded ForecastPanel with domain filters, probability bars,
  trend arrows, signal evidence, and cascade links
- Health monitoring integration (seed-meta freshness tracking)
- Refresh scheduler with API key guard

* test(forecast): add 47 unit tests for forecast detectors and utilities

Covers forecastId, normalize, resolveCascades, calibrateWithMarkets,
computeTrends, and smoke tests for all 6 domain detectors. Exports
testable functions from seed script with direct-run guard.

* fix(forecast): domain mismatch 'infra' vs 'infrastructure', add panel category

- Seed script used 'infra' but ForecastPanel filtered on 'infrastructure',
  causing Infra tab to show zero results
- Added 'forecast' to intelligence category in PANEL_CATEGORY_MAP

* fix(forecast): move CSS to one-time injection, improve type safety

- P2: Move style block from setContent to one-time document.head injection
  to prevent CSS accumulation on repeated renders
- P3: Replace +toFixed(3) with Math.round for readability in seed script
- P3: Use Forecast type instead of any[] in RPC handler filter

* fix(forecast): handle sebuf proto data shapes from Redis

Detectors now normalize CII scores from server-side proto format
(combinedScore, TREND_DIRECTION_RISING, region) to uniform shape.
Outage severity handles proto enum format (SEVERITY_LEVEL_HIGH).
Added confidence floor of 0.3 for single-source predictions.

Verified against live Redis: 2 predictions generated (Iran infra
shutdown, IL political instability).

* feat(forecast): unlock AI Forecasts on web, lock desktop only (trial)

- Remove forecast RPC from PREMIUM_RPC_PATHS (web access is free)
- Panel locked on desktop only (same as oref-sirens/telegram-intel)
- Remove API key guards from data-loader and refresh scheduler
- Web users get full access during trial period

* chore: regenerate proto types with make generate

Re-ran make generate after rebasing on main. Plugin v0.7.0 dropped
@ts-nocheck from output, added it back to all 50 generated files.
Fixed 4 type errors from proto codegen changes:
- MarketSource enum -> string union type
- TemporalAnomalyProto -> TemporalAnomaly rename
- webcam lastUpdated number -> string

* fix(forecast): use chokepoints v4 key, include ciiContribution in unrest

- P1: Switch chokepoints input from stale v2 to active v4 Redis key,
  matching bootstrap.js and cache-keys.ts
- P2: Add ciiContribution to unrest component fallback chain in
  normalizeCiiEntry so political detector reads the correct sebuf field

* feat(forecast): Phase 2 LLM scenario enrichment + confidence model

MiroFish-inspired enhancements:
- LLM scenario narratives via Groq/OpenRouter (narrative-only, no numeric
  adjustment). Evidence-grounded prompts with mandatory signal citation
  and few-shot examples from MiroFish's SECTION_SYSTEM_PROMPT_TEMPLATE.
- Top-4 predictions batched into single LLM call for cost efficiency.
- News context from newsInsights attached to all predictions for LLM
  prompt grounding (NOT in signals, cannot affect confidence).
- Deterministic confidence model: source diversity via SIGNAL_TO_SOURCE
  mapping (deduplicates cii+cii_delta, theater+indicators) + calibration
  agreement from prediction market drift. Floor 0.2, ceiling 1.0.
- Output validation: rejects scenarios without signal references.
- Truncated JSON repair for small model output.
- Structured JSON logging for LLM calls.
- Redis cache for LLM scenarios (1h TTL).
- 23 new tests (70 total), all passing.
- Live-tested: OpenRouter gemini-2.5-flash produces evidence-grounded
  scenario narratives from real WorldMonitor data.

* feat(forecast): Phase 3 multi-perspective scenarios, projections, data-driven cascades

MiroFish-inspired enhancements:
- Multi-perspective LLM analysis: top-2 predictions get strategic,
  regional, and contrarian viewpoints via combined LLM call
- Probability projections: domain-specific decay curves (h24/d7/d30)
  anchored to timeHorizon so probability equals projections[timeHorizon]
- Data-driven cascade rules: moved from hardcoded array to JSON config
  (scripts/data/cascade-rules.json) with schema validation, named
  predicate evaluators, unknown key rejection, and fallback to defaults
- 4 new cascade paths: infrastructure->supply_chain, infrastructure->market
  (both requiresSeverity:total), conflict->political, political->market
- Proto: added Perspectives and Projections messages to Forecast
- ForecastPanel: renders projections row and conditional perspectives toggle
- 89 tests (19 new), all passing
- Live-tested: OpenRouter produces perspectives from real data

* feat(forecast): Phase 4 data utilization + entity graph

Fixes data gaps that prevented 4 of 6 detectors from firing:
- Input normalizers: chokepoint v4 shape + GPS hexes-to-zones mapping
- Chokepoint warm-ping (production-only, requires WM_API_BASE_URL)
- Lowered CII conflict threshold from 70 to 60, gated on level=high|critical

4 new standalone detectors:
- UCDP conflict zones (10+ events per country)
- Cyber threat concentration (5+ threats per country)
- GPS jamming in maritime shipping zones (5 regions)
- Prediction markets as signals (60-90% probability markets)

Entity-relationship graph (file-based, 38 nodes):
- Countries, theaters, commodities, chokepoints, alliances
- Alias table resolves both ISO codes and display names
- Graph cascade discovery links predictions across entities

Result: 51 predictions (up from 1-2), spanning conflict, infrastructure,
and supply chain domains. 112 tests, all passing.

* fix(forecast): redis cache format, signal source mapping, type safety

Fresh-eyes audit fixes:
- BUG: redisSet used wrong Upstash API format (POST body with {value,ex}
  instead of command array ['SET',key,value,'EX',ttl]). LLM cache writes
  were silently failing, causing fresh LLM calls every run.
- BUG: prediction_market signal type missing from SIGNAL_TO_SOURCE,
  inflating confidence for market-derived predictions.
- CLEANUP: Remove unnecessary (f as any) casts in ForecastPanel since
  generated Forecast type already has projections/perspectives fields.
- CLEANUP: Bump health maxStaleMin from 60 to 90 to avoid false STALE
  alerts when LLM calls add latency to seed runs.

* feat(forecast): headline-entity matching with news corroboration signals

Uses entity graph aliases to match headlines to predictions by
country/theater (excludes commodity/infrastructure nodes to prevent
false positives). Predictions with matching headlines get a
news_corroboration signal visible in the panel.

Also fixes buildUserPrompt to merge unique headlines from ALL
predictions in the LLM batch (was only reading preds[0].newsContext).

Live-tested: 13 of 51 predictions now have corroborating headlines
(Iran, Israel, Syria, Ukraine, etc). 116 tests, all passing.

* feat(forecast): add country-codes.json for headline-entity matching

56 countries with ISO codes, full names, and scoring keywords (extracted
from src/config/countries.ts + UCDP-relevant additions). Used by
attachNewsContext for richer headline matching via getSearchTermsForRegion
which combines country-codes + entity graph + keyword aliases.

14/57 predictions now have news corroboration (limited by headline
coverage, not matching quality: only 8 headlines currently available).

* feat(forecast): read 300 headlines from news digest instead of 8

Read news:digest:v1:full:en (300 headlines across 16 categories) instead
of just news:insights:v1 topStories (8 headlines). Fallback to topStories
if digest is unavailable.

Result: news corroboration jumped from 25% to 64% (38/59 predictions).

* fix(forecast): handle parenthetical country names in headline matching

Strip suffixes like '(Zaire)', '(Burma)', '(Soviet Union)' from UCDP
region names before matching against country-codes.json. Also use
includes() for reverse name lookup to catch partial matches.

Corroboration: 64% -> 69% (41/59). Remaining 18 unmatched are countries
with no current English-language news coverage.

* fix(forecast): cache validated LLM output, add digest test, log cache errors

Fresh-eyes audit fixes:
- Combined LLM cache now stores only validated items (was caching raw
  unvalidated output, serving potentially invalid scenarios on cache hit)
- redisSet logs warnings on failure (was silently swallowing all errors)
- Added digest-based test for attachNewsContext (primary path was untested)
- Fixed test arity: attachNewsContext(preds, news, digest) with 3 params

* fix(forecast): remove dead confidenceFromSources, reduce warm-ping timeout

- P2: Remove confidenceFromSources (dead code, computeConfidence overwrites
  all initial confidence values). Inline the formula in original detectors.
- P3: Reduce warm-ping timeout from 30s to 15s (non-critical step)
- P3: Add trial status comment on forecast panel config

* fix(forecast): resolve ISO codes to country names, fix market detector, safe pre-push

P1 fixes from code review:
- CII ISO codes (IL, IR) now resolved to full country names (Israel, Iran)
  via country-codes.json. Prevents substring false positives (IL matching
  Chile) in event correlation. Uses word-boundary regex for matching.
- Market detector CII-to-theater mapping now uses entity graph traversal
  instead of broken theater-name substring matching. Iran correctly maps
  to Middle East theater via graph links.
- Pre-push hook no longer runs destructive git checkout on proto freshness
  failure. Reports mismatch and exits without modifying worktree.
2026-03-15 01:42:04 +04:00

1225 lines
16 KiB
JSON

{
"AF": {
"name": "Afghanistan",
"keywords": [
"afghanistan",
"kabul"
]
},
"AL": {
"name": "Albania",
"keywords": [
"albania",
"tirana"
]
},
"DZ": {
"name": "Algeria",
"keywords": [
"algeria",
"algiers"
]
},
"AD": {
"name": "Andorra",
"keywords": [
"andorra"
]
},
"AO": {
"name": "Angola",
"keywords": [
"angola",
"luanda"
]
},
"AG": {
"name": "Antigua and Barbuda",
"keywords": [
"antigua"
]
},
"AR": {
"name": "Argentina",
"keywords": [
"argentina",
"buenos aires"
]
},
"AM": {
"name": "Armenia",
"keywords": [
"armenia",
"yerevan"
]
},
"AU": {
"name": "Australia",
"keywords": [
"australia",
"canberra",
"sydney"
]
},
"AT": {
"name": "Austria",
"keywords": [
"austria",
"vienna"
]
},
"AZ": {
"name": "Azerbaijan",
"keywords": [
"azerbaijan",
"baku"
]
},
"BS": {
"name": "Bahamas",
"keywords": [
"bahamas"
]
},
"BH": {
"name": "Bahrain",
"keywords": [
"bahrain",
"manama"
]
},
"BD": {
"name": "Bangladesh",
"keywords": [
"bangladesh",
"dhaka"
]
},
"BB": {
"name": "Barbados",
"keywords": [
"barbados"
]
},
"BY": {
"name": "Belarus",
"keywords": [
"belarus",
"minsk",
"lukashenko"
]
},
"BE": {
"name": "Belgium",
"keywords": [
"belgium",
"brussels"
]
},
"BZ": {
"name": "Belize",
"keywords": [
"belize"
]
},
"BJ": {
"name": "Benin",
"keywords": [
"benin"
]
},
"BT": {
"name": "Bhutan",
"keywords": [
"bhutan"
]
},
"BO": {
"name": "Bolivia",
"keywords": [
"bolivia"
]
},
"BA": {
"name": "Bosnia and Herzegovina",
"keywords": [
"bosnia",
"sarajevo"
]
},
"BW": {
"name": "Botswana",
"keywords": [
"botswana"
]
},
"BR": {
"name": "Brazil",
"keywords": [
"brazil",
"brasilia",
"são paulo"
]
},
"BN": {
"name": "Brunei",
"keywords": [
"brunei"
]
},
"BG": {
"name": "Bulgaria",
"keywords": [
"bulgaria",
"sofia"
]
},
"BF": {
"name": "Burkina Faso",
"keywords": [
"burkina faso",
"ouagadougou"
]
},
"BI": {
"name": "Burundi",
"keywords": [
"burundi"
]
},
"CV": {
"name": "Cape Verde",
"keywords": [
"cape verde"
]
},
"KH": {
"name": "Cambodia",
"keywords": [
"cambodia",
"phnom penh"
]
},
"CM": {
"name": "Cameroon",
"keywords": [
"cameroon",
"yaoundé"
]
},
"CA": {
"name": "Canada",
"keywords": [
"canada",
"ottawa",
"toronto"
]
},
"CF": {
"name": "Central African Republic",
"keywords": [
"central african republic"
]
},
"TD": {
"name": "Chad",
"keywords": [
"chad",
"ndjamena"
]
},
"CL": {
"name": "Chile",
"keywords": [
"chile",
"santiago"
]
},
"CN": {
"name": "China",
"keywords": [
"china",
"beijing",
"xi jinping",
"prc"
]
},
"CO": {
"name": "Colombia",
"keywords": [
"colombia",
"bogotá"
]
},
"KM": {
"name": "Comoros",
"keywords": [
"comoros"
]
},
"CG": {
"name": "Congo",
"keywords": [
"congo",
"brazzaville"
]
},
"CD": {
"name": "DR Congo",
"keywords": [
"congo",
"kinshasa",
"drc"
]
},
"CR": {
"name": "Costa Rica",
"keywords": [
"costa rica"
]
},
"CI": {
"name": "Ivory Coast",
"keywords": [
"ivory coast",
"côte d'ivoire",
"abidjan"
]
},
"HR": {
"name": "Croatia",
"keywords": [
"croatia",
"zagreb"
]
},
"CU": {
"name": "Cuba",
"keywords": [
"cuba",
"havana"
]
},
"CY": {
"name": "Cyprus",
"keywords": [
"cyprus",
"nicosia"
]
},
"CZ": {
"name": "Czech Republic",
"keywords": [
"czech",
"prague"
]
},
"DK": {
"name": "Denmark",
"keywords": [
"denmark",
"copenhagen"
]
},
"DJ": {
"name": "Djibouti",
"keywords": [
"djibouti"
]
},
"DO": {
"name": "Dominican Republic",
"keywords": [
"dominican republic"
]
},
"EC": {
"name": "Ecuador",
"keywords": [
"ecuador",
"quito"
]
},
"EG": {
"name": "Egypt",
"keywords": [
"egypt",
"cairo",
"suez"
]
},
"SV": {
"name": "El Salvador",
"keywords": [
"el salvador"
]
},
"GQ": {
"name": "Equatorial Guinea",
"keywords": [
"equatorial guinea"
]
},
"ER": {
"name": "Eritrea",
"keywords": [
"eritrea",
"asmara"
]
},
"EE": {
"name": "Estonia",
"keywords": [
"estonia",
"tallinn"
]
},
"SZ": {
"name": "Eswatini",
"keywords": [
"eswatini",
"swaziland"
]
},
"ET": {
"name": "Ethiopia",
"keywords": [
"ethiopia",
"addis ababa",
"tigray"
]
},
"FJ": {
"name": "Fiji",
"keywords": [
"fiji"
]
},
"FI": {
"name": "Finland",
"keywords": [
"finland",
"helsinki"
]
},
"FR": {
"name": "France",
"keywords": [
"france",
"paris",
"macron"
]
},
"GA": {
"name": "Gabon",
"keywords": [
"gabon"
]
},
"GM": {
"name": "Gambia",
"keywords": [
"gambia"
]
},
"GE": {
"name": "Georgia",
"keywords": [
"georgia",
"tbilisi"
]
},
"DE": {
"name": "Germany",
"keywords": [
"germany",
"berlin"
]
},
"GH": {
"name": "Ghana",
"keywords": [
"ghana",
"accra"
]
},
"GR": {
"name": "Greece",
"keywords": [
"greece",
"athens"
]
},
"GT": {
"name": "Guatemala",
"keywords": [
"guatemala"
]
},
"GN": {
"name": "Guinea",
"keywords": [
"guinea",
"conakry"
]
},
"GW": {
"name": "Guinea-Bissau",
"keywords": [
"guinea-bissau"
]
},
"GY": {
"name": "Guyana",
"keywords": [
"guyana"
]
},
"HT": {
"name": "Haiti",
"keywords": [
"haiti",
"port-au-prince"
]
},
"HN": {
"name": "Honduras",
"keywords": [
"honduras"
]
},
"HK": {
"name": "Hong Kong",
"keywords": [
"hong kong"
]
},
"HU": {
"name": "Hungary",
"keywords": [
"hungary",
"budapest"
]
},
"IS": {
"name": "Iceland",
"keywords": [
"iceland",
"reykjavik"
]
},
"IN": {
"name": "India",
"keywords": [
"india",
"new delhi",
"modi"
]
},
"ID": {
"name": "Indonesia",
"keywords": [
"indonesia",
"jakarta"
]
},
"IR": {
"name": "Iran",
"keywords": [
"iran",
"tehran",
"khamenei",
"irgc"
]
},
"IQ": {
"name": "Iraq",
"keywords": [
"iraq",
"baghdad"
]
},
"IE": {
"name": "Ireland",
"keywords": [
"ireland",
"dublin"
]
},
"IL": {
"name": "Israel",
"keywords": [
"israel",
"tel aviv",
"netanyahu",
"idf",
"gaza",
"hamas",
"hezbollah"
]
},
"IT": {
"name": "Italy",
"keywords": [
"italy",
"rome"
]
},
"JM": {
"name": "Jamaica",
"keywords": [
"jamaica"
]
},
"JP": {
"name": "Japan",
"keywords": [
"japan",
"tokyo"
]
},
"JO": {
"name": "Jordan",
"keywords": [
"jordan",
"amman"
]
},
"KZ": {
"name": "Kazakhstan",
"keywords": [
"kazakhstan",
"astana"
]
},
"KE": {
"name": "Kenya",
"keywords": [
"kenya",
"nairobi"
]
},
"KP": {
"name": "North Korea",
"keywords": [
"north korea",
"pyongyang",
"kim jong"
]
},
"KR": {
"name": "South Korea",
"keywords": [
"south korea",
"seoul"
]
},
"KW": {
"name": "Kuwait",
"keywords": [
"kuwait"
]
},
"KG": {
"name": "Kyrgyzstan",
"keywords": [
"kyrgyzstan"
]
},
"LA": {
"name": "Laos",
"keywords": [
"laos"
]
},
"LV": {
"name": "Latvia",
"keywords": [
"latvia",
"riga"
]
},
"LB": {
"name": "Lebanon",
"keywords": [
"lebanon",
"beirut",
"hezbollah"
]
},
"LS": {
"name": "Lesotho",
"keywords": [
"lesotho"
]
},
"LR": {
"name": "Liberia",
"keywords": [
"liberia"
]
},
"LY": {
"name": "Libya",
"keywords": [
"libya",
"tripoli",
"benghazi"
]
},
"LI": {
"name": "Liechtenstein",
"keywords": [
"liechtenstein"
]
},
"LT": {
"name": "Lithuania",
"keywords": [
"lithuania",
"vilnius"
]
},
"LU": {
"name": "Luxembourg",
"keywords": [
"luxembourg"
]
},
"MG": {
"name": "Madagascar",
"keywords": [
"madagascar"
]
},
"MW": {
"name": "Malawi",
"keywords": [
"malawi"
]
},
"MY": {
"name": "Malaysia",
"keywords": [
"malaysia",
"kuala lumpur"
]
},
"MV": {
"name": "Maldives",
"keywords": [
"maldives"
]
},
"ML": {
"name": "Mali",
"keywords": [
"mali",
"bamako"
]
},
"MT": {
"name": "Malta",
"keywords": [
"malta"
]
},
"MR": {
"name": "Mauritania",
"keywords": [
"mauritania"
]
},
"MU": {
"name": "Mauritius",
"keywords": [
"mauritius"
]
},
"MX": {
"name": "Mexico",
"keywords": [
"mexico",
"mexico city"
]
},
"MD": {
"name": "Moldova",
"keywords": [
"moldova",
"chisinau"
]
},
"MN": {
"name": "Mongolia",
"keywords": [
"mongolia"
]
},
"ME": {
"name": "Montenegro",
"keywords": [
"montenegro"
]
},
"MA": {
"name": "Morocco",
"keywords": [
"morocco",
"rabat"
]
},
"MZ": {
"name": "Mozambique",
"keywords": [
"mozambique",
"maputo"
]
},
"MM": {
"name": "Myanmar",
"keywords": [
"myanmar",
"burma",
"naypyidaw"
]
},
"NA": {
"name": "Namibia",
"keywords": [
"namibia"
]
},
"NP": {
"name": "Nepal",
"keywords": [
"nepal",
"kathmandu"
]
},
"NL": {
"name": "Netherlands",
"keywords": [
"netherlands",
"dutch",
"amsterdam"
]
},
"NZ": {
"name": "New Zealand",
"keywords": [
"new zealand",
"wellington"
]
},
"NI": {
"name": "Nicaragua",
"keywords": [
"nicaragua"
]
},
"NE": {
"name": "Niger",
"keywords": [
"niger",
"niamey"
]
},
"NG": {
"name": "Nigeria",
"keywords": [
"nigeria",
"lagos",
"abuja"
]
},
"MK": {
"name": "North Macedonia",
"keywords": [
"north macedonia",
"skopje"
]
},
"NO": {
"name": "Norway",
"keywords": [
"norway",
"oslo"
]
},
"OM": {
"name": "Oman",
"keywords": [
"oman",
"muscat"
]
},
"PK": {
"name": "Pakistan",
"keywords": [
"pakistan",
"islamabad",
"karachi"
]
},
"PA": {
"name": "Panama",
"keywords": [
"panama"
]
},
"PG": {
"name": "Papua New Guinea",
"keywords": [
"papua new guinea"
]
},
"PY": {
"name": "Paraguay",
"keywords": [
"paraguay"
]
},
"PE": {
"name": "Peru",
"keywords": [
"peru",
"lima"
]
},
"PH": {
"name": "Philippines",
"keywords": [
"philippines",
"manila"
]
},
"PL": {
"name": "Poland",
"keywords": [
"poland",
"warsaw"
]
},
"PT": {
"name": "Portugal",
"keywords": [
"portugal",
"lisbon"
]
},
"QA": {
"name": "Qatar",
"keywords": [
"qatar",
"doha"
]
},
"RO": {
"name": "Romania",
"keywords": [
"romania",
"bucharest"
]
},
"RU": {
"name": "Russia",
"keywords": [
"russia",
"moscow",
"kremlin",
"putin"
]
},
"RW": {
"name": "Rwanda",
"keywords": [
"rwanda",
"kigali"
]
},
"SA": {
"name": "Saudi Arabia",
"keywords": [
"saudi arabia",
"riyadh",
"mbs"
]
},
"SN": {
"name": "Senegal",
"keywords": [
"senegal",
"dakar"
]
},
"RS": {
"name": "Serbia",
"keywords": [
"serbia",
"belgrade"
]
},
"SL": {
"name": "Sierra Leone",
"keywords": [
"sierra leone"
]
},
"SG": {
"name": "Singapore",
"keywords": [
"singapore"
]
},
"SK": {
"name": "Slovakia",
"keywords": [
"slovakia",
"bratislava"
]
},
"SI": {
"name": "Slovenia",
"keywords": [
"slovenia"
]
},
"SO": {
"name": "Somalia",
"keywords": [
"somalia",
"mogadishu"
]
},
"ZA": {
"name": "South Africa",
"keywords": [
"south africa",
"johannesburg",
"pretoria"
]
},
"SS": {
"name": "South Sudan",
"keywords": [
"south sudan",
"juba"
]
},
"ES": {
"name": "Spain",
"keywords": [
"spain",
"madrid"
]
},
"LK": {
"name": "Sri Lanka",
"keywords": [
"sri lanka",
"colombo"
]
},
"SD": {
"name": "Sudan",
"keywords": [
"sudan",
"khartoum",
"darfur"
]
},
"SR": {
"name": "Suriname",
"keywords": [
"suriname"
]
},
"SE": {
"name": "Sweden",
"keywords": [
"sweden",
"stockholm"
]
},
"CH": {
"name": "Switzerland",
"keywords": [
"switzerland",
"swiss",
"zurich",
"geneva"
]
},
"SY": {
"name": "Syria",
"keywords": [
"syria",
"damascus",
"assad"
]
},
"TW": {
"name": "Taiwan",
"keywords": [
"taiwan",
"taipei",
"tsmc"
]
},
"TJ": {
"name": "Tajikistan",
"keywords": [
"tajikistan"
]
},
"TZ": {
"name": "Tanzania",
"keywords": [
"tanzania",
"dar es salaam"
]
},
"TH": {
"name": "Thailand",
"keywords": [
"thailand",
"bangkok"
]
},
"TL": {
"name": "Timor-Leste",
"keywords": [
"timor-leste",
"east timor"
]
},
"TG": {
"name": "Togo",
"keywords": [
"togo"
]
},
"TT": {
"name": "Trinidad and Tobago",
"keywords": [
"trinidad"
]
},
"TN": {
"name": "Tunisia",
"keywords": [
"tunisia",
"tunis"
]
},
"TR": {
"name": "Turkey",
"keywords": [
"turkey",
"türkiye",
"ankara",
"erdogan",
"istanbul"
]
},
"TM": {
"name": "Turkmenistan",
"keywords": [
"turkmenistan"
]
},
"UG": {
"name": "Uganda",
"keywords": [
"uganda",
"kampala"
]
},
"UA": {
"name": "Ukraine",
"keywords": [
"ukraine",
"kyiv",
"zelensky"
]
},
"AE": {
"name": "United Arab Emirates",
"keywords": [
"uae",
"dubai",
"abu dhabi",
"emirates"
]
},
"GB": {
"name": "United Kingdom",
"keywords": [
"united kingdom",
"britain",
"london"
]
},
"US": {
"name": "United States",
"keywords": [
"united states",
"usa",
"america",
"washington",
"pentagon",
"trump",
"biden"
]
},
"UY": {
"name": "Uruguay",
"keywords": [
"uruguay"
]
},
"UZ": {
"name": "Uzbekistan",
"keywords": [
"uzbekistan",
"tashkent"
]
},
"VE": {
"name": "Venezuela",
"keywords": [
"venezuela",
"caracas",
"maduro"
]
},
"VN": {
"name": "Vietnam",
"keywords": [
"vietnam",
"hanoi"
]
},
"YE": {
"name": "Yemen",
"keywords": [
"yemen",
"sanaa",
"houthi"
]
},
"ZM": {
"name": "Zambia",
"keywords": [
"zambia"
]
},
"ZW": {
"name": "Zimbabwe",
"keywords": [
"zimbabwe",
"harare"
]
}
}