diff --git a/.vscode/settings.json b/.vscode/settings.json index eb0daea..43905f0 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -17,7 +17,4 @@ "editor.codeActionsOnSave": { "source.fixAll.eslint": "explicit" }, - "eslint.validate": [ - "javascript" - ], -} \ No newline at end of file +} diff --git a/Dockerfile.server b/Dockerfile.server new file mode 100644 index 0000000..cce442c --- /dev/null +++ b/Dockerfile.server @@ -0,0 +1,13 @@ +FROM node:24-alpine +WORKDIR /app + +COPY package.json package-lock.json ./ +RUN npm ci --omit=dev --legacy-peer-deps +COPY . . + +RUN npm run build + +EXPOSE 8080 + +ENV DIST=1 +CMD ["npm", "start"] diff --git a/README.md b/README.md index fbe3eba..f366021 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ This project aims to bring back the feel of the 90s with a weather forecast that Nostalgia. And I enjoy following the weather, especially severe storms. -It's also a creative outlet for me and keeps my programming skills honed for when I need them for my day job. +It's also a creative outlet for me and keeps my programming skills honed for when I need them for my day job. ### Included technology I've kept this open source, well commented, and made it as library-free as possible to help others interested in programming be able to jump right in and start working with the code. @@ -39,29 +39,95 @@ This project is tightly coupled to [NOAA's Weather API](https://www.weather.gov/ If you would like to display weather information for international locations (outside of the USA), please checkout a fork of this project created by [@mwood77](https://github.com/mwood77): - [`ws4kp-international`](https://github.com/mwood77/ws4kp-international) +## Deployment Modes + +WeatherStar 4000+ supports two deployment modes: + +### Server Deployment (Recommended) + +* Includes Node.js server with caching proxy for better performance (especially when running on a local server for multiple clients) +* Server-side request deduplication and caching +* Weather API observability and logging +* Used by: `npm start`, `DIST=1 npm start`, and `Dockerfile.server` + +### Static Deployment + +* Pure client-side deployment using nginx to serve static files +* All API requests are made directly from each browser to the weather services +* Browser-based caching +* Used by: static file hosting and default `Dockerfile` + ## Run Your WeatherStar -To run via Node locally: -``` + +Ensure you have Node installed. Clone the repository: +```bash git clone https://github.com/netbymatt/ws4kp.git cd ws4kp -npm i -node index.mjs +npm install ``` -To run via Docker: +### Development Mode (individual JS files, easier debugging) +```bash +npm start ``` + +### Development Mode without proxy caching +```bash +STATIC=1 npm start +``` + +### Production Mode (minified/concatenated JS, faster loading) +```bash +npm run build +DIST=1 npm start +``` + +### Production Mode without proxy caching (simulates static Docker deployment) +```bash +npm run build +STATIC=1 DIST=1 npm start +``` + +For all modes, access WeatherStar by going to: http://localhost:8080/ + +### Key Differences + +**Development Mode (`npm start`):** +- Uses individual JavaScript module files served directly +- Easier debugging with source maps and readable code +- Slower initial load (many HTTP requests for individual files) +- Live file watching and faster development iteration + +**Production Mode (`DIST=1 npm start`):** +- Uses minified and concatenated JavaScript bundles +- Faster initial load (fewer HTTP requests, smaller file sizes) +- Optimized for performance with multiple clients +- Requires `npm run build` to generate optimized files + +### Docker Deployments + +To run via Docker using a "static deployment" where everything happens in the browser (no server component, like STATIC=1): + +```bash docker run -p 8080:8080 ghcr.io/netbymatt/ws4kp ``` -Open your web browser: http://localhost:8080/ -To run via Docker Compose (docker-compose.yaml): +To run via Docker using a "server deployment" with a caching proxy server for multi-client performance and enhanced observability (like `npm run build; DIST=1 npm start`): + +```bash +docker build -f Dockerfile.server -t ws4kp-server . +docker run -p 8080:8080 ws4kp-server ``` + +To run via Docker Compose (shown here in static deployment mode): + +```yaml --- services: ws4kp: image: ghcr.io/netbymatt/ws4kp container_name: ws4kp - environment: + environment: # Each argument in the permalink URL can become an environment variable on the Docker host by adding WSQS_ # Following the "Sharing a Permalink" example below, here are a few environment variables defined. Visit that section for a # more complete list of configuration options. @@ -73,26 +139,33 @@ services: restart: unless-stopped ``` -### Serving static files -The app can be served as a static set of files on any web server. Run the provided gulp task to create a set of static distribution files: -``` +### Serving a static app + +There are several ways to deploy WeatherStar as a static app that runs entirely in the browser: + +**Manual static hosting (Apache, nginx, CDN, etc.):** +Build static distribution files for upload to any web server: + +```bash npm run build ``` -The resulting files will be in the /dist folder in the root of the project. These can then be uploaded to a web server for hosting, no server-side scripting is required. -When using the provided Docker image, the browser will generate `playlist.json` -on the fly by scanning the `/music` directory served by nginx. The image -intentionally omits this file so the page falls back to scanning the directory. -Simply bind mount your music folder and the playlist will be created -automatically. If no files are found in `/music`, the built in tracks located in -`/music/default/` will be used instead. +The resulting files in `/dist` can be uploaded to any web server; no server-side scripting is required. -The nginx configuration also sets the `X-Weatherstar: true` header on all -responses. This uses `add_header ... always` so the header is sent even for -404 responses. When `playlist.json` returns a 404 with this header present, the -browser falls back to scanning the `/music` directory. If you host the static -files elsewhere, be sure to include this header so the playlist can be generated -automatically. +**Docker static deployment:** +The default Docker image uses nginx to serve pre-built static files: + +```bash +docker run -p 8080:8080 ghcr.io/netbymatt/ws4kp +``` + +**Node.js in static mode:** +Use the Node.js server as a static file host without the caching proxy: + +```bash +STATIC=1 npm start # Use Express to serve development files +STATIC=1 DIST=1 npm start # Use Express to serve (minimized) production files +``` ## What's different @@ -135,7 +208,52 @@ Environment variables that are to be added to the default query string are prefi When using the Docker container, these environment variables are read on container start-up to generate the static redirect HTML. +## Settings + +**Speed:** Controls the playback speed multiplier of the displays, from "Very Fast" (1.5x) to "Very Slow" (0.5x) with "Normal" being 1x + +**Widescreen:** Stretches the background to 16:9 to avoid "pillarboxing" on modern displays + +**Kiosk:** Immediately activates kiosk mode, which hides all settings. Exit by refreshing the page or using `Ctrl-K`. (Kiosk mode is similar to clicking the "Fullscreen" icon, but scales to the current browser viewport instead of activating the browser's actual "Fullscreen" mode.) + +**Sticky Kiosk:** When enabled, stores the kiosk mode preference in local storage so the page automatically enters kiosk mode (maximizing the size of the main weather display without any settings) on subsequent visits. This feature is designed primarily for **iPhone and iPad users** who want to create a Home Screen app experience, since Mobile Safari doesn't support PWA installation via manifest.json or the Fullscreen API: + +**For iOS/iPadOS (Mobile Safari):** + +1. Tap the _Share_ icon and choose **Add to Home Screen** +2. Adjust the name as desired and tap **Add** +3. Launch the newly-created Home Screen shortcut +4. Configure all settings +5. Tap to enable **Sticky Kiosk** +6. _Make sure everything is configured exactly like you want it!_ +7. Tap **Kiosk** + +**For Android and Desktop browsers:** The included `manifest.json` file enables PWA (Progressive Web App) installation. To get the best app-like experience: + +1. Configure all your settings first (ignore the "Kiosk" and "Sticky Kiosk" settings) +2. Create a permalink using the "Copy Permalink" feature and manually add `&kiosk=true` to the end +3. Open the edited permalink URL in your browser +4. Look for browser prompts to "Install" or "Add to Home Screen" from the kiosk-enabled URL +5. The PWA will launch directly into kiosk mode (without forcing kiosk mode when accessed from the browser) + +For temporary fullscreen during regular browsing, use the fullscreen button in the toolbar. + +**Important Notes:** + +* **iOS/iPadOS limitations**: Mobile Safari strips all URL parameters when adding to Home Screen and runs shortcuts in an isolated environment with separate storage from the main Safari app +* After creating a Home Screen app on iOS or iPadOS and activating Kiosk mode, the only way to change settings is to delete the Home Screen shortcut and recreate it +* In situations where you _can_ edit a shortcut's URL, you can forcibly remove a "sticky" kiosk setting by adding `&kiosk=false` to the URL (or simply press `Ctrl-K` to exit kiosk mode if a keyboard is available) + +**Scan Lines:** Enables a retro-style scan line effect + +**Scan Lines Style:** Override the "auto" setting in case you prefer a different scale factor than what the automatic heuristics select for your browser and display + +**Units:** Switches between US and metric units. (Note that some text-based products from the National Weather Service APIs contain embedded units that are not converted.) + +**Volume:** Controls the audio level when music is enabled + ## Music + The WeatherStar had wonderful background music from the smooth jazz and new age genres by artists of the time. Lists of the music that played are available by searching online, but it's all copyrighted music and would be difficult to provide as part of this repository. I've used AI tools to create WeatherStar-inspired music tracks that are unencumbered by copyright and are included in this repo. To keep the size down, I've only included 4 tracks. Additional tracks are in a companion repository [ws4kp-music](https://github.com/netbymatt/ws4kp-music). @@ -143,16 +261,42 @@ I've used AI tools to create WeatherStar-inspired music tracks that are unencumb If you're looking for the original music that played during forecasts [TWCClassics](https://twcclassics.com/audio/) has thorough documentation of playlists. ### Customizing the music -Placing .mp3 files in the `/server/music` folder will override the default music included in the repo. Subdirectories will not be scanned. When weatherstar loads in the browser it will load a list if available files and randomize the order when it starts playing. On each loop through the available tracks the order will again be shuffled. If you're using the static files method to host your WeatherStar music is located in `/music`. -If using Docker, you can bind mount a local folder containing your music files. -Mount the folder at `/usr/share/nginx/html/music` so the browser can read the -directory listing and build the playlist automatically. If there are no `.mp3` -files in `/music`, the built in tracks from `/music/default/` are used. +WeatherStar 4000+ supports background music during forecast playback. The music behavior depends on how you deploy the application: + +#### Express server modes (`npm start`, `DIST=1 npm start`, or `Dockerfile.server`) + +When running with Node.js, the server generates a `playlist.json` file by scanning the `./server/music` directory for `.mp3` files. If no files are found in `./server/music`, it falls back to scanning `./server/music/default/`. The playlist is served dynamically at the `/playlist.json` endpoint. + +**Adding your own music:** Place `.mp3` files in `./server/music/` + +**Docker server example:** +```bash +docker build -f Dockerfile.server -t ws4kp-server . +docker run -p 8080:8080 -v /path/to/local/music:/app/server/music ws4kp-server ``` + +#### Static hosting modes (default `Dockerfile`, nginx, Apache, etc.) + +When hosting static files, there are two scenarios: + +**Static Docker deployment:** The build process creates a `playlist.json` file with default tracks, but the Docker image _intentionally_ removes it to force browser-based directory scanning. The browser attempts to fetch `playlist.json`, receives a 404 response with the `X-Weatherstar` header, which causes it to fallback to scanning the `music/` directory. + +**Manual static hosting:** If you build and upload the files yourself (`npm run build`), `playlist.json` will contain the default tracks unless you customize `./server/music/` before building. + +For directory scanning to work properly: +* Your web server must generate directory listings for the `music/` path +* Your web server must set the `X-Weatherstar: true` header (the provided nginx configuration does this) + +**Adding your own music:** Place `.mp3` files in `music/` (or bind mount to `/usr/share/nginx/html/music` for Docker) + +**Docker static example:** +```bash docker run -p 8080:8080 -v /path/to/local/music:/usr/share/nginx/html/music ghcr.io/netbymatt/ws4kp ``` +Subdirectories will not be scanned. When WeatherStar loads in the browser, it randomizes the track order and reshuffles on each loop through the playlist. + ### Music doesn't auto play Ws4kp is muted by default, but if it was unmuted on the last visit it is coded to try and auto play music on subsequent visits. But, it's considered bad form to have a web site play music automatically on load, and I fully agree with this. [Chrome](https://developer.chrome.com/blog/autoplay/#media_engagement_index) and [Firefox](https://hacks.mozilla.org/2019/02/firefox-66-to-block-automatically-playing-audible-video-and-audio/) have extensive details on how and when auto play is allowed. @@ -172,9 +316,13 @@ Thanks to the WeatherStar community for providing these discussions to further e * [ws4channels](https://github.com/rice9797/ws4channels) A Dockerized Node.js application to stream WeatherStar 4000 data into Channels DVR using Puppeteer and FFmpeg. ## Customization -A hook is provided as `/server/scripts/custom.js` to allow customizations to your own fork of this project, without accidentally pushing your customizations back upstream to the git repository. A sample file is provided at `/server/scripts/custom.sample.js` and should be renamed to `custom.js` activate it. -When using Docker, mount your `custom.js` file to `/usr/share/nginx/html/scripts/custom.js` to customize the static build. +A hook is provided as `server/scripts/custom.js` to allow customizations to your own fork of this project, without accidentally pushing your customizations back upstream to the git repository. A sample file is provided at `server/scripts/custom.sample.js` and should be renamed to `custom.js` activate it. + +When using Docker: + +* **Static deployment**: Mount your `custom.js` file to `/usr/share/nginx/html/scripts/custom.js` +* **Server deployment**: Mount your `custom.js` file to `/app/server/scripts/custom.js` ### RSS feeds and custom scroll If you would like your Weatherstar to have custom scrolling text in the bottom blue bar, or show headlines from an rss feed turn on the setting for `Enable RSS Feed/Text` and then enter a URL or text in the resulting text box. Then press set. diff --git a/datagenerators/output/stations-raw.json b/datagenerators/output/stations-raw.json new file mode 100644 index 0000000..4a76663 --- /dev/null +++ b/datagenerators/output/stations-raw.json @@ -0,0 +1,16130 @@ +{ + "KBID": { + "id": "KBID", + "city": "Block Island State Airport", + "state": "RI", + "lat": 41.1694699, + "lon": -71.5787299 + }, + "KOQU": { + "id": "KOQU", + "city": "N. Kingston / Quonset", + "state": "RI", + "lat": 41.6, + "lon": -71.41667 + }, + "KPVD": { + "id": "KPVD", + "city": "Rhode Island TF Green International Airport", + "state": "RI", + "lat": 41.72233, + "lon": -71.4277199 + }, + "KSFZ": { + "id": "KSFZ", + "city": "Pawtucket, North Central State Airport", + "state": "RI", + "lat": 41.91667, + "lon": -71.5 + }, + "KUUU": { + "id": "KUUU", + "city": "Newport, Newport State Airport", + "state": "RI", + "lat": 41.53, + "lon": -71.28361 + }, + "KWST": { + "id": "KWST", + "city": "Westerly, Westerly State Airport", + "state": "RI", + "lat": 41.34972, + "lon": -71.79889 + }, + "KDOV": { + "id": "KDOV", + "city": "Dover Air Force Base", + "state": "DE", + "lat": 39.13333, + "lon": -75.4666699 + }, + "KGED": { + "id": "KGED", + "city": "Georgetown - Delaware Coastal Airport", + "state": "DE", + "lat": 38.68974, + "lon": -75.36245 + }, + "KILG": { + "id": "KILG", + "city": "Wilmington, New Castle County Airport", + "state": "DE", + "lat": 39.67442, + "lon": -75.60567 + }, + "KAFO": { + "id": "KAFO", + "city": "Afton WY", + "state": "WY", + "lat": 42.7113299, + "lon": -110.94217 + }, + "KARL": { + "id": "KARL", + "city": "I80 - Arlington", + "state": "WY", + "lat": 41.5980599, + "lon": -106.21487 + }, + "KBFU": { + "id": "KBFU", + "city": "WY59 - Belle Fourche", + "state": "WY", + "lat": 43.93253, + "lon": -105.4467 + }, + "KBIT": { + "id": "KBIT", + "city": "I80/US30 - Bitter Creek", + "state": "WY", + "lat": 41.64599, + "lon": -108.5836 + }, + "KBPI": { + "id": "KBPI", + "city": "Big Piney - Marbleton Airport", + "state": "WY", + "lat": 42.57805, + "lon": -110.10972 + }, + "KBRX": { + "id": "KBRX", + "city": "I25/US87 - Bordeaux Interchange", + "state": "WY", + "lat": 41.93066, + "lon": -104.9436 + }, + "KBVR": { + "id": "KBVR", + "city": "US287/WY789 - Beaver Rim", + "state": "WY", + "lat": 42.58565, + "lon": -108.28199 + }, + "KBYG": { + "id": "KBYG", + "city": "Buffalo - Johnson County Airport", + "state": "WY", + "lat": 44.38122, + "lon": -106.71947 + }, + "KCHJ": { + "id": "KCHJ", + "city": "WY296 - Chief Joseph", + "state": "WY", + "lat": 44.73997, + "lon": -109.38088 + }, + "KCMS": { + "id": "KCMS", + "city": "I80/US30 - Peru Hill", + "state": "WY", + "lat": 41.54958, + "lon": -109.60197 + }, + "KCOD": { + "id": "KCOD", + "city": "Cody", + "state": "WY", + "lat": 44.51667, + "lon": -109.01667 + }, + "KCPR": { + "id": "KCPR", + "city": "Casper, Natrona County International Airport", + "state": "WY", + "lat": 42.8975, + "lon": -106.47306 + }, + "KCTD": { + "id": "KCTD", + "city": "I80/US30 - Continental Divide", + "state": "WY", + "lat": 41.71586, + "lon": -107.78256 + }, + "KCYS": { + "id": "KCYS", + "city": "Cheyenne, Cheyenne Airport", + "state": "WY", + "lat": 41.15789, + "lon": -104.80812 + }, + "KDGW": { + "id": "KDGW", + "city": "Douglas, Converse County Airport", + "state": "WY", + "lat": 42.79417, + "lon": -105.38194 + }, + "KDHS": { + "id": "KDHS", + "city": "I90 - Dead Horse", + "state": "WY", + "lat": 44.21906, + "lon": -106.10478 + }, + "KDRC": { + "id": "KDRC", + "city": "I25 - Deer Creek", + "state": "WY", + "lat": 42.83687, + "lon": -105.86063 + }, + "KDUB": { + "id": "KDUB", + "city": "Dubois Municipal Airport", + "state": "WY", + "lat": 43.5484, + "lon": -109.6903 + }, + "KDWX": { + "id": "KDWX", + "city": "Dixon Airport", + "state": "WY", + "lat": 41.03704, + "lon": -107.49976 + }, + "KEAN": { + "id": "KEAN", + "city": "Phifer Airfield - Wheatland", + "state": "WY", + "lat": 42.05472, + "lon": -104.93711 + }, + "KECS": { + "id": "KECS", + "city": "Mondell Field", + "state": "WY", + "lat": 43.8854, + "lon": -104.3179 + }, + "KEHY": { + "id": "KEHY", + "city": "Elk Mountain AWOS", + "state": "WY", + "lat": 41.7253, + "lon": -106.4594 + }, + "KEMM": { + "id": "KEMM", + "city": "KEMMERER", + "state": "WY", + "lat": 41.82, + "lon": -110.56 + }, + "KEVW": { + "id": "KEVW", + "city": "Evanston-Uinta County Airport - Burns Field", + "state": "WY", + "lat": 41.27306, + "lon": -111.03056 + }, + "KFBR": { + "id": "KFBR", + "city": "Fort Bridger WY", + "state": "WY", + "lat": 41.392, + "lon": -110.40683 + }, + "KFEW": { + "id": "KFEW", + "city": "Francis E Warren Air Force Base Heliport", + "state": "WY", + "lat": 41.13332, + "lon": -104.8671899 + }, + "KFIR": { + "id": "KFIR", + "city": "I80/US189 - First Divide", + "state": "WY", + "lat": 41.27649, + "lon": -110.80066 + }, + "KGCC": { + "id": "KGCC", + "city": "Gillette, Gillette-Campbell County Airport", + "state": "WY", + "lat": 44.33944, + "lon": -105.54194 + }, + "KGEY": { + "id": "KGEY", + "city": "South Big Horn County Airport", + "state": "WY", + "lat": 44.5174, + "lon": -108.0752 + }, + "KGUN": { + "id": "KGUN", + "city": "US85 - Gun Barrel", + "state": "WY", + "lat": 41.44368, + "lon": -104.34428 + }, + "KGUR": { + "id": "KGUR", + "city": "Camp Guernsey", + "state": "WY", + "lat": 42.2597, + "lon": -104.7283 + }, + "KHLD": { + "id": "KHLD", + "city": "US20/US26 - Hiland", + "state": "WY", + "lat": 43.0923, + "lon": -107.32198 + }, + "KHSG": { + "id": "KHSG", + "city": "Hot Springs County Airport", + "state": "WY", + "lat": 43.7136, + "lon": -108.3897 + }, + "KIDV": { + "id": "KIDV", + "city": "I25/US87 - I-25 Divide", + "state": "WY", + "lat": 43.89864, + "lon": -106.63833 + }, + "KIKA": { + "id": "KIKA", + "city": "I90 - Inyan Kara", + "state": "WY", + "lat": 44.29414, + "lon": -104.62926 + }, + "KJAC": { + "id": "KJAC", + "city": "Jackson, Jackson Hole Airport", + "state": "WY", + "lat": 43.6, + "lon": -110.73333 + }, + "KLAR": { + "id": "KLAR", + "city": "Laramie Regional Airport", + "state": "WY", + "lat": 41.3165, + "lon": -105.67287 + }, + "KLND": { + "id": "KLND", + "city": "Lander", + "state": "WY", + "lat": 42.81472, + "lon": -108.72806 + }, + "KMTR": { + "id": "KMTR", + "city": "WY120 - Meeteetse Rim", + "state": "WY", + "lat": 44.27011, + "lon": -108.87343 + }, + "KPAT": { + "id": "KPAT", + "city": "WY220 - Pathfinder", + "state": "WY", + "lat": 42.5581, + "lon": -106.8453399 + }, + "KPER": { + "id": "KPER", + "city": "I80/US30 - Green River Tunnel East", + "state": "WY", + "lat": 41.53186, + "lon": -109.45995 + }, + "KPNA": { + "id": "KPNA", + "city": "Pinedale, Ralph Wenz Field Airport", + "state": "WY", + "lat": 42.79528, + "lon": -109.80694 + }, + "KPOY": { + "id": "KPOY", + "city": "Powell Municipal Airport", + "state": "WY", + "lat": 44.8671999, + "lon": -108.7934 + }, + "KPUM": { + "id": "KPUM", + "city": "US287 - Pumpkin Vine", + "state": "WY", + "lat": 41.05218, + "lon": -105.46906 + }, + "KREC": { + "id": "KREC", + "city": "WY28 - Lower Red Canyon", + "state": "WY", + "lat": 42.61795, + "lon": -108.61093 + }, + "KRIW": { + "id": "KRIW", + "city": "Riverton Regional Airport", + "state": "WY", + "lat": 43.06219, + "lon": -108.44701 + }, + "KRKS": { + "id": "KRKS", + "city": "Rock Springs, Rock Springs-Sweetwater County Airport", + "state": "WY", + "lat": 41.59417, + "lon": -109.06528 + }, + "KRWL": { + "id": "KRWL", + "city": "Rawlins Municipal Airport", + "state": "WY", + "lat": 41.80648, + "lon": -107.19516 + }, + "KSAA": { + "id": "KSAA", + "city": "Saratoga WY", + "state": "WY", + "lat": 41.44483, + "lon": -106.8235 + }, + "KSGE": { + "id": "KSGE", + "city": "US30 - Sage Junction", + "state": "WY", + "lat": 41.82447, + "lon": -110.90764 + }, + "KSHC": { + "id": "KSHC", + "city": "WY372 - Shute Creek", + "state": "WY", + "lat": 41.94409, + "lon": -110.00399 + }, + "KSHR": { + "id": "KSHR", + "city": "Sheridan County Airport", + "state": "WY", + "lat": 44.7603099, + "lon": -106.97411 + }, + "KSKL": { + "id": "KSKL", + "city": "WY230 - Skyline", + "state": "WY", + "lat": 41.13753, + "lon": -106.57687 + }, + "KSOU": { + "id": "KSOU", + "city": "WY28 - South Pass", + "state": "WY", + "lat": 42.47752, + "lon": -108.8444 + }, + "KTBX": { + "id": "KTBX", + "city": "Boysen", + "state": "WY", + "lat": 43.4667, + "lon": -108.2333 + }, + "KTET": { + "id": "KTET", + "city": "WY22 - Teton Pass", + "state": "WY", + "lat": 43.49873, + "lon": -110.9562 + }, + "KTMH": { + "id": "KTMH", + "city": "I25/US87 - Twenty Mile Hill", + "state": "WY", + "lat": 43.12271, + "lon": -106.33705 + }, + "KTOR": { + "id": "KTOR", + "city": "Torrington Municipal Airport", + "state": "WY", + "lat": 42.06134, + "lon": -104.15842 + }, + "KVDW": { + "id": "KVDW", + "city": "I80/US30 - Vedauwoo", + "state": "WY", + "lat": 41.15687, + "lon": -105.40237 + }, + "KWRL": { + "id": "KWRL", + "city": "Worland, Worland Municipal Airport", + "state": "WY", + "lat": 43.9658299, + "lon": -107.95083 + }, + "KWTR": { + "id": "KWTR", + "city": "I25/US87 - Whitaker", + "state": "WY", + "lat": 41.41772, + "lon": -104.87502 + }, + "KWYH": { + "id": "KWYH", + "city": "I25/US87 - Wyo Hill", + "state": "WY", + "lat": 41.04746, + "lon": -104.8901 + }, + "KACK": { + "id": "KACK", + "city": "Nantucket, Nantucket Memorial Airport", + "state": "MA", + "lat": 41.25389, + "lon": -70.05972 + }, + "KAQW": { + "id": "KAQW", + "city": "North Adams Harriman-and-West Airport", + "state": "MA", + "lat": 42.69731, + "lon": -73.16955 + }, + "KBAF": { + "id": "KBAF", + "city": "Westfield, Barnes Municipal Airport", + "state": "MA", + "lat": 42.15972, + "lon": -72.71278 + }, + "KBED": { + "id": "KBED", + "city": "Laurence G Hanscom Field Airport", + "state": "MA", + "lat": 42.46811, + "lon": -71.29463 + }, + "KBOS": { + "id": "KBOS", + "city": "Boston, Logan International Airport", + "state": "MA", + "lat": 42.36056, + "lon": -71.01056 + }, + "KBVY": { + "id": "KBVY", + "city": "Beverly, Beverly Municipal Airport", + "state": "MA", + "lat": 42.58361, + "lon": -70.91639 + }, + "KCEF": { + "id": "KCEF", + "city": "Chicopee Falls / Westover Air Force Base", + "state": "MA", + "lat": 42.2, + "lon": -72.53333 + }, + "KCQX": { + "id": "KCQX", + "city": "Chatham, Chatham Municipal Airport", + "state": "MA", + "lat": 41.6875, + "lon": -69.99333 + }, + "KEWB": { + "id": "KEWB", + "city": "New Bedford, New Bedford Regional Airport", + "state": "MA", + "lat": 41.67528, + "lon": -70.95694 + }, + "KFIT": { + "id": "KFIT", + "city": "Fitchburg, Fitchburg Municipal Airport", + "state": "MA", + "lat": 42.55194, + "lon": -71.75583 + }, + "KFMH": { + "id": "KFMH", + "city": "Otis Air National Guard Base", + "state": "MA", + "lat": 41.65, + "lon": -70.51667 + }, + "KGHG": { + "id": "KGHG", + "city": "Marshfield Airport", + "state": "MA", + "lat": 42.0983, + "lon": -70.6722 + }, + "KHYA": { + "id": "KHYA", + "city": "Hyannis, Barnstable Municipal-Boardman Airport", + "state": "MA", + "lat": 41.67194, + "lon": -70.26972 + }, + "KLWM": { + "id": "KLWM", + "city": "Lawrence Municipal Airport", + "state": "MA", + "lat": 42.7126, + "lon": -71.12553 + }, + "KMVY": { + "id": "KMVY", + "city": "Marthas Vineyard Airport", + "state": "MA", + "lat": 41.39298, + "lon": -70.61588 + }, + "KORE": { + "id": "KORE", + "city": "Orange Municipal Airport", + "state": "MA", + "lat": 42.57, + "lon": -72.28693 + }, + "KORH": { + "id": "KORH", + "city": "Worcester, Worcester Regional Airport", + "state": "MA", + "lat": 42.27056, + "lon": -71.87306 + }, + "KOWD": { + "id": "KOWD", + "city": "Norwood, Norwood Memorial Airport", + "state": "MA", + "lat": 42.19083, + "lon": -71.17389 + }, + "KPSF": { + "id": "KPSF", + "city": "Pittsfield Municipal Airport", + "state": "MA", + "lat": 42.42691, + "lon": -73.28897 + }, + "KPVC": { + "id": "KPVC", + "city": "Provincetown Municipal Airport", + "state": "MA", + "lat": 42.07436, + "lon": -70.21816 + }, + "KPYM": { + "id": "KPYM", + "city": "Plymouth, Plymouth Municipal Airport", + "state": "MA", + "lat": 41.90861, + "lon": -70.72806 + }, + "KTAN": { + "id": "KTAN", + "city": "Taunton, Taunton Municipal Airport", + "state": "MA", + "lat": 41.87556, + "lon": -71.0211099 + }, + "KADF": { + "id": "KADF", + "city": "Dexter B Florence Memorial Field", + "state": "AR", + "lat": 34.0998, + "lon": -93.0661 + }, + "KAGO": { + "id": "KAGO", + "city": "Ralph C Weiser Field Airport", + "state": "AR", + "lat": 33.2274699, + "lon": -93.217 + }, + "KARG": { + "id": "KARG", + "city": "Walnut Ridge Regional Airport", + "state": "AR", + "lat": 36.12562, + "lon": -90.92148 + }, + "KASG": { + "id": "KASG", + "city": "Springdale Municipal", + "state": "AR", + "lat": 36.18333, + "lon": -94.11667 + }, + "KAWM": { + "id": "KAWM", + "city": "West Memphis, West Memphis Municipal Airport", + "state": "AR", + "lat": 35.13333, + "lon": -90.23333 + }, + "KBPK": { + "id": "KBPK", + "city": "Baxter County Airport", + "state": "AR", + "lat": 36.37056, + "lon": -92.47194 + }, + "KBVX": { + "id": "KBVX", + "city": "Batesville, Batesville Regional Airport", + "state": "AR", + "lat": 35.73333, + "lon": -91.65 + }, + "KCCA": { + "id": "KCCA", + "city": "Clinton Memorial Airfield", + "state": "AR", + "lat": 35.598, + "lon": -92.4516 + }, + "KCDH": { + "id": "KCDH", + "city": "Camden / Harrell Field", + "state": "AR", + "lat": 33.61667, + "lon": -92.76667 + }, + "KCXW": { + "id": "KCXW", + "city": "Conway - Cantrell Field", + "state": "AR", + "lat": 35.0199, + "lon": -92.5551 + }, + "KDEQ": { + "id": "KDEQ", + "city": "De Queen, J Lynn Helms Sevier County Airport", + "state": "AR", + "lat": 34.04694, + "lon": -94.39944 + }, + "KDRP": { + "id": "KDRP", + "city": "Delta Regional Airport", + "state": "AR", + "lat": 35.12005, + "lon": -90.8265 + }, + "KELD": { + "id": "KELD", + "city": "South Arkansas Regional Airport", + "state": "AR", + "lat": 33.22075, + "lon": -92.8139999 + }, + "KFLP": { + "id": "KFLP", + "city": "Flippin, Marion County Regional Airport", + "state": "AR", + "lat": 36.3, + "lon": -92.58333 + }, + "KFSM": { + "id": "KFSM", + "city": "Fort Smith Regional Airport", + "state": "AR", + "lat": 35.3335, + "lon": -94.36524 + }, + "KFYV": { + "id": "KFYV", + "city": "Fayetteville, Drake Field", + "state": "AR", + "lat": 36.01028, + "lon": -94.1677799 + }, + "KHKA": { + "id": "KHKA", + "city": "Blytheville, Blytheville Municipal Airport", + "state": "AR", + "lat": 35.93889, + "lon": -89.8325 + }, + "KHOT": { + "id": "KHOT", + "city": "Hot Springs, Memorial Field Airport", + "state": "AR", + "lat": 34.47806, + "lon": -93.09611 + }, + "KHRO": { + "id": "KHRO", + "city": "Harrison, Boone County Airport", + "state": "AR", + "lat": 36.26167, + "lon": -93.15472 + }, + "KJBR": { + "id": "KJBR", + "city": "Jonesboro, Jonesboro Municipal Airport", + "state": "AR", + "lat": 35.83722, + "lon": -90.64306 + }, + "KLIT": { + "id": "KLIT", + "city": "Little Rock, Adams Field", + "state": "AR", + "lat": 34.72667, + "lon": -92.23611 + }, + "KLLQ": { + "id": "KLLQ", + "city": "Monticello, Monticello Municipal Airport/Ellis Field", + "state": "AR", + "lat": 33.63833, + "lon": -91.75111 + }, + "KLRF": { + "id": "KLRF", + "city": "Little Rock Air Force Base", + "state": "AR", + "lat": 34.91667, + "lon": -92.15 + }, + "KMEZ": { + "id": "KMEZ", + "city": "Mena, Mena Intermountain Municipal Airport", + "state": "AR", + "lat": 34.54528, + "lon": -94.2025 + }, + "KMWT": { + "id": "KMWT", + "city": "Mount Ida", + "state": "AR", + "lat": 34.55, + "lon": -93.58333 + }, + "KORK": { + "id": "KORK", + "city": "North Little Rock Municipal Airport", + "state": "AR", + "lat": 34.83314, + "lon": -92.25414 + }, + "KPBF": { + "id": "KPBF", + "city": "Pine Bluff, Grider Field Airport", + "state": "AR", + "lat": 34.175, + "lon": -91.93472 + }, + "KROG": { + "id": "KROG", + "city": "Rogers - Rogers Executive Airport - Carter Field", + "state": "AR", + "lat": 36.36667, + "lon": -94.1 + }, + "KRUE": { + "id": "KRUE", + "city": "Russelville Municipal Airport", + "state": "AR", + "lat": 35.25737, + "lon": -93.0949399 + }, + "KSGT": { + "id": "KSGT", + "city": "Stuttgart, Stuttgart Municipal Airport", + "state": "AR", + "lat": 34.6, + "lon": -91.56667 + }, + "KSLG": { + "id": "KSLG", + "city": "Siloam Springs, Smith Field Airport", + "state": "AR", + "lat": 36.2, + "lon": -94.48333 + }, + "KSRC": { + "id": "KSRC", + "city": "Searcy Municipal Airport", + "state": "AR", + "lat": 35.21349, + "lon": -91.7392799 + }, + "KSUZ": { + "id": "KSUZ", + "city": "Saline County Regional Airport", + "state": "AR", + "lat": 34.59039, + "lon": -92.47944 + }, + "KTXK": { + "id": "KTXK", + "city": "Texarkana, Texarkana Regional-Webb Field", + "state": "AR", + "lat": 33.45611, + "lon": -93.9875 + }, + "KVBT": { + "id": "KVBT", + "city": "Bentonville, Bentonville Municipal Airport/Louise M Thaden Field", + "state": "AR", + "lat": 36.35, + "lon": -94.2166699 + }, + "KXNA": { + "id": "KXNA", + "city": "Northwest Arkansas Regional Airport", + "state": "AR", + "lat": 36.28977, + "lon": -94.3114499 + }, + "KACQ": { + "id": "KACQ", + "city": "Waseca Municipal Airport", + "state": "MN", + "lat": 44.07024, + "lon": -93.55342 + }, + "KADC": { + "id": "KADC", + "city": "Wadena Municipal Airport", + "state": "MN", + "lat": 46.45022, + "lon": -95.21353 + }, + "KAEL": { + "id": "KAEL", + "city": "Albert Lea, Albert Lea Municipal Airport", + "state": "MN", + "lat": 43.68333, + "lon": -93.36667 + }, + "KAIT": { + "id": "KAIT", + "city": "Aitkin Municipal Airport - Steve Kurtz Field", + "state": "MN", + "lat": 46.54899, + "lon": -93.67573 + }, + "KANE": { + "id": "KANE", + "city": "Minneapolis / Blaine", + "state": "MN", + "lat": 45.14258, + "lon": -93.21272 + }, + "KAQP": { + "id": "KAQP", + "city": "Appleton Municipal Airport", + "state": "MN", + "lat": 45.22488, + "lon": -96.00412 + }, + "KAUM": { + "id": "KAUM", + "city": "Austin Municipal", + "state": "MN", + "lat": 43.66667, + "lon": -92.93333 + }, + "KAXN": { + "id": "KAXN", + "city": "Alexandria, Chandler Field", + "state": "MN", + "lat": 45.8686099, + "lon": -95.39417 + }, + "KBBB": { + "id": "KBBB", + "city": "Benson Municipal Airport", + "state": "MN", + "lat": 45.3309799, + "lon": -95.64692 + }, + "KBDE": { + "id": "KBDE", + "city": "Baudette International Airport", + "state": "MN", + "lat": 48.72605, + "lon": -94.61215 + }, + "KBDH": { + "id": "KBDH", + "city": "Willmar Municipal Airport - John L. Rice Field", + "state": "MN", + "lat": 45.11113, + "lon": -95.1258299 + }, + "KBJI": { + "id": "KBJI", + "city": "Bemidji", + "state": "MN", + "lat": 47.50762, + "lon": -94.92783 + }, + "KBRD": { + "id": "KBRD", + "city": "Brainerd - Crow Wing County Airport", + "state": "MN", + "lat": 46.40205, + "lon": -94.12734 + }, + "KCBG": { + "id": "KCBG", + "city": "Cambridge Municipal Airport", + "state": "MN", + "lat": 45.56275, + "lon": -93.26436 + }, + "KCDD": { + "id": "KCDD", + "city": "Crane Lake - Scotts Seaplane Base", + "state": "MN", + "lat": 48.26014, + "lon": -92.47485 + }, + "KCFE": { + "id": "KCFE", + "city": "Buffalo, Buffalo Municipal Airport", + "state": "MN", + "lat": 45.15889, + "lon": -93.84306 + }, + "KCKC": { + "id": "KCKC", + "city": "Grand Marais/Cook County Airport", + "state": "MN", + "lat": 47.83665, + "lon": -90.3864399 + }, + "KCKN": { + "id": "KCKN", + "city": "Crookston Municipal Field", + "state": "MN", + "lat": 47.84042, + "lon": -96.6200999 + }, + "KCNB": { + "id": "KCNB", + "city": "Canby Airfield", + "state": "MN", + "lat": 44.7295, + "lon": -96.266 + }, + "KCOQ": { + "id": "KCOQ", + "city": "Cloquet Carlton County Airport", + "state": "MN", + "lat": 46.69869, + "lon": -92.5034 + }, + "KCQM": { + "id": "KCQM", + "city": "Cook Municipal Airport", + "state": "MN", + "lat": 47.81997, + "lon": -92.68169 + }, + "KDLH": { + "id": "KDLH", + "city": "Duluth International Airport", + "state": "MN", + "lat": 46.84347, + "lon": -92.1866 + }, + "KDTL": { + "id": "KDTL", + "city": "Detroit Lakes Airport-Wething Field", + "state": "MN", + "lat": 46.8285399, + "lon": -95.88567 + }, + "KDVP": { + "id": "KDVP", + "city": "Slayton Municipal Airport", + "state": "MN", + "lat": 43.99055, + "lon": -95.78102 + }, + "KDXX": { + "id": "KDXX", + "city": "Madison, Madison-Lac Qui Parle County Airport", + "state": "MN", + "lat": 44.9839399, + "lon": -96.1788399 + }, + "KDYT": { + "id": "KDYT", + "city": "Duluth - Sky Harbor Airport", + "state": "MN", + "lat": 46.72452, + "lon": -92.0444799 + }, + "KBIX": { + "id": "KBIX", + "city": "Keesler Air Force Base / Biloxi", + "state": "MS", + "lat": 30.41667, + "lon": -88.91667 + }, + "KCBM": { + "id": "KCBM", + "city": "Columbus Air Force Base", + "state": "MS", + "lat": 33.65, + "lon": -88.45 + }, + "KCKM": { + "id": "KCKM", + "city": "Fletcher Field, Clarksdale", + "state": "MS", + "lat": 34.2997, + "lon": -90.5123 + }, + "KCRX": { + "id": "KCRX", + "city": "Corinth", + "state": "MS", + "lat": 34.915, + "lon": -88.6035 + }, + "KGLH": { + "id": "KGLH", + "city": "Greenville, Mid Delta Regional Airport", + "state": "MS", + "lat": 33.48278, + "lon": -90.98556 + }, + "KGPT": { + "id": "KGPT", + "city": "Gulfport - Gulfport-Biloxi International Airport", + "state": "MS", + "lat": 30.41194, + "lon": -89.08083 + }, + "KGTR": { + "id": "KGTR", + "city": "Columbus/West Point/Starkville, Golden Triangle Regional Airport", + "state": "MS", + "lat": 33.45, + "lon": -88.58333 + }, + "KGWO": { + "id": "KGWO", + "city": "Greenwood, Greenwood-LeFlore Airport", + "state": "MS", + "lat": 33.4925, + "lon": -90.0836099 + }, + "KHBG": { + "id": "KHBG", + "city": "Hattiesburg, Bobby L Chain Municipal Airport", + "state": "MS", + "lat": 31.26945, + "lon": -89.25613 + }, + "KHEZ": { + "id": "KHEZ", + "city": "Natchez, Hardy-Anders Field Natchez-Adams County Airport", + "state": "MS", + "lat": 31.61593, + "lon": -91.29724 + }, + "KHKS": { + "id": "KHKS", + "city": "Jackson, Hawkins Field Airport", + "state": "MS", + "lat": 32.33472, + "lon": -90.2225 + }, + "KHSA": { + "id": "KHSA", + "city": "Bay St. Louis, Stennis International Airport", + "state": "MS", + "lat": 30.36778, + "lon": -89.45472 + }, + "KIKT": { + "id": "KIKT", + "city": "Nakika Subsea Development Platform", + "state": "MS", + "lat": 28.5208, + "lon": -88.2889 + }, + "KJAN": { + "id": "KJAN", + "city": "Jackson, Jackson International Airport", + "state": "MS", + "lat": 32.3197199, + "lon": -90.0775 + }, + "KJVW": { + "id": "KJVW", + "city": "JB Williams Airport", + "state": "MS", + "lat": 32.30447, + "lon": -90.41053 + }, + "KLMS": { + "id": "KLMS", + "city": "Louisville/Winston County Airport", + "state": "MS", + "lat": 33.14599, + "lon": -89.06245 + }, + "KLUL": { + "id": "KLUL", + "city": "LAUREL/NOBLE FIELD", + "state": "MS", + "lat": 31.67, + "lon": -89.17 + }, + "KMBO": { + "id": "KMBO", + "city": "Madison Bruce Campbell Field Airport", + "state": "MS", + "lat": 32.4384, + "lon": -90.1014 + }, + "KMCB": { + "id": "KMCB", + "city": "McComb, McComb / Pike County / John E Lewis Field Airport", + "state": "MS", + "lat": 31.17833, + "lon": -90.47194 + }, + "KMEI": { + "id": "KMEI", + "city": "Meridian, Key Field", + "state": "MS", + "lat": 32.33806, + "lon": -88.74778 + }, + "KMJD": { + "id": "KMJD", + "city": "Picayune Municipal Airport", + "state": "MS", + "lat": 30.48747, + "lon": -89.65119 + }, + "KMPE": { + "id": "KMPE", + "city": "Philadelphia Municipal Airport", + "state": "MS", + "lat": 32.79921, + "lon": -89.12599 + }, + "KNJW": { + "id": "KNJW", + "city": "Meridian, Joe Williams Naval Outlying Field", + "state": "MS", + "lat": 32.79611, + "lon": -88.83167 + }, + "KNMM": { + "id": "KNMM", + "city": "Meridian, Meridian Naval Air Station - McCain Field", + "state": "MS", + "lat": 32.55194, + "lon": -88.55528 + }, + "KOLV": { + "id": "KOLV", + "city": "Olive Branch, Olive Branch Airport", + "state": "MS", + "lat": 34.97889, + "lon": -89.78694 + }, + "KPIB": { + "id": "KPIB", + "city": "Hattiesburg/Laurel, Hattiesburg-Laurel Regional Airport", + "state": "MS", + "lat": 31.46667, + "lon": -89.33333 + }, + "KPMU": { + "id": "KPMU", + "city": "Batesville Panola County", + "state": "MS", + "lat": 34.3635, + "lon": -89.8929 + }, + "KPQL": { + "id": "KPQL", + "city": "Moss Point - Trent Lott International Airport", + "state": "MS", + "lat": 30.46305, + "lon": -88.53155 + }, + "KRNV": { + "id": "KRNV", + "city": "Cleveland Municipal Airport", + "state": "MS", + "lat": 33.7611, + "lon": -90.7579 + }, + "KSTF": { + "id": "KSTF", + "city": "George M Bryan Airport, Starkville", + "state": "MS", + "lat": 33.4331, + "lon": -88.8486 + }, + "KTUP": { + "id": "KTUP", + "city": "Tupelo, Tupelo Regional Airport", + "state": "MS", + "lat": 34.26806, + "lon": -88.77 + }, + "KUOX": { + "id": "KUOX", + "city": "Oxford, University-Oxford Airport", + "state": "MS", + "lat": 34.38444, + "lon": -89.53556 + }, + "KUTA": { + "id": "KUTA", + "city": "Tunica, Tunica Municipal Airport", + "state": "MS", + "lat": 34.68083, + "lon": -90.34639 + }, + "KVKS": { + "id": "KVKS", + "city": "Vicksburg Municipal", + "state": "MS", + "lat": 32.23333, + "lon": -90.93333 + }, + "KBDL": { + "id": "KBDL", + "city": "Windsor Locks, Bradley International Airport", + "state": "CT", + "lat": 41.93806, + "lon": -72.6825 + }, + "KBDR": { + "id": "KBDR", + "city": "Bridgeport, Sikorsky Memorial Airport", + "state": "CT", + "lat": 41.16421, + "lon": -73.12663 + }, + "KDXR": { + "id": "KDXR", + "city": "Danbury, Danbury Municipal Airport", + "state": "CT", + "lat": 41.37167, + "lon": -73.48444 + }, + "KGON": { + "id": "KGON", + "city": "Groton / New London, Groton / New London Airport", + "state": "CT", + "lat": 41.3275, + "lon": -72.04944 + }, + "KHFD": { + "id": "KHFD", + "city": "Hartford, Hartford-Brainard Airport", + "state": "CT", + "lat": 41.735, + "lon": -72.65167 + }, + "KHVN": { + "id": "KHVN", + "city": "New Haven, Tweed-New Haven Airport", + "state": "CT", + "lat": 41.26389, + "lon": -72.88722 + }, + "KIJD": { + "id": "KIJD", + "city": "Willimantic, Windham Airport", + "state": "CT", + "lat": 41.74194, + "lon": -72.18361 + }, + "KLZD": { + "id": "KLZD", + "city": "DANIELSON", + "state": "CT", + "lat": 41.8197, + "lon": -71.90096 + }, + "KMMK": { + "id": "KMMK", + "city": "Meriden, Meriden Markham Municipal Airport", + "state": "CT", + "lat": 41.50972, + "lon": -72.82778 + }, + "KOXC": { + "id": "KOXC", + "city": "Oxford, Waterbury-Oxford Airport", + "state": "CT", + "lat": 41.48333, + "lon": -73.13333 + }, + "KSNC": { + "id": "KSNC", + "city": "Chester, Chester Airport", + "state": "CT", + "lat": 41.38389, + "lon": -72.50583 + }, + "KAFK": { + "id": "KAFK", + "city": "Nebraska City, Nebraska City Municipal Airport", + "state": "NE", + "lat": 40.6, + "lon": -95.85 + }, + "KAHQ": { + "id": "KAHQ", + "city": "Wahoo", + "state": "NE", + "lat": 41.2406, + "lon": -96.5946 + }, + "KAIA": { + "id": "KAIA", + "city": "Alliance, Alliance Municipal Airport", + "state": "NE", + "lat": 42.05722, + "lon": -102.8 + }, + "KANW": { + "id": "KANW", + "city": "Ainsworth Regional Airport", + "state": "NE", + "lat": 42.57484, + "lon": -99.99832 + }, + "KAUH": { + "id": "KAUH", + "city": "Aurora, Aurora Municipal Airport", + "state": "NE", + "lat": 40.89389, + "lon": -97.99444 + }, + "KBBW": { + "id": "KBBW", + "city": "Broken Bow, Broken Bow Municipal Airport", + "state": "NE", + "lat": 41.43333, + "lon": -99.65 + }, + "KBFF": { + "id": "KBFF", + "city": "Scottsbluff, Heilig Field", + "state": "NE", + "lat": 41.86694, + "lon": -103.58583 + }, + "KBIE": { + "id": "KBIE", + "city": "Beatrice Municipal", + "state": "NE", + "lat": 40.3, + "lon": -96.75 + }, + "KBTA": { + "id": "KBTA", + "city": "Blair Municipal Airport", + "state": "NE", + "lat": 41.4148, + "lon": -96.109 + }, + "KBVN": { + "id": "KBVN", + "city": "Albion Municipal Airport", + "state": "NE", + "lat": 41.73016, + "lon": -98.05453 + }, + "KCDR": { + "id": "KCDR", + "city": "Chadron, Chadron Municipal Airport", + "state": "NE", + "lat": 42.8375, + "lon": -103.09528 + }, + "KCSB": { + "id": "KCSB", + "city": "Cambridge Municipal Airport", + "state": "NE", + "lat": 40.3065799, + "lon": -100.16207 + }, + "KEAR": { + "id": "KEAR", + "city": "Kearney, Kearney Municipal Airport", + "state": "NE", + "lat": 40.73333, + "lon": -99 + }, + "KFET": { + "id": "KFET", + "city": "Fremont Municipal Airport", + "state": "NE", + "lat": 41.45, + "lon": -96.51667 + }, + "KFNB": { + "id": "KFNB", + "city": "Falls City, Brenner Field Airport", + "state": "NE", + "lat": 40.07889, + "lon": -95.5919399 + }, + "KGGF": { + "id": "KGGF", + "city": "Grant Municipal Airport", + "state": "NE", + "lat": 40.87066, + "lon": -101.73388 + }, + "KGRI": { + "id": "KGRI", + "city": "Grand Island, Central Nebraska Regional Airport", + "state": "NE", + "lat": 40.9583299, + "lon": -98.3125 + }, + "KGRN": { + "id": "KGRN", + "city": "Gordon Municipal", + "state": "NE", + "lat": 42.8, + "lon": -102.16667 + }, + "KHDE": { + "id": "KHDE", + "city": "Brewster Field Airport", + "state": "NE", + "lat": 40.45, + "lon": -99.33333 + }, + "KHJH": { + "id": "KHJH", + "city": "Hebron, Hebron Municipal Airport", + "state": "NE", + "lat": 40.15222, + "lon": -97.58694 + }, + "KHSI": { + "id": "KHSI", + "city": "Hastings, Hastings Municipal Airport", + "state": "NE", + "lat": 40.60056, + "lon": -98.42583 + }, + "KIBM": { + "id": "KIBM", + "city": "Kimball, Kimball Municipal Airport/Robert E Arraj Field", + "state": "NE", + "lat": 41.18333, + "lon": -103.66667 + }, + "KIML": { + "id": "KIML", + "city": "Imperial, Imperial Municipal Airport", + "state": "NE", + "lat": 40.51667, + "lon": -101.61667 + }, + "KJYR": { + "id": "KJYR", + "city": "York, York Municipal Airport", + "state": "NE", + "lat": 40.89667, + "lon": -97.62278 + }, + "KLBF": { + "id": "KLBF", + "city": "North Platte, North Platte Regional Airport", + "state": "NE", + "lat": 41.12194, + "lon": -100.66833 + }, + "KLCG": { + "id": "KLCG", + "city": "Wayne, Wayne Municipal Airport", + "state": "NE", + "lat": 42.24167, + "lon": -96.98139 + }, + "KLNK": { + "id": "KLNK", + "city": "Lincoln, Lincoln Municipal Airport", + "state": "NE", + "lat": 40.83111, + "lon": -96.7644399 + }, + "KLXN": { + "id": "KLXN", + "city": "Lexington, Jim Kelly Field Airport", + "state": "NE", + "lat": 40.79111, + "lon": -99.77722 + }, + "KMCK": { + "id": "KMCK", + "city": "McCook, McCook Municipal Airport", + "state": "NE", + "lat": 40.20306, + "lon": -100.58833 + }, + "KMLE": { + "id": "KMLE", + "city": "Omaha, Millard Airport", + "state": "NE", + "lat": 41.19583, + "lon": -96.1122199 + }, + "KODX": { + "id": "KODX", + "city": "Ord, Evelyn Sharp Field Airport", + "state": "NE", + "lat": 41.62417, + "lon": -98.9525 + }, + "KOFF": { + "id": "KOFF", + "city": "Omaha / Offutt Air Force Base", + "state": "NE", + "lat": 41.11667, + "lon": -95.9 + }, + "KOFK": { + "id": "KOFK", + "city": "Norfolk, Stefan Memorial Airport", + "state": "NE", + "lat": 41.9805599, + "lon": -97.43694 + }, + "KOGA": { + "id": "KOGA", + "city": "Ogallala, Searle Field Airport", + "state": "NE", + "lat": 41.11972, + "lon": -101.76889 + }, + "KOLU": { + "id": "KOLU", + "city": "Columbus, Columbus Municipal Airport", + "state": "NE", + "lat": 41.45, + "lon": -97.33333 + }, + "KOMA": { + "id": "KOMA", + "city": "Omaha - Eppley Airfield", + "state": "NE", + "lat": 41.3119, + "lon": -95.90185 + }, + "KONL": { + "id": "KONL", + "city": "O'Neill / Baker Field", + "state": "NE", + "lat": 42.46667, + "lon": -98.68333 + }, + "KPMV": { + "id": "KPMV", + "city": "Plattsmouth, Plattsmouth Municipal Airport", + "state": "NE", + "lat": 40.95, + "lon": -95.9177799 + }, + "KSNY": { + "id": "KSNY", + "city": "Sidney, Sidney Municipal Airport", + "state": "NE", + "lat": 41.09944, + "lon": -102.98556 + }, + "KTIF": { + "id": "KTIF", + "city": "Thedford, Thomas County Airport", + "state": "NE", + "lat": 41.96194, + "lon": -100.56889 + }, + "KTQE": { + "id": "KTQE", + "city": "Tekamah, Tekamah Municipal Airport", + "state": "NE", + "lat": 41.76694, + "lon": -96.17778 + }, + "KVTN": { + "id": "KVTN", + "city": "Valentine, Miller Field", + "state": "NE", + "lat": 42.85861, + "lon": -100.55139 + }, + "KBTV": { + "id": "KBTV", + "city": "Burlington, Burlington International Airport", + "state": "VT", + "lat": 44.46806, + "lon": -73.15028 + }, + "KCDA": { + "id": "KCDA", + "city": "Caledonia County Airport", + "state": "VT", + "lat": 44.5691142, + "lon": -72.0179789 + }, + "KDDH": { + "id": "KDDH", + "city": "Bennington Morse State Airport", + "state": "VT", + "lat": 42.89355, + "lon": -73.2486 + }, + "KEFK": { + "id": "KEFK", + "city": "Northeast Kingdom International Airport", + "state": "VT", + "lat": 44.88846, + "lon": -72.23593 + }, + "KFSO": { + "id": "KFSO", + "city": "Franklin County State Airport", + "state": "VT", + "lat": 44.9402807, + "lon": -73.09746 + }, + "KMPV": { + "id": "KMPV", + "city": "Barre / Montpelier, Knapp State Airport", + "state": "VT", + "lat": 44.20472, + "lon": -72.56611 + }, + "KMVL": { + "id": "KMVL", + "city": "Morrisville-Stowe State Airport", + "state": "VT", + "lat": 44.53589, + "lon": -72.6162499 + }, + "KRUT": { + "id": "KRUT", + "city": "Rutland-Southern Vermont Regional Airport", + "state": "VT", + "lat": 43.53333, + "lon": -72.95 + }, + "KVSF": { + "id": "KVSF", + "city": "Springfield, Hartness State Springfield Airport", + "state": "VT", + "lat": 43.3425, + "lon": -72.52167 + }, + "KAIZ": { + "id": "KAIZ", + "city": "Kaiser Lake Ozark, Lee C Fine Memorial Airport", + "state": "MO", + "lat": 38.1, + "lon": -92.55 + }, + "KBBG": { + "id": "KBBG", + "city": "Branson", + "state": "MO", + "lat": 36.5321, + "lon": -93.2005 + }, + "KCDJ": { + "id": "KCDJ", + "city": "Chillicothe, Chillicothe Agri-Science Center", + "state": "MO", + "lat": 39.81667, + "lon": -93.58333 + }, + "KCGI": { + "id": "KCGI", + "city": "Cape Girardeau, Cape Girardeau Regional Airport", + "state": "MO", + "lat": 37.22556, + "lon": -89.5783299 + }, + "KCOU": { + "id": "KCOU", + "city": "Columbia, Columbia Regional Airport", + "state": "MO", + "lat": 38.81694, + "lon": -92.21833 + }, + "KDMO": { + "id": "KDMO", + "city": "Sedalia, Sedalia Memorial Airport", + "state": "MO", + "lat": 38.71222, + "lon": -93.17444 + }, + "KEOS": { + "id": "KEOS", + "city": "NEOSHOAIRPORT", + "state": "MO", + "lat": 36.8108, + "lon": -94.39169 + }, + "KEVU": { + "id": "KEVU", + "city": "Maryville Northwest Missouri Regional Airport", + "state": "MO", + "lat": 40.3525, + "lon": -94.915 + }, + "KEZZ": { + "id": "KEZZ", + "city": "Cameron Memorial Airport", + "state": "MO", + "lat": 39.7275599, + "lon": -94.27639 + }, + "KFAM": { + "id": "KFAM", + "city": "Farmington Airport", + "state": "MO", + "lat": 37.76667, + "lon": -90.43333 + }, + "KFWB": { + "id": "KFWB", + "city": "Branson West Muni - Emerson Field", + "state": "MO", + "lat": 36.6985, + "lon": -93.4021999 + }, + "KGLY": { + "id": "KGLY", + "city": "Clinton, MO", + "state": "MO", + "lat": 38.3566, + "lon": -93.6842 + }, + "KGPH": { + "id": "KGPH", + "city": "Mosby Midwest National Air Center Airport", + "state": "MO", + "lat": 39.3325, + "lon": -94.3096 + }, + "KHAE": { + "id": "KHAE", + "city": "Hannibal Regional Airport", + "state": "MO", + "lat": 39.7252, + "lon": -91.4439 + }, + "KHFJ": { + "id": "KHFJ", + "city": "Monett", + "state": "MO", + "lat": 36.9062, + "lon": -94.0128 + }, + "KIRK": { + "id": "KIRK", + "city": "Kirksville, Kirksville Regional Airport", + "state": "MO", + "lat": 40.09722, + "lon": -92.54333 + }, + "KJEF": { + "id": "KJEF", + "city": "Jefferson City, Jefferson City Memorial Airport", + "state": "MO", + "lat": 38.59444, + "lon": -92.15583 + }, + "KJLN": { + "id": "KJLN", + "city": "Joplin, Joplin Regional Airport", + "state": "MO", + "lat": 37.15611, + "lon": -94.5005599 + }, + "KLBO": { + "id": "KLBO", + "city": "LEBANON", + "state": "MO", + "lat": 37.64833, + "lon": -92.6525 + }, + "KAAS": { + "id": "KAAS", + "city": "Taylor County Airport", + "state": "KY", + "lat": 37.35828, + "lon": -85.30942 + }, + "KBRY": { + "id": "KBRY", + "city": "Samuels Field Airport", + "state": "KY", + "lat": 37.81433, + "lon": -85.49964 + }, + "KBWG": { + "id": "KBWG", + "city": "Bowling Green, Bowling Green-Warren County Regional Airport", + "state": "KY", + "lat": 36.96444, + "lon": -86.41944 + }, + "KBYL": { + "id": "KBYL", + "city": "Williamsburg-Whitley County Airport", + "state": "KY", + "lat": 36.7954099, + "lon": -84.2012699 + }, + "KCEY": { + "id": "KCEY", + "city": "Murray Kyle Oakley Field, KY", + "state": "KY", + "lat": 36.6646, + "lon": -88.3728 + }, + "KCPF": { + "id": "KCPF", + "city": "Wendell H Ford Airport", + "state": "KY", + "lat": 37.38736, + "lon": -83.26161 + }, + "KCVG": { + "id": "KCVG", + "city": "Cincinnati/Northern Kentucky International Airport", + "state": "KY", + "lat": 39.04456, + "lon": -84.67229 + }, + "KDVK": { + "id": "KDVK", + "city": "Stuart Powell Field Airport", + "state": "KY", + "lat": 37.5775751, + "lon": -84.7694978 + }, + "KDWU": { + "id": "KDWU", + "city": "Ashland Regional Airport", + "state": "KY", + "lat": 38.5545, + "lon": -82.738 + }, + "KEHR": { + "id": "KEHR", + "city": "Henderson City", + "state": "KY", + "lat": 37.81667, + "lon": -87.68333 + }, + "KEKQ": { + "id": "KEKQ", + "city": "Monticello, Wayne County Airport", + "state": "KY", + "lat": 36.85528, + "lon": -84.85611 + }, + "KEKX": { + "id": "KEKX", + "city": "Elizabethtown Addington Field Airport", + "state": "KY", + "lat": 37.686, + "lon": -85.925 + }, + "KFFT": { + "id": "KFFT", + "city": "Frankfort, Capital City Airport", + "state": "KY", + "lat": 38.18472, + "lon": -84.90333 + }, + "KFGX": { + "id": "KFGX", + "city": "Flemingsburg Fleming-Mason Airport", + "state": "KY", + "lat": 38.5418, + "lon": -83.7434 + }, + "KFTK": { + "id": "KFTK", + "city": "Fort Knox", + "state": "KY", + "lat": 37.9, + "lon": -85.9666699 + }, + "KGDA": { + "id": "KGDA", + "city": "MARION", + "state": "KY", + "lat": 37.3333, + "lon": -88.1 + }, + "KGLW": { + "id": "KGLW", + "city": "Glasgow, Glasgow Municipal Airport", + "state": "KY", + "lat": 37.03167, + "lon": -85.95361 + }, + "KHOP": { + "id": "KHOP", + "city": "Fort Campbell U. S. Army Airfield", + "state": "KY", + "lat": 36.66667, + "lon": -87.5 + }, + "KHVC": { + "id": "KHVC", + "city": "Hopkinsville-Christian County Airport", + "state": "KY", + "lat": 36.8569699, + "lon": -87.45508 + }, + "KIOB": { + "id": "KIOB", + "city": "Mount Sterling-Montgomery County Airport", + "state": "KY", + "lat": 38.0575, + "lon": -83.9829 + }, + "KJKL": { + "id": "KJKL", + "city": "Jackson, Carroll Airport", + "state": "KY", + "lat": 37.5913899, + "lon": -83.31444 + }, + "KLEX": { + "id": "KLEX", + "city": "Lexington Blue Grass Airport", + "state": "KY", + "lat": 38.0339, + "lon": -84.6114599 + }, + "KLOU": { + "id": "KLOU", + "city": "Louisville, Bowman Field Airport", + "state": "KY", + "lat": 38.22778, + "lon": -85.66361 + }, + "KLOZ": { + "id": "KLOZ", + "city": "London, London-Corbin Airport-Magee Field", + "state": "KY", + "lat": 37.08944, + "lon": -84.06861 + }, + "KOWB": { + "id": "KOWB", + "city": "Owensboro, Owensboro-Daviess County Airport", + "state": "KY", + "lat": 37.74, + "lon": -87.16667 + }, + "KPAH": { + "id": "KPAH", + "city": "Paducah, Barkley Regional Airport", + "state": "KY", + "lat": 37.05639, + "lon": -88.77389 + }, + "KPBX": { + "id": "KPBX", + "city": "Pikeville Pike County Airport and Hatcher Field", + "state": "KY", + "lat": 37.5587, + "lon": -82.5674 + }, + "KRGA": { + "id": "KRGA", + "city": "Central Kentucky Regional Airport", + "state": "KY", + "lat": 37.6308475, + "lon": -84.3323372 + }, + "KSDF": { + "id": "KSDF", + "city": "Louisville Muhammad Ali International Airport", + "state": "KY", + "lat": 38.17406, + "lon": -85.7365 + }, + "KSJS": { + "id": "KSJS", + "city": "Big Sandy Regional Airport", + "state": "KY", + "lat": 37.751, + "lon": -82.6367 + }, + "KSME": { + "id": "KSME", + "city": "Somerset, Somerset-Pulaski County - J.T. Wilson Field Airport", + "state": "KY", + "lat": 37.05417, + "lon": -84.615 + }, + "KSYM": { + "id": "KSYM", + "city": "Clyde A. Thomas Regional Airport", + "state": "KY", + "lat": 38.215, + "lon": -83.5874 + }, + "KTWT": { + "id": "KTWT", + "city": "Sturgis, Sturgis Municipal Airport", + "state": "KY", + "lat": 37.54083, + "lon": -87.9516699 + }, + "KACB": { + "id": "KACB", + "city": "Bellaire, Antrim County Airport", + "state": "MI", + "lat": 44.98833, + "lon": -85.19833 + }, + "KADG": { + "id": "KADG", + "city": "Adrian, Lenawee County Airport", + "state": "MI", + "lat": 41.86778, + "lon": -84.07944 + }, + "KAMN": { + "id": "KAMN", + "city": "Alma, Gratiot Community Airport", + "state": "MI", + "lat": 43.32194, + "lon": -84.68778 + }, + "KANJ": { + "id": "KANJ", + "city": "Sault Ste. Marie", + "state": "MI", + "lat": 46.4794399, + "lon": -84.35722 + }, + "KAPN": { + "id": "KAPN", + "city": "Alpena, Alpena County Regional Airport", + "state": "MI", + "lat": 45.07167, + "lon": -83.56444 + }, + "KARB": { + "id": "KARB", + "city": "Ann Arbor, Ann Arbor Municipal Airport", + "state": "MI", + "lat": 42.22389, + "lon": -83.74 + }, + "KAZO": { + "id": "KAZO", + "city": "Kalamazoo/Battle Creek International Airport", + "state": "MI", + "lat": 42.2283, + "lon": -85.54595 + }, + "KBAX": { + "id": "KBAX", + "city": "Huron County Memorial Airport", + "state": "MI", + "lat": 43.77741, + "lon": -82.98271 + }, + "KBEH": { + "id": "KBEH", + "city": "Southwest Michigan Regional Airport", + "state": "MI", + "lat": 42.12896, + "lon": -86.41515 + }, + "KBFA": { + "id": "KBFA", + "city": "Boyne Mountain Airport", + "state": "MI", + "lat": 45.16584, + "lon": -84.92411 + }, + "KBIV": { + "id": "KBIV", + "city": "Holland - West Michigan Regional Airport", + "state": "MI", + "lat": 42.74611, + "lon": -86.09667 + }, + "KBTL": { + "id": "KBTL", + "city": "Battle Creek Executive Airport", + "state": "MI", + "lat": 42.31197, + "lon": -85.24144 + }, + "KCAD": { + "id": "KCAD", + "city": "Wexford County Airport", + "state": "MI", + "lat": 44.27847, + "lon": -85.4206899 + }, + "KCFS": { + "id": "KCFS", + "city": "Caro, Tuscola Area Airport", + "state": "MI", + "lat": 43.45861, + "lon": -83.44528 + }, + "KCIU": { + "id": "KCIU", + "city": "Sault Ste Marie, Chippewa County International Airport", + "state": "MI", + "lat": 46.25, + "lon": -84.4666699 + }, + "KCMX": { + "id": "KCMX", + "city": "Houghton County Memorial Airport", + "state": "MI", + "lat": 47.16597, + "lon": -88.48072 + }, + "KCVX": { + "id": "KCVX", + "city": "Charlevoix, Charlevoix Municipal Airport", + "state": "MI", + "lat": 45.30472, + "lon": -85.27472 + }, + "KALX": { + "id": "KALX", + "city": "Alexander City, Thomas C Russell Field Airport", + "state": "AL", + "lat": 32.91472, + "lon": -85.96278 + }, + "KANB": { + "id": "KANB", + "city": "Anniston Metro Airport", + "state": "AL", + "lat": 33.59045, + "lon": -85.84789 + }, + "KASN": { + "id": "KASN", + "city": "Talladega Municipal Airport", + "state": "AL", + "lat": 33.5695, + "lon": -86.0512 + }, + "KAUO": { + "id": "KAUO", + "city": "Auburn-Opelika Airport", + "state": "AL", + "lat": 32.61667, + "lon": -85.43333 + }, + "KBFM": { + "id": "KBFM", + "city": "Mobile, Mobile Downtown Airport", + "state": "AL", + "lat": 30.61389, + "lon": -88.0633299 + }, + "KBFZ": { + "id": "KBFZ", + "city": "Albertville Regional Airport-Thomas J Brumlik Field", + "state": "AL", + "lat": 34.22911, + "lon": -86.25575 + }, + "KBHM": { + "id": "KBHM", + "city": "Birmingham, Birmingham International Airport", + "state": "AL", + "lat": 33.56556, + "lon": -86.745 + }, + "KCMD": { + "id": "KCMD", + "city": "Cullman Regional Folsom Field", + "state": "AL", + "lat": 34.2687, + "lon": -86.858 + }, + "KCQF": { + "id": "KCQF", + "city": "Sonny Callahan Airport", + "state": "AL", + "lat": 30.461, + "lon": -87.877 + }, + "KDCU": { + "id": "KDCU", + "city": "Decatur, Pryor Field", + "state": "AL", + "lat": 34.65806, + "lon": -86.94333 + }, + "KDHN": { + "id": "KDHN", + "city": "Dothan, Dothan Regional Airport", + "state": "AL", + "lat": 31.32139, + "lon": -85.44972 + }, + "KDYA": { + "id": "KDYA", + "city": "Demopolis Municipal Airport", + "state": "AL", + "lat": 32.4638, + "lon": -87.9541 + }, + "KEDN": { + "id": "KEDN", + "city": "Enterprise Municipal Airport", + "state": "AL", + "lat": 31.2982, + "lon": -85.9048 + }, + "KEET": { + "id": "KEET", + "city": "Alabaster, Shelby County Airport", + "state": "AL", + "lat": 33.17833, + "lon": -86.78167 + }, + "KEKY": { + "id": "KEKY", + "city": "Bessemer Airport", + "state": "AL", + "lat": 33.3126, + "lon": -86.9263 + }, + "KEUF": { + "id": "KEUF", + "city": "Eufaula Municipal Airport", + "state": "AL", + "lat": 31.951, + "lon": -85.129 + }, + "KGAD": { + "id": "KGAD", + "city": "Gadsden, Gadsden Municipal Airport", + "state": "AL", + "lat": 33.96667, + "lon": -86.08333 + }, + "KGZH": { + "id": "KGZH", + "city": "Evergreen, Middleton Field", + "state": "AL", + "lat": 31.41889, + "lon": -87.04806 + }, + "KHDL": { + "id": "KHDL", + "city": "Headland Municipal Airport", + "state": "AL", + "lat": 31.36414, + "lon": -85.31253 + }, + "KHEY": { + "id": "KHEY", + "city": "Hanchey AHP / Ozark", + "state": "AL", + "lat": 31.35, + "lon": -85.66667 + }, + "KHSV": { + "id": "KHSV", + "city": "Huntsville, Huntsville International / Jones Field", + "state": "AL", + "lat": 34.64361, + "lon": -86.78556 + }, + "KHUA": { + "id": "KHUA", + "city": "Redstone Airfield", + "state": "AL", + "lat": 34.6786, + "lon": -86.6847 + }, + "KJFX": { + "id": "KJFX", + "city": "Jasper Walker County Airport & Bevill Field", + "state": "AL", + "lat": 33.902, + "lon": -87.31417 + }, + "KJKA": { + "id": "KJKA", + "city": "Jack Edwards Airport", + "state": "AL", + "lat": 30.2896, + "lon": -87.6718 + }, + "KLOR": { + "id": "KLOR", + "city": "Fort Rucker, Lowe Army Heliport", + "state": "AL", + "lat": 31.35889, + "lon": -85.74833 + }, + "KMDQ": { + "id": "KMDQ", + "city": "Huntsville, Madison County Executive Airport", + "state": "AL", + "lat": 34.86139, + "lon": -86.55722 + }, + "KMGM": { + "id": "KMGM", + "city": "Montgomery, Dannelly Field", + "state": "AL", + "lat": 32.30028, + "lon": -86.40611 + }, + "KMOB": { + "id": "KMOB", + "city": "Mobile, Mobile Regional Airport", + "state": "AL", + "lat": 30.68833, + "lon": -88.24556 + }, + "KMSL": { + "id": "KMSL", + "city": "Muscle Shoals, North West Alabama Regional Airport", + "state": "AL", + "lat": 34.74389, + "lon": -87.59944 + }, + "KMXF": { + "id": "KMXF", + "city": "Maxwell Air Force Base / Montgomery", + "state": "AL", + "lat": 32.38333, + "lon": -86.36667 + }, + "KOZR": { + "id": "KOZR", + "city": "Cairns Army Air Field / Ozark", + "state": "AL", + "lat": 31.27672, + "lon": -85.71099 + }, + "KPLR": { + "id": "KPLR", + "city": "St Clair County Airport", + "state": "AL", + "lat": 33.5588, + "lon": -86.2491 + }, + "KPRN": { + "id": "KPRN", + "city": "Mac Crenshaw Memorial Airport", + "state": "AL", + "lat": 31.8457, + "lon": -86.6107 + }, + "KSCD": { + "id": "KSCD", + "city": "Merkel Field Sylacauga Municipal Airport", + "state": "AL", + "lat": 33.1718, + "lon": -86.3055 + }, + "KSEM": { + "id": "KSEM", + "city": "Craig Field / Selma", + "state": "AL", + "lat": 32.35, + "lon": -86.98333 + }, + "KSXS": { + "id": "KSXS", + "city": "SCHELL AHP", + "state": "AL", + "lat": 31.35, + "lon": -85.85 + }, + "KTCL": { + "id": "KTCL", + "city": "Tuscaloosa Regional Airport", + "state": "AL", + "lat": 33.21215, + "lon": -87.61554 + }, + "KTOI": { + "id": "KTOI", + "city": "Troy, Troy Municipal Airport", + "state": "AL", + "lat": 31.86056, + "lon": -86.01222 + }, + "KAFN": { + "id": "KAFN", + "city": "Jaffrey Airport-Silver Ranch", + "state": "NH", + "lat": 42.8066699, + "lon": -72.00127 + }, + "KASH": { + "id": "KASH", + "city": "Nashua - Boire Field Airport", + "state": "NH", + "lat": 42.77981, + "lon": -71.51409 + }, + "KBML": { + "id": "KBML", + "city": "Berlin, Berlin Municipal Airport", + "state": "NH", + "lat": 44.57611, + "lon": -71.17861 + }, + "KCON": { + "id": "KCON", + "city": "Concord Municipal Airport", + "state": "NH", + "lat": 43.20489, + "lon": -71.50257 + }, + "KDAW": { + "id": "KDAW", + "city": "Rochester - Skyhaven Airport", + "state": "NH", + "lat": 43.27939, + "lon": -70.92426 + }, + "KEEN": { + "id": "KEEN", + "city": "Keene, Dillant-Hopkins Airport", + "state": "NH", + "lat": 42.9, + "lon": -72.26667 + }, + "KHIE": { + "id": "KHIE", + "city": "Whitefield - Mount Washington Regional Airport", + "state": "NH", + "lat": 44.36595, + "lon": -71.55218 + }, + "KLCI": { + "id": "KLCI", + "city": "Laconia, Laconia Municipal Airport", + "state": "NH", + "lat": 43.56667, + "lon": -71.41667 + }, + "KLEB": { + "id": "KLEB", + "city": "Lebanon Municipal Airport", + "state": "NH", + "lat": 43.6271, + "lon": -72.30537 + }, + "KMHT": { + "id": "KMHT", + "city": "Manchester Airport", + "state": "NH", + "lat": 42.92964, + "lon": -71.43559 + }, + "KMWN": { + "id": "KMWN", + "city": "Mount Washington", + "state": "NH", + "lat": 44.27086, + "lon": -71.30337 + }, + "KPSM": { + "id": "KPSM", + "city": "Pease Air Force Base / Portsmouth", + "state": "NH", + "lat": 43.0833299, + "lon": -70.81667 + }, + "PHBK": { + "id": "PHBK", + "city": "Kekaha, Pacific Missile Test Facility Barking Sands", + "state": "HI", + "lat": 22.03639, + "lon": -159.78639 + }, + "PHHI": { + "id": "PHHI", + "city": "Wheeler Air Force Base / Oahu", + "state": "HI", + "lat": 21.48333, + "lon": -158.03333 + }, + "PHHN": { + "id": "PHHN", + "city": "HANA", + "state": "HI", + "lat": 20.79563, + "lon": -156.01444 + }, + "PHJR": { + "id": "PHJR", + "city": "Oahu, Kalaeloa Airport", + "state": "HI", + "lat": 21.30833, + "lon": -158.06806 + }, + "PHKO": { + "id": "PHKO", + "city": "Kailua / Kona, Keahole Airport", + "state": "HI", + "lat": 19.74083, + "lon": -156.05056 + }, + "PHLI": { + "id": "PHLI", + "city": "Lihue, Lihue Airport", + "state": "HI", + "lat": 21.98389, + "lon": -159.3411099 + }, + "PHMK": { + "id": "PHMK", + "city": "Kaunakakai, Molokai Airport", + "state": "HI", + "lat": 21.15, + "lon": -157.1 + }, + "PHMU": { + "id": "PHMU", + "city": "KAMUELA", + "state": "HI", + "lat": 20.00133, + "lon": -155.66817 + }, + "PHNG": { + "id": "PHNG", + "city": "Kaneohe, Marine Corps Air Station", + "state": "HI", + "lat": 21.45389, + "lon": -157.76556 + }, + "PHNL": { + "id": "PHNL", + "city": "Daniel K Inouye International Airport", + "state": "HI", + "lat": 21.3275, + "lon": -157.94306 + }, + "PHNY": { + "id": "PHNY", + "city": "Lanai City, Lanai Airport", + "state": "HI", + "lat": 20.78556, + "lon": -156.95139 + }, + "PHOG": { + "id": "PHOG", + "city": "Kahului, Kahului Airport", + "state": "HI", + "lat": 20.8924999, + "lon": -156.43694 + }, + "PHSF": { + "id": "PHSF", + "city": "Bradshaw Army Air Field / Hawaii", + "state": "HI", + "lat": 19.78333, + "lon": -155.55 + }, + "PHTO": { + "id": "PHTO", + "city": "Hilo, Hilo International Airport", + "state": "HI", + "lat": 19.72222, + "lon": -155.0558299 + }, + "KADU": { + "id": "KADU", + "city": "Audubon, Audubon County Airport", + "state": "IA", + "lat": 41.70111, + "lon": -94.92028 + }, + "KAIO": { + "id": "KAIO", + "city": "Atlantic", + "state": "IA", + "lat": 41.4, + "lon": -95.05 + }, + "KALO": { + "id": "KALO", + "city": "Waterloo, Waterloo Municipal Airport", + "state": "IA", + "lat": 42.55444, + "lon": -92.40111 + }, + "KAMW": { + "id": "KAMW", + "city": "Ames, Ames Municipal Airport", + "state": "IA", + "lat": 41.99056, + "lon": -93.6188899 + }, + "KAWG": { + "id": "KAWG", + "city": "Washington", + "state": "IA", + "lat": 41.28333, + "lon": -91.66667 + }, + "KAXA": { + "id": "KAXA", + "city": "Algona", + "state": "IA", + "lat": 43.0833299, + "lon": -94.26667 + }, + "KBNW": { + "id": "KBNW", + "city": "Boone Municipal", + "state": "IA", + "lat": 42.05, + "lon": -93.85 + }, + "KBRL": { + "id": "KBRL", + "city": "Burlington Regional Airport", + "state": "IA", + "lat": 40.77293, + "lon": -91.12543 + }, + "KCAV": { + "id": "KCAV", + "city": "Clarion", + "state": "IA", + "lat": 42.75, + "lon": -93.76667 + }, + "KCBF": { + "id": "KCBF", + "city": "Council Bluffs", + "state": "IA", + "lat": 41.2612499, + "lon": -95.7604 + }, + "KCCY": { + "id": "KCCY", + "city": "Charles City", + "state": "IA", + "lat": 43.06667, + "lon": -92.61667 + }, + "KCID": { + "id": "KCID", + "city": "Cedar Rapids Airport", + "state": "IA", + "lat": 41.88295, + "lon": -91.72456 + }, + "KCIN": { + "id": "KCIN", + "city": "Carroll", + "state": "IA", + "lat": 42.05, + "lon": -94.78333 + }, + "KCKP": { + "id": "KCKP", + "city": "Cherokee, Cherokee Municipal Airport", + "state": "IA", + "lat": 42.73167, + "lon": -95.55583 + }, + "KCNC": { + "id": "KCNC", + "city": "Chariton", + "state": "IA", + "lat": 41.03333, + "lon": -93.36667 + }, + "KCSQ": { + "id": "KCSQ", + "city": "Creston Municipal Airport", + "state": "IA", + "lat": 41.0188599, + "lon": -94.361 + }, + "KCWI": { + "id": "KCWI", + "city": "Clinton Municipal Airport", + "state": "IA", + "lat": 41.82954, + "lon": -90.33279 + }, + "KDBQ": { + "id": "KDBQ", + "city": "Dubuque Regional Airport", + "state": "IA", + "lat": 42.39837, + "lon": -90.7091 + }, + "KDEH": { + "id": "KDEH", + "city": "Decorah", + "state": "IA", + "lat": 43.28333, + "lon": -91.73333 + }, + "KDNS": { + "id": "KDNS", + "city": "Denison", + "state": "IA", + "lat": 41.98333, + "lon": -95.38333 + }, + "KDSM": { + "id": "KDSM", + "city": "Des Moines International Airport", + "state": "IA", + "lat": 41.53399, + "lon": -93.65307 + }, + "KDVN": { + "id": "KDVN", + "city": "Davenport Municipal Airport", + "state": "IA", + "lat": 41.61338, + "lon": -90.59479 + }, + "KEBS": { + "id": "KEBS", + "city": "Webster City Municipal Airport", + "state": "IA", + "lat": 42.43724, + "lon": -93.87237 + }, + "KEOK": { + "id": "KEOK", + "city": "Keokuk Municipal Airport", + "state": "IA", + "lat": 40.46149, + "lon": -91.42739 + }, + "KEST": { + "id": "KEST", + "city": "Estherville, Estherville Municipal Airport", + "state": "IA", + "lat": 43.40111, + "lon": -94.74722 + }, + "KFFL": { + "id": "KFFL", + "city": "Fairfield Municipal Airport", + "state": "IA", + "lat": 41.0521, + "lon": -91.98339 + }, + "KFOD": { + "id": "KFOD", + "city": "Fort Dodge", + "state": "IA", + "lat": 42.55, + "lon": -94.18333 + }, + "KFSW": { + "id": "KFSW", + "city": "Fort Madison Municipal Airport", + "state": "IA", + "lat": 40.66154, + "lon": -91.32672 + }, + "KFXY": { + "id": "KFXY", + "city": "Forest City Municipal Airport", + "state": "IA", + "lat": 43.235, + "lon": -93.624 + }, + "KGGI": { + "id": "KGGI", + "city": "Grinnell Municipal Airfield", + "state": "IA", + "lat": 41.7092, + "lon": -92.7349 + }, + "KHNR": { + "id": "KHNR", + "city": "Harlan, Harlan Municipal Airport", + "state": "IA", + "lat": 41.58444, + "lon": -95.33972 + }, + "KHPT": { + "id": "KHPT", + "city": "Hampton Municipal Airport", + "state": "IA", + "lat": 42.72369, + "lon": -93.22633 + }, + "KICL": { + "id": "KICL", + "city": "Schenck Field Airport", + "state": "IA", + "lat": 40.72421, + "lon": -95.02224 + }, + "KIFA": { + "id": "KIFA", + "city": "Iowa Falls Municipal Airport", + "state": "IA", + "lat": 42.4709999, + "lon": -93.27 + }, + "KIIB": { + "id": "KIIB", + "city": "Independence, Independence Municipal Airport", + "state": "IA", + "lat": 42.45, + "lon": -91.93333 + }, + "KIKV": { + "id": "KIKV", + "city": "Ankeny Regional Airport", + "state": "IA", + "lat": 41.68782, + "lon": -93.56944 + }, + "KIOW": { + "id": "KIOW", + "city": "Iowa City Municipal Airport", + "state": "IA", + "lat": 41.6394499, + "lon": -91.5445 + }, + "KLRJ": { + "id": "KLRJ", + "city": "Le Mars Municipal Airport", + "state": "IA", + "lat": 42.77478, + "lon": -96.19239 + }, + "KLWD": { + "id": "KLWD", + "city": "Lamoni, Lamoni Municipal Airport", + "state": "IA", + "lat": 40.63056, + "lon": -93.90083 + }, + "KMCW": { + "id": "KMCW", + "city": "Mason City Municipal Airport", + "state": "IA", + "lat": 43.15442, + "lon": -93.32607 + }, + "KMIW": { + "id": "KMIW", + "city": "Marshalltown, Marshalltown Municipal Airport", + "state": "IA", + "lat": 42.11056, + "lon": -92.91611 + }, + "KMPZ": { + "id": "KMPZ", + "city": "Mount Pleasant, Mount Pleasant Municipal Airport", + "state": "IA", + "lat": 40.94667, + "lon": -91.51111 + }, + "KMUT": { + "id": "KMUT", + "city": "Muscatine", + "state": "IA", + "lat": 41.36667, + "lon": -91.15 + }, + "KMXO": { + "id": "KMXO", + "city": "Monticello Regional Airport", + "state": "IA", + "lat": 42.22035, + "lon": -91.16041 + }, + "KOLZ": { + "id": "KOLZ", + "city": "Oelwein Municipal Airport", + "state": "IA", + "lat": 42.68316, + "lon": -91.97595 + }, + "KOOA": { + "id": "KOOA", + "city": "Oskaloosa, Oskaloosa Municipal Airport", + "state": "IA", + "lat": 41.22611, + "lon": -92.49361 + }, + "KOTM": { + "id": "KOTM", + "city": "Ottumwa Regional Airport", + "state": "IA", + "lat": 41.10082, + "lon": -92.4445099 + }, + "KOXV": { + "id": "KOXV", + "city": "Knoxville", + "state": "IA", + "lat": 41.3, + "lon": -93.11667 + }, + "KPEA": { + "id": "KPEA", + "city": "Pella, Pella Municipal Airport", + "state": "IA", + "lat": 41.4, + "lon": -92.93333 + }, + "KPRO": { + "id": "KPRO", + "city": "Perry Municipal Airport", + "state": "IA", + "lat": 41.828, + "lon": -94.1598999 + }, + "KRDK": { + "id": "KRDK", + "city": "Red Oak", + "state": "IA", + "lat": 41.01667, + "lon": -95.26667 + }, + "KSDA": { + "id": "KSDA", + "city": "Shenandoah Municipal", + "state": "IA", + "lat": 40.75, + "lon": -95.41667 + }, + "KSHL": { + "id": "KSHL", + "city": "Sheldon", + "state": "IA", + "lat": 43.21667, + "lon": -95.83333 + }, + "KSLB": { + "id": "KSLB", + "city": "Storm Lake", + "state": "IA", + "lat": 42.6, + "lon": -95.23333 + }, + "KSPW": { + "id": "KSPW", + "city": "Spencer Municipal Airport", + "state": "IA", + "lat": 43.16825, + "lon": -95.21008 + }, + "KSUX": { + "id": "KSUX", + "city": "Sioux City, Sioux Gateway Airport", + "state": "IA", + "lat": 42.4025, + "lon": -96.38444 + }, + "KSXK": { + "id": "KSXK", + "city": "Sioux County Regional Airport", + "state": "IA", + "lat": 42.98583, + "lon": -96.1614 + }, + "KTNU": { + "id": "KTNU", + "city": "Newton Municipal Airport - Earl Johnson Field", + "state": "IA", + "lat": 41.67014, + "lon": -93.01902 + }, + "KTVK": { + "id": "KTVK", + "city": "Centerville Municipal Airport", + "state": "IA", + "lat": 40.6839, + "lon": -92.901 + }, + "KVTI": { + "id": "KVTI", + "city": "Vinton, Vinton Veterans Memorial Airpark Airport", + "state": "IA", + "lat": 42.21861, + "lon": -92.02583 + }, + "KACP": { + "id": "KACP", + "city": "Oakdale, Allen Parish Airport", + "state": "LA", + "lat": 30.75056, + "lon": -92.68861 + }, + "KAEX": { + "id": "KAEX", + "city": "Alexandria, Alexandria International Airport", + "state": "LA", + "lat": 31.33472, + "lon": -92.55861 + }, + "KAPS": { + "id": "KAPS", + "city": "Port of South Louisiana Executive Regional Airport", + "state": "LA", + "lat": 30.08747, + "lon": -90.58283 + }, + "KAQV": { + "id": "KAQV", + "city": "Ft. Polk - Peason Ridge", + "state": "LA", + "lat": 31.4, + "lon": -93.2833 + }, + "KARA": { + "id": "KARA", + "city": "Acadiana Regional Airport", + "state": "LA", + "lat": 30.02918, + "lon": -91.88451 + }, + "KASD": { + "id": "KASD", + "city": "Slidell, Slidell Airport", + "state": "LA", + "lat": 30.34306, + "lon": -89.82194 + }, + "KATP": { + "id": "KATP", + "city": "Green Canyon 787 Atlantis", + "state": "LA", + "lat": 27.195, + "lon": -90.027 + }, + "KBAD": { + "id": "KBAD", + "city": "Barksdale Air Force Base", + "state": "LA", + "lat": 32.5, + "lon": -93.66667 + }, + "KBKB": { + "id": "KBKB", + "city": "Ft. Polk - Fullerton Landing Strip", + "state": "LA", + "lat": 31.0217, + "lon": -92.9107 + }, + "KBQP": { + "id": "KBQP", + "city": "Bastrop, Morehouse Memorial Airport", + "state": "LA", + "lat": 32.75583, + "lon": -91.88056 + }, + "KBTR": { + "id": "KBTR", + "city": "Baton Rouge, Baton Rouge Metropolitan, Ryan Field", + "state": "LA", + "lat": 30.53722, + "lon": -91.14694 + }, + "KBXA": { + "id": "KBXA", + "city": "Bogalusa, George R Carr Memorial Air Field", + "state": "LA", + "lat": 30.81361, + "lon": -89.86472 + }, + "KCWF": { + "id": "KCWF", + "city": "Chenault Airpark", + "state": "LA", + "lat": 30.21667, + "lon": -93.15 + }, + "KCYD": { + "id": "KCYD", + "city": "MISS CANYAN 807", + "state": "LA", + "lat": 28.17, + "lon": -89.22 + }, + "KDRI": { + "id": "KDRI", + "city": "De Ridder, Beauregard Parish Airport", + "state": "LA", + "lat": 30.83167, + "lon": -93.33972 + }, + "KDSF": { + "id": "KDSF", + "city": "Mississippi Canyon", + "state": "LA", + "lat": 28.35, + "lon": -88.26667 + }, + "KDTN": { + "id": "KDTN", + "city": "Shreveport, Shreveport Downtown Airport", + "state": "LA", + "lat": 32.5424999, + "lon": -93.74472 + }, + "KESF": { + "id": "KESF", + "city": "Alexandria Esler Regional Airport", + "state": "LA", + "lat": 31.39634, + "lon": -92.28273 + }, + "KGAO": { + "id": "KGAO", + "city": "Galliano, South Lafourche Airport", + "state": "LA", + "lat": 29.44472, + "lon": -90.26111 + }, + "KGBK": { + "id": "KGBK", + "city": "MAGNOLIA OIL PLATFORM", + "state": "LA", + "lat": 27.2, + "lon": -92.2 + }, + "KGHB": { + "id": "KGHB", + "city": "GB172/Salsa (Shell E-P)", + "state": "LA", + "lat": 27.84, + "lon": -91.988 + }, + "KHDC": { + "id": "KHDC", + "city": "Hammond, Hammond Municipal Airport", + "state": "LA", + "lat": 30.52083, + "lon": -90.4175 + }, + "KHUM": { + "id": "KHUM", + "city": "Houma-Terrebonne Airport", + "state": "LA", + "lat": 29.56341, + "lon": -90.66283 + }, + "KHZR": { + "id": "KHZR", + "city": "New Roads False River Regional Airport", + "state": "LA", + "lat": 30.7183, + "lon": -91.4787 + }, + "KIER": { + "id": "KIER", + "city": "Natchitoches, Natchitoches Regional Airport", + "state": "LA", + "lat": 31.73583, + "lon": -93.09917 + }, + "KIYA": { + "id": "KIYA", + "city": "Abbeville Chris Crusta Memorial Airport", + "state": "LA", + "lat": 29.97578, + "lon": -92.08422 + }, + "KLCH": { + "id": "KLCH", + "city": "Lake Charles Regional Airport", + "state": "LA", + "lat": 30.12556, + "lon": -93.22767 + }, + "KLFT": { + "id": "KLFT", + "city": "Lafayette, Lafayette Regional Airport", + "state": "LA", + "lat": 30.20222, + "lon": -91.99306 + }, + "KMLU": { + "id": "KMLU", + "city": "Monroe Regional Airport", + "state": "LA", + "lat": 32.5155699, + "lon": -92.02995 + }, + "KMNE": { + "id": "KMNE", + "city": "Minden Airport", + "state": "LA", + "lat": 32.64603, + "lon": -93.29808 + }, + "KMSY": { + "id": "KMSY", + "city": "New Orleans, New Orleans International Airport", + "state": "LA", + "lat": 29.99278, + "lon": -90.2508299 + }, + "KNBG": { + "id": "KNBG", + "city": "New Orleans Naval Air Station - Alvin Callender Field", + "state": "LA", + "lat": 29.83736, + "lon": -90.02445 + }, + "KNEW": { + "id": "KNEW", + "city": "New Orleans, New Orleans Lakefront Airport", + "state": "LA", + "lat": 30.04944, + "lon": -90.02889 + }, + "KOPL": { + "id": "KOPL", + "city": "Opelousas St Landry Parish Airport", + "state": "LA", + "lat": 30.5584, + "lon": -92.0994 + }, + "KPOE": { + "id": "KPOE", + "city": "Fort Polk, Polk AAF Ft Polk", + "state": "LA", + "lat": 31.05, + "lon": -93.19389 + }, + "KPTN": { + "id": "KPTN", + "city": "Patterson Memorial", + "state": "LA", + "lat": 29.71667, + "lon": -91.33333 + }, + "KREG": { + "id": "KREG", + "city": "Louisiana Regional Airport", + "state": "LA", + "lat": 30.1714, + "lon": -90.9404 + }, + "KRSN": { + "id": "KRSN", + "city": "Ruston, Ruston Regional Airport", + "state": "LA", + "lat": 32.51444, + "lon": -92.58833 + }, + "KSHV": { + "id": "KSHV", + "city": "Shreveport, Shreveport Regional Airport", + "state": "LA", + "lat": 32.44694, + "lon": -93.82417 + }, + "KTVR": { + "id": "KTVR", + "city": "Vicksburg, Vicksburg / Tallulah Regional Airport", + "state": "LA", + "lat": 32.3480599, + "lon": -91.03 + }, + "KUXL": { + "id": "KUXL", + "city": "Southland Field", + "state": "LA", + "lat": 30.1314, + "lon": -93.3760999 + }, + "KVOA": { + "id": "KVOA", + "city": "VK 786/Petronius (Chevron)", + "state": "LA", + "lat": 29.229, + "lon": -87.781 + }, + "KABQ": { + "id": "KABQ", + "city": "Albuquerque, Albuquerque International Airport", + "state": "NM", + "lat": 35.04167, + "lon": -106.61472 + }, + "KAEG": { + "id": "KAEG", + "city": "Albuquerque, Double Eagle II Airport", + "state": "NM", + "lat": 35.145, + "lon": -106.795 + }, + "KALM": { + "id": "KALM", + "city": "Alamogordo-White", + "state": "NM", + "lat": 32.83512, + "lon": -105.99408 + }, + "KATS": { + "id": "KATS", + "city": "Artesia Municipal Airport", + "state": "NM", + "lat": 32.85239, + "lon": -104.46444 + }, + "KAXX": { + "id": "KAXX", + "city": "Angel Fire Airport", + "state": "NM", + "lat": 36.42586, + "lon": -105.29028 + }, + "KBRG": { + "id": "KBRG", + "city": "Belen Regional Airport", + "state": "NM", + "lat": 34.64586, + "lon": -106.83634 + }, + "KCAO": { + "id": "KCAO", + "city": "Clayton Municipal Airpark", + "state": "NM", + "lat": 36.44834, + "lon": -103.15367 + }, + "KCNM": { + "id": "KCNM", + "city": "Carlsbad, Cavern City Air Terminal Airport", + "state": "NM", + "lat": 32.3375, + "lon": -104.26333 + }, + "KCQC": { + "id": "KCQC", + "city": "Clines Corners", + "state": "NM", + "lat": 35, + "lon": -105.66667 + }, + "KCVN": { + "id": "KCVN", + "city": "Clovis Municipal Airport", + "state": "NM", + "lat": 34.42274, + "lon": -103.0802 + }, + "KCVS": { + "id": "KCVS", + "city": "Cannon Air Force Base / Clovis", + "state": "NM", + "lat": 34.38333, + "lon": -103.31667 + }, + "KDMN": { + "id": "KDMN", + "city": "Deming Municipal Airport", + "state": "NM", + "lat": 32.25927, + "lon": -107.72051 + }, + "KDNA": { + "id": "KDNA", + "city": "Dona Ana County Jetport, Santa Teresa", + "state": "NM", + "lat": 31.87495, + "lon": -106.69385 + }, + "KFMN": { + "id": "KFMN", + "city": "Farmington, Four Corners Regional Airport", + "state": "NM", + "lat": 36.7436099, + "lon": -108.22917 + }, + "KGNT": { + "id": "KGNT", + "city": "Grants, Grants-Milan Municipal Airport", + "state": "NM", + "lat": 35.16528, + "lon": -107.90222 + }, + "KGUP": { + "id": "KGUP", + "city": "Gallup Municipal Airport", + "state": "NM", + "lat": 35.50859, + "lon": -108.79316 + }, + "KHMN": { + "id": "KHMN", + "city": "Holloman Air Force Base", + "state": "NM", + "lat": 32.85, + "lon": -106.1 + }, + "KHOB": { + "id": "KHOB", + "city": "Hobbs / Lea County", + "state": "NM", + "lat": 32.68333, + "lon": -103.2166699 + }, + "KLAM": { + "id": "KLAM", + "city": "Los Alamos Airport", + "state": "NM", + "lat": 35.8796899, + "lon": -106.26869 + }, + "KLRU": { + "id": "KLRU", + "city": "Las Cruces, Las Cruces International Airport", + "state": "NM", + "lat": 32.28944, + "lon": -106.92194 + }, + "KLSB": { + "id": "KLSB", + "city": "Lordsburg Municipal Airport", + "state": "NM", + "lat": 32.33346, + "lon": -108.69174 + }, + "KLVS": { + "id": "KLVS", + "city": "Las Vegas Municipal Airport", + "state": "NM", + "lat": 35.65584, + "lon": -105.13852 + }, + "KONM": { + "id": "KONM", + "city": "Socorro Municipal Airport", + "state": "NM", + "lat": 34.02633, + "lon": -106.90372 + }, + "KROW": { + "id": "KROW", + "city": "Roswell International Air Center Airport", + "state": "NM", + "lat": 33.30737, + "lon": -104.50816 + }, + "KRTN": { + "id": "KRTN", + "city": "Raton Municipal - Crews Field Airport", + "state": "NM", + "lat": 36.741528, + "lon": -104.502183 + }, + "KSAF": { + "id": "KSAF", + "city": "Santa Fe County Municipal Airport", + "state": "NM", + "lat": 35.61097, + "lon": -106.09573 + }, + "KSKX": { + "id": "KSKX", + "city": "Taos, Taos Regional Airport", + "state": "NM", + "lat": 36.45, + "lon": -105.66667 + }, + "KSRR": { + "id": "KSRR", + "city": "Sierra Blanca Regional Airport", + "state": "NM", + "lat": 33.4667699, + "lon": -105.52778 + }, + "KSVC": { + "id": "KSVC", + "city": "Grant County Airport", + "state": "NM", + "lat": 32.63099, + "lon": -108.14658 + }, + "KSXU": { + "id": "KSXU", + "city": "Santa Rosa Route 66 Airport", + "state": "NM", + "lat": 34.93567, + "lon": -104.64256 + }, + "KTCC": { + "id": "KTCC", + "city": "Tucumcari Municipal Airport", + "state": "NM", + "lat": 35.18053, + "lon": -103.60145 + }, + "KTCS": { + "id": "KTCS", + "city": "Truth Or Consequences, Truth Or Consequences Municipal Airport", + "state": "NM", + "lat": 33.2366699, + "lon": -107.26806 + }, + "KXNI": { + "id": "KXNI", + "city": "Andrew Othole Memorial Airport", + "state": "NM", + "lat": 35.06068, + "lon": -108.93759 + }, + "KADW": { + "id": "KADW", + "city": "Camp Springs / Andrews Air Force Base", + "state": "MD", + "lat": 38.81667, + "lon": -76.85 + }, + "KANP": { + "id": "KANP", + "city": "LEEAIRPORT", + "state": "MD", + "lat": 38.94287, + "lon": -76.5683899 + }, + "KAPG": { + "id": "KAPG", + "city": "Phillips Army Air Field / Aberdeen", + "state": "MD", + "lat": 39.46667, + "lon": -76.16667 + }, + "KBWI": { + "id": "KBWI", + "city": "Baltimore, Baltimore-Washington International Airport", + "state": "MD", + "lat": 39.17329, + "lon": -76.68404 + }, + "KCGE": { + "id": "KCGE", + "city": "Cambridge-Dorchester Airport", + "state": "MD", + "lat": 38.5393, + "lon": -76.0304 + }, + "KCGS": { + "id": "KCGS", + "city": "College Park Airport", + "state": "MD", + "lat": 38.9806, + "lon": -76.9223 + }, + "KDMH": { + "id": "KDMH", + "city": "Baltimore, Inner Harbor", + "state": "MD", + "lat": 39.28333, + "lon": -76.61667 + }, + "KDMW": { + "id": "KDMW", + "city": "Carroll County Regional Jack B Poage Field", + "state": "MD", + "lat": 39.6083, + "lon": -77.0077 + }, + "KEDG": { + "id": "KEDG", + "city": "WEIDE", + "state": "MD", + "lat": 39.39205, + "lon": -76.29106 + }, + "KESN": { + "id": "KESN", + "city": "Easton / Newman Field", + "state": "MD", + "lat": 38.8, + "lon": -76.06667 + }, + "KFDK": { + "id": "KFDK", + "city": "Frederick Municipal Airport", + "state": "MD", + "lat": 39.41775, + "lon": -77.36982 + }, + "KFME": { + "id": "KFME", + "city": "Fort Meade / Tipton", + "state": "MD", + "lat": 39.0833299, + "lon": -76.76667 + }, + "KGAI": { + "id": "KGAI", + "city": "Gaithersburg - Montgomery County Airport", + "state": "MD", + "lat": 39.16957, + "lon": -77.16551 + }, + "KHGR": { + "id": "KHGR", + "city": "Hagerstown, Washington County Regional Airport", + "state": "MD", + "lat": 39.70583, + "lon": -77.73 + }, + "KMTN": { + "id": "KMTN", + "city": "Baltimore / Martin", + "state": "MD", + "lat": 39.3333299, + "lon": -76.41667 + }, + "KNAK": { + "id": "KNAK", + "city": "Annapolis, United States Naval Academy", + "state": "MD", + "lat": 38.99125, + "lon": -76.48907 + }, + "KNHK": { + "id": "KNHK", + "city": "Patuxent River, Naval Air Station", + "state": "MD", + "lat": 38.27861, + "lon": -76.41389 + }, + "KNUI": { + "id": "KNUI", + "city": "St. Inigoes, Webster Field, Naval Electronic Systems Engineering Activity", + "state": "MD", + "lat": 38.14889, + "lon": -76.42 + }, + "KOXB": { + "id": "KOXB", + "city": "Ocean City, Ocean City Municipal Airport", + "state": "MD", + "lat": 38.31056, + "lon": -75.12389 + }, + "KRSP": { + "id": "KRSP", + "city": "Camp David", + "state": "MD", + "lat": 39.645, + "lon": -77.468 + }, + "KSBY": { + "id": "KSBY", + "city": "Salisbury, Salisbury-Ocean City Wicomico County Regional Airport", + "state": "MD", + "lat": 38.34056, + "lon": -75.51028 + }, + "KVKX": { + "id": "KVKX", + "city": "POTOMAC", + "state": "MD", + "lat": 38.74761, + "lon": -76.95719 + }, + "KAUG": { + "id": "KAUG", + "city": "Augusta, Augusta State Airport", + "state": "ME", + "lat": 44.32056, + "lon": -69.79722 + }, + "KBGR": { + "id": "KBGR", + "city": "Bangor, Bangor International Airport", + "state": "ME", + "lat": 44.79722, + "lon": -68.81861 + }, + "KBHB": { + "id": "KBHB", + "city": "Bar Harbor, Hancock County-Bar Harbor Airport", + "state": "ME", + "lat": 44.45, + "lon": -68.36667 + }, + "KBXM": { + "id": "KBXM", + "city": "BRUNSWICK", + "state": "ME", + "lat": 43.8923599, + "lon": -69.93883 + }, + "KCAR": { + "id": "KCAR", + "city": "Caribou, Caribou Municipal Airport", + "state": "ME", + "lat": 46.86722, + "lon": -68.01333 + }, + "KFVE": { + "id": "KFVE", + "city": "Frenchville, Northern Aroostook Regional Airport", + "state": "ME", + "lat": 47.2849999, + "lon": -68.30722 + }, + "KGNR": { + "id": "KGNR", + "city": "Greenville", + "state": "ME", + "lat": 45.4646199, + "lon": -69.5538 + }, + "KHUL": { + "id": "KHUL", + "city": "Houlton, Houlton International Airport", + "state": "ME", + "lat": 46.12306, + "lon": -67.79194 + }, + "KIWI": { + "id": "KIWI", + "city": "Wiscasset Airport", + "state": "ME", + "lat": 43.96401, + "lon": -69.7107599 + }, + "KIZG": { + "id": "KIZG", + "city": "Fryeburg, Eastern Slopes Regional Airport", + "state": "ME", + "lat": 43.98917, + "lon": -70.95028 + }, + "KLEW": { + "id": "KLEW", + "city": "Auburn-Lewiston", + "state": "ME", + "lat": 44.05, + "lon": -70.28333 + }, + "KMLT": { + "id": "KMLT", + "city": "Millinocket, Millinocket Municipal Airport", + "state": "ME", + "lat": 45.64778, + "lon": -68.69194 + }, + "KPQI": { + "id": "KPQI", + "city": "Presque Isle", + "state": "ME", + "lat": 46.68333, + "lon": -68.05 + }, + "KPWM": { + "id": "KPWM", + "city": "Portland, Portland International Jetport", + "state": "ME", + "lat": 43.64222, + "lon": -70.30444 + }, + "KRKD": { + "id": "KRKD", + "city": "Rockland, Knox County Regional Airport", + "state": "ME", + "lat": 44.06667, + "lon": -69.1 + }, + "KSFM": { + "id": "KSFM", + "city": "Sanford, Sanford Regional Airport", + "state": "ME", + "lat": 43.4, + "lon": -70.7166699 + }, + "KWVL": { + "id": "KWVL", + "city": "Waterville, Waterville Robert LaFleur Airport", + "state": "ME", + "lat": 44.53333, + "lon": -69.68333 + }, + "KABR": { + "id": "KABR", + "city": "Aberdeen, Aberdeen Regional Airport", + "state": "SD", + "lat": 45.44333, + "lon": -98.41306 + }, + "KAGZ": { + "id": "KAGZ", + "city": "WAGNERMUNC", + "state": "SD", + "lat": 43.06332, + "lon": -98.29618 + }, + "KATY": { + "id": "KATY", + "city": "Watertown, Watertown Municipal Airport", + "state": "SD", + "lat": 44.90472, + "lon": -97.14944 + }, + "KBKX": { + "id": "KBKX", + "city": "Brookings, Brookings Municipal Airport", + "state": "SD", + "lat": 44.3, + "lon": -96.81667 + }, + "KBTN": { + "id": "KBTN", + "city": "BRITTON", + "state": "SD", + "lat": 45.8152199, + "lon": -97.7431299 + }, + "KCUT": { + "id": "KCUT", + "city": "Custer, Custer County Airport", + "state": "SD", + "lat": 43.73306, + "lon": -103.6175 + }, + "KEFC": { + "id": "KEFC", + "city": "BELLEFCHE", + "state": "SD", + "lat": 44.7342, + "lon": -103.86199 + }, + "KFSD": { + "id": "KFSD", + "city": "Sioux Falls, Foss Field", + "state": "SD", + "lat": 43.57694, + "lon": -96.75361 + }, + "KHON": { + "id": "KHON", + "city": "Huron, Huron Regional Airport", + "state": "SD", + "lat": 44.38806, + "lon": -98.22833 + }, + "KHSR": { + "id": "KHSR", + "city": "HOTSPRINGS", + "state": "SD", + "lat": 43.36824, + "lon": -103.38813 + }, + "KICR": { + "id": "KICR", + "city": "Winner, Bob Wiley Field Airport", + "state": "SD", + "lat": 43.39056, + "lon": -99.8425 + }, + "KIEN": { + "id": "KIEN", + "city": "Pine Ridge, Pine Ridge Airport", + "state": "SD", + "lat": 43.02556, + "lon": -102.52306 + }, + "KLEM": { + "id": "KLEM", + "city": "LEMMON", + "state": "SD", + "lat": 45.91869, + "lon": -102.10617 + }, + "KMBG": { + "id": "KMBG", + "city": "Mobridge, Mobridge Municipal Airport", + "state": "SD", + "lat": 45.55, + "lon": -100.40861 + }, + "KMDS": { + "id": "KMDS", + "city": "Madison Municipal Airport", + "state": "SD", + "lat": 44.0164147, + "lon": -97.0855992 + }, + "KMHE": { + "id": "KMHE", + "city": "Mitchell, Mitchell Municipal Airport", + "state": "SD", + "lat": 43.76667, + "lon": -98.03333 + }, + "KMKA": { + "id": "KMKA", + "city": "MILLERMUNC", + "state": "SD", + "lat": 44.5252399, + "lon": -98.95811 + }, + "KPHP": { + "id": "KPHP", + "city": "Philip, Philip Airport", + "state": "SD", + "lat": 44.05111, + "lon": -101.60111 + }, + "KPIR": { + "id": "KPIR", + "city": "Pierre, Pierre Regional Airport", + "state": "SD", + "lat": 44.3827799, + "lon": -100.28583 + }, + "KRAP": { + "id": "KRAP", + "city": "Rapid City, Rapid City Regional Airport", + "state": "SD", + "lat": 44.04556, + "lon": -103.05389 + }, + "KRCA": { + "id": "KRCA", + "city": "Ellsworth Air Force Base", + "state": "SD", + "lat": 44.15, + "lon": -103.1 + }, + "KSPF": { + "id": "KSPF", + "city": "Spearfish / Clyde Ice", + "state": "SD", + "lat": 44.48333, + "lon": -103.78333 + }, + "KSUO": { + "id": "KSUO", + "city": "Rosebud Sioux Tribal Airport", + "state": "SD", + "lat": 43.25846, + "lon": -100.8594899 + }, + "KVMR": { + "id": "KVMR", + "city": "VERMILLION", + "state": "SD", + "lat": 42.76528, + "lon": -96.93425 + }, + "KYKN": { + "id": "KYKN", + "city": "Yankton, Chan Gurney Municipal Airport", + "state": "SD", + "lat": 42.91667, + "lon": -97.38333 + }, + "KAID": { + "id": "KAID", + "city": "Anderson Municipal Airport", + "state": "IN", + "lat": 40.10612, + "lon": -85.60977 + }, + "KANQ": { + "id": "KANQ", + "city": "Angola Tri-State Steuben County Airport", + "state": "IN", + "lat": 41.6404, + "lon": -85.0851 + }, + "KASW": { + "id": "KASW", + "city": "Warsaw, Warsaw Municipal Airport", + "state": "IN", + "lat": 41.27444, + "lon": -85.84 + }, + "KBAK": { + "id": "KBAK", + "city": "Columbus / Bakalar", + "state": "IN", + "lat": 39.26667, + "lon": -85.9 + }, + "KBFR": { + "id": "KBFR", + "city": "Virgil I Grissom Municipal Airport", + "state": "IN", + "lat": 38.84003, + "lon": -86.4453599 + }, + "KBMG": { + "id": "KBMG", + "city": "Bloomington, Monroe County Airport", + "state": "IN", + "lat": 39.14306, + "lon": -86.61667 + }, + "KCFJ": { + "id": "KCFJ", + "city": "Crawfordsville Municipal Airport", + "state": "IN", + "lat": 39.9756, + "lon": -86.9199 + }, + "KDCY": { + "id": "KDCY", + "city": "Daviess County Airport", + "state": "IN", + "lat": 38.7004, + "lon": -87.1297 + }, + "KEKM": { + "id": "KEKM", + "city": "Elkhart Municipal", + "state": "IN", + "lat": 41.71667, + "lon": -86 + }, + "KEVV": { + "id": "KEVV", + "city": "Evansville, Evansville Regional Airport", + "state": "IN", + "lat": 38.0430599, + "lon": -87.52028 + }, + "KEYE": { + "id": "KEYE", + "city": "Indianapolis, Eagle Creek Airpark", + "state": "IN", + "lat": 39.825, + "lon": -86.29583 + }, + "KFKR": { + "id": "KFKR", + "city": "Frankfort Municipal Airport", + "state": "IN", + "lat": 40.2734, + "lon": -86.5622 + }, + "KFRH": { + "id": "KFRH", + "city": "French Lick Municipal Airport", + "state": "IN", + "lat": 38.50622, + "lon": -86.63694 + }, + "KFWA": { + "id": "KFWA", + "city": "Fort Wayne International Airport", + "state": "IN", + "lat": 40.97251, + "lon": -85.20637 + }, + "KGEZ": { + "id": "KGEZ", + "city": "Shelbyville Municipal Airport", + "state": "IN", + "lat": 39.58546, + "lon": -85.79982 + }, + "KGGP": { + "id": "KGGP", + "city": "Logansport/Cass County Airport", + "state": "IN", + "lat": 40.711, + "lon": -86.373 + }, + "KGPC": { + "id": "KGPC", + "city": "Putnam County Regional Airport", + "state": "IN", + "lat": 39.6354, + "lon": -86.8155 + }, + "KGSH": { + "id": "KGSH", + "city": "Goshen, Goshen Municipal Airport", + "state": "IN", + "lat": 41.52611, + "lon": -85.78667 + }, + "KGUS": { + "id": "KGUS", + "city": "Grissom Air Force Base / Peru", + "state": "IN", + "lat": 40.65, + "lon": -86.15 + }, + "KGWB": { + "id": "KGWB", + "city": "Auburn De Kalb County Airport", + "state": "IN", + "lat": 41.307, + "lon": -85.0639999 + }, + "KGYY": { + "id": "KGYY", + "city": "Gary Regional Airport", + "state": "IN", + "lat": 41.61212, + "lon": -87.40908 + }, + "KHFY": { + "id": "KHFY", + "city": "Greenwood Municipal Airport", + "state": "IN", + "lat": 39.6276, + "lon": -86.0879999 + }, + "KHHG": { + "id": "KHHG", + "city": "Huntington Municipal Airport", + "state": "IN", + "lat": 40.8529, + "lon": -85.4571 + }, + "KHLB": { + "id": "KHLB", + "city": "Batesville Airport", + "state": "IN", + "lat": 39.34313, + "lon": -85.25843 + }, + "KHNB": { + "id": "KHNB", + "city": "Huntingburg", + "state": "IN", + "lat": 38.25, + "lon": -86.95 + }, + "KHUF": { + "id": "KHUF", + "city": "Terre Haute Regional Airport", + "state": "IN", + "lat": 39.4429, + "lon": -87.32207 + }, + "KIMS": { + "id": "KIMS", + "city": "Madison Municipal Airport", + "state": "IN", + "lat": 38.7589, + "lon": -85.4655 + }, + "KIND": { + "id": "KIND", + "city": "Indianapolis International Airport", + "state": "IN", + "lat": 39.72518, + "lon": -86.2816 + }, + "KJVY": { + "id": "KJVY", + "city": "Clark Regional Airport", + "state": "IN", + "lat": 38.36661, + "lon": -85.73814 + }, + "KLAF": { + "id": "KLAF", + "city": "Lafayette, Purdue University Airport", + "state": "IN", + "lat": 40.4125, + "lon": -86.9475 + }, + "KMCX": { + "id": "KMCX", + "city": "Monticello White County Airport", + "state": "IN", + "lat": 40.7087999, + "lon": -86.7668 + }, + "KMGC": { + "id": "KMGC", + "city": "Michigan City Municipal Airport", + "state": "IN", + "lat": 41.7033, + "lon": -86.8212 + }, + "KMIE": { + "id": "KMIE", + "city": "Muncie, Delaware County-Johnson Field", + "state": "IN", + "lat": 40.23417, + "lon": -85.39361 + }, + "KMQJ": { + "id": "KMQJ", + "city": "Indianapolis Regional Airport", + "state": "IN", + "lat": 39.84314, + "lon": -85.89774 + }, + "KMZZ": { + "id": "KMZZ", + "city": "Marion Municipal Airport", + "state": "IN", + "lat": 40.49, + "lon": -85.68 + }, + "KOKK": { + "id": "KOKK", + "city": "Kokomo, Kokomo Municipal Airport", + "state": "IN", + "lat": 40.53333, + "lon": -86.06667 + }, + "KOXI": { + "id": "KOXI", + "city": "Starke County Airport", + "state": "IN", + "lat": 41.33, + "lon": -86.665 + }, + "KPLD": { + "id": "KPLD", + "city": "Portland Municipal Airport", + "state": "IN", + "lat": 40.45158, + "lon": -84.98903 + }, + "KPPO": { + "id": "KPPO", + "city": "La Porte Municipal Airport", + "state": "IN", + "lat": 41.5725, + "lon": -86.7345 + }, + "KRCR": { + "id": "KRCR", + "city": "Rochester Fulton County Airport", + "state": "IN", + "lat": 41.06553, + "lon": -86.18169 + }, + "KRID": { + "id": "KRID", + "city": "Richmond Municipal Airport", + "state": "IN", + "lat": 39.7572, + "lon": -84.8428 + }, + "KRZL": { + "id": "KRZL", + "city": "Rensselaer Jasper County Airport", + "state": "IN", + "lat": 40.94789, + "lon": -87.18258 + }, + "KSBN": { + "id": "KSBN", + "city": "South Bend International Airport", + "state": "IN", + "lat": 41.7088899, + "lon": -86.31861 + }, + "KSMD": { + "id": "KSMD", + "city": "Smith Field Airport", + "state": "IN", + "lat": 41.14336, + "lon": -85.15277 + }, + "KTYQ": { + "id": "KTYQ", + "city": "INDIANAPOLIS", + "state": "IN", + "lat": 40.03066, + "lon": -86.2514999 + }, + "KUMP": { + "id": "KUMP", + "city": "Indianapolis Metro Airport", + "state": "IN", + "lat": 39.9354, + "lon": -86.04507 + }, + "KUWL": { + "id": "KUWL", + "city": "New Castle Henry County Airport", + "state": "IN", + "lat": 39.87672, + "lon": -85.32527 + }, + "KVPZ": { + "id": "KVPZ", + "city": "Valparaiso Porter County Municipal Airport", + "state": "IN", + "lat": 41.45349, + "lon": -86.99805 + }, + "KBAC": { + "id": "KBAC", + "city": "Valley City", + "state": "ND", + "lat": 46.9412, + "lon": -98.018 + }, + "KBIS": { + "id": "KBIS", + "city": "Bismarck, Bismarck Municipal Airport", + "state": "ND", + "lat": 46.7825, + "lon": -100.75722 + }, + "KBWP": { + "id": "KBWP", + "city": "Wahpeton, Harry Stern Airport", + "state": "ND", + "lat": 46.24389, + "lon": -96.60722 + }, + "KBWW": { + "id": "KBWW", + "city": "Bowman Regional Airport", + "state": "ND", + "lat": 46.16551, + "lon": -103.30074 + }, + "KDIK": { + "id": "KDIK", + "city": "Dickinson, Dickinson Municipal Airport", + "state": "ND", + "lat": 46.79722, + "lon": -102.80194 + }, + "KDVL": { + "id": "KDVL", + "city": "Devils Lake, Devils Lake Municipal Airport", + "state": "ND", + "lat": 48.11667, + "lon": -98.91667 + }, + "KFAR": { + "id": "KFAR", + "city": "Fargo, Hector International Airport", + "state": "ND", + "lat": 46.92528, + "lon": -96.81111 + }, + "KGAF": { + "id": "KGAF", + "city": "GRAFTON", + "state": "ND", + "lat": 48.4, + "lon": -97.37 + }, + "KGFK": { + "id": "KGFK", + "city": "Grand Forks, Grand Forks International Airport", + "state": "ND", + "lat": 47.94806, + "lon": -97.1825 + }, + "KGWR": { + "id": "KGWR", + "city": "Gwinner", + "state": "ND", + "lat": 46.2187, + "lon": -97.6435 + }, + "KHEI": { + "id": "KHEI", + "city": "Hettinger, Hettinger Municipal Airport", + "state": "ND", + "lat": 46.01056, + "lon": -102.64972 + }, + "KHZE": { + "id": "KHZE", + "city": "HAZEN", + "state": "ND", + "lat": 47.28, + "lon": -101.58 + }, + "KJMS": { + "id": "KJMS", + "city": "Jamestown, Jamestown Municipal Airport", + "state": "ND", + "lat": 46.92972, + "lon": -98.67833 + }, + "KMIB": { + "id": "KMIB", + "city": "Minot Air Force Base", + "state": "ND", + "lat": 48.41667, + "lon": -101.35 + }, + "KMOT": { + "id": "KMOT", + "city": "Minot International Airport", + "state": "ND", + "lat": 48.25203, + "lon": -101.2689 + }, + "KRDR": { + "id": "KRDR", + "city": "Grand Forks Air Force Base", + "state": "ND", + "lat": 47.96667, + "lon": -97.4 + }, + "KRUG": { + "id": "KRUG", + "city": "RUGBY", + "state": "ND", + "lat": 48.38, + "lon": -100.02 + }, + "KXWA": { + "id": "KXWA", + "city": "Williston Basin International Airport", + "state": "ND", + "lat": 48.26086, + "lon": -103.75114 + }, + "KBAM": { + "id": "KBAM", + "city": "Battle Mountain - Lander County Airport", + "state": "NV", + "lat": 40.5989999, + "lon": -116.8743 + }, + "KBVU": { + "id": "KBVU", + "city": "Boulder City Municipal Airport", + "state": "NV", + "lat": 35.9475, + "lon": -114.8611 + }, + "KCXP": { + "id": "KCXP", + "city": "Carson City Airport", + "state": "NV", + "lat": 39.19056, + "lon": -119.73191 + }, + "KDRA": { + "id": "KDRA", + "city": "Mercury, Desert Rock Airport", + "state": "NV", + "lat": 36.6207, + "lon": -116.02868 + }, + "KEKO": { + "id": "KEKO", + "city": "Elko, Elko Regional Airport", + "state": "NV", + "lat": 40.8240399, + "lon": -115.78635 + }, + "KELY": { + "id": "KELY", + "city": "Ely, Ely Airport", + "state": "NV", + "lat": 39.295, + "lon": -114.84528 + }, + "KHND": { + "id": "KHND", + "city": "Las Vegas - Henderson Executive Airport", + "state": "NV", + "lat": 35.97665, + "lon": -115.13221 + }, + "KHTH": { + "id": "KHTH", + "city": "Hawthorne Industrial Airport", + "state": "NV", + "lat": 38.54482, + "lon": -118.63137 + }, + "KINS": { + "id": "KINS", + "city": "Nellis AFB - Indian Springs Auxiliary Airfield", + "state": "NV", + "lat": 36.58573, + "lon": -115.69008 + }, + "KLAS": { + "id": "KLAS", + "city": "Harry Reid International Airport", + "state": "NV", + "lat": 36.07188, + "lon": -115.1634 + }, + "KLOL": { + "id": "KLOL", + "city": "Lovelock, Derby Field Airport", + "state": "NV", + "lat": 40.0683999, + "lon": -118.57017 + }, + "KLSV": { + "id": "KLSV", + "city": "Nellis Air Force Base", + "state": "NV", + "lat": 36.23333, + "lon": -115.03333 + }, + "KMEV": { + "id": "KMEV", + "city": "Minden-Tahoe Airport", + "state": "NV", + "lat": 38.9963, + "lon": -119.75 + }, + "KNFL": { + "id": "KNFL", + "city": "Fallon, Naval Air Station", + "state": "NV", + "lat": 39.43222, + "lon": -118.68556 + }, + "KRNO": { + "id": "KRNO", + "city": "Reno, Reno Tahoe International Airport", + "state": "NV", + "lat": 39.50776, + "lon": -119.76819 + }, + "KRTS": { + "id": "KRTS", + "city": "Reno/Stead", + "state": "NV", + "lat": 39.6682, + "lon": -119.8764 + }, + "KTMT": { + "id": "KTMT", + "city": "Austin Airport", + "state": "NV", + "lat": 39.46794, + "lon": -117.19745 + }, + "KTPH": { + "id": "KTPH", + "city": "Tonopah, Tonopah Airport", + "state": "NV", + "lat": 38.06028, + "lon": -117.08722 + }, + "KVGT": { + "id": "KVGT", + "city": "Las Vegas, North Las Vegas Airport", + "state": "NV", + "lat": 36.21205, + "lon": -115.19395 + }, + "KWMC": { + "id": "KWMC", + "city": "Winnemucca, Winnemucca Municipal Airport", + "state": "NV", + "lat": 40.90194, + "lon": -117.80722 + }, + "KADH": { + "id": "KADH", + "city": "Ada, Ada Municipal Airport", + "state": "OK", + "lat": 34.80444, + "lon": -96.67139 + }, + "KADM": { + "id": "KADM", + "city": "Ardmore, Ardmore Municipal Airport", + "state": "OK", + "lat": 34.30306, + "lon": -97.01944 + }, + "KAVK": { + "id": "KAVK", + "city": "Alva, Alva Regional Airport", + "state": "OK", + "lat": 36.77306, + "lon": -98.67 + }, + "KAXS": { + "id": "KAXS", + "city": "Altus, Altus/Quartz Mountain Regional Airport", + "state": "OK", + "lat": 34.69861, + "lon": -99.33806 + }, + "KBKN": { + "id": "KBKN", + "city": "Blackwell-Tonkawa Municipal Airport", + "state": "OK", + "lat": 36.7451099, + "lon": -97.34958 + }, + "KBVO": { + "id": "KBVO", + "city": "Bartlesville, Bartlesville Municipal Airport", + "state": "OK", + "lat": 36.76833, + "lon": -96.02611 + }, + "KCHK": { + "id": "KCHK", + "city": "Chickasha, Chickasha Municipal Airport", + "state": "OK", + "lat": 35.09611, + "lon": -97.96611 + }, + "KCLK": { + "id": "KCLK", + "city": "Clinton, Clinton Regional Airport", + "state": "OK", + "lat": 35.53806, + "lon": -98.92139 + }, + "KCQB": { + "id": "KCQB", + "city": "Chandler, Chandler Municipal Airport", + "state": "OK", + "lat": 35.72389, + "lon": -96.82028 + }, + "KCSM": { + "id": "KCSM", + "city": "Clinton, Clinton-Sherman Airport", + "state": "OK", + "lat": 35.35667, + "lon": -99.20361 + }, + "KCUH": { + "id": "KCUH", + "city": "Cushing, Cushing Municipal Airport", + "state": "OK", + "lat": 35.94972, + "lon": -96.77278 + }, + "KDUA": { + "id": "KDUA", + "city": "Durant, Eaker Field Airport", + "state": "OK", + "lat": 33.94222, + "lon": -96.39444 + }, + "KDUC": { + "id": "KDUC", + "city": "Duncan, Halliburton Field Airport", + "state": "OK", + "lat": 34.47083, + "lon": -97.9599999 + }, + "KELK": { + "id": "KELK", + "city": "Elk City Regional Business Airport", + "state": "OK", + "lat": 35.4308, + "lon": -99.3943 + }, + "KEND": { + "id": "KEND", + "city": "Vance Air Force Base / Enid", + "state": "OK", + "lat": 36.3333299, + "lon": -97.91667 + }, + "KFDR": { + "id": "KFDR", + "city": "Frederick, Frederick Municipal Airport", + "state": "OK", + "lat": 34.34444, + "lon": -98.98306 + }, + "KFSI": { + "id": "KFSI", + "city": "Fort Sill", + "state": "OK", + "lat": 34.6, + "lon": -98.4 + }, + "KGAG": { + "id": "KGAG", + "city": "Gage, Gage Airport", + "state": "OK", + "lat": 36.29667, + "lon": -99.76889 + }, + "KGCM": { + "id": "KGCM", + "city": "Claremore, Claremore Regional Airport", + "state": "OK", + "lat": 36.29444, + "lon": -95.47972 + }, + "KGMJ": { + "id": "KGMJ", + "city": "Grove, Grove Municipal Airport", + "state": "OK", + "lat": 36.60528, + "lon": -94.73861 + }, + "KGOK": { + "id": "KGOK", + "city": "Guthrie, Guthrie Municipal Airport", + "state": "OK", + "lat": 35.85194, + "lon": -97.4075 + }, + "KGUY": { + "id": "KGUY", + "city": "Guymon / Guymon Municipal Airport", + "state": "OK", + "lat": 36.6816699, + "lon": -101.50528 + }, + "KGZL": { + "id": "KGZL", + "city": "Stigler", + "state": "OK", + "lat": 35.2891, + "lon": -95.0939 + }, + "KHBR": { + "id": "KHBR", + "city": "Hobart, Hobart Municipal Airport", + "state": "OK", + "lat": 34.98944, + "lon": -99.0525 + }, + "KHHW": { + "id": "KHHW", + "city": "Hugo Stan Stamper Municipal Airport", + "state": "OK", + "lat": 34.0348, + "lon": -95.5419 + }, + "KHMY": { + "id": "KHMY", + "city": "MULDROWARMY", + "state": "OK", + "lat": 35.02638, + "lon": -97.23163 + }, + "KHSD": { + "id": "KHSD", + "city": "Sundance Airport", + "state": "OK", + "lat": 35.60183, + "lon": -97.70616 + }, + "KJSV": { + "id": "KJSV", + "city": "Sallisaw, Sallisaw Municipal Airport", + "state": "OK", + "lat": 35.43806, + "lon": -94.80278 + }, + "KJWG": { + "id": "KJWG", + "city": "Watonga, Watonga Airport", + "state": "OK", + "lat": 35.86472, + "lon": -98.42083 + }, + "KLAW": { + "id": "KLAW", + "city": "Lawton, Lawton Municipal Airport", + "state": "OK", + "lat": 34.5575, + "lon": -98.41667 + }, + "KLTS": { + "id": "KLTS", + "city": "Altus Air Force Base", + "state": "OK", + "lat": 34.65, + "lon": -99.26667 + }, + "KMIO": { + "id": "KMIO", + "city": "Miami Regional Airport", + "state": "OK", + "lat": 36.90922, + "lon": -94.8875 + }, + "KMKO": { + "id": "KMKO", + "city": "Muskogee-Davis Regional Airport", + "state": "OK", + "lat": 35.65694, + "lon": -95.35972 + }, + "KMLC": { + "id": "KMLC", + "city": "McAlester, McAlester Regional Airport", + "state": "OK", + "lat": 34.8822199, + "lon": -95.78306 + }, + "KOJA": { + "id": "KOJA", + "city": "Weatherford, Thomas P Stafford Airport", + "state": "OK", + "lat": 35.54472, + "lon": -98.66833 + }, + "KOKC": { + "id": "KOKC", + "city": "Oklahoma City, Will Rogers World Airport", + "state": "OK", + "lat": 35.38861, + "lon": -97.60028 + }, + "KOKM": { + "id": "KOKM", + "city": "Okmulgee, Okmulgee Municipal Airport", + "state": "OK", + "lat": 35.6680599, + "lon": -95.94861 + }, + "KOUN": { + "id": "KOUN", + "city": "Norman / Max Westheimer", + "state": "OK", + "lat": 35.2435, + "lon": -97.4708 + }, + "KOWP": { + "id": "KOWP", + "city": "William R Pogue Municipal Airport", + "state": "OK", + "lat": 36.1753, + "lon": -96.1518 + }, + "KPNC": { + "id": "KPNC", + "city": "Ponca City, Ponca City Municipal Airport", + "state": "OK", + "lat": 36.7305599, + "lon": -97.09972 + }, + "KPVJ": { + "id": "KPVJ", + "city": "Pauls Valley, Pauls Valley Municipal Airport", + "state": "OK", + "lat": 34.71111, + "lon": -97.22333 + }, + "KPWA": { + "id": "KPWA", + "city": "Oklahoma City, Wiley Post Airport", + "state": "OK", + "lat": 35.54111, + "lon": -97.64667 + }, + "KRCE": { + "id": "KRCE", + "city": "Clarence E Page Municipal Airport", + "state": "OK", + "lat": 35.4880799, + "lon": -97.82356 + }, + "KRKR": { + "id": "KRKR", + "city": "Poteau, Robert S Kerr Airport", + "state": "OK", + "lat": 35.02167, + "lon": -94.62139 + }, + "KRQO": { + "id": "KRQO", + "city": "El Reno, El Reno Regional Airport", + "state": "OK", + "lat": 35.4724999, + "lon": -98.00556 + }, + "KRVS": { + "id": "KRVS", + "city": "Tulsa - Jones Jr. Airport", + "state": "OK", + "lat": 36.04255, + "lon": -95.99005 + }, + "KSNL": { + "id": "KSNL", + "city": "Shawnee, Shawnee Municipal Airport", + "state": "OK", + "lat": 35.35722, + "lon": -96.94278 + }, + "KSRE": { + "id": "KSRE", + "city": "Seminole, Seminole Municipal Airport", + "state": "OK", + "lat": 35.27444, + "lon": -96.675 + }, + "KSWO": { + "id": "KSWO", + "city": "Stillwater, Stillwater Regional Airport", + "state": "OK", + "lat": 36.16222, + "lon": -97.08917 + }, + "KTIK": { + "id": "KTIK", + "city": "Tinker Air Force Base", + "state": "OK", + "lat": 35.41667, + "lon": -97.38333 + }, + "KTQH": { + "id": "KTQH", + "city": "Tahlequah, Tahlequah Municipal Airport", + "state": "OK", + "lat": 35.92889, + "lon": -95.00444 + }, + "KTUL": { + "id": "KTUL", + "city": "Tulsa, Tulsa International Airport", + "state": "OK", + "lat": 36.1975, + "lon": -95.88639 + }, + "KWDG": { + "id": "KWDG", + "city": "Enid, Enid Woodring Regional Airport", + "state": "OK", + "lat": 36.37917, + "lon": -97.79111 + }, + "KWWR": { + "id": "KWWR", + "city": "Woodward, West Woodward Airport", + "state": "OK", + "lat": 36.43667, + "lon": -99.5211099 + }, + "KBKW": { + "id": "KBKW", + "city": "Beckley, Raleigh County Memorial Airport", + "state": "WV", + "lat": 37.795, + "lon": -81.12472 + }, + "KBLF": { + "id": "KBLF", + "city": "Bluefield, Mercer County Airport", + "state": "WV", + "lat": 37.29583, + "lon": -81.20778 + }, + "KCBE": { + "id": "KCBE", + "city": "Cumberland, Greater Cumberland Regional Airport", + "state": "WV", + "lat": 39.61528, + "lon": -78.76083 + }, + "KCKB": { + "id": "KCKB", + "city": "Clarksburg, Clarksburg Benedum Airport", + "state": "WV", + "lat": 39.3, + "lon": -80.22472 + }, + "KCRW": { + "id": "KCRW", + "city": "Charleston, Yeager Airport", + "state": "WV", + "lat": 38.37944, + "lon": -81.59139 + }, + "KEKN": { + "id": "KEKN", + "city": "Elkins, Elkins-Randolph County-Jennings Randolph Field", + "state": "WV", + "lat": 38.88528, + "lon": -79.85278 + }, + "KHLG": { + "id": "KHLG", + "city": "Wheeling, Wheeling Ohio County Airport", + "state": "WV", + "lat": 40.17028, + "lon": -80.64444 + }, + "KHTS": { + "id": "KHTS", + "city": "Huntington, Tri-State Airport", + "state": "WV", + "lat": 38.365, + "lon": -82.555 + }, + "KLWB": { + "id": "KLWB", + "city": "Lewisburg / Greenbrier", + "state": "WV", + "lat": 37.86667, + "lon": -80.4 + }, + "KMGW": { + "id": "KMGW", + "city": "Morgantown Municipal-Hart Field", + "state": "WV", + "lat": 39.64985, + "lon": -79.92065 + }, + "KMRB": { + "id": "KMRB", + "city": "Eastern WV Regional Airport/Shepherd Field", + "state": "WV", + "lat": 39.40372, + "lon": -77.975 + }, + "KPKB": { + "id": "KPKB", + "city": "Parkersburg, Mid-Ohio Valley Regional Airport", + "state": "WV", + "lat": 39.345, + "lon": -81.43917 + }, + "KBGF": { + "id": "KBGF", + "city": "Winchester Municipal Airport", + "state": "TN", + "lat": 35.1775, + "lon": -86.0662 + }, + "KBNA": { + "id": "KBNA", + "city": "Nashville, Nashville International Airport", + "state": "TN", + "lat": 36.11889, + "lon": -86.68917 + }, + "KCHA": { + "id": "KCHA", + "city": "Chattanooga, Lovell Field", + "state": "TN", + "lat": 35.03333, + "lon": -85.2 + }, + "KCKV": { + "id": "KCKV", + "city": "Clarksville Outlaw Field", + "state": "TN", + "lat": 36.61689, + "lon": -87.41174 + }, + "KCSV": { + "id": "KCSV", + "city": "Crossville, Crossville Memorial-Whitson Field Airport", + "state": "TN", + "lat": 35.95139, + "lon": -85.0849999 + }, + "KDKX": { + "id": "KDKX", + "city": "Knoxville Downtown Airport", + "state": "TN", + "lat": 35.96581, + "lon": -83.87169 + }, + "KDYR": { + "id": "KDYR", + "city": "Dyersburg, Dyersburg Municipal Airport", + "state": "TN", + "lat": 36, + "lon": -89.4 + }, + "KFYE": { + "id": "KFYE", + "city": "Somerville - Fayette County Airport", + "state": "TN", + "lat": 35.2061, + "lon": -89.3929 + }, + "KFYM": { + "id": "KFYM", + "city": "Fayetteville Municipal Airport", + "state": "TN", + "lat": 35.0597, + "lon": -86.5639999 + }, + "KGCY": { + "id": "KGCY", + "city": "Greeneville-Greene County Municipal Airport", + "state": "TN", + "lat": 36.19601, + "lon": -82.81099 + }, + "KGKT": { + "id": "KGKT", + "city": "Sevierville Gatlinburg - Pigeon Forge Airport", + "state": "TN", + "lat": 35.85681, + "lon": -83.53334 + }, + "KGZS": { + "id": "KGZS", + "city": "Pulaski Abernathy Field Airport", + "state": "TN", + "lat": 35.1537, + "lon": -87.0568 + }, + "KHZD": { + "id": "KHZD", + "city": "Huntingdon Carroll County Airport", + "state": "TN", + "lat": 36.08896, + "lon": -88.46538 + }, + "KJAU": { + "id": "KJAU", + "city": "Jacksboro Campbell County Airport", + "state": "TN", + "lat": 36.3341, + "lon": -84.163 + }, + "KJWN": { + "id": "KJWN", + "city": "John C Tune Airport", + "state": "TN", + "lat": 36.18521, + "lon": -86.88331 + }, + "KLUG": { + "id": "KLUG", + "city": "Ellington Airport", + "state": "TN", + "lat": 35.50697, + "lon": -86.80389 + }, + "KMBT": { + "id": "KMBT", + "city": "Murfreesboro Municipal Airport", + "state": "TN", + "lat": 35.87866, + "lon": -86.37749 + }, + "KMEM": { + "id": "KMEM", + "city": "Memphis International Airport", + "state": "TN", + "lat": 35.05644, + "lon": -89.98634 + }, + "KMKL": { + "id": "KMKL", + "city": "Jackson, McKellar-Sipes Regional Airport", + "state": "TN", + "lat": 35.59306, + "lon": -88.91667 + }, + "KMMI": { + "id": "KMMI", + "city": "Athens McMinn County Airport", + "state": "TN", + "lat": 35.3973, + "lon": -84.5626 + }, + "KAIK": { + "id": "KAIK", + "city": "Aiken Municipal Airport", + "state": "SC", + "lat": 33.649, + "lon": -81.685 + }, + "KAND": { + "id": "KAND", + "city": "Anderson, Anderson County Airport", + "state": "SC", + "lat": 34.49778, + "lon": -82.70972 + }, + "KAQX": { + "id": "KAQX", + "city": "Allendale County Airport", + "state": "SC", + "lat": 32.9951, + "lon": -81.2703 + }, + "KARW": { + "id": "KARW", + "city": "Beaufort County Airport", + "state": "SC", + "lat": 32.412, + "lon": -80.634 + }, + "KBBP": { + "id": "KBBP", + "city": "Marlboro County Jetport", + "state": "SC", + "lat": 34.622, + "lon": -79.734 + }, + "KBNL": { + "id": "KBNL", + "city": "Barnwell Regional Airport", + "state": "SC", + "lat": 33.258, + "lon": -81.388 + }, + "KCAE": { + "id": "KCAE", + "city": "Columbia, Columbia Metropolitan Airport", + "state": "SC", + "lat": 33.94194, + "lon": -81.11806 + }, + "KCDN": { + "id": "KCDN", + "city": "Camden Woodward Field", + "state": "SC", + "lat": 34.284, + "lon": -80.565 + }, + "KCEU": { + "id": "KCEU", + "city": "Clemson, Clemson-Oconee County Airport", + "state": "SC", + "lat": 34.67222, + "lon": -82.88139 + }, + "KCHS": { + "id": "KCHS", + "city": "Charleston, Charleston Air Force Base", + "state": "SC", + "lat": 32.89889, + "lon": -80.04056 + }, + "KCKI": { + "id": "KCKI", + "city": "Kingstree Williamsburg Regional Airport", + "state": "SC", + "lat": 33.717, + "lon": -79.857 + }, + "KCQW": { + "id": "KCQW", + "city": "Cheraw Municipal Lynch Bellinger Field", + "state": "SC", + "lat": 34.713, + "lon": -79.9569999 + }, + "KCRE": { + "id": "KCRE", + "city": "North Myrtle Beach Grand Strand Airport", + "state": "SC", + "lat": 33.81619, + "lon": -78.7204299 + }, + "KCUB": { + "id": "KCUB", + "city": "Columbia - Jim Hamilton L.B. Owens Airport", + "state": "SC", + "lat": 33.97083, + "lon": -80.99444 + }, + "KDCM": { + "id": "KDCM", + "city": "Chester Catawba Regional Airport", + "state": "SC", + "lat": 34.789, + "lon": -81.196 + }, + "KDYB": { + "id": "KDYB", + "city": "Summerville Airport", + "state": "SC", + "lat": 33.063, + "lon": -80.279 + }, + "KEOE": { + "id": "KEOE", + "city": "Newberry County Airport", + "state": "SC", + "lat": 34.309, + "lon": -81.64 + }, + "KFDW": { + "id": "KFDW", + "city": "Winnsboro/Fairfield County Airport", + "state": "SC", + "lat": 34.315, + "lon": -81.109 + }, + "KFLO": { + "id": "KFLO", + "city": "Florence - Florence Regional Airport", + "state": "SC", + "lat": 34.1877799, + "lon": -79.73083 + }, + "KGGE": { + "id": "KGGE", + "city": "Georgetown County Airport ", + "state": "SC", + "lat": 33.3117, + "lon": -79.3196 + }, + "KGMU": { + "id": "KGMU", + "city": "Greenville Downtown Airport", + "state": "SC", + "lat": 34.84873, + "lon": -82.35004 + }, + "KGRD": { + "id": "KGRD", + "city": "Greenwood, Greenwood County Airport", + "state": "SC", + "lat": 34.24722, + "lon": -82.15472 + }, + "KGSP": { + "id": "KGSP", + "city": "Greenville Spartanburg International Airport", + "state": "SC", + "lat": 34.90611, + "lon": -82.2125499 + }, + "KGYH": { + "id": "KGYH", + "city": "Greenville-Donaldson Center Airport", + "state": "SC", + "lat": 34.7583, + "lon": -82.3764 + }, + "KHVS": { + "id": "KHVS", + "city": "Hartsville Regional Airport", + "state": "SC", + "lat": 34.403, + "lon": -80.119 + }, + "KHXD": { + "id": "KHXD", + "city": "Hilton Head Island, Hilton Head Airport", + "state": "SC", + "lat": 32.21667, + "lon": -80.7 + }, + "KHYW": { + "id": "KHYW", + "city": "Conway Horry County Airport", + "state": "SC", + "lat": 33.829, + "lon": -79.122 + }, + "KJZI": { + "id": "KJZI", + "city": "Charleston Executive Airport", + "state": "SC", + "lat": 32.701, + "lon": -80.003 + }, + "KLKR": { + "id": "KLKR", + "city": "Lancaster County-mc Whirter Field", + "state": "SC", + "lat": 34.723, + "lon": -80.855 + }, + "KLQK": { + "id": "KLQK", + "city": "Pickens County Airport", + "state": "SC", + "lat": 34.80997, + "lon": -82.70289 + }, + "KLRO": { + "id": "KLRO", + "city": "Mount Pleasant Regional-Faison Field", + "state": "SC", + "lat": 32.898, + "lon": -79.783 + }, + "KLUX": { + "id": "KLUX", + "city": "Laurens County Airport", + "state": "SC", + "lat": 34.507, + "lon": -81.947 + }, + "KMAO": { + "id": "KMAO", + "city": "Marion County Airport", + "state": "SC", + "lat": 34.181, + "lon": -79.3349999 + }, + "KMKS": { + "id": "KMKS", + "city": "Moncks Corner Berkeley County", + "state": "SC", + "lat": 33.1855, + "lon": -80.0361999 + }, + "KMMT": { + "id": "KMMT", + "city": "McEntire Air National Guard Weather Facility Base", + "state": "SC", + "lat": 33.91667, + "lon": -80.8 + }, + "KMNI": { + "id": "KMNI", + "city": "Manning / Cooper Regional", + "state": "SC", + "lat": 33.5833299, + "lon": -80.2166699 + }, + "KMYR": { + "id": "KMYR", + "city": "Myrtle Beach International Airport", + "state": "SC", + "lat": 33.67975, + "lon": -78.92833 + }, + "KNBC": { + "id": "KNBC", + "city": "Beaufort, Marine Corps Air Station", + "state": "SC", + "lat": 32.4936099, + "lon": -80.7030599 + }, + "KOGB": { + "id": "KOGB", + "city": "Orangeburg, Orangeburg Municipal Airport", + "state": "SC", + "lat": 33.46389, + "lon": -80.85361 + }, + "KRBW": { + "id": "KRBW", + "city": "Walterboro Lowcountry Regional Airport", + "state": "SC", + "lat": 32.921, + "lon": -80.641 + }, + "KSMS": { + "id": "KSMS", + "city": "Sumter Airport", + "state": "SC", + "lat": 33.995, + "lon": -80.361 + }, + "KSPA": { + "id": "KSPA", + "city": "Spartanburg Memorial", + "state": "SC", + "lat": 34.91667, + "lon": -81.95 + }, + "KSSC": { + "id": "KSSC", + "city": "Shaw Air Force Base", + "state": "SC", + "lat": 33.96667, + "lon": -80.48333 + }, + "KUDG": { + "id": "KUDG", + "city": "Darlington, Darlington County Jetport Airport", + "state": "SC", + "lat": 34.44917, + "lon": -79.89028 + }, + "KUZA": { + "id": "KUZA", + "city": "Rock Hill, Rock Hill - York County Airport", + "state": "SC", + "lat": 34.98389, + "lon": -81.05583 + }, + "KXNO": { + "id": "KXNO", + "city": "North Air Force Auxiliary Field", + "state": "SC", + "lat": 33.60949, + "lon": -81.08118 + }, + "KAIG": { + "id": "KAIG", + "city": "Langlade County Airport", + "state": "WI", + "lat": 45.15659, + "lon": -89.11144 + }, + "KARV": { + "id": "KARV", + "city": "Minocqua/Woodruff, Lakeland Airport/Noble F. Lee Memorial Field", + "state": "WI", + "lat": 45.93333, + "lon": -89.73333 + }, + "KASX": { + "id": "KASX", + "city": "John F Kennedy Memorial Airport", + "state": "WI", + "lat": 46.54679, + "lon": -90.91841 + }, + "KATW": { + "id": "KATW", + "city": "Appleton-Outagamie", + "state": "WI", + "lat": 44.2595, + "lon": -88.51567 + }, + "KAUW": { + "id": "KAUW", + "city": "Wausau Downtown Airport", + "state": "WI", + "lat": 44.92759, + "lon": -89.62512 + }, + "KBCK": { + "id": "KBCK", + "city": "Black River Falls Area Airport", + "state": "WI", + "lat": 44.24996, + "lon": -90.84999 + }, + "KBUU": { + "id": "KBUU", + "city": "Burlington Municipal Airport", + "state": "WI", + "lat": 42.69088, + "lon": -88.308 + }, + "KCLI": { + "id": "KCLI", + "city": "Clintonville Municipal Airport", + "state": "WI", + "lat": 44.61526, + "lon": -88.73129 + }, + "KCMY": { + "id": "KCMY", + "city": "Sparta, Sparta / Fort McCoy Airport", + "state": "WI", + "lat": 43.9583299, + "lon": -90.73778 + }, + "KCWA": { + "id": "KCWA", + "city": "Mosinee", + "state": "WI", + "lat": 44.77944, + "lon": -89.67098 + }, + "KDLL": { + "id": "KDLL", + "city": "Baraboo Wisconsin Dells Airport", + "state": "WI", + "lat": 43.52372, + "lon": -89.77345 + }, + "KEAU": { + "id": "KEAU", + "city": "Chippewa Valley Regional Airport", + "state": "WI", + "lat": 44.86668, + "lon": -91.488 + }, + "KEFT": { + "id": "KEFT", + "city": "Monroe Municipal Airport", + "state": "WI", + "lat": 42.61959, + "lon": -89.59309 + }, + "KEGV": { + "id": "KEGV", + "city": "Eagle River Union Airport", + "state": "WI", + "lat": 45.9309299, + "lon": -89.26702 + }, + "KENW": { + "id": "KENW", + "city": "Kenosha, Kenosha Regional Airport", + "state": "WI", + "lat": 42.595, + "lon": -87.9380599 + }, + "KETB": { + "id": "KETB", + "city": "West Bend Municipal Airport", + "state": "WI", + "lat": 43.42256, + "lon": -88.1326 + }, + "KEZS": { + "id": "KEZS", + "city": "Shawano Municipal Airport", + "state": "WI", + "lat": 44.787, + "lon": -88.56 + }, + "KFLD": { + "id": "KFLD", + "city": "Fond Du Lac County Airport", + "state": "WI", + "lat": 43.76955, + "lon": -88.49072 + }, + "KGRB": { + "id": "KGRB", + "city": "Green Bay, Austin Straubel International Airport", + "state": "WI", + "lat": 44.4794399, + "lon": -88.13667 + }, + "KHYR": { + "id": "KHYR", + "city": "Sawyer County Airport", + "state": "WI", + "lat": 46.03029, + "lon": -91.44259 + }, + "KISW": { + "id": "KISW", + "city": "Wisconsin Rapids, Alexander Field South Wood County Airport", + "state": "WI", + "lat": 44.35917, + "lon": -89.83694 + }, + "KJVL": { + "id": "KJVL", + "city": "Janesville-Rock County", + "state": "WI", + "lat": 42.62135, + "lon": -89.04186 + }, + "KLNL": { + "id": "KLNL", + "city": "Land O' Lakes, Kings Land O' Lakes Airport", + "state": "WI", + "lat": 46.1538899, + "lon": -89.21194 + }, + "KLNR": { + "id": "KLNR", + "city": "Lone Rock Tri-County Regional Airport", + "state": "WI", + "lat": 43.21108, + "lon": -90.18735 + }, + "KLSE": { + "id": "KLSE", + "city": "La Crosse - La Crosse Regional Airport", + "state": "WI", + "lat": 43.87944, + "lon": -91.25667 + }, + "KLUM": { + "id": "KLUM", + "city": "Menomonie Municipal Airport-Score Field", + "state": "WI", + "lat": 44.89363, + "lon": -91.86652 + }, + "KMDZ": { + "id": "KMDZ", + "city": "Taylor County Airport", + "state": "WI", + "lat": 45.10462, + "lon": -90.30253 + }, + "KMFI": { + "id": "KMFI", + "city": "Marshfield, Marshfield Municipal Airport", + "state": "WI", + "lat": 44.63806, + "lon": -90.1875 + }, + "KMKE": { + "id": "KMKE", + "city": "Milwaukee, General Mitchell International Airport", + "state": "WI", + "lat": 42.955, + "lon": -87.9044399 + }, + "KMRJ": { + "id": "KMRJ", + "city": "Iowa County Airport", + "state": "WI", + "lat": 42.88754, + "lon": -90.23147 + }, + "KMSN": { + "id": "KMSN", + "city": "Madison, Dane County Regional-Truax Field", + "state": "WI", + "lat": 43.14056, + "lon": -89.34528 + }, + "KMTW": { + "id": "KMTW", + "city": "Manitowoc, Manitowoc County Airport", + "state": "WI", + "lat": 44.13333, + "lon": -87.68333 + }, + "KMWC": { + "id": "KMWC", + "city": "Milwaukee-Timmerman", + "state": "WI", + "lat": 43.10961, + "lon": -88.03048 + }, + "KOCQ": { + "id": "KOCQ", + "city": "Oconto J. Douglas Bake Municipal Airport", + "state": "WI", + "lat": 44.8742, + "lon": -87.9096 + }, + "KOEO": { + "id": "KOEO", + "city": "L O Simenstad Municipal Airport", + "state": "WI", + "lat": 45.31084, + "lon": -92.6948 + }, + "KOLG": { + "id": "KOLG", + "city": "Solon Springs Municipal Airport", + "state": "WI", + "lat": 46.3148, + "lon": -91.8164 + }, + "KOSH": { + "id": "KOSH", + "city": "Wittman Regional Airport", + "state": "WI", + "lat": 43.96701, + "lon": -88.55814 + }, + "KOVS": { + "id": "KOVS", + "city": "Boscobel, Boscobel Airport", + "state": "WI", + "lat": 43.15611, + "lon": -90.6775 + }, + "KPBH": { + "id": "KPBH", + "city": "Phillips / Price County", + "state": "WI", + "lat": 45.7, + "lon": -90.4 + }, + "KPCZ": { + "id": "KPCZ", + "city": "Waupaca Municipal Airport", + "state": "WI", + "lat": 44.33425, + "lon": -89.02023 + }, + "KPDC": { + "id": "KPDC", + "city": "Prairie Du Chien Municipal Airport", + "state": "WI", + "lat": 43.01938, + "lon": -91.12112 + }, + "KPVB": { + "id": "KPVB", + "city": "Platteville Municipal Airport", + "state": "WI", + "lat": 42.69092, + "lon": -90.4412399 + }, + "KRAC": { + "id": "KRAC", + "city": "Racine, Batten International Airport", + "state": "WI", + "lat": 42.75861, + "lon": -87.81778 + }, + "KRCX": { + "id": "KRCX", + "city": "Ladysmith - Rusk County Airport", + "state": "WI", + "lat": 45.4935, + "lon": -90.9985 + }, + "KRGK": { + "id": "KRGK", + "city": "Red Wing - Red Wing Regional Airport", + "state": "WI", + "lat": 44.5926, + "lon": -92.48439 + }, + "KRHI": { + "id": "KRHI", + "city": "Rhinelander, Rhinelander-Oneida County Airport", + "state": "WI", + "lat": 45.63167, + "lon": -89.48222 + }, + "KRNH": { + "id": "KRNH", + "city": "New Richmond Municipal Airport", + "state": "WI", + "lat": 45.14762, + "lon": -92.53349 + }, + "KRPD": { + "id": "KRPD", + "city": "Rice Lake, Rice Lake Regional-Carl's Field Airport", + "state": "WI", + "lat": 45.4180599, + "lon": -91.77361 + }, + "KRRL": { + "id": "KRRL", + "city": "Merrill, Merrill Municipal Airport", + "state": "WI", + "lat": 45.19844, + "lon": -89.70996 + }, + "KRYV": { + "id": "KRYV", + "city": "Watertown", + "state": "WI", + "lat": 43.17016, + "lon": -88.72497 + }, + "KRZN": { + "id": "KRZN", + "city": "Siren, Burnett County Airport", + "state": "WI", + "lat": 45.82278, + "lon": -92.3725 + }, + "KSBM": { + "id": "KSBM", + "city": "Sheboygan County Memorial Airport", + "state": "WI", + "lat": 43.77483, + "lon": -87.84897 + }, + "KSTE": { + "id": "KSTE", + "city": "Stevens Point Municipal Airport", + "state": "WI", + "lat": 44.54371, + "lon": -89.53468 + }, + "KSUE": { + "id": "KSUE", + "city": "Door County Cherryland Airport", + "state": "WI", + "lat": 44.83941, + "lon": -87.42188 + }, + "KSUW": { + "id": "KSUW", + "city": "Richard I. Bong Airport", + "state": "WI", + "lat": 46.68335, + "lon": -92.09254 + }, + "KTKV": { + "id": "KTKV", + "city": "Tomahawk Regional Airport", + "state": "WI", + "lat": 45.46801, + "lon": -89.80962 + }, + "KUBE": { + "id": "KUBE", + "city": "Cumberland", + "state": "WI", + "lat": 45.506, + "lon": -91.9811 + }, + "KUES": { + "id": "KUES", + "city": "Waukesha County Airport", + "state": "WI", + "lat": 43.04245, + "lon": -88.24607 + }, + "KUNU": { + "id": "KUNU", + "city": "Juneau, Dodge County Airport", + "state": "WI", + "lat": 43.42667, + "lon": -88.7033299 + }, + "KVOK": { + "id": "KVOK", + "city": "Volk / Camp Douglas", + "state": "WI", + "lat": 43.93333, + "lon": -90.26667 + }, + "KACY": { + "id": "KACY", + "city": "Atlantic City, Atlantic City International Airport", + "state": "NJ", + "lat": 39.45202, + "lon": -74.56699 + }, + "KBLM": { + "id": "KBLM", + "city": "Belmar-Farmingdale", + "state": "NJ", + "lat": 40.18333, + "lon": -74.13333 + }, + "KCDW": { + "id": "KCDW", + "city": "Caldwell, Essex County Airport", + "state": "NJ", + "lat": 40.87639, + "lon": -74.28306 + }, + "KEWR": { + "id": "KEWR", + "city": "Newark, Newark International Airport", + "state": "NJ", + "lat": 40.6825, + "lon": -74.16944 + }, + "KFWN": { + "id": "KFWN", + "city": "Sussex, Sussex Airport", + "state": "NJ", + "lat": 41.19925, + "lon": -74.62594 + }, + "KLDJ": { + "id": "KLDJ", + "city": "Linden Airport", + "state": "NJ", + "lat": 40.6174, + "lon": -74.2446 + }, + "KMIV": { + "id": "KMIV", + "city": "Millville, Millville Municipal Airport", + "state": "NJ", + "lat": 39.36623, + "lon": -75.0778 + }, + "KMJX": { + "id": "KMJX", + "city": "Miller Air Park", + "state": "NJ", + "lat": 39.927, + "lon": -74.292 + }, + "KMMU": { + "id": "KMMU", + "city": "Morristown Municipal", + "state": "NJ", + "lat": 40.8, + "lon": -74.41667 + }, + "KNEL": { + "id": "KNEL", + "city": "Lakehurst Naval Air Station", + "state": "NJ", + "lat": 40.03661, + "lon": -74.35251 + }, + "KOBI": { + "id": "KOBI", + "city": "CAPE MAY", + "state": "NJ", + "lat": 39.2191, + "lon": -74.7948 + }, + "KSMQ": { + "id": "KSMQ", + "city": "Somerville, Somerset Airport", + "state": "NJ", + "lat": 40.6240499, + "lon": -74.66898 + }, + "KTEB": { + "id": "KTEB", + "city": "Teterboro, Teterboro Airport", + "state": "NJ", + "lat": 40.85889, + "lon": -74.05667 + }, + "KTTN": { + "id": "KTTN", + "city": "Trenton, Mercer County Airport", + "state": "NJ", + "lat": 40.27639, + "lon": -74.81639 + }, + "KVAY": { + "id": "KVAY", + "city": "Mount Holly, South Jersey Regional Airport", + "state": "NJ", + "lat": 39.94076, + "lon": -74.84071 + }, + "KWRI": { + "id": "KWRI", + "city": "Mcguire Air Force Base", + "state": "NJ", + "lat": 40.01667, + "lon": -74.6 + }, + "KWWD": { + "id": "KWWD", + "city": "Wildwood, Cape May County Airport", + "state": "NJ", + "lat": 39.01667, + "lon": -74.91667 + }, + "KELO": { + "id": "KELO", + "city": "Ely, Ely Municipal Airport", + "state": "MN", + "lat": 47.81667, + "lon": -91.83333 + }, + "KEVM": { + "id": "KEVM", + "city": "Eveleth-Virginia Municipal Airport", + "state": "MN", + "lat": 47.4274, + "lon": -92.49717 + }, + "KFBL": { + "id": "KFBL", + "city": "Faribault, Faribault Municipal Airport", + "state": "MN", + "lat": 44.32983, + "lon": -93.31186 + }, + "KFCM": { + "id": "KFCM", + "city": "Minneapolis - Flying Cloud Airport", + "state": "MN", + "lat": 44.83217, + "lon": -93.47051 + }, + "KFFM": { + "id": "KFFM", + "city": "Fergus Falls Municipal Airport-Einar Mickel", + "state": "MN", + "lat": 46.28655, + "lon": -96.15338 + }, + "KFGN": { + "id": "KFGN", + "city": "Flag Island", + "state": "MN", + "lat": 49.31667, + "lon": -94.9 + }, + "KFKA": { + "id": "KFKA", + "city": "Preston, Fillmore County Airport", + "state": "MN", + "lat": 43.67701, + "lon": -92.17422 + }, + "KFOZ": { + "id": "KFOZ", + "city": "Bigfork Municipal Airport", + "state": "MN", + "lat": 47.78317, + "lon": -93.65326 + }, + "KFRM": { + "id": "KFRM", + "city": "Fairmont, Fairmont Municipal Airport", + "state": "MN", + "lat": 43.65, + "lon": -94.41667 + }, + "KFSE": { + "id": "KFSE", + "city": "Fosston, Fosston Municipal Airport", + "state": "MN", + "lat": 47.59278, + "lon": -95.77333 + }, + "KGDB": { + "id": "KGDB", + "city": "Granite Falls, Granite Falls Municipal Airport/Lenzen-Roe Memorial Field", + "state": "MN", + "lat": 44.75306, + "lon": -95.55583 + }, + "KGHW": { + "id": "KGHW", + "city": "Glenwood Municipal Airport", + "state": "MN", + "lat": 45.64564, + "lon": -95.31876 + }, + "KGNA": { + "id": "KGNA", + "city": "Grand Marais, The Bay of Grand Marais", + "state": "MN", + "lat": 47.7472, + "lon": -90.3443999 + }, + "KGPZ": { + "id": "KGPZ", + "city": "Grand Rapids, Grand Rapids/Itasca County Airport-Gordon Newstrom Field", + "state": "MN", + "lat": 47.21667, + "lon": -93.51667 + }, + "KGYL": { + "id": "KGYL", + "city": "Glencoe Municipal Airport", + "state": "MN", + "lat": 44.7588, + "lon": -94.0905 + }, + "KHCD": { + "id": "KHCD", + "city": "Hutchinson, Hutchinson Municipal Airport-Butler Field", + "state": "MN", + "lat": 44.85961, + "lon": -94.38551 + }, + "KHCO": { + "id": "KHCO", + "city": "Hallock Municipal Airport", + "state": "MN", + "lat": 48.75245, + "lon": -96.93759 + }, + "KHIB": { + "id": "KHIB", + "city": "Chisholm-Hibbing Airport", + "state": "MN", + "lat": 47.38039, + "lon": -92.83245 + }, + "KHZX": { + "id": "KHZX", + "city": "Mc Gregor - Isedor Iverson Airport", + "state": "MN", + "lat": 46.61904, + "lon": -93.31267 + }, + "KINL": { + "id": "KINL", + "city": "Falls International Airport", + "state": "MN", + "lat": 48.55944, + "lon": -93.39556 + }, + "KJKJ": { + "id": "KJKJ", + "city": "Moorhead Municipal Airport", + "state": "MN", + "lat": 46.8404, + "lon": -96.65442 + }, + "KJMR": { + "id": "KJMR", + "city": "Mora Municipal Airport", + "state": "MN", + "lat": 45.88863, + "lon": -93.26901 + }, + "KJYG": { + "id": "KJYG", + "city": "St. James Municipal Airport", + "state": "MN", + "lat": 43.98558, + "lon": -94.55299 + }, + "KLJF": { + "id": "KLJF", + "city": "Litchfield Municipal Airport", + "state": "MN", + "lat": 45.09485, + "lon": -94.50837 + }, + "KLVN": { + "id": "KLVN", + "city": "Minneapolis, Airlake Airport", + "state": "MN", + "lat": 44.62778, + "lon": -93.22806 + }, + "KLXL": { + "id": "KLXL", + "city": "Little Falls, Little Falls/Morrison County Airport-Lindbergh Field", + "state": "MN", + "lat": 45.95, + "lon": -94.35 + }, + "KLYV": { + "id": "KLYV", + "city": "Quentin Aanenson Field Airport", + "state": "MN", + "lat": 43.62166, + "lon": -96.2139399 + }, + "KMGG": { + "id": "KMGG", + "city": "Maple Lake, Maple Lake Municipal Airport", + "state": "MN", + "lat": 45.2353499, + "lon": -93.98959 + }, + "KMIC": { + "id": "KMIC", + "city": "Minneapolis, Crystal Airport", + "state": "MN", + "lat": 45.0625, + "lon": -93.35083 + }, + "KMJQ": { + "id": "KMJQ", + "city": "Jackson, Jackson Municipal Airport", + "state": "MN", + "lat": 43.65, + "lon": -94.98333 + }, + "KMKT": { + "id": "KMKT", + "city": "Mankato, Mankato Regional Airport", + "state": "MN", + "lat": 44.21667, + "lon": -93.91667 + }, + "KMML": { + "id": "KMML", + "city": "Marshall, Southwest Minnesota Regional Airport - Marshall/Ryan Field", + "state": "MN", + "lat": 44.45, + "lon": -95.81667 + }, + "KMOX": { + "id": "KMOX", + "city": "Morris, Morris Municipal Airport", + "state": "MN", + "lat": 45.56667, + "lon": -95.9666699 + }, + "KMSP": { + "id": "KMSP", + "city": "Minneapolis, Minneapolis-St. Paul International Airport", + "state": "MN", + "lat": 44.88306, + "lon": -93.22889 + }, + "KMVE": { + "id": "KMVE", + "city": "Montevideo-Chippewa County Airport", + "state": "MN", + "lat": 44.96749, + "lon": -95.71159 + }, + "KMWM": { + "id": "KMWM", + "city": "Windom Municipal Airport", + "state": "MN", + "lat": 43.90999, + "lon": -95.10723 + }, + "KMZH": { + "id": "KMZH", + "city": "Moose Lake Carlton County Airport", + "state": "MN", + "lat": 46.41632, + "lon": -92.80491 + }, + "KONA": { + "id": "KONA", + "city": "Winona, Winona Municipal Airport-Max Conrad Field", + "state": "MN", + "lat": 44.0833299, + "lon": -91.7 + }, + "KORB": { + "id": "KORB", + "city": "Orr Regional Airport", + "state": "MN", + "lat": 48.0170699, + "lon": -92.85376 + }, + "KOTG": { + "id": "KOTG", + "city": "Worthington, Worthington Municipal Airport", + "state": "MN", + "lat": 43.65, + "lon": -95.58333 + }, + "KOVL": { + "id": "KOVL", + "city": "Olivia Regional Airport", + "state": "MN", + "lat": 44.77923, + "lon": -95.03033 + }, + "KOWA": { + "id": "KOWA", + "city": "Owatonna Degner Regional Airport", + "state": "MN", + "lat": 44.11907, + "lon": -93.25687 + }, + "KPEX": { + "id": "KPEX", + "city": "Paynesville, Paynesville Municipal Airport", + "state": "MN", + "lat": 45.37247, + "lon": -94.73878 + }, + "KPKD": { + "id": "KPKD", + "city": "Park Rapids Municipal Airport", + "state": "MN", + "lat": 46.8996799, + "lon": -95.06681 + }, + "KPNM": { + "id": "KPNM", + "city": "Princeton", + "state": "MN", + "lat": 45.56425, + "lon": -93.6080099 + }, + "KPWC": { + "id": "KPWC", + "city": "Pine River Regional Airport", + "state": "MN", + "lat": 46.72654, + "lon": -94.38485 + }, + "KROS": { + "id": "KROS", + "city": "Rush City Regional Airport", + "state": "MN", + "lat": 45.69628, + "lon": -92.95424 + }, + "KROX": { + "id": "KROX", + "city": "Roseau, Roseau Municipal Airport/Rudy Billberg Field", + "state": "MN", + "lat": 48.85, + "lon": -95.7 + }, + "KRRT": { + "id": "KRRT", + "city": "Warroad International Memorial Airport", + "state": "MN", + "lat": 48.93183, + "lon": -95.3404599 + }, + "KRST": { + "id": "KRST", + "city": "Rochester, Rochester International Airport", + "state": "MN", + "lat": 43.90417, + "lon": -92.49167 + }, + "KRWF": { + "id": "KRWF", + "city": "Redwood Falls Municipal Airport", + "state": "MN", + "lat": 44.54828, + "lon": -95.08042 + }, + "KSAZ": { + "id": "KSAZ", + "city": "Staples, Staples Municipal Airport", + "state": "MN", + "lat": 46.38083, + "lon": -94.80667 + }, + "KSGS": { + "id": "KSGS", + "city": "South St. Paul Municipal-Richard E. Flemi", + "state": "MN", + "lat": 44.86006, + "lon": -93.03203 + }, + "KSTC": { + "id": "KSTC", + "city": "St. Cloud Regional Airport", + "state": "MN", + "lat": 45.54415, + "lon": -94.05165 + }, + "KSTP": { + "id": "KSTP", + "city": "Downtown Holman Field", + "state": "MN", + "lat": 44.93237, + "lon": -93.05588 + }, + "KSYN": { + "id": "KSYN", + "city": "Stanton Airfield", + "state": "MN", + "lat": 44.4736199, + "lon": -93.01448 + }, + "KTKC": { + "id": "KTKC", + "city": "Tracy, Tracy Municipal Airport", + "state": "MN", + "lat": 44.24951, + "lon": -95.61189 + }, + "KTOB": { + "id": "KTOB", + "city": "Dodge Center Airport", + "state": "MN", + "lat": 44.02026, + "lon": -92.8295 + }, + "KTVF": { + "id": "KTVF", + "city": "Thief River Falls, Thief River Falls Regional Airport", + "state": "MN", + "lat": 48.06667, + "lon": -96.18333 + }, + "KTWM": { + "id": "KTWM", + "city": "Two Harbors", + "state": "MN", + "lat": 47.05, + "lon": -91.75 + }, + "KULM": { + "id": "KULM", + "city": "New Ulm Municipal Airport", + "state": "MN", + "lat": 44.32274, + "lon": -94.50244 + }, + "KVVV": { + "id": "KVVV", + "city": "Ortonville, Ortonville Muncipal-Martinson Field Airport", + "state": "MN", + "lat": 45.30556, + "lon": -96.42444 + }, + "KVWU": { + "id": "KVWU", + "city": "Waskish Municipal Airport", + "state": "MN", + "lat": 48.15014, + "lon": -94.512 + }, + "KXVG": { + "id": "KXVG", + "city": "Longville, Longville Municipal Airport", + "state": "MN", + "lat": 46.99028, + "lon": -94.20389 + }, + "PCKY": { + "id": "PCKY", + "city": "Pacific Creek at Moran, WY", + "state": "WY", + "lat": 43.8502777, + "lon": -110.5177777 + }, + "KBCE": { + "id": "KBCE", + "city": "Bryce Canyon Airport", + "state": "UT", + "lat": 37.7012799, + "lon": -112.14897 + }, + "KBDG": { + "id": "KBDG", + "city": "Blanding Municipal Airport", + "state": "UT", + "lat": 37.586, + "lon": -109.482 + }, + "KBMC": { + "id": "KBMC", + "city": "Brigham City Regional Airport", + "state": "UT", + "lat": 41.5464, + "lon": -112.0601 + }, + "KCDC": { + "id": "KCDC", + "city": "Cedar City Municipal Airport", + "state": "UT", + "lat": 37.70675, + "lon": -113.09695 + }, + "KCNY": { + "id": "KCNY", + "city": "Moab, Canyonlands Field", + "state": "UT", + "lat": 38.76, + "lon": -109.74472 + }, + "KDPG": { + "id": "KDPG", + "city": "Michael Army Airfield - Dugway Proving Ground", + "state": "UT", + "lat": 40.18376, + "lon": -112.9217 + }, + "KDTA": { + "id": "KDTA", + "city": "Delta, Delta Municipal Airport", + "state": "UT", + "lat": 39.38333, + "lon": -112.50967 + }, + "KENV": { + "id": "KENV", + "city": "Wendover Airport", + "state": "UT", + "lat": 40.72056, + "lon": -114.03583 + }, + "KFOM": { + "id": "KFOM", + "city": "Fillmore", + "state": "UT", + "lat": 38.95814, + "lon": -112.36314 + }, + "KHCR": { + "id": "KHCR", + "city": "Heber Valley Airport", + "state": "UT", + "lat": 40.47742, + "lon": -111.43295 + }, + "KHIF": { + "id": "KHIF", + "city": "Hill Air Force Base", + "state": "UT", + "lat": 41.11112, + "lon": -111.96229 + }, + "KHVE": { + "id": "KHVE", + "city": "Hanksville", + "state": "UT", + "lat": 38.418037, + "lon": -110.704038 + }, + "KKNB": { + "id": "KKNB", + "city": "KANAB MUNICIPAL AIRPORT", + "state": "UT", + "lat": 37.01, + "lon": -112.53 + }, + "KLGU": { + "id": "KLGU", + "city": "Logan-Cache Airport", + "state": "UT", + "lat": 41.78652, + "lon": -111.85187 + }, + "KMLF": { + "id": "KMLF", + "city": "Milford Municipal Airport", + "state": "UT", + "lat": 38.42252, + "lon": -113.01089 + }, + "KOGD": { + "id": "KOGD", + "city": "Ogden-Hinckley Airport", + "state": "UT", + "lat": 41.19406, + "lon": -112.01681 + }, + "KPUC": { + "id": "KPUC", + "city": "Price - Carbon County Regional Airport", + "state": "UT", + "lat": 39.60886, + "lon": -110.75548 + }, + "KPVU": { + "id": "KPVU", + "city": "Provo Municipal Airport", + "state": "UT", + "lat": 40.2239, + "lon": -111.7253 + }, + "KRIF": { + "id": "KRIF", + "city": "Richfield Municipal Airport", + "state": "UT", + "lat": 38.73411, + "lon": -112.10158 + }, + "KSGU": { + "id": "KSGU", + "city": "St George Regional Airport", + "state": "UT", + "lat": 37.0451, + "lon": -113.50561 + }, + "KSLC": { + "id": "KSLC", + "city": "Salt Lake City, Salt Lake City International Airport", + "state": "UT", + "lat": 40.77069, + "lon": -111.96503 + }, + "KSPK": { + "id": "KSPK", + "city": "Spanish Fork Municipal Airport", + "state": "UT", + "lat": 40.145, + "lon": -111.6677 + }, + "KSVR": { + "id": "KSVR", + "city": "South Valley Regional Airport", + "state": "UT", + "lat": 40.6196, + "lon": -111.99016 + }, + "KTVY": { + "id": "KTVY", + "city": "Bolinder Field-Tooele Valley Airport", + "state": "UT", + "lat": 40.61269, + "lon": -112.35362 + }, + "KVEL": { + "id": "KVEL", + "city": "Vernal Airport", + "state": "UT", + "lat": 40.44295, + "lon": -109.51273 + }, + "KAAO": { + "id": "KAAO", + "city": "Wichita Jabara Airport", + "state": "KS", + "lat": 37.74969, + "lon": -97.21908 + }, + "KADT": { + "id": "KADT", + "city": "Atwood-Rawlins County City-County Airport", + "state": "KS", + "lat": 39.84034, + "lon": -101.04248 + }, + "KBEC": { + "id": "KBEC", + "city": "Beech Factory Airport", + "state": "KS", + "lat": 37.69392, + "lon": -97.21492 + }, + "KCBK": { + "id": "KCBK", + "city": "Shalz Field Airport", + "state": "KS", + "lat": 39.42746, + "lon": -101.04662 + }, + "KCFV": { + "id": "KCFV", + "city": "Coffeyville, Coffeyville Municipal Airport", + "state": "KS", + "lat": 37.09111, + "lon": -95.56639 + }, + "KCNK": { + "id": "KCNK", + "city": "Concordia, Blosser Municipal Airport", + "state": "KS", + "lat": 39.55139, + "lon": -97.65056 + }, + "KCNU": { + "id": "KCNU", + "city": "Chanute, Chanute Martin Johnson Airport", + "state": "KS", + "lat": 37.67028, + "lon": -95.48417 + }, + "KDDC": { + "id": "KDDC", + "city": "Dodge City, Dodge City Regional Airport", + "state": "KS", + "lat": 37.77278, + "lon": -99.96972 + }, + "KEGT": { + "id": "KEGT", + "city": "WELLINGTON", + "state": "KS", + "lat": 37.32361, + "lon": -97.38834 + }, + "KEHA": { + "id": "KEHA", + "city": "Elkhart, Elkhart-Morton County Airport", + "state": "KS", + "lat": 37, + "lon": -101.88333 + }, + "KEMP": { + "id": "KEMP", + "city": "Emporia, Emporia Municipal Airport", + "state": "KS", + "lat": 38.32889, + "lon": -96.19389 + }, + "KEQA": { + "id": "KEQA", + "city": "El Dorado Captain Jack Thomas Airport", + "state": "KS", + "lat": 37.77534, + "lon": -96.81449 + }, + "KEWK": { + "id": "KEWK", + "city": "Newton, Newton City/County Airport", + "state": "KS", + "lat": 38.05, + "lon": -97.28333 + }, + "KFOE": { + "id": "KFOE", + "city": "Topeka, Forbes Field", + "state": "KS", + "lat": 38.94139, + "lon": -95.65056 + }, + "KFRI": { + "id": "KFRI", + "city": "Fort Riley - Marshall AAF", + "state": "KS", + "lat": 39.05586, + "lon": -96.76166 + }, + "KFSK": { + "id": "KFSK", + "city": "FORT SCOTT", + "state": "KS", + "lat": 37.79833, + "lon": -94.76933 + }, + "KGBD": { + "id": "KGBD", + "city": "Great Bend, Great Bend Municipal Airport", + "state": "KS", + "lat": 38.35, + "lon": -98.86667 + }, + "KGCK": { + "id": "KGCK", + "city": "Garden City Regional Airport", + "state": "KS", + "lat": 37.9275, + "lon": -100.72444 + }, + "KGLD": { + "id": "KGLD", + "city": "Goodland, Renner Field", + "state": "KS", + "lat": 39.3675, + "lon": -101.69306 + }, + "KHLC": { + "id": "KHLC", + "city": "Hill City, Hill City Municipal Airport", + "state": "KS", + "lat": 39.37472, + "lon": -99.82972 + }, + "KHQG": { + "id": "KHQG", + "city": "Hugoton Municipal Airport", + "state": "KS", + "lat": 37.16308, + "lon": -101.37052 + }, + "KHUT": { + "id": "KHUT", + "city": "Hutchinson, Hutchinson Municipal Airport", + "state": "KS", + "lat": 38.06806, + "lon": -97.86056 + }, + "KHYS": { + "id": "KHYS", + "city": "Hays, Hays Regional Airport", + "state": "KS", + "lat": 38.85, + "lon": -99.26667 + }, + "KIAB": { + "id": "KIAB", + "city": "McConnell Air Force Base", + "state": "KS", + "lat": 37.61667, + "lon": -97.26667 + }, + "KICT": { + "id": "KICT", + "city": "Wichita - Wichita Dwight D. Eisenhower National Airport", + "state": "KS", + "lat": 37.64722, + "lon": -97.42944 + }, + "KIDP": { + "id": "KIDP", + "city": "INDEPENDENCE", + "state": "KS", + "lat": 37.1584, + "lon": -95.7784 + }, + "KIXD": { + "id": "KIXD", + "city": "Olathe, New Century Aircenter", + "state": "KS", + "lat": 38.82444, + "lon": -94.88694 + }, + "KJHN": { + "id": "KJHN", + "city": "Stanton County Municipal Airport", + "state": "KS", + "lat": 37.5782, + "lon": -101.7304 + }, + "KLBL": { + "id": "KLBL", + "city": "Liberal, Liberal Municipal Airport", + "state": "KS", + "lat": 37.05, + "lon": -100.9666699 + }, + "KLWC": { + "id": "KLWC", + "city": "Lawrence, Lawrence Municipal Airport", + "state": "KS", + "lat": 39.00833, + "lon": -95.21167 + }, + "KLYO": { + "id": "KLYO", + "city": "Lyons-Rice County Municipal Airport", + "state": "KS", + "lat": 38.34025, + "lon": -98.22856 + }, + "KMHK": { + "id": "KMHK", + "city": "Manhattan, Manhattan Municipal Airport", + "state": "KS", + "lat": 39.13528, + "lon": -96.67778 + }, + "KMPR": { + "id": "KMPR", + "city": "MCPHERSON", + "state": "KS", + "lat": 38.35244, + "lon": -97.6913299 + }, + "KMYZ": { + "id": "KMYZ", + "city": "Marysville Municipal Airport", + "state": "KS", + "lat": 39.8553, + "lon": -96.6306 + }, + "KNRN": { + "id": "KNRN", + "city": "Norton Municipal Airport", + "state": "KS", + "lat": 39.85047, + "lon": -99.89469 + }, + "KOEL": { + "id": "KOEL", + "city": "Oakley Municipal Airport", + "state": "KS", + "lat": 39.11178, + "lon": -100.81667 + }, + "KOIN": { + "id": "KOIN", + "city": "Oberlin Municipal Airport", + "state": "KS", + "lat": 39.83489, + "lon": -100.5397799 + }, + "KOJC": { + "id": "KOJC", + "city": "Olathe, Johnson County Executive Airport", + "state": "KS", + "lat": 38.85, + "lon": -94.73917 + }, + "KOWI": { + "id": "KOWI", + "city": "Ottawa Municipal Airport", + "state": "KS", + "lat": 38.5409, + "lon": -95.2542 + }, + "KPHG": { + "id": "KPHG", + "city": "PHILLIPSBURG", + "state": "KS", + "lat": 39.735, + "lon": -99.3171 + }, + "KPPF": { + "id": "KPPF", + "city": "Parsons, Tri-City Airport", + "state": "KS", + "lat": 37.32778, + "lon": -95.50417 + }, + "KPTS": { + "id": "KPTS", + "city": "Atkinson Municipal Airport", + "state": "KS", + "lat": 37.4494, + "lon": -94.7311 + }, + "KPTT": { + "id": "KPTT", + "city": "Pratt Municipal", + "state": "KS", + "lat": 37.7, + "lon": -98.75 + }, + "KRSL": { + "id": "KRSL", + "city": "Russell, Russell Municipal Airport", + "state": "KS", + "lat": 38.87278, + "lon": -98.8130599 + }, + "KSLN": { + "id": "KSLN", + "city": "Salina, Salina Municipal Airport", + "state": "KS", + "lat": 38.78, + "lon": -97.64417 + }, + "KSYF": { + "id": "KSYF", + "city": "ST FRANCIS", + "state": "KS", + "lat": 39.763884, + "lon": -101.797861 + }, + "KTOP": { + "id": "KTOP", + "city": "Topeka, Philip Billard Municipal Airport", + "state": "KS", + "lat": 39.0725, + "lon": -95.6258299 + }, + "KTQK": { + "id": "KTQK", + "city": "Scott City Municipal Airport", + "state": "KS", + "lat": 38.47502, + "lon": -100.88444 + }, + "KUKL": { + "id": "KUKL", + "city": "Coffey County Airport", + "state": "KS", + "lat": 38.30247, + "lon": -95.72497 + }, + "KULS": { + "id": "KULS", + "city": "Ulysses Airport", + "state": "KS", + "lat": 37.604, + "lon": -101.37356 + }, + "KWLD": { + "id": "KWLD", + "city": "Winfield / Arkansas City, Strother Field", + "state": "KS", + "lat": 37.1680599, + "lon": -97.03694 + }, + "KALW": { + "id": "KALW", + "city": "Walla Walla Regional Airport", + "state": "WA", + "lat": 46.09462, + "lon": -118.2858 + }, + "KAWO": { + "id": "KAWO", + "city": "Arlington Municipal Airport", + "state": "WA", + "lat": 48.1584999, + "lon": -122.15909 + }, + "KBFI": { + "id": "KBFI", + "city": "Boeing Field - King County International Airport", + "state": "WA", + "lat": 47.54548, + "lon": -122.3147 + }, + "KBLI": { + "id": "KBLI", + "city": "Bellingham, Bellingham International Airport", + "state": "WA", + "lat": 48.79911, + "lon": -122.54064 + }, + "KBVS": { + "id": "KBVS", + "city": "Burlington/Mount Vernon, Skagit Regional Airport", + "state": "WA", + "lat": 48.47083, + "lon": -122.42083 + }, + "KCLM": { + "id": "KCLM", + "city": "Port Angeles Fairchild International Airport", + "state": "WA", + "lat": 48.12194, + "lon": -123.50661 + }, + "KCLS": { + "id": "KCLS", + "city": "Chehalis-Centralia Airport", + "state": "WA", + "lat": 46.677, + "lon": -122.9827 + }, + "KDEW": { + "id": "KDEW", + "city": "Deer Park, Deer Park Airport", + "state": "WA", + "lat": 47.97417, + "lon": -117.42833 + }, + "KDLS": { + "id": "KDLS", + "city": "The Dalles Municipal Airport", + "state": "WA", + "lat": 45.61901, + "lon": -121.16572 + }, + "KEAT": { + "id": "KEAT", + "city": "Wenatchee - Pangborn Memorial Airport", + "state": "WA", + "lat": 47.39749, + "lon": -120.20121 + }, + "KELN": { + "id": "KELN", + "city": "Ellensburg, Ellensburg Bowers Field", + "state": "WA", + "lat": 47.0337699, + "lon": -120.53132 + }, + "KEPH": { + "id": "KEPH", + "city": "Ephrata, Ephrata Municipal Airport", + "state": "WA", + "lat": 47.3075, + "lon": -119.51583 + }, + "KFHR": { + "id": "KFHR", + "city": "Friday Harbor Airport", + "state": "WA", + "lat": 48.52, + "lon": -123.02637 + }, + "KFLW": { + "id": "KFLW", + "city": "Kettle Falls", + "state": "WA", + "lat": 48.595, + "lon": -118.12417 + }, + "KGEG": { + "id": "KGEG", + "city": "Spokane, Spokane International Airport", + "state": "WA", + "lat": 47.62139, + "lon": -117.52778 + }, + "KGRF": { + "id": "KGRF", + "city": "Fort Lewis / Gray U. S. Army Airfield", + "state": "WA", + "lat": 47.11667, + "lon": -122.55 + }, + "KHQM": { + "id": "KHQM", + "city": "Hoquiam, Bowerman Airport", + "state": "WA", + "lat": 46.97111, + "lon": -123.92 + }, + "KKLS": { + "id": "KKLS", + "city": "Southwest Washington Regional Airport", + "state": "WA", + "lat": 46.11553, + "lon": -122.89273 + }, + "KMWH": { + "id": "KMWH", + "city": "Grant County Airport", + "state": "WA", + "lat": 47.19299, + "lon": -119.31451 + }, + "KNCW": { + "id": "KNCW", + "city": "KENNEWICK CANAL", + "state": "WA", + "lat": 46.2652777, + "lon": -119.5694444 + }, + "KNOW": { + "id": "KNOW", + "city": "Port Angeles Coast Guard Air Station", + "state": "WA", + "lat": 48.13333, + "lon": -123.4 + }, + "KNRA": { + "id": "KNRA", + "city": "Coupeville, Outlying Landing Field", + "state": "WA", + "lat": 48.19056, + "lon": -122.63056 + }, + "KNUW": { + "id": "KNUW", + "city": "Whidbey Island Naval Air Station - Ault Field", + "state": "WA", + "lat": 48.35525, + "lon": -122.66352 + }, + "KOLM": { + "id": "KOLM", + "city": "Olympia, Olympia Airport", + "state": "WA", + "lat": 46.97333, + "lon": -122.90333 + }, + "KOMK": { + "id": "KOMK", + "city": "Omak Airport", + "state": "WA", + "lat": 48.46116, + "lon": -119.52086 + }, + "KORS": { + "id": "KORS", + "city": "Eastsound, Orcas Island Airport", + "state": "WA", + "lat": 48.70806, + "lon": -122.91028 + }, + "KPAE": { + "id": "KPAE", + "city": "Everett Snohomish County", + "state": "WA", + "lat": 47.92331, + "lon": -122.28305 + }, + "KPLU": { + "id": "KPLU", + "city": "Pierce County-Thun Field", + "state": "WA", + "lat": 47.104, + "lon": -122.287 + }, + "KPSC": { + "id": "KPSC", + "city": "Tri-Cities Airport", + "state": "WA", + "lat": 46.26955, + "lon": -119.11813 + }, + "KPUW": { + "id": "KPUW", + "city": "Pullman / Moscow Regional Airport", + "state": "WA", + "lat": 46.74377, + "lon": -117.11579 + }, + "KPWT": { + "id": "KPWT", + "city": "Bremerton, Bremerton National Airport", + "state": "WA", + "lat": 47.5, + "lon": -122.75 + }, + "KRLD": { + "id": "KRLD", + "city": "Richland Airport", + "state": "WA", + "lat": 46.30859, + "lon": -119.3058 + }, + "KRNT": { + "id": "KRNT", + "city": "Renton Municipal Airport", + "state": "WA", + "lat": 47.49509, + "lon": -122.21437 + }, + "KSEA": { + "id": "KSEA", + "city": "Seattle, Seattle-Tacoma International Airport", + "state": "WA", + "lat": 47.4447199, + "lon": -122.31361 + }, + "KSFF": { + "id": "KSFF", + "city": "Spokane, Felts Field", + "state": "WA", + "lat": 47.68556, + "lon": -117.32028 + }, + "KSHN": { + "id": "KSHN", + "city": "Shelton, Shelton Sanderson Field", + "state": "WA", + "lat": 47.23806, + "lon": -123.14083 + }, + "KSKA": { + "id": "KSKA", + "city": "Fairchild Air Force Base", + "state": "WA", + "lat": 47.61667, + "lon": -117.65 + }, + "KSMP": { + "id": "KSMP", + "city": "Stampede Pass", + "state": "WA", + "lat": 47.27648, + "lon": -121.33817 + }, + "KTCM": { + "id": "KTCM", + "city": "Tacoma / McChord Air Force Base", + "state": "WA", + "lat": 47.15, + "lon": -122.48333 + }, + "KTCW": { + "id": "KTCW", + "city": "KITTITAS CANAL", + "state": "WA", + "lat": 47.2388888, + "lon": -121.1833333 + }, + "KTIW": { + "id": "KTIW", + "city": "Tacoma, Tacoma Narrows Airport", + "state": "WA", + "lat": 47.2675, + "lon": -122.57611 + }, + "KUIL": { + "id": "KUIL", + "city": "Quillayute, Quillayute State Airport", + "state": "WA", + "lat": 47.9375, + "lon": -124.555 + }, + "KVUO": { + "id": "KVUO", + "city": "Pearson Airfield", + "state": "WA", + "lat": 45.62103, + "lon": -122.65419 + }, + "KYKM": { + "id": "KYKM", + "city": "Yakima Air Terminal - McAllister Field", + "state": "WA", + "lat": 46.56402, + "lon": -120.53484 + }, + "KABE": { + "id": "KABE", + "city": "Allentown, Lehigh Valley International Airport", + "state": "PA", + "lat": 40.64985, + "lon": -75.44771 + }, + "KAFJ": { + "id": "KAFJ", + "city": "Washington County Airport", + "state": "PA", + "lat": 40.13624, + "lon": -80.28512 + }, + "KAGC": { + "id": "KAGC", + "city": "Pittsburgh - Allegheny County Airport", + "state": "PA", + "lat": 40.35521, + "lon": -79.92144 + }, + "KAOO": { + "id": "KAOO", + "city": "Altoona - Blair County Airport", + "state": "PA", + "lat": 40.29994, + "lon": -78.3168 + }, + "KAVP": { + "id": "KAVP", + "city": "Wilkes-Barre - Scranton, Wilkes-Barre / Scranton International Airport", + "state": "PA", + "lat": 41.33889, + "lon": -75.72667 + }, + "KBFD": { + "id": "KBFD", + "city": "Bradford Regional Airport", + "state": "PA", + "lat": 41.79838, + "lon": -78.63539 + }, + "KBTP": { + "id": "KBTP", + "city": "Pittsburgh/Butler Regional Airport", + "state": "PA", + "lat": 40.77658, + "lon": -79.95672 + }, + "KBVI": { + "id": "KBVI", + "city": "Beaver County Airport", + "state": "PA", + "lat": 40.77351, + "lon": -80.38248 + }, + "KCKZ": { + "id": "KCKZ", + "city": "Pennridge Airport", + "state": "PA", + "lat": 40.38919, + "lon": -75.29047 + }, + "KCXY": { + "id": "KCXY", + "city": "Harrisburg, Capital City Airport", + "state": "PA", + "lat": 40.21843, + "lon": -76.8552 + }, + "KDUJ": { + "id": "KDUJ", + "city": "Du Bois - Jefferson County Airport", + "state": "PA", + "lat": 41.17948, + "lon": -78.89326 + }, + "KDYL": { + "id": "KDYL", + "city": "Doylestown, Doylestown Airport", + "state": "PA", + "lat": 40.33016, + "lon": -75.12286 + }, + "KERI": { + "id": "KERI", + "city": "Erie, Erie International Airport", + "state": "PA", + "lat": 42.08, + "lon": -80.1825 + }, + "KFIG": { + "id": "KFIG", + "city": "Clearfield, Clearfield-Lawrence Airport", + "state": "PA", + "lat": 41.04667, + "lon": -78.41167 + }, + "KFKL": { + "id": "KFKL", + "city": "Venango Regional Airport", + "state": "PA", + "lat": 41.38051, + "lon": -79.86029 + }, + "KGKJ": { + "id": "KGKJ", + "city": "Port Meadville Airport", + "state": "PA", + "lat": 41.6258399, + "lon": -80.21231 + }, + "KHMZ": { + "id": "KHMZ", + "city": "Bedford, Bedford County Airport", + "state": "PA", + "lat": 40.08528, + "lon": -78.51222 + }, + "KHZL": { + "id": "KHZL", + "city": "Hazleton Municipal Airport", + "state": "PA", + "lat": 40.98447, + "lon": -75.99005 + }, + "KIDI": { + "id": "KIDI", + "city": "Indiana County Airport - Jimmy Stewart Field", + "state": "PA", + "lat": 40.6337199, + "lon": -79.10362 + }, + "KIPT": { + "id": "KIPT", + "city": "Williamsport - Lycoming County Airport", + "state": "PA", + "lat": 41.24298, + "lon": -76.92173 + }, + "KJST": { + "id": "KJST", + "city": "Johnstown - Cambria County Airport", + "state": "PA", + "lat": 40.3149, + "lon": -78.83074 + }, + "KLBE": { + "id": "KLBE", + "city": "Arnold Palmer Regional Airport", + "state": "PA", + "lat": 40.2767399, + "lon": -79.40393 + }, + "KLNS": { + "id": "KLNS", + "city": "Lancaster, Lancaster Airport", + "state": "PA", + "lat": 40.1205799, + "lon": -76.29446 + }, + "KLOM": { + "id": "KLOM", + "city": "Philadelphia - Wings Field Airport", + "state": "PA", + "lat": 40.13758, + "lon": -75.2684 + }, + "KMDT": { + "id": "KMDT", + "city": "Harrisburg, Harrisburg International Airport", + "state": "PA", + "lat": 40.19361, + "lon": -76.76333 + }, + "KMPO": { + "id": "KMPO", + "city": "Mount Pocono, Pocono Mountains Municipal Airport", + "state": "PA", + "lat": 41.13821, + "lon": -75.37971 + }, + "KMQS": { + "id": "KMQS", + "city": "Chester County Airport", + "state": "PA", + "lat": 39.98333, + "lon": -75.86667 + }, + "KMUI": { + "id": "KMUI", + "city": "Muir Army Air Field / Indiantown", + "state": "PA", + "lat": 40.43808, + "lon": -76.56434 + }, + "KOQN": { + "id": "KOQN", + "city": "Brandywine Regional Airport", + "state": "PA", + "lat": 39.99011, + "lon": -75.5819 + }, + "KOYM": { + "id": "KOYM", + "city": "St Marys Municipal Airport", + "state": "PA", + "lat": 41.41248, + "lon": -78.50263 + }, + "KPHL": { + "id": "KPHL", + "city": "Philadelphia, Philadelphia International Airport", + "state": "PA", + "lat": 39.87327, + "lon": -75.22678 + }, + "KPIT": { + "id": "KPIT", + "city": "Pittsburgh International Airport", + "state": "PA", + "lat": 40.4846, + "lon": -80.21447 + }, + "KPJC": { + "id": "KPJC", + "city": "Zelienople Municipal Airport", + "state": "PA", + "lat": 40.80095, + "lon": -80.16242 + }, + "KPNE": { + "id": "KPNE", + "city": "Philadelphia, Northeast Philadelphia Airport", + "state": "PA", + "lat": 40.07889, + "lon": -75.01361 + }, + "KPTW": { + "id": "KPTW", + "city": "Pottstown, Pottstown Limerick Airport", + "state": "PA", + "lat": 40.23802, + "lon": -75.5548699 + }, + "KRDG": { + "id": "KRDG", + "city": "Reading, Reading Regional Airport", + "state": "PA", + "lat": 40.37333, + "lon": -75.95944 + }, + "KRVL": { + "id": "KRVL", + "city": "Reedsville / Mifflin", + "state": "PA", + "lat": 40.68333, + "lon": -77.63333 + }, + "KSEG": { + "id": "KSEG", + "city": "Selinsgrove Penn Valley Airport", + "state": "PA", + "lat": 40.81929, + "lon": -76.86582 + }, + "KTHV": { + "id": "KTHV", + "city": "York, York Airport", + "state": "PA", + "lat": 39.91944, + "lon": -76.87694 + }, + "KUCP": { + "id": "KUCP", + "city": "New Castle Municipal Airport", + "state": "PA", + "lat": 41.02282, + "lon": -80.41533 + }, + "KUKT": { + "id": "KUKT", + "city": "Quakertown Airport", + "state": "PA", + "lat": 40.4368, + "lon": -75.38016 + }, + "KUNV": { + "id": "KUNV", + "city": "State College Regional Airport", + "state": "PA", + "lat": 40.85, + "lon": -77.8475799 + }, + "KVVS": { + "id": "KVVS", + "city": "Joseph A Hardy Connellsville Airport", + "state": "PA", + "lat": 39.95906, + "lon": -79.65742 + }, + "KXLL": { + "id": "KXLL", + "city": "Allentown Queen City Municipal Airport", + "state": "PA", + "lat": 40.57, + "lon": -75.488 + }, + "KZER": { + "id": "KZER", + "city": "Schuylkill County/Joe Zerbey Airport", + "state": "PA", + "lat": 40.70675, + "lon": -76.37375 + }, + "KABY": { + "id": "KABY", + "city": "Southwest Georgia Regional Airport", + "state": "GA", + "lat": 31.53652, + "lon": -84.19571 + }, + "KACJ": { + "id": "KACJ", + "city": "Americus Souther Field Airport", + "state": "GA", + "lat": 32.11081, + "lon": -84.18886 + }, + "KAGS": { + "id": "KAGS", + "city": "Augusta, Bush Field", + "state": "GA", + "lat": 33.36444, + "lon": -81.96333 + }, + "KAHN": { + "id": "KAHN", + "city": "Athens, Athens Airport", + "state": "GA", + "lat": 33.95083, + "lon": -83.3280599 + }, + "KAJR": { + "id": "KAJR", + "city": "Cornelia Habersham County Airport", + "state": "GA", + "lat": 34.4998, + "lon": -83.5567 + }, + "KAMG": { + "id": "KAMG", + "city": "Alma, Bacon County Airport", + "state": "GA", + "lat": 31.53611, + "lon": -82.50667 + }, + "KATL": { + "id": "KATL", + "city": "Atlanta, Hartsfield - Jackson Atlanta International Airport", + "state": "GA", + "lat": 33.64028, + "lon": -84.42694 + }, + "KAYS": { + "id": "KAYS", + "city": "Waycross / Ware County, Ga", + "state": "GA", + "lat": 31.25, + "lon": -82.4 + }, + "KAZE": { + "id": "KAZE", + "city": "Hazlehurst Airport", + "state": "GA", + "lat": 31.8847, + "lon": -82.6474 + }, + "KBGE": { + "id": "KBGE", + "city": "Bainbridge, Decatur County Industrial Air Park Airport", + "state": "GA", + "lat": 30.96667, + "lon": -84.63333 + }, + "KBHC": { + "id": "KBHC", + "city": "Baxley Municipal Airport", + "state": "GA", + "lat": 31.7138, + "lon": -82.3938 + }, + "KBIJ": { + "id": "KBIJ", + "city": "Blakely, Early County Airport", + "state": "GA", + "lat": 31.39694, + "lon": -84.895 + }, + "KBQK": { + "id": "KBQK", + "city": "Brunswick / Glynco", + "state": "GA", + "lat": 31.25, + "lon": -81.4666699 + }, + "KCCO": { + "id": "KCCO", + "city": "Newnan, Newnan Coweta County Airport", + "state": "GA", + "lat": 33.31222, + "lon": -84.77028 + }, + "KCNI": { + "id": "KCNI", + "city": "Canton, Cherokee County Airport", + "state": "GA", + "lat": 34.31056, + "lon": -84.42389 + }, + "KCPP": { + "id": "KCPP", + "city": "Greene County Regional Airport", + "state": "GA", + "lat": 33.5979699, + "lon": -83.13826 + }, + "KCSG": { + "id": "KCSG", + "city": "Columbus, Columbus Metropolitan Airport", + "state": "GA", + "lat": 32.51611, + "lon": -84.94222 + }, + "KCTJ": { + "id": "KCTJ", + "city": "Carrollton West Georgia Regional Airport", + "state": "GA", + "lat": 33.63, + "lon": -85.15 + }, + "KCVC": { + "id": "KCVC", + "city": "Covington Municipal Airport", + "state": "GA", + "lat": 33.632, + "lon": -83.85 + }, + "KCWV": { + "id": "KCWV", + "city": "Claxton Evans County Airport", + "state": "GA", + "lat": 32.1950999, + "lon": -81.8696 + }, + "KCXU": { + "id": "KCXU", + "city": "Camilla-Mitchell County Airport", + "state": "GA", + "lat": 31.2132, + "lon": -84.2352 + }, + "KCZL": { + "id": "KCZL", + "city": "Calhoun Tom B. David Field Airport", + "state": "GA", + "lat": 34.4554, + "lon": -84.9392 + }, + "KDBN": { + "id": "KDBN", + "city": "Dublin, W H 'Bud' Barron Airport", + "state": "GA", + "lat": 32.56444, + "lon": -82.985 + }, + "KDNL": { + "id": "KDNL", + "city": "Augusta Daniel Field", + "state": "GA", + "lat": 33.4669, + "lon": -82.03836 + }, + "KDNN": { + "id": "KDNN", + "city": "Dalton, Dalton Municipal Airport", + "state": "GA", + "lat": 34.72167, + "lon": -84.86917 + }, + "KDQH": { + "id": "KDQH", + "city": "Douglas, Douglas Municipal Airport", + "state": "GA", + "lat": 31.47667, + "lon": -82.86028 + }, + "KDZJ": { + "id": "KDZJ", + "city": "Blairsville Airport", + "state": "GA", + "lat": 34.8544, + "lon": -83.9973 + }, + "KEBA": { + "id": "KEBA", + "city": "Elbert County - Patz Field", + "state": "GA", + "lat": 34.095, + "lon": -82.81583 + }, + "KEZM": { + "id": "KEZM", + "city": "Eastman, Heart of Georgia Regional Airport", + "state": "GA", + "lat": 32.21417, + "lon": -83.12778 + }, + "KFFC": { + "id": "KFFC", + "city": "Atlanta Regional Airport-Falcon Field", + "state": "GA", + "lat": 33.35436, + "lon": -84.56893 + }, + "KFTY": { + "id": "KFTY", + "city": "Fulton County Airport-Brown Field", + "state": "GA", + "lat": 33.77764, + "lon": -84.52461 + }, + "KFZG": { + "id": "KFZG", + "city": "Fitzgerald Municipal Airport", + "state": "GA", + "lat": 31.6839, + "lon": -83.2709 + }, + "KGVL": { + "id": "KGVL", + "city": "Gainesville, Gilmer Memorial Airport", + "state": "GA", + "lat": 34.27194, + "lon": -83.83028 + }, + "KHMP": { + "id": "KHMP", + "city": "Henry County Airport", + "state": "GA", + "lat": 33.3899, + "lon": -84.331 + }, + "KHOE": { + "id": "KHOE", + "city": "Homerville Airport", + "state": "GA", + "lat": 31.0559, + "lon": -82.7741 + }, + "KHQU": { + "id": "KHQU", + "city": "Thomson, Thomson-McDuffie County Airport", + "state": "GA", + "lat": 33.52944, + "lon": -82.51639 + }, + "KIIY": { + "id": "KIIY", + "city": "Washington, Washington-Wilkes County Airport", + "state": "GA", + "lat": 33.77972, + "lon": -82.81639 + }, + "KJCA": { + "id": "KJCA", + "city": "Jackson County Airport", + "state": "GA", + "lat": 34.17586, + "lon": -83.5616 + }, + "KJES": { + "id": "KJES", + "city": "Jesup-Wayne County Airport", + "state": "GA", + "lat": 31.554, + "lon": -81.8824999 + }, + "KJYL": { + "id": "KJYL", + "city": "Sylvania, Plantation Airpark", + "state": "GA", + "lat": 32.64528, + "lon": -81.59639 + }, + "KJZP": { + "id": "KJZP", + "city": "Jasper Pickens County Airport", + "state": "GA", + "lat": 34.45417, + "lon": -84.45971 + }, + "KLGC": { + "id": "KLGC", + "city": "LaGrange-Callaway Airport", + "state": "GA", + "lat": 33.00617, + "lon": -85.06609 + }, + "KLHW": { + "id": "KLHW", + "city": "Wright Army Airfield (Fort Stewart)/Midcoast Regional Airport", + "state": "GA", + "lat": 31.88724, + "lon": -81.56244 + }, + "KLSF": { + "id": "KLSF", + "city": "Fort Benning", + "state": "GA", + "lat": 32.3333299, + "lon": -84.83333 + }, + "KLZU": { + "id": "KLZU", + "city": "Gwinnett County Airport-Briscoe Field", + "state": "GA", + "lat": 33.98288, + "lon": -83.95842 + }, + "KMCN": { + "id": "KMCN", + "city": "Middle Georgia Regional Airport", + "state": "GA", + "lat": 32.68892, + "lon": -83.65293 + }, + "KMGE": { + "id": "KMGE", + "city": "Marietta / Dobbins Air Force Base", + "state": "GA", + "lat": 33.91667, + "lon": -84.51667 + }, + "KMGR": { + "id": "KMGR", + "city": "Moultrie, Moultrie Municipal Airport", + "state": "GA", + "lat": 31.08472, + "lon": -83.80306 + }, + "KMHP": { + "id": "KMHP", + "city": "Metter Municipal Airport", + "state": "GA", + "lat": 32.37397, + "lon": -82.08144 + }, + "KMLJ": { + "id": "KMLJ", + "city": "Milledgeville, Baldwin County Airport", + "state": "GA", + "lat": 33.15417, + "lon": -83.24056 + }, + "KMQW": { + "id": "KMQW", + "city": "Telfair-Wheeler Airport", + "state": "GA", + "lat": 32.09699, + "lon": -82.8794099 + }, + "KOPN": { + "id": "KOPN", + "city": "Thomaston, Thomaston-Upson County Airport", + "state": "GA", + "lat": 32.955, + "lon": -84.2644399 + }, + "KPDK": { + "id": "KPDK", + "city": "Atlanta, De Kalb-Peachtree Airport", + "state": "GA", + "lat": 33.87833, + "lon": -84.29806 + }, + "KPIM": { + "id": "KPIM", + "city": "Pine Mountain Harris County Airport", + "state": "GA", + "lat": 32.8407, + "lon": -84.8824 + }, + "KPUJ": { + "id": "KPUJ", + "city": "Dallas Paulding County Regional Airport", + "state": "GA", + "lat": 33.9189999, + "lon": -84.952 + }, + "KPXE": { + "id": "KPXE", + "city": "Perry-Houston County Airport", + "state": "GA", + "lat": 32.5105999, + "lon": -83.7673 + }, + "KRMG": { + "id": "KRMG", + "city": "Rome, R. B. Russell Airport", + "state": "GA", + "lat": 34.34778, + "lon": -85.1611099 + }, + "KRVJ": { + "id": "KRVJ", + "city": "Swinton Smith Field at Reidsville Municipal Airport", + "state": "GA", + "lat": 32.0594899, + "lon": -82.15358 + }, + "KRYY": { + "id": "KRYY", + "city": "Cobb County International Airport - McCollum Field", + "state": "GA", + "lat": 34.01467, + "lon": -84.59635 + }, + "KSAV": { + "id": "KSAV", + "city": "Savannah-Hilton Head International Airport", + "state": "GA", + "lat": 32.1313699, + "lon": -81.20226 + }, + "KSBO": { + "id": "KSBO", + "city": "Swainsboro Emanuel County Airport", + "state": "GA", + "lat": 32.6091, + "lon": -82.3699 + }, + "KSSI": { + "id": "KSSI", + "city": "Brunswick, Malcolm McKinnon Airport", + "state": "GA", + "lat": 31.15167, + "lon": -81.39139 + }, + "KSVN": { + "id": "KSVN", + "city": "Hunter U. S. Army Airfield", + "state": "GA", + "lat": 32.01667, + "lon": -81.15 + }, + "KTBR": { + "id": "KTBR", + "city": "Statesboro, Statesboro-Bulloch County Airport", + "state": "GA", + "lat": 32.48306, + "lon": -81.7372199 + }, + "KTMA": { + "id": "KTMA", + "city": "Tifton Henry Tift Myers", + "state": "GA", + "lat": 31.429, + "lon": -83.4885 + }, + "KTOC": { + "id": "KTOC", + "city": "Toccoa Le Tourneau Airport", + "state": "GA", + "lat": 34.5927999, + "lon": -83.2964 + }, + "KTVI": { + "id": "KTVI", + "city": "Thomasville Regional Airport", + "state": "GA", + "lat": 30.90179, + "lon": -83.88113 + }, + "KVAD": { + "id": "KVAD", + "city": "Moody Air Force Base", + "state": "GA", + "lat": 30.97913, + "lon": -83.19247 + }, + "KVDI": { + "id": "KVDI", + "city": "Vidalia, Vidalia Municipal Airport", + "state": "GA", + "lat": 32.1925, + "lon": -82.37194 + }, + "KVLD": { + "id": "KVLD", + "city": "Valdosta Regional Airport", + "state": "GA", + "lat": 30.77632, + "lon": -83.27389 + }, + "KVPC": { + "id": "KVPC", + "city": "Cartersville Airport", + "state": "GA", + "lat": 34.11589, + "lon": -84.85064 + }, + "KWDR": { + "id": "KWDR", + "city": "Winder, Winder-Barrow Airport", + "state": "GA", + "lat": 33.98222, + "lon": -83.66806 + }, + "KWRB": { + "id": "KWRB", + "city": "Warner Robins Air Force Base", + "state": "GA", + "lat": 32.63333, + "lon": -83.6 + }, + "KMNV": { + "id": "KMNV", + "city": "Monroe County Airport", + "state": "TN", + "lat": 35.54522, + "lon": -84.38039 + }, + "KMOR": { + "id": "KMOR", + "city": "Morristown Moore-Murrell Airport", + "state": "TN", + "lat": 36.1794, + "lon": -83.3754 + }, + "KMQY": { + "id": "KMQY", + "city": "Smyrna, Smyrna Airport", + "state": "TN", + "lat": 36.00889, + "lon": -86.52 + }, + "KMRC": { + "id": "KMRC", + "city": "Columbia / Maury County", + "state": "TN", + "lat": 35.55, + "lon": -87.18333 + }, + "KNQA": { + "id": "KNQA", + "city": "Millington, Millington Municipal Airport", + "state": "TN", + "lat": 35.35667, + "lon": -89.8702799 + }, + "KOQT": { + "id": "KOQT", + "city": "Oak Ridge", + "state": "TN", + "lat": 36.02278, + "lon": -84.23333 + }, + "KPHT": { + "id": "KPHT", + "city": "Paris - Henry County Airport", + "state": "TN", + "lat": 36.34, + "lon": -88.38 + }, + "KRKW": { + "id": "KRKW", + "city": "Rockwood Municipal Airport", + "state": "TN", + "lat": 35.92501, + "lon": -84.691 + }, + "KRNC": { + "id": "KRNC", + "city": "McMinnville Warren County Memorial Airport", + "state": "TN", + "lat": 35.6991, + "lon": -85.8402 + }, + "KRZR": { + "id": "KRZR", + "city": "Cleveland Regional Jetport", + "state": "TN", + "lat": 35.2115, + "lon": -84.7998 + }, + "KSCX": { + "id": "KSCX", + "city": "Scott Municipal Airport", + "state": "TN", + "lat": 36.45569, + "lon": -84.58575 + }, + "KSNH": { + "id": "KSNH", + "city": "SAVANNAH/HARDIN CO", + "state": "TN", + "lat": 35.17, + "lon": -88.22 + }, + "KSRB": { + "id": "KSRB", + "city": "Sparta Upper Cumberland Regional Airport", + "state": "TN", + "lat": 36.0559, + "lon": -85.5307 + }, + "KSYI": { + "id": "KSYI", + "city": "Shelbyville Bomar Field & Shelbyville Municipal Airport", + "state": "TN", + "lat": 35.5593999, + "lon": -86.4425 + }, + "KSZY": { + "id": "KSZY", + "city": "SELMER/ROBERT SIBLEY", + "state": "TN", + "lat": 35.2, + "lon": -88.5 + }, + "KTHA": { + "id": "KTHA", + "city": "Tullahoma Regional Airport/William Northern Field", + "state": "TN", + "lat": 35.38, + "lon": -86.2467 + }, + "KTRI": { + "id": "KTRI", + "city": "Bristol / Johnson / Kingsport, Tri-City Regional Airport", + "state": "TN", + "lat": 36.47972, + "lon": -82.39889 + }, + "KTYS": { + "id": "KTYS", + "city": "Knoxville, McGhee Tyson Airport", + "state": "TN", + "lat": 35.81806, + "lon": -83.98583 + }, + "KUCY": { + "id": "KUCY", + "city": "Union City - Everett-Stewart Regional Airport", + "state": "TN", + "lat": 36.38, + "lon": -88.98 + }, + "KXNX": { + "id": "KXNX", + "city": "Sumner County Regional Airport", + "state": "TN", + "lat": 36.3750799, + "lon": -86.40842 + }, + "KAKR": { + "id": "KAKR", + "city": "Akron, Akron Fulton International Airport", + "state": "OH", + "lat": 41.0375, + "lon": -81.46417 + }, + "KAOH": { + "id": "KAOH", + "city": "Lima, Lima Allen County Airport", + "state": "OH", + "lat": 40.70806, + "lon": -84.02139 + }, + "KAXV": { + "id": "KAXV", + "city": "Neil Armstrong Airport", + "state": "OH", + "lat": 40.49356, + "lon": -84.29808 + }, + "KBJJ": { + "id": "KBJJ", + "city": "Wooster, Wayne County Airport", + "state": "OH", + "lat": 40.87306, + "lon": -81.88667 + }, + "KBKL": { + "id": "KBKL", + "city": "Cleveland, Burke Lakefront Airport", + "state": "OH", + "lat": 41.52556, + "lon": -81.66889 + }, + "KCAK": { + "id": "KCAK", + "city": "Akron Canton Regional Airport", + "state": "OH", + "lat": 40.91811, + "lon": -81.44343 + }, + "KCDI": { + "id": "KCDI", + "city": "Cambridge Municipal Airport", + "state": "OH", + "lat": 39.97393, + "lon": -81.5807899 + }, + "KCGF": { + "id": "KCGF", + "city": "Cleveland / Cuyahoga", + "state": "OH", + "lat": 41.56667, + "lon": -81.48333 + }, + "KCLE": { + "id": "KCLE", + "city": "Cleveland Hopkins International Airport", + "state": "OH", + "lat": 41.40569, + "lon": -81.85193 + }, + "KCMH": { + "id": "KCMH", + "city": "John Glenn Columbus International Airport", + "state": "OH", + "lat": 39.9906999, + "lon": -82.87691 + }, + "KDAY": { + "id": "KDAY", + "city": "Dayton, Cox Dayton International Airport", + "state": "OH", + "lat": 39.90611, + "lon": -84.21861 + }, + "KDFI": { + "id": "KDFI", + "city": "Defiance, Defiance Memorial Airport", + "state": "OH", + "lat": 41.33639, + "lon": -84.42944 + }, + "KDLZ": { + "id": "KDLZ", + "city": "Delaware Municipal Airport", + "state": "OH", + "lat": 40.2797, + "lon": -83.1148 + }, + "KEDJ": { + "id": "KEDJ", + "city": "Bellefontaine Regional Airport", + "state": "OH", + "lat": 40.3723, + "lon": -83.8192 + }, + "KFDY": { + "id": "KFDY", + "city": "Findlay, Findlay Airport", + "state": "OH", + "lat": 41.01361, + "lon": -83.66861 + }, + "KFFO": { + "id": "KFFO", + "city": "Dayton / Wright-Patterson Air Force Base", + "state": "OH", + "lat": 39.8333299, + "lon": -84.05 + }, + "KGDK": { + "id": "KGDK", + "city": "Greene County - Lewis A Jackson Regional Airport", + "state": "OH", + "lat": 39.69072, + "lon": -83.99278 + }, + "KHAO": { + "id": "KHAO", + "city": "Butler County Regional Airport", + "state": "OH", + "lat": 39.36121, + "lon": -84.52061 + }, + "KHOC": { + "id": "KHOC", + "city": "HILLSBORO", + "state": "OH", + "lat": 39.18876, + "lon": -83.53879 + }, + "KHZY": { + "id": "KHZY", + "city": "Ashtabula - Northeast Ohio Regional Airport", + "state": "OH", + "lat": 41.77944, + "lon": -80.69667 + }, + "KILN": { + "id": "KILN", + "city": "Wilmington, Airborne Airpark Airport", + "state": "OH", + "lat": 39.42833, + "lon": -83.7791699 + }, + "KJRO": { + "id": "KJRO", + "city": "JACKSON", + "state": "OH", + "lat": 38.9833, + "lon": -82.5833 + }, + "KLCK": { + "id": "KLCK", + "city": "Rickenbacker Air National Guard Base", + "state": "OH", + "lat": 39.81667, + "lon": -82.93333 + }, + "KLHQ": { + "id": "KLHQ", + "city": "Lancaster, Fairfield County Airport", + "state": "OH", + "lat": 39.7572199, + "lon": -82.66333 + }, + "KLNN": { + "id": "KLNN", + "city": "Willoughby", + "state": "OH", + "lat": 41.68333, + "lon": -81.38333 + }, + "KLPR": { + "id": "KLPR", + "city": "Lorain / Elyria, Lorain County Regional Airport", + "state": "OH", + "lat": 41.34611, + "lon": -82.17944 + }, + "KLUK": { + "id": "KLUK", + "city": "Cincinnati, Cincinnati Municipal Airport Lunken Field", + "state": "OH", + "lat": 39.10583, + "lon": -84.41583 + }, + "KMFD": { + "id": "KMFD", + "city": "Mansfield - Mansfield Lahm Regional Airport", + "state": "OH", + "lat": 40.8202799, + "lon": -82.51778 + }, + "KMGY": { + "id": "KMGY", + "city": "Dayton, Dayton-Wright Brothers Airport", + "state": "OH", + "lat": 39.58889, + "lon": -84.22472 + }, + "KMNN": { + "id": "KMNN", + "city": "Marion, Marion Municipal Airport", + "state": "OH", + "lat": 40.61667, + "lon": -83.06833 + }, + "KMRT": { + "id": "KMRT", + "city": "Marysville Union County Airport", + "state": "OH", + "lat": 40.2247, + "lon": -83.3516 + }, + "KMWO": { + "id": "KMWO", + "city": "Hook Field Municipal Airport", + "state": "OH", + "lat": 39.531, + "lon": -84.3953 + }, + "KOSU": { + "id": "KOSU", + "city": "Columbus, Ohio State University Airport", + "state": "OH", + "lat": 40.07806, + "lon": -83.0780599 + }, + "KOWX": { + "id": "KOWX", + "city": "Ottawa Putnam County Airport", + "state": "OH", + "lat": 41.0356, + "lon": -83.982 + }, + "KOXD": { + "id": "KOXD", + "city": "Miami University Airport", + "state": "OH", + "lat": 39.5022499, + "lon": -84.78436 + }, + "KPCW": { + "id": "KPCW", + "city": "Port Clinton Carl R Keller Field Airport", + "state": "OH", + "lat": 41.5163, + "lon": -82.8687 + }, + "KPHD": { + "id": "KPHD", + "city": "Harry Clever Field Airport", + "state": "OH", + "lat": 40.47032, + "lon": -81.42178 + }, + "KPMH": { + "id": "KPMH", + "city": "Greater Portsmouth Regional Airport", + "state": "OH", + "lat": 38.84047, + "lon": -82.8473099 + }, + "KPOV": { + "id": "KPOV", + "city": "Portage County Airport", + "state": "OH", + "lat": 41.21, + "lon": -81.252 + }, + "KRZT": { + "id": "KRZT", + "city": "Chillicothe Ross County Airport", + "state": "OH", + "lat": 39.4403999, + "lon": -83.0231 + }, + "KSGH": { + "id": "KSGH", + "city": "Springfield, Springfield-Beckley Municipal Airport", + "state": "OH", + "lat": 39.84028, + "lon": -83.84 + }, + "KTDZ": { + "id": "KTDZ", + "city": "Toledo - Toledo Executive Airport", + "state": "OH", + "lat": 41.56306, + "lon": -83.47639 + }, + "KTOL": { + "id": "KTOL", + "city": "Toledo - Toledo Express Airport", + "state": "OH", + "lat": 41.58704, + "lon": -83.80539 + }, + "KTZR": { + "id": "KTZR", + "city": "Columbus, Bolton Field Airport", + "state": "OH", + "lat": 39.90083, + "lon": -83.13722 + }, + "KUNI": { + "id": "KUNI", + "city": "OHIO U/ATHEN-ALBANY", + "state": "OH", + "lat": 39.22, + "lon": -82.23 + }, + "KUSE": { + "id": "KUSE", + "city": "Wauseon Fulton County Airport", + "state": "OH", + "lat": 41.6101, + "lon": -84.1272 + }, + "KUYF": { + "id": "KUYF", + "city": "London Madison County Airport", + "state": "OH", + "lat": 39.9326999, + "lon": -83.462 + }, + "KVES": { + "id": "KVES", + "city": "Versailles Darke County Airport", + "state": "OH", + "lat": 40.2044, + "lon": -84.5318999 + }, + "KVNW": { + "id": "KVNW", + "city": "Van Wert County Airport", + "state": "OH", + "lat": 40.86383, + "lon": -84.60636 + }, + "KVTA": { + "id": "KVTA", + "city": "Newark, Newark Heath Airport", + "state": "OH", + "lat": 40.02278, + "lon": -82.4625 + }, + "KYNG": { + "id": "KYNG", + "city": "Youngstown, Youngstown-Warren Regional Airport", + "state": "OH", + "lat": 41.25444, + "lon": -80.67389 + }, + "KZZV": { + "id": "KZZV", + "city": "Zanesville Municipal Airport", + "state": "OH", + "lat": 39.94609, + "lon": -81.89315 + }, + "KBOI": { + "id": "KBOI", + "city": "Boise Air Terminal", + "state": "ID", + "lat": 43.56704, + "lon": -116.24053 + }, + "KBYI": { + "id": "KBYI", + "city": "Burley Municipal Airport", + "state": "ID", + "lat": 42.54525, + "lon": -113.7686 + }, + "KCOE": { + "id": "KCOE", + "city": "Coeur d'Alene Airport - Pappy Boyington Field", + "state": "ID", + "lat": 47.76667, + "lon": -116.81667 + }, + "KDIJ": { + "id": "KDIJ", + "city": "Driggs, Driggs-Reed Memorial Airport", + "state": "ID", + "lat": 43.74167, + "lon": -111.09778 + }, + "KETI": { + "id": "KETI", + "city": "Ketchum Ranger Station", + "state": "ID", + "lat": 43.6816666, + "lon": -114.3627777 + }, + "KEUL": { + "id": "KEUL", + "city": "Caldwell - Caldwell Industrial Airport", + "state": "ID", + "lat": 43.64055, + "lon": -116.63017 + }, + "KGIC": { + "id": "KGIC", + "city": "Grangeville - Idaho County Airport", + "state": "ID", + "lat": 45.94111, + "lon": -116.13257 + }, + "KGNG": { + "id": "KGNG", + "city": "Gooding Municipal Airport", + "state": "ID", + "lat": 42.91716, + "lon": -114.76516 + }, + "KIDA": { + "id": "KIDA", + "city": "Idaho Falls Regional Airport", + "state": "ID", + "lat": 43.5208299, + "lon": -112.06611 + }, + "KJER": { + "id": "KJER", + "city": "Jerome County Airport", + "state": "ID", + "lat": 42.72736, + "lon": -114.45469 + }, + "KLLJ": { + "id": "KLLJ", + "city": "Challis - Challis Airport", + "state": "ID", + "lat": 44.523, + "lon": -114.21611 + }, + "KLWS": { + "id": "KLWS", + "city": "Lewiston, Lewiston-Nez Perce County Airport", + "state": "ID", + "lat": 46.37472, + "lon": -117.01444 + }, + "KMAN": { + "id": "KMAN", + "city": "Nampa Municipal Airport", + "state": "ID", + "lat": 43.5813, + "lon": -116.5231 + }, + "KMUO": { + "id": "KMUO", + "city": "Mountain Home Air Force Base", + "state": "ID", + "lat": 43.05, + "lon": -115.86667 + }, + "KMYL": { + "id": "KMYL", + "city": "McCall Airport", + "state": "ID", + "lat": 44.89425, + "lon": -116.09978 + }, + "KPIH": { + "id": "KPIH", + "city": "Pocatello, Pocatello Regional Airport", + "state": "ID", + "lat": 42.92028, + "lon": -112.57111 + }, + "KRXE": { + "id": "KRXE", + "city": "Rexburg, Rexburg-Madison County Airport", + "state": "ID", + "lat": 43.83167, + "lon": -111.80611 + }, + "KSMN": { + "id": "KSMN", + "city": "Salmon, Lemhi County Airport", + "state": "ID", + "lat": 45.11667, + "lon": -113.88333 + }, + "KSNT": { + "id": "KSNT", + "city": "Stanley, Stanley Ranger Station", + "state": "ID", + "lat": 44.20861, + "lon": -114.93444 + }, + "KSUN": { + "id": "KSUN", + "city": "Hailey, Friedman Memorial Airport", + "state": "ID", + "lat": 43.5, + "lon": -114.3 + }, + "KSZT": { + "id": "KSZT", + "city": "Sandpoint, Sandpoint Airport", + "state": "ID", + "lat": 48.29944, + "lon": -116.56 + }, + "KTBI": { + "id": "KTBI", + "city": "Kettle Butte", + "state": "ID", + "lat": 43.5486099, + "lon": -112.32583 + }, + "KTWF": { + "id": "KTWF", + "city": "Joslin Field - Magic Valley Regional Airport", + "state": "ID", + "lat": 42.4784999, + "lon": -114.47739 + }, + "PALI": { + "id": "PALI", + "city": "Snake River near Irwin, ID", + "state": "ID", + "lat": 43.3508333, + "lon": -111.2183333 + }, + "PARI": { + "id": "PARI", + "city": "Boise River near Parma, ID", + "state": "ID", + "lat": 43.7816666, + "lon": -116.9713888 + }, + "PAYI": { + "id": "PAYI", + "city": "North Fork Payette River at McCall, Idaho", + "state": "ID", + "lat": 44.9083333, + "lon": -116.1194444 + }, + "PECI": { + "id": "PECI", + "city": "Peoples Canal", + "state": "ID", + "lat": 43.2841666, + "lon": -112.25 + }, + "PICI": { + "id": "PICI", + "city": "PICABO", + "state": "ID", + "lat": 43.31167, + "lon": -114.16583 + }, + "PLCI": { + "id": "PLCI", + "city": "Palisades Canal near Irwin, ID", + "state": "ID", + "lat": 43.7458333, + "lon": -112.1027777 + }, + "PLEI": { + "id": "PLEI", + "city": "Payette River near Letha, ID", + "state": "ID", + "lat": 43.8963888, + "lon": -116.6258333 + }, + "PMAI": { + "id": "PMAI", + "city": "PARMA", + "state": "ID", + "lat": 43.8, + "lon": -116.93333 + }, + "PNRI": { + "id": "PNRI", + "city": "PN Region USBR Hydromet Test Site - Boise, ID", + "state": "ID", + "lat": 43.6225, + "lon": -116.1933333 + }, + "POCI": { + "id": "POCI", + "city": "Porter Canal", + "state": "ID", + "lat": 43.5030555, + "lon": -112.0480555 + }, + "PRKI": { + "id": "PRKI", + "city": "Parks and Lewisville Canal near Rigby, ID", + "state": "ID", + "lat": 43.6888888, + "lon": -111.8661111 + }, + "PRLI": { + "id": "PRLI", + "city": "South Fork Payette River at Lowman, ID", + "state": "ID", + "lat": 44.0847222, + "lon": -115.6027777 + }, + "PRPI": { + "id": "PRPI", + "city": "Payette River near Payette, ID", + "state": "ID", + "lat": 44.0424999, + "lon": -116.9241666 + }, + "PSFI": { + "id": "PSFI", + "city": "Post Falls", + "state": "ID", + "lat": 47.71366, + "lon": -116.9701 + }, + "KACZ": { + "id": "KACZ", + "city": "Henderson Field Airport", + "state": "NC", + "lat": 34.71786, + "lon": -78.00389 + }, + "KAFP": { + "id": "KAFP", + "city": "Anson County Airport", + "state": "NC", + "lat": 35.01944, + "lon": -80.07836 + }, + "KAKH": { + "id": "KAKH", + "city": "Gastonia Municipal Airport", + "state": "NC", + "lat": 35.1968699, + "lon": -81.15545 + }, + "KASJ": { + "id": "KASJ", + "city": "Ahoskie, Tri-County Airport", + "state": "NC", + "lat": 36.2975, + "lon": -77.17083 + }, + "KAVL": { + "id": "KAVL", + "city": "Asheville, Asheville Regional Airport", + "state": "NC", + "lat": 35.43194, + "lon": -82.5375 + }, + "KBUY": { + "id": "KBUY", + "city": "Burlington Alamance Regional Airport", + "state": "NC", + "lat": 36.04753, + "lon": -79.47375 + }, + "KCLT": { + "id": "KCLT", + "city": "Charlotte/Douglas International Airport", + "state": "NC", + "lat": 35.2083299, + "lon": -80.96139 + }, + "KCPC": { + "id": "KCPC", + "city": "Whiteville, Columbus County Municipal Airport", + "state": "NC", + "lat": 34.27278, + "lon": -78.715 + }, + "KCTZ": { + "id": "KCTZ", + "city": "Sampson County Airport", + "state": "NC", + "lat": 34.97522, + "lon": -78.36276 + }, + "KDPL": { + "id": "KDPL", + "city": "Duplin County Airport", + "state": "NC", + "lat": 34.99942, + "lon": -77.97995 + }, + "KECG": { + "id": "KECG", + "city": "Elizabeth City C/G Regional Airport", + "state": "NC", + "lat": 36.25771, + "lon": -76.1716 + }, + "KEDE": { + "id": "KEDE", + "city": "Edenton, Northeastern Regional Airport", + "state": "NC", + "lat": 36.02778, + "lon": -76.56722 + }, + "KEHO": { + "id": "KEHO", + "city": "Shelby Municipal Airport", + "state": "NC", + "lat": 35.2556299, + "lon": -81.59858 + }, + "KEQY": { + "id": "KEQY", + "city": "Monroe, Monroe Airport", + "state": "NC", + "lat": 35.01694, + "lon": -80.62056 + }, + "KETC": { + "id": "KETC", + "city": "Tarboro-Edgecombe Airport", + "state": "NC", + "lat": 35.9373, + "lon": -77.54648 + }, + "KEWN": { + "id": "KEWN", + "city": "New Bern, Craven County Regional Airport", + "state": "NC", + "lat": 35.0675, + "lon": -77.04722 + }, + "KEXX": { + "id": "KEXX", + "city": "Lexington, Davidson County Airport", + "state": "NC", + "lat": 35.78111, + "lon": -80.30389 + }, + "KEYF": { + "id": "KEYF", + "city": "Curtis L Brown Jr. Field Airport", + "state": "NC", + "lat": 34.60418, + "lon": -78.57902 + }, + "KFAY": { + "id": "KFAY", + "city": "Fayetteville, Fayetteville Regional Airport", + "state": "NC", + "lat": 34.98944, + "lon": -78.88 + }, + "KFBG": { + "id": "KFBG", + "city": "Fort Bragg / Simmons Army Airfield", + "state": "NC", + "lat": 35.1314, + "lon": -78.93158 + }, + "KFFA": { + "id": "KFFA", + "city": "Kill Devil Hills, First Flight Airport", + "state": "NC", + "lat": 36.01667, + "lon": -75.66667 + }, + "KFQD": { + "id": "KFQD", + "city": "Rutherfordton, Rutherford County-Marchman Field Airport", + "state": "NC", + "lat": 35.42833, + "lon": -81.935 + }, + "KGEV": { + "id": "KGEV", + "city": "Jefferson - Ashe County Airport", + "state": "NC", + "lat": 36.43333, + "lon": -81.41667 + }, + "KGSB": { + "id": "KGSB", + "city": "Seymour-Johnson Air Force Base", + "state": "NC", + "lat": 35.34457, + "lon": -77.94583 + }, + "KGSO": { + "id": "KGSO", + "city": "Greensboro, Piedmont Triad International Airport", + "state": "NC", + "lat": 36.0974999, + "lon": -79.94361 + }, + "KGWW": { + "id": "KGWW", + "city": "Goldsboro, Goldsboro-Wayne Municipal Airport", + "state": "NC", + "lat": 35.46056, + "lon": -77.965 + }, + "KHBI": { + "id": "KHBI", + "city": "Asheboro, Asheboro Municipal Airport", + "state": "NC", + "lat": 35.6538899, + "lon": -79.895 + }, + "KHFF": { + "id": "KHFF", + "city": "Mackall U. S. Army Airfield", + "state": "NC", + "lat": 35.03333, + "lon": -79.5 + }, + "KHKY": { + "id": "KHKY", + "city": "Hickory, Hickory Regional Airport", + "state": "NC", + "lat": 35.74222, + "lon": -81.38222 + }, + "KHNZ": { + "id": "KHNZ", + "city": "Henderson-Oxford Airport", + "state": "NC", + "lat": 36.36352, + "lon": -78.52889 + }, + "KHRJ": { + "id": "KHRJ", + "city": "Erwin, Harnett County Airport", + "state": "NC", + "lat": 35.37861, + "lon": -78.73361 + }, + "KHSE": { + "id": "KHSE", + "city": "Hatteras, Mitchell Field", + "state": "NC", + "lat": 35.23222, + "lon": -75.6225 + }, + "KILM": { + "id": "KILM", + "city": "Wilmington International Airport", + "state": "NC", + "lat": 34.26681, + "lon": -77.89987 + }, + "KINT": { + "id": "KINT", + "city": "Winston Salem, Smith Reynolds Airport", + "state": "NC", + "lat": 36.13333, + "lon": -80.22472 + }, + "KIPJ": { + "id": "KIPJ", + "city": "Lincolnton, Lincolnton-Lincoln County Regional Airport", + "state": "NC", + "lat": 35.48306, + "lon": -81.16139 + }, + "KISO": { + "id": "KISO", + "city": "Kinston, Kinston Regional Jetport at Stallings Field", + "state": "NC", + "lat": 35.3333299, + "lon": -77.61667 + }, + "KIXA": { + "id": "KIXA", + "city": "Halifax-Northampton Regional Airport", + "state": "NC", + "lat": 36.33, + "lon": -77.635 + }, + "KJNX": { + "id": "KJNX", + "city": "Smithfield, Johnston County Airport", + "state": "NC", + "lat": 35.54083, + "lon": -78.39028 + }, + "KJQF": { + "id": "KJQF", + "city": "Concord Regional Airport", + "state": "NC", + "lat": 35.3896299, + "lon": -80.70735 + }, + "KLBT": { + "id": "KLBT", + "city": "Lumberton Municipal Airport", + "state": "NC", + "lat": 34.60817, + "lon": -79.059 + }, + "KLHZ": { + "id": "KLHZ", + "city": "Franklin County Airport", + "state": "NC", + "lat": 36.02288, + "lon": -78.33405 + }, + "KMCZ": { + "id": "KMCZ", + "city": "Martin County Airport", + "state": "NC", + "lat": 35.86219, + "lon": -77.1782 + }, + "KMEB": { + "id": "KMEB", + "city": "Laurinburg Maxton Airport", + "state": "NC", + "lat": 34.79132, + "lon": -79.3683 + }, + "KMQI": { + "id": "KMQI", + "city": "Manteo / Dare County Regional", + "state": "NC", + "lat": 35.91667, + "lon": -75.7 + }, + "KMRH": { + "id": "KMRH", + "city": "Beaufort Smith Field", + "state": "NC", + "lat": 34.73259, + "lon": -76.6566 + }, + "KMRN": { + "id": "KMRN", + "city": "Morganton-Lenoir Airport", + "state": "NC", + "lat": 35.81922, + "lon": -81.60971 + }, + "KMWK": { + "id": "KMWK", + "city": "Mount Airy/Surry County Airport", + "state": "NC", + "lat": 36.45675, + "lon": -80.55483 + }, + "KNBT": { + "id": "KNBT", + "city": "Piney Island, Bt-11 Bombing Range", + "state": "NC", + "lat": 35.02222, + "lon": -76.4625 + }, + "KNCA": { + "id": "KNCA", + "city": "MCAS New River", + "state": "NC", + "lat": 34.70627, + "lon": -77.44066 + }, + "KNJM": { + "id": "KNJM", + "city": "Bogue Field Marine Corps Auxiliary Field", + "state": "NC", + "lat": 34.69403, + "lon": -77.02945 + }, + "KNKT": { + "id": "KNKT", + "city": "Cherry Point Marine Corps Air Station", + "state": "NC", + "lat": 34.89719, + "lon": -76.88135 + }, + "KOAJ": { + "id": "KOAJ", + "city": "Jacksonville, Albert J Ellis Airport", + "state": "NC", + "lat": 34.8333299, + "lon": -77.61667 + }, + "KOCW": { + "id": "KOCW", + "city": "Washington, Warren Field Airport", + "state": "NC", + "lat": 35.57056, + "lon": -77.0497199 + }, + "KONX": { + "id": "KONX", + "city": "Currituck, Currituck County Airport", + "state": "NC", + "lat": 36.39889, + "lon": -76.01611 + }, + "KPGV": { + "id": "KPGV", + "city": "Pitt-Greenville Airport", + "state": "NC", + "lat": 35.63742, + "lon": -77.38506 + }, + "KPOB": { + "id": "KPOB", + "city": "Pope Air Force Base", + "state": "NC", + "lat": 35.17531, + "lon": -79.00771 + }, + "KRCZ": { + "id": "KRCZ", + "city": "Rockingham-Hamlet Airport", + "state": "NC", + "lat": 34.8954499, + "lon": -79.75755 + }, + "KRDU": { + "id": "KRDU", + "city": "Raleigh / Durham, Raleigh-Durham International Airport", + "state": "NC", + "lat": 35.89223, + "lon": -78.78185 + }, + "KRHP": { + "id": "KRHP", + "city": "Andrews-Murphy Airport", + "state": "NC", + "lat": 35.19394, + "lon": -83.86182 + }, + "KRUQ": { + "id": "KRUQ", + "city": "Rowan County Airport", + "state": "NC", + "lat": 35.64417, + "lon": -80.52359 + }, + "KRWI": { + "id": "KRWI", + "city": "Rocky Mount, Rocky Mount-Wilson Regional Airport", + "state": "NC", + "lat": 35.8549999, + "lon": -77.89306 + }, + "KSCR": { + "id": "KSCR", + "city": "Siler City Municipal Airport", + "state": "NC", + "lat": 35.7043, + "lon": -79.5043 + }, + "KSIF": { + "id": "KSIF", + "city": "Reidsville, Rockingham County NC Shiloh Airport", + "state": "NC", + "lat": 36.43722, + "lon": -79.85083 + }, + "KSOP": { + "id": "KSOP", + "city": "Pinehurst/Southern Pines, Moore County Airport", + "state": "NC", + "lat": 35.23333, + "lon": -79.4 + }, + "KSUT": { + "id": "KSUT", + "city": "Brunswick County Airport", + "state": "NC", + "lat": 33.92921, + "lon": -78.07223 + }, + "KSVH": { + "id": "KSVH", + "city": "Statesville Municipal Airport", + "state": "NC", + "lat": 35.76362, + "lon": -80.9473 + }, + "KTDF": { + "id": "KTDF", + "city": "Roxboro, Person County Airport", + "state": "NC", + "lat": 36.2849999, + "lon": -78.98417 + }, + "KTNB": { + "id": "KTNB", + "city": "Watauga County Hospital Heliport", + "state": "NC", + "lat": 36.19856, + "lon": -81.65171 + }, + "KTQV": { + "id": "KTQV", + "city": "DURHAM/DUKE", + "state": "NC", + "lat": 36, + "lon": -78.9333 + }, + "KTTA": { + "id": "KTTA", + "city": "Sanford, Sanford-Lee County Regional Airport", + "state": "NC", + "lat": 35.5825, + "lon": -79.10139 + }, + "KUKF": { + "id": "KUKF", + "city": "North Wilkesboro, Wilkes County Airport", + "state": "NC", + "lat": 36.21667, + "lon": -81.08333 + }, + "KVUJ": { + "id": "KVUJ", + "city": "Albemarle, Stanly County Airport", + "state": "NC", + "lat": 35.41667, + "lon": -80.15083 + }, + "KLRY": { + "id": "KLRY", + "city": "Harrisonville Lawrence Smith Memorial Airport", + "state": "MO", + "lat": 38.611, + "lon": -94.3421 + }, + "KLXT": { + "id": "KLXT", + "city": "Lee's Summit, Lee's Summit Municipal Airport", + "state": "MO", + "lat": 38.95972, + "lon": -94.37167 + }, + "KMAW": { + "id": "KMAW", + "city": "Malden Municipal Airport", + "state": "MO", + "lat": 36.6004999, + "lon": -89.9922 + }, + "KMBY": { + "id": "KMBY", + "city": "Omar N Bradley Airport", + "state": "MO", + "lat": 39.46341, + "lon": -92.42638 + }, + "KMCI": { + "id": "KMCI", + "city": "Kansas City, Kansas City International Airport", + "state": "MO", + "lat": 39.29722, + "lon": -94.73056 + }, + "KMHL": { + "id": "KMHL", + "city": "Marshall Memorial Municipal Airport", + "state": "MO", + "lat": 39.0955, + "lon": -93.2028 + }, + "KMKC": { + "id": "KMKC", + "city": "Kansas City, Kansas City Downtown Airport", + "state": "MO", + "lat": 39.12083, + "lon": -94.59694 + }, + "KMYJ": { + "id": "KMYJ", + "city": "Mexico Memorial Airport", + "state": "MO", + "lat": 39.1575, + "lon": -91.8182999 + }, + "KOZS": { + "id": "KOZS", + "city": "Camdenton Memorial Airport", + "state": "MO", + "lat": 37.9739999, + "lon": -92.6912 + }, + "KPCD": { + "id": "KPCD", + "city": "Perryville Regional Airport", + "state": "MO", + "lat": 37.86867, + "lon": -89.86214 + }, + "KPOF": { + "id": "KPOF", + "city": "Poplar Bluff, Poplar Bluff Municipal Airport", + "state": "MO", + "lat": 36.77056, + "lon": -90.32222 + }, + "KRCM": { + "id": "KRCM", + "city": "Skyhaven Airport", + "state": "MO", + "lat": 38.7842, + "lon": -93.8028999 + }, + "KSET": { + "id": "KSET", + "city": "St. Charles, St. Charles County Smartt Airport", + "state": "MO", + "lat": 38.93056, + "lon": -90.4325 + }, + "KSGF": { + "id": "KSGF", + "city": "Springfield-Branson National Airport", + "state": "MO", + "lat": 37.23972, + "lon": -93.38972 + }, + "KSIK": { + "id": "KSIK", + "city": "Sikeston Memorial Municipal Airport", + "state": "MO", + "lat": 36.8989, + "lon": -89.5618 + }, + "KSTJ": { + "id": "KSTJ", + "city": "St. Joseph, Rosecrans Memorial Airport", + "state": "MO", + "lat": 39.76806, + "lon": -94.90917 + }, + "KSTL": { + "id": "KSTL", + "city": "St. Louis Lambert International Airport", + "state": "MO", + "lat": 38.7525, + "lon": -90.37361 + }, + "KSUS": { + "id": "KSUS", + "city": "St. Louis, Spirit Of St. Louis Airport", + "state": "MO", + "lat": 38.65722, + "lon": -90.65583 + }, + "KSZL": { + "id": "KSZL", + "city": "Whiteman Air Force Base", + "state": "MO", + "lat": 38.73333, + "lon": -93.55 + }, + "KTBN": { + "id": "KTBN", + "city": "Fort Leonard Wood", + "state": "MO", + "lat": 37.73333, + "lon": -92.13333 + }, + "KTKX": { + "id": "KTKX", + "city": "Kennett - Kennett Memorial Airport", + "state": "MO", + "lat": 36.22256, + "lon": -90.03671 + }, + "KUNO": { + "id": "KUNO", + "city": "West Plains, West Plains Municipal Airport", + "state": "MO", + "lat": 36.87917, + "lon": -91.905 + }, + "KUUV": { + "id": "KUUV", + "city": "SULLIVAN", + "state": "MO", + "lat": 38.2335, + "lon": -91.16433 + }, + "KVER": { + "id": "KVER", + "city": "Jesse Viertel Memorial Airport", + "state": "MO", + "lat": 38.94672, + "lon": -92.68267 + }, + "KVIH": { + "id": "KVIH", + "city": "Rolla / Vichy, Rolla National Airport", + "state": "MO", + "lat": 38.13194, + "lon": -91.76528 + }, + "KALB": { + "id": "KALB", + "city": "Albany International Airport", + "state": "NY", + "lat": 42.74722, + "lon": -73.79912 + }, + "KART": { + "id": "KART", + "city": "Watertown, Watertown International Airport", + "state": "NY", + "lat": 43.99194, + "lon": -76.02167 + }, + "KBGM": { + "id": "KBGM", + "city": "Greater Binghamton Airport", + "state": "NY", + "lat": 42.20778, + "lon": -75.98139 + }, + "KBUF": { + "id": "KBUF", + "city": "Buffalo, Greater Buffalo International Airport", + "state": "NY", + "lat": 42.93998, + "lon": -78.73604 + }, + "KCZG": { + "id": "KCZG", + "city": "ENDICOTT", + "state": "NY", + "lat": 42.0785, + "lon": -76.09633 + }, + "KDKK": { + "id": "KDKK", + "city": "Dunkirk, Chautauqua County / Dunkirk Airport", + "state": "NY", + "lat": 42.49306, + "lon": -79.27583 + }, + "KDSV": { + "id": "KDSV", + "city": "Dansville, Dansville Municipal Airport", + "state": "NY", + "lat": 42.56944, + "lon": -77.71444 + }, + "KELM": { + "id": "KELM", + "city": "Elmira, Elmira / Corning Regional Airport", + "state": "NY", + "lat": 42.15639, + "lon": -76.90278 + }, + "KELZ": { + "id": "KELZ", + "city": "Wellsville, Wellsville Municipal Airport", + "state": "NY", + "lat": 42.1075, + "lon": -77.98444 + }, + "KFOK": { + "id": "KFOK", + "city": "The Gabreski Airport", + "state": "NY", + "lat": 40.85053, + "lon": -72.61927 + }, + "KFRG": { + "id": "KFRG", + "city": "Farmingdale - Republic Airport", + "state": "NY", + "lat": 40.73443, + "lon": -73.41639 + }, + "KFZY": { + "id": "KFZY", + "city": "Fulton, Oswego County Airport", + "state": "NY", + "lat": 43.35083, + "lon": -76.38806 + }, + "KGFL": { + "id": "KGFL", + "city": "Glens Falls, Floyd Bennett Memorial Airport", + "state": "NY", + "lat": 43.34111, + "lon": -73.61056 + }, + "KGTB": { + "id": "KGTB", + "city": "Fort Drum / Wheeler-Sack U. S. Army Airfield", + "state": "NY", + "lat": 44.05, + "lon": -75.73333 + }, + "KGVQ": { + "id": "KGVQ", + "city": "Genesee County Airport", + "state": "NY", + "lat": 43.03175, + "lon": -78.16967 + }, + "KHPN": { + "id": "KHPN", + "city": "White Plains - Westchester County Airport", + "state": "NY", + "lat": 41.06237, + "lon": -73.70456 + }, + "KHTF": { + "id": "KHTF", + "city": "HORNELL", + "state": "NY", + "lat": 42.38216, + "lon": -77.68216 + }, + "KHWV": { + "id": "KHWV", + "city": "Shirley, Brookhaven Airport", + "state": "NY", + "lat": 40.82167, + "lon": -72.8688899 + }, + "KIAG": { + "id": "KIAG", + "city": "Niagara Falls, Niagara Falls International Airport", + "state": "NY", + "lat": 43.1082899, + "lon": -78.93818 + }, + "KISP": { + "id": "KISP", + "city": "Islip, Long Island Mac Arthur Airport", + "state": "NY", + "lat": 40.79389, + "lon": -73.10167 + }, + "KITH": { + "id": "KITH", + "city": "Ithaca Tompkins International Airport", + "state": "NY", + "lat": 42.49083, + "lon": -76.45833 + }, + "KIUA": { + "id": "KIUA", + "city": "Canandaigua Airport", + "state": "NY", + "lat": 42.9089, + "lon": -77.32523 + }, + "KJFK": { + "id": "KJFK", + "city": "New York, Kennedy International Airport", + "state": "NY", + "lat": 40.63915, + "lon": -73.76393 + }, + "KJHW": { + "id": "KJHW", + "city": "Jamestown, Chautauqua County/Jamestown Airport", + "state": "NY", + "lat": 42.15, + "lon": -79.26667 + }, + "KJPX": { + "id": "KJPX", + "city": "East Hampton Town Airport", + "state": "NY", + "lat": 40.95942, + "lon": -72.25167 + }, + "KJRB": { + "id": "KJRB", + "city": "New York Downtown Manhattan", + "state": "NY", + "lat": 40.7012, + "lon": -74.009 + }, + "KLGA": { + "id": "KLGA", + "city": "New York, La Guardia Airport", + "state": "NY", + "lat": 40.77917, + "lon": -73.88 + }, + "KLKP": { + "id": "KLKP", + "city": "Lake Placid Airport", + "state": "NY", + "lat": 44.26448, + "lon": -73.96187 + }, + "KMGJ": { + "id": "KMGJ", + "city": "Montgomery, Orange County Airport", + "state": "NY", + "lat": 41.50917, + "lon": -74.265 + }, + "KMSS": { + "id": "KMSS", + "city": "Massena, Massena International-Richards Field", + "state": "NY", + "lat": 44.93583, + "lon": -74.84556 + }, + "KMTP": { + "id": "KMTP", + "city": "Montauk, Montauk Airport", + "state": "NY", + "lat": 41.07306, + "lon": -71.92333 + }, + "KNYC": { + "id": "KNYC", + "city": "New York City, Central Park", + "state": "NY", + "lat": 40.78333, + "lon": -73.9666699 + }, + "KOGS": { + "id": "KOGS", + "city": "Ogdensburg International Airport", + "state": "NY", + "lat": 44.68186, + "lon": -75.4655 + }, + "KOIC": { + "id": "KOIC", + "city": "NORWICH", + "state": "NY", + "lat": 42.5665, + "lon": -75.52416 + }, + "KOLE": { + "id": "KOLE", + "city": "Cattaraugus County-Olean Airport", + "state": "NY", + "lat": 42.24119, + "lon": -78.37136 + }, + "KPBG": { + "id": "KPBG", + "city": "Plattsburgh International Airport ", + "state": "NY", + "lat": 44.65, + "lon": -73.4666699 + }, + "KPEO": { + "id": "KPEO", + "city": "Penn Yan, Penn Yan Airport", + "state": "NY", + "lat": 42.64306, + "lon": -77.04944 + }, + "KPOU": { + "id": "KPOU", + "city": "Poughkeepsie, Dutchess County Airport", + "state": "NY", + "lat": 41.62667, + "lon": -73.88417 + }, + "KPTD": { + "id": "KPTD", + "city": "Potsdam Municipal Airport/Damon Field", + "state": "NY", + "lat": 44.67667, + "lon": -74.94844 + }, + "KRME": { + "id": "KRME", + "city": "Griffiss International Airport", + "state": "NY", + "lat": 43.23333, + "lon": -75.4 + }, + "KROC": { + "id": "KROC", + "city": "Rochester, Greater Rochester International Airport", + "state": "NY", + "lat": 43.11667, + "lon": -77.67667 + }, + "KSCH": { + "id": "KSCH", + "city": "Schenectady Airport", + "state": "NY", + "lat": 42.85, + "lon": -73.93333 + }, + "KSDC": { + "id": "KSDC", + "city": "Williamson-Sodus Airport", + "state": "NY", + "lat": 43.23459, + "lon": -77.11946 + }, + "KSLK": { + "id": "KSLK", + "city": "Saranac Lake, Adirondack Regional Airport", + "state": "NY", + "lat": 44.39306, + "lon": -74.20278 + }, + "KSWF": { + "id": "KSWF", + "city": "Newburgh / Stewart", + "state": "NY", + "lat": 41.5, + "lon": -74.1 + }, + "KSYR": { + "id": "KSYR", + "city": "Syracuse, Syracuse Hancock International Airport", + "state": "NY", + "lat": 43.10917, + "lon": -76.10333 + }, + "KVGC": { + "id": "KVGC", + "city": "Hamilton Municipal Airport", + "state": "NY", + "lat": 42.84344, + "lon": -75.56119 + }, + "KAKQ": { + "id": "KAKQ", + "city": "Wakefield Municipal Airport", + "state": "VA", + "lat": 36.98274, + "lon": -77.00137 + }, + "KAVC": { + "id": "KAVC", + "city": "South Hill, Mecklenburg-Brunswick Regional Airport", + "state": "VA", + "lat": 36.68861, + "lon": -78.05417 + }, + "KBCB": { + "id": "KBCB", + "city": "Virginia Tech Airport", + "state": "VA", + "lat": 37.21667, + "lon": -80.41667 + }, + "KBKT": { + "id": "KBKT", + "city": "Ft. Pickett / Blackstone", + "state": "VA", + "lat": 37.0833299, + "lon": -77.95 + }, + "KCHO": { + "id": "KCHO", + "city": "Charlottesville-Albemarle Airport", + "state": "VA", + "lat": 38.13738, + "lon": -78.45516 + }, + "KCJR": { + "id": "KCJR", + "city": "Culpeper Regional Airport", + "state": "VA", + "lat": 38.52607, + "lon": -77.85738 + }, + "KCPK": { + "id": "KCPK", + "city": "Chesapeake, Chesapeake Municipal Airport", + "state": "VA", + "lat": 36.66556, + "lon": -76.32056 + }, + "KCXE": { + "id": "KCXE", + "city": "Chase City Municipal Airport", + "state": "VA", + "lat": 36.7883, + "lon": -78.5016 + }, + "KDAA": { + "id": "KDAA", + "city": "Fort Belvoir", + "state": "VA", + "lat": 38.71667, + "lon": -77.18333 + }, + "KDAN": { + "id": "KDAN", + "city": "Danville, Danville Regional Airport", + "state": "VA", + "lat": 36.57278, + "lon": -79.33611 + }, + "KDCA": { + "id": "KDCA", + "city": "Washington/Reagan National Airport, DC", + "state": "VA", + "lat": 38.84833, + "lon": -77.03417 + }, + "KEMV": { + "id": "KEMV", + "city": "Emporia, Emporia-Greensville Regional Airport", + "state": "VA", + "lat": 36.68694, + "lon": -77.48278 + }, + "KEZF": { + "id": "KEZF", + "city": "Fredericksburg, Shannon Airport", + "state": "VA", + "lat": 38.26667, + "lon": -77.45 + }, + "KFAF": { + "id": "KFAF", + "city": "Fort Eustis / Felker", + "state": "VA", + "lat": 37.13333, + "lon": -76.61667 + }, + "KFCI": { + "id": "KFCI", + "city": "Chesterfield County Airport", + "state": "VA", + "lat": 37.406444, + "lon": -77.524833 + }, + "KFKN": { + "id": "KFKN", + "city": "Franklin / J B Rose", + "state": "VA", + "lat": 36.7, + "lon": -76.9 + }, + "KFRR": { + "id": "KFRR", + "city": "Front Royal-warren County Airport", + "state": "VA", + "lat": 38.9174999, + "lon": -78.2535 + }, + "KFVX": { + "id": "KFVX", + "city": "Farmville", + "state": "VA", + "lat": 37.35, + "lon": -78.43333 + }, + "KFYJ": { + "id": "KFYJ", + "city": "West Point, Middle Peninsula Regional Airport", + "state": "VA", + "lat": 37.52111, + "lon": -76.7644399 + }, + "KGVE": { + "id": "KGVE", + "city": "Gordonsville Municipal Airport", + "state": "VA", + "lat": 38.156, + "lon": -78.1658 + }, + "KHEF": { + "id": "KHEF", + "city": "Manassas, Manassas Regional Airport/Harry P. Davis Field", + "state": "VA", + "lat": 38.71667, + "lon": -77.51667 + }, + "KHLX": { + "id": "KHLX", + "city": "Hillsville", + "state": "VA", + "lat": 36.76667, + "lon": -80.81667 + }, + "KHSP": { + "id": "KHSP", + "city": "Hot Springs / Ingalls", + "state": "VA", + "lat": 37.95, + "lon": -79.83333 + }, + "KHWY": { + "id": "KHWY", + "city": "Warrenton-Fauquier Airport", + "state": "VA", + "lat": 38.5876499, + "lon": -77.71501 + }, + "KIAD": { + "id": "KIAD", + "city": "Washington/Dulles International Airport, DC", + "state": "VA", + "lat": 38.93472, + "lon": -77.4475 + }, + "KJFZ": { + "id": "KJFZ", + "city": "Tazewell County Airport", + "state": "VA", + "lat": 37.064, + "lon": -81.798 + }, + "KJGG": { + "id": "KJGG", + "city": "Williamsburg-Jamestown Airport", + "state": "VA", + "lat": 37.24157, + "lon": -76.71672 + }, + "KJYO": { + "id": "KJYO", + "city": "Leesburg / Godfrey", + "state": "VA", + "lat": 39.0833299, + "lon": -77.56667 + }, + "KLFI": { + "id": "KLFI", + "city": "Langley Air Force Base", + "state": "VA", + "lat": 37.0833299, + "lon": -76.35 + }, + "KLKU": { + "id": "KLKU", + "city": "Louisa, Louisa County Airport/Freeman Field", + "state": "VA", + "lat": 38.00972, + "lon": -77.97028 + }, + "KLNP": { + "id": "KLNP", + "city": "Wise / Lonesome Pine", + "state": "VA", + "lat": 36.98333, + "lon": -82.53333 + }, + "KLUA": { + "id": "KLUA", + "city": "Luray Caverns", + "state": "VA", + "lat": 38.6671, + "lon": -78.5006 + }, + "KLVL": { + "id": "KLVL", + "city": "Lawrenceville/Brunswick Municipal Airport", + "state": "VA", + "lat": 36.7727999, + "lon": -77.7943 + }, + "KLYH": { + "id": "KLYH", + "city": "Lynchburg, Lynchburg Regional Airport", + "state": "VA", + "lat": 37.32083, + "lon": -79.20667 + }, + "KMKJ": { + "id": "KMKJ", + "city": "Marion / Wytheville", + "state": "VA", + "lat": 36.9, + "lon": -81.35 + }, + "KMTV": { + "id": "KMTV", + "city": "Martinsville", + "state": "VA", + "lat": 36.63333, + "lon": -80.01667 + }, + "KNFE": { + "id": "KNFE", + "city": "Fentress, Naval Auxiliary Landing Field", + "state": "VA", + "lat": 36.70083, + "lon": -76.12833 + }, + "KNGU": { + "id": "KNGU", + "city": "Norfolk, Naval Air Station", + "state": "VA", + "lat": 36.93361, + "lon": -76.29583 + }, + "KNTU": { + "id": "KNTU", + "city": "Virginia Beach, Oceana, Naval Air Station", + "state": "VA", + "lat": 36.82111, + "lon": -76.02833 + }, + "KNYG": { + "id": "KNYG", + "city": "Quantico Marine Corps Airfield - Turner Field", + "state": "VA", + "lat": 38.50326, + "lon": -77.30129 + }, + "KOFP": { + "id": "KOFP", + "city": "Ashland, Hanover County Municipal Airport", + "state": "VA", + "lat": 37.70806, + "lon": -77.43444 + }, + "KOKV": { + "id": "KOKV", + "city": "Winchester Regional", + "state": "VA", + "lat": 39.15, + "lon": -78.15 + }, + "KOMH": { + "id": "KOMH", + "city": "Orange, Orange County Airport", + "state": "VA", + "lat": 38.24722, + "lon": -78.04556 + }, + "KORF": { + "id": "KORF", + "city": "Norfolk, Norfolk International Airport", + "state": "VA", + "lat": 36.90361, + "lon": -76.19194 + }, + "KPHF": { + "id": "KPHF", + "city": "Newport News, Newport News / Williamsburg International Airport", + "state": "VA", + "lat": 37.13194, + "lon": -76.49306 + }, + "KPSK": { + "id": "KPSK", + "city": "Dublin / New River Valley", + "state": "VA", + "lat": 37.13333, + "lon": -80.68333 + }, + "KPTB": { + "id": "KPTB", + "city": "Petersburg, Dinwiddie County Airport", + "state": "VA", + "lat": 37.18333, + "lon": -77.51667 + }, + "KPVG": { + "id": "KPVG", + "city": "Norfolk Hampton Roads Executive Airport", + "state": "VA", + "lat": 36.7801, + "lon": -76.4488 + }, + "KRIC": { + "id": "KRIC", + "city": "Richmond, Richmond International Airport", + "state": "VA", + "lat": 37.51111, + "lon": -77.32333 + }, + "KRMN": { + "id": "KRMN", + "city": "Stafford, Stafford Regional Airport", + "state": "VA", + "lat": 38.39806, + "lon": -77.45528 + }, + "KROA": { + "id": "KROA", + "city": "Roanoke, Roanoke Regional Airport", + "state": "VA", + "lat": 37.31694, + "lon": -79.97417 + }, + "KSFQ": { + "id": "KSFQ", + "city": "Suffolk, Suffolk Municipal Airport", + "state": "VA", + "lat": 36.68222, + "lon": -76.60194 + }, + "KSHD": { + "id": "KSHD", + "city": "Staunton / Shenandoah", + "state": "VA", + "lat": 38.26667, + "lon": -78.9 + }, + "KTGI": { + "id": "KTGI", + "city": "Tangier Island Airport", + "state": "VA", + "lat": 37.82587, + "lon": -75.99766 + }, + "KVBW": { + "id": "KVBW", + "city": "Bridgewater Air Park", + "state": "VA", + "lat": 38.36674, + "lon": -78.96033 + }, + "KVJI": { + "id": "KVJI", + "city": "Abingdon", + "state": "VA", + "lat": 36.68333, + "lon": -82.03333 + }, + "KWAL": { + "id": "KWAL", + "city": "Wallops Flight Facility Airport", + "state": "VA", + "lat": 37.9372, + "lon": -75.46619 + }, + "KXSA": { + "id": "KXSA", + "city": "Tappahannock-Essex County Airport", + "state": "VA", + "lat": 37.859611, + "lon": -76.894111 + }, + "PAAD": { + "id": "PAAD", + "city": "Point Thomson Airstrip", + "state": "AK", + "lat": 70.136, + "lon": -146.2901 + }, + "PAAK": { + "id": "PAAK", + "city": "Atka, Atka Airport", + "state": "AK", + "lat": 52.22028, + "lon": -174.20639 + }, + "PAAQ": { + "id": "PAAQ", + "city": "Palmer, Palmer Municipal Airport", + "state": "AK", + "lat": 61.6, + "lon": -149.08333 + }, + "PABA": { + "id": "PABA", + "city": "Barter Island, Barter Island LRRS Airport", + "state": "AK", + "lat": 70.1338899, + "lon": -143.57694 + }, + "PABE": { + "id": "PABE", + "city": "Bethel, Bethel Airport", + "state": "AK", + "lat": 60.77972, + "lon": -161.83778 + }, + "PABI": { + "id": "PABI", + "city": "Delta Junction/Ft Greely, Allen Army Airfield", + "state": "AK", + "lat": 64, + "lon": -145.73333 + }, + "PABL": { + "id": "PABL", + "city": "Buckland, Buckland Airport", + "state": "AK", + "lat": 65.98222, + "lon": -161.15194 + }, + "PABR": { + "id": "PABR", + "city": "Wiley Post-Will Rogers Memorial Airport", + "state": "AK", + "lat": 71.28528, + "lon": -156.76583 + }, + "PABT": { + "id": "PABT", + "city": "Bettles, Bettles Airport", + "state": "AK", + "lat": 66.91667, + "lon": -151.51667 + }, + "PABV": { + "id": "PABV", + "city": "Birchwood, Birchwood Airport", + "state": "AK", + "lat": 61.41667, + "lon": -149.51667 + }, + "PACD": { + "id": "PACD", + "city": "Cold Bay, Cold Bay Airport", + "state": "AK", + "lat": 55.22083, + "lon": -162.72778 + }, + "PACV": { + "id": "PACV", + "city": "Cordova, Merle K (Mudhole) Smith Airport", + "state": "AK", + "lat": 60.49167, + "lon": -145.47778 + }, + "PACX": { + "id": "PACX", + "city": "Coldfoot Airport", + "state": "AK", + "lat": 67.25217, + "lon": -150.20391 + }, + "PACZ": { + "id": "PACZ", + "city": "Cape Romanzof, Cape Romanzof LRRS Airport", + "state": "AK", + "lat": 61.78333, + "lon": -166.03333 + }, + "PADE": { + "id": "PADE", + "city": "Deering, Deering/New Airport", + "state": "AK", + "lat": 66.08333, + "lon": -162.75 + }, + "PADG": { + "id": "PADG", + "city": "Red Dog", + "state": "AK", + "lat": 68.0321, + "lon": -162.8992 + }, + "PADK": { + "id": "PADK", + "city": "Adak Island, Adak Airport", + "state": "AK", + "lat": 51.87778, + "lon": -176.64583 + }, + "PADL": { + "id": "PADL", + "city": "Dillingham, Dillingham Airport", + "state": "AK", + "lat": 59.05, + "lon": -158.51667 + }, + "PADM": { + "id": "PADM", + "city": "Marshall", + "state": "AK", + "lat": 61.8643, + "lon": -162.0261 + }, + "PADQ": { + "id": "PADQ", + "city": "Kodiak, Kodiak Airport", + "state": "AK", + "lat": 57.75, + "lon": -152.5 + }, + "PADU": { + "id": "PADU", + "city": "Unalaska, Unalaska Airport", + "state": "AK", + "lat": 53.9, + "lon": -166.53333 + }, + "PAED": { + "id": "PAED", + "city": "Anchorage, Elmendorf Air Force Base", + "state": "AK", + "lat": 61.25306, + "lon": -149.79389 + }, + "PAEG": { + "id": "PAEG", + "city": "Eagle, Eagle Airport", + "state": "AK", + "lat": 64.77639, + "lon": -141.15083 + }, + "PAEH": { + "id": "PAEH", + "city": "Cape Newenham, Cape Newenham LRRS Airport", + "state": "AK", + "lat": 58.65, + "lon": -162.0666699 + }, + "PAEI": { + "id": "PAEI", + "city": "Fairbanks, Eielson Air Force Base", + "state": "AK", + "lat": 64.65, + "lon": -147.1 + }, + "PAEL": { + "id": "PAEL", + "city": "Elfin Cove - Elfin Cove Seaplane Base", + "state": "AK", + "lat": 58.19467, + "lon": -136.34663 + }, + "PAEM": { + "id": "PAEM", + "city": "Emmonak, Emmonak Airport", + "state": "AK", + "lat": 62.78333, + "lon": -164.5 + }, + "PAEN": { + "id": "PAEN", + "city": "Kenai, Kenai Municipal Airport", + "state": "AK", + "lat": 60.57306, + "lon": -151.245 + }, + "PAFA": { + "id": "PAFA", + "city": "Fairbanks, Fairbanks International Airport", + "state": "AK", + "lat": 64.80389, + "lon": -147.87611 + }, + "PAFB": { + "id": "PAFB", + "city": "Fort Wainwright AAF", + "state": "AK", + "lat": 64.83667, + "lon": -147.59556 + }, + "PAFE": { + "id": "PAFE", + "city": "Kake - Kake Airport", + "state": "AK", + "lat": 56.964, + "lon": -133.913 + }, + "PAFR": { + "id": "PAFR", + "city": "Ft. Richardson / Bryant U. S. Army Heliport, Ak", + "state": "AK", + "lat": 61.26667, + "lon": -149.65 + }, + "PAFS": { + "id": "PAFS", + "city": "Nikolai", + "state": "AK", + "lat": 63.019, + "lon": -154.358 + }, + "PAGA": { + "id": "PAGA", + "city": "Galena, Edward G. Pitka Sr. Airport", + "state": "AK", + "lat": 64.73333, + "lon": -156.93333 + }, + "PAGB": { + "id": "PAGB", + "city": "Galbraith Lake, Galbraith Lake Airport", + "state": "AK", + "lat": 68.48333, + "lon": -149.48333 + }, + "PAGH": { + "id": "PAGH", + "city": "Shungnak Airport", + "state": "AK", + "lat": 66.8881, + "lon": -157.1624 + }, + "PAGK": { + "id": "PAGK", + "city": "Gulkana, Gulkana Airport", + "state": "AK", + "lat": 62.15, + "lon": -145.45 + }, + "PAGL": { + "id": "PAGL", + "city": "Golovin, Golovin Airport", + "state": "AK", + "lat": 64.54333, + "lon": -163.03944 + }, + "PAGM": { + "id": "PAGM", + "city": "Gambell, Gambell Airport", + "state": "AK", + "lat": 63.76667, + "lon": -171.73333 + }, + "PAGN": { + "id": "PAGN", + "city": "Angoon", + "state": "AK", + "lat": 57.5, + "lon": -134.58333 + }, + "PAGS": { + "id": "PAGS", + "city": "Gustavus, Gustavus Airport", + "state": "AK", + "lat": 58.41667, + "lon": -135.7 + }, + "PAGY": { + "id": "PAGY", + "city": "Skagway", + "state": "AK", + "lat": 59.4544, + "lon": -135.3263 + }, + "PAHC": { + "id": "PAHC", + "city": "Holy Cross", + "state": "AK", + "lat": 62.1873, + "lon": -159.77657 + }, + "PAHL": { + "id": "PAHL", + "city": "Huslia, Huslia Airport", + "state": "AK", + "lat": 65.6975, + "lon": -156.35111 + }, + "PAHN": { + "id": "PAHN", + "city": "Haines - Haines Airport", + "state": "AK", + "lat": 59.2429, + "lon": -135.5114 + }, + "PAHO": { + "id": "PAHO", + "city": "Homer, Homer Airport", + "state": "AK", + "lat": 59.65, + "lon": -151.48333 + }, + "PAHX": { + "id": "PAHX", + "city": "Shageluk Airport", + "state": "AK", + "lat": 62.6923, + "lon": -159.5692 + }, + "PAHY": { + "id": "PAHY", + "city": "Hydaburg - Hydaburg Seaplane Base", + "state": "AK", + "lat": 55.2, + "lon": -132.83333 + }, + "PAIG": { + "id": "PAIG", + "city": "Igiugig", + "state": "AK", + "lat": 59.32395, + "lon": -155.90235 + }, + "PAII": { + "id": "PAII", + "city": "Egegik, Egegik Airport", + "state": "AK", + "lat": 58.18528, + "lon": -157.38556 + }, + "PAIK": { + "id": "PAIK", + "city": "Kinana / Bob Baker Me", + "state": "AK", + "lat": 66.98333, + "lon": -160.43333 + }, + "PAIL": { + "id": "PAIL", + "city": "Iliamna, Iliamna Airport", + "state": "AK", + "lat": 59.75, + "lon": -154.9 + }, + "PAIM": { + "id": "PAIM", + "city": "Utopia Creek, Indian Mountain LRRS Airport", + "state": "AK", + "lat": 66, + "lon": -153.7 + }, + "PAIN": { + "id": "PAIN", + "city": "McKinley Park, McKinley National Park Airport", + "state": "AK", + "lat": 63.73333, + "lon": -148.91667 + }, + "PAIW": { + "id": "PAIW", + "city": "Wales", + "state": "AK", + "lat": 65.6226, + "lon": -168.0949 + }, + "PAJC": { + "id": "PAJC", + "city": "Chignik, Chignik Airport", + "state": "AK", + "lat": 56.31139, + "lon": -158.37333 + }, + "PAJK": { + "id": "PAJK", + "city": "NWS Office: Juneau", + "state": "AK", + "lat": 58.4, + "lon": -134.57001 + }, + "PAJN": { + "id": "PAJN", + "city": "Juneau, Juneau International Airport", + "state": "AK", + "lat": 58.35472, + "lon": -134.57611 + }, + "PAJZ": { + "id": "PAJZ", + "city": "Koliganek", + "state": "AK", + "lat": 59.727, + "lon": -157.2589999 + }, + "PAKF": { + "id": "PAKF", + "city": "False Pass Airport", + "state": "AK", + "lat": 54.847, + "lon": -163.41 + }, + "PAKH": { + "id": "PAKH", + "city": "Akhiok", + "state": "AK", + "lat": 56.9387, + "lon": -154.1826 + }, + "PAKK": { + "id": "PAKK", + "city": "Koyuk, Koyuk Airport", + "state": "AK", + "lat": 64.93389, + "lon": -161.15806 + }, + "PAKN": { + "id": "PAKN", + "city": "King Salmon, King Salmon Airport", + "state": "AK", + "lat": 58.67667, + "lon": -156.64917 + }, + "PAKP": { + "id": "PAKP", + "city": "Anaktuvuk Pass, Anaktuvuk Pass Airport", + "state": "AK", + "lat": 68.13361, + "lon": -151.7433299 + }, + "PAKT": { + "id": "PAKT", + "city": "Ketchikan, Ketchikan International Airport", + "state": "AK", + "lat": 55.35556, + "lon": -131.71361 + }, + "PAKU": { + "id": "PAKU", + "city": "Kuparuk, Ugnu-Kuparuk Airport", + "state": "AK", + "lat": 70.31667, + "lon": -149.58333 + }, + "PAKV": { + "id": "PAKV", + "city": "Kaltag, Kaltag Airport", + "state": "AK", + "lat": 64.31667, + "lon": -158.73333 + }, + "PAKW": { + "id": "PAKW", + "city": "Klawock - Klawock Airport", + "state": "AK", + "lat": 55.5839, + "lon": -133.067 + }, + "PAKX": { + "id": "PAKX", + "city": "WILDER NATWICK", + "state": "AK", + "lat": 60.2, + "lon": -154.3166 + }, + "PALG": { + "id": "PALG", + "city": "Kalskag", + "state": "AK", + "lat": 61.5364, + "lon": -160.3414 + }, + "PALH": { + "id": "PALH", + "city": "Anchorage, Lake Hood Seaplane Base", + "state": "AK", + "lat": 61.18333, + "lon": -149.96667 + }, + "PALP": { + "id": "PALP", + "city": "Deadhorse, Alpine Airstrip", + "state": "AK", + "lat": 70.33333, + "lon": -150.93333 + }, + "PALU": { + "id": "PALU", + "city": "Cape Lisburne, Cape Lisburne LRRS Airport", + "state": "AK", + "lat": 68.88333, + "lon": -166.1 + }, + "PAMB": { + "id": "PAMB", + "city": "Manokotak", + "state": "AK", + "lat": 58.9902, + "lon": -159.0499 + }, + "PAMC": { + "id": "PAMC", + "city": "McGrath, McGrath Airport", + "state": "AK", + "lat": 62.96667, + "lon": -155.61667 + }, + "PAMD": { + "id": "PAMD", + "city": "Middleton Island Airport", + "state": "AK", + "lat": 59.4423, + "lon": -146.3166 + }, + "PAMH": { + "id": "PAMH", + "city": "Minchumina, Minchumina Airport", + "state": "AK", + "lat": 63.88056, + "lon": -152.30056 + }, + "PAMK": { + "id": "PAMK", + "city": "St Michael Airport", + "state": "AK", + "lat": 63.49006, + "lon": -162.11039 + }, + "PAMM": { + "id": "PAMM", + "city": "Metlakatla, Metlakatla Seaplane Base", + "state": "AK", + "lat": 55.13111, + "lon": -131.57806 + }, + "PAMO": { + "id": "PAMO", + "city": "Mountain Village", + "state": "AK", + "lat": 62.0953, + "lon": -163.6819 + }, + "PAMR": { + "id": "PAMR", + "city": "Anchorage, Merrill Field Airport", + "state": "AK", + "lat": 61.21667, + "lon": -149.85 + }, + "PAMY": { + "id": "PAMY", + "city": "Mekoryuk, Mekoryuk Airport", + "state": "AK", + "lat": 60.36667, + "lon": -166.26667 + }, + "PANA": { + "id": "PANA", + "city": "Napakiak Airport", + "state": "AK", + "lat": 60.6903, + "lon": -161.9785 + }, + "PANC": { + "id": "PANC", + "city": "Anchorage, Ted Stevens Anchorage International Airport", + "state": "AK", + "lat": 61.17444, + "lon": -149.9961099 + }, + "PANI": { + "id": "PANI", + "city": "Aniak, Aniak Airport", + "state": "AK", + "lat": 61.58139, + "lon": -159.54278 + }, + "PANN": { + "id": "PANN", + "city": "Nenana Municipal Airport", + "state": "AK", + "lat": 64.54796, + "lon": -149.08398 + }, + "PANU": { + "id": "PANU", + "city": "Nulato Airport", + "state": "AK", + "lat": 64.72933, + "lon": -158.07422 + }, + "PANV": { + "id": "PANV", + "city": "Anvik, Anvik Airport", + "state": "AK", + "lat": 62.64833, + "lon": -160.18972 + }, + "PANW": { + "id": "PANW", + "city": "New Stuyahok", + "state": "AK", + "lat": 59.45, + "lon": -157.328 + }, + "PAOH": { + "id": "PAOH", + "city": "Hoonah - Hoonah Seaplane Base", + "state": "AK", + "lat": 58.097, + "lon": -135.4139999 + }, + "PAOM": { + "id": "PAOM", + "city": "Nome, Nome Airport", + "state": "AK", + "lat": 64.51194, + "lon": -165.445 + }, + "PAOR": { + "id": "PAOR", + "city": "Northway, Northway Airport", + "state": "AK", + "lat": 62.96111, + "lon": -141.92889 + }, + "PAOT": { + "id": "PAOT", + "city": "Ralph Wien Memorial Airport", + "state": "AK", + "lat": 66.88576, + "lon": -162.60624 + }, + "PAOU": { + "id": "PAOU", + "city": "Nelson Lagoon", + "state": "AK", + "lat": 56.008, + "lon": -161.16 + }, + "PAPB": { + "id": "PAPB", + "city": "St. George, St. George Airport", + "state": "AK", + "lat": 56.57861, + "lon": -169.66139 + }, + "PAPG": { + "id": "PAPG", + "city": "Petersburg", + "state": "AK", + "lat": 56.8017, + "lon": -132.9453 + }, + "PAPH": { + "id": "PAPH", + "city": "Port Heiden, Port Heiden Airport", + "state": "AK", + "lat": 56.95, + "lon": -158.63333 + }, + "PAPM": { + "id": "PAPM", + "city": "Platinum", + "state": "AK", + "lat": 59.01667, + "lon": -161.8166699 + }, + "PAPN": { + "id": "PAPN", + "city": "Pilot Point Airport", + "state": "AK", + "lat": 57.58, + "lon": -157.572 + }, + "PAPO": { + "id": "PAPO", + "city": "Point Hope, Point Hope Airport", + "state": "AK", + "lat": 68.35, + "lon": -166.8 + }, + "PAPR": { + "id": "PAPR", + "city": "Prospect Creek, Prospect Creek Airport", + "state": "AK", + "lat": 66.81278, + "lon": -150.64389 + }, + "PAPT": { + "id": "PAPT", + "city": "Puntilla", + "state": "AK", + "lat": 62.1, + "lon": -152.75 + }, + "PAQH": { + "id": "PAQH", + "city": "Quinhagak Airport", + "state": "AK", + "lat": 59.7551, + "lon": -161.8454 + }, + "PAQT": { + "id": "PAQT", + "city": "Nuiqsut, Nuiqsut Airport", + "state": "AK", + "lat": 70.2099999, + "lon": -151.00556 + }, + "PARC": { + "id": "PARC", + "city": "Arctic Village, Arctic Village Airport", + "state": "AK", + "lat": 68.11444, + "lon": -145.57917 + }, + "PARS": { + "id": "PARS", + "city": "Russian Mission", + "state": "AK", + "lat": 61.775, + "lon": -161.3194 + }, + "PARY": { + "id": "PARY", + "city": "Ruby", + "state": "AK", + "lat": 64.7272, + "lon": -155.4697 + }, + "PASA": { + "id": "PASA", + "city": "Savoonga Airport", + "state": "AK", + "lat": 63.68333, + "lon": -170.5 + }, + "PASC": { + "id": "PASC", + "city": "Deadhorse, Deadhorse Airport", + "state": "AK", + "lat": 70.2, + "lon": -148.46667 + }, + "PASD": { + "id": "PASD", + "city": "Sand Point", + "state": "AK", + "lat": 55.31667, + "lon": -160.51667 + }, + "PASH": { + "id": "PASH", + "city": "Shishmaref, Shishmaref Airport", + "state": "AK", + "lat": 66.26667, + "lon": -166.08333 + }, + "PASI": { + "id": "PASI", + "city": "Sitka - Sitka Airport", + "state": "AK", + "lat": 57.048, + "lon": -135.3647 + }, + "PASK": { + "id": "PASK", + "city": "Selawik", + "state": "AK", + "lat": 66.61667, + "lon": -160 + }, + "PASL": { + "id": "PASL", + "city": "Sleetmute", + "state": "AK", + "lat": 61.69735, + "lon": -157.16712 + }, + "PASM": { + "id": "PASM", + "city": "St. Mary's, St. Mary's Airport", + "state": "AK", + "lat": 62.05, + "lon": -163.3 + }, + "PASN": { + "id": "PASN", + "city": "St. Paul Island, St. Paul Island Airport", + "state": "AK", + "lat": 57.16667, + "lon": -170.21667 + }, + "PASO": { + "id": "PASO", + "city": "Seldovia, Seldovia Airport", + "state": "AK", + "lat": 59.45, + "lon": -151.7 + }, + "PASV": { + "id": "PASV", + "city": "Sparrevohn Airways Facilities Sector", + "state": "AK", + "lat": 61.1, + "lon": -155.5666699 + }, + "PASX": { + "id": "PASX", + "city": "Soldotna", + "state": "AK", + "lat": 60.48333, + "lon": -151.03333 + }, + "PASY": { + "id": "PASY", + "city": "Shemya, Eareckson AFB", + "state": "AK", + "lat": 52.71667, + "lon": 174.11667 + }, + "PATA": { + "id": "PATA", + "city": "Tanana, Calhoun Memorial Airport", + "state": "AK", + "lat": 65.16667, + "lon": -152.1 + }, + "PATC": { + "id": "PATC", + "city": "Tin City Airways Facilities Sector", + "state": "AK", + "lat": 65.56667, + "lon": -167.91667 + }, + "PATE": { + "id": "PATE", + "city": "Teller", + "state": "AK", + "lat": 65.2403999, + "lon": -166.3393 + }, + "PATG": { + "id": "PATG", + "city": "Togiac Village, Togiak Airport", + "state": "AK", + "lat": 59.05, + "lon": -160.4 + }, + "PATK": { + "id": "PATK", + "city": "Talkeetna, Talkeetna Airport", + "state": "AK", + "lat": 62.32056, + "lon": -150.09361 + }, + "PATL": { + "id": "PATL", + "city": "Takotna, Tatalina LRRS Airport", + "state": "AK", + "lat": 62.9, + "lon": -155.98333 + }, + "PATO": { + "id": "PATO", + "city": "Portage, Portage Glacier", + "state": "AK", + "lat": 60.78333, + "lon": -148.83333 + }, + "PATQ": { + "id": "PATQ", + "city": "Atqasuk", + "state": "AK", + "lat": 70.4673, + "lon": -157.4357 + }, + "PAUN": { + "id": "PAUN", + "city": "Unalakleet", + "state": "AK", + "lat": 63.88333, + "lon": -160.8 + }, + "PAVA": { + "id": "PAVA", + "city": "Chevak Airport", + "state": "AK", + "lat": 61.5408, + "lon": -165.6009 + }, + "PAVC": { + "id": "PAVC", + "city": "King Cove", + "state": "AK", + "lat": 55.116, + "lon": -162.266 + }, + "PAVD": { + "id": "PAVD", + "city": "Valdez 2", + "state": "AK", + "lat": 61.13333, + "lon": -146.26667 + }, + "PAVL": { + "id": "PAVL", + "city": "Kivalina, Kivalina Airport", + "state": "AK", + "lat": 67.73333, + "lon": -164.55 + }, + "PAWD": { + "id": "PAWD", + "city": "Seward", + "state": "AK", + "lat": 60.11667, + "lon": -149.45 + }, + "PAWG": { + "id": "PAWG", + "city": "Wrangell", + "state": "AK", + "lat": 56.48333, + "lon": -132.36667 + }, + "PAWM": { + "id": "PAWM", + "city": "White Mountain Airport", + "state": "AK", + "lat": 64.6892, + "lon": -163.4127 + }, + "PAWN": { + "id": "PAWN", + "city": "Noatak, Noatak Airport", + "state": "AK", + "lat": 67.56667, + "lon": -162.98333 + }, + "PAWS": { + "id": "PAWS", + "city": "Wasilla, Wasilla Airport", + "state": "AK", + "lat": 61.57194, + "lon": -149.54056 + }, + "PAYA": { + "id": "PAYA", + "city": "Yakutat", + "state": "AK", + "lat": 59.51667, + "lon": -139.66667 + }, + "PAZK": { + "id": "PAZK", + "city": "Eureka, Skelton Airport", + "state": "AK", + "lat": 61.93333, + "lon": -147.16667 + }, + "PFCB": { + "id": "PFCB", + "city": "Chenega Bay Airport", + "state": "AK", + "lat": 60.07856, + "lon": -147.99473 + }, + "PFCL": { + "id": "PFCL", + "city": "Clarks Point Airport", + "state": "AK", + "lat": 58.8337, + "lon": -158.5294 + }, + "PFEL": { + "id": "PFEL", + "city": "Elim Airport", + "state": "AK", + "lat": 64.615, + "lon": -162.2705 + }, + "PFKO": { + "id": "PFKO", + "city": "Kotlik Airport", + "state": "AK", + "lat": 63.03058, + "lon": -163.5326399 + }, + "PFKT": { + "id": "PFKT", + "city": "Brevig Mission Airport", + "state": "AK", + "lat": 65.3313, + "lon": -166.4657 + }, + "PFKW": { + "id": "PFKW", + "city": "Kwethluk Airport", + "state": "AK", + "lat": 60.7903, + "lon": -161.4437 + }, + "PFNO": { + "id": "PFNO", + "city": "Noorvik", + "state": "AK", + "lat": 66.8175, + "lon": -161.0223 + }, + "PFSH": { + "id": "PFSH", + "city": "Shaktoolik Airport", + "state": "AK", + "lat": 64.3711, + "lon": -161.224 + }, + "PFTO": { + "id": "PFTO", + "city": "Tok Junction Airport", + "state": "AK", + "lat": 63.32951, + "lon": -142.95368 + }, + "PFWS": { + "id": "PFWS", + "city": "South Naknek Nr 2 Airport", + "state": "AK", + "lat": 58.7021, + "lon": -157.0026 + }, + "PFYU": { + "id": "PFYU", + "city": "Fort Yukon, Fort Yukon Airport", + "state": "AK", + "lat": 66.56667, + "lon": -145.26667 + }, + "PFZK": { + "id": "PFZK", + "city": "Akiachak Airport", + "state": "AK", + "lat": 60.91381, + "lon": -161.4933299 + }, + "POKA": { + "id": "POKA", + "city": "Tununak Airport", + "state": "AK", + "lat": 60.56953, + "lon": -165.24628 + }, + "PPIT": { + "id": "PPIT", + "city": "Nunapitchuk Airport", + "state": "AK", + "lat": 60.906, + "lon": -162.4406 + }, + "PPIZ": { + "id": "PPIZ", + "city": "Point Lay, Point Lay LRRS Airport", + "state": "AK", + "lat": 69.7166699, + "lon": -163 + }, + "KDET": { + "id": "KDET", + "city": "Coleman A Young Municipal Airport", + "state": "MI", + "lat": 42.40729, + "lon": -83.00894 + }, + "KDRM": { + "id": "KDRM", + "city": "Drummond Island Airport", + "state": "MI", + "lat": 46.0072, + "lon": -83.7427 + }, + "KDTW": { + "id": "KDTW", + "city": "Detroit, Detroit Metropolitan Wayne County Airport", + "state": "MI", + "lat": 42.23139, + "lon": -83.33083 + }, + "KDUH": { + "id": "KDUH", + "city": "Lambertville, Toledo Suburban Airport", + "state": "MI", + "lat": 41.73583, + "lon": -83.65528 + }, + "KERY": { + "id": "KERY", + "city": "Newberry, Luce County Airport", + "state": "MI", + "lat": 46.31111, + "lon": -85.45722 + }, + "KESC": { + "id": "KESC", + "city": "Delta County Airport", + "state": "MI", + "lat": 45.7226799, + "lon": -87.09372 + }, + "KFFX": { + "id": "KFFX", + "city": "Fremont Municipal Airport", + "state": "MI", + "lat": 43.43933, + "lon": -85.9948299 + }, + "KFKS": { + "id": "KFKS", + "city": "Frankfort, Frankfort Dow Memorial Field Airport", + "state": "MI", + "lat": 44.625, + "lon": -86.20056 + }, + "KFNT": { + "id": "KFNT", + "city": "Flint, Bishop International Airport", + "state": "MI", + "lat": 42.96667, + "lon": -83.74944 + }, + "KFPK": { + "id": "KFPK", + "city": "Charlotte, Fitch H Beach Airport", + "state": "MI", + "lat": 42.57444, + "lon": -84.81139 + }, + "KGLR": { + "id": "KGLR", + "city": "Gaylord Regional Airport", + "state": "MI", + "lat": 45.01658, + "lon": -84.68937 + }, + "KGOV": { + "id": "KGOV", + "city": "Grayling, Grayling Army Airfield", + "state": "MI", + "lat": 44.68028, + "lon": -84.72889 + }, + "KGRR": { + "id": "KGRR", + "city": "Grand Rapids, Gerald R. Ford International Airport", + "state": "MI", + "lat": 42.88083, + "lon": -85.52278 + }, + "KHAI": { + "id": "KHAI", + "city": "Haines Memorial Airport", + "state": "MI", + "lat": 41.9598, + "lon": -85.5934 + }, + "KHTL": { + "id": "KHTL", + "city": "Houghton Lake, Roscommon County Airport", + "state": "MI", + "lat": 44.35111, + "lon": -84.67417 + }, + "KHYX": { + "id": "KHYX", + "city": "Saginaw County H W Browne Airport", + "state": "MI", + "lat": 43.43191, + "lon": -83.86476 + }, + "KIKW": { + "id": "KIKW", + "city": "Jack Barstow Airport", + "state": "MI", + "lat": 43.6624, + "lon": -84.26213 + }, + "KIMT": { + "id": "KIMT", + "city": "Iron Mountain / Kingsford, Ford Airport", + "state": "MI", + "lat": 45.81417, + "lon": -88.10889 + }, + "KIRS": { + "id": "KIRS", + "city": "Sturgis, Kirsch Municipal Airport", + "state": "MI", + "lat": 41.8127799, + "lon": -85.43917 + }, + "KISQ": { + "id": "KISQ", + "city": "Manistique, Schoolcraft County Airport", + "state": "MI", + "lat": 45.97472, + "lon": -86.17194 + }, + "KIWD": { + "id": "KIWD", + "city": "Ironwood, Gogebic-Iron County Airport", + "state": "MI", + "lat": 46.53333, + "lon": -90.13333 + }, + "KJXN": { + "id": "KJXN", + "city": "Jackson County Airport - Reynolds Field", + "state": "MI", + "lat": 42.26171, + "lon": -84.46147 + }, + "KJYM": { + "id": "KJYM", + "city": "Hillsdale Municipal Airport", + "state": "MI", + "lat": 41.91972, + "lon": -84.58528 + }, + "KLAN": { + "id": "KLAN", + "city": "Capital Region International Airport", + "state": "MI", + "lat": 42.77616, + "lon": -84.5997 + }, + "KLDM": { + "id": "KLDM", + "city": "Ludington, Mason County Airport", + "state": "MI", + "lat": 43.96667, + "lon": -86.4 + }, + "KLWA": { + "id": "KLWA", + "city": "South Haven, South Haven Area Regional Airport", + "state": "MI", + "lat": 42.35083, + "lon": -86.25611 + }, + "KMBL": { + "id": "KMBL", + "city": "Manistee County - Blacker Airport", + "state": "MI", + "lat": 44.27142, + "lon": -86.23773 + }, + "KMBS": { + "id": "KMBS", + "city": "MBS International Airport", + "state": "MI", + "lat": 43.5281, + "lon": -84.08129 + }, + "KMCD": { + "id": "KMCD", + "city": "Mackinac Island Airport", + "state": "MI", + "lat": 45.86628, + "lon": -84.63437 + }, + "KMGN": { + "id": "KMGN", + "city": "Harbor Springs, Harbor Springs Airport", + "state": "MI", + "lat": 45.42556, + "lon": -84.91333 + }, + "KMKG": { + "id": "KMKG", + "city": "Muskegon, Muskegon County Airport", + "state": "MI", + "lat": 43.17111, + "lon": -86.23667 + }, + "KMNM": { + "id": "KMNM", + "city": "Menominee - Marinette Twin County Airport", + "state": "MI", + "lat": 45.12628, + "lon": -87.64438 + }, + "KMOP": { + "id": "KMOP", + "city": "Mount Pleasant, Mount Pleasant Municipal Airport", + "state": "MI", + "lat": 43.61667, + "lon": -84.73333 + }, + "KMTC": { + "id": "KMTC", + "city": "Selfridge Air National Guard Base", + "state": "MI", + "lat": 42.60458, + "lon": -82.83528 + }, + "KOEB": { + "id": "KOEB", + "city": "Branch County Memorial Airport", + "state": "MI", + "lat": 41.93085, + "lon": -85.05429 + }, + "KONZ": { + "id": "KONZ", + "city": "Detroit/Grosse Ile, Grosse Ile Airport", + "state": "MI", + "lat": 42.09861, + "lon": -83.1611099 + }, + "KOSC": { + "id": "KOSC", + "city": "Oscoda, Oscoda-Wurtsmith Airport", + "state": "MI", + "lat": 44.45, + "lon": -83.36667 + }, + "KOZW": { + "id": "KOZW", + "city": "Howell, Livingston County Airport", + "state": "MI", + "lat": 42.62944, + "lon": -83.98417 + }, + "KPHN": { + "id": "KPHN", + "city": "St Clair County International Airport", + "state": "MI", + "lat": 42.91031, + "lon": -82.53315 + }, + "KPLN": { + "id": "KPLN", + "city": "Pellston Regional Airport of Emmet County", + "state": "MI", + "lat": 45.56443, + "lon": -84.7928699 + }, + "KPTK": { + "id": "KPTK", + "city": "Pontiac, Oakland County International Airport", + "state": "MI", + "lat": 42.66306, + "lon": -83.41 + }, + "KPZQ": { + "id": "KPZQ", + "city": "Rogers City, Presque Isle County Airport", + "state": "MI", + "lat": 45.40694, + "lon": -83.81278 + }, + "KRMY": { + "id": "KRMY", + "city": "Brooks Field Airport", + "state": "MI", + "lat": 42.25238, + "lon": -84.95253 + }, + "KRNP": { + "id": "KRNP", + "city": "Owosso, Owosso Community Airport", + "state": "MI", + "lat": 42.99278, + "lon": -84.13889 + }, + "KRQB": { + "id": "KRQB", + "city": "Big Rapids, Roben-Hood Airport", + "state": "MI", + "lat": 43.7224999, + "lon": -85.50417 + }, + "KSAW": { + "id": "KSAW", + "city": "Marquette, Sawyer International Airport", + "state": "MI", + "lat": 46.35361, + "lon": -87.39528 + }, + "KSJX": { + "id": "KSJX", + "city": "Beaver Island, Beaver Island Airport", + "state": "MI", + "lat": 45.69222, + "lon": -85.56639 + }, + "KSLH": { + "id": "KSLH", + "city": "Cheboygan, Cheboygan County Airport", + "state": "MI", + "lat": 45.65361, + "lon": -84.51917 + }, + "KTEW": { + "id": "KTEW", + "city": "Mason, Mason Jewett Field Airport", + "state": "MI", + "lat": 42.56583, + "lon": -84.42333 + }, + "KTTF": { + "id": "KTTF", + "city": "Monroe, Custer Airport", + "state": "MI", + "lat": 41.94, + "lon": -83.43472 + }, + "KTVC": { + "id": "KTVC", + "city": "Cherry Capital Airport", + "state": "MI", + "lat": 44.73898, + "lon": -85.56788 + }, + "KVLL": { + "id": "KVLL", + "city": "Troy, Oakland/Troy Airport", + "state": "MI", + "lat": 42.54278, + "lon": -83.17778 + }, + "KYIP": { + "id": "KYIP", + "city": "Detroit, Willow Run Airport", + "state": "MI", + "lat": 42.2366699, + "lon": -83.52611 + }, + "KBHK": { + "id": "KBHK", + "city": "Baker, Baker Municipal Airport", + "state": "MT", + "lat": 46.34778, + "lon": -104.2574999 + }, + "KBIL": { + "id": "KBIL", + "city": "Billings, Billings Logan International Airport", + "state": "MT", + "lat": 45.80694, + "lon": -108.54222 + }, + "KBTM": { + "id": "KBTM", + "city": "Butte, Bert Mooney Airport", + "state": "MT", + "lat": 45.95472, + "lon": -112.4975 + }, + "KBZN": { + "id": "KBZN", + "city": "Bozeman, Gallatin Field", + "state": "MT", + "lat": 45.78806, + "lon": -111.16083 + }, + "KCTB": { + "id": "KCTB", + "city": "Cut Bank, Cut Bank Municipal Airport", + "state": "MT", + "lat": 48.60833, + "lon": -112.37611 + }, + "KDLN": { + "id": "KDLN", + "city": "Dillon, Dillon Airport", + "state": "MT", + "lat": 45.2575, + "lon": -112.55444 + }, + "KEKS": { + "id": "KEKS", + "city": "Ennis - Big Sky Airport", + "state": "MT", + "lat": 45.27436, + "lon": -111.64886 + }, + "KGDV": { + "id": "KGDV", + "city": "Glendive, Dawson Community Airport", + "state": "MT", + "lat": 47.13333, + "lon": -104.8 + }, + "KGFA": { + "id": "KGFA", + "city": "Malmstrom Air Force Base", + "state": "MT", + "lat": 47.5, + "lon": -111.18333 + }, + "KGGW": { + "id": "KGGW", + "city": "Glasgow, Glasgow International Airport", + "state": "MT", + "lat": 48.21389, + "lon": -106.62139 + }, + "KGPI": { + "id": "KGPI", + "city": "Kalispell, Glacier Park International Airport", + "state": "MT", + "lat": 48.30417, + "lon": -114.26361 + }, + "KGTF": { + "id": "KGTF", + "city": "Great Falls, Great Falls International Airport", + "state": "MT", + "lat": 47.47333, + "lon": -111.38222 + }, + "KHLN": { + "id": "KHLN", + "city": "Helena Regional Airport", + "state": "MT", + "lat": 46.60445, + "lon": -111.9892 + }, + "KHRF": { + "id": "KHRF", + "city": "Ravalli County Airport", + "state": "MT", + "lat": 46.25463, + "lon": -114.1246 + }, + "KHVR": { + "id": "KHVR", + "city": "Havre, Havre City-County Airport", + "state": "MT", + "lat": 48.54278, + "lon": -109.76333 + }, + "KJDN": { + "id": "KJDN", + "city": "Jordan, Jordan Airport", + "state": "MT", + "lat": 47.32583, + "lon": -106.9475 + }, + "KLVM": { + "id": "KLVM", + "city": "Livingston, Mission Field Airport", + "state": "MT", + "lat": 45.69944, + "lon": -110.44833 + }, + "KLWT": { + "id": "KLWT", + "city": "Lewistown, Lewistown Municipal Airport", + "state": "MT", + "lat": 47.0491699, + "lon": -109.46639 + }, + "KMLP": { + "id": "KMLP", + "city": "Mullan Pass, Mullan Pass Vor", + "state": "MT", + "lat": 47.45417, + "lon": -115.66972 + }, + "KMLS": { + "id": "KMLS", + "city": "Miles City, Frank Wiley Field Airport", + "state": "MT", + "lat": 46.42806, + "lon": -105.88639 + }, + "KMSO": { + "id": "KMSO", + "city": "Missoula, Missoula International Airport", + "state": "MT", + "lat": 46.92083, + "lon": -114.0925 + }, + "KMVH": { + "id": "KMVH", + "city": "N BAR Ranch Airport", + "state": "MT", + "lat": 46.8381, + "lon": -108.9368 + }, + "KOLF": { + "id": "KOLF", + "city": "Wolf Point, Clayton Airport", + "state": "MT", + "lat": 48.09444, + "lon": -105.57722 + }, + "KPWD": { + "id": "KPWD", + "city": "Sher-Wood Airport", + "state": "MT", + "lat": 48.789, + "lon": -104.52297 + }, + "KRVF": { + "id": "KRVF", + "city": "Ruby Valley Field Airport", + "state": "MT", + "lat": 45.53542, + "lon": -112.30228 + }, + "KSBX": { + "id": "KSBX", + "city": "Shelby Airport", + "state": "MT", + "lat": 48.54069, + "lon": -111.87125 + }, + "KSDY": { + "id": "KSDY", + "city": "Sidney-Richland", + "state": "MT", + "lat": 47.7, + "lon": -104.2 + }, + "KWYS": { + "id": "KWYS", + "city": "West Yellowstone", + "state": "MT", + "lat": 44.68333, + "lon": -111.11667 + }, + "KAAA": { + "id": "KAAA", + "city": "Logan County Airport", + "state": "IL", + "lat": 40.15885, + "lon": -89.33891 + }, + "KAJG": { + "id": "KAJG", + "city": "Mount Carmel, Mount Carmel Municipal Airport", + "state": "IL", + "lat": 38.60928, + "lon": -87.72508 + }, + "KALN": { + "id": "KALN", + "city": "St. Louis Regional Airport", + "state": "IL", + "lat": 38.88968, + "lon": -90.03163 + }, + "KARR": { + "id": "KARR", + "city": "Aurora Municipal Airport", + "state": "IL", + "lat": 41.77132, + "lon": -88.48147 + }, + "KBLV": { + "id": "KBLV", + "city": "Belleville, Scott AFB/MidAmerica Airport", + "state": "IL", + "lat": 38.55, + "lon": -89.85 + }, + "KBMI": { + "id": "KBMI", + "city": "Bloomington/Normal, Central Illinois Regional Airport at Bloomington-Normal", + "state": "IL", + "lat": 40.47694, + "lon": -88.91583 + }, + "KCIR": { + "id": "KCIR", + "city": "Cairo Regional Airport", + "state": "IL", + "lat": 37.06388, + "lon": -89.2232 + }, + "KCMI": { + "id": "KCMI", + "city": "University of Illinois - Willard", + "state": "IL", + "lat": 40.03245, + "lon": -88.27547 + }, + "KCPS": { + "id": "KCPS", + "city": "St. Louis Downtown Airport", + "state": "IL", + "lat": 38.56403, + "lon": -90.14871 + }, + "KDEC": { + "id": "KDEC", + "city": "Decatur Airport", + "state": "IL", + "lat": 39.8308, + "lon": -88.87192 + }, + "KDKB": { + "id": "KDKB", + "city": "De Kalb Taylor Municipal Airport", + "state": "IL", + "lat": 41.93381, + "lon": -88.70657 + }, + "KDNV": { + "id": "KDNV", + "city": "Danville, Vermilion County Airport", + "state": "IL", + "lat": 40.19944, + "lon": -87.59556 + }, + "KDPA": { + "id": "KDPA", + "city": "Chicago / West Chicago, Dupage Airport", + "state": "IL", + "lat": 41.8963899, + "lon": -88.25111 + }, + "KENL": { + "id": "KENL", + "city": "Centralia Municipal Airport", + "state": "IL", + "lat": 38.50951, + "lon": -89.08996 + }, + "KFOA": { + "id": "KFOA", + "city": "Flora Municipal Airport", + "state": "IL", + "lat": 38.66726, + "lon": -88.4526999 + }, + "KFWC": { + "id": "KFWC", + "city": "Fairfield, Fairfield Municipal Airport", + "state": "IL", + "lat": 38.37861, + "lon": -88.41278 + }, + "KGBG": { + "id": "KGBG", + "city": "Galesburg Municipal Airport", + "state": "IL", + "lat": 40.9328999, + "lon": -90.43339 + }, + "KHSB": { + "id": "KHSB", + "city": "Harrisburg-Raleigh Airport", + "state": "IL", + "lat": 37.81281, + "lon": -88.54486 + }, + "KIGQ": { + "id": "KIGQ", + "city": "Lansing Municipal Airport", + "state": "IL", + "lat": 41.54125, + "lon": -87.52822 + }, + "KIJX": { + "id": "KIJX", + "city": "Jacksonville Municipal Airport", + "state": "IL", + "lat": 39.7740099, + "lon": -90.24187 + }, + "KIKK": { + "id": "KIKK", + "city": "Greater Kankakee Airport", + "state": "IL", + "lat": 41.06871, + "lon": -87.85372 + }, + "KJOT": { + "id": "KJOT", + "city": "Joliet Regional Airport", + "state": "IL", + "lat": 41.51755, + "lon": -88.17903 + }, + "KLOT": { + "id": "KLOT", + "city": "Lewis University Airport", + "state": "IL", + "lat": 41.60307, + "lon": -88.10164 + }, + "KLWV": { + "id": "KLWV", + "city": "Lawrenceville-Vincennes International Airport", + "state": "IL", + "lat": 38.76046, + "lon": -87.59903 + }, + "KMDH": { + "id": "KMDH", + "city": "Southern Illinois Airport", + "state": "IL", + "lat": 37.78328, + "lon": -89.24532 + }, + "KMDW": { + "id": "KMDW", + "city": "Chicago, Chicago Midway Airport", + "state": "IL", + "lat": 41.78417, + "lon": -87.75528 + }, + "KMLI": { + "id": "KMLI", + "city": "Moline Quad-City Airport", + "state": "IL", + "lat": 41.4482, + "lon": -90.52359 + }, + "KMQB": { + "id": "KMQB", + "city": "Macomb Municipal Airport", + "state": "IL", + "lat": 40.5176299, + "lon": -90.64807 + }, + "KMTO": { + "id": "KMTO", + "city": "Mattoon / Charleston, Coles County Memorial Airport", + "state": "IL", + "lat": 39.47806, + "lon": -88.2791699 + }, + "KMVN": { + "id": "KMVN", + "city": "Mount Vernon Airport", + "state": "IL", + "lat": 38.32842, + "lon": -88.85292 + }, + "KMWA": { + "id": "KMWA", + "city": "Marion - Williamson County Regional Airport", + "state": "IL", + "lat": 37.76671, + "lon": -89.00993 + }, + "KOLY": { + "id": "KOLY", + "city": "Olney-Noble Airport", + "state": "IL", + "lat": 38.72133, + "lon": -88.1799 + }, + "KORD": { + "id": "KORD", + "city": "Chicago, Chicago-O'Hare International Airport", + "state": "IL", + "lat": 41.97972, + "lon": -87.9044399 + }, + "KPIA": { + "id": "KPIA", + "city": "Peoria - General Downing-Peoria International Airport", + "state": "IL", + "lat": 40.6674999, + "lon": -89.68389 + }, + "KPNT": { + "id": "KPNT", + "city": "Pontiac Municipal Airport", + "state": "IL", + "lat": 40.92327, + "lon": -88.6213 + }, + "KPPQ": { + "id": "KPPQ", + "city": "Pittsfield, Pittsfield Penstone Municipal Airport", + "state": "IL", + "lat": 39.63889, + "lon": -90.77833 + }, + "KPRG": { + "id": "KPRG", + "city": "Edgar County Airport", + "state": "IL", + "lat": 39.69817, + "lon": -87.6669 + }, + "KPWK": { + "id": "KPWK", + "city": "Chicago / Wheeling, Pal-Waukee Airport", + "state": "IL", + "lat": 42.12083, + "lon": -87.90472 + }, + "KRFD": { + "id": "KRFD", + "city": "Rockford, Greater Rockford Airport", + "state": "IL", + "lat": 42.19278, + "lon": -89.09333 + }, + "KRPJ": { + "id": "KRPJ", + "city": "Rochelle, Rochelle Municipal-Koritz Field Airport", + "state": "IL", + "lat": 41.8905699, + "lon": -89.08175 + }, + "KSAR": { + "id": "KSAR", + "city": "Sparta Community-Hunter Field Airport", + "state": "IL", + "lat": 38.14624, + "lon": -89.70243 + }, + "KSLO": { + "id": "KSLO", + "city": "Salem, Salem-Leckrone Airport", + "state": "IL", + "lat": 38.64278, + "lon": -88.96417 + }, + "KSPI": { + "id": "KSPI", + "city": "Springfield - Abraham Lincoln Capital Airport", + "state": "IL", + "lat": 39.84527, + "lon": -89.68405 + }, + "KSQI": { + "id": "KSQI", + "city": "Sterling Rockfalls", + "state": "IL", + "lat": 41.7432, + "lon": -89.66547 + }, + "KTAZ": { + "id": "KTAZ", + "city": "Taylorville, Taylorville Municipal Airport", + "state": "IL", + "lat": 39.53417, + "lon": -89.32778 + }, + "KTIP": { + "id": "KTIP", + "city": "Rantoul National Aviation Center Airport", + "state": "IL", + "lat": 40.28952, + "lon": -88.1473 + }, + "KUGN": { + "id": "KUGN", + "city": "Chicago/Waukegan Regional Airport", + "state": "IL", + "lat": 42.42546, + "lon": -87.86339 + }, + "KUIN": { + "id": "KUIN", + "city": "Quincy Regional Airport-Baldwin Field", + "state": "IL", + "lat": 39.9371, + "lon": -91.19659 + }, + "KVYS": { + "id": "KVYS", + "city": "Illinois Valley Regional Airport", + "state": "IL", + "lat": 41.35175, + "lon": -89.14963 + }, + "KALK": { + "id": "KALK", + "city": "Pioneer Airfield", + "state": "AZ", + "lat": 31.60564, + "lon": -110.4281 + }, + "KAVQ": { + "id": "KAVQ", + "city": "Tucson Marana Regional Airport", + "state": "AZ", + "lat": 32.4096, + "lon": -111.2184 + }, + "KAZC": { + "id": "KAZC", + "city": "Colorado City, Colorado City Municipal Airport", + "state": "AZ", + "lat": 36.95, + "lon": -113 + }, + "KBXK": { + "id": "KBXK", + "city": "Buckeye Municipal Airport", + "state": "AZ", + "lat": 33.4204, + "lon": -112.6862 + }, + "KCGZ": { + "id": "KCGZ", + "city": "Casa Grande, Casa Grande Municipal Airport", + "state": "AZ", + "lat": 32.95, + "lon": -111.76667 + }, + "KCHD": { + "id": "KCHD", + "city": "Chandler, Chandler Municipal Airport", + "state": "AZ", + "lat": 33.26917, + "lon": -111.81111 + }, + "KCMR": { + "id": "KCMR", + "city": "Williams/Clark Memorial Airport", + "state": "AZ", + "lat": 35.3054721, + "lon": -112.1943889 + }, + "KDMA": { + "id": "KDMA", + "city": "Davis-Monthan Air Force Base", + "state": "AZ", + "lat": 32.16667, + "lon": -110.88333 + }, + "KDUG": { + "id": "KDUG", + "city": "Bisbee Douglas International Airport", + "state": "AZ", + "lat": 31.45838, + "lon": -109.60676 + }, + "KDVT": { + "id": "KDVT", + "city": "Phoenix, Phoenix-Deer Valley Municipal Airport", + "state": "AZ", + "lat": 33.69026, + "lon": -112.06618 + }, + "KFFZ": { + "id": "KFFZ", + "city": "Mesa / Falcon Field", + "state": "AZ", + "lat": 33.46667, + "lon": -111.73333 + }, + "KFHU": { + "id": "KFHU", + "city": "Fort Huachuca, Libby AAF Ft Huachuca", + "state": "AZ", + "lat": 31.58333, + "lon": -110.33333 + }, + "KFLG": { + "id": "KFLG", + "city": "Flagstaff Pulliam Airport", + "state": "AZ", + "lat": 35.1443299, + "lon": -111.66637 + }, + "KGCN": { + "id": "KGCN", + "city": "Grand Canyon National Park Airport", + "state": "AZ", + "lat": 35.94582, + "lon": -112.15538 + }, + "KGEU": { + "id": "KGEU", + "city": "Glendale, Glendale Municipal Airport", + "state": "AZ", + "lat": 33.52722, + "lon": -112.29528 + }, + "KGXF": { + "id": "KGXF", + "city": "Gila Bend Air Force Auxiliary Field", + "state": "AZ", + "lat": 32.8875, + "lon": -112.72 + }, + "KGYR": { + "id": "KGYR", + "city": "Goodyear Municipal", + "state": "AZ", + "lat": 33.41667, + "lon": -112.38333 + }, + "KHII": { + "id": "KHII", + "city": "Havasu City Airport", + "state": "AZ", + "lat": 34.56595, + "lon": -114.35224 + }, + "KIFP": { + "id": "KIFP", + "city": "Bullhead City, Laughlin/Bullhead International Airport", + "state": "AZ", + "lat": 35.1575, + "lon": -114.55944 + }, + "KIGM": { + "id": "KIGM", + "city": "Kingman, Kingman Airport", + "state": "AZ", + "lat": 35.2577799, + "lon": -113.93306 + }, + "KINW": { + "id": "KINW", + "city": "Winslow, Winslow Municipal Airport", + "state": "AZ", + "lat": 35.02806, + "lon": -110.72083 + }, + "KIWA": { + "id": "KIWA", + "city": "Phoenix-Mesa Gateway Airport", + "state": "AZ", + "lat": 33.31667, + "lon": -111.65 + }, + "KJTC": { + "id": "KJTC", + "city": "Springerville Municipal Airport", + "state": "AZ", + "lat": 34.1293999, + "lon": -109.3109 + }, + "KLGF": { + "id": "KLGF", + "city": "Laguna Army Airfield", + "state": "AZ", + "lat": 32.86459, + "lon": -114.39298 + }, + "KLUF": { + "id": "KLUF", + "city": "Luke Air Force Base / Phoenix", + "state": "AZ", + "lat": 33.53333, + "lon": -112.38333 + }, + "KMZJ": { + "id": "KMZJ", + "city": "Pinal Airpark", + "state": "AZ", + "lat": 32.50983, + "lon": -111.32533 + }, + "KNOZ": { + "id": "KNOZ", + "city": "Yuma Auxiliary Airfield", + "state": "AZ", + "lat": 32.5, + "lon": -114.45 + }, + "KNYL": { + "id": "KNYL", + "city": "Yuma, Marine Corps Air Station", + "state": "AZ", + "lat": 32.6594399, + "lon": -114.59306 + }, + "KOLS": { + "id": "KOLS", + "city": "Nogales, Nogales International Airport", + "state": "AZ", + "lat": 31.42083, + "lon": -110.84583 + }, + "KPAN": { + "id": "KPAN", + "city": "Payson Airport", + "state": "AZ", + "lat": 34.2568364, + "lon": -111.3392558 + }, + "KPGA": { + "id": "KPGA", + "city": "Page, Page Municipal Airport", + "state": "AZ", + "lat": 36.92056, + "lon": -111.44806 + }, + "KPHX": { + "id": "KPHX", + "city": "Phoenix, Phoenix Sky Harbor International Airport", + "state": "AZ", + "lat": 33.427799, + "lon": -112.003465 + }, + "KPRC": { + "id": "KPRC", + "city": "Prescott, Love Field", + "state": "AZ", + "lat": 34.64917, + "lon": -112.42222 + }, + "KRQE": { + "id": "KRQE", + "city": "Window Rock, Window Rock Airport", + "state": "AZ", + "lat": 35.65, + "lon": -109.06667 + }, + "KRYN": { + "id": "KRYN", + "city": "Tucson Ryan Field Airport", + "state": "AZ", + "lat": 32.1422, + "lon": -111.1746 + }, + "KSAD": { + "id": "KSAD", + "city": "Safford, Safford Municipal Airport", + "state": "AZ", + "lat": 32.85722, + "lon": -109.63556 + }, + "KSDL": { + "id": "KSDL", + "city": "Scottsdale Airport", + "state": "AZ", + "lat": 33.61235, + "lon": -111.92316 + }, + "KSEZ": { + "id": "KSEZ", + "city": "Sedona Airport", + "state": "AZ", + "lat": 34.85, + "lon": -111.78333 + }, + "KSJN": { + "id": "KSJN", + "city": "St. Johns, St. Johns Industrial Airpark", + "state": "AZ", + "lat": 34.51833, + "lon": -109.37917 + }, + "KSOW": { + "id": "KSOW", + "city": "Show Low, Show Low Regional Airport", + "state": "AZ", + "lat": 34.26528, + "lon": -110.00556 + }, + "KTUS": { + "id": "KTUS", + "city": "Tucson, Tucson International Airport", + "state": "AZ", + "lat": 32.13153, + "lon": -110.95635 + }, + "KTYL": { + "id": "KTYL", + "city": "Taylor Airport", + "state": "AZ", + "lat": 34.45272, + "lon": -110.11503 + }, + "KAAF": { + "id": "KAAF", + "city": "Apalachicola, Apalachicola", + "state": "FL", + "lat": 29.72694, + "lon": -85.02472 + }, + "KAPF": { + "id": "KAPF", + "city": "Naples, Naples Municipal Airport", + "state": "FL", + "lat": 26.15, + "lon": -81.76667 + }, + "KBCR": { + "id": "KBCR", + "city": "Tri-County Airport", + "state": "FL", + "lat": 30.84389, + "lon": -85.60175 + }, + "KBCT": { + "id": "KBCT", + "city": "Boca Raton, Boca Raton Airport", + "state": "FL", + "lat": 26.3786099, + "lon": -80.10778 + }, + "KBKV": { + "id": "KBKV", + "city": "Brooksville-Tampa Bay Regional Airport", + "state": "FL", + "lat": 28.47361, + "lon": -82.45444 + }, + "KBOW": { + "id": "KBOW", + "city": "Bartow Municipal", + "state": "FL", + "lat": 27.95, + "lon": -81.78333 + }, + "KCEW": { + "id": "KCEW", + "city": "Crestview, Sikes Airport", + "state": "FL", + "lat": 30.77222, + "lon": -86.52 + }, + "KCGC": { + "id": "KCGC", + "city": "Crystal River Airport", + "state": "FL", + "lat": 28.8673, + "lon": -82.5712999 + }, + "KCLW": { + "id": "KCLW", + "city": "Clearwater Air Park", + "state": "FL", + "lat": 27.9742, + "lon": -82.7563 + }, + "KCOF": { + "id": "KCOF", + "city": "Cocoa - Patrick Air Force Base", + "state": "FL", + "lat": 28.24219, + "lon": -80.60799 + }, + "KCOI": { + "id": "KCOI", + "city": "Merritt Island Airport", + "state": "FL", + "lat": 28.3422, + "lon": -80.68407 + }, + "KCRG": { + "id": "KCRG", + "city": "Jacksonville Craig Municipal Airport", + "state": "FL", + "lat": 30.33709, + "lon": -81.51275 + }, + "KCTY": { + "id": "KCTY", + "city": "Cross City Airport", + "state": "FL", + "lat": 29.633326, + "lon": -83.105458 + }, + "KDAB": { + "id": "KDAB", + "city": "Daytona Beach International Airport", + "state": "FL", + "lat": 29.17354, + "lon": -81.07186 + }, + "KDED": { + "id": "KDED", + "city": "DeLand Municipal Airport", + "state": "FL", + "lat": 29.067, + "lon": -81.2837 + }, + "KDTS": { + "id": "KDTS", + "city": "Destin, Destin-Ft. Walton Beach Airport", + "state": "FL", + "lat": 30.39333, + "lon": -86.4675 + }, + "KECP": { + "id": "KECP", + "city": "Panama City - Northwest Florida Beaches International Airport", + "state": "FL", + "lat": 30.3582, + "lon": -85.7955999 + }, + "KEGI": { + "id": "KEGI", + "city": "Duke Field / Eglin Auxiliary", + "state": "FL", + "lat": 30.65, + "lon": -86.51667 + }, + "KEVB": { + "id": "KEVB", + "city": "New Smyrna Beach Municipal Airport", + "state": "FL", + "lat": 29.05687, + "lon": -80.94909 + }, + "KEYW": { + "id": "KEYW", + "city": "Key West International Airport", + "state": "FL", + "lat": 24.55707, + "lon": -81.75539 + }, + "KFHB": { + "id": "KFHB", + "city": "Fernandina Beach Municipal Airport", + "state": "FL", + "lat": 30.61183, + "lon": -81.46119 + }, + "KFIN": { + "id": "KFIN", + "city": "Flagler County Airport", + "state": "FL", + "lat": 29.4657, + "lon": -81.20872 + }, + "KFLL": { + "id": "KFLL", + "city": "Fort Lauderdale/Hollywood International Airport", + "state": "FL", + "lat": 26.07874, + "lon": -80.1622 + }, + "KFMY": { + "id": "KFMY", + "city": "Fort Myers, Page Field", + "state": "FL", + "lat": 26.58417, + "lon": -81.8625 + }, + "KFPR": { + "id": "KFPR", + "city": "Fort Pierce, St. Lucie County International Airport", + "state": "FL", + "lat": 27.49806, + "lon": -80.37667 + }, + "KFPY": { + "id": "KFPY", + "city": "Perry-Foley Airport", + "state": "FL", + "lat": 30.07081, + "lon": -83.58154 + }, + "KFXE": { + "id": "KFXE", + "city": "Fort Lauderdale, Fort Lauderdale Executive Airport", + "state": "FL", + "lat": 26.2, + "lon": -80.18333 + }, + "KGIF": { + "id": "KGIF", + "city": "Winter Havens Gilbert Airport", + "state": "FL", + "lat": 28.06138, + "lon": -81.75684 + }, + "KGNV": { + "id": "KGNV", + "city": "Gainesville, Gainesville Regional Airport", + "state": "FL", + "lat": 29.69194, + "lon": -82.27556 + }, + "KHEG": { + "id": "KHEG", + "city": "Herlong Recreational Airport", + "state": "FL", + "lat": 30.27778, + "lon": -81.80594 + }, + "KHRT": { + "id": "KHRT", + "city": "Hurlburt Field", + "state": "FL", + "lat": 30.41667, + "lon": -86.68333 + }, + "KHST": { + "id": "KHST", + "city": "Homestead Air Reserve Base", + "state": "FL", + "lat": 25.4948799, + "lon": -80.37324 + }, + "KHWO": { + "id": "KHWO", + "city": "Hollywood, North Perry Airport", + "state": "FL", + "lat": 25.99889, + "lon": -80.24111 + }, + "KIMM": { + "id": "KIMM", + "city": "IMMOKALEE", + "state": "FL", + "lat": 26.43, + "lon": -81.4 + }, + "KINF": { + "id": "KINF", + "city": "Inverness Airport", + "state": "FL", + "lat": 28.8086, + "lon": -82.3165 + }, + "KISM": { + "id": "KISM", + "city": "Kissimmee Gateway Airport", + "state": "FL", + "lat": 28.29236, + "lon": -81.43716 + }, + "KJAX": { + "id": "KJAX", + "city": "Jacksonville International Airport", + "state": "FL", + "lat": 30.49534, + "lon": -81.6937 + }, + "KLAL": { + "id": "KLAL", + "city": "Lakeland Linder International Airport", + "state": "FL", + "lat": 27.98333, + "lon": -82.01667 + }, + "KLCQ": { + "id": "KLCQ", + "city": "Lake City Municipal Airport", + "state": "FL", + "lat": 30.1821, + "lon": -82.5769 + }, + "KLEE": { + "id": "KLEE", + "city": "Leesburg International Airport", + "state": "FL", + "lat": 28.82142, + "lon": -81.80964 + }, + "KLNA": { + "id": "KLNA", + "city": "Palm Beach County Park Airport", + "state": "FL", + "lat": 26.59305, + "lon": -80.08506 + }, + "KMAI": { + "id": "KMAI", + "city": "Marianna Municipal Airport", + "state": "FL", + "lat": 30.83698, + "lon": -85.18347 + }, + "KMCF": { + "id": "KMCF", + "city": "Macdill Air Force Base, Fl.", + "state": "FL", + "lat": 27.85, + "lon": -82.5 + }, + "KMCO": { + "id": "KMCO", + "city": "Orlando International Airport", + "state": "FL", + "lat": 28.41826, + "lon": -81.32413 + }, + "KMIA": { + "id": "KMIA", + "city": "Miami, Miami International Airport", + "state": "FL", + "lat": 25.79056, + "lon": -80.31639 + }, + "KMLB": { + "id": "KMLB", + "city": "Melbourne International Airport", + "state": "FL", + "lat": 28.09973, + "lon": -80.6356 + }, + "KMTH": { + "id": "KMTH", + "city": "The Florida Keys - Marathon International Airport", + "state": "FL", + "lat": 24.72626, + "lon": -81.04765 + }, + "KNDZ": { + "id": "KNDZ", + "city": "Milton, Whiting Field South", + "state": "FL", + "lat": 30.69722, + "lon": -87.02 + }, + "KNEN": { + "id": "KNEN", + "city": "WHITEHOUSE NOF", + "state": "FL", + "lat": 30.35, + "lon": -81.88 + }, + "KNIP": { + "id": "KNIP", + "city": "Jacksonville Naval Air Station", + "state": "FL", + "lat": 30.23468, + "lon": -81.67462 + }, + "KNPA": { + "id": "KNPA", + "city": "Pensacola Naval Air Station", + "state": "FL", + "lat": 30.35641, + "lon": -87.32326 + }, + "KNQX": { + "id": "KNQX", + "city": "Key West Naval Air Station", + "state": "FL", + "lat": 24.5800899, + "lon": -81.68293 + }, + "KNRB": { + "id": "KNRB", + "city": "Mayport Naval Station - Adm David L. McDonald Field", + "state": "FL", + "lat": 30.39589, + "lon": -81.42286 + }, + "KNSE": { + "id": "KNSE", + "city": "Milton - Whiting Field Naval Air Station North", + "state": "FL", + "lat": 30.72848, + "lon": -87.02192 + }, + "KOBE": { + "id": "KOBE", + "city": "Okeechobee County Airport", + "state": "FL", + "lat": 27.2628, + "lon": -80.8498 + }, + "KOCF": { + "id": "KOCF", + "city": "Ocala International Airport - Jim Taylor Field", + "state": "FL", + "lat": 29.16372, + "lon": -82.22097 + }, + "KOMN": { + "id": "KOMN", + "city": "Ormond Beach, Ormond Beach Municipal Airport", + "state": "FL", + "lat": 29.30111, + "lon": -81.11361 + }, + "KOPF": { + "id": "KOPF", + "city": "Miami, Opa Locka Airport", + "state": "FL", + "lat": 25.91, + "lon": -80.28306 + }, + "KORL": { + "id": "KORL", + "city": "Orlando Executive Airport", + "state": "FL", + "lat": 28.54655, + "lon": -81.33543 + }, + "KPAM": { + "id": "KPAM", + "city": "Tyndall Air Force Base", + "state": "FL", + "lat": 30.06444, + "lon": -85.5637 + }, + "KPBI": { + "id": "KPBI", + "city": "West Palm Beach - Palm Beach International Airport", + "state": "FL", + "lat": 26.6850999, + "lon": -80.0991899 + }, + "KPCM": { + "id": "KPCM", + "city": "Plant City, Plant City Municipal Airport", + "state": "FL", + "lat": 28, + "lon": -82.15 + }, + "KPGD": { + "id": "KPGD", + "city": "Punta Gorda, Charlotte County Airport", + "state": "FL", + "lat": 26.91778, + "lon": -81.99361 + }, + "KPIE": { + "id": "KPIE", + "city": "St. Petersburg/Clearwater Airport", + "state": "FL", + "lat": 27.91259, + "lon": -82.68554 + }, + "KPMP": { + "id": "KPMP", + "city": "Pompano Beach, Pompano Beach Airpark", + "state": "FL", + "lat": 26.24556, + "lon": -80.11139 + }, + "KPNS": { + "id": "KPNS", + "city": "Pensacola - Pensacola International Airport", + "state": "FL", + "lat": 30.47806, + "lon": -87.18694 + }, + "KRSW": { + "id": "KRSW", + "city": "Fort Myers, Southwest Florida International Airport", + "state": "FL", + "lat": 26.52694, + "lon": -81.76639 + }, + "KSEF": { + "id": "KSEF", + "city": "Sebring Regional Airport", + "state": "FL", + "lat": 27.45639, + "lon": -81.34239 + }, + "KSFB": { + "id": "KSFB", + "city": "Orlando / Sanford Airport", + "state": "FL", + "lat": 28.78333, + "lon": -81.25 + }, + "KSGJ": { + "id": "KSGJ", + "city": "Northeast Florida Regional Airport", + "state": "FL", + "lat": 29.95924, + "lon": -81.34105 + }, + "KSPG": { + "id": "KSPG", + "city": "Albert Whitted Airport", + "state": "FL", + "lat": 27.76852, + "lon": -82.62564 + }, + "KSRQ": { + "id": "KSRQ", + "city": "Sarasota / Bradenton, Sarasota-Bradenton International Airport", + "state": "FL", + "lat": 27.40139, + "lon": -82.55861 + }, + "KSUA": { + "id": "KSUA", + "city": "Witham Field Airport", + "state": "FL", + "lat": 27.18157, + "lon": -80.22519 + }, + "KTDR": { + "id": "KTDR", + "city": "Tyndall Drone Runway", + "state": "FL", + "lat": 30.0333, + "lon": -85.5333 + }, + "KTIX": { + "id": "KTIX", + "city": "Titusville", + "state": "FL", + "lat": 28.51667, + "lon": -80.8 + }, + "KTLH": { + "id": "KTLH", + "city": "Tallahassee International Airport", + "state": "FL", + "lat": 30.39675, + "lon": -84.35087 + }, + "KTMB": { + "id": "KTMB", + "city": "Miami, Kendall-Tamiami Executive Airport", + "state": "FL", + "lat": 25.64194, + "lon": -80.43472 + }, + "KTPA": { + "id": "KTPA", + "city": "Tampa, Tampa International Airport", + "state": "FL", + "lat": 27.96139, + "lon": -82.54028 + }, + "KTPF": { + "id": "KTPF", + "city": "Tampa, Peter O Knight Airport", + "state": "FL", + "lat": 27.91556, + "lon": -82.44917 + }, + "KTTS": { + "id": "KTTS", + "city": "Titusville, NASA Shuttle Landing Facility", + "state": "FL", + "lat": 28.61667, + "lon": -80.7 + }, + "KVDF": { + "id": "KVDF", + "city": "Tampa, Vandenberg Airport", + "state": "FL", + "lat": 28.01983, + "lon": -82.3415 + }, + "KVNC": { + "id": "KVNC", + "city": "Venice Municipal Airport", + "state": "FL", + "lat": 27.0716, + "lon": -82.44033 + }, + "KVPS": { + "id": "KVPS", + "city": "Valparaiso / Eglin Air Force Base", + "state": "FL", + "lat": 30.48333, + "lon": -86.51667 + }, + "KVQQ": { + "id": "KVQQ", + "city": "Cecil Airport", + "state": "FL", + "lat": 30.21292, + "lon": -81.8707 + }, + "KVRB": { + "id": "KVRB", + "city": "Vero Beach, Vero Beach Municipal Airport", + "state": "FL", + "lat": 27.65556, + "lon": -80.41806 + }, + "KXMR": { + "id": "KXMR", + "city": "Cocoa Beach, Cape Canaveral Air Force Station Skid Strip", + "state": "FL", + "lat": 28.46667, + "lon": -80.56667 + }, + "KZPH": { + "id": "KZPH", + "city": "Zephyrhills Airport", + "state": "FL", + "lat": 28.2281, + "lon": -82.1559 + }, + "KABH": { + "id": "KABH", + "city": "ELLICOTT-B AFA", + "state": "CO", + "lat": 38.7578, + "lon": -104.3013 + }, + "KAFF": { + "id": "KAFF", + "city": "Air Force Academy", + "state": "CO", + "lat": 38.96667, + "lon": -104.81667 + }, + "KAIB": { + "id": "KAIB", + "city": "Nucla Hopkins Field Airport", + "state": "CO", + "lat": 38.23875, + "lon": -108.563277 + }, + "KAJZ": { + "id": "KAJZ", + "city": "Delta/Blake Field Airport", + "state": "CO", + "lat": 38.7868799, + "lon": -108.06584 + }, + "KAKO": { + "id": "KAKO", + "city": "Colorado Plains Regional Airport", + "state": "CO", + "lat": 40.17428, + "lon": -103.21459 + }, + "KALS": { + "id": "KALS", + "city": "San Luis Valley Regional Airport", + "state": "CO", + "lat": 37.43933, + "lon": -105.8618 + }, + "KANK": { + "id": "KANK", + "city": "Harriet Alexander Field Airport", + "state": "CO", + "lat": 38.53828, + "lon": -106.04864 + }, + "KAPA": { + "id": "KAPA", + "city": "Denver - Centennial Airport", + "state": "CO", + "lat": 39.55991, + "lon": -104.84841 + }, + "KASE": { + "id": "KASE", + "city": "Aspen-Pitkin County Airport", + "state": "CO", + "lat": 39.22992, + "lon": -106.87051 + }, + "KBDU": { + "id": "KBDU", + "city": "Boulder Municipal Airport", + "state": "CO", + "lat": 40.0394297, + "lon": -105.2258217 + }, + "KBJC": { + "id": "KBJC", + "city": "Broomfield / Jeffco", + "state": "CO", + "lat": 39.90085, + "lon": -105.10417 + }, + "KBKF": { + "id": "KBKF", + "city": "Buckley Space Force Base", + "state": "CO", + "lat": 39.71331, + "lon": -104.75806 + }, + "KCAG": { + "id": "KCAG", + "city": "Craig-Moffat Airport", + "state": "CO", + "lat": 40.49297, + "lon": -107.52394 + }, + "KCCU": { + "id": "KCCU", + "city": "Copper Mountain - Red Cliff Pass", + "state": "CO", + "lat": 39.47523, + "lon": -106.15228 + }, + "KCEZ": { + "id": "KCEZ", + "city": "Cortez-Montezuma County Airport", + "state": "CO", + "lat": 37.30706, + "lon": -108.62644 + }, + "KCFO": { + "id": "KCFO", + "city": "Colorado Air and Space Port Airport", + "state": "CO", + "lat": 39.78419, + "lon": -104.53764 + }, + "KCOS": { + "id": "KCOS", + "city": "City of Colorado Springs Municipal Airport", + "state": "CO", + "lat": 38.8094899, + "lon": -104.68873 + }, + "KCPW": { + "id": "KCPW", + "city": "Pagosa Springs, Wolf Creek Pass", + "state": "CO", + "lat": 37.45139, + "lon": -106.80028 + }, + "KCWN": { + "id": "KCWN", + "city": "Cheyenne Mountain", + "state": "CO", + "lat": 38.7434299, + "lon": -104.84334 + }, + "KDEN": { + "id": "KDEN", + "city": "Denver, Denver International Airport", + "state": "CO", + "lat": 39.84658, + "lon": -104.65622 + }, + "KDRO": { + "id": "KDRO", + "city": "Durango-La Plata County Airport", + "state": "CO", + "lat": 37.14312, + "lon": -107.76023 + }, + "KEEO": { + "id": "KEEO", + "city": "Meeker Airport", + "state": "CO", + "lat": 40.0444, + "lon": -107.88832 + }, + "KEGE": { + "id": "KEGE", + "city": "Eagle County Regional", + "state": "CO", + "lat": 39.65, + "lon": -106.91667 + }, + "KEIK": { + "id": "KEIK", + "city": "Erie Municipal Airport", + "state": "CO", + "lat": 40.01169, + "lon": -105.05033 + }, + "KFCS": { + "id": "KFCS", + "city": "Butts Army Airfield (Fort Carson)", + "state": "CO", + "lat": 38.68312, + "lon": -104.75977 + }, + "KFLY": { + "id": "KFLY", + "city": "Meadow Lake Airport", + "state": "CO", + "lat": 38.94391, + "lon": -104.5684 + }, + "KFMM": { + "id": "KFMM", + "city": "Fort Morgan Municipal Airport", + "state": "CO", + "lat": 40.33148, + "lon": -103.80704 + }, + "KFNL": { + "id": "KFNL", + "city": "Fort Collins/Loveland - Northern Colorado Regional Airport", + "state": "CO", + "lat": 40.45, + "lon": -105.01667 + }, + "KGJT": { + "id": "KGJT", + "city": "Grand Junction Regional Airport", + "state": "CO", + "lat": 39.13389, + "lon": -108.53861 + }, + "KGNB": { + "id": "KGNB", + "city": "Granby-Grand County Airport", + "state": "CO", + "lat": 40.09006, + "lon": -105.91664 + }, + "KGUC": { + "id": "KGUC", + "city": "Gunnison, Gunnison-Crested Butte Regional Airport", + "state": "CO", + "lat": 38.53333, + "lon": -106.93333 + }, + "KGXY": { + "id": "KGXY", + "city": "Greeley, Greeley-Weld County Airport", + "state": "CO", + "lat": 40.43333, + "lon": -104.63333 + }, + "KHEQ": { + "id": "KHEQ", + "city": "Holyoke Airport", + "state": "CO", + "lat": 40.57155, + "lon": -102.27676 + }, + "KITR": { + "id": "KITR", + "city": "Burlington - Carson County Airport", + "state": "CO", + "lat": 39.24149, + "lon": -102.2818999 + }, + "KLAA": { + "id": "KLAA", + "city": "Lamar Municipal Airport", + "state": "CO", + "lat": 38.0717799, + "lon": -102.68745 + }, + "KLHX": { + "id": "KLHX", + "city": "La Junta Municipal Airport", + "state": "CO", + "lat": 38.04949, + "lon": -103.51334 + }, + "KLIC": { + "id": "KLIC", + "city": "Limon Municipal Airport", + "state": "CO", + "lat": 39.27334, + "lon": -103.66738 + }, + "KLMO": { + "id": "KLMO", + "city": "Vance Brand Airport", + "state": "CO", + "lat": 40.16115, + "lon": -105.16042 + }, + "KLXV": { + "id": "KLXV", + "city": "Leadville, Lake County Airport", + "state": "CO", + "lat": 39.22806, + "lon": -106.31611 + }, + "KMNH": { + "id": "KMNH", + "city": "Elbert Mountain - Monument Pass", + "state": "CO", + "lat": 39.22317, + "lon": -104.6422599 + }, + "KMTJ": { + "id": "KMTJ", + "city": "Montrose, Montrose Regional Airport", + "state": "CO", + "lat": 38.505, + "lon": -107.8975 + }, + "KMYP": { + "id": "KMYP", + "city": "Salida - Monarch Pass", + "state": "CO", + "lat": 38.4972, + "lon": -106.3197 + }, + "KPSO": { + "id": "KPSO", + "city": "Stevens Field, Pagosa Springs", + "state": "CO", + "lat": 37.2862, + "lon": -107.056 + }, + "KPUB": { + "id": "KPUB", + "city": "Pueblo Memorial Airport", + "state": "CO", + "lat": 38.28869, + "lon": -104.5057 + }, + "KRCV": { + "id": "KRCV", + "city": "Astronaut Kent Rominger - Del Norte", + "state": "CO", + "lat": 37.7138, + "lon": -106.352 + }, + "KRIL": { + "id": "KRIL", + "city": "Garfield County Regional Airport", + "state": "CO", + "lat": 39.52793, + "lon": -107.71961 + }, + "KSBS": { + "id": "KSBS", + "city": "Steamboat Springs", + "state": "CO", + "lat": 40.5153, + "lon": -106.86767 + }, + "KSHM": { + "id": "KSHM", + "city": "Schriever AFB", + "state": "CO", + "lat": 38.8, + "lon": -104.5167 + }, + "KSPD": { + "id": "KSPD", + "city": "Springfield, Comanche National Grassland", + "state": "CO", + "lat": 37.28333, + "lon": -102.61667 + }, + "KSTK": { + "id": "KSTK", + "city": "Sterling Municipal Airport", + "state": "CO", + "lat": 40.61331, + "lon": -103.26109 + }, + "KTAD": { + "id": "KTAD", + "city": "Perry Stokes Airport", + "state": "CO", + "lat": 37.26218, + "lon": -104.33184 + }, + "KTEX": { + "id": "KTEX", + "city": "Telluride, Telluride Regional Airport", + "state": "CO", + "lat": 37.95389, + "lon": -107.90861 + }, + "KVTP": { + "id": "KVTP", + "city": "La Veta Mountain, La Veta Pass", + "state": "CO", + "lat": 37.50111, + "lon": -105.16694 + }, + "PARW": { + "id": "PARW", + "city": "YAKIMA RIVER NEAR PARKER, WA.", + "state": "WA", + "lat": 46.5061111, + "lon": -120.4519444 + }, + "QSPW": { + "id": "QSPW", + "city": "QUARTZ MTN", + "state": "WA", + "lat": 47.0672222, + "lon": -121.0788888 + }, + "KABI": { + "id": "KABI", + "city": "Abilene, Abilene Regional Airport", + "state": "TX", + "lat": 32.41028, + "lon": -99.68167 + }, + "KACT": { + "id": "KACT", + "city": "Waco, Waco Regional Airport", + "state": "TX", + "lat": 31.61722, + "lon": -97.22778 + }, + "KADS": { + "id": "KADS", + "city": "Dallas / Addison Airport", + "state": "TX", + "lat": 32.96667, + "lon": -96.83333 + }, + "KAFW": { + "id": "KAFW", + "city": "Fort Worth, Fort Worth Alliance Airport", + "state": "TX", + "lat": 32.97333, + "lon": -97.31806 + }, + "KALI": { + "id": "KALI", + "city": "Alice, Alice International Airport", + "state": "TX", + "lat": 27.74111, + "lon": -98.02694 + }, + "KAMA": { + "id": "KAMA", + "city": "Amarillo, Amarillo International Airport", + "state": "TX", + "lat": 35.22, + "lon": -101.71722 + }, + "KAPY": { + "id": "KAPY", + "city": "Zapata, TX", + "state": "TX", + "lat": 26.969, + "lon": -99.249 + }, + "KAQO": { + "id": "KAQO", + "city": "Llano, Llano Municipal Airport", + "state": "TX", + "lat": 30.78361, + "lon": -98.66194 + }, + "KARM": { + "id": "KARM", + "city": "Wharton, Wharton Regional Airport", + "state": "TX", + "lat": 29.25417, + "lon": -96.1541699 + }, + "KASL": { + "id": "KASL", + "city": "Marshall", + "state": "TX", + "lat": 32.5205, + "lon": -94.3078 + }, + "KATT": { + "id": "KATT", + "city": "Austin City, Austin Camp Mabry", + "state": "TX", + "lat": 30.31667, + "lon": -97.76667 + }, + "KAUS": { + "id": "KAUS", + "city": "Austin-Bergstrom International Airport", + "state": "TX", + "lat": 30.18304, + "lon": -97.6798699 + }, + "KAXH": { + "id": "KAXH", + "city": "Houston Southwest Airport", + "state": "TX", + "lat": 29.50613, + "lon": -95.47692 + }, + "KBAZ": { + "id": "KBAZ", + "city": "New Braunfels National Airport", + "state": "TX", + "lat": 29.70575, + "lon": -98.04322 + }, + "KBBD": { + "id": "KBBD", + "city": "Brady, Curtis Field Airport", + "state": "TX", + "lat": 31.17917, + "lon": -99.32389 + }, + "KBEA": { + "id": "KBEA", + "city": "Beeville Municipal Airport", + "state": "TX", + "lat": 28.362, + "lon": -97.791 + }, + "KBGD": { + "id": "KBGD", + "city": "Borger, Hutchinson County Airport", + "state": "TX", + "lat": 35.695, + "lon": -101.395 + }, + "KBIF": { + "id": "KBIF", + "city": "Biggs Army Air Field - Fort Bliss", + "state": "TX", + "lat": 31.86119, + "lon": -106.3691599 + }, + "KBKD": { + "id": "KBKD", + "city": "Stephens County Airport", + "state": "TX", + "lat": 32.719, + "lon": -98.891 + }, + "KBKS": { + "id": "KBKS", + "city": "Falfurrias, Brooks County Airport", + "state": "TX", + "lat": 27.20667, + "lon": -98.12111 + }, + "KBMQ": { + "id": "KBMQ", + "city": "Burnet, Burnet Municipal Craddock Field", + "state": "TX", + "lat": 30.74056, + "lon": -98.23528 + }, + "KBMT": { + "id": "KBMT", + "city": "Beaumont Municipal Airport", + "state": "TX", + "lat": 30.0702, + "lon": -94.2151 + }, + "KBPC": { + "id": "KBPC", + "city": "Mesa Vista Ranch AP", + "state": "TX", + "lat": 35.889, + "lon": -101.03 + }, + "KBPG": { + "id": "KBPG", + "city": "Big Spring, Big Spring McMahon-Wrinkle Airport", + "state": "TX", + "lat": 32.2, + "lon": -101.51667 + }, + "KBPT": { + "id": "KBPT", + "city": "Beaumont/Port Arthur Southeast Texas Regional Airport", + "state": "TX", + "lat": 29.9521, + "lon": -94.0261 + }, + "KBQX": { + "id": "KBQX", + "city": "BRAZOS 451 OIL PLATFORM", + "state": "TX", + "lat": 28.5, + "lon": -95.72 + }, + "KBRO": { + "id": "KBRO", + "city": "Brownsville, Brownsville / South Padre Island International Airport", + "state": "TX", + "lat": 25.91417, + "lon": -97.42306 + }, + "KBWD": { + "id": "KBWD", + "city": "Brownwood, Brownwood Regional Airport", + "state": "TX", + "lat": 31.8, + "lon": -98.95 + }, + "KBYY": { + "id": "KBYY", + "city": "Bay City, Bay City Municipal Airport", + "state": "TX", + "lat": 28.97306, + "lon": -95.86333 + }, + "KCDS": { + "id": "KCDS", + "city": "Childress, Childress Municipal Airport", + "state": "TX", + "lat": 34.4275, + "lon": -100.28333 + }, + "KCFD": { + "id": "KCFD", + "city": "Bryan Coulter Field", + "state": "TX", + "lat": 30.7157, + "lon": -96.3314 + }, + "KCLL": { + "id": "KCLL", + "city": "College Station, Easterwood Field", + "state": "TX", + "lat": 30.58222, + "lon": -96.36167 + }, + "KCNW": { + "id": "KCNW", + "city": "Waco-James Connally Airport", + "state": "TX", + "lat": 31.6378, + "lon": -97.0741 + }, + "KCOM": { + "id": "KCOM", + "city": "COLEMAN", + "state": "TX", + "lat": 31.84, + "lon": -99.4 + }, + "KCOT": { + "id": "KCOT", + "city": "Cotulla, Cotulla-La Salle County Airport", + "state": "TX", + "lat": 28.45833, + "lon": -99.22028 + }, + "KCPT": { + "id": "KCPT", + "city": "Cleburne, Cleburne Municipal Airport", + "state": "TX", + "lat": 32.35361, + "lon": -97.43361 + }, + "KCRP": { + "id": "KCRP", + "city": "Corpus Christi, Corpus Christi International Airport", + "state": "TX", + "lat": 27.77306, + "lon": -97.51278 + }, + "KCRS": { + "id": "KCRS", + "city": "Corsicana, Campbell Field-Corsicana Municipal Airport", + "state": "TX", + "lat": 32.03111, + "lon": -96.39889 + }, + "KCVB": { + "id": "KCVB", + "city": "Castroville Municipal Airport", + "state": "TX", + "lat": 29.34192, + "lon": -98.8509 + }, + "KCWC": { + "id": "KCWC", + "city": "Kickapoo Downtown Airport", + "state": "TX", + "lat": 33.8606, + "lon": -98.4903999 + }, + "KCXO": { + "id": "KCXO", + "city": "Conroe, Montgomery County Airport", + "state": "TX", + "lat": 30.35667, + "lon": -95.41389 + }, + "KCZT": { + "id": "KCZT", + "city": "Carrizo Springs Dimmit County Airport", + "state": "TX", + "lat": 28.5222, + "lon": -99.8236 + }, + "KDAL": { + "id": "KDAL", + "city": "Dallas Love Field", + "state": "TX", + "lat": 32.85416, + "lon": -96.85506 + }, + "KDFW": { + "id": "KDFW", + "city": "Dallas/Fort Worth International Airport", + "state": "TX", + "lat": 32.89743, + "lon": -97.02196 + }, + "KDHT": { + "id": "KDHT", + "city": "Dalhart, Dalhart Municipal Airport", + "state": "TX", + "lat": 36.02333, + "lon": -102.54722 + }, + "KDKR": { + "id": "KDKR", + "city": "Crockett, Houston County Airport", + "state": "TX", + "lat": 31.30694, + "lon": -95.40361 + }, + "KDLF": { + "id": "KDLF", + "city": "Laughlin Air Force Base Auxiliary Airfield", + "state": "TX", + "lat": 29.36652, + "lon": -100.78469 + }, + "KDRT": { + "id": "KDRT", + "city": "Del Rio, Del Rio International Airport", + "state": "TX", + "lat": 29.37472, + "lon": -100.92361 + }, + "KDTO": { + "id": "KDTO", + "city": "Denton Enterprise Airport", + "state": "TX", + "lat": 33.20505, + "lon": -97.20061 + }, + "KDUX": { + "id": "KDUX", + "city": "Dumas, Moore County Airport", + "state": "TX", + "lat": 35.85778, + "lon": -102.01306 + }, + "KDWH": { + "id": "KDWH", + "city": "Houston, Hooks Memorial Airport", + "state": "TX", + "lat": 30.0675, + "lon": -95.55611 + }, + "KDYS": { + "id": "KDYS", + "city": "Abilene, Dyess Air Force Base", + "state": "TX", + "lat": 32.42, + "lon": -99.85694 + }, + "KDZB": { + "id": "KDZB", + "city": "Horseshoe Bay Resort Airpark", + "state": "TX", + "lat": 30.5271, + "lon": -98.3588 + }, + "KEBG": { + "id": "KEBG", + "city": "Edinburg, Edinburg International Airport", + "state": "TX", + "lat": 26.44194, + "lon": -98.12944 + }, + "KECU": { + "id": "KECU", + "city": "Rocksprings, Edwards County Airport", + "state": "TX", + "lat": 29.94667, + "lon": -100.17361 + }, + "KEDC": { + "id": "KEDC", + "city": "Austin Executive Airport", + "state": "TX", + "lat": 30.3925, + "lon": -97.5621 + }, + "KEFD": { + "id": "KEFD", + "city": "Houston / Ellington", + "state": "TX", + "lat": 29.6, + "lon": -95.16667 + }, + "KELA": { + "id": "KELA", + "city": "Eagle Lake", + "state": "TX", + "lat": 29.6006, + "lon": -96.3219 + }, + "KELP": { + "id": "KELP", + "city": "El Paso, El Paso International Airport", + "state": "TX", + "lat": 31.81111, + "lon": -106.3758299 + }, + "KERV": { + "id": "KERV", + "city": "Kerrville, Kerrville Municipal Airport/Louis Schreiner Field", + "state": "TX", + "lat": 29.96667, + "lon": -99.08333 + }, + "KETN": { + "id": "KETN", + "city": "Eastland Municipal Airport", + "state": "TX", + "lat": 32.41489, + "lon": -98.80969 + }, + "KFST": { + "id": "KFST", + "city": "Fort Stockton, Fort Stockton-Pecos County Airport", + "state": "TX", + "lat": 30.91194, + "lon": -102.91667 + }, + "KFTN": { + "id": "KFTN", + "city": "Faith Ranch Airport", + "state": "TX", + "lat": 28.2086, + "lon": -100.0188 + }, + "KFTW": { + "id": "KFTW", + "city": "Fort Worth, Meacham International Airport", + "state": "TX", + "lat": 32.82528, + "lon": -97.36417 + }, + "KFWS": { + "id": "KFWS", + "city": "Fort Worth Spinks Airport", + "state": "TX", + "lat": 32.56537, + "lon": -97.30837 + }, + "KGDJ": { + "id": "KGDJ", + "city": "Granbury, Granbury Municipal Airport", + "state": "TX", + "lat": 32.44417, + "lon": -97.81667 + }, + "KGGG": { + "id": "KGGG", + "city": "Longview - East Texas Regional Airport", + "state": "TX", + "lat": 32.39056, + "lon": -94.71389 + }, + "KGKY": { + "id": "KGKY", + "city": "Arlington Municipal Airport", + "state": "TX", + "lat": 32.65829, + "lon": -97.09509 + }, + "KGLS": { + "id": "KGLS", + "city": "Galveston, Scholes Field", + "state": "TX", + "lat": 29.27028, + "lon": -94.86417 + }, + "KGNC": { + "id": "KGNC", + "city": "Seminole, Gaines County Airport", + "state": "TX", + "lat": 32.67528, + "lon": -102.6525 + }, + "KGOP": { + "id": "KGOP", + "city": "Gatesville, City-County Airport", + "state": "TX", + "lat": 31.42111, + "lon": -97.79694 + }, + "KGPM": { + "id": "KGPM", + "city": "Grand Prairie, Grand Prairie Municipal Airport", + "state": "TX", + "lat": 32.69861, + "lon": -97.04667 + }, + "KGRK": { + "id": "KGRK", + "city": "Fort Hood, Robert Gray AAF Ft Hood", + "state": "TX", + "lat": 31.06667, + "lon": -97.81667 + }, + "KGTU": { + "id": "KGTU", + "city": "Georgetown, Georgetown Municipal Airport", + "state": "TX", + "lat": 30.68333, + "lon": -97.68333 + }, + "KGUL": { + "id": "KGUL", + "city": "GUNNISON OIL PLATFORM", + "state": "TX", + "lat": 27.3, + "lon": -93.53 + }, + "KGVT": { + "id": "KGVT", + "city": "Greenville / Majors", + "state": "TX", + "lat": 33.06667, + "lon": -96.06667 + }, + "KGVW": { + "id": "KGVW", + "city": "Galveston 209A", + "state": "TX", + "lat": 29.13, + "lon": -94.55 + }, + "KGYB": { + "id": "KGYB", + "city": "Giddings, Giddings-Lee County Airport", + "state": "TX", + "lat": 30.16917, + "lon": -96.98 + }, + "KGYI": { + "id": "KGYI", + "city": "Sherman/Denison, Grayson County Airport", + "state": "TX", + "lat": 33.71667, + "lon": -96.66667 + }, + "KGZN": { + "id": "KGZN", + "city": "Gregory M Simmons Memorial Airport", + "state": "TX", + "lat": 32.3658, + "lon": -99.0237 + }, + "KHDO": { + "id": "KHDO", + "city": "Hondo, Hondo Municipal Airport", + "state": "TX", + "lat": 29.35944, + "lon": -99.17417 + }, + "KHHF": { + "id": "KHHF", + "city": "Canadian, Hemphill County Airport", + "state": "TX", + "lat": 35.9, + "lon": -100.4 + }, + "KHHV": { + "id": "KHHV", + "city": "Alaminos Canyon 25/H-D (ExxonMobil)", + "state": "TX", + "lat": 26.939, + "lon": -94.6889999 + }, + "KHLR": { + "id": "KHLR", + "city": "Fort Hood, Hood AAF Ft Hood", + "state": "TX", + "lat": 31.13333, + "lon": -97.7 + }, + "KHOU": { + "id": "KHOU", + "city": "Houston, Houston Hobby Airport", + "state": "TX", + "lat": 29.6375, + "lon": -95.2825 + }, + "KHQZ": { + "id": "KHQZ", + "city": "Mesquite, Mesquite Metro Airport", + "state": "TX", + "lat": 32.74694, + "lon": -96.53028 + }, + "KHRL": { + "id": "KHRL", + "city": "Harlingen, Rio Grande Valley International Airport", + "state": "TX", + "lat": 26.22972, + "lon": -97.65528 + }, + "KHRX": { + "id": "KHRX", + "city": "Hereford Municipal Airport", + "state": "TX", + "lat": 34.8578, + "lon": -102.3264 + }, + "KHYI": { + "id": "KHYI", + "city": "San Marcos, San Marcos Municipal Airport", + "state": "TX", + "lat": 29.89361, + "lon": -97.86472 + }, + "KIAH": { + "id": "KIAH", + "city": "Houston Intercontinental Airport", + "state": "TX", + "lat": 29.9844, + "lon": -95.36074 + }, + "KIKG": { + "id": "KIKG", + "city": "Kleberg County Airport", + "state": "TX", + "lat": 27.5509, + "lon": -98.0309 + }, + "KILE": { + "id": "KILE", + "city": "Killeen, Skylark Field Airport", + "state": "TX", + "lat": 31.08333, + "lon": -97.68333 + }, + "KINJ": { + "id": "KINJ", + "city": "Hillsboro, Hillsboro Municipal Airport", + "state": "TX", + "lat": 32.0833299, + "lon": -97.0972199 + }, + "KINK": { + "id": "KINK", + "city": "Wink, Winkler County Airport", + "state": "TX", + "lat": 31.77972, + "lon": -103.20139 + }, + "KJAS": { + "id": "KJAS", + "city": "Jasper, Jasper County-Bell Field Airport", + "state": "TX", + "lat": 30.88556, + "lon": -94.0347199 + }, + "KJCT": { + "id": "KJCT", + "city": "Junction, Kimble County Airport", + "state": "TX", + "lat": 30.51083, + "lon": -99.76639 + }, + "KJDD": { + "id": "KJDD", + "city": "Mineola/Quitman, Wood County Airport", + "state": "TX", + "lat": 32.74194, + "lon": -95.49639 + }, + "KJSO": { + "id": "KJSO", + "city": "Jacksonville, Cherokee County Airport", + "state": "TX", + "lat": 31.86917, + "lon": -95.21722 + }, + "KJWY": { + "id": "KJWY", + "city": "Midlothian/Waxahachie, Mid-Way Regional Airport", + "state": "TX", + "lat": 32.45583, + "lon": -96.91222 + }, + "KJXI": { + "id": "KJXI", + "city": "Gilmer, Fox Stephens Field - Gilmer Municipal Airport", + "state": "TX", + "lat": 32.69889, + "lon": -94.94861 + }, + "KLBB": { + "id": "KLBB", + "city": "Lubbock, Lubbock International Airport", + "state": "TX", + "lat": 33.6674999, + "lon": -101.8213899 + }, + "KLFK": { + "id": "KLFK", + "city": "Lufkin, Angelina County Airport", + "state": "TX", + "lat": 31.23389, + "lon": -94.75 + }, + "KLHB": { + "id": "KLHB", + "city": "Hearne, Hearne Municipal Airport", + "state": "TX", + "lat": 30.87167, + "lon": -96.62222 + }, + "KLLN": { + "id": "KLLN", + "city": "Levelland Municipal Airport", + "state": "TX", + "lat": 33.55253, + "lon": -102.37253 + }, + "KLNC": { + "id": "KLNC", + "city": "Lancaster Airport", + "state": "TX", + "lat": 32.58323, + "lon": -96.72091 + }, + "KLRD": { + "id": "KLRD", + "city": "Laredo, Laredo International Airport", + "state": "TX", + "lat": 27.54361, + "lon": -99.46139 + }, + "KLUD": { + "id": "KLUD", + "city": "Decatur, Decatur Municipal Airport", + "state": "TX", + "lat": 33.25444, + "lon": -97.58056 + }, + "KLUV": { + "id": "KLUV", + "city": "Lamesa Municipal Airport", + "state": "TX", + "lat": 32.75631, + "lon": -101.92022 + }, + "KLVJ": { + "id": "KLVJ", + "city": "Houston, Pearland Regional Airport", + "state": "TX", + "lat": 29.52111, + "lon": -95.24194 + }, + "KLXY": { + "id": "KLXY", + "city": "Mexia Limestone County Airport", + "state": "TX", + "lat": 31.6412, + "lon": -96.5145 + }, + "KMAF": { + "id": "KMAF", + "city": "Midland, Midland International Airport", + "state": "TX", + "lat": 31.94778, + "lon": -102.2086099 + }, + "KMCJ": { + "id": "KMCJ", + "city": "John Dunn Helistop", + "state": "TX", + "lat": 29.714, + "lon": -95.395 + }, + "KMDD": { + "id": "KMDD", + "city": "Midland, Midland Airpark", + "state": "TX", + "lat": 32.03639, + "lon": -102.10083 + }, + "KMFE": { + "id": "KMFE", + "city": "McAllen, Miller International Airport", + "state": "TX", + "lat": 26.17972, + "lon": -98.24444 + }, + "KMKN": { + "id": "KMKN", + "city": "Comanche, Comanche County-City Airport", + "state": "TX", + "lat": 31.91667, + "lon": -98.60028 + }, + "KMNZ": { + "id": "KMNZ", + "city": "Hamilton Municipal Airport", + "state": "TX", + "lat": 31.6659, + "lon": -98.1486 + }, + "KMWL": { + "id": "KMWL", + "city": "Mineral Wells, Mineral Wells Airport", + "state": "TX", + "lat": 32.78167, + "lon": -98.06028 + }, + "KNFW": { + "id": "KNFW", + "city": "Fort Worth, Naval Air Station", + "state": "TX", + "lat": 32.76583, + "lon": -97.43333 + }, + "KNGP": { + "id": "KNGP", + "city": "Corpus Christi, Corpus Christi Naval Air Station/Truax Field", + "state": "TX", + "lat": 27.6925, + "lon": -97.29111 + }, + "KNOG": { + "id": "KNOG", + "city": "Orange Grove NALF", + "state": "TX", + "lat": 27.8947, + "lon": -98.0425099 + }, + "KNQI": { + "id": "KNQI", + "city": "Kingsville, Naval Air Station", + "state": "TX", + "lat": 27.50306, + "lon": -97.81167 + }, + "KOCH": { + "id": "KOCH", + "city": "Nacogdoches, A L Mangham Jr. Regional Airport", + "state": "TX", + "lat": 31.58333, + "lon": -94.7166699 + }, + "KODO": { + "id": "KODO", + "city": "Odessa, Odessa-Schlemeyer Field", + "state": "TX", + "lat": 31.92139, + "lon": -102.39167 + }, + "KORG": { + "id": "KORG", + "city": "Orange, Orange County Airport", + "state": "TX", + "lat": 30.06917, + "lon": -93.80361 + }, + "KOSA": { + "id": "KOSA", + "city": "Mount Pleasant, Mount Pleasant Regional Airport", + "state": "TX", + "lat": 33.09528, + "lon": -94.96139 + }, + "KOZA": { + "id": "KOZA", + "city": "Ozona Municipal Airport", + "state": "TX", + "lat": 30.7353, + "lon": -101.203 + }, + "KPEZ": { + "id": "KPEZ", + "city": "Pleasanton Municipal Airport", + "state": "TX", + "lat": 28.9562, + "lon": -98.5184 + }, + "KPIL": { + "id": "KPIL", + "city": "Port Isabel, Port Isabel-Cameron County Airport", + "state": "TX", + "lat": 26.15917, + "lon": -97.3375 + }, + "KPKV": { + "id": "KPKV", + "city": "Port Lavaca - Calhoun County Airport", + "state": "TX", + "lat": 28.65159, + "lon": -96.68196 + }, + "KPPA": { + "id": "KPPA", + "city": "Pampa, Perry Lefors Field Airport", + "state": "TX", + "lat": 35.61278, + "lon": -100.99611 + }, + "KPRS": { + "id": "KPRS", + "city": "Presidio Lely International Airport", + "state": "TX", + "lat": 29.6341, + "lon": -104.3616 + }, + "KPRX": { + "id": "KPRX", + "city": "Paris / Cox Field", + "state": "TX", + "lat": 33.63333, + "lon": -95.45 + }, + "KPSN": { + "id": "KPSN", + "city": "Palestine, Palestine Municipal Airport", + "state": "TX", + "lat": 31.77944, + "lon": -95.70611 + }, + "KPVW": { + "id": "KPVW", + "city": "Plainview, Hale County Airport", + "state": "TX", + "lat": 34.1680599, + "lon": -101.71722 + }, + "KPWG": { + "id": "KPWG", + "city": "Waco, Mc Gregor Executive Airport", + "state": "TX", + "lat": 31.48333, + "lon": -97.31667 + }, + "KPYX": { + "id": "KPYX", + "city": "Perryton, Perryton Ochiltree County Airport", + "state": "TX", + "lat": 36.4, + "lon": -100.73333 + }, + "KRAS": { + "id": "KRAS", + "city": "Port Aransas, Mustang Beach Airport", + "state": "TX", + "lat": 27.81167, + "lon": -97.08861 + }, + "KRBD": { + "id": "KRBD", + "city": "Dallas, Redbird Airport", + "state": "TX", + "lat": 32.67583, + "lon": -96.86389 + }, + "KRBO": { + "id": "KRBO", + "city": "Robstown, Nueces County Airport", + "state": "TX", + "lat": 27.77833, + "lon": -97.69028 + }, + "KRFI": { + "id": "KRFI", + "city": "Rusk County Airport", + "state": "TX", + "lat": 32.1417, + "lon": -94.8516999 + }, + "KRKP": { + "id": "KRKP", + "city": "Rockport Aransas County Airport", + "state": "TX", + "lat": 28.08371, + "lon": -97.04664 + }, + "KRND": { + "id": "KRND", + "city": "Randolph Air Force Base", + "state": "TX", + "lat": 29.53333, + "lon": -98.28333 + }, + "KRPH": { + "id": "KRPH", + "city": "Graham, Graham Municipal Airport", + "state": "TX", + "lat": 33.11, + "lon": -98.55528 + }, + "KRWV": { + "id": "KRWV", + "city": "Caldwell, Caldwell Municipal Airport", + "state": "TX", + "lat": 30.51528, + "lon": -96.70389 + }, + "KRYW": { + "id": "KRYW", + "city": "Lago Vista TX, Rusty Allen Airport", + "state": "TX", + "lat": 30.4967, + "lon": -97.9659 + }, + "KSAT": { + "id": "KSAT", + "city": "San Antonio, San Antonio International Airport", + "state": "TX", + "lat": 29.53278, + "lon": -98.46361 + }, + "KSEP": { + "id": "KSEP", + "city": "Stephenville, Clark Field Municipal Airport", + "state": "TX", + "lat": 32.21667, + "lon": -98.18333 + }, + "KSEQ": { + "id": "KSEQ", + "city": "Seguin - Randolph AFB Auxiliary Field", + "state": "TX", + "lat": 29.56579, + "lon": -97.90834 + }, + "KSGR": { + "id": "KSGR", + "city": "Houston, Sugar Land Municipal / Hull Field Airport", + "state": "TX", + "lat": 29.62222, + "lon": -95.65667 + }, + "KSHP": { + "id": "KSHP", + "city": "Sheppard Air Force Base", + "state": "TX", + "lat": 33.96667, + "lon": -98.48333 + }, + "KSJT": { + "id": "KSJT", + "city": "San Angelo, Mathis Field", + "state": "TX", + "lat": 31.35139, + "lon": -100.4938899 + }, + "KSKF": { + "id": "KSKF", + "city": "San Antonio - Kelly Field", + "state": "TX", + "lat": 29.38333, + "lon": -98.58333 + }, + "KSLR": { + "id": "KSLR", + "city": "Sulphur Springs, Sulphur Springs Municipal Airport", + "state": "TX", + "lat": 33.16111, + "lon": -95.62111 + }, + "KSNK": { + "id": "KSNK", + "city": "Snyder, Winston Field Airport", + "state": "TX", + "lat": 32.69333, + "lon": -100.95028 + }, + "KSOA": { + "id": "KSOA", + "city": "Sonora, Sonora Municipal Airport", + "state": "TX", + "lat": 30.58556, + "lon": -100.64833 + }, + "KSPS": { + "id": "KSPS", + "city": "Wichita Falls, Sheppard Air Force Base", + "state": "TX", + "lat": 33.97861, + "lon": -98.49278 + }, + "KSSF": { + "id": "KSSF", + "city": "San Antonio, Stinson Municipal Airport", + "state": "TX", + "lat": 29.33889, + "lon": -98.47167 + }, + "KSWW": { + "id": "KSWW", + "city": "Sweetwater, Avenger Field Airport", + "state": "TX", + "lat": 32.46722, + "lon": -100.46639 + }, + "KTFP": { + "id": "KTFP", + "city": "Mc Campbell", + "state": "TX", + "lat": 27.913, + "lon": -97.2115 + }, + "KTKI": { + "id": "KTKI", + "city": "McKinney - McKinney National Airport", + "state": "TX", + "lat": 33.17778, + "lon": -96.59028 + }, + "KTME": { + "id": "KTME", + "city": "Houston Executive Airport", + "state": "TX", + "lat": 29.80717, + "lon": -95.89791 + }, + "KTPL": { + "id": "KTPL", + "city": "Temple, Draughon-Miller Central Texas Regional Airport", + "state": "TX", + "lat": 31.15, + "lon": -97.4 + }, + "KTRL": { + "id": "KTRL", + "city": "Terrell, Terrell Municipal Airport", + "state": "TX", + "lat": 32.71361, + "lon": -96.26833 + }, + "KTXW": { + "id": "KTXW", + "city": "Mid Valley Airport", + "state": "TX", + "lat": 26.17871, + "lon": -97.97401 + }, + "KTYR": { + "id": "KTYR", + "city": "Tyler, Tyler Pounds Field", + "state": "TX", + "lat": 32.35861, + "lon": -95.40389 + }, + "KUTS": { + "id": "KUTS", + "city": "Huntsville, Huntsville Municipal Airport", + "state": "TX", + "lat": 30.74389, + "lon": -95.58611 + }, + "KUVA": { + "id": "KUVA", + "city": "Uvalde, Garner Field Airport", + "state": "TX", + "lat": 29.21111, + "lon": -99.74333 + }, + "KVAF": { + "id": "KVAF", + "city": "East Breaks 643/Boomvang Spar", + "state": "TX", + "lat": 27.354, + "lon": -94.625 + }, + "KVCT": { + "id": "KVCT", + "city": "Victoria, Victoria Regional Airport", + "state": "TX", + "lat": 28.8625, + "lon": -96.92972 + }, + "KVHN": { + "id": "KVHN", + "city": "Culberson County Airport", + "state": "TX", + "lat": 31.05783, + "lon": -104.78381 + }, + "KXBP": { + "id": "KXBP", + "city": "Bridgeport, Bridgeport Municipal Airport", + "state": "TX", + "lat": 33.17528, + "lon": -97.8283299 + }, + "KAST": { + "id": "KAST", + "city": "Astoria, Astoria Regional Airport", + "state": "OR", + "lat": 46.15694, + "lon": -123.8825 + }, + "KBDN": { + "id": "KBDN", + "city": "Bend Airport AWOS", + "state": "OR", + "lat": 44.0948, + "lon": -121.2006 + }, + "KBKE": { + "id": "KBKE", + "city": "Baker Municipal Airport", + "state": "OR", + "lat": 44.84302, + "lon": -117.80987 + }, + "KBNO": { + "id": "KBNO", + "city": "Burns Municipal Airport", + "state": "OR", + "lat": 43.59488, + "lon": -118.95791 + }, + "KBOK": { + "id": "KBOK", + "city": "Brookings, Brookings Airport", + "state": "OR", + "lat": 42.07444, + "lon": -124.29 + }, + "KCVO": { + "id": "KCVO", + "city": "Corvallis, Corvallis Municipal Airport", + "state": "OR", + "lat": 44.5, + "lon": -123.28333 + }, + "KEUG": { + "id": "KEUG", + "city": "Eugene, Mahlon Sweet Field", + "state": "OR", + "lat": 44.13333, + "lon": -123.21444 + }, + "KGCD": { + "id": "KGCD", + "city": "Grant County Regional Airport", + "state": "OR", + "lat": 44.40287, + "lon": -118.96715 + }, + "KHIO": { + "id": "KHIO", + "city": "Portland-Hillsboro Airport", + "state": "OR", + "lat": 45.54765, + "lon": -122.95568 + }, + "KHRI": { + "id": "KHRI", + "city": "Hermiston, Hermiston Municipal Airport", + "state": "OR", + "lat": 45.82583, + "lon": -119.26111 + }, + "KJSY": { + "id": "KJSY", + "city": "Joseph State Airport AWOS", + "state": "OR", + "lat": 45.355889, + "lon": -117.254083 + }, + "KLGD": { + "id": "KLGD", + "city": "La Grande/Union County Airport", + "state": "OR", + "lat": 45.29066, + "lon": -118.00884 + }, + "KLKV": { + "id": "KLKV", + "city": "Lake County Airport", + "state": "OR", + "lat": 42.15664, + "lon": -120.39721 + }, + "KLMT": { + "id": "KLMT", + "city": "Klamath Falls International Airport", + "state": "OR", + "lat": 42.14703, + "lon": -121.72548 + }, + "KMEH": { + "id": "KMEH", + "city": "Meacham", + "state": "OR", + "lat": 45.51176, + "lon": -118.42466 + }, + "KMFR": { + "id": "KMFR", + "city": "Rogue Valley International Airport", + "state": "OR", + "lat": 42.37503, + "lon": -122.87696 + }, + "KMMV": { + "id": "KMMV", + "city": "McMinnville, McMinnville Municipal Airport", + "state": "OR", + "lat": 45.19611, + "lon": -123.13222 + }, + "KONO": { + "id": "KONO", + "city": "Ontario Municipal Airport", + "state": "OR", + "lat": 44.01424, + "lon": -117.00808 + }, + "KONP": { + "id": "KONP", + "city": "Newport, Newport Municipal Airport", + "state": "OR", + "lat": 44.58028, + "lon": -124.05806 + }, + "KOTH": { + "id": "KOTH", + "city": "Southwest Oregon Regional Airport", + "state": "OR", + "lat": 43.41948, + "lon": -124.2437 + }, + "KPDT": { + "id": "KPDT", + "city": "Eastern Oregon Regional Airport at Pendleton", + "state": "OR", + "lat": 45.69757, + "lon": -118.83444 + }, + "KPDX": { + "id": "KPDX", + "city": "Portland, Portland International Airport", + "state": "OR", + "lat": 45.59578, + "lon": -122.60917 + }, + "KRBG": { + "id": "KRBG", + "city": "Roseburg Regional Airport", + "state": "OR", + "lat": 43.23368, + "lon": -123.3577 + }, + "KRDM": { + "id": "KRDM", + "city": "Redmond Roberts Field", + "state": "OR", + "lat": 44.25588, + "lon": -121.14059 + }, + "KREO": { + "id": "KREO", + "city": "Rome State Airport", + "state": "OR", + "lat": 42.57766, + "lon": -117.88543 + }, + "KSLE": { + "id": "KSLE", + "city": "Salem - McNary Field", + "state": "OR", + "lat": 44.90493, + "lon": -123.00096 + }, + "KSPB": { + "id": "KSPB", + "city": "Scappoose Industrial Airpark", + "state": "OR", + "lat": 45.7691, + "lon": -122.86365 + }, + "KSXT": { + "id": "KSXT", + "city": "Sexton Summit", + "state": "OR", + "lat": 42.6, + "lon": -123.3656 + }, + "KTMK": { + "id": "KTMK", + "city": "Tillamook, Tillamook Airport", + "state": "OR", + "lat": 45.4180599, + "lon": -123.81444 + }, + "KTTD": { + "id": "KTTD", + "city": "Portland, Portland-Troutdale Airport", + "state": "OR", + "lat": 45.55111, + "lon": -122.40889 + }, + "KUAO": { + "id": "KUAO", + "city": "Aurora State Airport", + "state": "OR", + "lat": 45.24658, + "lon": -122.77095 + }, + "KAAT": { + "id": "KAAT", + "city": "Alturas", + "state": "CA", + "lat": 41.48362, + "lon": -120.5615 + }, + "KACV": { + "id": "KACV", + "city": "Arcata / Eureka, Arcata Airport", + "state": "CA", + "lat": 40.97806, + "lon": -124.10861 + }, + "KAJO": { + "id": "KAJO", + "city": "Corona Airport", + "state": "CA", + "lat": 33.8977, + "lon": -117.6024 + }, + "KAPC": { + "id": "KAPC", + "city": "Napa, Napa County Airport", + "state": "CA", + "lat": 38.2075, + "lon": -122.27944 + }, + "KAPV": { + "id": "KAPV", + "city": "APPLEVALLEY", + "state": "CA", + "lat": 34.57533, + "lon": -117.18619 + }, + "KAUN": { + "id": "KAUN", + "city": "Auburn Municipal Airport", + "state": "CA", + "lat": 38.95535, + "lon": -121.08636 + }, + "KAVX": { + "id": "KAVX", + "city": "Avalon Catalina Airport", + "state": "CA", + "lat": 33.40421, + "lon": -118.41456 + }, + "KBAB": { + "id": "KBAB", + "city": "Marysville, Beale Air Force Base", + "state": "CA", + "lat": 39.13333, + "lon": -121.43333 + }, + "KBAN": { + "id": "KBAN", + "city": "MCMWTC BRIDGEPORT", + "state": "CA", + "lat": 38.3557, + "lon": -119.5188 + }, + "KBFL": { + "id": "KBFL", + "city": "Bakersfield, Meadows Field Airport", + "state": "CA", + "lat": 35.43361, + "lon": -119.05667 + }, + "KBIH": { + "id": "KBIH", + "city": "Bishop, Bishop Airport", + "state": "CA", + "lat": 37.37111, + "lon": -118.35806 + }, + "KBLH": { + "id": "KBLH", + "city": "Blythe, Blythe Airport", + "state": "CA", + "lat": 33.6191699, + "lon": -114.71694 + }, + "KBLU": { + "id": "KBLU", + "city": "Emigrant Gap, Blue Canyon Nyack Airport", + "state": "CA", + "lat": 39.27611, + "lon": -120.70806 + }, + "KBUR": { + "id": "KBUR", + "city": "Burbank - Bob Hope Airport", + "state": "CA", + "lat": 34.19967, + "lon": -118.36538 + }, + "KBYS": { + "id": "KBYS", + "city": "Fort Irwin/Barstow, Bicycle Lake Army Airfield", + "state": "CA", + "lat": 35.28333, + "lon": -116.61667 + }, + "KCCB": { + "id": "KCCB", + "city": "Cable Airport", + "state": "CA", + "lat": 34.11161, + "lon": -117.68739 + }, + "KCCR": { + "id": "KCCR", + "city": "Concord, Buchanan Field", + "state": "CA", + "lat": 37.99167, + "lon": -122.05194 + }, + "KCEC": { + "id": "KCEC", + "city": "Crescent City, Jack McNamara Field Airport", + "state": "CA", + "lat": 41.78028, + "lon": -124.23667 + }, + "KCIC": { + "id": "KCIC", + "city": "Chico Municipal Airport", + "state": "CA", + "lat": 39.7987899, + "lon": -121.85795 + }, + "KCMA": { + "id": "KCMA", + "city": "Camarillo, Camarillo Airport", + "state": "CA", + "lat": 34.21667, + "lon": -119.08333 + }, + "KCNO": { + "id": "KCNO", + "city": "Chino, Chino Airport", + "state": "CA", + "lat": 33.97556, + "lon": -117.62361 + }, + "KCPU": { + "id": "KCPU", + "city": "San Andreas Calaveras County Airport", + "state": "CA", + "lat": 38.1460999, + "lon": -120.6482 + }, + "KCRQ": { + "id": "KCRQ", + "city": "Carlsbad, McClellan-Palomar Airport", + "state": "CA", + "lat": 33.13, + "lon": -117.27583 + }, + "KCVH": { + "id": "KCVH", + "city": "Hollister, CA", + "state": "CA", + "lat": 36.8933, + "lon": -121.4103 + }, + "KDAG": { + "id": "KDAG", + "city": "Daggett, Barstow-Daggett Airport", + "state": "CA", + "lat": 34.85361, + "lon": -116.78667 + }, + "KDLO": { + "id": "KDLO", + "city": "Delano Municipal Airport", + "state": "CA", + "lat": 35.74556, + "lon": -119.2365 + }, + "KDVO": { + "id": "KDVO", + "city": "Novato / Gnoss Field", + "state": "CA", + "lat": 38.14178, + "lon": -122.55463 + }, + "KDWA": { + "id": "KDWA", + "city": "Yolo County Airport", + "state": "CA", + "lat": 38.5793899, + "lon": -121.85694 + }, + "KEDU": { + "id": "KEDU", + "city": "University Airport", + "state": "CA", + "lat": 38.5315, + "lon": -121.7865 + }, + "KEDW": { + "id": "KEDW", + "city": "Edwards Air Force Base", + "state": "CA", + "lat": 34.918, + "lon": -117.879 + }, + "KEED": { + "id": "KEED", + "city": "Needles, Needles Airport", + "state": "CA", + "lat": 34.76611, + "lon": -114.62333 + }, + "KEMT": { + "id": "KEMT", + "city": "El Monte", + "state": "CA", + "lat": 34.0833299, + "lon": -118.03333 + }, + "KFAT": { + "id": "KFAT", + "city": "Fresno, Fresno Air Terminal", + "state": "CA", + "lat": 36.78, + "lon": -119.71944 + }, + "KFOT": { + "id": "KFOT", + "city": "Fortuna Rohnerville Airport", + "state": "CA", + "lat": 40.55296, + "lon": -124.13338 + }, + "KFUL": { + "id": "KFUL", + "city": "Fullerton, Fullerton Municipal Airport", + "state": "CA", + "lat": 33.87194, + "lon": -117.98472 + }, + "KGOO": { + "id": "KGOO", + "city": "Nevada County Air Park", + "state": "CA", + "lat": 39.2240279, + "lon": -121.003083 + }, + "KHAF": { + "id": "KHAF", + "city": "Half Moon Bay Airport", + "state": "CA", + "lat": 37.5135999, + "lon": -122.4996 + }, + "KHHR": { + "id": "KHHR", + "city": "Hawthorne, Hawthorne Municipal Airport", + "state": "CA", + "lat": 33.9236099, + "lon": -118.33194 + }, + "KHJO": { + "id": "KHJO", + "city": "Hanford Municipal Airport", + "state": "CA", + "lat": 36.31145, + "lon": -119.62315 + }, + "KHMT": { + "id": "KHMT", + "city": "Hemet-Ryan Airport", + "state": "CA", + "lat": 33.73403, + "lon": -117.02231 + }, + "KHWD": { + "id": "KHWD", + "city": "Hayward, Hayward Air Terminal", + "state": "CA", + "lat": 37.66083, + "lon": -122.11833 + }, + "KIPL": { + "id": "KIPL", + "city": "Imperial, Imperial County Airport", + "state": "CA", + "lat": 32.83417, + "lon": -115.57861 + }, + "KIZA": { + "id": "KIZA", + "city": "Santa Ynez, Santa Ynez Airport", + "state": "CA", + "lat": 34.60694, + "lon": -120.07556 + }, + "KJAQ": { + "id": "KJAQ", + "city": "Westover Field - Amador County Airport", + "state": "CA", + "lat": 38.3768, + "lon": -120.79391 + }, + "KLAX": { + "id": "KLAX", + "city": "Los Angeles, Los Angeles International Airport", + "state": "CA", + "lat": 33.93806, + "lon": -118.38889 + }, + "KLGB": { + "id": "KLGB", + "city": "Long Beach, Long Beach Airport", + "state": "CA", + "lat": 33.81167, + "lon": -118.14639 + }, + "KLHM": { + "id": "KLHM", + "city": "Lincoln Regional Karl Harder Field", + "state": "CA", + "lat": 38.9092, + "lon": -121.3513 + }, + "KLPC": { + "id": "KLPC", + "city": "Lompoc, Lompoc Airport", + "state": "CA", + "lat": 34.66667, + "lon": -120.46667 + }, + "KLVK": { + "id": "KLVK", + "city": "Livermore, Livermore Municipal Airport", + "state": "CA", + "lat": 37.69278, + "lon": -121.81444 + }, + "KMAE": { + "id": "KMAE", + "city": "Madera Municipal Airport", + "state": "CA", + "lat": 36.9851, + "lon": -120.11064 + }, + "KMCC": { + "id": "KMCC", + "city": "Sacramento, McClellan Airfield Airport", + "state": "CA", + "lat": 38.66667, + "lon": -121.4 + }, + "KMCE": { + "id": "KMCE", + "city": "Merced Regional Airport", + "state": "CA", + "lat": 37.28306, + "lon": -120.50778 + }, + "KMHR": { + "id": "KMHR", + "city": "Sacramento Mather Airport", + "state": "CA", + "lat": 38.5599599, + "lon": -121.28397 + }, + "KMHS": { + "id": "KMHS", + "city": "Mount Shasta", + "state": "CA", + "lat": 41.31494, + "lon": -122.31702 + }, + "KMHV": { + "id": "KMHV", + "city": "Mojave", + "state": "CA", + "lat": 35.06667, + "lon": -118.15 + }, + "KMMH": { + "id": "KMMH", + "city": "Mammoth Yosemite Airport", + "state": "CA", + "lat": 37.6241, + "lon": -118.8423 + }, + "KMOD": { + "id": "KMOD", + "city": "Modesto City-County Airport - Harry Sham Field", + "state": "CA", + "lat": 37.62549, + "lon": -120.9549 + }, + "KMRY": { + "id": "KMRY", + "city": "Monterey Regional Airport", + "state": "CA", + "lat": 36.59047, + "lon": -121.84875 + }, + "KMWS": { + "id": "KMWS", + "city": "MOUNT WILSON", + "state": "CA", + "lat": 34.22, + "lon": -118.07 + }, + "KMYF": { + "id": "KMYF", + "city": "San Diego, Montgomery Field", + "state": "CA", + "lat": 32.81444, + "lon": -117.13639 + }, + "KMYV": { + "id": "KMYV", + "city": "Marysville, Yuba County Airport", + "state": "CA", + "lat": 39.09778, + "lon": -121.56972 + }, + "KNFG": { + "id": "KNFG", + "city": "Oceanside, Camp Pendleton, Marine Corps Air Station", + "state": "CA", + "lat": 33.30472, + "lon": -117.35389 + }, + "KNID": { + "id": "KNID", + "city": "China Lake, Naval Air Facility", + "state": "CA", + "lat": 35.68639, + "lon": -117.69 + }, + "KNJK": { + "id": "KNJK", + "city": "El Centro, Naval Air Facility", + "state": "CA", + "lat": 32.825, + "lon": -115.66056 + }, + "KNKX": { + "id": "KNKX", + "city": "San Diego, Miramar MCAS/Mitscher Field Airport", + "state": "CA", + "lat": 32.86833, + "lon": -117.1425 + }, + "KNLC": { + "id": "KNLC", + "city": "Lemoore Naval Air Station - Reeves Field", + "state": "CA", + "lat": 36.30244, + "lon": -119.93968 + }, + "KNRS": { + "id": "KNRS", + "city": "Imperial Beach Naval Outlying Field - Ream Field", + "state": "CA", + "lat": 32.56302, + "lon": -117.11091 + }, + "KNSI": { + "id": "KNSI", + "city": "San Nicolas Island Naval Outlying Field", + "state": "CA", + "lat": 33.23379, + "lon": -119.45588 + }, + "KNTD": { + "id": "KNTD", + "city": "Point Mugu, Naval Air Warfare Center", + "state": "CA", + "lat": 34.12389, + "lon": -119.12167 + }, + "KNUC": { + "id": "KNUC", + "city": "San Clemente Island NALF", + "state": "CA", + "lat": 33.0218, + "lon": -118.58266 + }, + "KNUQ": { + "id": "KNUQ", + "city": "Mountain View, Moffett Field", + "state": "CA", + "lat": 37.40583, + "lon": -122.04806 + }, + "KNXP": { + "id": "KNXP", + "city": "Twentynine Palms SELF Airport", + "state": "CA", + "lat": 34.29401, + "lon": -116.14717 + }, + "KNZY": { + "id": "KNZY", + "city": "San Diego, North Island, Naval Air Station", + "state": "CA", + "lat": 32.69083, + "lon": -117.20889 + }, + "KOAK": { + "id": "KOAK", + "city": "San Francisco Bay Oakland International Airport", + "state": "CA", + "lat": 37.72126, + "lon": -122.22115 + }, + "KOAR": { + "id": "KOAR", + "city": "FORT ORD/FRITZSCHE", + "state": "CA", + "lat": 36.68, + "lon": -121.77 + }, + "KOKB": { + "id": "KOKB", + "city": "Oceanside, Oceanside Municipal Airport", + "state": "CA", + "lat": 33.21806, + "lon": -117.35139 + }, + "KONT": { + "id": "KONT", + "city": "Ontario International Airport", + "state": "CA", + "lat": 34.05316, + "lon": -117.57685 + }, + "KOVE": { + "id": "KOVE", + "city": "Oroville Municipal Airport", + "state": "CA", + "lat": 39.49436, + "lon": -121.62223 + }, + "KOXR": { + "id": "KOXR", + "city": "Oxnard, Oxnard Airport", + "state": "CA", + "lat": 34.20056, + "lon": -119.20306 + }, + "KPAO": { + "id": "KPAO", + "city": "Palo Alto Airport", + "state": "CA", + "lat": 37.46667, + "lon": -122.11667 + }, + "KPMD": { + "id": "KPMD", + "city": "Palmdale, Palmdale Production Flight Plant", + "state": "CA", + "lat": 34.62972, + "lon": -118.08139 + }, + "KPOC": { + "id": "KPOC", + "city": "Brackett Field Airport", + "state": "CA", + "lat": 34.09282, + "lon": -117.77937 + }, + "KPRB": { + "id": "KPRB", + "city": "Paso Robles Municipal Airport", + "state": "CA", + "lat": 35.66941, + "lon": -120.62912 + }, + "KPSP": { + "id": "KPSP", + "city": "Palm Springs Regional Airport", + "state": "CA", + "lat": 33.82219, + "lon": -116.50431 + }, + "KPTV": { + "id": "KPTV", + "city": "Porterville, Porterville Municipal Airport", + "state": "CA", + "lat": 36.03333, + "lon": -119.06667 + }, + "KPVF": { + "id": "KPVF", + "city": "Placerville Airport", + "state": "CA", + "lat": 38.7242, + "lon": -120.7533 + }, + "KRAL": { + "id": "KRAL", + "city": "Riverside Municipal Airport", + "state": "CA", + "lat": 33.95189, + "lon": -117.44511 + }, + "KRBL": { + "id": "KRBL", + "city": "Red Bluff, Red Bluff Municipal Airport", + "state": "CA", + "lat": 40.15056, + "lon": -122.25222 + }, + "KRDD": { + "id": "KRDD", + "city": "Redding Municipal Airport", + "state": "CA", + "lat": 40.51461, + "lon": -122.2977 + }, + "KREI": { + "id": "KREI", + "city": "REDLANDS", + "state": "CA", + "lat": 34.08526, + "lon": -117.14637 + }, + "KRHV": { + "id": "KRHV", + "city": "San Jose / Reid / Hillv", + "state": "CA", + "lat": 37.3333299, + "lon": -121.81667 + }, + "KRIV": { + "id": "KRIV", + "city": "March Air Reserve Base", + "state": "CA", + "lat": 33.88194, + "lon": -117.25902 + }, + "KRNM": { + "id": "KRNM", + "city": "Ramona, Ramona Airport", + "state": "CA", + "lat": 33.0375, + "lon": -116.91583 + }, + "KSAC": { + "id": "KSAC", + "city": "Sacramento Executive Airport", + "state": "CA", + "lat": 38.50674, + "lon": -121.49597 + }, + "KSAN": { + "id": "KSAN", + "city": "San Diego International Airport", + "state": "CA", + "lat": 32.73361, + "lon": -117.18306 + }, + "KSBA": { + "id": "KSBA", + "city": "Santa Barbara, Santa Barbara Municipal Airport", + "state": "CA", + "lat": 34.42611, + "lon": -119.84361 + }, + "KSBD": { + "id": "KSBD", + "city": "San Bernardino Intl. Airport", + "state": "CA", + "lat": 34.0902699, + "lon": -117.24705 + }, + "KSBP": { + "id": "KSBP", + "city": "San Luis Obispo, San Luis Obispo County-Mc Chesney Field", + "state": "CA", + "lat": 35.2361099, + "lon": -120.63611 + }, + "KSCK": { + "id": "KSCK", + "city": "Stockton, Stockton Metropolitan Airport", + "state": "CA", + "lat": 37.8897199, + "lon": -121.22361 + }, + "KSDB": { + "id": "KSDB", + "city": "Sandberg", + "state": "CA", + "lat": 34.7436099, + "lon": -118.72444 + }, + "KSDM": { + "id": "KSDM", + "city": "San Diego, Brown Field Municipal Airport", + "state": "CA", + "lat": 32.57528, + "lon": -116.99306 + }, + "KSEE": { + "id": "KSEE", + "city": "Gillespie Field Airport", + "state": "CA", + "lat": 32.82738, + "lon": -116.97369 + }, + "KSFO": { + "id": "KSFO", + "city": "San Francisco, San Francisco International Airport", + "state": "CA", + "lat": 37.61961, + "lon": -122.36558 + }, + "KSIY": { + "id": "KSIY", + "city": "Montague Siskiyou County Airport", + "state": "CA", + "lat": 41.77375, + "lon": -122.46817 + }, + "KSJC": { + "id": "KSJC", + "city": "San Jose, San Jose International Airport", + "state": "CA", + "lat": 37.35917, + "lon": -121.92417 + }, + "KSLI": { + "id": "KSLI", + "city": "Los Alamitos Army Airfield", + "state": "CA", + "lat": 33.79628, + "lon": -118.04179 + }, + "KSMF": { + "id": "KSMF", + "city": "Sacramento International Airport", + "state": "CA", + "lat": 38.70071, + "lon": -121.59479 + }, + "KSMO": { + "id": "KSMO", + "city": "Santa Monica, Santa Monica Municipal Airport", + "state": "CA", + "lat": 34.01583, + "lon": -118.45139 + }, + "KSMX": { + "id": "KSMX", + "city": "Santa Maria Public Airport/Capt G Allan Hancock Field", + "state": "CA", + "lat": 34.89408, + "lon": -120.45212 + }, + "KSNA": { + "id": "KSNA", + "city": "John Wayne-Orange County Airport", + "state": "CA", + "lat": 33.6798, + "lon": -117.8674 + }, + "KSNS": { + "id": "KSNS", + "city": "Salinas, Salinas Municipal Airport", + "state": "CA", + "lat": 36.66361, + "lon": -121.60806 + }, + "KSQL": { + "id": "KSQL", + "city": "San Carlos Airport", + "state": "CA", + "lat": 37.51667, + "lon": -122.25 + }, + "KSTS": { + "id": "KSTS", + "city": "Santa Rosa, Santa Rosa Sonoma County Airport", + "state": "CA", + "lat": 38.5, + "lon": -122.81667 + }, + "KSUU": { + "id": "KSUU", + "city": "Fairfield / Travis Air Force Base", + "state": "CA", + "lat": 38.26667, + "lon": -121.95 + }, + "KSVE": { + "id": "KSVE", + "city": "Susanville Municipal Airport", + "state": "CA", + "lat": 40.37569, + "lon": -120.57269 + }, + "KTCY": { + "id": "KTCY", + "city": "Tracy Municipal Airport", + "state": "CA", + "lat": 37.6888999, + "lon": -121.44158 + }, + "KTOA": { + "id": "KTOA", + "city": "Torrance, Zamperini Field Airport", + "state": "CA", + "lat": 33.8, + "lon": -118.33333 + }, + "KTQS": { + "id": "KTQS", + "city": "Vandenberg SFB - South", + "state": "CA", + "lat": 34.633, + "lon": -120.617 + }, + "KTRK": { + "id": "KTRK", + "city": "Truckee-Tahoe", + "state": "CA", + "lat": 39.31667, + "lon": -120.13333 + }, + "KTRM": { + "id": "KTRM", + "city": "Palm Springs, Jacqueline Cochran Regional Airport", + "state": "CA", + "lat": 33.62667, + "lon": -116.15944 + }, + "KTSP": { + "id": "KTSP", + "city": "Tehachapi Municipal Airport", + "state": "CA", + "lat": 35.135, + "lon": -118.4392 + }, + "KTVL": { + "id": "KTVL", + "city": "South Lake Tahoe, Lake Tahoe Airport", + "state": "CA", + "lat": 38.8983599, + "lon": -119.99615 + }, + "KUKI": { + "id": "KUKI", + "city": "Ukiah Municipal Airport", + "state": "CA", + "lat": 39.12783, + "lon": -123.20011 + }, + "KVBG": { + "id": "KVBG", + "city": "Vandenberg Space Force Base", + "state": "CA", + "lat": 34.7294399, + "lon": -120.57667 + }, + "KVCB": { + "id": "KVCB", + "city": "Vacaville Nut Tree Airport", + "state": "CA", + "lat": 38.37755, + "lon": -121.95853 + }, + "KVCV": { + "id": "KVCV", + "city": "Victorville, Southern California Logistics Airport", + "state": "CA", + "lat": 34.59722, + "lon": -117.38278 + }, + "KVIS": { + "id": "KVIS", + "city": "Visalia, Visalia Municipal Airport", + "state": "CA", + "lat": 36.31667, + "lon": -119.4 + }, + "KVNY": { + "id": "KVNY", + "city": "Van Nuys, Van Nuys Airport", + "state": "CA", + "lat": 34.2125, + "lon": -118.49083 + }, + "KWHP": { + "id": "KWHP", + "city": "Los Angeles, Whiteman Airport", + "state": "CA", + "lat": 34.25, + "lon": -118.4 + }, + "KWJF": { + "id": "KWJF", + "city": "General Wm J Fox Airfield", + "state": "CA", + "lat": 34.74123, + "lon": -118.21251 + }, + "KWVI": { + "id": "KWVI", + "city": "Watsonville, Watsonville Municipal Airport", + "state": "CA", + "lat": 36.93944, + "lon": -121.78889 + }, + "PARO": { + "id": "PARO", + "city": "PARKDALE", + "state": "OR", + "lat": 45.54444, + "lon": -121.61667 + }, + "PCYO": { + "id": "PCYO", + "city": "PRARIE CITY", + "state": "OR", + "lat": 44.44083, + "lon": -118.62778 + }, + "PDTO": { + "id": "PDTO", + "city": "Umatilla River at Pendleton, OR", + "state": "OR", + "lat": 45.6722222, + "lon": -118.7916666 + }, + "PILO": { + "id": "PILO", + "city": "Pilot Rock 11E, OR", + "state": "OR", + "lat": 45.5019444, + "lon": -118.6205555 + }, + "PNGO": { + "id": "PNGO", + "city": "PINEGROVE", + "state": "OR", + "lat": 45.65222, + "lon": -121.50917 + }, + "POBO": { + "id": "POBO", + "city": "POWELL BUTTE", + "state": "OR", + "lat": 44.24833, + "lon": -120.94972 + }, + "PRHO": { + "id": "PRHO", + "city": "Powder River at Hudspeth Lane near Sumpter, OR", + "state": "OR", + "lat": 44.6861111, + "lon": -118.1 + }, + "PRIO": { + "id": "PRIO", + "city": "Prineville 4NW, OR", + "state": "OR", + "lat": 44.3691666, + "lon": -120.9377777 + }, + "PRVO": { + "id": "PRVO", + "city": "Crooked River near Prineville, OR", + "state": "OR", + "lat": 44.1138888, + "lon": -120.7944444 + }, + "PWDO": { + "id": "PWDO", + "city": "Powder River at Baker, OR", + "state": "OR", + "lat": 44.7683333, + "lon": -117.8305555 + } +} \ No newline at end of file diff --git a/datagenerators/output/stations.json b/datagenerators/output/stations.json index 30484a2..823aea8 100644 --- a/datagenerators/output/stations.json +++ b/datagenerators/output/stations.json @@ -1,16130 +1,2306 @@ { - "KBID": { - "id": "KBID", - "city": "Block Island State Airport", - "state": "RI", - "lat": 41.1694699, - "lon": -71.5787299 - }, - "KOQU": { - "id": "KOQU", - "city": "N. Kingston / Quonset", - "state": "RI", - "lat": 41.6, - "lon": -71.41667 - }, - "KPVD": { - "id": "KPVD", - "city": "Rhode Island TF Green International Airport", - "state": "RI", - "lat": 41.72233, - "lon": -71.4277199 - }, - "KSFZ": { - "id": "KSFZ", - "city": "Pawtucket, North Central State Airport", - "state": "RI", - "lat": 41.91667, - "lon": -71.5 - }, - "KUUU": { - "id": "KUUU", - "city": "Newport, Newport State Airport", - "state": "RI", - "lat": 41.53, - "lon": -71.28361 - }, - "KWST": { - "id": "KWST", - "city": "Westerly, Westerly State Airport", - "state": "RI", - "lat": 41.34972, - "lon": -71.79889 - }, - "KDOV": { - "id": "KDOV", - "city": "Dover Air Force Base", - "state": "DE", - "lat": 39.13333, - "lon": -75.4666699 - }, - "KGED": { - "id": "KGED", - "city": "Georgetown - Delaware Coastal Airport", - "state": "DE", - "lat": 38.68974, - "lon": -75.36245 - }, - "KILG": { - "id": "KILG", - "city": "Wilmington, New Castle County Airport", - "state": "DE", - "lat": 39.67442, - "lon": -75.60567 - }, - "KAFO": { - "id": "KAFO", - "city": "Afton WY", - "state": "WY", - "lat": 42.7113299, - "lon": -110.94217 - }, - "KARL": { - "id": "KARL", - "city": "I80 - Arlington", - "state": "WY", - "lat": 41.5980599, - "lon": -106.21487 - }, - "KBFU": { - "id": "KBFU", - "city": "WY59 - Belle Fourche", - "state": "WY", - "lat": 43.93253, - "lon": -105.4467 - }, - "KBIT": { - "id": "KBIT", - "city": "I80/US30 - Bitter Creek", - "state": "WY", - "lat": 41.64599, - "lon": -108.5836 - }, - "KBPI": { - "id": "KBPI", - "city": "Big Piney - Marbleton Airport", - "state": "WY", - "lat": 42.57805, - "lon": -110.10972 - }, - "KBRX": { - "id": "KBRX", - "city": "I25/US87 - Bordeaux Interchange", - "state": "WY", - "lat": 41.93066, - "lon": -104.9436 - }, - "KBVR": { - "id": "KBVR", - "city": "US287/WY789 - Beaver Rim", - "state": "WY", - "lat": 42.58565, - "lon": -108.28199 - }, - "KBYG": { - "id": "KBYG", - "city": "Buffalo - Johnson County Airport", - "state": "WY", - "lat": 44.38122, - "lon": -106.71947 - }, - "KCHJ": { - "id": "KCHJ", - "city": "WY296 - Chief Joseph", - "state": "WY", - "lat": 44.73997, - "lon": -109.38088 - }, - "KCMS": { - "id": "KCMS", - "city": "I80/US30 - Peru Hill", - "state": "WY", - "lat": 41.54958, - "lon": -109.60197 - }, - "KCOD": { - "id": "KCOD", - "city": "Cody", - "state": "WY", - "lat": 44.51667, - "lon": -109.01667 - }, - "KCPR": { - "id": "KCPR", - "city": "Casper, Natrona County International Airport", - "state": "WY", - "lat": 42.8975, - "lon": -106.47306 - }, - "KCTD": { - "id": "KCTD", - "city": "I80/US30 - Continental Divide", - "state": "WY", - "lat": 41.71586, - "lon": -107.78256 - }, - "KCYS": { - "id": "KCYS", - "city": "Cheyenne, Cheyenne Airport", - "state": "WY", - "lat": 41.15789, - "lon": -104.80812 - }, - "KDGW": { - "id": "KDGW", - "city": "Douglas, Converse County Airport", - "state": "WY", - "lat": 42.79417, - "lon": -105.38194 - }, - "KDHS": { - "id": "KDHS", - "city": "I90 - Dead Horse", - "state": "WY", - "lat": 44.21906, - "lon": -106.10478 - }, - "KDRC": { - "id": "KDRC", - "city": "I25 - Deer Creek", - "state": "WY", - "lat": 42.83687, - "lon": -105.86063 - }, - "KDUB": { - "id": "KDUB", - "city": "Dubois Municipal Airport", - "state": "WY", - "lat": 43.5484, - "lon": -109.6903 - }, - "KDWX": { - "id": "KDWX", - "city": "Dixon Airport", - "state": "WY", - "lat": 41.03704, - "lon": -107.49976 - }, - "KEAN": { - "id": "KEAN", - "city": "Phifer Airfield - Wheatland", - "state": "WY", - "lat": 42.05472, - "lon": -104.93711 - }, - "KECS": { - "id": "KECS", - "city": "Mondell Field", - "state": "WY", - "lat": 43.8854, - "lon": -104.3179 - }, - "KEHY": { - "id": "KEHY", - "city": "Elk Mountain AWOS", - "state": "WY", - "lat": 41.7253, - "lon": -106.4594 - }, - "KEMM": { - "id": "KEMM", - "city": "KEMMERER", - "state": "WY", - "lat": 41.82, - "lon": -110.56 - }, - "KEVW": { - "id": "KEVW", - "city": "Evanston-Uinta County Airport - Burns Field", - "state": "WY", - "lat": 41.27306, - "lon": -111.03056 - }, - "KFBR": { - "id": "KFBR", - "city": "Fort Bridger WY", - "state": "WY", - "lat": 41.392, - "lon": -110.40683 - }, - "KFEW": { - "id": "KFEW", - "city": "Francis E Warren Air Force Base Heliport", - "state": "WY", - "lat": 41.13332, - "lon": -104.8671899 - }, - "KFIR": { - "id": "KFIR", - "city": "I80/US189 - First Divide", - "state": "WY", - "lat": 41.27649, - "lon": -110.80066 - }, - "KGCC": { - "id": "KGCC", - "city": "Gillette, Gillette-Campbell County Airport", - "state": "WY", - "lat": 44.33944, - "lon": -105.54194 - }, - "KGEY": { - "id": "KGEY", - "city": "South Big Horn County Airport", - "state": "WY", - "lat": 44.5174, - "lon": -108.0752 - }, - "KGUN": { - "id": "KGUN", - "city": "US85 - Gun Barrel", - "state": "WY", - "lat": 41.44368, - "lon": -104.34428 - }, - "KGUR": { - "id": "KGUR", - "city": "Camp Guernsey", - "state": "WY", - "lat": 42.2597, - "lon": -104.7283 - }, - "KHLD": { - "id": "KHLD", - "city": "US20/US26 - Hiland", - "state": "WY", - "lat": 43.0923, - "lon": -107.32198 - }, - "KHSG": { - "id": "KHSG", - "city": "Hot Springs County Airport", - "state": "WY", - "lat": 43.7136, - "lon": -108.3897 - }, - "KIDV": { - "id": "KIDV", - "city": "I25/US87 - I-25 Divide", - "state": "WY", - "lat": 43.89864, - "lon": -106.63833 - }, - "KIKA": { - "id": "KIKA", - "city": "I90 - Inyan Kara", - "state": "WY", - "lat": 44.29414, - "lon": -104.62926 - }, - "KJAC": { - "id": "KJAC", - "city": "Jackson, Jackson Hole Airport", - "state": "WY", - "lat": 43.6, - "lon": -110.73333 - }, - "KLAR": { - "id": "KLAR", - "city": "Laramie Regional Airport", - "state": "WY", - "lat": 41.3165, - "lon": -105.67287 - }, - "KLND": { - "id": "KLND", - "city": "Lander", - "state": "WY", - "lat": 42.81472, - "lon": -108.72806 - }, - "KMTR": { - "id": "KMTR", - "city": "WY120 - Meeteetse Rim", - "state": "WY", - "lat": 44.27011, - "lon": -108.87343 - }, - "KPAT": { - "id": "KPAT", - "city": "WY220 - Pathfinder", - "state": "WY", - "lat": 42.5581, - "lon": -106.8453399 - }, - "KPER": { - "id": "KPER", - "city": "I80/US30 - Green River Tunnel East", - "state": "WY", - "lat": 41.53186, - "lon": -109.45995 - }, - "KPNA": { - "id": "KPNA", - "city": "Pinedale, Ralph Wenz Field Airport", - "state": "WY", - "lat": 42.79528, - "lon": -109.80694 - }, - "KPOY": { - "id": "KPOY", - "city": "Powell Municipal Airport", - "state": "WY", - "lat": 44.8671999, - "lon": -108.7934 - }, - "KPUM": { - "id": "KPUM", - "city": "US287 - Pumpkin Vine", - "state": "WY", - "lat": 41.05218, - "lon": -105.46906 - }, - "KREC": { - "id": "KREC", - "city": "WY28 - Lower Red Canyon", - "state": "WY", - "lat": 42.61795, - "lon": -108.61093 - }, - "KRIW": { - "id": "KRIW", - "city": "Riverton Regional Airport", - "state": "WY", - "lat": 43.06219, - "lon": -108.44701 - }, - "KRKS": { - "id": "KRKS", - "city": "Rock Springs, Rock Springs-Sweetwater County Airport", - "state": "WY", - "lat": 41.59417, - "lon": -109.06528 - }, - "KRWL": { - "id": "KRWL", - "city": "Rawlins Municipal Airport", - "state": "WY", - "lat": 41.80648, - "lon": -107.19516 - }, - "KSAA": { - "id": "KSAA", - "city": "Saratoga WY", - "state": "WY", - "lat": 41.44483, - "lon": -106.8235 - }, - "KSGE": { - "id": "KSGE", - "city": "US30 - Sage Junction", - "state": "WY", - "lat": 41.82447, - "lon": -110.90764 - }, - "KSHC": { - "id": "KSHC", - "city": "WY372 - Shute Creek", - "state": "WY", - "lat": 41.94409, - "lon": -110.00399 - }, - "KSHR": { - "id": "KSHR", - "city": "Sheridan County Airport", - "state": "WY", - "lat": 44.7603099, - "lon": -106.97411 - }, - "KSKL": { - "id": "KSKL", - "city": "WY230 - Skyline", - "state": "WY", - "lat": 41.13753, - "lon": -106.57687 - }, - "KSOU": { - "id": "KSOU", - "city": "WY28 - South Pass", - "state": "WY", - "lat": 42.47752, - "lon": -108.8444 - }, - "KTBX": { - "id": "KTBX", - "city": "Boysen", - "state": "WY", - "lat": 43.4667, - "lon": -108.2333 - }, - "KTET": { - "id": "KTET", - "city": "WY22 - Teton Pass", - "state": "WY", - "lat": 43.49873, - "lon": -110.9562 - }, - "KTMH": { - "id": "KTMH", - "city": "I25/US87 - Twenty Mile Hill", - "state": "WY", - "lat": 43.12271, - "lon": -106.33705 - }, - "KTOR": { - "id": "KTOR", - "city": "Torrington Municipal Airport", - "state": "WY", - "lat": 42.06134, - "lon": -104.15842 - }, - "KVDW": { - "id": "KVDW", - "city": "I80/US30 - Vedauwoo", - "state": "WY", - "lat": 41.15687, - "lon": -105.40237 - }, - "KWRL": { - "id": "KWRL", - "city": "Worland, Worland Municipal Airport", - "state": "WY", - "lat": 43.9658299, - "lon": -107.95083 - }, - "KWTR": { - "id": "KWTR", - "city": "I25/US87 - Whitaker", - "state": "WY", - "lat": 41.41772, - "lon": -104.87502 - }, - "KWYH": { - "id": "KWYH", - "city": "I25/US87 - Wyo Hill", - "state": "WY", - "lat": 41.04746, - "lon": -104.8901 - }, - "KACK": { - "id": "KACK", - "city": "Nantucket, Nantucket Memorial Airport", - "state": "MA", - "lat": 41.25389, - "lon": -70.05972 - }, - "KAQW": { - "id": "KAQW", - "city": "North Adams Harriman-and-West Airport", - "state": "MA", - "lat": 42.69731, - "lon": -73.16955 - }, - "KBAF": { - "id": "KBAF", - "city": "Westfield, Barnes Municipal Airport", - "state": "MA", - "lat": 42.15972, - "lon": -72.71278 - }, - "KBED": { - "id": "KBED", - "city": "Laurence G Hanscom Field Airport", - "state": "MA", - "lat": 42.46811, - "lon": -71.29463 - }, - "KBOS": { - "id": "KBOS", - "city": "Boston, Logan International Airport", - "state": "MA", - "lat": 42.36056, - "lon": -71.01056 - }, - "KBVY": { - "id": "KBVY", - "city": "Beverly, Beverly Municipal Airport", - "state": "MA", - "lat": 42.58361, - "lon": -70.91639 - }, - "KCEF": { - "id": "KCEF", - "city": "Chicopee Falls / Westover Air Force Base", - "state": "MA", - "lat": 42.2, - "lon": -72.53333 - }, - "KCQX": { - "id": "KCQX", - "city": "Chatham, Chatham Municipal Airport", - "state": "MA", - "lat": 41.6875, - "lon": -69.99333 - }, - "KEWB": { - "id": "KEWB", - "city": "New Bedford, New Bedford Regional Airport", - "state": "MA", - "lat": 41.67528, - "lon": -70.95694 - }, - "KFIT": { - "id": "KFIT", - "city": "Fitchburg, Fitchburg Municipal Airport", - "state": "MA", - "lat": 42.55194, - "lon": -71.75583 - }, - "KFMH": { - "id": "KFMH", - "city": "Otis Air National Guard Base", - "state": "MA", - "lat": 41.65, - "lon": -70.51667 - }, - "KGHG": { - "id": "KGHG", - "city": "Marshfield Airport", - "state": "MA", - "lat": 42.0983, - "lon": -70.6722 - }, - "KHYA": { - "id": "KHYA", - "city": "Hyannis, Barnstable Municipal-Boardman Airport", - "state": "MA", - "lat": 41.67194, - "lon": -70.26972 - }, - "KLWM": { - "id": "KLWM", - "city": "Lawrence Municipal Airport", - "state": "MA", - "lat": 42.7126, - "lon": -71.12553 - }, - "KMVY": { - "id": "KMVY", - "city": "Marthas Vineyard Airport", - "state": "MA", - "lat": 41.39298, - "lon": -70.61588 - }, - "KORE": { - "id": "KORE", - "city": "Orange Municipal Airport", - "state": "MA", - "lat": 42.57, - "lon": -72.28693 - }, - "KORH": { - "id": "KORH", - "city": "Worcester, Worcester Regional Airport", - "state": "MA", - "lat": 42.27056, - "lon": -71.87306 - }, - "KOWD": { - "id": "KOWD", - "city": "Norwood, Norwood Memorial Airport", - "state": "MA", - "lat": 42.19083, - "lon": -71.17389 - }, - "KPSF": { - "id": "KPSF", - "city": "Pittsfield Municipal Airport", - "state": "MA", - "lat": 42.42691, - "lon": -73.28897 - }, - "KPVC": { - "id": "KPVC", - "city": "Provincetown Municipal Airport", - "state": "MA", - "lat": 42.07436, - "lon": -70.21816 - }, - "KPYM": { - "id": "KPYM", - "city": "Plymouth, Plymouth Municipal Airport", - "state": "MA", - "lat": 41.90861, - "lon": -70.72806 - }, - "KTAN": { - "id": "KTAN", - "city": "Taunton, Taunton Municipal Airport", - "state": "MA", - "lat": 41.87556, - "lon": -71.0211099 - }, - "KADF": { - "id": "KADF", - "city": "Dexter B Florence Memorial Field", - "state": "AR", - "lat": 34.0998, - "lon": -93.0661 - }, - "KAGO": { - "id": "KAGO", - "city": "Ralph C Weiser Field Airport", - "state": "AR", - "lat": 33.2274699, - "lon": -93.217 - }, - "KARG": { - "id": "KARG", - "city": "Walnut Ridge Regional Airport", - "state": "AR", - "lat": 36.12562, - "lon": -90.92148 - }, - "KASG": { - "id": "KASG", - "city": "Springdale Municipal", - "state": "AR", - "lat": 36.18333, - "lon": -94.11667 - }, - "KAWM": { - "id": "KAWM", - "city": "West Memphis, West Memphis Municipal Airport", - "state": "AR", - "lat": 35.13333, - "lon": -90.23333 - }, - "KBPK": { - "id": "KBPK", - "city": "Baxter County Airport", - "state": "AR", - "lat": 36.37056, - "lon": -92.47194 - }, - "KBVX": { - "id": "KBVX", - "city": "Batesville, Batesville Regional Airport", - "state": "AR", - "lat": 35.73333, - "lon": -91.65 - }, - "KCCA": { - "id": "KCCA", - "city": "Clinton Memorial Airfield", - "state": "AR", - "lat": 35.598, - "lon": -92.4516 - }, - "KCDH": { - "id": "KCDH", - "city": "Camden / Harrell Field", - "state": "AR", - "lat": 33.61667, - "lon": -92.76667 - }, - "KCXW": { - "id": "KCXW", - "city": "Conway - Cantrell Field", - "state": "AR", - "lat": 35.0199, - "lon": -92.5551 - }, - "KDEQ": { - "id": "KDEQ", - "city": "De Queen, J Lynn Helms Sevier County Airport", - "state": "AR", - "lat": 34.04694, - "lon": -94.39944 - }, - "KDRP": { - "id": "KDRP", - "city": "Delta Regional Airport", - "state": "AR", - "lat": 35.12005, - "lon": -90.8265 - }, - "KELD": { - "id": "KELD", - "city": "South Arkansas Regional Airport", - "state": "AR", - "lat": 33.22075, - "lon": -92.8139999 - }, - "KFLP": { - "id": "KFLP", - "city": "Flippin, Marion County Regional Airport", - "state": "AR", - "lat": 36.3, - "lon": -92.58333 - }, - "KFSM": { - "id": "KFSM", - "city": "Fort Smith Regional Airport", - "state": "AR", - "lat": 35.3335, - "lon": -94.36524 - }, - "KFYV": { - "id": "KFYV", - "city": "Fayetteville, Drake Field", - "state": "AR", - "lat": 36.01028, - "lon": -94.1677799 - }, - "KHKA": { - "id": "KHKA", - "city": "Blytheville, Blytheville Municipal Airport", - "state": "AR", - "lat": 35.93889, - "lon": -89.8325 - }, - "KHOT": { - "id": "KHOT", - "city": "Hot Springs, Memorial Field Airport", - "state": "AR", - "lat": 34.47806, - "lon": -93.09611 - }, - "KHRO": { - "id": "KHRO", - "city": "Harrison, Boone County Airport", - "state": "AR", - "lat": 36.26167, - "lon": -93.15472 - }, - "KJBR": { - "id": "KJBR", - "city": "Jonesboro, Jonesboro Municipal Airport", - "state": "AR", - "lat": 35.83722, - "lon": -90.64306 - }, - "KLIT": { - "id": "KLIT", - "city": "Little Rock, Adams Field", - "state": "AR", - "lat": 34.72667, - "lon": -92.23611 - }, - "KLLQ": { - "id": "KLLQ", - "city": "Monticello, Monticello Municipal Airport/Ellis Field", - "state": "AR", - "lat": 33.63833, - "lon": -91.75111 - }, - "KLRF": { - "id": "KLRF", - "city": "Little Rock Air Force Base", - "state": "AR", - "lat": 34.91667, - "lon": -92.15 - }, - "KMEZ": { - "id": "KMEZ", - "city": "Mena, Mena Intermountain Municipal Airport", - "state": "AR", - "lat": 34.54528, - "lon": -94.2025 - }, - "KMWT": { - "id": "KMWT", - "city": "Mount Ida", - "state": "AR", - "lat": 34.55, - "lon": -93.58333 - }, - "KORK": { - "id": "KORK", - "city": "North Little Rock Municipal Airport", - "state": "AR", - "lat": 34.83314, - "lon": -92.25414 - }, - "KPBF": { - "id": "KPBF", - "city": "Pine Bluff, Grider Field Airport", - "state": "AR", - "lat": 34.175, - "lon": -91.93472 - }, - "KROG": { - "id": "KROG", - "city": "Rogers - Rogers Executive Airport - Carter Field", - "state": "AR", - "lat": 36.36667, - "lon": -94.1 - }, - "KRUE": { - "id": "KRUE", - "city": "Russelville Municipal Airport", - "state": "AR", - "lat": 35.25737, - "lon": -93.0949399 - }, - "KSGT": { - "id": "KSGT", - "city": "Stuttgart, Stuttgart Municipal Airport", - "state": "AR", - "lat": 34.6, - "lon": -91.56667 - }, - "KSLG": { - "id": "KSLG", - "city": "Siloam Springs, Smith Field Airport", - "state": "AR", - "lat": 36.2, - "lon": -94.48333 - }, - "KSRC": { - "id": "KSRC", - "city": "Searcy Municipal Airport", - "state": "AR", - "lat": 35.21349, - "lon": -91.7392799 - }, - "KSUZ": { - "id": "KSUZ", - "city": "Saline County Regional Airport", - "state": "AR", - "lat": 34.59039, - "lon": -92.47944 - }, - "KTXK": { - "id": "KTXK", - "city": "Texarkana, Texarkana Regional-Webb Field", - "state": "AR", - "lat": 33.45611, - "lon": -93.9875 - }, - "KVBT": { - "id": "KVBT", - "city": "Bentonville, Bentonville Municipal Airport/Louise M Thaden Field", - "state": "AR", - "lat": 36.35, - "lon": -94.2166699 - }, - "KXNA": { - "id": "KXNA", - "city": "Northwest Arkansas Regional Airport", - "state": "AR", - "lat": 36.28977, - "lon": -94.3114499 - }, - "KACQ": { - "id": "KACQ", - "city": "Waseca Municipal Airport", - "state": "MN", - "lat": 44.07024, - "lon": -93.55342 - }, - "KADC": { - "id": "KADC", - "city": "Wadena Municipal Airport", - "state": "MN", - "lat": 46.45022, - "lon": -95.21353 - }, - "KAEL": { - "id": "KAEL", - "city": "Albert Lea, Albert Lea Municipal Airport", - "state": "MN", - "lat": 43.68333, - "lon": -93.36667 - }, - "KAIT": { - "id": "KAIT", - "city": "Aitkin Municipal Airport - Steve Kurtz Field", - "state": "MN", - "lat": 46.54899, - "lon": -93.67573 - }, - "KANE": { - "id": "KANE", - "city": "Minneapolis / Blaine", - "state": "MN", - "lat": 45.14258, - "lon": -93.21272 - }, - "KAQP": { - "id": "KAQP", - "city": "Appleton Municipal Airport", - "state": "MN", - "lat": 45.22488, - "lon": -96.00412 - }, - "KAUM": { - "id": "KAUM", - "city": "Austin Municipal", - "state": "MN", - "lat": 43.66667, - "lon": -92.93333 - }, - "KAXN": { - "id": "KAXN", - "city": "Alexandria, Chandler Field", - "state": "MN", - "lat": 45.8686099, - "lon": -95.39417 - }, - "KBBB": { - "id": "KBBB", - "city": "Benson Municipal Airport", - "state": "MN", - "lat": 45.3309799, - "lon": -95.64692 - }, - "KBDE": { - "id": "KBDE", - "city": "Baudette International Airport", - "state": "MN", - "lat": 48.72605, - "lon": -94.61215 - }, - "KBDH": { - "id": "KBDH", - "city": "Willmar Municipal Airport - John L. Rice Field", - "state": "MN", - "lat": 45.11113, - "lon": -95.1258299 - }, - "KBJI": { - "id": "KBJI", - "city": "Bemidji", - "state": "MN", - "lat": 47.50762, - "lon": -94.92783 - }, - "KBRD": { - "id": "KBRD", - "city": "Brainerd - Crow Wing County Airport", - "state": "MN", - "lat": 46.40205, - "lon": -94.12734 - }, - "KCBG": { - "id": "KCBG", - "city": "Cambridge Municipal Airport", - "state": "MN", - "lat": 45.56275, - "lon": -93.26436 - }, - "KCDD": { - "id": "KCDD", - "city": "Crane Lake - Scotts Seaplane Base", - "state": "MN", - "lat": 48.26014, - "lon": -92.47485 - }, - "KCFE": { - "id": "KCFE", - "city": "Buffalo, Buffalo Municipal Airport", - "state": "MN", - "lat": 45.15889, - "lon": -93.84306 - }, - "KCKC": { - "id": "KCKC", - "city": "Grand Marais/Cook County Airport", - "state": "MN", - "lat": 47.83665, - "lon": -90.3864399 - }, - "KCKN": { - "id": "KCKN", - "city": "Crookston Municipal Field", - "state": "MN", - "lat": 47.84042, - "lon": -96.6200999 - }, - "KCNB": { - "id": "KCNB", - "city": "Canby Airfield", - "state": "MN", - "lat": 44.7295, - "lon": -96.266 - }, - "KCOQ": { - "id": "KCOQ", - "city": "Cloquet Carlton County Airport", - "state": "MN", - "lat": 46.69869, - "lon": -92.5034 - }, - "KCQM": { - "id": "KCQM", - "city": "Cook Municipal Airport", - "state": "MN", - "lat": 47.81997, - "lon": -92.68169 - }, - "KDLH": { - "id": "KDLH", - "city": "Duluth International Airport", - "state": "MN", - "lat": 46.84347, - "lon": -92.1866 - }, - "KDTL": { - "id": "KDTL", - "city": "Detroit Lakes Airport-Wething Field", - "state": "MN", - "lat": 46.8285399, - "lon": -95.88567 - }, - "KDVP": { - "id": "KDVP", - "city": "Slayton Municipal Airport", - "state": "MN", - "lat": 43.99055, - "lon": -95.78102 - }, - "KDXX": { - "id": "KDXX", - "city": "Madison, Madison-Lac Qui Parle County Airport", - "state": "MN", - "lat": 44.9839399, - "lon": -96.1788399 - }, - "KDYT": { - "id": "KDYT", - "city": "Duluth - Sky Harbor Airport", - "state": "MN", - "lat": 46.72452, - "lon": -92.0444799 - }, - "KBIX": { - "id": "KBIX", - "city": "Keesler Air Force Base / Biloxi", - "state": "MS", - "lat": 30.41667, - "lon": -88.91667 - }, - "KCBM": { - "id": "KCBM", - "city": "Columbus Air Force Base", - "state": "MS", - "lat": 33.65, - "lon": -88.45 - }, - "KCKM": { - "id": "KCKM", - "city": "Fletcher Field, Clarksdale", - "state": "MS", - "lat": 34.2997, - "lon": -90.5123 - }, - "KCRX": { - "id": "KCRX", - "city": "Corinth", - "state": "MS", - "lat": 34.915, - "lon": -88.6035 - }, - "KGLH": { - "id": "KGLH", - "city": "Greenville, Mid Delta Regional Airport", - "state": "MS", - "lat": 33.48278, - "lon": -90.98556 - }, - "KGPT": { - "id": "KGPT", - "city": "Gulfport - Gulfport-Biloxi International Airport", - "state": "MS", - "lat": 30.41194, - "lon": -89.08083 - }, - "KGTR": { - "id": "KGTR", - "city": "Columbus/West Point/Starkville, Golden Triangle Regional Airport", - "state": "MS", - "lat": 33.45, - "lon": -88.58333 - }, - "KGWO": { - "id": "KGWO", - "city": "Greenwood, Greenwood-LeFlore Airport", - "state": "MS", - "lat": 33.4925, - "lon": -90.0836099 - }, - "KHBG": { - "id": "KHBG", - "city": "Hattiesburg, Bobby L Chain Municipal Airport", - "state": "MS", - "lat": 31.26945, - "lon": -89.25613 - }, - "KHEZ": { - "id": "KHEZ", - "city": "Natchez, Hardy-Anders Field Natchez-Adams County Airport", - "state": "MS", - "lat": 31.61593, - "lon": -91.29724 - }, - "KHKS": { - "id": "KHKS", - "city": "Jackson, Hawkins Field Airport", - "state": "MS", - "lat": 32.33472, - "lon": -90.2225 - }, - "KHSA": { - "id": "KHSA", - "city": "Bay St. Louis, Stennis International Airport", - "state": "MS", - "lat": 30.36778, - "lon": -89.45472 - }, - "KIKT": { - "id": "KIKT", - "city": "Nakika Subsea Development Platform", - "state": "MS", - "lat": 28.5208, - "lon": -88.2889 - }, - "KJAN": { - "id": "KJAN", - "city": "Jackson, Jackson International Airport", - "state": "MS", - "lat": 32.3197199, - "lon": -90.0775 - }, - "KJVW": { - "id": "KJVW", - "city": "JB Williams Airport", - "state": "MS", - "lat": 32.30447, - "lon": -90.41053 - }, - "KLMS": { - "id": "KLMS", - "city": "Louisville/Winston County Airport", - "state": "MS", - "lat": 33.14599, - "lon": -89.06245 - }, - "KLUL": { - "id": "KLUL", - "city": "LAUREL/NOBLE FIELD", - "state": "MS", - "lat": 31.67, - "lon": -89.17 - }, - "KMBO": { - "id": "KMBO", - "city": "Madison Bruce Campbell Field Airport", - "state": "MS", - "lat": 32.4384, - "lon": -90.1014 - }, - "KMCB": { - "id": "KMCB", - "city": "McComb, McComb / Pike County / John E Lewis Field Airport", - "state": "MS", - "lat": 31.17833, - "lon": -90.47194 - }, - "KMEI": { - "id": "KMEI", - "city": "Meridian, Key Field", - "state": "MS", - "lat": 32.33806, - "lon": -88.74778 - }, - "KMJD": { - "id": "KMJD", - "city": "Picayune Municipal Airport", - "state": "MS", - "lat": 30.48747, - "lon": -89.65119 - }, - "KMPE": { - "id": "KMPE", - "city": "Philadelphia Municipal Airport", - "state": "MS", - "lat": 32.79921, - "lon": -89.12599 - }, - "KNJW": { - "id": "KNJW", - "city": "Meridian, Joe Williams Naval Outlying Field", - "state": "MS", - "lat": 32.79611, - "lon": -88.83167 - }, - "KNMM": { - "id": "KNMM", - "city": "Meridian, Meridian Naval Air Station - McCain Field", - "state": "MS", - "lat": 32.55194, - "lon": -88.55528 - }, - "KOLV": { - "id": "KOLV", - "city": "Olive Branch, Olive Branch Airport", - "state": "MS", - "lat": 34.97889, - "lon": -89.78694 - }, - "KPIB": { - "id": "KPIB", - "city": "Hattiesburg/Laurel, Hattiesburg-Laurel Regional Airport", - "state": "MS", - "lat": 31.46667, - "lon": -89.33333 - }, - "KPMU": { - "id": "KPMU", - "city": "Batesville Panola County", - "state": "MS", - "lat": 34.3635, - "lon": -89.8929 - }, - "KPQL": { - "id": "KPQL", - "city": "Moss Point - Trent Lott International Airport", - "state": "MS", - "lat": 30.46305, - "lon": -88.53155 - }, - "KRNV": { - "id": "KRNV", - "city": "Cleveland Municipal Airport", - "state": "MS", - "lat": 33.7611, - "lon": -90.7579 - }, - "KSTF": { - "id": "KSTF", - "city": "George M Bryan Airport, Starkville", - "state": "MS", - "lat": 33.4331, - "lon": -88.8486 - }, - "KTUP": { - "id": "KTUP", - "city": "Tupelo, Tupelo Regional Airport", - "state": "MS", - "lat": 34.26806, - "lon": -88.77 - }, - "KUOX": { - "id": "KUOX", - "city": "Oxford, University-Oxford Airport", - "state": "MS", - "lat": 34.38444, - "lon": -89.53556 - }, - "KUTA": { - "id": "KUTA", - "city": "Tunica, Tunica Municipal Airport", - "state": "MS", - "lat": 34.68083, - "lon": -90.34639 - }, - "KVKS": { - "id": "KVKS", - "city": "Vicksburg Municipal", - "state": "MS", - "lat": 32.23333, - "lon": -90.93333 - }, - "KBDL": { - "id": "KBDL", - "city": "Windsor Locks, Bradley International Airport", - "state": "CT", - "lat": 41.93806, - "lon": -72.6825 - }, - "KBDR": { - "id": "KBDR", - "city": "Bridgeport, Sikorsky Memorial Airport", - "state": "CT", - "lat": 41.16421, - "lon": -73.12663 - }, - "KDXR": { - "id": "KDXR", - "city": "Danbury, Danbury Municipal Airport", - "state": "CT", - "lat": 41.37167, - "lon": -73.48444 - }, - "KGON": { - "id": "KGON", - "city": "Groton / New London, Groton / New London Airport", - "state": "CT", - "lat": 41.3275, - "lon": -72.04944 - }, - "KHFD": { - "id": "KHFD", - "city": "Hartford, Hartford-Brainard Airport", - "state": "CT", - "lat": 41.735, - "lon": -72.65167 - }, - "KHVN": { - "id": "KHVN", - "city": "New Haven, Tweed-New Haven Airport", - "state": "CT", - "lat": 41.26389, - "lon": -72.88722 - }, - "KIJD": { - "id": "KIJD", - "city": "Willimantic, Windham Airport", - "state": "CT", - "lat": 41.74194, - "lon": -72.18361 - }, - "KLZD": { - "id": "KLZD", - "city": "DANIELSON", - "state": "CT", - "lat": 41.8197, - "lon": -71.90096 - }, - "KMMK": { - "id": "KMMK", - "city": "Meriden, Meriden Markham Municipal Airport", - "state": "CT", - "lat": 41.50972, - "lon": -72.82778 - }, - "KOXC": { - "id": "KOXC", - "city": "Oxford, Waterbury-Oxford Airport", - "state": "CT", - "lat": 41.48333, - "lon": -73.13333 - }, - "KSNC": { - "id": "KSNC", - "city": "Chester, Chester Airport", - "state": "CT", - "lat": 41.38389, - "lon": -72.50583 - }, - "KAFK": { - "id": "KAFK", - "city": "Nebraska City, Nebraska City Municipal Airport", - "state": "NE", - "lat": 40.6, - "lon": -95.85 - }, - "KAHQ": { - "id": "KAHQ", - "city": "Wahoo", - "state": "NE", - "lat": 41.2406, - "lon": -96.5946 - }, - "KAIA": { - "id": "KAIA", - "city": "Alliance, Alliance Municipal Airport", - "state": "NE", - "lat": 42.05722, - "lon": -102.8 - }, - "KANW": { - "id": "KANW", - "city": "Ainsworth Regional Airport", - "state": "NE", - "lat": 42.57484, - "lon": -99.99832 - }, - "KAUH": { - "id": "KAUH", - "city": "Aurora, Aurora Municipal Airport", - "state": "NE", - "lat": 40.89389, - "lon": -97.99444 - }, - "KBBW": { - "id": "KBBW", - "city": "Broken Bow, Broken Bow Municipal Airport", - "state": "NE", - "lat": 41.43333, - "lon": -99.65 - }, - "KBFF": { - "id": "KBFF", - "city": "Scottsbluff, Heilig Field", - "state": "NE", - "lat": 41.86694, - "lon": -103.58583 - }, - "KBIE": { - "id": "KBIE", - "city": "Beatrice Municipal", - "state": "NE", - "lat": 40.3, - "lon": -96.75 - }, - "KBTA": { - "id": "KBTA", - "city": "Blair Municipal Airport", - "state": "NE", - "lat": 41.4148, - "lon": -96.109 - }, - "KBVN": { - "id": "KBVN", - "city": "Albion Municipal Airport", - "state": "NE", - "lat": 41.73016, - "lon": -98.05453 - }, - "KCDR": { - "id": "KCDR", - "city": "Chadron, Chadron Municipal Airport", - "state": "NE", - "lat": 42.8375, - "lon": -103.09528 - }, - "KCSB": { - "id": "KCSB", - "city": "Cambridge Municipal Airport", - "state": "NE", - "lat": 40.3065799, - "lon": -100.16207 - }, - "KEAR": { - "id": "KEAR", - "city": "Kearney, Kearney Municipal Airport", - "state": "NE", - "lat": 40.73333, - "lon": -99 - }, - "KFET": { - "id": "KFET", - "city": "Fremont Municipal Airport", - "state": "NE", - "lat": 41.45, - "lon": -96.51667 - }, - "KFNB": { - "id": "KFNB", - "city": "Falls City, Brenner Field Airport", - "state": "NE", - "lat": 40.07889, - "lon": -95.5919399 - }, - "KGGF": { - "id": "KGGF", - "city": "Grant Municipal Airport", - "state": "NE", - "lat": 40.87066, - "lon": -101.73388 - }, - "KGRI": { - "id": "KGRI", - "city": "Grand Island, Central Nebraska Regional Airport", - "state": "NE", - "lat": 40.9583299, - "lon": -98.3125 - }, - "KGRN": { - "id": "KGRN", - "city": "Gordon Municipal", - "state": "NE", - "lat": 42.8, - "lon": -102.16667 - }, - "KHDE": { - "id": "KHDE", - "city": "Brewster Field Airport", - "state": "NE", - "lat": 40.45, - "lon": -99.33333 - }, - "KHJH": { - "id": "KHJH", - "city": "Hebron, Hebron Municipal Airport", - "state": "NE", - "lat": 40.15222, - "lon": -97.58694 - }, - "KHSI": { - "id": "KHSI", - "city": "Hastings, Hastings Municipal Airport", - "state": "NE", - "lat": 40.60056, - "lon": -98.42583 - }, - "KIBM": { - "id": "KIBM", - "city": "Kimball, Kimball Municipal Airport/Robert E Arraj Field", - "state": "NE", - "lat": 41.18333, - "lon": -103.66667 - }, - "KIML": { - "id": "KIML", - "city": "Imperial, Imperial Municipal Airport", - "state": "NE", - "lat": 40.51667, - "lon": -101.61667 - }, - "KJYR": { - "id": "KJYR", - "city": "York, York Municipal Airport", - "state": "NE", - "lat": 40.89667, - "lon": -97.62278 - }, - "KLBF": { - "id": "KLBF", - "city": "North Platte, North Platte Regional Airport", - "state": "NE", - "lat": 41.12194, - "lon": -100.66833 - }, - "KLCG": { - "id": "KLCG", - "city": "Wayne, Wayne Municipal Airport", - "state": "NE", - "lat": 42.24167, - "lon": -96.98139 - }, - "KLNK": { - "id": "KLNK", - "city": "Lincoln, Lincoln Municipal Airport", - "state": "NE", - "lat": 40.83111, - "lon": -96.7644399 - }, - "KLXN": { - "id": "KLXN", - "city": "Lexington, Jim Kelly Field Airport", - "state": "NE", - "lat": 40.79111, - "lon": -99.77722 - }, - "KMCK": { - "id": "KMCK", - "city": "McCook, McCook Municipal Airport", - "state": "NE", - "lat": 40.20306, - "lon": -100.58833 - }, - "KMLE": { - "id": "KMLE", - "city": "Omaha, Millard Airport", - "state": "NE", - "lat": 41.19583, - "lon": -96.1122199 - }, - "KODX": { - "id": "KODX", - "city": "Ord, Evelyn Sharp Field Airport", - "state": "NE", - "lat": 41.62417, - "lon": -98.9525 - }, - "KOFF": { - "id": "KOFF", - "city": "Omaha / Offutt Air Force Base", - "state": "NE", - "lat": 41.11667, - "lon": -95.9 - }, - "KOFK": { - "id": "KOFK", - "city": "Norfolk, Stefan Memorial Airport", - "state": "NE", - "lat": 41.9805599, - "lon": -97.43694 - }, - "KOGA": { - "id": "KOGA", - "city": "Ogallala, Searle Field Airport", - "state": "NE", - "lat": 41.11972, - "lon": -101.76889 - }, - "KOLU": { - "id": "KOLU", - "city": "Columbus, Columbus Municipal Airport", - "state": "NE", - "lat": 41.45, - "lon": -97.33333 - }, - "KOMA": { - "id": "KOMA", - "city": "Omaha - Eppley Airfield", - "state": "NE", - "lat": 41.3119, - "lon": -95.90185 - }, - "KONL": { - "id": "KONL", - "city": "O'Neill / Baker Field", - "state": "NE", - "lat": 42.46667, - "lon": -98.68333 - }, - "KPMV": { - "id": "KPMV", - "city": "Plattsmouth, Plattsmouth Municipal Airport", - "state": "NE", - "lat": 40.95, - "lon": -95.9177799 - }, - "KSNY": { - "id": "KSNY", - "city": "Sidney, Sidney Municipal Airport", - "state": "NE", - "lat": 41.09944, - "lon": -102.98556 - }, - "KTIF": { - "id": "KTIF", - "city": "Thedford, Thomas County Airport", - "state": "NE", - "lat": 41.96194, - "lon": -100.56889 - }, - "KTQE": { - "id": "KTQE", - "city": "Tekamah, Tekamah Municipal Airport", - "state": "NE", - "lat": 41.76694, - "lon": -96.17778 - }, - "KVTN": { - "id": "KVTN", - "city": "Valentine, Miller Field", - "state": "NE", - "lat": 42.85861, - "lon": -100.55139 - }, - "KBTV": { - "id": "KBTV", - "city": "Burlington, Burlington International Airport", - "state": "VT", - "lat": 44.46806, - "lon": -73.15028 - }, - "KCDA": { - "id": "KCDA", - "city": "Caledonia County Airport", - "state": "VT", - "lat": 44.5691142, - "lon": -72.0179789 - }, - "KDDH": { - "id": "KDDH", - "city": "Bennington Morse State Airport", - "state": "VT", - "lat": 42.89355, - "lon": -73.2486 - }, - "KEFK": { - "id": "KEFK", - "city": "Northeast Kingdom International Airport", - "state": "VT", - "lat": 44.88846, - "lon": -72.23593 - }, - "KFSO": { - "id": "KFSO", - "city": "Franklin County State Airport", - "state": "VT", - "lat": 44.9402807, - "lon": -73.09746 - }, - "KMPV": { - "id": "KMPV", - "city": "Barre / Montpelier, Knapp State Airport", - "state": "VT", - "lat": 44.20472, - "lon": -72.56611 - }, - "KMVL": { - "id": "KMVL", - "city": "Morrisville-Stowe State Airport", - "state": "VT", - "lat": 44.53589, - "lon": -72.6162499 - }, - "KRUT": { - "id": "KRUT", - "city": "Rutland-Southern Vermont Regional Airport", - "state": "VT", - "lat": 43.53333, - "lon": -72.95 - }, - "KVSF": { - "id": "KVSF", - "city": "Springfield, Hartness State Springfield Airport", - "state": "VT", - "lat": 43.3425, - "lon": -72.52167 - }, - "KAIZ": { - "id": "KAIZ", - "city": "Kaiser Lake Ozark, Lee C Fine Memorial Airport", - "state": "MO", - "lat": 38.1, - "lon": -92.55 - }, - "KBBG": { - "id": "KBBG", - "city": "Branson", - "state": "MO", - "lat": 36.5321, - "lon": -93.2005 - }, - "KCDJ": { - "id": "KCDJ", - "city": "Chillicothe, Chillicothe Agri-Science Center", - "state": "MO", - "lat": 39.81667, - "lon": -93.58333 - }, - "KCGI": { - "id": "KCGI", - "city": "Cape Girardeau, Cape Girardeau Regional Airport", - "state": "MO", - "lat": 37.22556, - "lon": -89.5783299 - }, - "KCOU": { - "id": "KCOU", - "city": "Columbia, Columbia Regional Airport", - "state": "MO", - "lat": 38.81694, - "lon": -92.21833 - }, - "KDMO": { - "id": "KDMO", - "city": "Sedalia, Sedalia Memorial Airport", - "state": "MO", - "lat": 38.71222, - "lon": -93.17444 - }, - "KEOS": { - "id": "KEOS", - "city": "NEOSHOAIRPORT", - "state": "MO", - "lat": 36.8108, - "lon": -94.39169 - }, - "KEVU": { - "id": "KEVU", - "city": "Maryville Northwest Missouri Regional Airport", - "state": "MO", - "lat": 40.3525, - "lon": -94.915 - }, - "KEZZ": { - "id": "KEZZ", - "city": "Cameron Memorial Airport", - "state": "MO", - "lat": 39.7275599, - "lon": -94.27639 - }, - "KFAM": { - "id": "KFAM", - "city": "Farmington Airport", - "state": "MO", - "lat": 37.76667, - "lon": -90.43333 - }, - "KFWB": { - "id": "KFWB", - "city": "Branson West Muni - Emerson Field", - "state": "MO", - "lat": 36.6985, - "lon": -93.4021999 - }, - "KGLY": { - "id": "KGLY", - "city": "Clinton, MO", - "state": "MO", - "lat": 38.3566, - "lon": -93.6842 - }, - "KGPH": { - "id": "KGPH", - "city": "Mosby Midwest National Air Center Airport", - "state": "MO", - "lat": 39.3325, - "lon": -94.3096 - }, - "KHAE": { - "id": "KHAE", - "city": "Hannibal Regional Airport", - "state": "MO", - "lat": 39.7252, - "lon": -91.4439 - }, - "KHFJ": { - "id": "KHFJ", - "city": "Monett", - "state": "MO", - "lat": 36.9062, - "lon": -94.0128 - }, - "KIRK": { - "id": "KIRK", - "city": "Kirksville, Kirksville Regional Airport", - "state": "MO", - "lat": 40.09722, - "lon": -92.54333 - }, - "KJEF": { - "id": "KJEF", - "city": "Jefferson City, Jefferson City Memorial Airport", - "state": "MO", - "lat": 38.59444, - "lon": -92.15583 - }, - "KJLN": { - "id": "KJLN", - "city": "Joplin, Joplin Regional Airport", - "state": "MO", - "lat": 37.15611, - "lon": -94.5005599 - }, - "KLBO": { - "id": "KLBO", - "city": "LEBANON", - "state": "MO", - "lat": 37.64833, - "lon": -92.6525 - }, - "KAAS": { - "id": "KAAS", - "city": "Taylor County Airport", - "state": "KY", - "lat": 37.35828, - "lon": -85.30942 - }, - "KBRY": { - "id": "KBRY", - "city": "Samuels Field Airport", - "state": "KY", - "lat": 37.81433, - "lon": -85.49964 - }, - "KBWG": { - "id": "KBWG", - "city": "Bowling Green, Bowling Green-Warren County Regional Airport", - "state": "KY", - "lat": 36.96444, - "lon": -86.41944 - }, - "KBYL": { - "id": "KBYL", - "city": "Williamsburg-Whitley County Airport", - "state": "KY", - "lat": 36.7954099, - "lon": -84.2012699 - }, - "KCEY": { - "id": "KCEY", - "city": "Murray Kyle Oakley Field, KY", - "state": "KY", - "lat": 36.6646, - "lon": -88.3728 - }, - "KCPF": { - "id": "KCPF", - "city": "Wendell H Ford Airport", - "state": "KY", - "lat": 37.38736, - "lon": -83.26161 - }, - "KCVG": { - "id": "KCVG", - "city": "Cincinnati/Northern Kentucky International Airport", - "state": "KY", - "lat": 39.04456, - "lon": -84.67229 - }, - "KDVK": { - "id": "KDVK", - "city": "Stuart Powell Field Airport", - "state": "KY", - "lat": 37.5775751, - "lon": -84.7694978 - }, - "KDWU": { - "id": "KDWU", - "city": "Ashland Regional Airport", - "state": "KY", - "lat": 38.5545, - "lon": -82.738 - }, - "KEHR": { - "id": "KEHR", - "city": "Henderson City", - "state": "KY", - "lat": 37.81667, - "lon": -87.68333 - }, - "KEKQ": { - "id": "KEKQ", - "city": "Monticello, Wayne County Airport", - "state": "KY", - "lat": 36.85528, - "lon": -84.85611 - }, - "KEKX": { - "id": "KEKX", - "city": "Elizabethtown Addington Field Airport", - "state": "KY", - "lat": 37.686, - "lon": -85.925 - }, - "KFFT": { - "id": "KFFT", - "city": "Frankfort, Capital City Airport", - "state": "KY", - "lat": 38.18472, - "lon": -84.90333 - }, - "KFGX": { - "id": "KFGX", - "city": "Flemingsburg Fleming-Mason Airport", - "state": "KY", - "lat": 38.5418, - "lon": -83.7434 - }, - "KFTK": { - "id": "KFTK", - "city": "Fort Knox", - "state": "KY", - "lat": 37.9, - "lon": -85.9666699 - }, - "KGDA": { - "id": "KGDA", - "city": "MARION", - "state": "KY", - "lat": 37.3333, - "lon": -88.1 - }, - "KGLW": { - "id": "KGLW", - "city": "Glasgow, Glasgow Municipal Airport", - "state": "KY", - "lat": 37.03167, - "lon": -85.95361 - }, - "KHOP": { - "id": "KHOP", - "city": "Fort Campbell U. S. Army Airfield", - "state": "KY", - "lat": 36.66667, - "lon": -87.5 - }, - "KHVC": { - "id": "KHVC", - "city": "Hopkinsville-Christian County Airport", - "state": "KY", - "lat": 36.8569699, - "lon": -87.45508 - }, - "KIOB": { - "id": "KIOB", - "city": "Mount Sterling-Montgomery County Airport", - "state": "KY", - "lat": 38.0575, - "lon": -83.9829 - }, - "KJKL": { - "id": "KJKL", - "city": "Jackson, Carroll Airport", - "state": "KY", - "lat": 37.5913899, - "lon": -83.31444 - }, - "KLEX": { - "id": "KLEX", - "city": "Lexington Blue Grass Airport", - "state": "KY", - "lat": 38.0339, - "lon": -84.6114599 - }, - "KLOU": { - "id": "KLOU", - "city": "Louisville, Bowman Field Airport", - "state": "KY", - "lat": 38.22778, - "lon": -85.66361 - }, - "KLOZ": { - "id": "KLOZ", - "city": "London, London-Corbin Airport-Magee Field", - "state": "KY", - "lat": 37.08944, - "lon": -84.06861 - }, - "KOWB": { - "id": "KOWB", - "city": "Owensboro, Owensboro-Daviess County Airport", - "state": "KY", - "lat": 37.74, - "lon": -87.16667 - }, - "KPAH": { - "id": "KPAH", - "city": "Paducah, Barkley Regional Airport", - "state": "KY", - "lat": 37.05639, - "lon": -88.77389 - }, - "KPBX": { - "id": "KPBX", - "city": "Pikeville Pike County Airport and Hatcher Field", - "state": "KY", - "lat": 37.5587, - "lon": -82.5674 - }, - "KRGA": { - "id": "KRGA", - "city": "Central Kentucky Regional Airport", - "state": "KY", - "lat": 37.6308475, - "lon": -84.3323372 - }, - "KSDF": { - "id": "KSDF", - "city": "Louisville Muhammad Ali International Airport", - "state": "KY", - "lat": 38.17406, - "lon": -85.7365 - }, - "KSJS": { - "id": "KSJS", - "city": "Big Sandy Regional Airport", - "state": "KY", - "lat": 37.751, - "lon": -82.6367 - }, - "KSME": { - "id": "KSME", - "city": "Somerset, Somerset-Pulaski County - J.T. Wilson Field Airport", - "state": "KY", - "lat": 37.05417, - "lon": -84.615 - }, - "KSYM": { - "id": "KSYM", - "city": "Clyde A. Thomas Regional Airport", - "state": "KY", - "lat": 38.215, - "lon": -83.5874 - }, - "KTWT": { - "id": "KTWT", - "city": "Sturgis, Sturgis Municipal Airport", - "state": "KY", - "lat": 37.54083, - "lon": -87.9516699 - }, - "KACB": { - "id": "KACB", - "city": "Bellaire, Antrim County Airport", - "state": "MI", - "lat": 44.98833, - "lon": -85.19833 - }, - "KADG": { - "id": "KADG", - "city": "Adrian, Lenawee County Airport", - "state": "MI", - "lat": 41.86778, - "lon": -84.07944 - }, - "KAMN": { - "id": "KAMN", - "city": "Alma, Gratiot Community Airport", - "state": "MI", - "lat": 43.32194, - "lon": -84.68778 - }, - "KANJ": { - "id": "KANJ", - "city": "Sault Ste. Marie", - "state": "MI", - "lat": 46.4794399, - "lon": -84.35722 - }, - "KAPN": { - "id": "KAPN", - "city": "Alpena, Alpena County Regional Airport", - "state": "MI", - "lat": 45.07167, - "lon": -83.56444 - }, - "KARB": { - "id": "KARB", - "city": "Ann Arbor, Ann Arbor Municipal Airport", - "state": "MI", - "lat": 42.22389, - "lon": -83.74 - }, - "KAZO": { - "id": "KAZO", - "city": "Kalamazoo/Battle Creek International Airport", - "state": "MI", - "lat": 42.2283, - "lon": -85.54595 - }, - "KBAX": { - "id": "KBAX", - "city": "Huron County Memorial Airport", - "state": "MI", - "lat": 43.77741, - "lon": -82.98271 - }, - "KBEH": { - "id": "KBEH", - "city": "Southwest Michigan Regional Airport", - "state": "MI", - "lat": 42.12896, - "lon": -86.41515 - }, - "KBFA": { - "id": "KBFA", - "city": "Boyne Mountain Airport", - "state": "MI", - "lat": 45.16584, - "lon": -84.92411 - }, - "KBIV": { - "id": "KBIV", - "city": "Holland - West Michigan Regional Airport", - "state": "MI", - "lat": 42.74611, - "lon": -86.09667 - }, - "KBTL": { - "id": "KBTL", - "city": "Battle Creek Executive Airport", - "state": "MI", - "lat": 42.31197, - "lon": -85.24144 - }, - "KCAD": { - "id": "KCAD", - "city": "Wexford County Airport", - "state": "MI", - "lat": 44.27847, - "lon": -85.4206899 - }, - "KCFS": { - "id": "KCFS", - "city": "Caro, Tuscola Area Airport", - "state": "MI", - "lat": 43.45861, - "lon": -83.44528 - }, - "KCIU": { - "id": "KCIU", - "city": "Sault Ste Marie, Chippewa County International Airport", - "state": "MI", - "lat": 46.25, - "lon": -84.4666699 - }, - "KCMX": { - "id": "KCMX", - "city": "Houghton County Memorial Airport", - "state": "MI", - "lat": 47.16597, - "lon": -88.48072 - }, - "KCVX": { - "id": "KCVX", - "city": "Charlevoix, Charlevoix Municipal Airport", - "state": "MI", - "lat": 45.30472, - "lon": -85.27472 - }, - "KALX": { - "id": "KALX", - "city": "Alexander City, Thomas C Russell Field Airport", - "state": "AL", - "lat": 32.91472, - "lon": -85.96278 - }, - "KANB": { - "id": "KANB", - "city": "Anniston Metro Airport", - "state": "AL", - "lat": 33.59045, - "lon": -85.84789 - }, - "KASN": { - "id": "KASN", - "city": "Talladega Municipal Airport", - "state": "AL", - "lat": 33.5695, - "lon": -86.0512 - }, - "KAUO": { - "id": "KAUO", - "city": "Auburn-Opelika Airport", - "state": "AL", - "lat": 32.61667, - "lon": -85.43333 - }, - "KBFM": { - "id": "KBFM", - "city": "Mobile, Mobile Downtown Airport", - "state": "AL", - "lat": 30.61389, - "lon": -88.0633299 - }, - "KBFZ": { - "id": "KBFZ", - "city": "Albertville Regional Airport-Thomas J Brumlik Field", - "state": "AL", - "lat": 34.22911, - "lon": -86.25575 - }, - "KBHM": { - "id": "KBHM", - "city": "Birmingham, Birmingham International Airport", - "state": "AL", - "lat": 33.56556, - "lon": -86.745 - }, - "KCMD": { - "id": "KCMD", - "city": "Cullman Regional Folsom Field", - "state": "AL", - "lat": 34.2687, - "lon": -86.858 - }, - "KCQF": { - "id": "KCQF", - "city": "Sonny Callahan Airport", - "state": "AL", - "lat": 30.461, - "lon": -87.877 - }, - "KDCU": { - "id": "KDCU", - "city": "Decatur, Pryor Field", - "state": "AL", - "lat": 34.65806, - "lon": -86.94333 - }, - "KDHN": { - "id": "KDHN", - "city": "Dothan, Dothan Regional Airport", - "state": "AL", - "lat": 31.32139, - "lon": -85.44972 - }, - "KDYA": { - "id": "KDYA", - "city": "Demopolis Municipal Airport", - "state": "AL", - "lat": 32.4638, - "lon": -87.9541 - }, - "KEDN": { - "id": "KEDN", - "city": "Enterprise Municipal Airport", - "state": "AL", - "lat": 31.2982, - "lon": -85.9048 - }, - "KEET": { - "id": "KEET", - "city": "Alabaster, Shelby County Airport", - "state": "AL", - "lat": 33.17833, - "lon": -86.78167 - }, - "KEKY": { - "id": "KEKY", - "city": "Bessemer Airport", - "state": "AL", - "lat": 33.3126, - "lon": -86.9263 - }, - "KEUF": { - "id": "KEUF", - "city": "Eufaula Municipal Airport", - "state": "AL", - "lat": 31.951, - "lon": -85.129 - }, - "KGAD": { - "id": "KGAD", - "city": "Gadsden, Gadsden Municipal Airport", - "state": "AL", - "lat": 33.96667, - "lon": -86.08333 - }, - "KGZH": { - "id": "KGZH", - "city": "Evergreen, Middleton Field", - "state": "AL", - "lat": 31.41889, - "lon": -87.04806 - }, - "KHDL": { - "id": "KHDL", - "city": "Headland Municipal Airport", - "state": "AL", - "lat": 31.36414, - "lon": -85.31253 - }, - "KHEY": { - "id": "KHEY", - "city": "Hanchey AHP / Ozark", - "state": "AL", - "lat": 31.35, - "lon": -85.66667 - }, - "KHSV": { - "id": "KHSV", - "city": "Huntsville, Huntsville International / Jones Field", - "state": "AL", - "lat": 34.64361, - "lon": -86.78556 - }, - "KHUA": { - "id": "KHUA", - "city": "Redstone Airfield", - "state": "AL", - "lat": 34.6786, - "lon": -86.6847 - }, - "KJFX": { - "id": "KJFX", - "city": "Jasper Walker County Airport & Bevill Field", - "state": "AL", - "lat": 33.902, - "lon": -87.31417 - }, - "KJKA": { - "id": "KJKA", - "city": "Jack Edwards Airport", - "state": "AL", - "lat": 30.2896, - "lon": -87.6718 - }, - "KLOR": { - "id": "KLOR", - "city": "Fort Rucker, Lowe Army Heliport", - "state": "AL", - "lat": 31.35889, - "lon": -85.74833 - }, - "KMDQ": { - "id": "KMDQ", - "city": "Huntsville, Madison County Executive Airport", - "state": "AL", - "lat": 34.86139, - "lon": -86.55722 - }, - "KMGM": { - "id": "KMGM", - "city": "Montgomery, Dannelly Field", - "state": "AL", - "lat": 32.30028, - "lon": -86.40611 - }, - "KMOB": { - "id": "KMOB", - "city": "Mobile, Mobile Regional Airport", - "state": "AL", - "lat": 30.68833, - "lon": -88.24556 - }, - "KMSL": { - "id": "KMSL", - "city": "Muscle Shoals, North West Alabama Regional Airport", - "state": "AL", - "lat": 34.74389, - "lon": -87.59944 - }, - "KMXF": { - "id": "KMXF", - "city": "Maxwell Air Force Base / Montgomery", - "state": "AL", - "lat": 32.38333, - "lon": -86.36667 - }, - "KOZR": { - "id": "KOZR", - "city": "Cairns Army Air Field / Ozark", - "state": "AL", - "lat": 31.27672, - "lon": -85.71099 - }, - "KPLR": { - "id": "KPLR", - "city": "St Clair County Airport", - "state": "AL", - "lat": 33.5588, - "lon": -86.2491 - }, - "KPRN": { - "id": "KPRN", - "city": "Mac Crenshaw Memorial Airport", - "state": "AL", - "lat": 31.8457, - "lon": -86.6107 - }, - "KSCD": { - "id": "KSCD", - "city": "Merkel Field Sylacauga Municipal Airport", - "state": "AL", - "lat": 33.1718, - "lon": -86.3055 - }, - "KSEM": { - "id": "KSEM", - "city": "Craig Field / Selma", - "state": "AL", - "lat": 32.35, - "lon": -86.98333 - }, - "KSXS": { - "id": "KSXS", - "city": "SCHELL AHP", - "state": "AL", - "lat": 31.35, - "lon": -85.85 - }, - "KTCL": { - "id": "KTCL", - "city": "Tuscaloosa Regional Airport", - "state": "AL", - "lat": 33.21215, - "lon": -87.61554 - }, - "KTOI": { - "id": "KTOI", - "city": "Troy, Troy Municipal Airport", - "state": "AL", - "lat": 31.86056, - "lon": -86.01222 - }, - "KAFN": { - "id": "KAFN", - "city": "Jaffrey Airport-Silver Ranch", - "state": "NH", - "lat": 42.8066699, - "lon": -72.00127 - }, - "KASH": { - "id": "KASH", - "city": "Nashua - Boire Field Airport", - "state": "NH", - "lat": 42.77981, - "lon": -71.51409 - }, - "KBML": { - "id": "KBML", - "city": "Berlin, Berlin Municipal Airport", - "state": "NH", - "lat": 44.57611, - "lon": -71.17861 - }, - "KCON": { - "id": "KCON", - "city": "Concord Municipal Airport", - "state": "NH", - "lat": 43.20489, - "lon": -71.50257 - }, - "KDAW": { - "id": "KDAW", - "city": "Rochester - Skyhaven Airport", - "state": "NH", - "lat": 43.27939, - "lon": -70.92426 - }, - "KEEN": { - "id": "KEEN", - "city": "Keene, Dillant-Hopkins Airport", - "state": "NH", - "lat": 42.9, - "lon": -72.26667 - }, - "KHIE": { - "id": "KHIE", - "city": "Whitefield - Mount Washington Regional Airport", - "state": "NH", - "lat": 44.36595, - "lon": -71.55218 - }, - "KLCI": { - "id": "KLCI", - "city": "Laconia, Laconia Municipal Airport", - "state": "NH", - "lat": 43.56667, - "lon": -71.41667 - }, - "KLEB": { - "id": "KLEB", - "city": "Lebanon Municipal Airport", - "state": "NH", - "lat": 43.6271, - "lon": -72.30537 - }, - "KMHT": { - "id": "KMHT", - "city": "Manchester Airport", - "state": "NH", - "lat": 42.92964, - "lon": -71.43559 - }, - "KMWN": { - "id": "KMWN", - "city": "Mount Washington", - "state": "NH", - "lat": 44.27086, - "lon": -71.30337 - }, - "KPSM": { - "id": "KPSM", - "city": "Pease Air Force Base / Portsmouth", - "state": "NH", - "lat": 43.0833299, - "lon": -70.81667 - }, - "PHBK": { - "id": "PHBK", - "city": "Kekaha, Pacific Missile Test Facility Barking Sands", - "state": "HI", - "lat": 22.03639, - "lon": -159.78639 - }, - "PHHI": { - "id": "PHHI", - "city": "Wheeler Air Force Base / Oahu", - "state": "HI", - "lat": 21.48333, - "lon": -158.03333 - }, - "PHHN": { - "id": "PHHN", - "city": "HANA", - "state": "HI", - "lat": 20.79563, - "lon": -156.01444 - }, - "PHJR": { - "id": "PHJR", - "city": "Oahu, Kalaeloa Airport", - "state": "HI", - "lat": 21.30833, - "lon": -158.06806 - }, - "PHKO": { - "id": "PHKO", - "city": "Kailua / Kona, Keahole Airport", - "state": "HI", - "lat": 19.74083, - "lon": -156.05056 - }, - "PHLI": { - "id": "PHLI", - "city": "Lihue, Lihue Airport", - "state": "HI", - "lat": 21.98389, - "lon": -159.3411099 - }, - "PHMK": { - "id": "PHMK", - "city": "Kaunakakai, Molokai Airport", - "state": "HI", - "lat": 21.15, - "lon": -157.1 - }, - "PHMU": { - "id": "PHMU", - "city": "KAMUELA", - "state": "HI", - "lat": 20.00133, - "lon": -155.66817 - }, - "PHNG": { - "id": "PHNG", - "city": "Kaneohe, Marine Corps Air Station", - "state": "HI", - "lat": 21.45389, - "lon": -157.76556 - }, - "PHNL": { - "id": "PHNL", - "city": "Daniel K Inouye International Airport", - "state": "HI", - "lat": 21.3275, - "lon": -157.94306 - }, - "PHNY": { - "id": "PHNY", - "city": "Lanai City, Lanai Airport", - "state": "HI", - "lat": 20.78556, - "lon": -156.95139 - }, - "PHOG": { - "id": "PHOG", - "city": "Kahului, Kahului Airport", - "state": "HI", - "lat": 20.8924999, - "lon": -156.43694 - }, - "PHSF": { - "id": "PHSF", - "city": "Bradshaw Army Air Field / Hawaii", - "state": "HI", - "lat": 19.78333, - "lon": -155.55 - }, - "PHTO": { - "id": "PHTO", - "city": "Hilo, Hilo International Airport", - "state": "HI", - "lat": 19.72222, - "lon": -155.0558299 - }, - "KADU": { - "id": "KADU", - "city": "Audubon, Audubon County Airport", - "state": "IA", - "lat": 41.70111, - "lon": -94.92028 - }, - "KAIO": { - "id": "KAIO", - "city": "Atlantic", - "state": "IA", - "lat": 41.4, - "lon": -95.05 - }, - "KALO": { - "id": "KALO", - "city": "Waterloo, Waterloo Municipal Airport", - "state": "IA", - "lat": 42.55444, - "lon": -92.40111 - }, - "KAMW": { - "id": "KAMW", - "city": "Ames, Ames Municipal Airport", - "state": "IA", - "lat": 41.99056, - "lon": -93.6188899 - }, - "KAWG": { - "id": "KAWG", - "city": "Washington", - "state": "IA", - "lat": 41.28333, - "lon": -91.66667 - }, - "KAXA": { - "id": "KAXA", - "city": "Algona", - "state": "IA", - "lat": 43.0833299, - "lon": -94.26667 - }, - "KBNW": { - "id": "KBNW", - "city": "Boone Municipal", - "state": "IA", - "lat": 42.05, - "lon": -93.85 - }, - "KBRL": { - "id": "KBRL", - "city": "Burlington Regional Airport", - "state": "IA", - "lat": 40.77293, - "lon": -91.12543 - }, - "KCAV": { - "id": "KCAV", - "city": "Clarion", - "state": "IA", - "lat": 42.75, - "lon": -93.76667 - }, - "KCBF": { - "id": "KCBF", - "city": "Council Bluffs", - "state": "IA", - "lat": 41.2612499, - "lon": -95.7604 - }, - "KCCY": { - "id": "KCCY", - "city": "Charles City", - "state": "IA", - "lat": 43.06667, - "lon": -92.61667 - }, - "KCID": { - "id": "KCID", - "city": "Cedar Rapids Airport", - "state": "IA", - "lat": 41.88295, - "lon": -91.72456 - }, - "KCIN": { - "id": "KCIN", - "city": "Carroll", - "state": "IA", - "lat": 42.05, - "lon": -94.78333 - }, - "KCKP": { - "id": "KCKP", - "city": "Cherokee, Cherokee Municipal Airport", - "state": "IA", - "lat": 42.73167, - "lon": -95.55583 - }, - "KCNC": { - "id": "KCNC", - "city": "Chariton", - "state": "IA", - "lat": 41.03333, - "lon": -93.36667 - }, - "KCSQ": { - "id": "KCSQ", - "city": "Creston Municipal Airport", - "state": "IA", - "lat": 41.0188599, - "lon": -94.361 - }, - "KCWI": { - "id": "KCWI", - "city": "Clinton Municipal Airport", - "state": "IA", - "lat": 41.82954, - "lon": -90.33279 - }, - "KDBQ": { - "id": "KDBQ", - "city": "Dubuque Regional Airport", - "state": "IA", - "lat": 42.39837, - "lon": -90.7091 - }, - "KDEH": { - "id": "KDEH", - "city": "Decorah", - "state": "IA", - "lat": 43.28333, - "lon": -91.73333 - }, - "KDNS": { - "id": "KDNS", - "city": "Denison", - "state": "IA", - "lat": 41.98333, - "lon": -95.38333 - }, - "KDSM": { - "id": "KDSM", - "city": "Des Moines International Airport", - "state": "IA", - "lat": 41.53399, - "lon": -93.65307 - }, - "KDVN": { - "id": "KDVN", - "city": "Davenport Municipal Airport", - "state": "IA", - "lat": 41.61338, - "lon": -90.59479 - }, - "KEBS": { - "id": "KEBS", - "city": "Webster City Municipal Airport", - "state": "IA", - "lat": 42.43724, - "lon": -93.87237 - }, - "KEOK": { - "id": "KEOK", - "city": "Keokuk Municipal Airport", - "state": "IA", - "lat": 40.46149, - "lon": -91.42739 - }, - "KEST": { - "id": "KEST", - "city": "Estherville, Estherville Municipal Airport", - "state": "IA", - "lat": 43.40111, - "lon": -94.74722 - }, - "KFFL": { - "id": "KFFL", - "city": "Fairfield Municipal Airport", - "state": "IA", - "lat": 41.0521, - "lon": -91.98339 - }, - "KFOD": { - "id": "KFOD", - "city": "Fort Dodge", - "state": "IA", - "lat": 42.55, - "lon": -94.18333 - }, - "KFSW": { - "id": "KFSW", - "city": "Fort Madison Municipal Airport", - "state": "IA", - "lat": 40.66154, - "lon": -91.32672 - }, - "KFXY": { - "id": "KFXY", - "city": "Forest City Municipal Airport", - "state": "IA", - "lat": 43.235, - "lon": -93.624 - }, - "KGGI": { - "id": "KGGI", - "city": "Grinnell Municipal Airfield", - "state": "IA", - "lat": 41.7092, - "lon": -92.7349 - }, - "KHNR": { - "id": "KHNR", - "city": "Harlan, Harlan Municipal Airport", - "state": "IA", - "lat": 41.58444, - "lon": -95.33972 - }, - "KHPT": { - "id": "KHPT", - "city": "Hampton Municipal Airport", - "state": "IA", - "lat": 42.72369, - "lon": -93.22633 - }, - "KICL": { - "id": "KICL", - "city": "Schenck Field Airport", - "state": "IA", - "lat": 40.72421, - "lon": -95.02224 - }, - "KIFA": { - "id": "KIFA", - "city": "Iowa Falls Municipal Airport", - "state": "IA", - "lat": 42.4709999, - "lon": -93.27 - }, - "KIIB": { - "id": "KIIB", - "city": "Independence, Independence Municipal Airport", - "state": "IA", - "lat": 42.45, - "lon": -91.93333 - }, - "KIKV": { - "id": "KIKV", - "city": "Ankeny Regional Airport", - "state": "IA", - "lat": 41.68782, - "lon": -93.56944 - }, - "KIOW": { - "id": "KIOW", - "city": "Iowa City Municipal Airport", - "state": "IA", - "lat": 41.6394499, - "lon": -91.5445 - }, - "KLRJ": { - "id": "KLRJ", - "city": "Le Mars Municipal Airport", - "state": "IA", - "lat": 42.77478, - "lon": -96.19239 - }, - "KLWD": { - "id": "KLWD", - "city": "Lamoni, Lamoni Municipal Airport", - "state": "IA", - "lat": 40.63056, - "lon": -93.90083 - }, - "KMCW": { - "id": "KMCW", - "city": "Mason City Municipal Airport", - "state": "IA", - "lat": 43.15442, - "lon": -93.32607 - }, - "KMIW": { - "id": "KMIW", - "city": "Marshalltown, Marshalltown Municipal Airport", - "state": "IA", - "lat": 42.11056, - "lon": -92.91611 - }, - "KMPZ": { - "id": "KMPZ", - "city": "Mount Pleasant, Mount Pleasant Municipal Airport", - "state": "IA", - "lat": 40.94667, - "lon": -91.51111 - }, - "KMUT": { - "id": "KMUT", - "city": "Muscatine", - "state": "IA", - "lat": 41.36667, - "lon": -91.15 - }, - "KMXO": { - "id": "KMXO", - "city": "Monticello Regional Airport", - "state": "IA", - "lat": 42.22035, - "lon": -91.16041 - }, - "KOLZ": { - "id": "KOLZ", - "city": "Oelwein Municipal Airport", - "state": "IA", - "lat": 42.68316, - "lon": -91.97595 - }, - "KOOA": { - "id": "KOOA", - "city": "Oskaloosa, Oskaloosa Municipal Airport", - "state": "IA", - "lat": 41.22611, - "lon": -92.49361 - }, - "KOTM": { - "id": "KOTM", - "city": "Ottumwa Regional Airport", - "state": "IA", - "lat": 41.10082, - "lon": -92.4445099 - }, - "KOXV": { - "id": "KOXV", - "city": "Knoxville", - "state": "IA", - "lat": 41.3, - "lon": -93.11667 - }, - "KPEA": { - "id": "KPEA", - "city": "Pella, Pella Municipal Airport", - "state": "IA", - "lat": 41.4, - "lon": -92.93333 - }, - "KPRO": { - "id": "KPRO", - "city": "Perry Municipal Airport", - "state": "IA", - "lat": 41.828, - "lon": -94.1598999 - }, - "KRDK": { - "id": "KRDK", - "city": "Red Oak", - "state": "IA", - "lat": 41.01667, - "lon": -95.26667 - }, - "KSDA": { - "id": "KSDA", - "city": "Shenandoah Municipal", - "state": "IA", - "lat": 40.75, - "lon": -95.41667 - }, - "KSHL": { - "id": "KSHL", - "city": "Sheldon", - "state": "IA", - "lat": 43.21667, - "lon": -95.83333 - }, - "KSLB": { - "id": "KSLB", - "city": "Storm Lake", - "state": "IA", - "lat": 42.6, - "lon": -95.23333 - }, - "KSPW": { - "id": "KSPW", - "city": "Spencer Municipal Airport", - "state": "IA", - "lat": 43.16825, - "lon": -95.21008 - }, - "KSUX": { - "id": "KSUX", - "city": "Sioux City, Sioux Gateway Airport", - "state": "IA", - "lat": 42.4025, - "lon": -96.38444 - }, - "KSXK": { - "id": "KSXK", - "city": "Sioux County Regional Airport", - "state": "IA", - "lat": 42.98583, - "lon": -96.1614 - }, - "KTNU": { - "id": "KTNU", - "city": "Newton Municipal Airport - Earl Johnson Field", - "state": "IA", - "lat": 41.67014, - "lon": -93.01902 - }, - "KTVK": { - "id": "KTVK", - "city": "Centerville Municipal Airport", - "state": "IA", - "lat": 40.6839, - "lon": -92.901 - }, - "KVTI": { - "id": "KVTI", - "city": "Vinton, Vinton Veterans Memorial Airpark Airport", - "state": "IA", - "lat": 42.21861, - "lon": -92.02583 - }, - "KACP": { - "id": "KACP", - "city": "Oakdale, Allen Parish Airport", - "state": "LA", - "lat": 30.75056, - "lon": -92.68861 - }, - "KAEX": { - "id": "KAEX", - "city": "Alexandria, Alexandria International Airport", - "state": "LA", - "lat": 31.33472, - "lon": -92.55861 - }, - "KAPS": { - "id": "KAPS", - "city": "Port of South Louisiana Executive Regional Airport", - "state": "LA", - "lat": 30.08747, - "lon": -90.58283 - }, - "KAQV": { - "id": "KAQV", - "city": "Ft. Polk - Peason Ridge", - "state": "LA", - "lat": 31.4, - "lon": -93.2833 - }, - "KARA": { - "id": "KARA", - "city": "Acadiana Regional Airport", - "state": "LA", - "lat": 30.02918, - "lon": -91.88451 - }, - "KASD": { - "id": "KASD", - "city": "Slidell, Slidell Airport", - "state": "LA", - "lat": 30.34306, - "lon": -89.82194 - }, - "KATP": { - "id": "KATP", - "city": "Green Canyon 787 Atlantis", - "state": "LA", - "lat": 27.195, - "lon": -90.027 - }, - "KBAD": { - "id": "KBAD", - "city": "Barksdale Air Force Base", - "state": "LA", - "lat": 32.5, - "lon": -93.66667 - }, - "KBKB": { - "id": "KBKB", - "city": "Ft. Polk - Fullerton Landing Strip", - "state": "LA", - "lat": 31.0217, - "lon": -92.9107 - }, - "KBQP": { - "id": "KBQP", - "city": "Bastrop, Morehouse Memorial Airport", - "state": "LA", - "lat": 32.75583, - "lon": -91.88056 - }, - "KBTR": { - "id": "KBTR", - "city": "Baton Rouge, Baton Rouge Metropolitan, Ryan Field", - "state": "LA", - "lat": 30.53722, - "lon": -91.14694 - }, - "KBXA": { - "id": "KBXA", - "city": "Bogalusa, George R Carr Memorial Air Field", - "state": "LA", - "lat": 30.81361, - "lon": -89.86472 - }, - "KCWF": { - "id": "KCWF", - "city": "Chenault Airpark", - "state": "LA", - "lat": 30.21667, - "lon": -93.15 - }, - "KCYD": { - "id": "KCYD", - "city": "MISS CANYAN 807", - "state": "LA", - "lat": 28.17, - "lon": -89.22 - }, - "KDRI": { - "id": "KDRI", - "city": "De Ridder, Beauregard Parish Airport", - "state": "LA", - "lat": 30.83167, - "lon": -93.33972 - }, - "KDSF": { - "id": "KDSF", - "city": "Mississippi Canyon", - "state": "LA", - "lat": 28.35, - "lon": -88.26667 - }, - "KDTN": { - "id": "KDTN", - "city": "Shreveport, Shreveport Downtown Airport", - "state": "LA", - "lat": 32.5424999, - "lon": -93.74472 - }, - "KESF": { - "id": "KESF", - "city": "Alexandria Esler Regional Airport", - "state": "LA", - "lat": 31.39634, - "lon": -92.28273 - }, - "KGAO": { - "id": "KGAO", - "city": "Galliano, South Lafourche Airport", - "state": "LA", - "lat": 29.44472, - "lon": -90.26111 - }, - "KGBK": { - "id": "KGBK", - "city": "MAGNOLIA OIL PLATFORM", - "state": "LA", - "lat": 27.2, - "lon": -92.2 - }, - "KGHB": { - "id": "KGHB", - "city": "GB172/Salsa (Shell E-P)", - "state": "LA", - "lat": 27.84, - "lon": -91.988 - }, - "KHDC": { - "id": "KHDC", - "city": "Hammond, Hammond Municipal Airport", - "state": "LA", - "lat": 30.52083, - "lon": -90.4175 - }, - "KHUM": { - "id": "KHUM", - "city": "Houma-Terrebonne Airport", - "state": "LA", - "lat": 29.56341, - "lon": -90.66283 - }, - "KHZR": { - "id": "KHZR", - "city": "New Roads False River Regional Airport", - "state": "LA", - "lat": 30.7183, - "lon": -91.4787 - }, - "KIER": { - "id": "KIER", - "city": "Natchitoches, Natchitoches Regional Airport", - "state": "LA", - "lat": 31.73583, - "lon": -93.09917 - }, - "KIYA": { - "id": "KIYA", - "city": "Abbeville Chris Crusta Memorial Airport", - "state": "LA", - "lat": 29.97578, - "lon": -92.08422 - }, - "KLCH": { - "id": "KLCH", - "city": "Lake Charles Regional Airport", - "state": "LA", - "lat": 30.12556, - "lon": -93.22767 - }, - "KLFT": { - "id": "KLFT", - "city": "Lafayette, Lafayette Regional Airport", - "state": "LA", - "lat": 30.20222, - "lon": -91.99306 - }, - "KMLU": { - "id": "KMLU", - "city": "Monroe Regional Airport", - "state": "LA", - "lat": 32.5155699, - "lon": -92.02995 - }, - "KMNE": { - "id": "KMNE", - "city": "Minden Airport", - "state": "LA", - "lat": 32.64603, - "lon": -93.29808 - }, - "KMSY": { - "id": "KMSY", - "city": "New Orleans, New Orleans International Airport", - "state": "LA", - "lat": 29.99278, - "lon": -90.2508299 - }, - "KNBG": { - "id": "KNBG", - "city": "New Orleans Naval Air Station - Alvin Callender Field", - "state": "LA", - "lat": 29.83736, - "lon": -90.02445 - }, - "KNEW": { - "id": "KNEW", - "city": "New Orleans, New Orleans Lakefront Airport", - "state": "LA", - "lat": 30.04944, - "lon": -90.02889 - }, - "KOPL": { - "id": "KOPL", - "city": "Opelousas St Landry Parish Airport", - "state": "LA", - "lat": 30.5584, - "lon": -92.0994 - }, - "KPOE": { - "id": "KPOE", - "city": "Fort Polk, Polk AAF Ft Polk", - "state": "LA", - "lat": 31.05, - "lon": -93.19389 - }, - "KPTN": { - "id": "KPTN", - "city": "Patterson Memorial", - "state": "LA", - "lat": 29.71667, - "lon": -91.33333 - }, - "KREG": { - "id": "KREG", - "city": "Louisiana Regional Airport", - "state": "LA", - "lat": 30.1714, - "lon": -90.9404 - }, - "KRSN": { - "id": "KRSN", - "city": "Ruston, Ruston Regional Airport", - "state": "LA", - "lat": 32.51444, - "lon": -92.58833 - }, - "KSHV": { - "id": "KSHV", - "city": "Shreveport, Shreveport Regional Airport", - "state": "LA", - "lat": 32.44694, - "lon": -93.82417 - }, - "KTVR": { - "id": "KTVR", - "city": "Vicksburg, Vicksburg / Tallulah Regional Airport", - "state": "LA", - "lat": 32.3480599, - "lon": -91.03 - }, - "KUXL": { - "id": "KUXL", - "city": "Southland Field", - "state": "LA", - "lat": 30.1314, - "lon": -93.3760999 - }, - "KVOA": { - "id": "KVOA", - "city": "VK 786/Petronius (Chevron)", - "state": "LA", - "lat": 29.229, - "lon": -87.781 - }, - "KABQ": { - "id": "KABQ", - "city": "Albuquerque, Albuquerque International Airport", - "state": "NM", - "lat": 35.04167, - "lon": -106.61472 - }, - "KAEG": { - "id": "KAEG", - "city": "Albuquerque, Double Eagle II Airport", - "state": "NM", - "lat": 35.145, - "lon": -106.795 - }, - "KALM": { - "id": "KALM", - "city": "Alamogordo-White", - "state": "NM", - "lat": 32.83512, - "lon": -105.99408 - }, - "KATS": { - "id": "KATS", - "city": "Artesia Municipal Airport", - "state": "NM", - "lat": 32.85239, - "lon": -104.46444 - }, - "KAXX": { - "id": "KAXX", - "city": "Angel Fire Airport", - "state": "NM", - "lat": 36.42586, - "lon": -105.29028 - }, - "KBRG": { - "id": "KBRG", - "city": "Belen Regional Airport", - "state": "NM", - "lat": 34.64586, - "lon": -106.83634 - }, - "KCAO": { - "id": "KCAO", - "city": "Clayton Municipal Airpark", - "state": "NM", - "lat": 36.44834, - "lon": -103.15367 - }, - "KCNM": { - "id": "KCNM", - "city": "Carlsbad, Cavern City Air Terminal Airport", - "state": "NM", - "lat": 32.3375, - "lon": -104.26333 - }, - "KCQC": { - "id": "KCQC", - "city": "Clines Corners", - "state": "NM", - "lat": 35, - "lon": -105.66667 - }, - "KCVN": { - "id": "KCVN", - "city": "Clovis Municipal Airport", - "state": "NM", - "lat": 34.42274, - "lon": -103.0802 - }, - "KCVS": { - "id": "KCVS", - "city": "Cannon Air Force Base / Clovis", - "state": "NM", - "lat": 34.38333, - "lon": -103.31667 - }, - "KDMN": { - "id": "KDMN", - "city": "Deming Municipal Airport", - "state": "NM", - "lat": 32.25927, - "lon": -107.72051 - }, - "KDNA": { - "id": "KDNA", - "city": "Dona Ana County Jetport, Santa Teresa", - "state": "NM", - "lat": 31.87495, - "lon": -106.69385 - }, - "KFMN": { - "id": "KFMN", - "city": "Farmington, Four Corners Regional Airport", - "state": "NM", - "lat": 36.7436099, - "lon": -108.22917 - }, - "KGNT": { - "id": "KGNT", - "city": "Grants, Grants-Milan Municipal Airport", - "state": "NM", - "lat": 35.16528, - "lon": -107.90222 - }, - "KGUP": { - "id": "KGUP", - "city": "Gallup Municipal Airport", - "state": "NM", - "lat": 35.50859, - "lon": -108.79316 - }, - "KHMN": { - "id": "KHMN", - "city": "Holloman Air Force Base", - "state": "NM", - "lat": 32.85, - "lon": -106.1 - }, - "KHOB": { - "id": "KHOB", - "city": "Hobbs / Lea County", - "state": "NM", - "lat": 32.68333, - "lon": -103.2166699 - }, - "KLAM": { - "id": "KLAM", - "city": "Los Alamos Airport", - "state": "NM", - "lat": 35.8796899, - "lon": -106.26869 - }, - "KLRU": { - "id": "KLRU", - "city": "Las Cruces, Las Cruces International Airport", - "state": "NM", - "lat": 32.28944, - "lon": -106.92194 - }, - "KLSB": { - "id": "KLSB", - "city": "Lordsburg Municipal Airport", - "state": "NM", - "lat": 32.33346, - "lon": -108.69174 - }, - "KLVS": { - "id": "KLVS", - "city": "Las Vegas Municipal Airport", - "state": "NM", - "lat": 35.65584, - "lon": -105.13852 - }, - "KONM": { - "id": "KONM", - "city": "Socorro Municipal Airport", - "state": "NM", - "lat": 34.02633, - "lon": -106.90372 - }, - "KROW": { - "id": "KROW", - "city": "Roswell International Air Center Airport", - "state": "NM", - "lat": 33.30737, - "lon": -104.50816 - }, - "KRTN": { - "id": "KRTN", - "city": "Raton Municipal - Crews Field Airport", - "state": "NM", - "lat": 36.741528, - "lon": -104.502183 - }, - "KSAF": { - "id": "KSAF", - "city": "Santa Fe County Municipal Airport", - "state": "NM", - "lat": 35.61097, - "lon": -106.09573 - }, - "KSKX": { - "id": "KSKX", - "city": "Taos, Taos Regional Airport", - "state": "NM", - "lat": 36.45, - "lon": -105.66667 - }, - "KSRR": { - "id": "KSRR", - "city": "Sierra Blanca Regional Airport", - "state": "NM", - "lat": 33.4667699, - "lon": -105.52778 - }, - "KSVC": { - "id": "KSVC", - "city": "Grant County Airport", - "state": "NM", - "lat": 32.63099, - "lon": -108.14658 - }, - "KSXU": { - "id": "KSXU", - "city": "Santa Rosa Route 66 Airport", - "state": "NM", - "lat": 34.93567, - "lon": -104.64256 - }, - "KTCC": { - "id": "KTCC", - "city": "Tucumcari Municipal Airport", - "state": "NM", - "lat": 35.18053, - "lon": -103.60145 - }, - "KTCS": { - "id": "KTCS", - "city": "Truth Or Consequences, Truth Or Consequences Municipal Airport", - "state": "NM", - "lat": 33.2366699, - "lon": -107.26806 - }, - "KXNI": { - "id": "KXNI", - "city": "Andrew Othole Memorial Airport", - "state": "NM", - "lat": 35.06068, - "lon": -108.93759 - }, - "KADW": { - "id": "KADW", - "city": "Camp Springs / Andrews Air Force Base", - "state": "MD", - "lat": 38.81667, - "lon": -76.85 - }, - "KANP": { - "id": "KANP", - "city": "LEEAIRPORT", - "state": "MD", - "lat": 38.94287, - "lon": -76.5683899 - }, - "KAPG": { - "id": "KAPG", - "city": "Phillips Army Air Field / Aberdeen", - "state": "MD", - "lat": 39.46667, - "lon": -76.16667 - }, - "KBWI": { - "id": "KBWI", - "city": "Baltimore, Baltimore-Washington International Airport", - "state": "MD", - "lat": 39.17329, - "lon": -76.68404 - }, - "KCGE": { - "id": "KCGE", - "city": "Cambridge-Dorchester Airport", - "state": "MD", - "lat": 38.5393, - "lon": -76.0304 - }, - "KCGS": { - "id": "KCGS", - "city": "College Park Airport", - "state": "MD", - "lat": 38.9806, - "lon": -76.9223 - }, - "KDMH": { - "id": "KDMH", - "city": "Baltimore, Inner Harbor", - "state": "MD", - "lat": 39.28333, - "lon": -76.61667 - }, - "KDMW": { - "id": "KDMW", - "city": "Carroll County Regional Jack B Poage Field", - "state": "MD", - "lat": 39.6083, - "lon": -77.0077 - }, - "KEDG": { - "id": "KEDG", - "city": "WEIDE", - "state": "MD", - "lat": 39.39205, - "lon": -76.29106 - }, - "KESN": { - "id": "KESN", - "city": "Easton / Newman Field", - "state": "MD", - "lat": 38.8, - "lon": -76.06667 - }, - "KFDK": { - "id": "KFDK", - "city": "Frederick Municipal Airport", - "state": "MD", - "lat": 39.41775, - "lon": -77.36982 - }, - "KFME": { - "id": "KFME", - "city": "Fort Meade / Tipton", - "state": "MD", - "lat": 39.0833299, - "lon": -76.76667 - }, - "KGAI": { - "id": "KGAI", - "city": "Gaithersburg - Montgomery County Airport", - "state": "MD", - "lat": 39.16957, - "lon": -77.16551 - }, - "KHGR": { - "id": "KHGR", - "city": "Hagerstown, Washington County Regional Airport", - "state": "MD", - "lat": 39.70583, - "lon": -77.73 - }, - "KMTN": { - "id": "KMTN", - "city": "Baltimore / Martin", - "state": "MD", - "lat": 39.3333299, - "lon": -76.41667 - }, - "KNAK": { - "id": "KNAK", - "city": "Annapolis, United States Naval Academy", - "state": "MD", - "lat": 38.99125, - "lon": -76.48907 - }, - "KNHK": { - "id": "KNHK", - "city": "Patuxent River, Naval Air Station", - "state": "MD", - "lat": 38.27861, - "lon": -76.41389 - }, - "KNUI": { - "id": "KNUI", - "city": "St. Inigoes, Webster Field, Naval Electronic Systems Engineering Activity", - "state": "MD", - "lat": 38.14889, - "lon": -76.42 - }, - "KOXB": { - "id": "KOXB", - "city": "Ocean City, Ocean City Municipal Airport", - "state": "MD", - "lat": 38.31056, - "lon": -75.12389 - }, - "KRSP": { - "id": "KRSP", - "city": "Camp David", - "state": "MD", - "lat": 39.645, - "lon": -77.468 - }, - "KSBY": { - "id": "KSBY", - "city": "Salisbury, Salisbury-Ocean City Wicomico County Regional Airport", - "state": "MD", - "lat": 38.34056, - "lon": -75.51028 - }, - "KVKX": { - "id": "KVKX", - "city": "POTOMAC", - "state": "MD", - "lat": 38.74761, - "lon": -76.95719 - }, - "KAUG": { - "id": "KAUG", - "city": "Augusta, Augusta State Airport", - "state": "ME", - "lat": 44.32056, - "lon": -69.79722 - }, - "KBGR": { - "id": "KBGR", - "city": "Bangor, Bangor International Airport", - "state": "ME", - "lat": 44.79722, - "lon": -68.81861 - }, - "KBHB": { - "id": "KBHB", - "city": "Bar Harbor, Hancock County-Bar Harbor Airport", - "state": "ME", - "lat": 44.45, - "lon": -68.36667 - }, - "KBXM": { - "id": "KBXM", - "city": "BRUNSWICK", - "state": "ME", - "lat": 43.8923599, - "lon": -69.93883 - }, - "KCAR": { - "id": "KCAR", - "city": "Caribou, Caribou Municipal Airport", - "state": "ME", - "lat": 46.86722, - "lon": -68.01333 - }, - "KFVE": { - "id": "KFVE", - "city": "Frenchville, Northern Aroostook Regional Airport", - "state": "ME", - "lat": 47.2849999, - "lon": -68.30722 - }, - "KGNR": { - "id": "KGNR", - "city": "Greenville", - "state": "ME", - "lat": 45.4646199, - "lon": -69.5538 - }, - "KHUL": { - "id": "KHUL", - "city": "Houlton, Houlton International Airport", - "state": "ME", - "lat": 46.12306, - "lon": -67.79194 - }, - "KIWI": { - "id": "KIWI", - "city": "Wiscasset Airport", - "state": "ME", - "lat": 43.96401, - "lon": -69.7107599 - }, - "KIZG": { - "id": "KIZG", - "city": "Fryeburg, Eastern Slopes Regional Airport", - "state": "ME", - "lat": 43.98917, - "lon": -70.95028 - }, - "KLEW": { - "id": "KLEW", - "city": "Auburn-Lewiston", - "state": "ME", - "lat": 44.05, - "lon": -70.28333 - }, - "KMLT": { - "id": "KMLT", - "city": "Millinocket, Millinocket Municipal Airport", - "state": "ME", - "lat": 45.64778, - "lon": -68.69194 - }, - "KPQI": { - "id": "KPQI", - "city": "Presque Isle", - "state": "ME", - "lat": 46.68333, - "lon": -68.05 - }, - "KPWM": { - "id": "KPWM", - "city": "Portland, Portland International Jetport", - "state": "ME", - "lat": 43.64222, - "lon": -70.30444 - }, - "KRKD": { - "id": "KRKD", - "city": "Rockland, Knox County Regional Airport", - "state": "ME", - "lat": 44.06667, - "lon": -69.1 - }, - "KSFM": { - "id": "KSFM", - "city": "Sanford, Sanford Regional Airport", - "state": "ME", - "lat": 43.4, - "lon": -70.7166699 - }, - "KWVL": { - "id": "KWVL", - "city": "Waterville, Waterville Robert LaFleur Airport", - "state": "ME", - "lat": 44.53333, - "lon": -69.68333 - }, - "KABR": { - "id": "KABR", - "city": "Aberdeen, Aberdeen Regional Airport", - "state": "SD", - "lat": 45.44333, - "lon": -98.41306 - }, - "KAGZ": { - "id": "KAGZ", - "city": "WAGNERMUNC", - "state": "SD", - "lat": 43.06332, - "lon": -98.29618 - }, - "KATY": { - "id": "KATY", - "city": "Watertown, Watertown Municipal Airport", - "state": "SD", - "lat": 44.90472, - "lon": -97.14944 - }, - "KBKX": { - "id": "KBKX", - "city": "Brookings, Brookings Municipal Airport", - "state": "SD", - "lat": 44.3, - "lon": -96.81667 - }, - "KBTN": { - "id": "KBTN", - "city": "BRITTON", - "state": "SD", - "lat": 45.8152199, - "lon": -97.7431299 - }, - "KCUT": { - "id": "KCUT", - "city": "Custer, Custer County Airport", - "state": "SD", - "lat": 43.73306, - "lon": -103.6175 - }, - "KEFC": { - "id": "KEFC", - "city": "BELLEFCHE", - "state": "SD", - "lat": 44.7342, - "lon": -103.86199 - }, - "KFSD": { - "id": "KFSD", - "city": "Sioux Falls, Foss Field", - "state": "SD", - "lat": 43.57694, - "lon": -96.75361 - }, - "KHON": { - "id": "KHON", - "city": "Huron, Huron Regional Airport", - "state": "SD", - "lat": 44.38806, - "lon": -98.22833 - }, - "KHSR": { - "id": "KHSR", - "city": "HOTSPRINGS", - "state": "SD", - "lat": 43.36824, - "lon": -103.38813 - }, - "KICR": { - "id": "KICR", - "city": "Winner, Bob Wiley Field Airport", - "state": "SD", - "lat": 43.39056, - "lon": -99.8425 - }, - "KIEN": { - "id": "KIEN", - "city": "Pine Ridge, Pine Ridge Airport", - "state": "SD", - "lat": 43.02556, - "lon": -102.52306 - }, - "KLEM": { - "id": "KLEM", - "city": "LEMMON", - "state": "SD", - "lat": 45.91869, - "lon": -102.10617 - }, - "KMBG": { - "id": "KMBG", - "city": "Mobridge, Mobridge Municipal Airport", - "state": "SD", - "lat": 45.55, - "lon": -100.40861 - }, - "KMDS": { - "id": "KMDS", - "city": "Madison Municipal Airport", - "state": "SD", - "lat": 44.0164147, - "lon": -97.0855992 - }, - "KMHE": { - "id": "KMHE", - "city": "Mitchell, Mitchell Municipal Airport", - "state": "SD", - "lat": 43.76667, - "lon": -98.03333 - }, - "KMKA": { - "id": "KMKA", - "city": "MILLERMUNC", - "state": "SD", - "lat": 44.5252399, - "lon": -98.95811 - }, - "KPHP": { - "id": "KPHP", - "city": "Philip, Philip Airport", - "state": "SD", - "lat": 44.05111, - "lon": -101.60111 - }, - "KPIR": { - "id": "KPIR", - "city": "Pierre, Pierre Regional Airport", - "state": "SD", - "lat": 44.3827799, - "lon": -100.28583 - }, - "KRAP": { - "id": "KRAP", - "city": "Rapid City, Rapid City Regional Airport", - "state": "SD", - "lat": 44.04556, - "lon": -103.05389 - }, - "KRCA": { - "id": "KRCA", - "city": "Ellsworth Air Force Base", - "state": "SD", - "lat": 44.15, - "lon": -103.1 - }, - "KSPF": { - "id": "KSPF", - "city": "Spearfish / Clyde Ice", - "state": "SD", - "lat": 44.48333, - "lon": -103.78333 - }, - "KSUO": { - "id": "KSUO", - "city": "Rosebud Sioux Tribal Airport", - "state": "SD", - "lat": 43.25846, - "lon": -100.8594899 - }, - "KVMR": { - "id": "KVMR", - "city": "VERMILLION", - "state": "SD", - "lat": 42.76528, - "lon": -96.93425 - }, - "KYKN": { - "id": "KYKN", - "city": "Yankton, Chan Gurney Municipal Airport", - "state": "SD", - "lat": 42.91667, - "lon": -97.38333 - }, - "KAID": { - "id": "KAID", - "city": "Anderson Municipal Airport", - "state": "IN", - "lat": 40.10612, - "lon": -85.60977 - }, - "KANQ": { - "id": "KANQ", - "city": "Angola Tri-State Steuben County Airport", - "state": "IN", - "lat": 41.6404, - "lon": -85.0851 - }, - "KASW": { - "id": "KASW", - "city": "Warsaw, Warsaw Municipal Airport", - "state": "IN", - "lat": 41.27444, - "lon": -85.84 - }, - "KBAK": { - "id": "KBAK", - "city": "Columbus / Bakalar", - "state": "IN", - "lat": 39.26667, - "lon": -85.9 - }, - "KBFR": { - "id": "KBFR", - "city": "Virgil I Grissom Municipal Airport", - "state": "IN", - "lat": 38.84003, - "lon": -86.4453599 - }, - "KBMG": { - "id": "KBMG", - "city": "Bloomington, Monroe County Airport", - "state": "IN", - "lat": 39.14306, - "lon": -86.61667 - }, - "KCFJ": { - "id": "KCFJ", - "city": "Crawfordsville Municipal Airport", - "state": "IN", - "lat": 39.9756, - "lon": -86.9199 - }, - "KDCY": { - "id": "KDCY", - "city": "Daviess County Airport", - "state": "IN", - "lat": 38.7004, - "lon": -87.1297 - }, - "KEKM": { - "id": "KEKM", - "city": "Elkhart Municipal", - "state": "IN", - "lat": 41.71667, - "lon": -86 - }, - "KEVV": { - "id": "KEVV", - "city": "Evansville, Evansville Regional Airport", - "state": "IN", - "lat": 38.0430599, - "lon": -87.52028 - }, - "KEYE": { - "id": "KEYE", - "city": "Indianapolis, Eagle Creek Airpark", - "state": "IN", - "lat": 39.825, - "lon": -86.29583 - }, - "KFKR": { - "id": "KFKR", - "city": "Frankfort Municipal Airport", - "state": "IN", - "lat": 40.2734, - "lon": -86.5622 - }, - "KFRH": { - "id": "KFRH", - "city": "French Lick Municipal Airport", - "state": "IN", - "lat": 38.50622, - "lon": -86.63694 - }, - "KFWA": { - "id": "KFWA", - "city": "Fort Wayne International Airport", - "state": "IN", - "lat": 40.97251, - "lon": -85.20637 - }, - "KGEZ": { - "id": "KGEZ", - "city": "Shelbyville Municipal Airport", - "state": "IN", - "lat": 39.58546, - "lon": -85.79982 - }, - "KGGP": { - "id": "KGGP", - "city": "Logansport/Cass County Airport", - "state": "IN", - "lat": 40.711, - "lon": -86.373 - }, - "KGPC": { - "id": "KGPC", - "city": "Putnam County Regional Airport", - "state": "IN", - "lat": 39.6354, - "lon": -86.8155 - }, - "KGSH": { - "id": "KGSH", - "city": "Goshen, Goshen Municipal Airport", - "state": "IN", - "lat": 41.52611, - "lon": -85.78667 - }, - "KGUS": { - "id": "KGUS", - "city": "Grissom Air Force Base / Peru", - "state": "IN", - "lat": 40.65, - "lon": -86.15 - }, - "KGWB": { - "id": "KGWB", - "city": "Auburn De Kalb County Airport", - "state": "IN", - "lat": 41.307, - "lon": -85.0639999 - }, - "KGYY": { - "id": "KGYY", - "city": "Gary Regional Airport", - "state": "IN", - "lat": 41.61212, - "lon": -87.40908 - }, - "KHFY": { - "id": "KHFY", - "city": "Greenwood Municipal Airport", - "state": "IN", - "lat": 39.6276, - "lon": -86.0879999 - }, - "KHHG": { - "id": "KHHG", - "city": "Huntington Municipal Airport", - "state": "IN", - "lat": 40.8529, - "lon": -85.4571 - }, - "KHLB": { - "id": "KHLB", - "city": "Batesville Airport", - "state": "IN", - "lat": 39.34313, - "lon": -85.25843 - }, - "KHNB": { - "id": "KHNB", - "city": "Huntingburg", - "state": "IN", - "lat": 38.25, - "lon": -86.95 - }, - "KHUF": { - "id": "KHUF", - "city": "Terre Haute Regional Airport", - "state": "IN", - "lat": 39.4429, - "lon": -87.32207 - }, - "KIMS": { - "id": "KIMS", - "city": "Madison Municipal Airport", - "state": "IN", - "lat": 38.7589, - "lon": -85.4655 - }, - "KIND": { - "id": "KIND", - "city": "Indianapolis International Airport", - "state": "IN", - "lat": 39.72518, - "lon": -86.2816 - }, - "KJVY": { - "id": "KJVY", - "city": "Clark Regional Airport", - "state": "IN", - "lat": 38.36661, - "lon": -85.73814 - }, - "KLAF": { - "id": "KLAF", - "city": "Lafayette, Purdue University Airport", - "state": "IN", - "lat": 40.4125, - "lon": -86.9475 - }, - "KMCX": { - "id": "KMCX", - "city": "Monticello White County Airport", - "state": "IN", - "lat": 40.7087999, - "lon": -86.7668 - }, - "KMGC": { - "id": "KMGC", - "city": "Michigan City Municipal Airport", - "state": "IN", - "lat": 41.7033, - "lon": -86.8212 - }, - "KMIE": { - "id": "KMIE", - "city": "Muncie, Delaware County-Johnson Field", - "state": "IN", - "lat": 40.23417, - "lon": -85.39361 - }, - "KMQJ": { - "id": "KMQJ", - "city": "Indianapolis Regional Airport", - "state": "IN", - "lat": 39.84314, - "lon": -85.89774 - }, - "KMZZ": { - "id": "KMZZ", - "city": "Marion Municipal Airport", - "state": "IN", - "lat": 40.49, - "lon": -85.68 - }, - "KOKK": { - "id": "KOKK", - "city": "Kokomo, Kokomo Municipal Airport", - "state": "IN", - "lat": 40.53333, - "lon": -86.06667 - }, - "KOXI": { - "id": "KOXI", - "city": "Starke County Airport", - "state": "IN", - "lat": 41.33, - "lon": -86.665 - }, - "KPLD": { - "id": "KPLD", - "city": "Portland Municipal Airport", - "state": "IN", - "lat": 40.45158, - "lon": -84.98903 - }, - "KPPO": { - "id": "KPPO", - "city": "La Porte Municipal Airport", - "state": "IN", - "lat": 41.5725, - "lon": -86.7345 - }, - "KRCR": { - "id": "KRCR", - "city": "Rochester Fulton County Airport", - "state": "IN", - "lat": 41.06553, - "lon": -86.18169 - }, - "KRID": { - "id": "KRID", - "city": "Richmond Municipal Airport", - "state": "IN", - "lat": 39.7572, - "lon": -84.8428 - }, - "KRZL": { - "id": "KRZL", - "city": "Rensselaer Jasper County Airport", - "state": "IN", - "lat": 40.94789, - "lon": -87.18258 - }, - "KSBN": { - "id": "KSBN", - "city": "South Bend International Airport", - "state": "IN", - "lat": 41.7088899, - "lon": -86.31861 - }, - "KSMD": { - "id": "KSMD", - "city": "Smith Field Airport", - "state": "IN", - "lat": 41.14336, - "lon": -85.15277 - }, - "KTYQ": { - "id": "KTYQ", - "city": "INDIANAPOLIS", - "state": "IN", - "lat": 40.03066, - "lon": -86.2514999 - }, - "KUMP": { - "id": "KUMP", - "city": "Indianapolis Metro Airport", - "state": "IN", - "lat": 39.9354, - "lon": -86.04507 - }, - "KUWL": { - "id": "KUWL", - "city": "New Castle Henry County Airport", - "state": "IN", - "lat": 39.87672, - "lon": -85.32527 - }, - "KVPZ": { - "id": "KVPZ", - "city": "Valparaiso Porter County Municipal Airport", - "state": "IN", - "lat": 41.45349, - "lon": -86.99805 - }, - "KBAC": { - "id": "KBAC", - "city": "Valley City", - "state": "ND", - "lat": 46.9412, - "lon": -98.018 - }, - "KBIS": { - "id": "KBIS", - "city": "Bismarck, Bismarck Municipal Airport", - "state": "ND", - "lat": 46.7825, - "lon": -100.75722 - }, - "KBWP": { - "id": "KBWP", - "city": "Wahpeton, Harry Stern Airport", - "state": "ND", - "lat": 46.24389, - "lon": -96.60722 - }, - "KBWW": { - "id": "KBWW", - "city": "Bowman Regional Airport", - "state": "ND", - "lat": 46.16551, - "lon": -103.30074 - }, - "KDIK": { - "id": "KDIK", - "city": "Dickinson, Dickinson Municipal Airport", - "state": "ND", - "lat": 46.79722, - "lon": -102.80194 - }, - "KDVL": { - "id": "KDVL", - "city": "Devils Lake, Devils Lake Municipal Airport", - "state": "ND", - "lat": 48.11667, - "lon": -98.91667 - }, - "KFAR": { - "id": "KFAR", - "city": "Fargo, Hector International Airport", - "state": "ND", - "lat": 46.92528, - "lon": -96.81111 - }, - "KGAF": { - "id": "KGAF", - "city": "GRAFTON", - "state": "ND", - "lat": 48.4, - "lon": -97.37 - }, - "KGFK": { - "id": "KGFK", - "city": "Grand Forks, Grand Forks International Airport", - "state": "ND", - "lat": 47.94806, - "lon": -97.1825 - }, - "KGWR": { - "id": "KGWR", - "city": "Gwinner", - "state": "ND", - "lat": 46.2187, - "lon": -97.6435 - }, - "KHEI": { - "id": "KHEI", - "city": "Hettinger, Hettinger Municipal Airport", - "state": "ND", - "lat": 46.01056, - "lon": -102.64972 - }, - "KHZE": { - "id": "KHZE", - "city": "HAZEN", - "state": "ND", - "lat": 47.28, - "lon": -101.58 - }, - "KJMS": { - "id": "KJMS", - "city": "Jamestown, Jamestown Municipal Airport", - "state": "ND", - "lat": 46.92972, - "lon": -98.67833 - }, - "KMIB": { - "id": "KMIB", - "city": "Minot Air Force Base", - "state": "ND", - "lat": 48.41667, - "lon": -101.35 - }, - "KMOT": { - "id": "KMOT", - "city": "Minot International Airport", - "state": "ND", - "lat": 48.25203, - "lon": -101.2689 - }, - "KRDR": { - "id": "KRDR", - "city": "Grand Forks Air Force Base", - "state": "ND", - "lat": 47.96667, - "lon": -97.4 - }, - "KRUG": { - "id": "KRUG", - "city": "RUGBY", - "state": "ND", - "lat": 48.38, - "lon": -100.02 - }, - "KXWA": { - "id": "KXWA", - "city": "Williston Basin International Airport", - "state": "ND", - "lat": 48.26086, - "lon": -103.75114 - }, - "KBAM": { - "id": "KBAM", - "city": "Battle Mountain - Lander County Airport", - "state": "NV", - "lat": 40.5989999, - "lon": -116.8743 - }, - "KBVU": { - "id": "KBVU", - "city": "Boulder City Municipal Airport", - "state": "NV", - "lat": 35.9475, - "lon": -114.8611 - }, - "KCXP": { - "id": "KCXP", - "city": "Carson City Airport", - "state": "NV", - "lat": 39.19056, - "lon": -119.73191 - }, - "KDRA": { - "id": "KDRA", - "city": "Mercury, Desert Rock Airport", - "state": "NV", - "lat": 36.6207, - "lon": -116.02868 - }, - "KEKO": { - "id": "KEKO", - "city": "Elko, Elko Regional Airport", - "state": "NV", - "lat": 40.8240399, - "lon": -115.78635 - }, - "KELY": { - "id": "KELY", - "city": "Ely, Ely Airport", - "state": "NV", - "lat": 39.295, - "lon": -114.84528 - }, - "KHND": { - "id": "KHND", - "city": "Las Vegas - Henderson Executive Airport", - "state": "NV", - "lat": 35.97665, - "lon": -115.13221 - }, - "KHTH": { - "id": "KHTH", - "city": "Hawthorne Industrial Airport", - "state": "NV", - "lat": 38.54482, - "lon": -118.63137 - }, - "KINS": { - "id": "KINS", - "city": "Nellis AFB - Indian Springs Auxiliary Airfield", - "state": "NV", - "lat": 36.58573, - "lon": -115.69008 - }, - "KLAS": { - "id": "KLAS", - "city": "Harry Reid International Airport", - "state": "NV", - "lat": 36.07188, - "lon": -115.1634 - }, - "KLOL": { - "id": "KLOL", - "city": "Lovelock, Derby Field Airport", - "state": "NV", - "lat": 40.0683999, - "lon": -118.57017 - }, - "KLSV": { - "id": "KLSV", - "city": "Nellis Air Force Base", - "state": "NV", - "lat": 36.23333, - "lon": -115.03333 - }, - "KMEV": { - "id": "KMEV", - "city": "Minden-Tahoe Airport", - "state": "NV", - "lat": 38.9963, - "lon": -119.75 - }, - "KNFL": { - "id": "KNFL", - "city": "Fallon, Naval Air Station", - "state": "NV", - "lat": 39.43222, - "lon": -118.68556 - }, - "KRNO": { - "id": "KRNO", - "city": "Reno, Reno Tahoe International Airport", - "state": "NV", - "lat": 39.50776, - "lon": -119.76819 - }, - "KRTS": { - "id": "KRTS", - "city": "Reno/Stead", - "state": "NV", - "lat": 39.6682, - "lon": -119.8764 - }, - "KTMT": { - "id": "KTMT", - "city": "Austin Airport", - "state": "NV", - "lat": 39.46794, - "lon": -117.19745 - }, - "KTPH": { - "id": "KTPH", - "city": "Tonopah, Tonopah Airport", - "state": "NV", - "lat": 38.06028, - "lon": -117.08722 - }, - "KVGT": { - "id": "KVGT", - "city": "Las Vegas, North Las Vegas Airport", - "state": "NV", - "lat": 36.21205, - "lon": -115.19395 - }, - "KWMC": { - "id": "KWMC", - "city": "Winnemucca, Winnemucca Municipal Airport", - "state": "NV", - "lat": 40.90194, - "lon": -117.80722 - }, - "KADH": { - "id": "KADH", - "city": "Ada, Ada Municipal Airport", - "state": "OK", - "lat": 34.80444, - "lon": -96.67139 - }, - "KADM": { - "id": "KADM", - "city": "Ardmore, Ardmore Municipal Airport", - "state": "OK", - "lat": 34.30306, - "lon": -97.01944 - }, - "KAVK": { - "id": "KAVK", - "city": "Alva, Alva Regional Airport", - "state": "OK", - "lat": 36.77306, - "lon": -98.67 - }, - "KAXS": { - "id": "KAXS", - "city": "Altus, Altus/Quartz Mountain Regional Airport", - "state": "OK", - "lat": 34.69861, - "lon": -99.33806 - }, - "KBKN": { - "id": "KBKN", - "city": "Blackwell-Tonkawa Municipal Airport", - "state": "OK", - "lat": 36.7451099, - "lon": -97.34958 - }, - "KBVO": { - "id": "KBVO", - "city": "Bartlesville, Bartlesville Municipal Airport", - "state": "OK", - "lat": 36.76833, - "lon": -96.02611 - }, - "KCHK": { - "id": "KCHK", - "city": "Chickasha, Chickasha Municipal Airport", - "state": "OK", - "lat": 35.09611, - "lon": -97.96611 - }, - "KCLK": { - "id": "KCLK", - "city": "Clinton, Clinton Regional Airport", - "state": "OK", - "lat": 35.53806, - "lon": -98.92139 - }, - "KCQB": { - "id": "KCQB", - "city": "Chandler, Chandler Municipal Airport", - "state": "OK", - "lat": 35.72389, - "lon": -96.82028 - }, - "KCSM": { - "id": "KCSM", - "city": "Clinton, Clinton-Sherman Airport", - "state": "OK", - "lat": 35.35667, - "lon": -99.20361 - }, - "KCUH": { - "id": "KCUH", - "city": "Cushing, Cushing Municipal Airport", - "state": "OK", - "lat": 35.94972, - "lon": -96.77278 - }, - "KDUA": { - "id": "KDUA", - "city": "Durant, Eaker Field Airport", - "state": "OK", - "lat": 33.94222, - "lon": -96.39444 - }, - "KDUC": { - "id": "KDUC", - "city": "Duncan, Halliburton Field Airport", - "state": "OK", - "lat": 34.47083, - "lon": -97.9599999 - }, - "KELK": { - "id": "KELK", - "city": "Elk City Regional Business Airport", - "state": "OK", - "lat": 35.4308, - "lon": -99.3943 - }, - "KEND": { - "id": "KEND", - "city": "Vance Air Force Base / Enid", - "state": "OK", - "lat": 36.3333299, - "lon": -97.91667 - }, - "KFDR": { - "id": "KFDR", - "city": "Frederick, Frederick Municipal Airport", - "state": "OK", - "lat": 34.34444, - "lon": -98.98306 - }, - "KFSI": { - "id": "KFSI", - "city": "Fort Sill", - "state": "OK", - "lat": 34.6, - "lon": -98.4 - }, - "KGAG": { - "id": "KGAG", - "city": "Gage, Gage Airport", - "state": "OK", - "lat": 36.29667, - "lon": -99.76889 - }, - "KGCM": { - "id": "KGCM", - "city": "Claremore, Claremore Regional Airport", - "state": "OK", - "lat": 36.29444, - "lon": -95.47972 - }, - "KGMJ": { - "id": "KGMJ", - "city": "Grove, Grove Municipal Airport", - "state": "OK", - "lat": 36.60528, - "lon": -94.73861 - }, - "KGOK": { - "id": "KGOK", - "city": "Guthrie, Guthrie Municipal Airport", - "state": "OK", - "lat": 35.85194, - "lon": -97.4075 - }, - "KGUY": { - "id": "KGUY", - "city": "Guymon / Guymon Municipal Airport", - "state": "OK", - "lat": 36.6816699, - "lon": -101.50528 - }, - "KGZL": { - "id": "KGZL", - "city": "Stigler", - "state": "OK", - "lat": 35.2891, - "lon": -95.0939 - }, - "KHBR": { - "id": "KHBR", - "city": "Hobart, Hobart Municipal Airport", - "state": "OK", - "lat": 34.98944, - "lon": -99.0525 - }, - "KHHW": { - "id": "KHHW", - "city": "Hugo Stan Stamper Municipal Airport", - "state": "OK", - "lat": 34.0348, - "lon": -95.5419 - }, - "KHMY": { - "id": "KHMY", - "city": "MULDROWARMY", - "state": "OK", - "lat": 35.02638, - "lon": -97.23163 - }, - "KHSD": { - "id": "KHSD", - "city": "Sundance Airport", - "state": "OK", - "lat": 35.60183, - "lon": -97.70616 - }, - "KJSV": { - "id": "KJSV", - "city": "Sallisaw, Sallisaw Municipal Airport", - "state": "OK", - "lat": 35.43806, - "lon": -94.80278 - }, - "KJWG": { - "id": "KJWG", - "city": "Watonga, Watonga Airport", - "state": "OK", - "lat": 35.86472, - "lon": -98.42083 - }, - "KLAW": { - "id": "KLAW", - "city": "Lawton, Lawton Municipal Airport", - "state": "OK", - "lat": 34.5575, - "lon": -98.41667 - }, - "KLTS": { - "id": "KLTS", - "city": "Altus Air Force Base", - "state": "OK", - "lat": 34.65, - "lon": -99.26667 - }, - "KMIO": { - "id": "KMIO", - "city": "Miami Regional Airport", - "state": "OK", - "lat": 36.90922, - "lon": -94.8875 - }, - "KMKO": { - "id": "KMKO", - "city": "Muskogee-Davis Regional Airport", - "state": "OK", - "lat": 35.65694, - "lon": -95.35972 - }, - "KMLC": { - "id": "KMLC", - "city": "McAlester, McAlester Regional Airport", - "state": "OK", - "lat": 34.8822199, - "lon": -95.78306 - }, - "KOJA": { - "id": "KOJA", - "city": "Weatherford, Thomas P Stafford Airport", - "state": "OK", - "lat": 35.54472, - "lon": -98.66833 - }, - "KOKC": { - "id": "KOKC", - "city": "Oklahoma City, Will Rogers World Airport", - "state": "OK", - "lat": 35.38861, - "lon": -97.60028 - }, - "KOKM": { - "id": "KOKM", - "city": "Okmulgee, Okmulgee Municipal Airport", - "state": "OK", - "lat": 35.6680599, - "lon": -95.94861 - }, - "KOUN": { - "id": "KOUN", - "city": "Norman / Max Westheimer", - "state": "OK", - "lat": 35.2435, - "lon": -97.4708 - }, - "KOWP": { - "id": "KOWP", - "city": "William R Pogue Municipal Airport", - "state": "OK", - "lat": 36.1753, - "lon": -96.1518 - }, - "KPNC": { - "id": "KPNC", - "city": "Ponca City, Ponca City Municipal Airport", - "state": "OK", - "lat": 36.7305599, - "lon": -97.09972 - }, - "KPVJ": { - "id": "KPVJ", - "city": "Pauls Valley, Pauls Valley Municipal Airport", - "state": "OK", - "lat": 34.71111, - "lon": -97.22333 - }, - "KPWA": { - "id": "KPWA", - "city": "Oklahoma City, Wiley Post Airport", - "state": "OK", - "lat": 35.54111, - "lon": -97.64667 - }, - "KRCE": { - "id": "KRCE", - "city": "Clarence E Page Municipal Airport", - "state": "OK", - "lat": 35.4880799, - "lon": -97.82356 - }, - "KRKR": { - "id": "KRKR", - "city": "Poteau, Robert S Kerr Airport", - "state": "OK", - "lat": 35.02167, - "lon": -94.62139 - }, - "KRQO": { - "id": "KRQO", - "city": "El Reno, El Reno Regional Airport", - "state": "OK", - "lat": 35.4724999, - "lon": -98.00556 - }, - "KRVS": { - "id": "KRVS", - "city": "Tulsa - Jones Jr. Airport", - "state": "OK", - "lat": 36.04255, - "lon": -95.99005 - }, - "KSNL": { - "id": "KSNL", - "city": "Shawnee, Shawnee Municipal Airport", - "state": "OK", - "lat": 35.35722, - "lon": -96.94278 - }, - "KSRE": { - "id": "KSRE", - "city": "Seminole, Seminole Municipal Airport", - "state": "OK", - "lat": 35.27444, - "lon": -96.675 - }, - "KSWO": { - "id": "KSWO", - "city": "Stillwater, Stillwater Regional Airport", - "state": "OK", - "lat": 36.16222, - "lon": -97.08917 - }, - "KTIK": { - "id": "KTIK", - "city": "Tinker Air Force Base", - "state": "OK", - "lat": 35.41667, - "lon": -97.38333 - }, - "KTQH": { - "id": "KTQH", - "city": "Tahlequah, Tahlequah Municipal Airport", - "state": "OK", - "lat": 35.92889, - "lon": -95.00444 - }, - "KTUL": { - "id": "KTUL", - "city": "Tulsa, Tulsa International Airport", - "state": "OK", - "lat": 36.1975, - "lon": -95.88639 - }, - "KWDG": { - "id": "KWDG", - "city": "Enid, Enid Woodring Regional Airport", - "state": "OK", - "lat": 36.37917, - "lon": -97.79111 - }, - "KWWR": { - "id": "KWWR", - "city": "Woodward, West Woodward Airport", - "state": "OK", - "lat": 36.43667, - "lon": -99.5211099 - }, - "KBKW": { - "id": "KBKW", - "city": "Beckley, Raleigh County Memorial Airport", - "state": "WV", - "lat": 37.795, - "lon": -81.12472 - }, - "KBLF": { - "id": "KBLF", - "city": "Bluefield, Mercer County Airport", - "state": "WV", - "lat": 37.29583, - "lon": -81.20778 - }, - "KCBE": { - "id": "KCBE", - "city": "Cumberland, Greater Cumberland Regional Airport", - "state": "WV", - "lat": 39.61528, - "lon": -78.76083 - }, - "KCKB": { - "id": "KCKB", - "city": "Clarksburg, Clarksburg Benedum Airport", - "state": "WV", - "lat": 39.3, - "lon": -80.22472 - }, - "KCRW": { - "id": "KCRW", - "city": "Charleston, Yeager Airport", - "state": "WV", - "lat": 38.37944, - "lon": -81.59139 - }, - "KEKN": { - "id": "KEKN", - "city": "Elkins, Elkins-Randolph County-Jennings Randolph Field", - "state": "WV", - "lat": 38.88528, - "lon": -79.85278 - }, - "KHLG": { - "id": "KHLG", - "city": "Wheeling, Wheeling Ohio County Airport", - "state": "WV", - "lat": 40.17028, - "lon": -80.64444 - }, - "KHTS": { - "id": "KHTS", - "city": "Huntington, Tri-State Airport", - "state": "WV", - "lat": 38.365, - "lon": -82.555 - }, - "KLWB": { - "id": "KLWB", - "city": "Lewisburg / Greenbrier", - "state": "WV", - "lat": 37.86667, - "lon": -80.4 - }, - "KMGW": { - "id": "KMGW", - "city": "Morgantown Municipal-Hart Field", - "state": "WV", - "lat": 39.64985, - "lon": -79.92065 - }, - "KMRB": { - "id": "KMRB", - "city": "Eastern WV Regional Airport/Shepherd Field", - "state": "WV", - "lat": 39.40372, - "lon": -77.975 - }, - "KPKB": { - "id": "KPKB", - "city": "Parkersburg, Mid-Ohio Valley Regional Airport", - "state": "WV", - "lat": 39.345, - "lon": -81.43917 - }, - "KBGF": { - "id": "KBGF", - "city": "Winchester Municipal Airport", - "state": "TN", - "lat": 35.1775, - "lon": -86.0662 - }, - "KBNA": { - "id": "KBNA", - "city": "Nashville, Nashville International Airport", - "state": "TN", - "lat": 36.11889, - "lon": -86.68917 - }, - "KCHA": { - "id": "KCHA", - "city": "Chattanooga, Lovell Field", - "state": "TN", - "lat": 35.03333, - "lon": -85.2 - }, - "KCKV": { - "id": "KCKV", - "city": "Clarksville Outlaw Field", - "state": "TN", - "lat": 36.61689, - "lon": -87.41174 - }, - "KCSV": { - "id": "KCSV", - "city": "Crossville, Crossville Memorial-Whitson Field Airport", - "state": "TN", - "lat": 35.95139, - "lon": -85.0849999 - }, - "KDKX": { - "id": "KDKX", - "city": "Knoxville Downtown Airport", - "state": "TN", - "lat": 35.96581, - "lon": -83.87169 - }, - "KDYR": { - "id": "KDYR", - "city": "Dyersburg, Dyersburg Municipal Airport", - "state": "TN", - "lat": 36, - "lon": -89.4 - }, - "KFYE": { - "id": "KFYE", - "city": "Somerville - Fayette County Airport", - "state": "TN", - "lat": 35.2061, - "lon": -89.3929 - }, - "KFYM": { - "id": "KFYM", - "city": "Fayetteville Municipal Airport", - "state": "TN", - "lat": 35.0597, - "lon": -86.5639999 - }, - "KGCY": { - "id": "KGCY", - "city": "Greeneville-Greene County Municipal Airport", - "state": "TN", - "lat": 36.19601, - "lon": -82.81099 - }, - "KGKT": { - "id": "KGKT", - "city": "Sevierville Gatlinburg - Pigeon Forge Airport", - "state": "TN", - "lat": 35.85681, - "lon": -83.53334 - }, - "KGZS": { - "id": "KGZS", - "city": "Pulaski Abernathy Field Airport", - "state": "TN", - "lat": 35.1537, - "lon": -87.0568 - }, - "KHZD": { - "id": "KHZD", - "city": "Huntingdon Carroll County Airport", - "state": "TN", - "lat": 36.08896, - "lon": -88.46538 - }, - "KJAU": { - "id": "KJAU", - "city": "Jacksboro Campbell County Airport", - "state": "TN", - "lat": 36.3341, - "lon": -84.163 - }, - "KJWN": { - "id": "KJWN", - "city": "John C Tune Airport", - "state": "TN", - "lat": 36.18521, - "lon": -86.88331 - }, - "KLUG": { - "id": "KLUG", - "city": "Ellington Airport", - "state": "TN", - "lat": 35.50697, - "lon": -86.80389 - }, - "KMBT": { - "id": "KMBT", - "city": "Murfreesboro Municipal Airport", - "state": "TN", - "lat": 35.87866, - "lon": -86.37749 - }, - "KMEM": { - "id": "KMEM", - "city": "Memphis International Airport", - "state": "TN", - "lat": 35.05644, - "lon": -89.98634 - }, - "KMKL": { - "id": "KMKL", - "city": "Jackson, McKellar-Sipes Regional Airport", - "state": "TN", - "lat": 35.59306, - "lon": -88.91667 - }, - "KMMI": { - "id": "KMMI", - "city": "Athens McMinn County Airport", - "state": "TN", - "lat": 35.3973, - "lon": -84.5626 - }, - "KAIK": { - "id": "KAIK", - "city": "Aiken Municipal Airport", - "state": "SC", - "lat": 33.649, - "lon": -81.685 - }, - "KAND": { - "id": "KAND", - "city": "Anderson, Anderson County Airport", - "state": "SC", - "lat": 34.49778, - "lon": -82.70972 - }, - "KAQX": { - "id": "KAQX", - "city": "Allendale County Airport", - "state": "SC", - "lat": 32.9951, - "lon": -81.2703 - }, - "KARW": { - "id": "KARW", - "city": "Beaufort County Airport", - "state": "SC", - "lat": 32.412, - "lon": -80.634 - }, - "KBBP": { - "id": "KBBP", - "city": "Marlboro County Jetport", - "state": "SC", - "lat": 34.622, - "lon": -79.734 - }, - "KBNL": { - "id": "KBNL", - "city": "Barnwell Regional Airport", - "state": "SC", - "lat": 33.258, - "lon": -81.388 - }, - "KCAE": { - "id": "KCAE", - "city": "Columbia, Columbia Metropolitan Airport", - "state": "SC", - "lat": 33.94194, - "lon": -81.11806 - }, - "KCDN": { - "id": "KCDN", - "city": "Camden Woodward Field", - "state": "SC", - "lat": 34.284, - "lon": -80.565 - }, - "KCEU": { - "id": "KCEU", - "city": "Clemson, Clemson-Oconee County Airport", - "state": "SC", - "lat": 34.67222, - "lon": -82.88139 - }, - "KCHS": { - "id": "KCHS", - "city": "Charleston, Charleston Air Force Base", - "state": "SC", - "lat": 32.89889, - "lon": -80.04056 - }, - "KCKI": { - "id": "KCKI", - "city": "Kingstree Williamsburg Regional Airport", - "state": "SC", - "lat": 33.717, - "lon": -79.857 - }, - "KCQW": { - "id": "KCQW", - "city": "Cheraw Municipal Lynch Bellinger Field", - "state": "SC", - "lat": 34.713, - "lon": -79.9569999 - }, - "KCRE": { - "id": "KCRE", - "city": "North Myrtle Beach Grand Strand Airport", - "state": "SC", - "lat": 33.81619, - "lon": -78.7204299 - }, - "KCUB": { - "id": "KCUB", - "city": "Columbia - Jim Hamilton L.B. Owens Airport", - "state": "SC", - "lat": 33.97083, - "lon": -80.99444 - }, - "KDCM": { - "id": "KDCM", - "city": "Chester Catawba Regional Airport", - "state": "SC", - "lat": 34.789, - "lon": -81.196 - }, - "KDYB": { - "id": "KDYB", - "city": "Summerville Airport", - "state": "SC", - "lat": 33.063, - "lon": -80.279 - }, - "KEOE": { - "id": "KEOE", - "city": "Newberry County Airport", - "state": "SC", - "lat": 34.309, - "lon": -81.64 - }, - "KFDW": { - "id": "KFDW", - "city": "Winnsboro/Fairfield County Airport", - "state": "SC", - "lat": 34.315, - "lon": -81.109 - }, - "KFLO": { - "id": "KFLO", - "city": "Florence - Florence Regional Airport", - "state": "SC", - "lat": 34.1877799, - "lon": -79.73083 - }, - "KGGE": { - "id": "KGGE", - "city": "Georgetown County Airport ", - "state": "SC", - "lat": 33.3117, - "lon": -79.3196 - }, - "KGMU": { - "id": "KGMU", - "city": "Greenville Downtown Airport", - "state": "SC", - "lat": 34.84873, - "lon": -82.35004 - }, - "KGRD": { - "id": "KGRD", - "city": "Greenwood, Greenwood County Airport", - "state": "SC", - "lat": 34.24722, - "lon": -82.15472 - }, - "KGSP": { - "id": "KGSP", - "city": "Greenville Spartanburg International Airport", - "state": "SC", - "lat": 34.90611, - "lon": -82.2125499 - }, - "KGYH": { - "id": "KGYH", - "city": "Greenville-Donaldson Center Airport", - "state": "SC", - "lat": 34.7583, - "lon": -82.3764 - }, - "KHVS": { - "id": "KHVS", - "city": "Hartsville Regional Airport", - "state": "SC", - "lat": 34.403, - "lon": -80.119 - }, - "KHXD": { - "id": "KHXD", - "city": "Hilton Head Island, Hilton Head Airport", - "state": "SC", - "lat": 32.21667, - "lon": -80.7 - }, - "KHYW": { - "id": "KHYW", - "city": "Conway Horry County Airport", - "state": "SC", - "lat": 33.829, - "lon": -79.122 - }, - "KJZI": { - "id": "KJZI", - "city": "Charleston Executive Airport", - "state": "SC", - "lat": 32.701, - "lon": -80.003 - }, - "KLKR": { - "id": "KLKR", - "city": "Lancaster County-mc Whirter Field", - "state": "SC", - "lat": 34.723, - "lon": -80.855 - }, - "KLQK": { - "id": "KLQK", - "city": "Pickens County Airport", - "state": "SC", - "lat": 34.80997, - "lon": -82.70289 - }, - "KLRO": { - "id": "KLRO", - "city": "Mount Pleasant Regional-Faison Field", - "state": "SC", - "lat": 32.898, - "lon": -79.783 - }, - "KLUX": { - "id": "KLUX", - "city": "Laurens County Airport", - "state": "SC", - "lat": 34.507, - "lon": -81.947 - }, - "KMAO": { - "id": "KMAO", - "city": "Marion County Airport", - "state": "SC", - "lat": 34.181, - "lon": -79.3349999 - }, - "KMKS": { - "id": "KMKS", - "city": "Moncks Corner Berkeley County", - "state": "SC", - "lat": 33.1855, - "lon": -80.0361999 - }, - "KMMT": { - "id": "KMMT", - "city": "McEntire Air National Guard Weather Facility Base", - "state": "SC", - "lat": 33.91667, - "lon": -80.8 - }, - "KMNI": { - "id": "KMNI", - "city": "Manning / Cooper Regional", - "state": "SC", - "lat": 33.5833299, - "lon": -80.2166699 - }, - "KMYR": { - "id": "KMYR", - "city": "Myrtle Beach International Airport", - "state": "SC", - "lat": 33.67975, - "lon": -78.92833 - }, - "KNBC": { - "id": "KNBC", - "city": "Beaufort, Marine Corps Air Station", - "state": "SC", - "lat": 32.4936099, - "lon": -80.7030599 - }, - "KOGB": { - "id": "KOGB", - "city": "Orangeburg, Orangeburg Municipal Airport", - "state": "SC", - "lat": 33.46389, - "lon": -80.85361 - }, - "KRBW": { - "id": "KRBW", - "city": "Walterboro Lowcountry Regional Airport", - "state": "SC", - "lat": 32.921, - "lon": -80.641 - }, - "KSMS": { - "id": "KSMS", - "city": "Sumter Airport", - "state": "SC", - "lat": 33.995, - "lon": -80.361 - }, - "KSPA": { - "id": "KSPA", - "city": "Spartanburg Memorial", - "state": "SC", - "lat": 34.91667, - "lon": -81.95 - }, - "KSSC": { - "id": "KSSC", - "city": "Shaw Air Force Base", - "state": "SC", - "lat": 33.96667, - "lon": -80.48333 - }, - "KUDG": { - "id": "KUDG", - "city": "Darlington, Darlington County Jetport Airport", - "state": "SC", - "lat": 34.44917, - "lon": -79.89028 - }, - "KUZA": { - "id": "KUZA", - "city": "Rock Hill, Rock Hill - York County Airport", - "state": "SC", - "lat": 34.98389, - "lon": -81.05583 - }, - "KXNO": { - "id": "KXNO", - "city": "North Air Force Auxiliary Field", - "state": "SC", - "lat": 33.60949, - "lon": -81.08118 - }, - "KAIG": { - "id": "KAIG", - "city": "Langlade County Airport", - "state": "WI", - "lat": 45.15659, - "lon": -89.11144 - }, - "KARV": { - "id": "KARV", - "city": "Minocqua/Woodruff, Lakeland Airport/Noble F. Lee Memorial Field", - "state": "WI", - "lat": 45.93333, - "lon": -89.73333 - }, - "KASX": { - "id": "KASX", - "city": "John F Kennedy Memorial Airport", - "state": "WI", - "lat": 46.54679, - "lon": -90.91841 - }, - "KATW": { - "id": "KATW", - "city": "Appleton-Outagamie", - "state": "WI", - "lat": 44.2595, - "lon": -88.51567 - }, - "KAUW": { - "id": "KAUW", - "city": "Wausau Downtown Airport", - "state": "WI", - "lat": 44.92759, - "lon": -89.62512 - }, - "KBCK": { - "id": "KBCK", - "city": "Black River Falls Area Airport", - "state": "WI", - "lat": 44.24996, - "lon": -90.84999 - }, - "KBUU": { - "id": "KBUU", - "city": "Burlington Municipal Airport", - "state": "WI", - "lat": 42.69088, - "lon": -88.308 - }, - "KCLI": { - "id": "KCLI", - "city": "Clintonville Municipal Airport", - "state": "WI", - "lat": 44.61526, - "lon": -88.73129 - }, - "KCMY": { - "id": "KCMY", - "city": "Sparta, Sparta / Fort McCoy Airport", - "state": "WI", - "lat": 43.9583299, - "lon": -90.73778 - }, - "KCWA": { - "id": "KCWA", - "city": "Mosinee", - "state": "WI", - "lat": 44.77944, - "lon": -89.67098 - }, - "KDLL": { - "id": "KDLL", - "city": "Baraboo Wisconsin Dells Airport", - "state": "WI", - "lat": 43.52372, - "lon": -89.77345 - }, - "KEAU": { - "id": "KEAU", - "city": "Chippewa Valley Regional Airport", - "state": "WI", - "lat": 44.86668, - "lon": -91.488 - }, - "KEFT": { - "id": "KEFT", - "city": "Monroe Municipal Airport", - "state": "WI", - "lat": 42.61959, - "lon": -89.59309 - }, - "KEGV": { - "id": "KEGV", - "city": "Eagle River Union Airport", - "state": "WI", - "lat": 45.9309299, - "lon": -89.26702 - }, - "KENW": { - "id": "KENW", - "city": "Kenosha, Kenosha Regional Airport", - "state": "WI", - "lat": 42.595, - "lon": -87.9380599 - }, - "KETB": { - "id": "KETB", - "city": "West Bend Municipal Airport", - "state": "WI", - "lat": 43.42256, - "lon": -88.1326 - }, - "KEZS": { - "id": "KEZS", - "city": "Shawano Municipal Airport", - "state": "WI", - "lat": 44.787, - "lon": -88.56 - }, - "KFLD": { - "id": "KFLD", - "city": "Fond Du Lac County Airport", - "state": "WI", - "lat": 43.76955, - "lon": -88.49072 - }, - "KGRB": { - "id": "KGRB", - "city": "Green Bay, Austin Straubel International Airport", - "state": "WI", - "lat": 44.4794399, - "lon": -88.13667 - }, - "KHYR": { - "id": "KHYR", - "city": "Sawyer County Airport", - "state": "WI", - "lat": 46.03029, - "lon": -91.44259 - }, - "KISW": { - "id": "KISW", - "city": "Wisconsin Rapids, Alexander Field South Wood County Airport", - "state": "WI", - "lat": 44.35917, - "lon": -89.83694 - }, - "KJVL": { - "id": "KJVL", - "city": "Janesville-Rock County", - "state": "WI", - "lat": 42.62135, - "lon": -89.04186 - }, - "KLNL": { - "id": "KLNL", - "city": "Land O' Lakes, Kings Land O' Lakes Airport", - "state": "WI", - "lat": 46.1538899, - "lon": -89.21194 - }, - "KLNR": { - "id": "KLNR", - "city": "Lone Rock Tri-County Regional Airport", - "state": "WI", - "lat": 43.21108, - "lon": -90.18735 - }, - "KLSE": { - "id": "KLSE", - "city": "La Crosse - La Crosse Regional Airport", - "state": "WI", - "lat": 43.87944, - "lon": -91.25667 - }, - "KLUM": { - "id": "KLUM", - "city": "Menomonie Municipal Airport-Score Field", - "state": "WI", - "lat": 44.89363, - "lon": -91.86652 - }, - "KMDZ": { - "id": "KMDZ", - "city": "Taylor County Airport", - "state": "WI", - "lat": 45.10462, - "lon": -90.30253 - }, - "KMFI": { - "id": "KMFI", - "city": "Marshfield, Marshfield Municipal Airport", - "state": "WI", - "lat": 44.63806, - "lon": -90.1875 - }, - "KMKE": { - "id": "KMKE", - "city": "Milwaukee, General Mitchell International Airport", - "state": "WI", - "lat": 42.955, - "lon": -87.9044399 - }, - "KMRJ": { - "id": "KMRJ", - "city": "Iowa County Airport", - "state": "WI", - "lat": 42.88754, - "lon": -90.23147 - }, - "KMSN": { - "id": "KMSN", - "city": "Madison, Dane County Regional-Truax Field", - "state": "WI", - "lat": 43.14056, - "lon": -89.34528 - }, - "KMTW": { - "id": "KMTW", - "city": "Manitowoc, Manitowoc County Airport", - "state": "WI", - "lat": 44.13333, - "lon": -87.68333 - }, - "KMWC": { - "id": "KMWC", - "city": "Milwaukee-Timmerman", - "state": "WI", - "lat": 43.10961, - "lon": -88.03048 - }, - "KOCQ": { - "id": "KOCQ", - "city": "Oconto J. Douglas Bake Municipal Airport", - "state": "WI", - "lat": 44.8742, - "lon": -87.9096 - }, - "KOEO": { - "id": "KOEO", - "city": "L O Simenstad Municipal Airport", - "state": "WI", - "lat": 45.31084, - "lon": -92.6948 - }, - "KOLG": { - "id": "KOLG", - "city": "Solon Springs Municipal Airport", - "state": "WI", - "lat": 46.3148, - "lon": -91.8164 - }, - "KOSH": { - "id": "KOSH", - "city": "Wittman Regional Airport", - "state": "WI", - "lat": 43.96701, - "lon": -88.55814 - }, - "KOVS": { - "id": "KOVS", - "city": "Boscobel, Boscobel Airport", - "state": "WI", - "lat": 43.15611, - "lon": -90.6775 - }, - "KPBH": { - "id": "KPBH", - "city": "Phillips / Price County", - "state": "WI", - "lat": 45.7, - "lon": -90.4 - }, - "KPCZ": { - "id": "KPCZ", - "city": "Waupaca Municipal Airport", - "state": "WI", - "lat": 44.33425, - "lon": -89.02023 - }, - "KPDC": { - "id": "KPDC", - "city": "Prairie Du Chien Municipal Airport", - "state": "WI", - "lat": 43.01938, - "lon": -91.12112 - }, - "KPVB": { - "id": "KPVB", - "city": "Platteville Municipal Airport", - "state": "WI", - "lat": 42.69092, - "lon": -90.4412399 - }, - "KRAC": { - "id": "KRAC", - "city": "Racine, Batten International Airport", - "state": "WI", - "lat": 42.75861, - "lon": -87.81778 - }, - "KRCX": { - "id": "KRCX", - "city": "Ladysmith - Rusk County Airport", - "state": "WI", - "lat": 45.4935, - "lon": -90.9985 - }, - "KRGK": { - "id": "KRGK", - "city": "Red Wing - Red Wing Regional Airport", - "state": "WI", - "lat": 44.5926, - "lon": -92.48439 - }, - "KRHI": { - "id": "KRHI", - "city": "Rhinelander, Rhinelander-Oneida County Airport", - "state": "WI", - "lat": 45.63167, - "lon": -89.48222 - }, - "KRNH": { - "id": "KRNH", - "city": "New Richmond Municipal Airport", - "state": "WI", - "lat": 45.14762, - "lon": -92.53349 - }, - "KRPD": { - "id": "KRPD", - "city": "Rice Lake, Rice Lake Regional-Carl's Field Airport", - "state": "WI", - "lat": 45.4180599, - "lon": -91.77361 - }, - "KRRL": { - "id": "KRRL", - "city": "Merrill, Merrill Municipal Airport", - "state": "WI", - "lat": 45.19844, - "lon": -89.70996 - }, - "KRYV": { - "id": "KRYV", - "city": "Watertown", - "state": "WI", - "lat": 43.17016, - "lon": -88.72497 - }, - "KRZN": { - "id": "KRZN", - "city": "Siren, Burnett County Airport", - "state": "WI", - "lat": 45.82278, - "lon": -92.3725 - }, - "KSBM": { - "id": "KSBM", - "city": "Sheboygan County Memorial Airport", - "state": "WI", - "lat": 43.77483, - "lon": -87.84897 - }, - "KSTE": { - "id": "KSTE", - "city": "Stevens Point Municipal Airport", - "state": "WI", - "lat": 44.54371, - "lon": -89.53468 - }, - "KSUE": { - "id": "KSUE", - "city": "Door County Cherryland Airport", - "state": "WI", - "lat": 44.83941, - "lon": -87.42188 - }, - "KSUW": { - "id": "KSUW", - "city": "Richard I. Bong Airport", - "state": "WI", - "lat": 46.68335, - "lon": -92.09254 - }, - "KTKV": { - "id": "KTKV", - "city": "Tomahawk Regional Airport", - "state": "WI", - "lat": 45.46801, - "lon": -89.80962 - }, - "KUBE": { - "id": "KUBE", - "city": "Cumberland", - "state": "WI", - "lat": 45.506, - "lon": -91.9811 - }, - "KUES": { - "id": "KUES", - "city": "Waukesha County Airport", - "state": "WI", - "lat": 43.04245, - "lon": -88.24607 - }, - "KUNU": { - "id": "KUNU", - "city": "Juneau, Dodge County Airport", - "state": "WI", - "lat": 43.42667, - "lon": -88.7033299 - }, - "KVOK": { - "id": "KVOK", - "city": "Volk / Camp Douglas", - "state": "WI", - "lat": 43.93333, - "lon": -90.26667 - }, - "KACY": { - "id": "KACY", - "city": "Atlantic City, Atlantic City International Airport", - "state": "NJ", - "lat": 39.45202, - "lon": -74.56699 - }, - "KBLM": { - "id": "KBLM", - "city": "Belmar-Farmingdale", - "state": "NJ", - "lat": 40.18333, - "lon": -74.13333 - }, - "KCDW": { - "id": "KCDW", - "city": "Caldwell, Essex County Airport", - "state": "NJ", - "lat": 40.87639, - "lon": -74.28306 - }, - "KEWR": { - "id": "KEWR", - "city": "Newark, Newark International Airport", - "state": "NJ", - "lat": 40.6825, - "lon": -74.16944 - }, - "KFWN": { - "id": "KFWN", - "city": "Sussex, Sussex Airport", - "state": "NJ", - "lat": 41.19925, - "lon": -74.62594 - }, - "KLDJ": { - "id": "KLDJ", - "city": "Linden Airport", - "state": "NJ", - "lat": 40.6174, - "lon": -74.2446 - }, - "KMIV": { - "id": "KMIV", - "city": "Millville, Millville Municipal Airport", - "state": "NJ", - "lat": 39.36623, - "lon": -75.0778 - }, - "KMJX": { - "id": "KMJX", - "city": "Miller Air Park", - "state": "NJ", - "lat": 39.927, - "lon": -74.292 - }, - "KMMU": { - "id": "KMMU", - "city": "Morristown Municipal", - "state": "NJ", - "lat": 40.8, - "lon": -74.41667 - }, - "KNEL": { - "id": "KNEL", - "city": "Lakehurst Naval Air Station", - "state": "NJ", - "lat": 40.03661, - "lon": -74.35251 - }, - "KOBI": { - "id": "KOBI", - "city": "CAPE MAY", - "state": "NJ", - "lat": 39.2191, - "lon": -74.7948 - }, - "KSMQ": { - "id": "KSMQ", - "city": "Somerville, Somerset Airport", - "state": "NJ", - "lat": 40.6240499, - "lon": -74.66898 - }, - "KTEB": { - "id": "KTEB", - "city": "Teterboro, Teterboro Airport", - "state": "NJ", - "lat": 40.85889, - "lon": -74.05667 - }, - "KTTN": { - "id": "KTTN", - "city": "Trenton, Mercer County Airport", - "state": "NJ", - "lat": 40.27639, - "lon": -74.81639 - }, - "KVAY": { - "id": "KVAY", - "city": "Mount Holly, South Jersey Regional Airport", - "state": "NJ", - "lat": 39.94076, - "lon": -74.84071 - }, - "KWRI": { - "id": "KWRI", - "city": "Mcguire Air Force Base", - "state": "NJ", - "lat": 40.01667, - "lon": -74.6 - }, - "KWWD": { - "id": "KWWD", - "city": "Wildwood, Cape May County Airport", - "state": "NJ", - "lat": 39.01667, - "lon": -74.91667 - }, - "KELO": { - "id": "KELO", - "city": "Ely, Ely Municipal Airport", - "state": "MN", - "lat": 47.81667, - "lon": -91.83333 - }, - "KEVM": { - "id": "KEVM", - "city": "Eveleth-Virginia Municipal Airport", - "state": "MN", - "lat": 47.4274, - "lon": -92.49717 - }, - "KFBL": { - "id": "KFBL", - "city": "Faribault, Faribault Municipal Airport", - "state": "MN", - "lat": 44.32983, - "lon": -93.31186 - }, - "KFCM": { - "id": "KFCM", - "city": "Minneapolis - Flying Cloud Airport", - "state": "MN", - "lat": 44.83217, - "lon": -93.47051 - }, - "KFFM": { - "id": "KFFM", - "city": "Fergus Falls Municipal Airport-Einar Mickel", - "state": "MN", - "lat": 46.28655, - "lon": -96.15338 - }, - "KFGN": { - "id": "KFGN", - "city": "Flag Island", - "state": "MN", - "lat": 49.31667, - "lon": -94.9 - }, - "KFKA": { - "id": "KFKA", - "city": "Preston, Fillmore County Airport", - "state": "MN", - "lat": 43.67701, - "lon": -92.17422 - }, - "KFOZ": { - "id": "KFOZ", - "city": "Bigfork Municipal Airport", - "state": "MN", - "lat": 47.78317, - "lon": -93.65326 - }, - "KFRM": { - "id": "KFRM", - "city": "Fairmont, Fairmont Municipal Airport", - "state": "MN", - "lat": 43.65, - "lon": -94.41667 - }, - "KFSE": { - "id": "KFSE", - "city": "Fosston, Fosston Municipal Airport", - "state": "MN", - "lat": 47.59278, - "lon": -95.77333 - }, - "KGDB": { - "id": "KGDB", - "city": "Granite Falls, Granite Falls Municipal Airport/Lenzen-Roe Memorial Field", - "state": "MN", - "lat": 44.75306, - "lon": -95.55583 - }, - "KGHW": { - "id": "KGHW", - "city": "Glenwood Municipal Airport", - "state": "MN", - "lat": 45.64564, - "lon": -95.31876 - }, - "KGNA": { - "id": "KGNA", - "city": "Grand Marais, The Bay of Grand Marais", - "state": "MN", - "lat": 47.7472, - "lon": -90.3443999 - }, - "KGPZ": { - "id": "KGPZ", - "city": "Grand Rapids, Grand Rapids/Itasca County Airport-Gordon Newstrom Field", - "state": "MN", - "lat": 47.21667, - "lon": -93.51667 - }, - "KGYL": { - "id": "KGYL", - "city": "Glencoe Municipal Airport", - "state": "MN", - "lat": 44.7588, - "lon": -94.0905 - }, - "KHCD": { - "id": "KHCD", - "city": "Hutchinson, Hutchinson Municipal Airport-Butler Field", - "state": "MN", - "lat": 44.85961, - "lon": -94.38551 - }, - "KHCO": { - "id": "KHCO", - "city": "Hallock Municipal Airport", - "state": "MN", - "lat": 48.75245, - "lon": -96.93759 - }, - "KHIB": { - "id": "KHIB", - "city": "Chisholm-Hibbing Airport", - "state": "MN", - "lat": 47.38039, - "lon": -92.83245 - }, - "KHZX": { - "id": "KHZX", - "city": "Mc Gregor - Isedor Iverson Airport", - "state": "MN", - "lat": 46.61904, - "lon": -93.31267 - }, - "KINL": { - "id": "KINL", - "city": "Falls International Airport", - "state": "MN", - "lat": 48.55944, - "lon": -93.39556 - }, - "KJKJ": { - "id": "KJKJ", - "city": "Moorhead Municipal Airport", - "state": "MN", - "lat": 46.8404, - "lon": -96.65442 - }, - "KJMR": { - "id": "KJMR", - "city": "Mora Municipal Airport", - "state": "MN", - "lat": 45.88863, - "lon": -93.26901 - }, - "KJYG": { - "id": "KJYG", - "city": "St. James Municipal Airport", - "state": "MN", - "lat": 43.98558, - "lon": -94.55299 - }, - "KLJF": { - "id": "KLJF", - "city": "Litchfield Municipal Airport", - "state": "MN", - "lat": 45.09485, - "lon": -94.50837 - }, - "KLVN": { - "id": "KLVN", - "city": "Minneapolis, Airlake Airport", - "state": "MN", - "lat": 44.62778, - "lon": -93.22806 - }, - "KLXL": { - "id": "KLXL", - "city": "Little Falls, Little Falls/Morrison County Airport-Lindbergh Field", - "state": "MN", - "lat": 45.95, - "lon": -94.35 - }, - "KLYV": { - "id": "KLYV", - "city": "Quentin Aanenson Field Airport", - "state": "MN", - "lat": 43.62166, - "lon": -96.2139399 - }, - "KMGG": { - "id": "KMGG", - "city": "Maple Lake, Maple Lake Municipal Airport", - "state": "MN", - "lat": 45.2353499, - "lon": -93.98959 - }, - "KMIC": { - "id": "KMIC", - "city": "Minneapolis, Crystal Airport", - "state": "MN", - "lat": 45.0625, - "lon": -93.35083 - }, - "KMJQ": { - "id": "KMJQ", - "city": "Jackson, Jackson Municipal Airport", - "state": "MN", - "lat": 43.65, - "lon": -94.98333 - }, - "KMKT": { - "id": "KMKT", - "city": "Mankato, Mankato Regional Airport", - "state": "MN", - "lat": 44.21667, - "lon": -93.91667 - }, - "KMML": { - "id": "KMML", - "city": "Marshall, Southwest Minnesota Regional Airport - Marshall/Ryan Field", - "state": "MN", - "lat": 44.45, - "lon": -95.81667 - }, - "KMOX": { - "id": "KMOX", - "city": "Morris, Morris Municipal Airport", - "state": "MN", - "lat": 45.56667, - "lon": -95.9666699 - }, - "KMSP": { - "id": "KMSP", - "city": "Minneapolis, Minneapolis-St. Paul International Airport", - "state": "MN", - "lat": 44.88306, - "lon": -93.22889 - }, - "KMVE": { - "id": "KMVE", - "city": "Montevideo-Chippewa County Airport", - "state": "MN", - "lat": 44.96749, - "lon": -95.71159 - }, - "KMWM": { - "id": "KMWM", - "city": "Windom Municipal Airport", - "state": "MN", - "lat": 43.90999, - "lon": -95.10723 - }, - "KMZH": { - "id": "KMZH", - "city": "Moose Lake Carlton County Airport", - "state": "MN", - "lat": 46.41632, - "lon": -92.80491 - }, - "KONA": { - "id": "KONA", - "city": "Winona, Winona Municipal Airport-Max Conrad Field", - "state": "MN", - "lat": 44.0833299, - "lon": -91.7 - }, - "KORB": { - "id": "KORB", - "city": "Orr Regional Airport", - "state": "MN", - "lat": 48.0170699, - "lon": -92.85376 - }, - "KOTG": { - "id": "KOTG", - "city": "Worthington, Worthington Municipal Airport", - "state": "MN", - "lat": 43.65, - "lon": -95.58333 - }, - "KOVL": { - "id": "KOVL", - "city": "Olivia Regional Airport", - "state": "MN", - "lat": 44.77923, - "lon": -95.03033 - }, - "KOWA": { - "id": "KOWA", - "city": "Owatonna Degner Regional Airport", - "state": "MN", - "lat": 44.11907, - "lon": -93.25687 - }, - "KPEX": { - "id": "KPEX", - "city": "Paynesville, Paynesville Municipal Airport", - "state": "MN", - "lat": 45.37247, - "lon": -94.73878 - }, - "KPKD": { - "id": "KPKD", - "city": "Park Rapids Municipal Airport", - "state": "MN", - "lat": 46.8996799, - "lon": -95.06681 - }, - "KPNM": { - "id": "KPNM", - "city": "Princeton", - "state": "MN", - "lat": 45.56425, - "lon": -93.6080099 - }, - "KPWC": { - "id": "KPWC", - "city": "Pine River Regional Airport", - "state": "MN", - "lat": 46.72654, - "lon": -94.38485 - }, - "KROS": { - "id": "KROS", - "city": "Rush City Regional Airport", - "state": "MN", - "lat": 45.69628, - "lon": -92.95424 - }, - "KROX": { - "id": "KROX", - "city": "Roseau, Roseau Municipal Airport/Rudy Billberg Field", - "state": "MN", - "lat": 48.85, - "lon": -95.7 - }, - "KRRT": { - "id": "KRRT", - "city": "Warroad International Memorial Airport", - "state": "MN", - "lat": 48.93183, - "lon": -95.3404599 - }, - "KRST": { - "id": "KRST", - "city": "Rochester, Rochester International Airport", - "state": "MN", - "lat": 43.90417, - "lon": -92.49167 - }, - "KRWF": { - "id": "KRWF", - "city": "Redwood Falls Municipal Airport", - "state": "MN", - "lat": 44.54828, - "lon": -95.08042 - }, - "KSAZ": { - "id": "KSAZ", - "city": "Staples, Staples Municipal Airport", - "state": "MN", - "lat": 46.38083, - "lon": -94.80667 - }, - "KSGS": { - "id": "KSGS", - "city": "South St. Paul Municipal-Richard E. Flemi", - "state": "MN", - "lat": 44.86006, - "lon": -93.03203 - }, - "KSTC": { - "id": "KSTC", - "city": "St. Cloud Regional Airport", - "state": "MN", - "lat": 45.54415, - "lon": -94.05165 - }, - "KSTP": { - "id": "KSTP", - "city": "Downtown Holman Field", - "state": "MN", - "lat": 44.93237, - "lon": -93.05588 - }, - "KSYN": { - "id": "KSYN", - "city": "Stanton Airfield", - "state": "MN", - "lat": 44.4736199, - "lon": -93.01448 - }, - "KTKC": { - "id": "KTKC", - "city": "Tracy, Tracy Municipal Airport", - "state": "MN", - "lat": 44.24951, - "lon": -95.61189 - }, - "KTOB": { - "id": "KTOB", - "city": "Dodge Center Airport", - "state": "MN", - "lat": 44.02026, - "lon": -92.8295 - }, - "KTVF": { - "id": "KTVF", - "city": "Thief River Falls, Thief River Falls Regional Airport", - "state": "MN", - "lat": 48.06667, - "lon": -96.18333 - }, - "KTWM": { - "id": "KTWM", - "city": "Two Harbors", - "state": "MN", - "lat": 47.05, - "lon": -91.75 - }, - "KULM": { - "id": "KULM", - "city": "New Ulm Municipal Airport", - "state": "MN", - "lat": 44.32274, - "lon": -94.50244 - }, - "KVVV": { - "id": "KVVV", - "city": "Ortonville, Ortonville Muncipal-Martinson Field Airport", - "state": "MN", - "lat": 45.30556, - "lon": -96.42444 - }, - "KVWU": { - "id": "KVWU", - "city": "Waskish Municipal Airport", - "state": "MN", - "lat": 48.15014, - "lon": -94.512 - }, - "KXVG": { - "id": "KXVG", - "city": "Longville, Longville Municipal Airport", - "state": "MN", - "lat": 46.99028, - "lon": -94.20389 - }, - "PCKY": { - "id": "PCKY", - "city": "Pacific Creek at Moran, WY", - "state": "WY", - "lat": 43.8502777, - "lon": -110.5177777 - }, - "KBCE": { - "id": "KBCE", - "city": "Bryce Canyon Airport", - "state": "UT", - "lat": 37.7012799, - "lon": -112.14897 - }, - "KBDG": { - "id": "KBDG", - "city": "Blanding Municipal Airport", - "state": "UT", - "lat": 37.586, - "lon": -109.482 - }, - "KBMC": { - "id": "KBMC", - "city": "Brigham City Regional Airport", - "state": "UT", - "lat": 41.5464, - "lon": -112.0601 - }, - "KCDC": { - "id": "KCDC", - "city": "Cedar City Municipal Airport", - "state": "UT", - "lat": 37.70675, - "lon": -113.09695 - }, - "KCNY": { - "id": "KCNY", - "city": "Moab, Canyonlands Field", - "state": "UT", - "lat": 38.76, - "lon": -109.74472 - }, - "KDPG": { - "id": "KDPG", - "city": "Michael Army Airfield - Dugway Proving Ground", - "state": "UT", - "lat": 40.18376, - "lon": -112.9217 - }, - "KDTA": { - "id": "KDTA", - "city": "Delta, Delta Municipal Airport", - "state": "UT", - "lat": 39.38333, - "lon": -112.50967 - }, - "KENV": { - "id": "KENV", - "city": "Wendover Airport", - "state": "UT", - "lat": 40.72056, - "lon": -114.03583 - }, - "KFOM": { - "id": "KFOM", - "city": "Fillmore", - "state": "UT", - "lat": 38.95814, - "lon": -112.36314 - }, - "KHCR": { - "id": "KHCR", - "city": "Heber Valley Airport", - "state": "UT", - "lat": 40.47742, - "lon": -111.43295 - }, - "KHIF": { - "id": "KHIF", - "city": "Hill Air Force Base", - "state": "UT", - "lat": 41.11112, - "lon": -111.96229 - }, - "KHVE": { - "id": "KHVE", - "city": "Hanksville", - "state": "UT", - "lat": 38.418037, - "lon": -110.704038 - }, - "KKNB": { - "id": "KKNB", - "city": "KANAB MUNICIPAL AIRPORT", - "state": "UT", - "lat": 37.01, - "lon": -112.53 - }, - "KLGU": { - "id": "KLGU", - "city": "Logan-Cache Airport", - "state": "UT", - "lat": 41.78652, - "lon": -111.85187 - }, - "KMLF": { - "id": "KMLF", - "city": "Milford Municipal Airport", - "state": "UT", - "lat": 38.42252, - "lon": -113.01089 - }, - "KOGD": { - "id": "KOGD", - "city": "Ogden-Hinckley Airport", - "state": "UT", - "lat": 41.19406, - "lon": -112.01681 - }, - "KPUC": { - "id": "KPUC", - "city": "Price - Carbon County Regional Airport", - "state": "UT", - "lat": 39.60886, - "lon": -110.75548 - }, - "KPVU": { - "id": "KPVU", - "city": "Provo Municipal Airport", - "state": "UT", - "lat": 40.2239, - "lon": -111.7253 - }, - "KRIF": { - "id": "KRIF", - "city": "Richfield Municipal Airport", - "state": "UT", - "lat": 38.73411, - "lon": -112.10158 - }, - "KSGU": { - "id": "KSGU", - "city": "St George Regional Airport", - "state": "UT", - "lat": 37.0451, - "lon": -113.50561 - }, - "KSLC": { - "id": "KSLC", - "city": "Salt Lake City, Salt Lake City International Airport", - "state": "UT", - "lat": 40.77069, - "lon": -111.96503 - }, - "KSPK": { - "id": "KSPK", - "city": "Spanish Fork Municipal Airport", - "state": "UT", - "lat": 40.145, - "lon": -111.6677 - }, - "KSVR": { - "id": "KSVR", - "city": "South Valley Regional Airport", - "state": "UT", - "lat": 40.6196, - "lon": -111.99016 - }, - "KTVY": { - "id": "KTVY", - "city": "Bolinder Field-Tooele Valley Airport", - "state": "UT", - "lat": 40.61269, - "lon": -112.35362 - }, - "KVEL": { - "id": "KVEL", - "city": "Vernal Airport", - "state": "UT", - "lat": 40.44295, - "lon": -109.51273 - }, - "KAAO": { - "id": "KAAO", - "city": "Wichita Jabara Airport", - "state": "KS", - "lat": 37.74969, - "lon": -97.21908 - }, - "KADT": { - "id": "KADT", - "city": "Atwood-Rawlins County City-County Airport", - "state": "KS", - "lat": 39.84034, - "lon": -101.04248 - }, - "KBEC": { - "id": "KBEC", - "city": "Beech Factory Airport", - "state": "KS", - "lat": 37.69392, - "lon": -97.21492 - }, - "KCBK": { - "id": "KCBK", - "city": "Shalz Field Airport", - "state": "KS", - "lat": 39.42746, - "lon": -101.04662 - }, - "KCFV": { - "id": "KCFV", - "city": "Coffeyville, Coffeyville Municipal Airport", - "state": "KS", - "lat": 37.09111, - "lon": -95.56639 - }, - "KCNK": { - "id": "KCNK", - "city": "Concordia, Blosser Municipal Airport", - "state": "KS", - "lat": 39.55139, - "lon": -97.65056 - }, - "KCNU": { - "id": "KCNU", - "city": "Chanute, Chanute Martin Johnson Airport", - "state": "KS", - "lat": 37.67028, - "lon": -95.48417 - }, - "KDDC": { - "id": "KDDC", - "city": "Dodge City, Dodge City Regional Airport", - "state": "KS", - "lat": 37.77278, - "lon": -99.96972 - }, - "KEGT": { - "id": "KEGT", - "city": "WELLINGTON", - "state": "KS", - "lat": 37.32361, - "lon": -97.38834 - }, - "KEHA": { - "id": "KEHA", - "city": "Elkhart, Elkhart-Morton County Airport", - "state": "KS", - "lat": 37, - "lon": -101.88333 - }, - "KEMP": { - "id": "KEMP", - "city": "Emporia, Emporia Municipal Airport", - "state": "KS", - "lat": 38.32889, - "lon": -96.19389 - }, - "KEQA": { - "id": "KEQA", - "city": "El Dorado Captain Jack Thomas Airport", - "state": "KS", - "lat": 37.77534, - "lon": -96.81449 - }, - "KEWK": { - "id": "KEWK", - "city": "Newton, Newton City/County Airport", - "state": "KS", - "lat": 38.05, - "lon": -97.28333 - }, - "KFOE": { - "id": "KFOE", - "city": "Topeka, Forbes Field", - "state": "KS", - "lat": 38.94139, - "lon": -95.65056 - }, - "KFRI": { - "id": "KFRI", - "city": "Fort Riley - Marshall AAF", - "state": "KS", - "lat": 39.05586, - "lon": -96.76166 - }, - "KFSK": { - "id": "KFSK", - "city": "FORT SCOTT", - "state": "KS", - "lat": 37.79833, - "lon": -94.76933 - }, - "KGBD": { - "id": "KGBD", - "city": "Great Bend, Great Bend Municipal Airport", - "state": "KS", - "lat": 38.35, - "lon": -98.86667 - }, - "KGCK": { - "id": "KGCK", - "city": "Garden City Regional Airport", - "state": "KS", - "lat": 37.9275, - "lon": -100.72444 - }, - "KGLD": { - "id": "KGLD", - "city": "Goodland, Renner Field", - "state": "KS", - "lat": 39.3675, - "lon": -101.69306 - }, - "KHLC": { - "id": "KHLC", - "city": "Hill City, Hill City Municipal Airport", - "state": "KS", - "lat": 39.37472, - "lon": -99.82972 - }, - "KHQG": { - "id": "KHQG", - "city": "Hugoton Municipal Airport", - "state": "KS", - "lat": 37.16308, - "lon": -101.37052 - }, - "KHUT": { - "id": "KHUT", - "city": "Hutchinson, Hutchinson Municipal Airport", - "state": "KS", - "lat": 38.06806, - "lon": -97.86056 - }, - "KHYS": { - "id": "KHYS", - "city": "Hays, Hays Regional Airport", - "state": "KS", - "lat": 38.85, - "lon": -99.26667 - }, - "KIAB": { - "id": "KIAB", - "city": "McConnell Air Force Base", - "state": "KS", - "lat": 37.61667, - "lon": -97.26667 - }, - "KICT": { - "id": "KICT", - "city": "Wichita - Wichita Dwight D. Eisenhower National Airport", - "state": "KS", - "lat": 37.64722, - "lon": -97.42944 - }, - "KIDP": { - "id": "KIDP", - "city": "INDEPENDENCE", - "state": "KS", - "lat": 37.1584, - "lon": -95.7784 - }, - "KIXD": { - "id": "KIXD", - "city": "Olathe, New Century Aircenter", - "state": "KS", - "lat": 38.82444, - "lon": -94.88694 - }, - "KJHN": { - "id": "KJHN", - "city": "Stanton County Municipal Airport", - "state": "KS", - "lat": 37.5782, - "lon": -101.7304 - }, - "KLBL": { - "id": "KLBL", - "city": "Liberal, Liberal Municipal Airport", - "state": "KS", - "lat": 37.05, - "lon": -100.9666699 - }, - "KLWC": { - "id": "KLWC", - "city": "Lawrence, Lawrence Municipal Airport", - "state": "KS", - "lat": 39.00833, - "lon": -95.21167 - }, - "KLYO": { - "id": "KLYO", - "city": "Lyons-Rice County Municipal Airport", - "state": "KS", - "lat": 38.34025, - "lon": -98.22856 - }, - "KMHK": { - "id": "KMHK", - "city": "Manhattan, Manhattan Municipal Airport", - "state": "KS", - "lat": 39.13528, - "lon": -96.67778 - }, - "KMPR": { - "id": "KMPR", - "city": "MCPHERSON", - "state": "KS", - "lat": 38.35244, - "lon": -97.6913299 - }, - "KMYZ": { - "id": "KMYZ", - "city": "Marysville Municipal Airport", - "state": "KS", - "lat": 39.8553, - "lon": -96.6306 - }, - "KNRN": { - "id": "KNRN", - "city": "Norton Municipal Airport", - "state": "KS", - "lat": 39.85047, - "lon": -99.89469 - }, - "KOEL": { - "id": "KOEL", - "city": "Oakley Municipal Airport", - "state": "KS", - "lat": 39.11178, - "lon": -100.81667 - }, - "KOIN": { - "id": "KOIN", - "city": "Oberlin Municipal Airport", - "state": "KS", - "lat": 39.83489, - "lon": -100.5397799 - }, - "KOJC": { - "id": "KOJC", - "city": "Olathe, Johnson County Executive Airport", - "state": "KS", - "lat": 38.85, - "lon": -94.73917 - }, - "KOWI": { - "id": "KOWI", - "city": "Ottawa Municipal Airport", - "state": "KS", - "lat": 38.5409, - "lon": -95.2542 - }, - "KPHG": { - "id": "KPHG", - "city": "PHILLIPSBURG", - "state": "KS", - "lat": 39.735, - "lon": -99.3171 - }, - "KPPF": { - "id": "KPPF", - "city": "Parsons, Tri-City Airport", - "state": "KS", - "lat": 37.32778, - "lon": -95.50417 - }, - "KPTS": { - "id": "KPTS", - "city": "Atkinson Municipal Airport", - "state": "KS", - "lat": 37.4494, - "lon": -94.7311 - }, - "KPTT": { - "id": "KPTT", - "city": "Pratt Municipal", - "state": "KS", - "lat": 37.7, - "lon": -98.75 - }, - "KRSL": { - "id": "KRSL", - "city": "Russell, Russell Municipal Airport", - "state": "KS", - "lat": 38.87278, - "lon": -98.8130599 - }, - "KSLN": { - "id": "KSLN", - "city": "Salina, Salina Municipal Airport", - "state": "KS", - "lat": 38.78, - "lon": -97.64417 - }, - "KSYF": { - "id": "KSYF", - "city": "ST FRANCIS", - "state": "KS", - "lat": 39.763884, - "lon": -101.797861 - }, - "KTOP": { - "id": "KTOP", - "city": "Topeka, Philip Billard Municipal Airport", - "state": "KS", - "lat": 39.0725, - "lon": -95.6258299 - }, - "KTQK": { - "id": "KTQK", - "city": "Scott City Municipal Airport", - "state": "KS", - "lat": 38.47502, - "lon": -100.88444 - }, - "KUKL": { - "id": "KUKL", - "city": "Coffey County Airport", - "state": "KS", - "lat": 38.30247, - "lon": -95.72497 - }, - "KULS": { - "id": "KULS", - "city": "Ulysses Airport", - "state": "KS", - "lat": 37.604, - "lon": -101.37356 - }, - "KWLD": { - "id": "KWLD", - "city": "Winfield / Arkansas City, Strother Field", - "state": "KS", - "lat": 37.1680599, - "lon": -97.03694 - }, - "KALW": { - "id": "KALW", - "city": "Walla Walla Regional Airport", - "state": "WA", - "lat": 46.09462, - "lon": -118.2858 - }, - "KAWO": { - "id": "KAWO", - "city": "Arlington Municipal Airport", - "state": "WA", - "lat": 48.1584999, - "lon": -122.15909 - }, - "KBFI": { - "id": "KBFI", - "city": "Boeing Field - King County International Airport", - "state": "WA", - "lat": 47.54548, - "lon": -122.3147 - }, - "KBLI": { - "id": "KBLI", - "city": "Bellingham, Bellingham International Airport", - "state": "WA", - "lat": 48.79911, - "lon": -122.54064 - }, - "KBVS": { - "id": "KBVS", - "city": "Burlington/Mount Vernon, Skagit Regional Airport", - "state": "WA", - "lat": 48.47083, - "lon": -122.42083 - }, - "KCLM": { - "id": "KCLM", - "city": "Port Angeles Fairchild International Airport", - "state": "WA", - "lat": 48.12194, - "lon": -123.50661 - }, - "KCLS": { - "id": "KCLS", - "city": "Chehalis-Centralia Airport", - "state": "WA", - "lat": 46.677, - "lon": -122.9827 - }, - "KDEW": { - "id": "KDEW", - "city": "Deer Park, Deer Park Airport", - "state": "WA", - "lat": 47.97417, - "lon": -117.42833 - }, - "KDLS": { - "id": "KDLS", - "city": "The Dalles Municipal Airport", - "state": "WA", - "lat": 45.61901, - "lon": -121.16572 - }, - "KEAT": { - "id": "KEAT", - "city": "Wenatchee - Pangborn Memorial Airport", - "state": "WA", - "lat": 47.39749, - "lon": -120.20121 - }, - "KELN": { - "id": "KELN", - "city": "Ellensburg, Ellensburg Bowers Field", - "state": "WA", - "lat": 47.0337699, - "lon": -120.53132 - }, - "KEPH": { - "id": "KEPH", - "city": "Ephrata, Ephrata Municipal Airport", - "state": "WA", - "lat": 47.3075, - "lon": -119.51583 - }, - "KFHR": { - "id": "KFHR", - "city": "Friday Harbor Airport", - "state": "WA", - "lat": 48.52, - "lon": -123.02637 - }, - "KFLW": { - "id": "KFLW", - "city": "Kettle Falls", - "state": "WA", - "lat": 48.595, - "lon": -118.12417 - }, - "KGEG": { - "id": "KGEG", - "city": "Spokane, Spokane International Airport", - "state": "WA", - "lat": 47.62139, - "lon": -117.52778 - }, - "KGRF": { - "id": "KGRF", - "city": "Fort Lewis / Gray U. S. Army Airfield", - "state": "WA", - "lat": 47.11667, - "lon": -122.55 - }, - "KHQM": { - "id": "KHQM", - "city": "Hoquiam, Bowerman Airport", - "state": "WA", - "lat": 46.97111, - "lon": -123.92 - }, - "KKLS": { - "id": "KKLS", - "city": "Southwest Washington Regional Airport", - "state": "WA", - "lat": 46.11553, - "lon": -122.89273 - }, - "KMWH": { - "id": "KMWH", - "city": "Grant County Airport", - "state": "WA", - "lat": 47.19299, - "lon": -119.31451 - }, - "KNCW": { - "id": "KNCW", - "city": "KENNEWICK CANAL", - "state": "WA", - "lat": 46.2652777, - "lon": -119.5694444 - }, - "KNOW": { - "id": "KNOW", - "city": "Port Angeles Coast Guard Air Station", - "state": "WA", - "lat": 48.13333, - "lon": -123.4 - }, - "KNRA": { - "id": "KNRA", - "city": "Coupeville, Outlying Landing Field", - "state": "WA", - "lat": 48.19056, - "lon": -122.63056 - }, - "KNUW": { - "id": "KNUW", - "city": "Whidbey Island Naval Air Station - Ault Field", - "state": "WA", - "lat": 48.35525, - "lon": -122.66352 - }, - "KOLM": { - "id": "KOLM", - "city": "Olympia, Olympia Airport", - "state": "WA", - "lat": 46.97333, - "lon": -122.90333 - }, - "KOMK": { - "id": "KOMK", - "city": "Omak Airport", - "state": "WA", - "lat": 48.46116, - "lon": -119.52086 - }, - "KORS": { - "id": "KORS", - "city": "Eastsound, Orcas Island Airport", - "state": "WA", - "lat": 48.70806, - "lon": -122.91028 - }, - "KPAE": { - "id": "KPAE", - "city": "Everett Snohomish County", - "state": "WA", - "lat": 47.92331, - "lon": -122.28305 - }, - "KPLU": { - "id": "KPLU", - "city": "Pierce County-Thun Field", - "state": "WA", - "lat": 47.104, - "lon": -122.287 - }, - "KPSC": { - "id": "KPSC", - "city": "Tri-Cities Airport", - "state": "WA", - "lat": 46.26955, - "lon": -119.11813 - }, - "KPUW": { - "id": "KPUW", - "city": "Pullman / Moscow Regional Airport", - "state": "WA", - "lat": 46.74377, - "lon": -117.11579 - }, - "KPWT": { - "id": "KPWT", - "city": "Bremerton, Bremerton National Airport", - "state": "WA", - "lat": 47.5, - "lon": -122.75 - }, - "KRLD": { - "id": "KRLD", - "city": "Richland Airport", - "state": "WA", - "lat": 46.30859, - "lon": -119.3058 - }, - "KRNT": { - "id": "KRNT", - "city": "Renton Municipal Airport", - "state": "WA", - "lat": 47.49509, - "lon": -122.21437 - }, - "KSEA": { - "id": "KSEA", - "city": "Seattle, Seattle-Tacoma International Airport", - "state": "WA", - "lat": 47.4447199, - "lon": -122.31361 - }, - "KSFF": { - "id": "KSFF", - "city": "Spokane, Felts Field", - "state": "WA", - "lat": 47.68556, - "lon": -117.32028 - }, - "KSHN": { - "id": "KSHN", - "city": "Shelton, Shelton Sanderson Field", - "state": "WA", - "lat": 47.23806, - "lon": -123.14083 - }, - "KSKA": { - "id": "KSKA", - "city": "Fairchild Air Force Base", - "state": "WA", - "lat": 47.61667, - "lon": -117.65 - }, - "KSMP": { - "id": "KSMP", - "city": "Stampede Pass", - "state": "WA", - "lat": 47.27648, - "lon": -121.33817 - }, - "KTCM": { - "id": "KTCM", - "city": "Tacoma / McChord Air Force Base", - "state": "WA", - "lat": 47.15, - "lon": -122.48333 - }, - "KTCW": { - "id": "KTCW", - "city": "KITTITAS CANAL", - "state": "WA", - "lat": 47.2388888, - "lon": -121.1833333 - }, - "KTIW": { - "id": "KTIW", - "city": "Tacoma, Tacoma Narrows Airport", - "state": "WA", - "lat": 47.2675, - "lon": -122.57611 - }, - "KUIL": { - "id": "KUIL", - "city": "Quillayute, Quillayute State Airport", - "state": "WA", - "lat": 47.9375, - "lon": -124.555 - }, - "KVUO": { - "id": "KVUO", - "city": "Pearson Airfield", - "state": "WA", - "lat": 45.62103, - "lon": -122.65419 - }, - "KYKM": { - "id": "KYKM", - "city": "Yakima Air Terminal - McAllister Field", - "state": "WA", - "lat": 46.56402, - "lon": -120.53484 - }, - "KABE": { - "id": "KABE", - "city": "Allentown, Lehigh Valley International Airport", - "state": "PA", - "lat": 40.64985, - "lon": -75.44771 - }, - "KAFJ": { - "id": "KAFJ", - "city": "Washington County Airport", - "state": "PA", - "lat": 40.13624, - "lon": -80.28512 - }, - "KAGC": { - "id": "KAGC", - "city": "Pittsburgh - Allegheny County Airport", - "state": "PA", - "lat": 40.35521, - "lon": -79.92144 - }, - "KAOO": { - "id": "KAOO", - "city": "Altoona - Blair County Airport", - "state": "PA", - "lat": 40.29994, - "lon": -78.3168 - }, - "KAVP": { - "id": "KAVP", - "city": "Wilkes-Barre - Scranton, Wilkes-Barre / Scranton International Airport", - "state": "PA", - "lat": 41.33889, - "lon": -75.72667 - }, - "KBFD": { - "id": "KBFD", - "city": "Bradford Regional Airport", - "state": "PA", - "lat": 41.79838, - "lon": -78.63539 - }, - "KBTP": { - "id": "KBTP", - "city": "Pittsburgh/Butler Regional Airport", - "state": "PA", - "lat": 40.77658, - "lon": -79.95672 - }, - "KBVI": { - "id": "KBVI", - "city": "Beaver County Airport", - "state": "PA", - "lat": 40.77351, - "lon": -80.38248 - }, - "KCKZ": { - "id": "KCKZ", - "city": "Pennridge Airport", - "state": "PA", - "lat": 40.38919, - "lon": -75.29047 - }, - "KCXY": { - "id": "KCXY", - "city": "Harrisburg, Capital City Airport", - "state": "PA", - "lat": 40.21843, - "lon": -76.8552 - }, - "KDUJ": { - "id": "KDUJ", - "city": "Du Bois - Jefferson County Airport", - "state": "PA", - "lat": 41.17948, - "lon": -78.89326 - }, - "KDYL": { - "id": "KDYL", - "city": "Doylestown, Doylestown Airport", - "state": "PA", - "lat": 40.33016, - "lon": -75.12286 - }, - "KERI": { - "id": "KERI", - "city": "Erie, Erie International Airport", - "state": "PA", - "lat": 42.08, - "lon": -80.1825 - }, - "KFIG": { - "id": "KFIG", - "city": "Clearfield, Clearfield-Lawrence Airport", - "state": "PA", - "lat": 41.04667, - "lon": -78.41167 - }, - "KFKL": { - "id": "KFKL", - "city": "Venango Regional Airport", - "state": "PA", - "lat": 41.38051, - "lon": -79.86029 - }, - "KGKJ": { - "id": "KGKJ", - "city": "Port Meadville Airport", - "state": "PA", - "lat": 41.6258399, - "lon": -80.21231 - }, - "KHMZ": { - "id": "KHMZ", - "city": "Bedford, Bedford County Airport", - "state": "PA", - "lat": 40.08528, - "lon": -78.51222 - }, - "KHZL": { - "id": "KHZL", - "city": "Hazleton Municipal Airport", - "state": "PA", - "lat": 40.98447, - "lon": -75.99005 - }, - "KIDI": { - "id": "KIDI", - "city": "Indiana County Airport - Jimmy Stewart Field", - "state": "PA", - "lat": 40.6337199, - "lon": -79.10362 - }, - "KIPT": { - "id": "KIPT", - "city": "Williamsport - Lycoming County Airport", - "state": "PA", - "lat": 41.24298, - "lon": -76.92173 - }, - "KJST": { - "id": "KJST", - "city": "Johnstown - Cambria County Airport", - "state": "PA", - "lat": 40.3149, - "lon": -78.83074 - }, - "KLBE": { - "id": "KLBE", - "city": "Arnold Palmer Regional Airport", - "state": "PA", - "lat": 40.2767399, - "lon": -79.40393 - }, - "KLNS": { - "id": "KLNS", - "city": "Lancaster, Lancaster Airport", - "state": "PA", - "lat": 40.1205799, - "lon": -76.29446 - }, - "KLOM": { - "id": "KLOM", - "city": "Philadelphia - Wings Field Airport", - "state": "PA", - "lat": 40.13758, - "lon": -75.2684 - }, - "KMDT": { - "id": "KMDT", - "city": "Harrisburg, Harrisburg International Airport", - "state": "PA", - "lat": 40.19361, - "lon": -76.76333 - }, - "KMPO": { - "id": "KMPO", - "city": "Mount Pocono, Pocono Mountains Municipal Airport", - "state": "PA", - "lat": 41.13821, - "lon": -75.37971 - }, - "KMQS": { - "id": "KMQS", - "city": "Chester County Airport", - "state": "PA", - "lat": 39.98333, - "lon": -75.86667 - }, - "KMUI": { - "id": "KMUI", - "city": "Muir Army Air Field / Indiantown", - "state": "PA", - "lat": 40.43808, - "lon": -76.56434 - }, - "KOQN": { - "id": "KOQN", - "city": "Brandywine Regional Airport", - "state": "PA", - "lat": 39.99011, - "lon": -75.5819 - }, - "KOYM": { - "id": "KOYM", - "city": "St Marys Municipal Airport", - "state": "PA", - "lat": 41.41248, - "lon": -78.50263 - }, - "KPHL": { - "id": "KPHL", - "city": "Philadelphia, Philadelphia International Airport", - "state": "PA", - "lat": 39.87327, - "lon": -75.22678 - }, - "KPIT": { - "id": "KPIT", - "city": "Pittsburgh International Airport", - "state": "PA", - "lat": 40.4846, - "lon": -80.21447 - }, - "KPJC": { - "id": "KPJC", - "city": "Zelienople Municipal Airport", - "state": "PA", - "lat": 40.80095, - "lon": -80.16242 - }, - "KPNE": { - "id": "KPNE", - "city": "Philadelphia, Northeast Philadelphia Airport", - "state": "PA", - "lat": 40.07889, - "lon": -75.01361 - }, - "KPTW": { - "id": "KPTW", - "city": "Pottstown, Pottstown Limerick Airport", - "state": "PA", - "lat": 40.23802, - "lon": -75.5548699 - }, - "KRDG": { - "id": "KRDG", - "city": "Reading, Reading Regional Airport", - "state": "PA", - "lat": 40.37333, - "lon": -75.95944 - }, - "KRVL": { - "id": "KRVL", - "city": "Reedsville / Mifflin", - "state": "PA", - "lat": 40.68333, - "lon": -77.63333 - }, - "KSEG": { - "id": "KSEG", - "city": "Selinsgrove Penn Valley Airport", - "state": "PA", - "lat": 40.81929, - "lon": -76.86582 - }, - "KTHV": { - "id": "KTHV", - "city": "York, York Airport", - "state": "PA", - "lat": 39.91944, - "lon": -76.87694 - }, - "KUCP": { - "id": "KUCP", - "city": "New Castle Municipal Airport", - "state": "PA", - "lat": 41.02282, - "lon": -80.41533 - }, - "KUKT": { - "id": "KUKT", - "city": "Quakertown Airport", - "state": "PA", - "lat": 40.4368, - "lon": -75.38016 - }, - "KUNV": { - "id": "KUNV", - "city": "State College Regional Airport", - "state": "PA", - "lat": 40.85, - "lon": -77.8475799 - }, - "KVVS": { - "id": "KVVS", - "city": "Joseph A Hardy Connellsville Airport", - "state": "PA", - "lat": 39.95906, - "lon": -79.65742 - }, - "KXLL": { - "id": "KXLL", - "city": "Allentown Queen City Municipal Airport", - "state": "PA", - "lat": 40.57, - "lon": -75.488 - }, - "KZER": { - "id": "KZER", - "city": "Schuylkill County/Joe Zerbey Airport", - "state": "PA", - "lat": 40.70675, - "lon": -76.37375 - }, - "KABY": { - "id": "KABY", - "city": "Southwest Georgia Regional Airport", - "state": "GA", - "lat": 31.53652, - "lon": -84.19571 - }, - "KACJ": { - "id": "KACJ", - "city": "Americus Souther Field Airport", - "state": "GA", - "lat": 32.11081, - "lon": -84.18886 - }, - "KAGS": { - "id": "KAGS", - "city": "Augusta, Bush Field", - "state": "GA", - "lat": 33.36444, - "lon": -81.96333 - }, - "KAHN": { - "id": "KAHN", - "city": "Athens, Athens Airport", - "state": "GA", - "lat": 33.95083, - "lon": -83.3280599 - }, - "KAJR": { - "id": "KAJR", - "city": "Cornelia Habersham County Airport", - "state": "GA", - "lat": 34.4998, - "lon": -83.5567 - }, - "KAMG": { - "id": "KAMG", - "city": "Alma, Bacon County Airport", - "state": "GA", - "lat": 31.53611, - "lon": -82.50667 - }, - "KATL": { - "id": "KATL", - "city": "Atlanta, Hartsfield - Jackson Atlanta International Airport", - "state": "GA", - "lat": 33.64028, - "lon": -84.42694 - }, - "KAYS": { - "id": "KAYS", - "city": "Waycross / Ware County, Ga", - "state": "GA", - "lat": 31.25, - "lon": -82.4 - }, - "KAZE": { - "id": "KAZE", - "city": "Hazlehurst Airport", - "state": "GA", - "lat": 31.8847, - "lon": -82.6474 - }, - "KBGE": { - "id": "KBGE", - "city": "Bainbridge, Decatur County Industrial Air Park Airport", - "state": "GA", - "lat": 30.96667, - "lon": -84.63333 - }, - "KBHC": { - "id": "KBHC", - "city": "Baxley Municipal Airport", - "state": "GA", - "lat": 31.7138, - "lon": -82.3938 - }, - "KBIJ": { - "id": "KBIJ", - "city": "Blakely, Early County Airport", - "state": "GA", - "lat": 31.39694, - "lon": -84.895 - }, - "KBQK": { - "id": "KBQK", - "city": "Brunswick / Glynco", - "state": "GA", - "lat": 31.25, - "lon": -81.4666699 - }, - "KCCO": { - "id": "KCCO", - "city": "Newnan, Newnan Coweta County Airport", - "state": "GA", - "lat": 33.31222, - "lon": -84.77028 - }, - "KCNI": { - "id": "KCNI", - "city": "Canton, Cherokee County Airport", - "state": "GA", - "lat": 34.31056, - "lon": -84.42389 - }, - "KCPP": { - "id": "KCPP", - "city": "Greene County Regional Airport", - "state": "GA", - "lat": 33.5979699, - "lon": -83.13826 - }, - "KCSG": { - "id": "KCSG", - "city": "Columbus, Columbus Metropolitan Airport", - "state": "GA", - "lat": 32.51611, - "lon": -84.94222 - }, - "KCTJ": { - "id": "KCTJ", - "city": "Carrollton West Georgia Regional Airport", - "state": "GA", - "lat": 33.63, - "lon": -85.15 - }, - "KCVC": { - "id": "KCVC", - "city": "Covington Municipal Airport", - "state": "GA", - "lat": 33.632, - "lon": -83.85 - }, - "KCWV": { - "id": "KCWV", - "city": "Claxton Evans County Airport", - "state": "GA", - "lat": 32.1950999, - "lon": -81.8696 - }, - "KCXU": { - "id": "KCXU", - "city": "Camilla-Mitchell County Airport", - "state": "GA", - "lat": 31.2132, - "lon": -84.2352 - }, - "KCZL": { - "id": "KCZL", - "city": "Calhoun Tom B. David Field Airport", - "state": "GA", - "lat": 34.4554, - "lon": -84.9392 - }, - "KDBN": { - "id": "KDBN", - "city": "Dublin, W H 'Bud' Barron Airport", - "state": "GA", - "lat": 32.56444, - "lon": -82.985 - }, - "KDNL": { - "id": "KDNL", - "city": "Augusta Daniel Field", - "state": "GA", - "lat": 33.4669, - "lon": -82.03836 - }, - "KDNN": { - "id": "KDNN", - "city": "Dalton, Dalton Municipal Airport", - "state": "GA", - "lat": 34.72167, - "lon": -84.86917 - }, - "KDQH": { - "id": "KDQH", - "city": "Douglas, Douglas Municipal Airport", - "state": "GA", - "lat": 31.47667, - "lon": -82.86028 - }, - "KDZJ": { - "id": "KDZJ", - "city": "Blairsville Airport", - "state": "GA", - "lat": 34.8544, - "lon": -83.9973 - }, - "KEBA": { - "id": "KEBA", - "city": "Elbert County - Patz Field", - "state": "GA", - "lat": 34.095, - "lon": -82.81583 - }, - "KEZM": { - "id": "KEZM", - "city": "Eastman, Heart of Georgia Regional Airport", - "state": "GA", - "lat": 32.21417, - "lon": -83.12778 - }, - "KFFC": { - "id": "KFFC", - "city": "Atlanta Regional Airport-Falcon Field", - "state": "GA", - "lat": 33.35436, - "lon": -84.56893 - }, - "KFTY": { - "id": "KFTY", - "city": "Fulton County Airport-Brown Field", - "state": "GA", - "lat": 33.77764, - "lon": -84.52461 - }, - "KFZG": { - "id": "KFZG", - "city": "Fitzgerald Municipal Airport", - "state": "GA", - "lat": 31.6839, - "lon": -83.2709 - }, - "KGVL": { - "id": "KGVL", - "city": "Gainesville, Gilmer Memorial Airport", - "state": "GA", - "lat": 34.27194, - "lon": -83.83028 - }, - "KHMP": { - "id": "KHMP", - "city": "Henry County Airport", - "state": "GA", - "lat": 33.3899, - "lon": -84.331 - }, - "KHOE": { - "id": "KHOE", - "city": "Homerville Airport", - "state": "GA", - "lat": 31.0559, - "lon": -82.7741 - }, - "KHQU": { - "id": "KHQU", - "city": "Thomson, Thomson-McDuffie County Airport", - "state": "GA", - "lat": 33.52944, - "lon": -82.51639 - }, - "KIIY": { - "id": "KIIY", - "city": "Washington, Washington-Wilkes County Airport", - "state": "GA", - "lat": 33.77972, - "lon": -82.81639 - }, - "KJCA": { - "id": "KJCA", - "city": "Jackson County Airport", - "state": "GA", - "lat": 34.17586, - "lon": -83.5616 - }, - "KJES": { - "id": "KJES", - "city": "Jesup-Wayne County Airport", - "state": "GA", - "lat": 31.554, - "lon": -81.8824999 - }, - "KJYL": { - "id": "KJYL", - "city": "Sylvania, Plantation Airpark", - "state": "GA", - "lat": 32.64528, - "lon": -81.59639 - }, - "KJZP": { - "id": "KJZP", - "city": "Jasper Pickens County Airport", - "state": "GA", - "lat": 34.45417, - "lon": -84.45971 - }, - "KLGC": { - "id": "KLGC", - "city": "LaGrange-Callaway Airport", - "state": "GA", - "lat": 33.00617, - "lon": -85.06609 - }, - "KLHW": { - "id": "KLHW", - "city": "Wright Army Airfield (Fort Stewart)/Midcoast Regional Airport", - "state": "GA", - "lat": 31.88724, - "lon": -81.56244 - }, - "KLSF": { - "id": "KLSF", - "city": "Fort Benning", - "state": "GA", - "lat": 32.3333299, - "lon": -84.83333 - }, - "KLZU": { - "id": "KLZU", - "city": "Gwinnett County Airport-Briscoe Field", - "state": "GA", - "lat": 33.98288, - "lon": -83.95842 - }, - "KMCN": { - "id": "KMCN", - "city": "Middle Georgia Regional Airport", - "state": "GA", - "lat": 32.68892, - "lon": -83.65293 - }, - "KMGE": { - "id": "KMGE", - "city": "Marietta / Dobbins Air Force Base", - "state": "GA", - "lat": 33.91667, - "lon": -84.51667 - }, - "KMGR": { - "id": "KMGR", - "city": "Moultrie, Moultrie Municipal Airport", - "state": "GA", - "lat": 31.08472, - "lon": -83.80306 - }, - "KMHP": { - "id": "KMHP", - "city": "Metter Municipal Airport", - "state": "GA", - "lat": 32.37397, - "lon": -82.08144 - }, - "KMLJ": { - "id": "KMLJ", - "city": "Milledgeville, Baldwin County Airport", - "state": "GA", - "lat": 33.15417, - "lon": -83.24056 - }, - "KMQW": { - "id": "KMQW", - "city": "Telfair-Wheeler Airport", - "state": "GA", - "lat": 32.09699, - "lon": -82.8794099 - }, - "KOPN": { - "id": "KOPN", - "city": "Thomaston, Thomaston-Upson County Airport", - "state": "GA", - "lat": 32.955, - "lon": -84.2644399 - }, - "KPDK": { - "id": "KPDK", - "city": "Atlanta, De Kalb-Peachtree Airport", - "state": "GA", - "lat": 33.87833, - "lon": -84.29806 - }, - "KPIM": { - "id": "KPIM", - "city": "Pine Mountain Harris County Airport", - "state": "GA", - "lat": 32.8407, - "lon": -84.8824 - }, - "KPUJ": { - "id": "KPUJ", - "city": "Dallas Paulding County Regional Airport", - "state": "GA", - "lat": 33.9189999, - "lon": -84.952 - }, - "KPXE": { - "id": "KPXE", - "city": "Perry-Houston County Airport", - "state": "GA", - "lat": 32.5105999, - "lon": -83.7673 - }, - "KRMG": { - "id": "KRMG", - "city": "Rome, R. B. Russell Airport", - "state": "GA", - "lat": 34.34778, - "lon": -85.1611099 - }, - "KRVJ": { - "id": "KRVJ", - "city": "Swinton Smith Field at Reidsville Municipal Airport", - "state": "GA", - "lat": 32.0594899, - "lon": -82.15358 - }, - "KRYY": { - "id": "KRYY", - "city": "Cobb County International Airport - McCollum Field", - "state": "GA", - "lat": 34.01467, - "lon": -84.59635 - }, - "KSAV": { - "id": "KSAV", - "city": "Savannah-Hilton Head International Airport", - "state": "GA", - "lat": 32.1313699, - "lon": -81.20226 - }, - "KSBO": { - "id": "KSBO", - "city": "Swainsboro Emanuel County Airport", - "state": "GA", - "lat": 32.6091, - "lon": -82.3699 - }, - "KSSI": { - "id": "KSSI", - "city": "Brunswick, Malcolm McKinnon Airport", - "state": "GA", - "lat": 31.15167, - "lon": -81.39139 - }, - "KSVN": { - "id": "KSVN", - "city": "Hunter U. S. Army Airfield", - "state": "GA", - "lat": 32.01667, - "lon": -81.15 - }, - "KTBR": { - "id": "KTBR", - "city": "Statesboro, Statesboro-Bulloch County Airport", - "state": "GA", - "lat": 32.48306, - "lon": -81.7372199 - }, - "KTMA": { - "id": "KTMA", - "city": "Tifton Henry Tift Myers", - "state": "GA", - "lat": 31.429, - "lon": -83.4885 - }, - "KTOC": { - "id": "KTOC", - "city": "Toccoa Le Tourneau Airport", - "state": "GA", - "lat": 34.5927999, - "lon": -83.2964 - }, - "KTVI": { - "id": "KTVI", - "city": "Thomasville Regional Airport", - "state": "GA", - "lat": 30.90179, - "lon": -83.88113 - }, - "KVAD": { - "id": "KVAD", - "city": "Moody Air Force Base", - "state": "GA", - "lat": 30.97913, - "lon": -83.19247 - }, - "KVDI": { - "id": "KVDI", - "city": "Vidalia, Vidalia Municipal Airport", - "state": "GA", - "lat": 32.1925, - "lon": -82.37194 - }, - "KVLD": { - "id": "KVLD", - "city": "Valdosta Regional Airport", - "state": "GA", - "lat": 30.77632, - "lon": -83.27389 - }, - "KVPC": { - "id": "KVPC", - "city": "Cartersville Airport", - "state": "GA", - "lat": 34.11589, - "lon": -84.85064 - }, - "KWDR": { - "id": "KWDR", - "city": "Winder, Winder-Barrow Airport", - "state": "GA", - "lat": 33.98222, - "lon": -83.66806 - }, - "KWRB": { - "id": "KWRB", - "city": "Warner Robins Air Force Base", - "state": "GA", - "lat": 32.63333, - "lon": -83.6 - }, - "KMNV": { - "id": "KMNV", - "city": "Monroe County Airport", - "state": "TN", - "lat": 35.54522, - "lon": -84.38039 - }, - "KMOR": { - "id": "KMOR", - "city": "Morristown Moore-Murrell Airport", - "state": "TN", - "lat": 36.1794, - "lon": -83.3754 - }, - "KMQY": { - "id": "KMQY", - "city": "Smyrna, Smyrna Airport", - "state": "TN", - "lat": 36.00889, - "lon": -86.52 - }, - "KMRC": { - "id": "KMRC", - "city": "Columbia / Maury County", - "state": "TN", - "lat": 35.55, - "lon": -87.18333 - }, - "KNQA": { - "id": "KNQA", - "city": "Millington, Millington Municipal Airport", - "state": "TN", - "lat": 35.35667, - "lon": -89.8702799 - }, - "KOQT": { - "id": "KOQT", - "city": "Oak Ridge", - "state": "TN", - "lat": 36.02278, - "lon": -84.23333 - }, - "KPHT": { - "id": "KPHT", - "city": "Paris - Henry County Airport", - "state": "TN", - "lat": 36.34, - "lon": -88.38 - }, - "KRKW": { - "id": "KRKW", - "city": "Rockwood Municipal Airport", - "state": "TN", - "lat": 35.92501, - "lon": -84.691 - }, - "KRNC": { - "id": "KRNC", - "city": "McMinnville Warren County Memorial Airport", - "state": "TN", - "lat": 35.6991, - "lon": -85.8402 - }, - "KRZR": { - "id": "KRZR", - "city": "Cleveland Regional Jetport", - "state": "TN", - "lat": 35.2115, - "lon": -84.7998 - }, - "KSCX": { - "id": "KSCX", - "city": "Scott Municipal Airport", - "state": "TN", - "lat": 36.45569, - "lon": -84.58575 - }, - "KSNH": { - "id": "KSNH", - "city": "SAVANNAH/HARDIN CO", - "state": "TN", - "lat": 35.17, - "lon": -88.22 - }, - "KSRB": { - "id": "KSRB", - "city": "Sparta Upper Cumberland Regional Airport", - "state": "TN", - "lat": 36.0559, - "lon": -85.5307 - }, - "KSYI": { - "id": "KSYI", - "city": "Shelbyville Bomar Field & Shelbyville Municipal Airport", - "state": "TN", - "lat": 35.5593999, - "lon": -86.4425 - }, - "KSZY": { - "id": "KSZY", - "city": "SELMER/ROBERT SIBLEY", - "state": "TN", - "lat": 35.2, - "lon": -88.5 - }, - "KTHA": { - "id": "KTHA", - "city": "Tullahoma Regional Airport/William Northern Field", - "state": "TN", - "lat": 35.38, - "lon": -86.2467 - }, - "KTRI": { - "id": "KTRI", - "city": "Bristol / Johnson / Kingsport, Tri-City Regional Airport", - "state": "TN", - "lat": 36.47972, - "lon": -82.39889 - }, - "KTYS": { - "id": "KTYS", - "city": "Knoxville, McGhee Tyson Airport", - "state": "TN", - "lat": 35.81806, - "lon": -83.98583 - }, - "KUCY": { - "id": "KUCY", - "city": "Union City - Everett-Stewart Regional Airport", - "state": "TN", - "lat": 36.38, - "lon": -88.98 - }, - "KXNX": { - "id": "KXNX", - "city": "Sumner County Regional Airport", - "state": "TN", - "lat": 36.3750799, - "lon": -86.40842 - }, - "KAKR": { - "id": "KAKR", - "city": "Akron, Akron Fulton International Airport", - "state": "OH", - "lat": 41.0375, - "lon": -81.46417 - }, - "KAOH": { - "id": "KAOH", - "city": "Lima, Lima Allen County Airport", - "state": "OH", - "lat": 40.70806, - "lon": -84.02139 - }, - "KAXV": { - "id": "KAXV", - "city": "Neil Armstrong Airport", - "state": "OH", - "lat": 40.49356, - "lon": -84.29808 - }, - "KBJJ": { - "id": "KBJJ", - "city": "Wooster, Wayne County Airport", - "state": "OH", - "lat": 40.87306, - "lon": -81.88667 - }, - "KBKL": { - "id": "KBKL", - "city": "Cleveland, Burke Lakefront Airport", - "state": "OH", - "lat": 41.52556, - "lon": -81.66889 - }, - "KCAK": { - "id": "KCAK", - "city": "Akron Canton Regional Airport", - "state": "OH", - "lat": 40.91811, - "lon": -81.44343 - }, - "KCDI": { - "id": "KCDI", - "city": "Cambridge Municipal Airport", - "state": "OH", - "lat": 39.97393, - "lon": -81.5807899 - }, - "KCGF": { - "id": "KCGF", - "city": "Cleveland / Cuyahoga", - "state": "OH", - "lat": 41.56667, - "lon": -81.48333 - }, - "KCLE": { - "id": "KCLE", - "city": "Cleveland Hopkins International Airport", - "state": "OH", - "lat": 41.40569, - "lon": -81.85193 - }, - "KCMH": { - "id": "KCMH", - "city": "John Glenn Columbus International Airport", - "state": "OH", - "lat": 39.9906999, - "lon": -82.87691 - }, - "KDAY": { - "id": "KDAY", - "city": "Dayton, Cox Dayton International Airport", - "state": "OH", - "lat": 39.90611, - "lon": -84.21861 - }, - "KDFI": { - "id": "KDFI", - "city": "Defiance, Defiance Memorial Airport", - "state": "OH", - "lat": 41.33639, - "lon": -84.42944 - }, - "KDLZ": { - "id": "KDLZ", - "city": "Delaware Municipal Airport", - "state": "OH", - "lat": 40.2797, - "lon": -83.1148 - }, - "KEDJ": { - "id": "KEDJ", - "city": "Bellefontaine Regional Airport", - "state": "OH", - "lat": 40.3723, - "lon": -83.8192 - }, - "KFDY": { - "id": "KFDY", - "city": "Findlay, Findlay Airport", - "state": "OH", - "lat": 41.01361, - "lon": -83.66861 - }, - "KFFO": { - "id": "KFFO", - "city": "Dayton / Wright-Patterson Air Force Base", - "state": "OH", - "lat": 39.8333299, - "lon": -84.05 - }, - "KGDK": { - "id": "KGDK", - "city": "Greene County - Lewis A Jackson Regional Airport", - "state": "OH", - "lat": 39.69072, - "lon": -83.99278 - }, - "KHAO": { - "id": "KHAO", - "city": "Butler County Regional Airport", - "state": "OH", - "lat": 39.36121, - "lon": -84.52061 - }, - "KHOC": { - "id": "KHOC", - "city": "HILLSBORO", - "state": "OH", - "lat": 39.18876, - "lon": -83.53879 - }, - "KHZY": { - "id": "KHZY", - "city": "Ashtabula - Northeast Ohio Regional Airport", - "state": "OH", - "lat": 41.77944, - "lon": -80.69667 - }, - "KILN": { - "id": "KILN", - "city": "Wilmington, Airborne Airpark Airport", - "state": "OH", - "lat": 39.42833, - "lon": -83.7791699 - }, - "KJRO": { - "id": "KJRO", - "city": "JACKSON", - "state": "OH", - "lat": 38.9833, - "lon": -82.5833 - }, - "KLCK": { - "id": "KLCK", - "city": "Rickenbacker Air National Guard Base", - "state": "OH", - "lat": 39.81667, - "lon": -82.93333 - }, - "KLHQ": { - "id": "KLHQ", - "city": "Lancaster, Fairfield County Airport", - "state": "OH", - "lat": 39.7572199, - "lon": -82.66333 - }, - "KLNN": { - "id": "KLNN", - "city": "Willoughby", - "state": "OH", - "lat": 41.68333, - "lon": -81.38333 - }, - "KLPR": { - "id": "KLPR", - "city": "Lorain / Elyria, Lorain County Regional Airport", - "state": "OH", - "lat": 41.34611, - "lon": -82.17944 - }, - "KLUK": { - "id": "KLUK", - "city": "Cincinnati, Cincinnati Municipal Airport Lunken Field", - "state": "OH", - "lat": 39.10583, - "lon": -84.41583 - }, - "KMFD": { - "id": "KMFD", - "city": "Mansfield - Mansfield Lahm Regional Airport", - "state": "OH", - "lat": 40.8202799, - "lon": -82.51778 - }, - "KMGY": { - "id": "KMGY", - "city": "Dayton, Dayton-Wright Brothers Airport", - "state": "OH", - "lat": 39.58889, - "lon": -84.22472 - }, - "KMNN": { - "id": "KMNN", - "city": "Marion, Marion Municipal Airport", - "state": "OH", - "lat": 40.61667, - "lon": -83.06833 - }, - "KMRT": { - "id": "KMRT", - "city": "Marysville Union County Airport", - "state": "OH", - "lat": 40.2247, - "lon": -83.3516 - }, - "KMWO": { - "id": "KMWO", - "city": "Hook Field Municipal Airport", - "state": "OH", - "lat": 39.531, - "lon": -84.3953 - }, - "KOSU": { - "id": "KOSU", - "city": "Columbus, Ohio State University Airport", - "state": "OH", - "lat": 40.07806, - "lon": -83.0780599 - }, - "KOWX": { - "id": "KOWX", - "city": "Ottawa Putnam County Airport", - "state": "OH", - "lat": 41.0356, - "lon": -83.982 - }, - "KOXD": { - "id": "KOXD", - "city": "Miami University Airport", - "state": "OH", - "lat": 39.5022499, - "lon": -84.78436 - }, - "KPCW": { - "id": "KPCW", - "city": "Port Clinton Carl R Keller Field Airport", - "state": "OH", - "lat": 41.5163, - "lon": -82.8687 - }, - "KPHD": { - "id": "KPHD", - "city": "Harry Clever Field Airport", - "state": "OH", - "lat": 40.47032, - "lon": -81.42178 - }, - "KPMH": { - "id": "KPMH", - "city": "Greater Portsmouth Regional Airport", - "state": "OH", - "lat": 38.84047, - "lon": -82.8473099 - }, - "KPOV": { - "id": "KPOV", - "city": "Portage County Airport", - "state": "OH", - "lat": 41.21, - "lon": -81.252 - }, - "KRZT": { - "id": "KRZT", - "city": "Chillicothe Ross County Airport", - "state": "OH", - "lat": 39.4403999, - "lon": -83.0231 - }, - "KSGH": { - "id": "KSGH", - "city": "Springfield, Springfield-Beckley Municipal Airport", - "state": "OH", - "lat": 39.84028, - "lon": -83.84 - }, - "KTDZ": { - "id": "KTDZ", - "city": "Toledo - Toledo Executive Airport", - "state": "OH", - "lat": 41.56306, - "lon": -83.47639 - }, - "KTOL": { - "id": "KTOL", - "city": "Toledo - Toledo Express Airport", - "state": "OH", - "lat": 41.58704, - "lon": -83.80539 - }, - "KTZR": { - "id": "KTZR", - "city": "Columbus, Bolton Field Airport", - "state": "OH", - "lat": 39.90083, - "lon": -83.13722 - }, - "KUNI": { - "id": "KUNI", - "city": "OHIO U/ATHEN-ALBANY", - "state": "OH", - "lat": 39.22, - "lon": -82.23 - }, - "KUSE": { - "id": "KUSE", - "city": "Wauseon Fulton County Airport", - "state": "OH", - "lat": 41.6101, - "lon": -84.1272 - }, - "KUYF": { - "id": "KUYF", - "city": "London Madison County Airport", - "state": "OH", - "lat": 39.9326999, - "lon": -83.462 - }, - "KVES": { - "id": "KVES", - "city": "Versailles Darke County Airport", - "state": "OH", - "lat": 40.2044, - "lon": -84.5318999 - }, - "KVNW": { - "id": "KVNW", - "city": "Van Wert County Airport", - "state": "OH", - "lat": 40.86383, - "lon": -84.60636 - }, - "KVTA": { - "id": "KVTA", - "city": "Newark, Newark Heath Airport", - "state": "OH", - "lat": 40.02278, - "lon": -82.4625 - }, - "KYNG": { - "id": "KYNG", - "city": "Youngstown, Youngstown-Warren Regional Airport", - "state": "OH", - "lat": 41.25444, - "lon": -80.67389 - }, - "KZZV": { - "id": "KZZV", - "city": "Zanesville Municipal Airport", - "state": "OH", - "lat": 39.94609, - "lon": -81.89315 - }, - "KBOI": { - "id": "KBOI", - "city": "Boise Air Terminal", - "state": "ID", - "lat": 43.56704, - "lon": -116.24053 - }, - "KBYI": { - "id": "KBYI", - "city": "Burley Municipal Airport", - "state": "ID", - "lat": 42.54525, - "lon": -113.7686 - }, - "KCOE": { - "id": "KCOE", - "city": "Coeur d'Alene Airport - Pappy Boyington Field", - "state": "ID", - "lat": 47.76667, - "lon": -116.81667 - }, - "KDIJ": { - "id": "KDIJ", - "city": "Driggs, Driggs-Reed Memorial Airport", - "state": "ID", - "lat": 43.74167, - "lon": -111.09778 - }, - "KETI": { - "id": "KETI", - "city": "Ketchum Ranger Station", - "state": "ID", - "lat": 43.6816666, - "lon": -114.3627777 - }, - "KEUL": { - "id": "KEUL", - "city": "Caldwell - Caldwell Industrial Airport", - "state": "ID", - "lat": 43.64055, - "lon": -116.63017 - }, - "KGIC": { - "id": "KGIC", - "city": "Grangeville - Idaho County Airport", - "state": "ID", - "lat": 45.94111, - "lon": -116.13257 - }, - "KGNG": { - "id": "KGNG", - "city": "Gooding Municipal Airport", - "state": "ID", - "lat": 42.91716, - "lon": -114.76516 - }, - "KIDA": { - "id": "KIDA", - "city": "Idaho Falls Regional Airport", - "state": "ID", - "lat": 43.5208299, - "lon": -112.06611 - }, - "KJER": { - "id": "KJER", - "city": "Jerome County Airport", - "state": "ID", - "lat": 42.72736, - "lon": -114.45469 - }, - "KLLJ": { - "id": "KLLJ", - "city": "Challis - Challis Airport", - "state": "ID", - "lat": 44.523, - "lon": -114.21611 - }, - "KLWS": { - "id": "KLWS", - "city": "Lewiston, Lewiston-Nez Perce County Airport", - "state": "ID", - "lat": 46.37472, - "lon": -117.01444 - }, - "KMAN": { - "id": "KMAN", - "city": "Nampa Municipal Airport", - "state": "ID", - "lat": 43.5813, - "lon": -116.5231 - }, - "KMUO": { - "id": "KMUO", - "city": "Mountain Home Air Force Base", - "state": "ID", - "lat": 43.05, - "lon": -115.86667 - }, - "KMYL": { - "id": "KMYL", - "city": "McCall Airport", - "state": "ID", - "lat": 44.89425, - "lon": -116.09978 - }, - "KPIH": { - "id": "KPIH", - "city": "Pocatello, Pocatello Regional Airport", - "state": "ID", - "lat": 42.92028, - "lon": -112.57111 - }, - "KRXE": { - "id": "KRXE", - "city": "Rexburg, Rexburg-Madison County Airport", - "state": "ID", - "lat": 43.83167, - "lon": -111.80611 - }, - "KSMN": { - "id": "KSMN", - "city": "Salmon, Lemhi County Airport", - "state": "ID", - "lat": 45.11667, - "lon": -113.88333 - }, - "KSNT": { - "id": "KSNT", - "city": "Stanley, Stanley Ranger Station", - "state": "ID", - "lat": 44.20861, - "lon": -114.93444 - }, - "KSUN": { - "id": "KSUN", - "city": "Hailey, Friedman Memorial Airport", - "state": "ID", - "lat": 43.5, - "lon": -114.3 - }, - "KSZT": { - "id": "KSZT", - "city": "Sandpoint, Sandpoint Airport", - "state": "ID", - "lat": 48.29944, - "lon": -116.56 - }, - "KTBI": { - "id": "KTBI", - "city": "Kettle Butte", - "state": "ID", - "lat": 43.5486099, - "lon": -112.32583 - }, - "KTWF": { - "id": "KTWF", - "city": "Joslin Field - Magic Valley Regional Airport", - "state": "ID", - "lat": 42.4784999, - "lon": -114.47739 - }, - "PALI": { - "id": "PALI", - "city": "Snake River near Irwin, ID", - "state": "ID", - "lat": 43.3508333, - "lon": -111.2183333 - }, - "PARI": { - "id": "PARI", - "city": "Boise River near Parma, ID", - "state": "ID", - "lat": 43.7816666, - "lon": -116.9713888 - }, - "PAYI": { - "id": "PAYI", - "city": "North Fork Payette River at McCall, Idaho", - "state": "ID", - "lat": 44.9083333, - "lon": -116.1194444 - }, - "PECI": { - "id": "PECI", - "city": "Peoples Canal", - "state": "ID", - "lat": 43.2841666, - "lon": -112.25 - }, - "PICI": { - "id": "PICI", - "city": "PICABO", - "state": "ID", - "lat": 43.31167, - "lon": -114.16583 - }, - "PLCI": { - "id": "PLCI", - "city": "Palisades Canal near Irwin, ID", - "state": "ID", - "lat": 43.7458333, - "lon": -112.1027777 - }, - "PLEI": { - "id": "PLEI", - "city": "Payette River near Letha, ID", - "state": "ID", - "lat": 43.8963888, - "lon": -116.6258333 - }, - "PMAI": { - "id": "PMAI", - "city": "PARMA", - "state": "ID", - "lat": 43.8, - "lon": -116.93333 - }, - "PNRI": { - "id": "PNRI", - "city": "PN Region USBR Hydromet Test Site - Boise, ID", - "state": "ID", - "lat": 43.6225, - "lon": -116.1933333 - }, - "POCI": { - "id": "POCI", - "city": "Porter Canal", - "state": "ID", - "lat": 43.5030555, - "lon": -112.0480555 - }, - "PRKI": { - "id": "PRKI", - "city": "Parks and Lewisville Canal near Rigby, ID", - "state": "ID", - "lat": 43.6888888, - "lon": -111.8661111 - }, - "PRLI": { - "id": "PRLI", - "city": "South Fork Payette River at Lowman, ID", - "state": "ID", - "lat": 44.0847222, - "lon": -115.6027777 - }, - "PRPI": { - "id": "PRPI", - "city": "Payette River near Payette, ID", - "state": "ID", - "lat": 44.0424999, - "lon": -116.9241666 - }, - "PSFI": { - "id": "PSFI", - "city": "Post Falls", - "state": "ID", - "lat": 47.71366, - "lon": -116.9701 - }, - "KACZ": { - "id": "KACZ", - "city": "Henderson Field Airport", - "state": "NC", - "lat": 34.71786, - "lon": -78.00389 - }, - "KAFP": { - "id": "KAFP", - "city": "Anson County Airport", - "state": "NC", - "lat": 35.01944, - "lon": -80.07836 - }, - "KAKH": { - "id": "KAKH", - "city": "Gastonia Municipal Airport", - "state": "NC", - "lat": 35.1968699, - "lon": -81.15545 - }, - "KASJ": { - "id": "KASJ", - "city": "Ahoskie, Tri-County Airport", - "state": "NC", - "lat": 36.2975, - "lon": -77.17083 - }, - "KAVL": { - "id": "KAVL", - "city": "Asheville, Asheville Regional Airport", - "state": "NC", - "lat": 35.43194, - "lon": -82.5375 - }, - "KBUY": { - "id": "KBUY", - "city": "Burlington Alamance Regional Airport", - "state": "NC", - "lat": 36.04753, - "lon": -79.47375 - }, - "KCLT": { - "id": "KCLT", - "city": "Charlotte/Douglas International Airport", - "state": "NC", - "lat": 35.2083299, - "lon": -80.96139 - }, - "KCPC": { - "id": "KCPC", - "city": "Whiteville, Columbus County Municipal Airport", - "state": "NC", - "lat": 34.27278, - "lon": -78.715 - }, - "KCTZ": { - "id": "KCTZ", - "city": "Sampson County Airport", - "state": "NC", - "lat": 34.97522, - "lon": -78.36276 - }, - "KDPL": { - "id": "KDPL", - "city": "Duplin County Airport", - "state": "NC", - "lat": 34.99942, - "lon": -77.97995 - }, - "KECG": { - "id": "KECG", - "city": "Elizabeth City C/G Regional Airport", - "state": "NC", - "lat": 36.25771, - "lon": -76.1716 - }, - "KEDE": { - "id": "KEDE", - "city": "Edenton, Northeastern Regional Airport", - "state": "NC", - "lat": 36.02778, - "lon": -76.56722 - }, - "KEHO": { - "id": "KEHO", - "city": "Shelby Municipal Airport", - "state": "NC", - "lat": 35.2556299, - "lon": -81.59858 - }, - "KEQY": { - "id": "KEQY", - "city": "Monroe, Monroe Airport", - "state": "NC", - "lat": 35.01694, - "lon": -80.62056 - }, - "KETC": { - "id": "KETC", - "city": "Tarboro-Edgecombe Airport", - "state": "NC", - "lat": 35.9373, - "lon": -77.54648 - }, - "KEWN": { - "id": "KEWN", - "city": "New Bern, Craven County Regional Airport", - "state": "NC", - "lat": 35.0675, - "lon": -77.04722 - }, - "KEXX": { - "id": "KEXX", - "city": "Lexington, Davidson County Airport", - "state": "NC", - "lat": 35.78111, - "lon": -80.30389 - }, - "KEYF": { - "id": "KEYF", - "city": "Curtis L Brown Jr. Field Airport", - "state": "NC", - "lat": 34.60418, - "lon": -78.57902 - }, - "KFAY": { - "id": "KFAY", - "city": "Fayetteville, Fayetteville Regional Airport", - "state": "NC", - "lat": 34.98944, - "lon": -78.88 - }, - "KFBG": { - "id": "KFBG", - "city": "Fort Bragg / Simmons Army Airfield", - "state": "NC", - "lat": 35.1314, - "lon": -78.93158 - }, - "KFFA": { - "id": "KFFA", - "city": "Kill Devil Hills, First Flight Airport", - "state": "NC", - "lat": 36.01667, - "lon": -75.66667 - }, - "KFQD": { - "id": "KFQD", - "city": "Rutherfordton, Rutherford County-Marchman Field Airport", - "state": "NC", - "lat": 35.42833, - "lon": -81.935 - }, - "KGEV": { - "id": "KGEV", - "city": "Jefferson - Ashe County Airport", - "state": "NC", - "lat": 36.43333, - "lon": -81.41667 - }, - "KGSB": { - "id": "KGSB", - "city": "Seymour-Johnson Air Force Base", - "state": "NC", - "lat": 35.34457, - "lon": -77.94583 - }, - "KGSO": { - "id": "KGSO", - "city": "Greensboro, Piedmont Triad International Airport", - "state": "NC", - "lat": 36.0974999, - "lon": -79.94361 - }, - "KGWW": { - "id": "KGWW", - "city": "Goldsboro, Goldsboro-Wayne Municipal Airport", - "state": "NC", - "lat": 35.46056, - "lon": -77.965 - }, - "KHBI": { - "id": "KHBI", - "city": "Asheboro, Asheboro Municipal Airport", - "state": "NC", - "lat": 35.6538899, - "lon": -79.895 - }, - "KHFF": { - "id": "KHFF", - "city": "Mackall U. S. Army Airfield", - "state": "NC", - "lat": 35.03333, - "lon": -79.5 - }, - "KHKY": { - "id": "KHKY", - "city": "Hickory, Hickory Regional Airport", - "state": "NC", - "lat": 35.74222, - "lon": -81.38222 - }, - "KHNZ": { - "id": "KHNZ", - "city": "Henderson-Oxford Airport", - "state": "NC", - "lat": 36.36352, - "lon": -78.52889 - }, - "KHRJ": { - "id": "KHRJ", - "city": "Erwin, Harnett County Airport", - "state": "NC", - "lat": 35.37861, - "lon": -78.73361 - }, - "KHSE": { - "id": "KHSE", - "city": "Hatteras, Mitchell Field", - "state": "NC", - "lat": 35.23222, - "lon": -75.6225 - }, - "KILM": { - "id": "KILM", - "city": "Wilmington International Airport", - "state": "NC", - "lat": 34.26681, - "lon": -77.89987 - }, - "KINT": { - "id": "KINT", - "city": "Winston Salem, Smith Reynolds Airport", - "state": "NC", - "lat": 36.13333, - "lon": -80.22472 - }, - "KIPJ": { - "id": "KIPJ", - "city": "Lincolnton, Lincolnton-Lincoln County Regional Airport", - "state": "NC", - "lat": 35.48306, - "lon": -81.16139 - }, - "KISO": { - "id": "KISO", - "city": "Kinston, Kinston Regional Jetport at Stallings Field", - "state": "NC", - "lat": 35.3333299, - "lon": -77.61667 - }, - "KIXA": { - "id": "KIXA", - "city": "Halifax-Northampton Regional Airport", - "state": "NC", - "lat": 36.33, - "lon": -77.635 - }, - "KJNX": { - "id": "KJNX", - "city": "Smithfield, Johnston County Airport", - "state": "NC", - "lat": 35.54083, - "lon": -78.39028 - }, - "KJQF": { - "id": "KJQF", - "city": "Concord Regional Airport", - "state": "NC", - "lat": 35.3896299, - "lon": -80.70735 - }, - "KLBT": { - "id": "KLBT", - "city": "Lumberton Municipal Airport", - "state": "NC", - "lat": 34.60817, - "lon": -79.059 - }, - "KLHZ": { - "id": "KLHZ", - "city": "Franklin County Airport", - "state": "NC", - "lat": 36.02288, - "lon": -78.33405 - }, - "KMCZ": { - "id": "KMCZ", - "city": "Martin County Airport", - "state": "NC", - "lat": 35.86219, - "lon": -77.1782 - }, - "KMEB": { - "id": "KMEB", - "city": "Laurinburg Maxton Airport", - "state": "NC", - "lat": 34.79132, - "lon": -79.3683 - }, - "KMQI": { - "id": "KMQI", - "city": "Manteo / Dare County Regional", - "state": "NC", - "lat": 35.91667, - "lon": -75.7 - }, - "KMRH": { - "id": "KMRH", - "city": "Beaufort Smith Field", - "state": "NC", - "lat": 34.73259, - "lon": -76.6566 - }, - "KMRN": { - "id": "KMRN", - "city": "Morganton-Lenoir Airport", - "state": "NC", - "lat": 35.81922, - "lon": -81.60971 - }, - "KMWK": { - "id": "KMWK", - "city": "Mount Airy/Surry County Airport", - "state": "NC", - "lat": 36.45675, - "lon": -80.55483 - }, - "KNBT": { - "id": "KNBT", - "city": "Piney Island, Bt-11 Bombing Range", - "state": "NC", - "lat": 35.02222, - "lon": -76.4625 - }, - "KNCA": { - "id": "KNCA", - "city": "MCAS New River", - "state": "NC", - "lat": 34.70627, - "lon": -77.44066 - }, - "KNJM": { - "id": "KNJM", - "city": "Bogue Field Marine Corps Auxiliary Field", - "state": "NC", - "lat": 34.69403, - "lon": -77.02945 - }, - "KNKT": { - "id": "KNKT", - "city": "Cherry Point Marine Corps Air Station", - "state": "NC", - "lat": 34.89719, - "lon": -76.88135 - }, - "KOAJ": { - "id": "KOAJ", - "city": "Jacksonville, Albert J Ellis Airport", - "state": "NC", - "lat": 34.8333299, - "lon": -77.61667 - }, - "KOCW": { - "id": "KOCW", - "city": "Washington, Warren Field Airport", - "state": "NC", - "lat": 35.57056, - "lon": -77.0497199 - }, - "KONX": { - "id": "KONX", - "city": "Currituck, Currituck County Airport", - "state": "NC", - "lat": 36.39889, - "lon": -76.01611 - }, - "KPGV": { - "id": "KPGV", - "city": "Pitt-Greenville Airport", - "state": "NC", - "lat": 35.63742, - "lon": -77.38506 - }, - "KPOB": { - "id": "KPOB", - "city": "Pope Air Force Base", - "state": "NC", - "lat": 35.17531, - "lon": -79.00771 - }, - "KRCZ": { - "id": "KRCZ", - "city": "Rockingham-Hamlet Airport", - "state": "NC", - "lat": 34.8954499, - "lon": -79.75755 - }, - "KRDU": { - "id": "KRDU", - "city": "Raleigh / Durham, Raleigh-Durham International Airport", - "state": "NC", - "lat": 35.89223, - "lon": -78.78185 - }, - "KRHP": { - "id": "KRHP", - "city": "Andrews-Murphy Airport", - "state": "NC", - "lat": 35.19394, - "lon": -83.86182 - }, - "KRUQ": { - "id": "KRUQ", - "city": "Rowan County Airport", - "state": "NC", - "lat": 35.64417, - "lon": -80.52359 - }, - "KRWI": { - "id": "KRWI", - "city": "Rocky Mount, Rocky Mount-Wilson Regional Airport", - "state": "NC", - "lat": 35.8549999, - "lon": -77.89306 - }, - "KSCR": { - "id": "KSCR", - "city": "Siler City Municipal Airport", - "state": "NC", - "lat": 35.7043, - "lon": -79.5043 - }, - "KSIF": { - "id": "KSIF", - "city": "Reidsville, Rockingham County NC Shiloh Airport", - "state": "NC", - "lat": 36.43722, - "lon": -79.85083 - }, - "KSOP": { - "id": "KSOP", - "city": "Pinehurst/Southern Pines, Moore County Airport", - "state": "NC", - "lat": 35.23333, - "lon": -79.4 - }, - "KSUT": { - "id": "KSUT", - "city": "Brunswick County Airport", - "state": "NC", - "lat": 33.92921, - "lon": -78.07223 - }, - "KSVH": { - "id": "KSVH", - "city": "Statesville Municipal Airport", - "state": "NC", - "lat": 35.76362, - "lon": -80.9473 - }, - "KTDF": { - "id": "KTDF", - "city": "Roxboro, Person County Airport", - "state": "NC", - "lat": 36.2849999, - "lon": -78.98417 - }, - "KTNB": { - "id": "KTNB", - "city": "Watauga County Hospital Heliport", - "state": "NC", - "lat": 36.19856, - "lon": -81.65171 - }, - "KTQV": { - "id": "KTQV", - "city": "DURHAM/DUKE", - "state": "NC", - "lat": 36, - "lon": -78.9333 - }, - "KTTA": { - "id": "KTTA", - "city": "Sanford, Sanford-Lee County Regional Airport", - "state": "NC", - "lat": 35.5825, - "lon": -79.10139 - }, - "KUKF": { - "id": "KUKF", - "city": "North Wilkesboro, Wilkes County Airport", - "state": "NC", - "lat": 36.21667, - "lon": -81.08333 - }, - "KVUJ": { - "id": "KVUJ", - "city": "Albemarle, Stanly County Airport", - "state": "NC", - "lat": 35.41667, - "lon": -80.15083 - }, - "KLRY": { - "id": "KLRY", - "city": "Harrisonville Lawrence Smith Memorial Airport", - "state": "MO", - "lat": 38.611, - "lon": -94.3421 - }, - "KLXT": { - "id": "KLXT", - "city": "Lee's Summit, Lee's Summit Municipal Airport", - "state": "MO", - "lat": 38.95972, - "lon": -94.37167 - }, - "KMAW": { - "id": "KMAW", - "city": "Malden Municipal Airport", - "state": "MO", - "lat": 36.6004999, - "lon": -89.9922 - }, - "KMBY": { - "id": "KMBY", - "city": "Omar N Bradley Airport", - "state": "MO", - "lat": 39.46341, - "lon": -92.42638 - }, - "KMCI": { - "id": "KMCI", - "city": "Kansas City, Kansas City International Airport", - "state": "MO", - "lat": 39.29722, - "lon": -94.73056 - }, - "KMHL": { - "id": "KMHL", - "city": "Marshall Memorial Municipal Airport", - "state": "MO", - "lat": 39.0955, - "lon": -93.2028 - }, - "KMKC": { - "id": "KMKC", - "city": "Kansas City, Kansas City Downtown Airport", - "state": "MO", - "lat": 39.12083, - "lon": -94.59694 - }, - "KMYJ": { - "id": "KMYJ", - "city": "Mexico Memorial Airport", - "state": "MO", - "lat": 39.1575, - "lon": -91.8182999 - }, - "KOZS": { - "id": "KOZS", - "city": "Camdenton Memorial Airport", - "state": "MO", - "lat": 37.9739999, - "lon": -92.6912 - }, - "KPCD": { - "id": "KPCD", - "city": "Perryville Regional Airport", - "state": "MO", - "lat": 37.86867, - "lon": -89.86214 - }, - "KPOF": { - "id": "KPOF", - "city": "Poplar Bluff, Poplar Bluff Municipal Airport", - "state": "MO", - "lat": 36.77056, - "lon": -90.32222 - }, - "KRCM": { - "id": "KRCM", - "city": "Skyhaven Airport", - "state": "MO", - "lat": 38.7842, - "lon": -93.8028999 - }, - "KSET": { - "id": "KSET", - "city": "St. Charles, St. Charles County Smartt Airport", - "state": "MO", - "lat": 38.93056, - "lon": -90.4325 - }, - "KSGF": { - "id": "KSGF", - "city": "Springfield-Branson National Airport", - "state": "MO", - "lat": 37.23972, - "lon": -93.38972 - }, - "KSIK": { - "id": "KSIK", - "city": "Sikeston Memorial Municipal Airport", - "state": "MO", - "lat": 36.8989, - "lon": -89.5618 - }, - "KSTJ": { - "id": "KSTJ", - "city": "St. Joseph, Rosecrans Memorial Airport", - "state": "MO", - "lat": 39.76806, - "lon": -94.90917 - }, - "KSTL": { - "id": "KSTL", - "city": "St. Louis Lambert International Airport", - "state": "MO", - "lat": 38.7525, - "lon": -90.37361 - }, - "KSUS": { - "id": "KSUS", - "city": "St. Louis, Spirit Of St. Louis Airport", - "state": "MO", - "lat": 38.65722, - "lon": -90.65583 - }, - "KSZL": { - "id": "KSZL", - "city": "Whiteman Air Force Base", - "state": "MO", - "lat": 38.73333, - "lon": -93.55 - }, - "KTBN": { - "id": "KTBN", - "city": "Fort Leonard Wood", - "state": "MO", - "lat": 37.73333, - "lon": -92.13333 - }, - "KTKX": { - "id": "KTKX", - "city": "Kennett - Kennett Memorial Airport", - "state": "MO", - "lat": 36.22256, - "lon": -90.03671 - }, - "KUNO": { - "id": "KUNO", - "city": "West Plains, West Plains Municipal Airport", - "state": "MO", - "lat": 36.87917, - "lon": -91.905 - }, - "KUUV": { - "id": "KUUV", - "city": "SULLIVAN", - "state": "MO", - "lat": 38.2335, - "lon": -91.16433 - }, - "KVER": { - "id": "KVER", - "city": "Jesse Viertel Memorial Airport", - "state": "MO", - "lat": 38.94672, - "lon": -92.68267 - }, - "KVIH": { - "id": "KVIH", - "city": "Rolla / Vichy, Rolla National Airport", - "state": "MO", - "lat": 38.13194, - "lon": -91.76528 - }, - "KALB": { - "id": "KALB", - "city": "Albany International Airport", - "state": "NY", - "lat": 42.74722, - "lon": -73.79912 - }, - "KART": { - "id": "KART", - "city": "Watertown, Watertown International Airport", - "state": "NY", - "lat": 43.99194, - "lon": -76.02167 - }, - "KBGM": { - "id": "KBGM", - "city": "Greater Binghamton Airport", - "state": "NY", - "lat": 42.20778, - "lon": -75.98139 - }, - "KBUF": { - "id": "KBUF", - "city": "Buffalo, Greater Buffalo International Airport", - "state": "NY", - "lat": 42.93998, - "lon": -78.73604 - }, - "KCZG": { - "id": "KCZG", - "city": "ENDICOTT", - "state": "NY", - "lat": 42.0785, - "lon": -76.09633 - }, - "KDKK": { - "id": "KDKK", - "city": "Dunkirk, Chautauqua County / Dunkirk Airport", - "state": "NY", - "lat": 42.49306, - "lon": -79.27583 - }, - "KDSV": { - "id": "KDSV", - "city": "Dansville, Dansville Municipal Airport", - "state": "NY", - "lat": 42.56944, - "lon": -77.71444 - }, - "KELM": { - "id": "KELM", - "city": "Elmira, Elmira / Corning Regional Airport", - "state": "NY", - "lat": 42.15639, - "lon": -76.90278 - }, - "KELZ": { - "id": "KELZ", - "city": "Wellsville, Wellsville Municipal Airport", - "state": "NY", - "lat": 42.1075, - "lon": -77.98444 - }, - "KFOK": { - "id": "KFOK", - "city": "The Gabreski Airport", - "state": "NY", - "lat": 40.85053, - "lon": -72.61927 - }, - "KFRG": { - "id": "KFRG", - "city": "Farmingdale - Republic Airport", - "state": "NY", - "lat": 40.73443, - "lon": -73.41639 - }, - "KFZY": { - "id": "KFZY", - "city": "Fulton, Oswego County Airport", - "state": "NY", - "lat": 43.35083, - "lon": -76.38806 - }, - "KGFL": { - "id": "KGFL", - "city": "Glens Falls, Floyd Bennett Memorial Airport", - "state": "NY", - "lat": 43.34111, - "lon": -73.61056 - }, - "KGTB": { - "id": "KGTB", - "city": "Fort Drum / Wheeler-Sack U. S. Army Airfield", - "state": "NY", - "lat": 44.05, - "lon": -75.73333 - }, - "KGVQ": { - "id": "KGVQ", - "city": "Genesee County Airport", - "state": "NY", - "lat": 43.03175, - "lon": -78.16967 - }, - "KHPN": { - "id": "KHPN", - "city": "White Plains - Westchester County Airport", - "state": "NY", - "lat": 41.06237, - "lon": -73.70456 - }, - "KHTF": { - "id": "KHTF", - "city": "HORNELL", - "state": "NY", - "lat": 42.38216, - "lon": -77.68216 - }, - "KHWV": { - "id": "KHWV", - "city": "Shirley, Brookhaven Airport", - "state": "NY", - "lat": 40.82167, - "lon": -72.8688899 - }, - "KIAG": { - "id": "KIAG", - "city": "Niagara Falls, Niagara Falls International Airport", - "state": "NY", - "lat": 43.1082899, - "lon": -78.93818 - }, - "KISP": { - "id": "KISP", - "city": "Islip, Long Island Mac Arthur Airport", - "state": "NY", - "lat": 40.79389, - "lon": -73.10167 - }, - "KITH": { - "id": "KITH", - "city": "Ithaca Tompkins International Airport", - "state": "NY", - "lat": 42.49083, - "lon": -76.45833 - }, - "KIUA": { - "id": "KIUA", - "city": "Canandaigua Airport", - "state": "NY", - "lat": 42.9089, - "lon": -77.32523 - }, - "KJFK": { - "id": "KJFK", - "city": "New York, Kennedy International Airport", - "state": "NY", - "lat": 40.63915, - "lon": -73.76393 - }, - "KJHW": { - "id": "KJHW", - "city": "Jamestown, Chautauqua County/Jamestown Airport", - "state": "NY", - "lat": 42.15, - "lon": -79.26667 - }, - "KJPX": { - "id": "KJPX", - "city": "East Hampton Town Airport", - "state": "NY", - "lat": 40.95942, - "lon": -72.25167 - }, - "KJRB": { - "id": "KJRB", - "city": "New York Downtown Manhattan", - "state": "NY", - "lat": 40.7012, - "lon": -74.009 - }, - "KLGA": { - "id": "KLGA", - "city": "New York, La Guardia Airport", - "state": "NY", - "lat": 40.77917, - "lon": -73.88 - }, - "KLKP": { - "id": "KLKP", - "city": "Lake Placid Airport", - "state": "NY", - "lat": 44.26448, - "lon": -73.96187 - }, - "KMGJ": { - "id": "KMGJ", - "city": "Montgomery, Orange County Airport", - "state": "NY", - "lat": 41.50917, - "lon": -74.265 - }, - "KMSS": { - "id": "KMSS", - "city": "Massena, Massena International-Richards Field", - "state": "NY", - "lat": 44.93583, - "lon": -74.84556 - }, - "KMTP": { - "id": "KMTP", - "city": "Montauk, Montauk Airport", - "state": "NY", - "lat": 41.07306, - "lon": -71.92333 - }, - "KNYC": { - "id": "KNYC", - "city": "New York City, Central Park", - "state": "NY", - "lat": 40.78333, - "lon": -73.9666699 - }, - "KOGS": { - "id": "KOGS", - "city": "Ogdensburg International Airport", - "state": "NY", - "lat": 44.68186, - "lon": -75.4655 - }, - "KOIC": { - "id": "KOIC", - "city": "NORWICH", - "state": "NY", - "lat": 42.5665, - "lon": -75.52416 - }, - "KOLE": { - "id": "KOLE", - "city": "Cattaraugus County-Olean Airport", - "state": "NY", - "lat": 42.24119, - "lon": -78.37136 - }, - "KPBG": { - "id": "KPBG", - "city": "Plattsburgh International Airport ", - "state": "NY", - "lat": 44.65, - "lon": -73.4666699 - }, - "KPEO": { - "id": "KPEO", - "city": "Penn Yan, Penn Yan Airport", - "state": "NY", - "lat": 42.64306, - "lon": -77.04944 - }, - "KPOU": { - "id": "KPOU", - "city": "Poughkeepsie, Dutchess County Airport", - "state": "NY", - "lat": 41.62667, - "lon": -73.88417 - }, - "KPTD": { - "id": "KPTD", - "city": "Potsdam Municipal Airport/Damon Field", - "state": "NY", - "lat": 44.67667, - "lon": -74.94844 - }, - "KRME": { - "id": "KRME", - "city": "Griffiss International Airport", - "state": "NY", - "lat": 43.23333, - "lon": -75.4 - }, - "KROC": { - "id": "KROC", - "city": "Rochester, Greater Rochester International Airport", - "state": "NY", - "lat": 43.11667, - "lon": -77.67667 - }, - "KSCH": { - "id": "KSCH", - "city": "Schenectady Airport", - "state": "NY", - "lat": 42.85, - "lon": -73.93333 - }, - "KSDC": { - "id": "KSDC", - "city": "Williamson-Sodus Airport", - "state": "NY", - "lat": 43.23459, - "lon": -77.11946 - }, - "KSLK": { - "id": "KSLK", - "city": "Saranac Lake, Adirondack Regional Airport", - "state": "NY", - "lat": 44.39306, - "lon": -74.20278 - }, - "KSWF": { - "id": "KSWF", - "city": "Newburgh / Stewart", - "state": "NY", - "lat": 41.5, - "lon": -74.1 - }, - "KSYR": { - "id": "KSYR", - "city": "Syracuse, Syracuse Hancock International Airport", - "state": "NY", - "lat": 43.10917, - "lon": -76.10333 - }, - "KVGC": { - "id": "KVGC", - "city": "Hamilton Municipal Airport", - "state": "NY", - "lat": 42.84344, - "lon": -75.56119 - }, - "KAKQ": { - "id": "KAKQ", - "city": "Wakefield Municipal Airport", - "state": "VA", - "lat": 36.98274, - "lon": -77.00137 - }, - "KAVC": { - "id": "KAVC", - "city": "South Hill, Mecklenburg-Brunswick Regional Airport", - "state": "VA", - "lat": 36.68861, - "lon": -78.05417 - }, - "KBCB": { - "id": "KBCB", - "city": "Virginia Tech Airport", - "state": "VA", - "lat": 37.21667, - "lon": -80.41667 - }, - "KBKT": { - "id": "KBKT", - "city": "Ft. Pickett / Blackstone", - "state": "VA", - "lat": 37.0833299, - "lon": -77.95 - }, - "KCHO": { - "id": "KCHO", - "city": "Charlottesville-Albemarle Airport", - "state": "VA", - "lat": 38.13738, - "lon": -78.45516 - }, - "KCJR": { - "id": "KCJR", - "city": "Culpeper Regional Airport", - "state": "VA", - "lat": 38.52607, - "lon": -77.85738 - }, - "KCPK": { - "id": "KCPK", - "city": "Chesapeake, Chesapeake Municipal Airport", - "state": "VA", - "lat": 36.66556, - "lon": -76.32056 - }, - "KCXE": { - "id": "KCXE", - "city": "Chase City Municipal Airport", - "state": "VA", - "lat": 36.7883, - "lon": -78.5016 - }, - "KDAA": { - "id": "KDAA", - "city": "Fort Belvoir", - "state": "VA", - "lat": 38.71667, - "lon": -77.18333 - }, - "KDAN": { - "id": "KDAN", - "city": "Danville, Danville Regional Airport", - "state": "VA", - "lat": 36.57278, - "lon": -79.33611 - }, - "KDCA": { - "id": "KDCA", - "city": "Washington/Reagan National Airport, DC", - "state": "VA", - "lat": 38.84833, - "lon": -77.03417 - }, - "KEMV": { - "id": "KEMV", - "city": "Emporia, Emporia-Greensville Regional Airport", - "state": "VA", - "lat": 36.68694, - "lon": -77.48278 - }, - "KEZF": { - "id": "KEZF", - "city": "Fredericksburg, Shannon Airport", - "state": "VA", - "lat": 38.26667, - "lon": -77.45 - }, - "KFAF": { - "id": "KFAF", - "city": "Fort Eustis / Felker", - "state": "VA", - "lat": 37.13333, - "lon": -76.61667 - }, - "KFCI": { - "id": "KFCI", - "city": "Chesterfield County Airport", - "state": "VA", - "lat": 37.406444, - "lon": -77.524833 - }, - "KFKN": { - "id": "KFKN", - "city": "Franklin / J B Rose", - "state": "VA", - "lat": 36.7, - "lon": -76.9 - }, - "KFRR": { - "id": "KFRR", - "city": "Front Royal-warren County Airport", - "state": "VA", - "lat": 38.9174999, - "lon": -78.2535 - }, - "KFVX": { - "id": "KFVX", - "city": "Farmville", - "state": "VA", - "lat": 37.35, - "lon": -78.43333 - }, - "KFYJ": { - "id": "KFYJ", - "city": "West Point, Middle Peninsula Regional Airport", - "state": "VA", - "lat": 37.52111, - "lon": -76.7644399 - }, - "KGVE": { - "id": "KGVE", - "city": "Gordonsville Municipal Airport", - "state": "VA", - "lat": 38.156, - "lon": -78.1658 - }, - "KHEF": { - "id": "KHEF", - "city": "Manassas, Manassas Regional Airport/Harry P. Davis Field", - "state": "VA", - "lat": 38.71667, - "lon": -77.51667 - }, - "KHLX": { - "id": "KHLX", - "city": "Hillsville", - "state": "VA", - "lat": 36.76667, - "lon": -80.81667 - }, - "KHSP": { - "id": "KHSP", - "city": "Hot Springs / Ingalls", - "state": "VA", - "lat": 37.95, - "lon": -79.83333 - }, - "KHWY": { - "id": "KHWY", - "city": "Warrenton-Fauquier Airport", - "state": "VA", - "lat": 38.5876499, - "lon": -77.71501 - }, - "KIAD": { - "id": "KIAD", - "city": "Washington/Dulles International Airport, DC", - "state": "VA", - "lat": 38.93472, - "lon": -77.4475 - }, - "KJFZ": { - "id": "KJFZ", - "city": "Tazewell County Airport", - "state": "VA", - "lat": 37.064, - "lon": -81.798 - }, - "KJGG": { - "id": "KJGG", - "city": "Williamsburg-Jamestown Airport", - "state": "VA", - "lat": 37.24157, - "lon": -76.71672 - }, - "KJYO": { - "id": "KJYO", - "city": "Leesburg / Godfrey", - "state": "VA", - "lat": 39.0833299, - "lon": -77.56667 - }, - "KLFI": { - "id": "KLFI", - "city": "Langley Air Force Base", - "state": "VA", - "lat": 37.0833299, - "lon": -76.35 - }, - "KLKU": { - "id": "KLKU", - "city": "Louisa, Louisa County Airport/Freeman Field", - "state": "VA", - "lat": 38.00972, - "lon": -77.97028 - }, - "KLNP": { - "id": "KLNP", - "city": "Wise / Lonesome Pine", - "state": "VA", - "lat": 36.98333, - "lon": -82.53333 - }, - "KLUA": { - "id": "KLUA", - "city": "Luray Caverns", - "state": "VA", - "lat": 38.6671, - "lon": -78.5006 - }, - "KLVL": { - "id": "KLVL", - "city": "Lawrenceville/Brunswick Municipal Airport", - "state": "VA", - "lat": 36.7727999, - "lon": -77.7943 - }, - "KLYH": { - "id": "KLYH", - "city": "Lynchburg, Lynchburg Regional Airport", - "state": "VA", - "lat": 37.32083, - "lon": -79.20667 - }, - "KMKJ": { - "id": "KMKJ", - "city": "Marion / Wytheville", - "state": "VA", - "lat": 36.9, - "lon": -81.35 - }, - "KMTV": { - "id": "KMTV", - "city": "Martinsville", - "state": "VA", - "lat": 36.63333, - "lon": -80.01667 - }, - "KNFE": { - "id": "KNFE", - "city": "Fentress, Naval Auxiliary Landing Field", - "state": "VA", - "lat": 36.70083, - "lon": -76.12833 - }, - "KNGU": { - "id": "KNGU", - "city": "Norfolk, Naval Air Station", - "state": "VA", - "lat": 36.93361, - "lon": -76.29583 - }, - "KNTU": { - "id": "KNTU", - "city": "Virginia Beach, Oceana, Naval Air Station", - "state": "VA", - "lat": 36.82111, - "lon": -76.02833 - }, - "KNYG": { - "id": "KNYG", - "city": "Quantico Marine Corps Airfield - Turner Field", - "state": "VA", - "lat": 38.50326, - "lon": -77.30129 - }, - "KOFP": { - "id": "KOFP", - "city": "Ashland, Hanover County Municipal Airport", - "state": "VA", - "lat": 37.70806, - "lon": -77.43444 - }, - "KOKV": { - "id": "KOKV", - "city": "Winchester Regional", - "state": "VA", - "lat": 39.15, - "lon": -78.15 - }, - "KOMH": { - "id": "KOMH", - "city": "Orange, Orange County Airport", - "state": "VA", - "lat": 38.24722, - "lon": -78.04556 - }, - "KORF": { - "id": "KORF", - "city": "Norfolk, Norfolk International Airport", - "state": "VA", - "lat": 36.90361, - "lon": -76.19194 - }, - "KPHF": { - "id": "KPHF", - "city": "Newport News, Newport News / Williamsburg International Airport", - "state": "VA", - "lat": 37.13194, - "lon": -76.49306 - }, - "KPSK": { - "id": "KPSK", - "city": "Dublin / New River Valley", - "state": "VA", - "lat": 37.13333, - "lon": -80.68333 - }, - "KPTB": { - "id": "KPTB", - "city": "Petersburg, Dinwiddie County Airport", - "state": "VA", - "lat": 37.18333, - "lon": -77.51667 - }, - "KPVG": { - "id": "KPVG", - "city": "Norfolk Hampton Roads Executive Airport", - "state": "VA", - "lat": 36.7801, - "lon": -76.4488 - }, - "KRIC": { - "id": "KRIC", - "city": "Richmond, Richmond International Airport", - "state": "VA", - "lat": 37.51111, - "lon": -77.32333 - }, - "KRMN": { - "id": "KRMN", - "city": "Stafford, Stafford Regional Airport", - "state": "VA", - "lat": 38.39806, - "lon": -77.45528 - }, - "KROA": { - "id": "KROA", - "city": "Roanoke, Roanoke Regional Airport", - "state": "VA", - "lat": 37.31694, - "lon": -79.97417 - }, - "KSFQ": { - "id": "KSFQ", - "city": "Suffolk, Suffolk Municipal Airport", - "state": "VA", - "lat": 36.68222, - "lon": -76.60194 - }, - "KSHD": { - "id": "KSHD", - "city": "Staunton / Shenandoah", - "state": "VA", - "lat": 38.26667, - "lon": -78.9 - }, - "KTGI": { - "id": "KTGI", - "city": "Tangier Island Airport", - "state": "VA", - "lat": 37.82587, - "lon": -75.99766 - }, - "KVBW": { - "id": "KVBW", - "city": "Bridgewater Air Park", - "state": "VA", - "lat": 38.36674, - "lon": -78.96033 - }, - "KVJI": { - "id": "KVJI", - "city": "Abingdon", - "state": "VA", - "lat": 36.68333, - "lon": -82.03333 - }, - "KWAL": { - "id": "KWAL", - "city": "Wallops Flight Facility Airport", - "state": "VA", - "lat": 37.9372, - "lon": -75.46619 - }, - "KXSA": { - "id": "KXSA", - "city": "Tappahannock-Essex County Airport", - "state": "VA", - "lat": 37.859611, - "lon": -76.894111 - }, - "PAAD": { - "id": "PAAD", - "city": "Point Thomson Airstrip", - "state": "AK", - "lat": 70.136, - "lon": -146.2901 - }, - "PAAK": { - "id": "PAAK", - "city": "Atka, Atka Airport", - "state": "AK", - "lat": 52.22028, - "lon": -174.20639 - }, - "PAAQ": { - "id": "PAAQ", - "city": "Palmer, Palmer Municipal Airport", - "state": "AK", - "lat": 61.6, - "lon": -149.08333 - }, - "PABA": { - "id": "PABA", - "city": "Barter Island, Barter Island LRRS Airport", - "state": "AK", - "lat": 70.1338899, - "lon": -143.57694 - }, - "PABE": { - "id": "PABE", - "city": "Bethel, Bethel Airport", - "state": "AK", - "lat": 60.77972, - "lon": -161.83778 - }, - "PABI": { - "id": "PABI", - "city": "Delta Junction/Ft Greely, Allen Army Airfield", - "state": "AK", - "lat": 64, - "lon": -145.73333 - }, - "PABL": { - "id": "PABL", - "city": "Buckland, Buckland Airport", - "state": "AK", - "lat": 65.98222, - "lon": -161.15194 - }, - "PABR": { - "id": "PABR", - "city": "Wiley Post-Will Rogers Memorial Airport", - "state": "AK", - "lat": 71.28528, - "lon": -156.76583 - }, - "PABT": { - "id": "PABT", - "city": "Bettles, Bettles Airport", - "state": "AK", - "lat": 66.91667, - "lon": -151.51667 - }, - "PABV": { - "id": "PABV", - "city": "Birchwood, Birchwood Airport", - "state": "AK", - "lat": 61.41667, - "lon": -149.51667 - }, - "PACD": { - "id": "PACD", - "city": "Cold Bay, Cold Bay Airport", - "state": "AK", - "lat": 55.22083, - "lon": -162.72778 - }, - "PACV": { - "id": "PACV", - "city": "Cordova, Merle K (Mudhole) Smith Airport", - "state": "AK", - "lat": 60.49167, - "lon": -145.47778 - }, - "PACX": { - "id": "PACX", - "city": "Coldfoot Airport", - "state": "AK", - "lat": 67.25217, - "lon": -150.20391 - }, - "PACZ": { - "id": "PACZ", - "city": "Cape Romanzof, Cape Romanzof LRRS Airport", - "state": "AK", - "lat": 61.78333, - "lon": -166.03333 - }, - "PADE": { - "id": "PADE", - "city": "Deering, Deering/New Airport", - "state": "AK", - "lat": 66.08333, - "lon": -162.75 - }, - "PADG": { - "id": "PADG", - "city": "Red Dog", - "state": "AK", - "lat": 68.0321, - "lon": -162.8992 - }, - "PADK": { - "id": "PADK", - "city": "Adak Island, Adak Airport", - "state": "AK", - "lat": 51.87778, - "lon": -176.64583 - }, - "PADL": { - "id": "PADL", - "city": "Dillingham, Dillingham Airport", - "state": "AK", - "lat": 59.05, - "lon": -158.51667 - }, - "PADM": { - "id": "PADM", - "city": "Marshall", - "state": "AK", - "lat": 61.8643, - "lon": -162.0261 - }, - "PADQ": { - "id": "PADQ", - "city": "Kodiak, Kodiak Airport", - "state": "AK", - "lat": 57.75, - "lon": -152.5 - }, - "PADU": { - "id": "PADU", - "city": "Unalaska, Unalaska Airport", - "state": "AK", - "lat": 53.9, - "lon": -166.53333 - }, - "PAED": { - "id": "PAED", - "city": "Anchorage, Elmendorf Air Force Base", - "state": "AK", - "lat": 61.25306, - "lon": -149.79389 - }, - "PAEG": { - "id": "PAEG", - "city": "Eagle, Eagle Airport", - "state": "AK", - "lat": 64.77639, - "lon": -141.15083 - }, - "PAEH": { - "id": "PAEH", - "city": "Cape Newenham, Cape Newenham LRRS Airport", - "state": "AK", - "lat": 58.65, - "lon": -162.0666699 - }, - "PAEI": { - "id": "PAEI", - "city": "Fairbanks, Eielson Air Force Base", - "state": "AK", - "lat": 64.65, - "lon": -147.1 - }, - "PAEL": { - "id": "PAEL", - "city": "Elfin Cove - Elfin Cove Seaplane Base", - "state": "AK", - "lat": 58.19467, - "lon": -136.34663 - }, - "PAEM": { - "id": "PAEM", - "city": "Emmonak, Emmonak Airport", - "state": "AK", - "lat": 62.78333, - "lon": -164.5 - }, - "PAEN": { - "id": "PAEN", - "city": "Kenai, Kenai Municipal Airport", - "state": "AK", - "lat": 60.57306, - "lon": -151.245 - }, - "PAFA": { - "id": "PAFA", - "city": "Fairbanks, Fairbanks International Airport", - "state": "AK", - "lat": 64.80389, - "lon": -147.87611 - }, - "PAFB": { - "id": "PAFB", - "city": "Fort Wainwright AAF", - "state": "AK", - "lat": 64.83667, - "lon": -147.59556 - }, - "PAFE": { - "id": "PAFE", - "city": "Kake - Kake Airport", - "state": "AK", - "lat": 56.964, - "lon": -133.913 - }, - "PAFR": { - "id": "PAFR", - "city": "Ft. Richardson / Bryant U. S. Army Heliport, Ak", - "state": "AK", - "lat": 61.26667, - "lon": -149.65 - }, - "PAFS": { - "id": "PAFS", - "city": "Nikolai", - "state": "AK", - "lat": 63.019, - "lon": -154.358 - }, - "PAGA": { - "id": "PAGA", - "city": "Galena, Edward G. Pitka Sr. Airport", - "state": "AK", - "lat": 64.73333, - "lon": -156.93333 - }, - "PAGB": { - "id": "PAGB", - "city": "Galbraith Lake, Galbraith Lake Airport", - "state": "AK", - "lat": 68.48333, - "lon": -149.48333 - }, - "PAGH": { - "id": "PAGH", - "city": "Shungnak Airport", - "state": "AK", - "lat": 66.8881, - "lon": -157.1624 - }, - "PAGK": { - "id": "PAGK", - "city": "Gulkana, Gulkana Airport", - "state": "AK", - "lat": 62.15, - "lon": -145.45 - }, - "PAGL": { - "id": "PAGL", - "city": "Golovin, Golovin Airport", - "state": "AK", - "lat": 64.54333, - "lon": -163.03944 - }, - "PAGM": { - "id": "PAGM", - "city": "Gambell, Gambell Airport", - "state": "AK", - "lat": 63.76667, - "lon": -171.73333 - }, - "PAGN": { - "id": "PAGN", - "city": "Angoon", - "state": "AK", - "lat": 57.5, - "lon": -134.58333 - }, - "PAGS": { - "id": "PAGS", - "city": "Gustavus, Gustavus Airport", - "state": "AK", - "lat": 58.41667, - "lon": -135.7 - }, - "PAGY": { - "id": "PAGY", - "city": "Skagway", - "state": "AK", - "lat": 59.4544, - "lon": -135.3263 - }, - "PAHC": { - "id": "PAHC", - "city": "Holy Cross", - "state": "AK", - "lat": 62.1873, - "lon": -159.77657 - }, - "PAHL": { - "id": "PAHL", - "city": "Huslia, Huslia Airport", - "state": "AK", - "lat": 65.6975, - "lon": -156.35111 - }, - "PAHN": { - "id": "PAHN", - "city": "Haines - Haines Airport", - "state": "AK", - "lat": 59.2429, - "lon": -135.5114 - }, - "PAHO": { - "id": "PAHO", - "city": "Homer, Homer Airport", - "state": "AK", - "lat": 59.65, - "lon": -151.48333 - }, - "PAHX": { - "id": "PAHX", - "city": "Shageluk Airport", - "state": "AK", - "lat": 62.6923, - "lon": -159.5692 - }, - "PAHY": { - "id": "PAHY", - "city": "Hydaburg - Hydaburg Seaplane Base", - "state": "AK", - "lat": 55.2, - "lon": -132.83333 - }, - "PAIG": { - "id": "PAIG", - "city": "Igiugig", - "state": "AK", - "lat": 59.32395, - "lon": -155.90235 - }, - "PAII": { - "id": "PAII", - "city": "Egegik, Egegik Airport", - "state": "AK", - "lat": 58.18528, - "lon": -157.38556 - }, - "PAIK": { - "id": "PAIK", - "city": "Kinana / Bob Baker Me", - "state": "AK", - "lat": 66.98333, - "lon": -160.43333 - }, - "PAIL": { - "id": "PAIL", - "city": "Iliamna, Iliamna Airport", - "state": "AK", - "lat": 59.75, - "lon": -154.9 - }, - "PAIM": { - "id": "PAIM", - "city": "Utopia Creek, Indian Mountain LRRS Airport", - "state": "AK", - "lat": 66, - "lon": -153.7 - }, - "PAIN": { - "id": "PAIN", - "city": "McKinley Park, McKinley National Park Airport", - "state": "AK", - "lat": 63.73333, - "lon": -148.91667 - }, - "PAIW": { - "id": "PAIW", - "city": "Wales", - "state": "AK", - "lat": 65.6226, - "lon": -168.0949 - }, - "PAJC": { - "id": "PAJC", - "city": "Chignik, Chignik Airport", - "state": "AK", - "lat": 56.31139, - "lon": -158.37333 - }, - "PAJK": { - "id": "PAJK", - "city": "NWS Office: Juneau", - "state": "AK", - "lat": 58.4, - "lon": -134.57001 - }, - "PAJN": { - "id": "PAJN", - "city": "Juneau, Juneau International Airport", - "state": "AK", - "lat": 58.35472, - "lon": -134.57611 - }, - "PAJZ": { - "id": "PAJZ", - "city": "Koliganek", - "state": "AK", - "lat": 59.727, - "lon": -157.2589999 - }, - "PAKF": { - "id": "PAKF", - "city": "False Pass Airport", - "state": "AK", - "lat": 54.847, - "lon": -163.41 - }, - "PAKH": { - "id": "PAKH", - "city": "Akhiok", - "state": "AK", - "lat": 56.9387, - "lon": -154.1826 - }, - "PAKK": { - "id": "PAKK", - "city": "Koyuk, Koyuk Airport", - "state": "AK", - "lat": 64.93389, - "lon": -161.15806 - }, - "PAKN": { - "id": "PAKN", - "city": "King Salmon, King Salmon Airport", - "state": "AK", - "lat": 58.67667, - "lon": -156.64917 - }, - "PAKP": { - "id": "PAKP", - "city": "Anaktuvuk Pass, Anaktuvuk Pass Airport", - "state": "AK", - "lat": 68.13361, - "lon": -151.7433299 - }, - "PAKT": { - "id": "PAKT", - "city": "Ketchikan, Ketchikan International Airport", - "state": "AK", - "lat": 55.35556, - "lon": -131.71361 - }, - "PAKU": { - "id": "PAKU", - "city": "Kuparuk, Ugnu-Kuparuk Airport", - "state": "AK", - "lat": 70.31667, - "lon": -149.58333 - }, - "PAKV": { - "id": "PAKV", - "city": "Kaltag, Kaltag Airport", - "state": "AK", - "lat": 64.31667, - "lon": -158.73333 - }, - "PAKW": { - "id": "PAKW", - "city": "Klawock - Klawock Airport", - "state": "AK", - "lat": 55.5839, - "lon": -133.067 - }, - "PAKX": { - "id": "PAKX", - "city": "WILDER NATWICK", - "state": "AK", - "lat": 60.2, - "lon": -154.3166 - }, - "PALG": { - "id": "PALG", - "city": "Kalskag", - "state": "AK", - "lat": 61.5364, - "lon": -160.3414 - }, - "PALH": { - "id": "PALH", - "city": "Anchorage, Lake Hood Seaplane Base", - "state": "AK", - "lat": 61.18333, - "lon": -149.96667 - }, - "PALP": { - "id": "PALP", - "city": "Deadhorse, Alpine Airstrip", - "state": "AK", - "lat": 70.33333, - "lon": -150.93333 - }, - "PALU": { - "id": "PALU", - "city": "Cape Lisburne, Cape Lisburne LRRS Airport", - "state": "AK", - "lat": 68.88333, - "lon": -166.1 - }, - "PAMB": { - "id": "PAMB", - "city": "Manokotak", - "state": "AK", - "lat": 58.9902, - "lon": -159.0499 - }, - "PAMC": { - "id": "PAMC", - "city": "McGrath, McGrath Airport", - "state": "AK", - "lat": 62.96667, - "lon": -155.61667 - }, - "PAMD": { - "id": "PAMD", - "city": "Middleton Island Airport", - "state": "AK", - "lat": 59.4423, - "lon": -146.3166 - }, - "PAMH": { - "id": "PAMH", - "city": "Minchumina, Minchumina Airport", - "state": "AK", - "lat": 63.88056, - "lon": -152.30056 - }, - "PAMK": { - "id": "PAMK", - "city": "St Michael Airport", - "state": "AK", - "lat": 63.49006, - "lon": -162.11039 - }, - "PAMM": { - "id": "PAMM", - "city": "Metlakatla, Metlakatla Seaplane Base", - "state": "AK", - "lat": 55.13111, - "lon": -131.57806 - }, - "PAMO": { - "id": "PAMO", - "city": "Mountain Village", - "state": "AK", - "lat": 62.0953, - "lon": -163.6819 - }, - "PAMR": { - "id": "PAMR", - "city": "Anchorage, Merrill Field Airport", - "state": "AK", - "lat": 61.21667, - "lon": -149.85 - }, - "PAMY": { - "id": "PAMY", - "city": "Mekoryuk, Mekoryuk Airport", - "state": "AK", - "lat": 60.36667, - "lon": -166.26667 - }, - "PANA": { - "id": "PANA", - "city": "Napakiak Airport", - "state": "AK", - "lat": 60.6903, - "lon": -161.9785 - }, - "PANC": { - "id": "PANC", - "city": "Anchorage, Ted Stevens Anchorage International Airport", - "state": "AK", - "lat": 61.17444, - "lon": -149.9961099 - }, - "PANI": { - "id": "PANI", - "city": "Aniak, Aniak Airport", - "state": "AK", - "lat": 61.58139, - "lon": -159.54278 - }, - "PANN": { - "id": "PANN", - "city": "Nenana Municipal Airport", - "state": "AK", - "lat": 64.54796, - "lon": -149.08398 - }, - "PANU": { - "id": "PANU", - "city": "Nulato Airport", - "state": "AK", - "lat": 64.72933, - "lon": -158.07422 - }, - "PANV": { - "id": "PANV", - "city": "Anvik, Anvik Airport", - "state": "AK", - "lat": 62.64833, - "lon": -160.18972 - }, - "PANW": { - "id": "PANW", - "city": "New Stuyahok", - "state": "AK", - "lat": 59.45, - "lon": -157.328 - }, - "PAOH": { - "id": "PAOH", - "city": "Hoonah - Hoonah Seaplane Base", - "state": "AK", - "lat": 58.097, - "lon": -135.4139999 - }, - "PAOM": { - "id": "PAOM", - "city": "Nome, Nome Airport", - "state": "AK", - "lat": 64.51194, - "lon": -165.445 - }, - "PAOR": { - "id": "PAOR", - "city": "Northway, Northway Airport", - "state": "AK", - "lat": 62.96111, - "lon": -141.92889 - }, - "PAOT": { - "id": "PAOT", - "city": "Ralph Wien Memorial Airport", - "state": "AK", - "lat": 66.88576, - "lon": -162.60624 - }, - "PAOU": { - "id": "PAOU", - "city": "Nelson Lagoon", - "state": "AK", - "lat": 56.008, - "lon": -161.16 - }, - "PAPB": { - "id": "PAPB", - "city": "St. George, St. George Airport", - "state": "AK", - "lat": 56.57861, - "lon": -169.66139 - }, - "PAPG": { - "id": "PAPG", - "city": "Petersburg", - "state": "AK", - "lat": 56.8017, - "lon": -132.9453 - }, - "PAPH": { - "id": "PAPH", - "city": "Port Heiden, Port Heiden Airport", - "state": "AK", - "lat": 56.95, - "lon": -158.63333 - }, - "PAPM": { - "id": "PAPM", - "city": "Platinum", - "state": "AK", - "lat": 59.01667, - "lon": -161.8166699 - }, - "PAPN": { - "id": "PAPN", - "city": "Pilot Point Airport", - "state": "AK", - "lat": 57.58, - "lon": -157.572 - }, - "PAPO": { - "id": "PAPO", - "city": "Point Hope, Point Hope Airport", - "state": "AK", - "lat": 68.35, - "lon": -166.8 - }, - "PAPR": { - "id": "PAPR", - "city": "Prospect Creek, Prospect Creek Airport", - "state": "AK", - "lat": 66.81278, - "lon": -150.64389 - }, - "PAPT": { - "id": "PAPT", - "city": "Puntilla", - "state": "AK", - "lat": 62.1, - "lon": -152.75 - }, - "PAQH": { - "id": "PAQH", - "city": "Quinhagak Airport", - "state": "AK", - "lat": 59.7551, - "lon": -161.8454 - }, - "PAQT": { - "id": "PAQT", - "city": "Nuiqsut, Nuiqsut Airport", - "state": "AK", - "lat": 70.2099999, - "lon": -151.00556 - }, - "PARC": { - "id": "PARC", - "city": "Arctic Village, Arctic Village Airport", - "state": "AK", - "lat": 68.11444, - "lon": -145.57917 - }, - "PARS": { - "id": "PARS", - "city": "Russian Mission", - "state": "AK", - "lat": 61.775, - "lon": -161.3194 - }, - "PARY": { - "id": "PARY", - "city": "Ruby", - "state": "AK", - "lat": 64.7272, - "lon": -155.4697 - }, - "PASA": { - "id": "PASA", - "city": "Savoonga Airport", - "state": "AK", - "lat": 63.68333, - "lon": -170.5 - }, - "PASC": { - "id": "PASC", - "city": "Deadhorse, Deadhorse Airport", - "state": "AK", - "lat": 70.2, - "lon": -148.46667 - }, - "PASD": { - "id": "PASD", - "city": "Sand Point", - "state": "AK", - "lat": 55.31667, - "lon": -160.51667 - }, - "PASH": { - "id": "PASH", - "city": "Shishmaref, Shishmaref Airport", - "state": "AK", - "lat": 66.26667, - "lon": -166.08333 - }, - "PASI": { - "id": "PASI", - "city": "Sitka - Sitka Airport", - "state": "AK", - "lat": 57.048, - "lon": -135.3647 - }, - "PASK": { - "id": "PASK", - "city": "Selawik", - "state": "AK", - "lat": 66.61667, - "lon": -160 - }, - "PASL": { - "id": "PASL", - "city": "Sleetmute", - "state": "AK", - "lat": 61.69735, - "lon": -157.16712 - }, - "PASM": { - "id": "PASM", - "city": "St. Mary's, St. Mary's Airport", - "state": "AK", - "lat": 62.05, - "lon": -163.3 - }, - "PASN": { - "id": "PASN", - "city": "St. Paul Island, St. Paul Island Airport", - "state": "AK", - "lat": 57.16667, - "lon": -170.21667 - }, - "PASO": { - "id": "PASO", - "city": "Seldovia, Seldovia Airport", - "state": "AK", - "lat": 59.45, - "lon": -151.7 - }, - "PASV": { - "id": "PASV", - "city": "Sparrevohn Airways Facilities Sector", - "state": "AK", - "lat": 61.1, - "lon": -155.5666699 - }, - "PASX": { - "id": "PASX", - "city": "Soldotna", - "state": "AK", - "lat": 60.48333, - "lon": -151.03333 - }, - "PASY": { - "id": "PASY", - "city": "Shemya, Eareckson AFB", - "state": "AK", - "lat": 52.71667, - "lon": 174.11667 - }, - "PATA": { - "id": "PATA", - "city": "Tanana, Calhoun Memorial Airport", - "state": "AK", - "lat": 65.16667, - "lon": -152.1 - }, - "PATC": { - "id": "PATC", - "city": "Tin City Airways Facilities Sector", - "state": "AK", - "lat": 65.56667, - "lon": -167.91667 - }, - "PATE": { - "id": "PATE", - "city": "Teller", - "state": "AK", - "lat": 65.2403999, - "lon": -166.3393 - }, - "PATG": { - "id": "PATG", - "city": "Togiac Village, Togiak Airport", - "state": "AK", - "lat": 59.05, - "lon": -160.4 - }, - "PATK": { - "id": "PATK", - "city": "Talkeetna, Talkeetna Airport", - "state": "AK", - "lat": 62.32056, - "lon": -150.09361 - }, - "PATL": { - "id": "PATL", - "city": "Takotna, Tatalina LRRS Airport", - "state": "AK", - "lat": 62.9, - "lon": -155.98333 - }, - "PATO": { - "id": "PATO", - "city": "Portage, Portage Glacier", - "state": "AK", - "lat": 60.78333, - "lon": -148.83333 - }, - "PATQ": { - "id": "PATQ", - "city": "Atqasuk", - "state": "AK", - "lat": 70.4673, - "lon": -157.4357 - }, - "PAUN": { - "id": "PAUN", - "city": "Unalakleet", - "state": "AK", - "lat": 63.88333, - "lon": -160.8 - }, - "PAVA": { - "id": "PAVA", - "city": "Chevak Airport", - "state": "AK", - "lat": 61.5408, - "lon": -165.6009 - }, - "PAVC": { - "id": "PAVC", - "city": "King Cove", - "state": "AK", - "lat": 55.116, - "lon": -162.266 - }, - "PAVD": { - "id": "PAVD", - "city": "Valdez 2", - "state": "AK", - "lat": 61.13333, - "lon": -146.26667 - }, - "PAVL": { - "id": "PAVL", - "city": "Kivalina, Kivalina Airport", - "state": "AK", - "lat": 67.73333, - "lon": -164.55 - }, - "PAWD": { - "id": "PAWD", - "city": "Seward", - "state": "AK", - "lat": 60.11667, - "lon": -149.45 - }, - "PAWG": { - "id": "PAWG", - "city": "Wrangell", - "state": "AK", - "lat": 56.48333, - "lon": -132.36667 - }, - "PAWM": { - "id": "PAWM", - "city": "White Mountain Airport", - "state": "AK", - "lat": 64.6892, - "lon": -163.4127 - }, - "PAWN": { - "id": "PAWN", - "city": "Noatak, Noatak Airport", - "state": "AK", - "lat": 67.56667, - "lon": -162.98333 - }, - "PAWS": { - "id": "PAWS", - "city": "Wasilla, Wasilla Airport", - "state": "AK", - "lat": 61.57194, - "lon": -149.54056 - }, - "PAYA": { - "id": "PAYA", - "city": "Yakutat", - "state": "AK", - "lat": 59.51667, - "lon": -139.66667 - }, - "PAZK": { - "id": "PAZK", - "city": "Eureka, Skelton Airport", - "state": "AK", - "lat": 61.93333, - "lon": -147.16667 - }, - "PFCB": { - "id": "PFCB", - "city": "Chenega Bay Airport", - "state": "AK", - "lat": 60.07856, - "lon": -147.99473 - }, - "PFCL": { - "id": "PFCL", - "city": "Clarks Point Airport", - "state": "AK", - "lat": 58.8337, - "lon": -158.5294 - }, - "PFEL": { - "id": "PFEL", - "city": "Elim Airport", - "state": "AK", - "lat": 64.615, - "lon": -162.2705 - }, - "PFKO": { - "id": "PFKO", - "city": "Kotlik Airport", - "state": "AK", - "lat": 63.03058, - "lon": -163.5326399 - }, - "PFKT": { - "id": "PFKT", - "city": "Brevig Mission Airport", - "state": "AK", - "lat": 65.3313, - "lon": -166.4657 - }, - "PFKW": { - "id": "PFKW", - "city": "Kwethluk Airport", - "state": "AK", - "lat": 60.7903, - "lon": -161.4437 - }, - "PFNO": { - "id": "PFNO", - "city": "Noorvik", - "state": "AK", - "lat": 66.8175, - "lon": -161.0223 - }, - "PFSH": { - "id": "PFSH", - "city": "Shaktoolik Airport", - "state": "AK", - "lat": 64.3711, - "lon": -161.224 - }, - "PFTO": { - "id": "PFTO", - "city": "Tok Junction Airport", - "state": "AK", - "lat": 63.32951, - "lon": -142.95368 - }, - "PFWS": { - "id": "PFWS", - "city": "South Naknek Nr 2 Airport", - "state": "AK", - "lat": 58.7021, - "lon": -157.0026 - }, - "PFYU": { - "id": "PFYU", - "city": "Fort Yukon, Fort Yukon Airport", - "state": "AK", - "lat": 66.56667, - "lon": -145.26667 - }, - "PFZK": { - "id": "PFZK", - "city": "Akiachak Airport", - "state": "AK", - "lat": 60.91381, - "lon": -161.4933299 - }, - "POKA": { - "id": "POKA", - "city": "Tununak Airport", - "state": "AK", - "lat": 60.56953, - "lon": -165.24628 - }, - "PPIT": { - "id": "PPIT", - "city": "Nunapitchuk Airport", - "state": "AK", - "lat": 60.906, - "lon": -162.4406 - }, - "PPIZ": { - "id": "PPIZ", - "city": "Point Lay, Point Lay LRRS Airport", - "state": "AK", - "lat": 69.7166699, - "lon": -163 - }, - "KDET": { - "id": "KDET", - "city": "Coleman A Young Municipal Airport", - "state": "MI", - "lat": 42.40729, - "lon": -83.00894 - }, - "KDRM": { - "id": "KDRM", - "city": "Drummond Island Airport", - "state": "MI", - "lat": 46.0072, - "lon": -83.7427 - }, - "KDTW": { - "id": "KDTW", - "city": "Detroit, Detroit Metropolitan Wayne County Airport", - "state": "MI", - "lat": 42.23139, - "lon": -83.33083 - }, - "KDUH": { - "id": "KDUH", - "city": "Lambertville, Toledo Suburban Airport", - "state": "MI", - "lat": 41.73583, - "lon": -83.65528 - }, - "KERY": { - "id": "KERY", - "city": "Newberry, Luce County Airport", - "state": "MI", - "lat": 46.31111, - "lon": -85.45722 - }, - "KESC": { - "id": "KESC", - "city": "Delta County Airport", - "state": "MI", - "lat": 45.7226799, - "lon": -87.09372 - }, - "KFFX": { - "id": "KFFX", - "city": "Fremont Municipal Airport", - "state": "MI", - "lat": 43.43933, - "lon": -85.9948299 - }, - "KFKS": { - "id": "KFKS", - "city": "Frankfort, Frankfort Dow Memorial Field Airport", - "state": "MI", - "lat": 44.625, - "lon": -86.20056 - }, - "KFNT": { - "id": "KFNT", - "city": "Flint, Bishop International Airport", - "state": "MI", - "lat": 42.96667, - "lon": -83.74944 - }, - "KFPK": { - "id": "KFPK", - "city": "Charlotte, Fitch H Beach Airport", - "state": "MI", - "lat": 42.57444, - "lon": -84.81139 - }, - "KGLR": { - "id": "KGLR", - "city": "Gaylord Regional Airport", - "state": "MI", - "lat": 45.01658, - "lon": -84.68937 - }, - "KGOV": { - "id": "KGOV", - "city": "Grayling, Grayling Army Airfield", - "state": "MI", - "lat": 44.68028, - "lon": -84.72889 - }, - "KGRR": { - "id": "KGRR", - "city": "Grand Rapids, Gerald R. Ford International Airport", - "state": "MI", - "lat": 42.88083, - "lon": -85.52278 - }, - "KHAI": { - "id": "KHAI", - "city": "Haines Memorial Airport", - "state": "MI", - "lat": 41.9598, - "lon": -85.5934 - }, - "KHTL": { - "id": "KHTL", - "city": "Houghton Lake, Roscommon County Airport", - "state": "MI", - "lat": 44.35111, - "lon": -84.67417 - }, - "KHYX": { - "id": "KHYX", - "city": "Saginaw County H W Browne Airport", - "state": "MI", - "lat": 43.43191, - "lon": -83.86476 - }, - "KIKW": { - "id": "KIKW", - "city": "Jack Barstow Airport", - "state": "MI", - "lat": 43.6624, - "lon": -84.26213 - }, - "KIMT": { - "id": "KIMT", - "city": "Iron Mountain / Kingsford, Ford Airport", - "state": "MI", - "lat": 45.81417, - "lon": -88.10889 - }, - "KIRS": { - "id": "KIRS", - "city": "Sturgis, Kirsch Municipal Airport", - "state": "MI", - "lat": 41.8127799, - "lon": -85.43917 - }, - "KISQ": { - "id": "KISQ", - "city": "Manistique, Schoolcraft County Airport", - "state": "MI", - "lat": 45.97472, - "lon": -86.17194 - }, - "KIWD": { - "id": "KIWD", - "city": "Ironwood, Gogebic-Iron County Airport", - "state": "MI", - "lat": 46.53333, - "lon": -90.13333 - }, - "KJXN": { - "id": "KJXN", - "city": "Jackson County Airport - Reynolds Field", - "state": "MI", - "lat": 42.26171, - "lon": -84.46147 - }, - "KJYM": { - "id": "KJYM", - "city": "Hillsdale Municipal Airport", - "state": "MI", - "lat": 41.91972, - "lon": -84.58528 - }, - "KLAN": { - "id": "KLAN", - "city": "Capital Region International Airport", - "state": "MI", - "lat": 42.77616, - "lon": -84.5997 - }, - "KLDM": { - "id": "KLDM", - "city": "Ludington, Mason County Airport", - "state": "MI", - "lat": 43.96667, - "lon": -86.4 - }, - "KLWA": { - "id": "KLWA", - "city": "South Haven, South Haven Area Regional Airport", - "state": "MI", - "lat": 42.35083, - "lon": -86.25611 - }, - "KMBL": { - "id": "KMBL", - "city": "Manistee County - Blacker Airport", - "state": "MI", - "lat": 44.27142, - "lon": -86.23773 - }, - "KMBS": { - "id": "KMBS", - "city": "MBS International Airport", - "state": "MI", - "lat": 43.5281, - "lon": -84.08129 - }, - "KMCD": { - "id": "KMCD", - "city": "Mackinac Island Airport", - "state": "MI", - "lat": 45.86628, - "lon": -84.63437 - }, - "KMGN": { - "id": "KMGN", - "city": "Harbor Springs, Harbor Springs Airport", - "state": "MI", - "lat": 45.42556, - "lon": -84.91333 - }, - "KMKG": { - "id": "KMKG", - "city": "Muskegon, Muskegon County Airport", - "state": "MI", - "lat": 43.17111, - "lon": -86.23667 - }, - "KMNM": { - "id": "KMNM", - "city": "Menominee - Marinette Twin County Airport", - "state": "MI", - "lat": 45.12628, - "lon": -87.64438 - }, - "KMOP": { - "id": "KMOP", - "city": "Mount Pleasant, Mount Pleasant Municipal Airport", - "state": "MI", - "lat": 43.61667, - "lon": -84.73333 - }, - "KMTC": { - "id": "KMTC", - "city": "Selfridge Air National Guard Base", - "state": "MI", - "lat": 42.60458, - "lon": -82.83528 - }, - "KOEB": { - "id": "KOEB", - "city": "Branch County Memorial Airport", - "state": "MI", - "lat": 41.93085, - "lon": -85.05429 - }, - "KONZ": { - "id": "KONZ", - "city": "Detroit/Grosse Ile, Grosse Ile Airport", - "state": "MI", - "lat": 42.09861, - "lon": -83.1611099 - }, - "KOSC": { - "id": "KOSC", - "city": "Oscoda, Oscoda-Wurtsmith Airport", - "state": "MI", - "lat": 44.45, - "lon": -83.36667 - }, - "KOZW": { - "id": "KOZW", - "city": "Howell, Livingston County Airport", - "state": "MI", - "lat": 42.62944, - "lon": -83.98417 - }, - "KPHN": { - "id": "KPHN", - "city": "St Clair County International Airport", - "state": "MI", - "lat": 42.91031, - "lon": -82.53315 - }, - "KPLN": { - "id": "KPLN", - "city": "Pellston Regional Airport of Emmet County", - "state": "MI", - "lat": 45.56443, - "lon": -84.7928699 - }, - "KPTK": { - "id": "KPTK", - "city": "Pontiac, Oakland County International Airport", - "state": "MI", - "lat": 42.66306, - "lon": -83.41 - }, - "KPZQ": { - "id": "KPZQ", - "city": "Rogers City, Presque Isle County Airport", - "state": "MI", - "lat": 45.40694, - "lon": -83.81278 - }, - "KRMY": { - "id": "KRMY", - "city": "Brooks Field Airport", - "state": "MI", - "lat": 42.25238, - "lon": -84.95253 - }, - "KRNP": { - "id": "KRNP", - "city": "Owosso, Owosso Community Airport", - "state": "MI", - "lat": 42.99278, - "lon": -84.13889 - }, - "KRQB": { - "id": "KRQB", - "city": "Big Rapids, Roben-Hood Airport", - "state": "MI", - "lat": 43.7224999, - "lon": -85.50417 - }, - "KSAW": { - "id": "KSAW", - "city": "Marquette, Sawyer International Airport", - "state": "MI", - "lat": 46.35361, - "lon": -87.39528 - }, - "KSJX": { - "id": "KSJX", - "city": "Beaver Island, Beaver Island Airport", - "state": "MI", - "lat": 45.69222, - "lon": -85.56639 - }, - "KSLH": { - "id": "KSLH", - "city": "Cheboygan, Cheboygan County Airport", - "state": "MI", - "lat": 45.65361, - "lon": -84.51917 - }, - "KTEW": { - "id": "KTEW", - "city": "Mason, Mason Jewett Field Airport", - "state": "MI", - "lat": 42.56583, - "lon": -84.42333 - }, - "KTTF": { - "id": "KTTF", - "city": "Monroe, Custer Airport", - "state": "MI", - "lat": 41.94, - "lon": -83.43472 - }, - "KTVC": { - "id": "KTVC", - "city": "Cherry Capital Airport", - "state": "MI", - "lat": 44.73898, - "lon": -85.56788 - }, - "KVLL": { - "id": "KVLL", - "city": "Troy, Oakland/Troy Airport", - "state": "MI", - "lat": 42.54278, - "lon": -83.17778 - }, - "KYIP": { - "id": "KYIP", - "city": "Detroit, Willow Run Airport", - "state": "MI", - "lat": 42.2366699, - "lon": -83.52611 - }, - "KBHK": { - "id": "KBHK", - "city": "Baker, Baker Municipal Airport", - "state": "MT", - "lat": 46.34778, - "lon": -104.2574999 - }, - "KBIL": { - "id": "KBIL", - "city": "Billings, Billings Logan International Airport", - "state": "MT", - "lat": 45.80694, - "lon": -108.54222 - }, - "KBTM": { - "id": "KBTM", - "city": "Butte, Bert Mooney Airport", - "state": "MT", - "lat": 45.95472, - "lon": -112.4975 - }, - "KBZN": { - "id": "KBZN", - "city": "Bozeman, Gallatin Field", - "state": "MT", - "lat": 45.78806, - "lon": -111.16083 - }, - "KCTB": { - "id": "KCTB", - "city": "Cut Bank, Cut Bank Municipal Airport", - "state": "MT", - "lat": 48.60833, - "lon": -112.37611 - }, - "KDLN": { - "id": "KDLN", - "city": "Dillon, Dillon Airport", - "state": "MT", - "lat": 45.2575, - "lon": -112.55444 - }, - "KEKS": { - "id": "KEKS", - "city": "Ennis - Big Sky Airport", - "state": "MT", - "lat": 45.27436, - "lon": -111.64886 - }, - "KGDV": { - "id": "KGDV", - "city": "Glendive, Dawson Community Airport", - "state": "MT", - "lat": 47.13333, - "lon": -104.8 - }, - "KGFA": { - "id": "KGFA", - "city": "Malmstrom Air Force Base", - "state": "MT", - "lat": 47.5, - "lon": -111.18333 - }, - "KGGW": { - "id": "KGGW", - "city": "Glasgow, Glasgow International Airport", - "state": "MT", - "lat": 48.21389, - "lon": -106.62139 - }, - "KGPI": { - "id": "KGPI", - "city": "Kalispell, Glacier Park International Airport", - "state": "MT", - "lat": 48.30417, - "lon": -114.26361 - }, - "KGTF": { - "id": "KGTF", - "city": "Great Falls, Great Falls International Airport", - "state": "MT", - "lat": 47.47333, - "lon": -111.38222 - }, - "KHLN": { - "id": "KHLN", - "city": "Helena Regional Airport", - "state": "MT", - "lat": 46.60445, - "lon": -111.9892 - }, - "KHRF": { - "id": "KHRF", - "city": "Ravalli County Airport", - "state": "MT", - "lat": 46.25463, - "lon": -114.1246 - }, - "KHVR": { - "id": "KHVR", - "city": "Havre, Havre City-County Airport", - "state": "MT", - "lat": 48.54278, - "lon": -109.76333 - }, - "KJDN": { - "id": "KJDN", - "city": "Jordan, Jordan Airport", - "state": "MT", - "lat": 47.32583, - "lon": -106.9475 - }, - "KLVM": { - "id": "KLVM", - "city": "Livingston, Mission Field Airport", - "state": "MT", - "lat": 45.69944, - "lon": -110.44833 - }, - "KLWT": { - "id": "KLWT", - "city": "Lewistown, Lewistown Municipal Airport", - "state": "MT", - "lat": 47.0491699, - "lon": -109.46639 - }, - "KMLP": { - "id": "KMLP", - "city": "Mullan Pass, Mullan Pass Vor", - "state": "MT", - "lat": 47.45417, - "lon": -115.66972 - }, - "KMLS": { - "id": "KMLS", - "city": "Miles City, Frank Wiley Field Airport", - "state": "MT", - "lat": 46.42806, - "lon": -105.88639 - }, - "KMSO": { - "id": "KMSO", - "city": "Missoula, Missoula International Airport", - "state": "MT", - "lat": 46.92083, - "lon": -114.0925 - }, - "KMVH": { - "id": "KMVH", - "city": "N BAR Ranch Airport", - "state": "MT", - "lat": 46.8381, - "lon": -108.9368 - }, - "KOLF": { - "id": "KOLF", - "city": "Wolf Point, Clayton Airport", - "state": "MT", - "lat": 48.09444, - "lon": -105.57722 - }, - "KPWD": { - "id": "KPWD", - "city": "Sher-Wood Airport", - "state": "MT", - "lat": 48.789, - "lon": -104.52297 - }, - "KRVF": { - "id": "KRVF", - "city": "Ruby Valley Field Airport", - "state": "MT", - "lat": 45.53542, - "lon": -112.30228 - }, - "KSBX": { - "id": "KSBX", - "city": "Shelby Airport", - "state": "MT", - "lat": 48.54069, - "lon": -111.87125 - }, - "KSDY": { - "id": "KSDY", - "city": "Sidney-Richland", - "state": "MT", - "lat": 47.7, - "lon": -104.2 - }, - "KWYS": { - "id": "KWYS", - "city": "West Yellowstone", - "state": "MT", - "lat": 44.68333, - "lon": -111.11667 - }, - "KAAA": { - "id": "KAAA", - "city": "Logan County Airport", - "state": "IL", - "lat": 40.15885, - "lon": -89.33891 - }, - "KAJG": { - "id": "KAJG", - "city": "Mount Carmel, Mount Carmel Municipal Airport", - "state": "IL", - "lat": 38.60928, - "lon": -87.72508 - }, - "KALN": { - "id": "KALN", - "city": "St. Louis Regional Airport", - "state": "IL", - "lat": 38.88968, - "lon": -90.03163 - }, - "KARR": { - "id": "KARR", - "city": "Aurora Municipal Airport", - "state": "IL", - "lat": 41.77132, - "lon": -88.48147 - }, - "KBLV": { - "id": "KBLV", - "city": "Belleville, Scott AFB/MidAmerica Airport", - "state": "IL", - "lat": 38.55, - "lon": -89.85 - }, - "KBMI": { - "id": "KBMI", - "city": "Bloomington/Normal, Central Illinois Regional Airport at Bloomington-Normal", - "state": "IL", - "lat": 40.47694, - "lon": -88.91583 - }, - "KCIR": { - "id": "KCIR", - "city": "Cairo Regional Airport", - "state": "IL", - "lat": 37.06388, - "lon": -89.2232 - }, - "KCMI": { - "id": "KCMI", - "city": "University of Illinois - Willard", - "state": "IL", - "lat": 40.03245, - "lon": -88.27547 - }, - "KCPS": { - "id": "KCPS", - "city": "St. Louis Downtown Airport", - "state": "IL", - "lat": 38.56403, - "lon": -90.14871 - }, - "KDEC": { - "id": "KDEC", - "city": "Decatur Airport", - "state": "IL", - "lat": 39.8308, - "lon": -88.87192 - }, - "KDKB": { - "id": "KDKB", - "city": "De Kalb Taylor Municipal Airport", - "state": "IL", - "lat": 41.93381, - "lon": -88.70657 - }, - "KDNV": { - "id": "KDNV", - "city": "Danville, Vermilion County Airport", - "state": "IL", - "lat": 40.19944, - "lon": -87.59556 - }, - "KDPA": { - "id": "KDPA", - "city": "Chicago / West Chicago, Dupage Airport", - "state": "IL", - "lat": 41.8963899, - "lon": -88.25111 - }, - "KENL": { - "id": "KENL", - "city": "Centralia Municipal Airport", - "state": "IL", - "lat": 38.50951, - "lon": -89.08996 - }, - "KFOA": { - "id": "KFOA", - "city": "Flora Municipal Airport", - "state": "IL", - "lat": 38.66726, - "lon": -88.4526999 - }, - "KFWC": { - "id": "KFWC", - "city": "Fairfield, Fairfield Municipal Airport", - "state": "IL", - "lat": 38.37861, - "lon": -88.41278 - }, - "KGBG": { - "id": "KGBG", - "city": "Galesburg Municipal Airport", - "state": "IL", - "lat": 40.9328999, - "lon": -90.43339 - }, - "KHSB": { - "id": "KHSB", - "city": "Harrisburg-Raleigh Airport", - "state": "IL", - "lat": 37.81281, - "lon": -88.54486 - }, - "KIGQ": { - "id": "KIGQ", - "city": "Lansing Municipal Airport", - "state": "IL", - "lat": 41.54125, - "lon": -87.52822 - }, - "KIJX": { - "id": "KIJX", - "city": "Jacksonville Municipal Airport", - "state": "IL", - "lat": 39.7740099, - "lon": -90.24187 - }, - "KIKK": { - "id": "KIKK", - "city": "Greater Kankakee Airport", - "state": "IL", - "lat": 41.06871, - "lon": -87.85372 - }, - "KJOT": { - "id": "KJOT", - "city": "Joliet Regional Airport", - "state": "IL", - "lat": 41.51755, - "lon": -88.17903 - }, - "KLOT": { - "id": "KLOT", - "city": "Lewis University Airport", - "state": "IL", - "lat": 41.60307, - "lon": -88.10164 - }, - "KLWV": { - "id": "KLWV", - "city": "Lawrenceville-Vincennes International Airport", - "state": "IL", - "lat": 38.76046, - "lon": -87.59903 - }, - "KMDH": { - "id": "KMDH", - "city": "Southern Illinois Airport", - "state": "IL", - "lat": 37.78328, - "lon": -89.24532 - }, - "KMDW": { - "id": "KMDW", - "city": "Chicago, Chicago Midway Airport", - "state": "IL", - "lat": 41.78417, - "lon": -87.75528 - }, - "KMLI": { - "id": "KMLI", - "city": "Moline Quad-City Airport", - "state": "IL", - "lat": 41.4482, - "lon": -90.52359 - }, - "KMQB": { - "id": "KMQB", - "city": "Macomb Municipal Airport", - "state": "IL", - "lat": 40.5176299, - "lon": -90.64807 - }, - "KMTO": { - "id": "KMTO", - "city": "Mattoon / Charleston, Coles County Memorial Airport", - "state": "IL", - "lat": 39.47806, - "lon": -88.2791699 - }, - "KMVN": { - "id": "KMVN", - "city": "Mount Vernon Airport", - "state": "IL", - "lat": 38.32842, - "lon": -88.85292 - }, - "KMWA": { - "id": "KMWA", - "city": "Marion - Williamson County Regional Airport", - "state": "IL", - "lat": 37.76671, - "lon": -89.00993 - }, - "KOLY": { - "id": "KOLY", - "city": "Olney-Noble Airport", - "state": "IL", - "lat": 38.72133, - "lon": -88.1799 - }, - "KORD": { - "id": "KORD", - "city": "Chicago, Chicago-O'Hare International Airport", - "state": "IL", - "lat": 41.97972, - "lon": -87.9044399 - }, - "KPIA": { - "id": "KPIA", - "city": "Peoria - General Downing-Peoria International Airport", - "state": "IL", - "lat": 40.6674999, - "lon": -89.68389 - }, - "KPNT": { - "id": "KPNT", - "city": "Pontiac Municipal Airport", - "state": "IL", - "lat": 40.92327, - "lon": -88.6213 - }, - "KPPQ": { - "id": "KPPQ", - "city": "Pittsfield, Pittsfield Penstone Municipal Airport", - "state": "IL", - "lat": 39.63889, - "lon": -90.77833 - }, - "KPRG": { - "id": "KPRG", - "city": "Edgar County Airport", - "state": "IL", - "lat": 39.69817, - "lon": -87.6669 - }, - "KPWK": { - "id": "KPWK", - "city": "Chicago / Wheeling, Pal-Waukee Airport", - "state": "IL", - "lat": 42.12083, - "lon": -87.90472 - }, - "KRFD": { - "id": "KRFD", - "city": "Rockford, Greater Rockford Airport", - "state": "IL", - "lat": 42.19278, - "lon": -89.09333 - }, - "KRPJ": { - "id": "KRPJ", - "city": "Rochelle, Rochelle Municipal-Koritz Field Airport", - "state": "IL", - "lat": 41.8905699, - "lon": -89.08175 - }, - "KSAR": { - "id": "KSAR", - "city": "Sparta Community-Hunter Field Airport", - "state": "IL", - "lat": 38.14624, - "lon": -89.70243 - }, - "KSLO": { - "id": "KSLO", - "city": "Salem, Salem-Leckrone Airport", - "state": "IL", - "lat": 38.64278, - "lon": -88.96417 - }, - "KSPI": { - "id": "KSPI", - "city": "Springfield - Abraham Lincoln Capital Airport", - "state": "IL", - "lat": 39.84527, - "lon": -89.68405 - }, - "KSQI": { - "id": "KSQI", - "city": "Sterling Rockfalls", - "state": "IL", - "lat": 41.7432, - "lon": -89.66547 - }, - "KTAZ": { - "id": "KTAZ", - "city": "Taylorville, Taylorville Municipal Airport", - "state": "IL", - "lat": 39.53417, - "lon": -89.32778 - }, - "KTIP": { - "id": "KTIP", - "city": "Rantoul National Aviation Center Airport", - "state": "IL", - "lat": 40.28952, - "lon": -88.1473 - }, - "KUGN": { - "id": "KUGN", - "city": "Chicago/Waukegan Regional Airport", - "state": "IL", - "lat": 42.42546, - "lon": -87.86339 - }, - "KUIN": { - "id": "KUIN", - "city": "Quincy Regional Airport-Baldwin Field", - "state": "IL", - "lat": 39.9371, - "lon": -91.19659 - }, - "KVYS": { - "id": "KVYS", - "city": "Illinois Valley Regional Airport", - "state": "IL", - "lat": 41.35175, - "lon": -89.14963 - }, - "KALK": { - "id": "KALK", - "city": "Pioneer Airfield", - "state": "AZ", - "lat": 31.60564, - "lon": -110.4281 - }, - "KAVQ": { - "id": "KAVQ", - "city": "Tucson Marana Regional Airport", - "state": "AZ", - "lat": 32.4096, - "lon": -111.2184 - }, - "KAZC": { - "id": "KAZC", - "city": "Colorado City, Colorado City Municipal Airport", - "state": "AZ", - "lat": 36.95, - "lon": -113 - }, - "KBXK": { - "id": "KBXK", - "city": "Buckeye Municipal Airport", - "state": "AZ", - "lat": 33.4204, - "lon": -112.6862 - }, - "KCGZ": { - "id": "KCGZ", - "city": "Casa Grande, Casa Grande Municipal Airport", - "state": "AZ", - "lat": 32.95, - "lon": -111.76667 - }, - "KCHD": { - "id": "KCHD", - "city": "Chandler, Chandler Municipal Airport", - "state": "AZ", - "lat": 33.26917, - "lon": -111.81111 - }, - "KCMR": { - "id": "KCMR", - "city": "Williams/Clark Memorial Airport", - "state": "AZ", - "lat": 35.3054721, - "lon": -112.1943889 - }, - "KDMA": { - "id": "KDMA", - "city": "Davis-Monthan Air Force Base", - "state": "AZ", - "lat": 32.16667, - "lon": -110.88333 - }, - "KDUG": { - "id": "KDUG", - "city": "Bisbee Douglas International Airport", - "state": "AZ", - "lat": 31.45838, - "lon": -109.60676 - }, - "KDVT": { - "id": "KDVT", - "city": "Phoenix, Phoenix-Deer Valley Municipal Airport", - "state": "AZ", - "lat": 33.69026, - "lon": -112.06618 - }, - "KFFZ": { - "id": "KFFZ", - "city": "Mesa / Falcon Field", - "state": "AZ", - "lat": 33.46667, - "lon": -111.73333 - }, - "KFHU": { - "id": "KFHU", - "city": "Fort Huachuca, Libby AAF Ft Huachuca", - "state": "AZ", - "lat": 31.58333, - "lon": -110.33333 - }, - "KFLG": { - "id": "KFLG", - "city": "Flagstaff Pulliam Airport", - "state": "AZ", - "lat": 35.1443299, - "lon": -111.66637 - }, - "KGCN": { - "id": "KGCN", - "city": "Grand Canyon National Park Airport", - "state": "AZ", - "lat": 35.94582, - "lon": -112.15538 - }, - "KGEU": { - "id": "KGEU", - "city": "Glendale, Glendale Municipal Airport", - "state": "AZ", - "lat": 33.52722, - "lon": -112.29528 - }, - "KGXF": { - "id": "KGXF", - "city": "Gila Bend Air Force Auxiliary Field", - "state": "AZ", - "lat": 32.8875, - "lon": -112.72 - }, - "KGYR": { - "id": "KGYR", - "city": "Goodyear Municipal", - "state": "AZ", - "lat": 33.41667, - "lon": -112.38333 - }, - "KHII": { - "id": "KHII", - "city": "Havasu City Airport", - "state": "AZ", - "lat": 34.56595, - "lon": -114.35224 - }, - "KIFP": { - "id": "KIFP", - "city": "Bullhead City, Laughlin/Bullhead International Airport", - "state": "AZ", - "lat": 35.1575, - "lon": -114.55944 - }, - "KIGM": { - "id": "KIGM", - "city": "Kingman, Kingman Airport", - "state": "AZ", - "lat": 35.2577799, - "lon": -113.93306 - }, - "KINW": { - "id": "KINW", - "city": "Winslow, Winslow Municipal Airport", - "state": "AZ", - "lat": 35.02806, - "lon": -110.72083 - }, - "KIWA": { - "id": "KIWA", - "city": "Phoenix-Mesa Gateway Airport", - "state": "AZ", - "lat": 33.31667, - "lon": -111.65 - }, - "KJTC": { - "id": "KJTC", - "city": "Springerville Municipal Airport", - "state": "AZ", - "lat": 34.1293999, - "lon": -109.3109 - }, - "KLGF": { - "id": "KLGF", - "city": "Laguna Army Airfield", - "state": "AZ", - "lat": 32.86459, - "lon": -114.39298 - }, - "KLUF": { - "id": "KLUF", - "city": "Luke Air Force Base / Phoenix", - "state": "AZ", - "lat": 33.53333, - "lon": -112.38333 - }, - "KMZJ": { - "id": "KMZJ", - "city": "Pinal Airpark", - "state": "AZ", - "lat": 32.50983, - "lon": -111.32533 - }, - "KNOZ": { - "id": "KNOZ", - "city": "Yuma Auxiliary Airfield", - "state": "AZ", - "lat": 32.5, - "lon": -114.45 - }, - "KNYL": { - "id": "KNYL", - "city": "Yuma, Marine Corps Air Station", - "state": "AZ", - "lat": 32.6594399, - "lon": -114.59306 - }, - "KOLS": { - "id": "KOLS", - "city": "Nogales, Nogales International Airport", - "state": "AZ", - "lat": 31.42083, - "lon": -110.84583 - }, - "KPAN": { - "id": "KPAN", - "city": "Payson Airport", - "state": "AZ", - "lat": 34.2568364, - "lon": -111.3392558 - }, - "KPGA": { - "id": "KPGA", - "city": "Page, Page Municipal Airport", - "state": "AZ", - "lat": 36.92056, - "lon": -111.44806 - }, - "KPHX": { - "id": "KPHX", - "city": "Phoenix, Phoenix Sky Harbor International Airport", - "state": "AZ", - "lat": 33.427799, - "lon": -112.003465 - }, - "KPRC": { - "id": "KPRC", - "city": "Prescott, Love Field", - "state": "AZ", - "lat": 34.64917, - "lon": -112.42222 - }, - "KRQE": { - "id": "KRQE", - "city": "Window Rock, Window Rock Airport", - "state": "AZ", - "lat": 35.65, - "lon": -109.06667 - }, - "KRYN": { - "id": "KRYN", - "city": "Tucson Ryan Field Airport", - "state": "AZ", - "lat": 32.1422, - "lon": -111.1746 - }, - "KSAD": { - "id": "KSAD", - "city": "Safford, Safford Municipal Airport", - "state": "AZ", - "lat": 32.85722, - "lon": -109.63556 - }, - "KSDL": { - "id": "KSDL", - "city": "Scottsdale Airport", - "state": "AZ", - "lat": 33.61235, - "lon": -111.92316 - }, - "KSEZ": { - "id": "KSEZ", - "city": "Sedona Airport", - "state": "AZ", - "lat": 34.85, - "lon": -111.78333 - }, - "KSJN": { - "id": "KSJN", - "city": "St. Johns, St. Johns Industrial Airpark", - "state": "AZ", - "lat": 34.51833, - "lon": -109.37917 - }, - "KSOW": { - "id": "KSOW", - "city": "Show Low, Show Low Regional Airport", - "state": "AZ", - "lat": 34.26528, - "lon": -110.00556 - }, - "KTUS": { - "id": "KTUS", - "city": "Tucson, Tucson International Airport", - "state": "AZ", - "lat": 32.13153, - "lon": -110.95635 - }, - "KTYL": { - "id": "KTYL", - "city": "Taylor Airport", - "state": "AZ", - "lat": 34.45272, - "lon": -110.11503 - }, - "KAAF": { - "id": "KAAF", - "city": "Apalachicola, Apalachicola", - "state": "FL", - "lat": 29.72694, - "lon": -85.02472 - }, - "KAPF": { - "id": "KAPF", - "city": "Naples, Naples Municipal Airport", - "state": "FL", - "lat": 26.15, - "lon": -81.76667 - }, - "KBCR": { - "id": "KBCR", - "city": "Tri-County Airport", - "state": "FL", - "lat": 30.84389, - "lon": -85.60175 - }, - "KBCT": { - "id": "KBCT", - "city": "Boca Raton, Boca Raton Airport", - "state": "FL", - "lat": 26.3786099, - "lon": -80.10778 - }, - "KBKV": { - "id": "KBKV", - "city": "Brooksville-Tampa Bay Regional Airport", - "state": "FL", - "lat": 28.47361, - "lon": -82.45444 - }, - "KBOW": { - "id": "KBOW", - "city": "Bartow Municipal", - "state": "FL", - "lat": 27.95, - "lon": -81.78333 - }, - "KCEW": { - "id": "KCEW", - "city": "Crestview, Sikes Airport", - "state": "FL", - "lat": 30.77222, - "lon": -86.52 - }, - "KCGC": { - "id": "KCGC", - "city": "Crystal River Airport", - "state": "FL", - "lat": 28.8673, - "lon": -82.5712999 - }, - "KCLW": { - "id": "KCLW", - "city": "Clearwater Air Park", - "state": "FL", - "lat": 27.9742, - "lon": -82.7563 - }, - "KCOF": { - "id": "KCOF", - "city": "Cocoa - Patrick Air Force Base", - "state": "FL", - "lat": 28.24219, - "lon": -80.60799 - }, - "KCOI": { - "id": "KCOI", - "city": "Merritt Island Airport", - "state": "FL", - "lat": 28.3422, - "lon": -80.68407 - }, - "KCRG": { - "id": "KCRG", - "city": "Jacksonville Craig Municipal Airport", - "state": "FL", - "lat": 30.33709, - "lon": -81.51275 - }, - "KCTY": { - "id": "KCTY", - "city": "Cross City Airport", - "state": "FL", - "lat": 29.633326, - "lon": -83.105458 - }, - "KDAB": { - "id": "KDAB", - "city": "Daytona Beach International Airport", - "state": "FL", - "lat": 29.17354, - "lon": -81.07186 - }, - "KDED": { - "id": "KDED", - "city": "DeLand Municipal Airport", - "state": "FL", - "lat": 29.067, - "lon": -81.2837 - }, - "KDTS": { - "id": "KDTS", - "city": "Destin, Destin-Ft. Walton Beach Airport", - "state": "FL", - "lat": 30.39333, - "lon": -86.4675 - }, - "KECP": { - "id": "KECP", - "city": "Panama City - Northwest Florida Beaches International Airport", - "state": "FL", - "lat": 30.3582, - "lon": -85.7955999 - }, - "KEGI": { - "id": "KEGI", - "city": "Duke Field / Eglin Auxiliary", - "state": "FL", - "lat": 30.65, - "lon": -86.51667 - }, - "KEVB": { - "id": "KEVB", - "city": "New Smyrna Beach Municipal Airport", - "state": "FL", - "lat": 29.05687, - "lon": -80.94909 - }, - "KEYW": { - "id": "KEYW", - "city": "Key West International Airport", - "state": "FL", - "lat": 24.55707, - "lon": -81.75539 - }, - "KFHB": { - "id": "KFHB", - "city": "Fernandina Beach Municipal Airport", - "state": "FL", - "lat": 30.61183, - "lon": -81.46119 - }, - "KFIN": { - "id": "KFIN", - "city": "Flagler County Airport", - "state": "FL", - "lat": 29.4657, - "lon": -81.20872 - }, - "KFLL": { - "id": "KFLL", - "city": "Fort Lauderdale/Hollywood International Airport", - "state": "FL", - "lat": 26.07874, - "lon": -80.1622 - }, - "KFMY": { - "id": "KFMY", - "city": "Fort Myers, Page Field", - "state": "FL", - "lat": 26.58417, - "lon": -81.8625 - }, - "KFPR": { - "id": "KFPR", - "city": "Fort Pierce, St. Lucie County International Airport", - "state": "FL", - "lat": 27.49806, - "lon": -80.37667 - }, - "KFPY": { - "id": "KFPY", - "city": "Perry-Foley Airport", - "state": "FL", - "lat": 30.07081, - "lon": -83.58154 - }, - "KFXE": { - "id": "KFXE", - "city": "Fort Lauderdale, Fort Lauderdale Executive Airport", - "state": "FL", - "lat": 26.2, - "lon": -80.18333 - }, - "KGIF": { - "id": "KGIF", - "city": "Winter Havens Gilbert Airport", - "state": "FL", - "lat": 28.06138, - "lon": -81.75684 - }, - "KGNV": { - "id": "KGNV", - "city": "Gainesville, Gainesville Regional Airport", - "state": "FL", - "lat": 29.69194, - "lon": -82.27556 - }, - "KHEG": { - "id": "KHEG", - "city": "Herlong Recreational Airport", - "state": "FL", - "lat": 30.27778, - "lon": -81.80594 - }, - "KHRT": { - "id": "KHRT", - "city": "Hurlburt Field", - "state": "FL", - "lat": 30.41667, - "lon": -86.68333 - }, - "KHST": { - "id": "KHST", - "city": "Homestead Air Reserve Base", - "state": "FL", - "lat": 25.4948799, - "lon": -80.37324 - }, - "KHWO": { - "id": "KHWO", - "city": "Hollywood, North Perry Airport", - "state": "FL", - "lat": 25.99889, - "lon": -80.24111 - }, - "KIMM": { - "id": "KIMM", - "city": "IMMOKALEE", - "state": "FL", - "lat": 26.43, - "lon": -81.4 - }, - "KINF": { - "id": "KINF", - "city": "Inverness Airport", - "state": "FL", - "lat": 28.8086, - "lon": -82.3165 - }, - "KISM": { - "id": "KISM", - "city": "Kissimmee Gateway Airport", - "state": "FL", - "lat": 28.29236, - "lon": -81.43716 - }, - "KJAX": { - "id": "KJAX", - "city": "Jacksonville International Airport", - "state": "FL", - "lat": 30.49534, - "lon": -81.6937 - }, - "KLAL": { - "id": "KLAL", - "city": "Lakeland Linder International Airport", - "state": "FL", - "lat": 27.98333, - "lon": -82.01667 - }, - "KLCQ": { - "id": "KLCQ", - "city": "Lake City Municipal Airport", - "state": "FL", - "lat": 30.1821, - "lon": -82.5769 - }, - "KLEE": { - "id": "KLEE", - "city": "Leesburg International Airport", - "state": "FL", - "lat": 28.82142, - "lon": -81.80964 - }, - "KLNA": { - "id": "KLNA", - "city": "Palm Beach County Park Airport", - "state": "FL", - "lat": 26.59305, - "lon": -80.08506 - }, - "KMAI": { - "id": "KMAI", - "city": "Marianna Municipal Airport", - "state": "FL", - "lat": 30.83698, - "lon": -85.18347 - }, - "KMCF": { - "id": "KMCF", - "city": "Macdill Air Force Base, Fl.", - "state": "FL", - "lat": 27.85, - "lon": -82.5 - }, - "KMCO": { - "id": "KMCO", - "city": "Orlando International Airport", - "state": "FL", - "lat": 28.41826, - "lon": -81.32413 - }, - "KMIA": { - "id": "KMIA", - "city": "Miami, Miami International Airport", - "state": "FL", - "lat": 25.79056, - "lon": -80.31639 - }, - "KMLB": { - "id": "KMLB", - "city": "Melbourne International Airport", - "state": "FL", - "lat": 28.09973, - "lon": -80.6356 - }, - "KMTH": { - "id": "KMTH", - "city": "The Florida Keys - Marathon International Airport", - "state": "FL", - "lat": 24.72626, - "lon": -81.04765 - }, - "KNDZ": { - "id": "KNDZ", - "city": "Milton, Whiting Field South", - "state": "FL", - "lat": 30.69722, - "lon": -87.02 - }, - "KNEN": { - "id": "KNEN", - "city": "WHITEHOUSE NOF", - "state": "FL", - "lat": 30.35, - "lon": -81.88 - }, - "KNIP": { - "id": "KNIP", - "city": "Jacksonville Naval Air Station", - "state": "FL", - "lat": 30.23468, - "lon": -81.67462 - }, - "KNPA": { - "id": "KNPA", - "city": "Pensacola Naval Air Station", - "state": "FL", - "lat": 30.35641, - "lon": -87.32326 - }, - "KNQX": { - "id": "KNQX", - "city": "Key West Naval Air Station", - "state": "FL", - "lat": 24.5800899, - "lon": -81.68293 - }, - "KNRB": { - "id": "KNRB", - "city": "Mayport Naval Station - Adm David L. McDonald Field", - "state": "FL", - "lat": 30.39589, - "lon": -81.42286 - }, - "KNSE": { - "id": "KNSE", - "city": "Milton - Whiting Field Naval Air Station North", - "state": "FL", - "lat": 30.72848, - "lon": -87.02192 - }, - "KOBE": { - "id": "KOBE", - "city": "Okeechobee County Airport", - "state": "FL", - "lat": 27.2628, - "lon": -80.8498 - }, - "KOCF": { - "id": "KOCF", - "city": "Ocala International Airport - Jim Taylor Field", - "state": "FL", - "lat": 29.16372, - "lon": -82.22097 - }, - "KOMN": { - "id": "KOMN", - "city": "Ormond Beach, Ormond Beach Municipal Airport", - "state": "FL", - "lat": 29.30111, - "lon": -81.11361 - }, - "KOPF": { - "id": "KOPF", - "city": "Miami, Opa Locka Airport", - "state": "FL", - "lat": 25.91, - "lon": -80.28306 - }, - "KORL": { - "id": "KORL", - "city": "Orlando Executive Airport", - "state": "FL", - "lat": 28.54655, - "lon": -81.33543 - }, - "KPAM": { - "id": "KPAM", - "city": "Tyndall Air Force Base", - "state": "FL", - "lat": 30.06444, - "lon": -85.5637 - }, - "KPBI": { - "id": "KPBI", - "city": "West Palm Beach - Palm Beach International Airport", - "state": "FL", - "lat": 26.6850999, - "lon": -80.0991899 - }, - "KPCM": { - "id": "KPCM", - "city": "Plant City, Plant City Municipal Airport", - "state": "FL", - "lat": 28, - "lon": -82.15 - }, - "KPGD": { - "id": "KPGD", - "city": "Punta Gorda, Charlotte County Airport", - "state": "FL", - "lat": 26.91778, - "lon": -81.99361 - }, - "KPIE": { - "id": "KPIE", - "city": "St. Petersburg/Clearwater Airport", - "state": "FL", - "lat": 27.91259, - "lon": -82.68554 - }, - "KPMP": { - "id": "KPMP", - "city": "Pompano Beach, Pompano Beach Airpark", - "state": "FL", - "lat": 26.24556, - "lon": -80.11139 - }, - "KPNS": { - "id": "KPNS", - "city": "Pensacola - Pensacola International Airport", - "state": "FL", - "lat": 30.47806, - "lon": -87.18694 - }, - "KRSW": { - "id": "KRSW", - "city": "Fort Myers, Southwest Florida International Airport", - "state": "FL", - "lat": 26.52694, - "lon": -81.76639 - }, - "KSEF": { - "id": "KSEF", - "city": "Sebring Regional Airport", - "state": "FL", - "lat": 27.45639, - "lon": -81.34239 - }, - "KSFB": { - "id": "KSFB", - "city": "Orlando / Sanford Airport", - "state": "FL", - "lat": 28.78333, - "lon": -81.25 - }, - "KSGJ": { - "id": "KSGJ", - "city": "Northeast Florida Regional Airport", - "state": "FL", - "lat": 29.95924, - "lon": -81.34105 - }, - "KSPG": { - "id": "KSPG", - "city": "Albert Whitted Airport", - "state": "FL", - "lat": 27.76852, - "lon": -82.62564 - }, - "KSRQ": { - "id": "KSRQ", - "city": "Sarasota / Bradenton, Sarasota-Bradenton International Airport", - "state": "FL", - "lat": 27.40139, - "lon": -82.55861 - }, - "KSUA": { - "id": "KSUA", - "city": "Witham Field Airport", - "state": "FL", - "lat": 27.18157, - "lon": -80.22519 - }, - "KTDR": { - "id": "KTDR", - "city": "Tyndall Drone Runway", - "state": "FL", - "lat": 30.0333, - "lon": -85.5333 - }, - "KTIX": { - "id": "KTIX", - "city": "Titusville", - "state": "FL", - "lat": 28.51667, - "lon": -80.8 - }, - "KTLH": { - "id": "KTLH", - "city": "Tallahassee International Airport", - "state": "FL", - "lat": 30.39675, - "lon": -84.35087 - }, - "KTMB": { - "id": "KTMB", - "city": "Miami, Kendall-Tamiami Executive Airport", - "state": "FL", - "lat": 25.64194, - "lon": -80.43472 - }, - "KTPA": { - "id": "KTPA", - "city": "Tampa, Tampa International Airport", - "state": "FL", - "lat": 27.96139, - "lon": -82.54028 - }, - "KTPF": { - "id": "KTPF", - "city": "Tampa, Peter O Knight Airport", - "state": "FL", - "lat": 27.91556, - "lon": -82.44917 - }, - "KTTS": { - "id": "KTTS", - "city": "Titusville, NASA Shuttle Landing Facility", - "state": "FL", - "lat": 28.61667, - "lon": -80.7 - }, - "KVDF": { - "id": "KVDF", - "city": "Tampa, Vandenberg Airport", - "state": "FL", - "lat": 28.01983, - "lon": -82.3415 - }, - "KVNC": { - "id": "KVNC", - "city": "Venice Municipal Airport", - "state": "FL", - "lat": 27.0716, - "lon": -82.44033 - }, - "KVPS": { - "id": "KVPS", - "city": "Valparaiso / Eglin Air Force Base", - "state": "FL", - "lat": 30.48333, - "lon": -86.51667 - }, - "KVQQ": { - "id": "KVQQ", - "city": "Cecil Airport", - "state": "FL", - "lat": 30.21292, - "lon": -81.8707 - }, - "KVRB": { - "id": "KVRB", - "city": "Vero Beach, Vero Beach Municipal Airport", - "state": "FL", - "lat": 27.65556, - "lon": -80.41806 - }, - "KXMR": { - "id": "KXMR", - "city": "Cocoa Beach, Cape Canaveral Air Force Station Skid Strip", - "state": "FL", - "lat": 28.46667, - "lon": -80.56667 - }, - "KZPH": { - "id": "KZPH", - "city": "Zephyrhills Airport", - "state": "FL", - "lat": 28.2281, - "lon": -82.1559 - }, - "KABH": { - "id": "KABH", - "city": "ELLICOTT-B AFA", - "state": "CO", - "lat": 38.7578, - "lon": -104.3013 - }, - "KAEJ": { - "id": "KAEJ", - "city": "Central Colorado Regional Airport", - "state": "CO", - "lat": 38.81416, - "lon": -106.12069 - }, - "KAFF": { - "id": "KAFF", - "city": "Air Force Academy", - "state": "CO", - "lat": 38.96667, - "lon": -104.81667 - }, - "KAJZ": { - "id": "KAJZ", - "city": "Delta/Blake Field Airport", - "state": "CO", - "lat": 38.7868799, - "lon": -108.06584 - }, - "KAKO": { - "id": "KAKO", - "city": "Colorado Plains Regional Airport", - "state": "CO", - "lat": 40.17428, - "lon": -103.21459 - }, - "KALS": { - "id": "KALS", - "city": "San Luis Valley Regional Airport", - "state": "CO", - "lat": 37.43933, - "lon": -105.8618 - }, - "KANK": { - "id": "KANK", - "city": "Harriet Alexander Field Airport", - "state": "CO", - "lat": 38.53828, - "lon": -106.04864 - }, - "KAPA": { - "id": "KAPA", - "city": "Denver - Centennial Airport", - "state": "CO", - "lat": 39.55991, - "lon": -104.84841 - }, - "KASE": { - "id": "KASE", - "city": "Aspen-Pitkin County Airport", - "state": "CO", - "lat": 39.22992, - "lon": -106.87051 - }, - "KBDU": { - "id": "KBDU", - "city": "Boulder Municipal Airport", - "state": "CO", - "lat": 40.0394297, - "lon": -105.2258217 - }, - "KBJC": { - "id": "KBJC", - "city": "Rocky Mountain Metro", - "state": "CO", - "lat": 39.90085, - "lon": -105.10417 - }, - "KBKF": { - "id": "KBKF", - "city": "Buckley Space Force Base", - "state": "CO", - "lat": 39.71331, - "lon": -104.75806 - }, - "KCAG": { - "id": "KCAG", - "city": "Craig-Moffat Airport", - "state": "CO", - "lat": 40.49297, - "lon": -107.52394 - }, - "KCCU": { - "id": "KCCU", - "city": "Copper Mountain - Red Cliff Pass", - "state": "CO", - "lat": 39.47523, - "lon": -106.15228 - }, - "KCEZ": { - "id": "KCEZ", - "city": "Cortez-Montezuma County Airport", - "state": "CO", - "lat": 37.30706, - "lon": -108.62644 - }, - "KCFO": { - "id": "KCFO", - "city": "Colorado Air and Space Port Airport", - "state": "CO", - "lat": 39.78419, - "lon": -104.53764 - }, - "KCOS": { - "id": "KCOS", - "city": "City of Colorado Springs Municipal Airport", - "state": "CO", - "lat": 38.8094899, - "lon": -104.68873 - }, - "KCPW": { - "id": "KCPW", - "city": "Pagosa Springs, Wolf Creek Pass", - "state": "CO", - "lat": 37.45139, - "lon": -106.80028 - }, - "KCWN": { - "id": "KCWN", - "city": "Cheyenne Mountain", - "state": "CO", - "lat": 38.7434299, - "lon": -104.84334 - }, - "KDEN": { - "id": "KDEN", - "city": "Denver, Denver International Airport", - "state": "CO", - "lat": 39.84658, - "lon": -104.65622 - }, - "KDRO": { - "id": "KDRO", - "city": "Durango-La Plata County Airport", - "state": "CO", - "lat": 37.14312, - "lon": -107.76023 - }, - "KEEO": { - "id": "KEEO", - "city": "Meeker Airport", - "state": "CO", - "lat": 40.0444, - "lon": -107.88832 - }, - "KEGE": { - "id": "KEGE", - "city": "Eagle County Regional", - "state": "CO", - "lat": 39.65, - "lon": -106.91667 - }, - "KEIK": { - "id": "KEIK", - "city": "Erie Municipal Airport", - "state": "CO", - "lat": 40.01169, - "lon": -105.05033 - }, - "KFCS": { - "id": "KFCS", - "city": "Butts Army Airfield (Fort Carson)", - "state": "CO", - "lat": 38.68312, - "lon": -104.75977 - }, - "KFLY": { - "id": "KFLY", - "city": "Meadow Lake Airport", - "state": "CO", - "lat": 38.94391, - "lon": -104.5684 - }, - "KFMM": { - "id": "KFMM", - "city": "Fort Morgan Municipal Airport", - "state": "CO", - "lat": 40.33148, - "lon": -103.80704 - }, - "KFNL": { - "id": "KFNL", - "city": "Fort Collins/Loveland - Northern Colorado Regional Airport", - "state": "CO", - "lat": 40.45, - "lon": -105.01667 - }, - "KGJT": { - "id": "KGJT", - "city": "Grand Junction Regional Airport", - "state": "CO", - "lat": 39.13389, - "lon": -108.53861 - }, - "KGNB": { - "id": "KGNB", - "city": "Granby-Grand County Airport", - "state": "CO", - "lat": 40.09006, - "lon": -105.91664 - }, - "KGUC": { - "id": "KGUC", - "city": "Gunnison, Gunnison-Crested Butte Regional Airport", - "state": "CO", - "lat": 38.53333, - "lon": -106.93333 - }, - "KGXY": { - "id": "KGXY", - "city": "Greeley, Greeley-Weld County Airport", - "state": "CO", - "lat": 40.43333, - "lon": -104.63333 - }, - "KHEQ": { - "id": "KHEQ", - "city": "Holyoke Airport", - "state": "CO", - "lat": 40.57155, - "lon": -102.27676 - }, - "KITR": { - "id": "KITR", - "city": "Burlington - Carson County Airport", - "state": "CO", - "lat": 39.24149, - "lon": -102.2818999 - }, - "KLAA": { - "id": "KLAA", - "city": "Lamar Municipal Airport", - "state": "CO", - "lat": 38.0717799, - "lon": -102.68745 - }, - "KLHX": { - "id": "KLHX", - "city": "La Junta Municipal Airport", - "state": "CO", - "lat": 38.04949, - "lon": -103.51334 - }, - "KLIC": { - "id": "KLIC", - "city": "Limon Municipal Airport", - "state": "CO", - "lat": 39.27334, - "lon": -103.66738 - }, - "KLMO": { - "id": "KLMO", - "city": "Vance Brand Airport", - "state": "CO", - "lat": 40.16115, - "lon": -105.16042 - }, - "KLXV": { - "id": "KLXV", - "city": "Leadville, Lake County Airport", - "state": "CO", - "lat": 39.22806, - "lon": -106.31611 - }, - "KMNH": { - "id": "KMNH", - "city": "Elbert Mountain - Monument Pass", - "state": "CO", - "lat": 39.22317, - "lon": -104.6422599 - }, - "KMTJ": { - "id": "KMTJ", - "city": "Montrose, Montrose Regional Airport", - "state": "CO", - "lat": 38.505, - "lon": -107.8975 - }, - "KMYP": { - "id": "KMYP", - "city": "Salida - Monarch Pass", - "state": "CO", - "lat": 38.4972, - "lon": -106.3197 - }, - "KPSO": { - "id": "KPSO", - "city": "Stevens Field, Pagosa Springs", - "state": "CO", - "lat": 37.2862, - "lon": -107.056 - }, - "KPUB": { - "id": "KPUB", - "city": "Pueblo Memorial Airport", - "state": "CO", - "lat": 38.28869, - "lon": -104.5057 - }, - "KRCV": { - "id": "KRCV", - "city": "Astronaut Kent Rominger - Del Norte", - "state": "CO", - "lat": 37.7138, - "lon": -106.352 - }, - "KRIL": { - "id": "KRIL", - "city": "Garfield County Regional Airport", - "state": "CO", - "lat": 39.52793, - "lon": -107.71961 - }, - "KSBS": { - "id": "KSBS", - "city": "Steamboat Springs", - "state": "CO", - "lat": 40.5153, - "lon": -106.86767 - }, - "KSHM": { - "id": "KSHM", - "city": "Schriever AFB", - "state": "CO", - "lat": 38.8, - "lon": -104.5167 - }, - "KSPD": { - "id": "KSPD", - "city": "Springfield, Comanche National Grassland", - "state": "CO", - "lat": 37.28333, - "lon": -102.61667 - }, - "KSTK": { - "id": "KSTK", - "city": "Sterling Municipal Airport", - "state": "CO", - "lat": 40.61331, - "lon": -103.26109 - }, - "KTAD": { - "id": "KTAD", - "city": "Perry Stokes Airport", - "state": "CO", - "lat": 37.26218, - "lon": -104.33184 - }, - "KTEX": { - "id": "KTEX", - "city": "Telluride, Telluride Regional Airport", - "state": "CO", - "lat": 37.95389, - "lon": -107.90861 - }, - "KVTP": { - "id": "KVTP", - "city": "La Veta Mountain, La Veta Pass", - "state": "CO", - "lat": 37.50111, - "lon": -105.16694 - }, - "PARW": { - "id": "PARW", - "city": "YAKIMA RIVER NEAR PARKER, WA.", - "state": "WA", - "lat": 46.5061111, - "lon": -120.4519444 - }, - "QSPW": { - "id": "QSPW", - "city": "QUARTZ MTN", - "state": "WA", - "lat": 47.0672222, - "lon": -121.0788888 - }, - "KABI": { - "id": "KABI", - "city": "Abilene, Abilene Regional Airport", - "state": "TX", - "lat": 32.41028, - "lon": -99.68167 - }, - "KACT": { - "id": "KACT", - "city": "Waco, Waco Regional Airport", - "state": "TX", - "lat": 31.61722, - "lon": -97.22778 - }, - "KADS": { - "id": "KADS", - "city": "Dallas / Addison Airport", - "state": "TX", - "lat": 32.96667, - "lon": -96.83333 - }, - "KAFW": { - "id": "KAFW", - "city": "Fort Worth, Fort Worth Alliance Airport", - "state": "TX", - "lat": 32.97333, - "lon": -97.31806 - }, - "KALI": { - "id": "KALI", - "city": "Alice, Alice International Airport", - "state": "TX", - "lat": 27.74111, - "lon": -98.02694 - }, - "KAMA": { - "id": "KAMA", - "city": "Amarillo, Amarillo International Airport", - "state": "TX", - "lat": 35.22, - "lon": -101.71722 - }, - "KAPY": { - "id": "KAPY", - "city": "Zapata, TX", - "state": "TX", - "lat": 26.969, - "lon": -99.249 - }, - "KAQO": { - "id": "KAQO", - "city": "Llano, Llano Municipal Airport", - "state": "TX", - "lat": 30.78361, - "lon": -98.66194 - }, - "KARM": { - "id": "KARM", - "city": "Wharton, Wharton Regional Airport", - "state": "TX", - "lat": 29.25417, - "lon": -96.1541699 - }, - "KASL": { - "id": "KASL", - "city": "Marshall", - "state": "TX", - "lat": 32.5205, - "lon": -94.3078 - }, - "KATT": { - "id": "KATT", - "city": "Austin City, Austin Camp Mabry", - "state": "TX", - "lat": 30.31667, - "lon": -97.76667 - }, - "KAUS": { - "id": "KAUS", - "city": "Austin-Bergstrom International Airport", - "state": "TX", - "lat": 30.18304, - "lon": -97.6798699 - }, - "KAXH": { - "id": "KAXH", - "city": "Houston Southwest Airport", - "state": "TX", - "lat": 29.50613, - "lon": -95.47692 - }, - "KBAZ": { - "id": "KBAZ", - "city": "New Braunfels National Airport", - "state": "TX", - "lat": 29.70575, - "lon": -98.04322 - }, - "KBBD": { - "id": "KBBD", - "city": "Brady, Curtis Field Airport", - "state": "TX", - "lat": 31.17917, - "lon": -99.32389 - }, - "KBEA": { - "id": "KBEA", - "city": "Beeville Municipal Airport", - "state": "TX", - "lat": 28.362, - "lon": -97.791 - }, - "KBGD": { - "id": "KBGD", - "city": "Borger, Hutchinson County Airport", - "state": "TX", - "lat": 35.695, - "lon": -101.395 - }, - "KBIF": { - "id": "KBIF", - "city": "Biggs Army Air Field - Fort Bliss", - "state": "TX", - "lat": 31.86119, - "lon": -106.3691599 - }, - "KBKD": { - "id": "KBKD", - "city": "Stephens County Airport", - "state": "TX", - "lat": 32.719, - "lon": -98.891 - }, - "KBKS": { - "id": "KBKS", - "city": "Falfurrias, Brooks County Airport", - "state": "TX", - "lat": 27.20667, - "lon": -98.12111 - }, - "KBMQ": { - "id": "KBMQ", - "city": "Burnet, Burnet Municipal Craddock Field", - "state": "TX", - "lat": 30.74056, - "lon": -98.23528 - }, - "KBMT": { - "id": "KBMT", - "city": "Beaumont Municipal Airport", - "state": "TX", - "lat": 30.0702, - "lon": -94.2151 - }, - "KBPC": { - "id": "KBPC", - "city": "Mesa Vista Ranch AP", - "state": "TX", - "lat": 35.889, - "lon": -101.03 - }, - "KBPG": { - "id": "KBPG", - "city": "Big Spring, Big Spring McMahon-Wrinkle Airport", - "state": "TX", - "lat": 32.2, - "lon": -101.51667 - }, - "KBPT": { - "id": "KBPT", - "city": "Beaumont/Port Arthur Southeast Texas Regional Airport", - "state": "TX", - "lat": 29.9521, - "lon": -94.0261 - }, - "KBQX": { - "id": "KBQX", - "city": "BRAZOS 451 OIL PLATFORM", - "state": "TX", - "lat": 28.5, - "lon": -95.72 - }, - "KBRO": { - "id": "KBRO", - "city": "Brownsville, Brownsville / South Padre Island International Airport", - "state": "TX", - "lat": 25.91417, - "lon": -97.42306 - }, - "KBWD": { - "id": "KBWD", - "city": "Brownwood, Brownwood Regional Airport", - "state": "TX", - "lat": 31.8, - "lon": -98.95 - }, - "KBYY": { - "id": "KBYY", - "city": "Bay City, Bay City Municipal Airport", - "state": "TX", - "lat": 28.97306, - "lon": -95.86333 - }, - "KCDS": { - "id": "KCDS", - "city": "Childress, Childress Municipal Airport", - "state": "TX", - "lat": 34.4275, - "lon": -100.28333 - }, - "KCFD": { - "id": "KCFD", - "city": "Bryan Coulter Field", - "state": "TX", - "lat": 30.7157, - "lon": -96.3314 - }, - "KCLL": { - "id": "KCLL", - "city": "College Station, Easterwood Field", - "state": "TX", - "lat": 30.58222, - "lon": -96.36167 - }, - "KCNW": { - "id": "KCNW", - "city": "Waco-James Connally Airport", - "state": "TX", - "lat": 31.6378, - "lon": -97.0741 - }, - "KCOM": { - "id": "KCOM", - "city": "COLEMAN", - "state": "TX", - "lat": 31.84, - "lon": -99.4 - }, - "KCOT": { - "id": "KCOT", - "city": "Cotulla, Cotulla-La Salle County Airport", - "state": "TX", - "lat": 28.45833, - "lon": -99.22028 - }, - "KCPT": { - "id": "KCPT", - "city": "Cleburne, Cleburne Municipal Airport", - "state": "TX", - "lat": 32.35361, - "lon": -97.43361 - }, - "KCRP": { - "id": "KCRP", - "city": "Corpus Christi, Corpus Christi International Airport", - "state": "TX", - "lat": 27.77306, - "lon": -97.51278 - }, - "KCRS": { - "id": "KCRS", - "city": "Corsicana, Campbell Field-Corsicana Municipal Airport", - "state": "TX", - "lat": 32.03111, - "lon": -96.39889 - }, - "KCVB": { - "id": "KCVB", - "city": "Castroville Municipal Airport", - "state": "TX", - "lat": 29.34192, - "lon": -98.8509 - }, - "KCWC": { - "id": "KCWC", - "city": "Kickapoo Downtown Airport", - "state": "TX", - "lat": 33.8606, - "lon": -98.4903999 - }, - "KCXO": { - "id": "KCXO", - "city": "Conroe, Montgomery County Airport", - "state": "TX", - "lat": 30.35667, - "lon": -95.41389 - }, - "KCZT": { - "id": "KCZT", - "city": "Carrizo Springs Dimmit County Airport", - "state": "TX", - "lat": 28.5222, - "lon": -99.8236 - }, - "KDAL": { - "id": "KDAL", - "city": "Dallas Love Field", - "state": "TX", - "lat": 32.85416, - "lon": -96.85506 - }, - "KDFW": { - "id": "KDFW", - "city": "Dallas/Fort Worth International Airport", - "state": "TX", - "lat": 32.89743, - "lon": -97.02196 - }, - "KDHT": { - "id": "KDHT", - "city": "Dalhart, Dalhart Municipal Airport", - "state": "TX", - "lat": 36.02333, - "lon": -102.54722 - }, - "KDKR": { - "id": "KDKR", - "city": "Crockett, Houston County Airport", - "state": "TX", - "lat": 31.30694, - "lon": -95.40361 - }, - "KDLF": { - "id": "KDLF", - "city": "Laughlin Air Force Base Auxiliary Airfield", - "state": "TX", - "lat": 29.36652, - "lon": -100.78469 - }, - "KDRT": { - "id": "KDRT", - "city": "Del Rio, Del Rio International Airport", - "state": "TX", - "lat": 29.37472, - "lon": -100.92361 - }, - "KDTO": { - "id": "KDTO", - "city": "Denton Enterprise Airport", - "state": "TX", - "lat": 33.20505, - "lon": -97.20061 - }, - "KDUX": { - "id": "KDUX", - "city": "Dumas, Moore County Airport", - "state": "TX", - "lat": 35.85778, - "lon": -102.01306 - }, - "KDWH": { - "id": "KDWH", - "city": "Houston, Hooks Memorial Airport", - "state": "TX", - "lat": 30.0675, - "lon": -95.55611 - }, - "KDYS": { - "id": "KDYS", - "city": "Abilene, Dyess Air Force Base", - "state": "TX", - "lat": 32.42, - "lon": -99.85694 - }, - "KDZB": { - "id": "KDZB", - "city": "Horseshoe Bay Resort Airpark", - "state": "TX", - "lat": 30.5271, - "lon": -98.3588 - }, - "KEBG": { - "id": "KEBG", - "city": "Edinburg, Edinburg International Airport", - "state": "TX", - "lat": 26.44194, - "lon": -98.12944 - }, - "KECU": { - "id": "KECU", - "city": "Rocksprings, Edwards County Airport", - "state": "TX", - "lat": 29.94667, - "lon": -100.17361 - }, - "KEDC": { - "id": "KEDC", - "city": "Austin Executive Airport", - "state": "TX", - "lat": 30.3925, - "lon": -97.5621 - }, - "KEFD": { - "id": "KEFD", - "city": "Houston / Ellington", - "state": "TX", - "lat": 29.6, - "lon": -95.16667 - }, - "KELA": { - "id": "KELA", - "city": "Eagle Lake", - "state": "TX", - "lat": 29.6006, - "lon": -96.3219 - }, - "KELP": { - "id": "KELP", - "city": "El Paso, El Paso International Airport", - "state": "TX", - "lat": 31.81111, - "lon": -106.3758299 - }, - "KERV": { - "id": "KERV", - "city": "Kerrville, Kerrville Municipal Airport/Louis Schreiner Field", - "state": "TX", - "lat": 29.96667, - "lon": -99.08333 - }, - "KETN": { - "id": "KETN", - "city": "Eastland Municipal Airport", - "state": "TX", - "lat": 32.41489, - "lon": -98.80969 - }, - "KFST": { - "id": "KFST", - "city": "Fort Stockton, Fort Stockton-Pecos County Airport", - "state": "TX", - "lat": 30.91194, - "lon": -102.91667 - }, - "KFTN": { - "id": "KFTN", - "city": "Faith Ranch Airport", - "state": "TX", - "lat": 28.2086, - "lon": -100.0188 - }, - "KFTW": { - "id": "KFTW", - "city": "Fort Worth, Meacham International Airport", - "state": "TX", - "lat": 32.82528, - "lon": -97.36417 - }, - "KFWS": { - "id": "KFWS", - "city": "Fort Worth Spinks Airport", - "state": "TX", - "lat": 32.56537, - "lon": -97.30837 - }, - "KGDJ": { - "id": "KGDJ", - "city": "Granbury, Granbury Municipal Airport", - "state": "TX", - "lat": 32.44417, - "lon": -97.81667 - }, - "KGGG": { - "id": "KGGG", - "city": "Longview - East Texas Regional Airport", - "state": "TX", - "lat": 32.39056, - "lon": -94.71389 - }, - "KGKY": { - "id": "KGKY", - "city": "Arlington Municipal Airport", - "state": "TX", - "lat": 32.65829, - "lon": -97.09509 - }, - "KGLS": { - "id": "KGLS", - "city": "Galveston, Scholes Field", - "state": "TX", - "lat": 29.27028, - "lon": -94.86417 - }, - "KGNC": { - "id": "KGNC", - "city": "Seminole, Gaines County Airport", - "state": "TX", - "lat": 32.67528, - "lon": -102.6525 - }, - "KGOP": { - "id": "KGOP", - "city": "Gatesville, City-County Airport", - "state": "TX", - "lat": 31.42111, - "lon": -97.79694 - }, - "KGPM": { - "id": "KGPM", - "city": "Grand Prairie, Grand Prairie Municipal Airport", - "state": "TX", - "lat": 32.69861, - "lon": -97.04667 - }, - "KGRK": { - "id": "KGRK", - "city": "Fort Hood, Robert Gray AAF Ft Hood", - "state": "TX", - "lat": 31.06667, - "lon": -97.81667 - }, - "KGTU": { - "id": "KGTU", - "city": "Georgetown, Georgetown Municipal Airport", - "state": "TX", - "lat": 30.68333, - "lon": -97.68333 - }, - "KGUL": { - "id": "KGUL", - "city": "GUNNISON OIL PLATFORM", - "state": "TX", - "lat": 27.3, - "lon": -93.53 - }, - "KGVT": { - "id": "KGVT", - "city": "Greenville / Majors", - "state": "TX", - "lat": 33.06667, - "lon": -96.06667 - }, - "KGVW": { - "id": "KGVW", - "city": "Galveston 209A", - "state": "TX", - "lat": 29.13, - "lon": -94.55 - }, - "KGYB": { - "id": "KGYB", - "city": "Giddings, Giddings-Lee County Airport", - "state": "TX", - "lat": 30.16917, - "lon": -96.98 - }, - "KGYI": { - "id": "KGYI", - "city": "Sherman/Denison, Grayson County Airport", - "state": "TX", - "lat": 33.71667, - "lon": -96.66667 - }, - "KGZN": { - "id": "KGZN", - "city": "Gregory M Simmons Memorial Airport", - "state": "TX", - "lat": 32.3658, - "lon": -99.0237 - }, - "KHDO": { - "id": "KHDO", - "city": "Hondo, Hondo Municipal Airport", - "state": "TX", - "lat": 29.35944, - "lon": -99.17417 - }, - "KHHF": { - "id": "KHHF", - "city": "Canadian, Hemphill County Airport", - "state": "TX", - "lat": 35.9, - "lon": -100.4 - }, - "KHHV": { - "id": "KHHV", - "city": "Alaminos Canyon 25/H-D (ExxonMobil)", - "state": "TX", - "lat": 26.939, - "lon": -94.6889999 - }, - "KHLR": { - "id": "KHLR", - "city": "Fort Hood, Hood AAF Ft Hood", - "state": "TX", - "lat": 31.13333, - "lon": -97.7 - }, - "KHOU": { - "id": "KHOU", - "city": "Houston, Houston Hobby Airport", - "state": "TX", - "lat": 29.6375, - "lon": -95.2825 - }, - "KHQZ": { - "id": "KHQZ", - "city": "Mesquite, Mesquite Metro Airport", - "state": "TX", - "lat": 32.74694, - "lon": -96.53028 - }, - "KHRL": { - "id": "KHRL", - "city": "Harlingen, Rio Grande Valley International Airport", - "state": "TX", - "lat": 26.22972, - "lon": -97.65528 - }, - "KHRX": { - "id": "KHRX", - "city": "Hereford Municipal Airport", - "state": "TX", - "lat": 34.8578, - "lon": -102.3264 - }, - "KHYI": { - "id": "KHYI", - "city": "San Marcos, San Marcos Municipal Airport", - "state": "TX", - "lat": 29.89361, - "lon": -97.86472 - }, - "KIAH": { - "id": "KIAH", - "city": "Houston Intercontinental Airport", - "state": "TX", - "lat": 29.9844, - "lon": -95.36074 - }, - "KIKG": { - "id": "KIKG", - "city": "Kleberg County Airport", - "state": "TX", - "lat": 27.5509, - "lon": -98.0309 - }, - "KILE": { - "id": "KILE", - "city": "Killeen, Skylark Field Airport", - "state": "TX", - "lat": 31.08333, - "lon": -97.68333 - }, - "KINJ": { - "id": "KINJ", - "city": "Hillsboro, Hillsboro Municipal Airport", - "state": "TX", - "lat": 32.0833299, - "lon": -97.0972199 - }, - "KINK": { - "id": "KINK", - "city": "Wink, Winkler County Airport", - "state": "TX", - "lat": 31.77972, - "lon": -103.20139 - }, - "KJAS": { - "id": "KJAS", - "city": "Jasper, Jasper County-Bell Field Airport", - "state": "TX", - "lat": 30.88556, - "lon": -94.0347199 - }, - "KJCT": { - "id": "KJCT", - "city": "Junction, Kimble County Airport", - "state": "TX", - "lat": 30.51083, - "lon": -99.76639 - }, - "KJDD": { - "id": "KJDD", - "city": "Mineola/Quitman, Wood County Airport", - "state": "TX", - "lat": 32.74194, - "lon": -95.49639 - }, - "KJSO": { - "id": "KJSO", - "city": "Jacksonville, Cherokee County Airport", - "state": "TX", - "lat": 31.86917, - "lon": -95.21722 - }, - "KJWY": { - "id": "KJWY", - "city": "Midlothian/Waxahachie, Mid-Way Regional Airport", - "state": "TX", - "lat": 32.45583, - "lon": -96.91222 - }, - "KJXI": { - "id": "KJXI", - "city": "Gilmer, Fox Stephens Field - Gilmer Municipal Airport", - "state": "TX", - "lat": 32.69889, - "lon": -94.94861 - }, - "KLBB": { - "id": "KLBB", - "city": "Lubbock, Lubbock International Airport", - "state": "TX", - "lat": 33.6674999, - "lon": -101.8213899 - }, - "KLFK": { - "id": "KLFK", - "city": "Lufkin, Angelina County Airport", - "state": "TX", - "lat": 31.23389, - "lon": -94.75 - }, - "KLHB": { - "id": "KLHB", - "city": "Hearne, Hearne Municipal Airport", - "state": "TX", - "lat": 30.87167, - "lon": -96.62222 - }, - "KLLN": { - "id": "KLLN", - "city": "Levelland Municipal Airport", - "state": "TX", - "lat": 33.55253, - "lon": -102.37253 - }, - "KLNC": { - "id": "KLNC", - "city": "Lancaster Airport", - "state": "TX", - "lat": 32.58323, - "lon": -96.72091 - }, - "KLRD": { - "id": "KLRD", - "city": "Laredo, Laredo International Airport", - "state": "TX", - "lat": 27.54361, - "lon": -99.46139 - }, - "KLUD": { - "id": "KLUD", - "city": "Decatur, Decatur Municipal Airport", - "state": "TX", - "lat": 33.25444, - "lon": -97.58056 - }, - "KLUV": { - "id": "KLUV", - "city": "Lamesa Municipal Airport", - "state": "TX", - "lat": 32.75631, - "lon": -101.92022 - }, - "KLVJ": { - "id": "KLVJ", - "city": "Houston, Pearland Regional Airport", - "state": "TX", - "lat": 29.52111, - "lon": -95.24194 - }, - "KLXY": { - "id": "KLXY", - "city": "Mexia Limestone County Airport", - "state": "TX", - "lat": 31.6412, - "lon": -96.5145 - }, - "KMAF": { - "id": "KMAF", - "city": "Midland, Midland International Airport", - "state": "TX", - "lat": 31.94778, - "lon": -102.2086099 - }, - "KMCJ": { - "id": "KMCJ", - "city": "John Dunn Helistop", - "state": "TX", - "lat": 29.714, - "lon": -95.395 - }, - "KMDD": { - "id": "KMDD", - "city": "Midland, Midland Airpark", - "state": "TX", - "lat": 32.03639, - "lon": -102.10083 - }, - "KMFE": { - "id": "KMFE", - "city": "McAllen, Miller International Airport", - "state": "TX", - "lat": 26.17972, - "lon": -98.24444 - }, - "KMKN": { - "id": "KMKN", - "city": "Comanche, Comanche County-City Airport", - "state": "TX", - "lat": 31.91667, - "lon": -98.60028 - }, - "KMNZ": { - "id": "KMNZ", - "city": "Hamilton Municipal Airport", - "state": "TX", - "lat": 31.6659, - "lon": -98.1486 - }, - "KMWL": { - "id": "KMWL", - "city": "Mineral Wells, Mineral Wells Airport", - "state": "TX", - "lat": 32.78167, - "lon": -98.06028 - }, - "KNFW": { - "id": "KNFW", - "city": "Fort Worth, Naval Air Station", - "state": "TX", - "lat": 32.76583, - "lon": -97.43333 - }, - "KNGP": { - "id": "KNGP", - "city": "Corpus Christi, Corpus Christi Naval Air Station/Truax Field", - "state": "TX", - "lat": 27.6925, - "lon": -97.29111 - }, - "KNOG": { - "id": "KNOG", - "city": "Orange Grove NALF", - "state": "TX", - "lat": 27.8947, - "lon": -98.0425099 - }, - "KNQI": { - "id": "KNQI", - "city": "Kingsville, Naval Air Station", - "state": "TX", - "lat": 27.50306, - "lon": -97.81167 - }, - "KOCH": { - "id": "KOCH", - "city": "Nacogdoches, A L Mangham Jr. Regional Airport", - "state": "TX", - "lat": 31.58333, - "lon": -94.7166699 - }, - "KODO": { - "id": "KODO", - "city": "Odessa, Odessa-Schlemeyer Field", - "state": "TX", - "lat": 31.92139, - "lon": -102.39167 - }, - "KORG": { - "id": "KORG", - "city": "Orange, Orange County Airport", - "state": "TX", - "lat": 30.06917, - "lon": -93.80361 - }, - "KOSA": { - "id": "KOSA", - "city": "Mount Pleasant, Mount Pleasant Regional Airport", - "state": "TX", - "lat": 33.09528, - "lon": -94.96139 - }, - "KOZA": { - "id": "KOZA", - "city": "Ozona Municipal Airport", - "state": "TX", - "lat": 30.7353, - "lon": -101.203 - }, - "KPEZ": { - "id": "KPEZ", - "city": "Pleasanton Municipal Airport", - "state": "TX", - "lat": 28.9562, - "lon": -98.5184 - }, - "KPIL": { - "id": "KPIL", - "city": "Port Isabel, Port Isabel-Cameron County Airport", - "state": "TX", - "lat": 26.15917, - "lon": -97.3375 - }, - "KPKV": { - "id": "KPKV", - "city": "Port Lavaca - Calhoun County Airport", - "state": "TX", - "lat": 28.65159, - "lon": -96.68196 - }, - "KPPA": { - "id": "KPPA", - "city": "Pampa, Perry Lefors Field Airport", - "state": "TX", - "lat": 35.61278, - "lon": -100.99611 - }, - "KPRS": { - "id": "KPRS", - "city": "Presidio Lely International Airport", - "state": "TX", - "lat": 29.6341, - "lon": -104.3616 - }, - "KPRX": { - "id": "KPRX", - "city": "Paris / Cox Field", - "state": "TX", - "lat": 33.63333, - "lon": -95.45 - }, - "KPSN": { - "id": "KPSN", - "city": "Palestine, Palestine Municipal Airport", - "state": "TX", - "lat": 31.77944, - "lon": -95.70611 - }, - "KPVW": { - "id": "KPVW", - "city": "Plainview, Hale County Airport", - "state": "TX", - "lat": 34.1680599, - "lon": -101.71722 - }, - "KPWG": { - "id": "KPWG", - "city": "Waco, Mc Gregor Executive Airport", - "state": "TX", - "lat": 31.48333, - "lon": -97.31667 - }, - "KPYX": { - "id": "KPYX", - "city": "Perryton, Perryton Ochiltree County Airport", - "state": "TX", - "lat": 36.4, - "lon": -100.73333 - }, - "KRAS": { - "id": "KRAS", - "city": "Port Aransas, Mustang Beach Airport", - "state": "TX", - "lat": 27.81167, - "lon": -97.08861 - }, - "KRBD": { - "id": "KRBD", - "city": "Dallas, Redbird Airport", - "state": "TX", - "lat": 32.67583, - "lon": -96.86389 - }, - "KRBO": { - "id": "KRBO", - "city": "Robstown, Nueces County Airport", - "state": "TX", - "lat": 27.77833, - "lon": -97.69028 - }, - "KRFI": { - "id": "KRFI", - "city": "Rusk County Airport", - "state": "TX", - "lat": 32.1417, - "lon": -94.8516999 - }, - "KRKP": { - "id": "KRKP", - "city": "Rockport Aransas County Airport", - "state": "TX", - "lat": 28.08371, - "lon": -97.04664 - }, - "KRND": { - "id": "KRND", - "city": "Randolph Air Force Base", - "state": "TX", - "lat": 29.53333, - "lon": -98.28333 - }, - "KRPH": { - "id": "KRPH", - "city": "Graham, Graham Municipal Airport", - "state": "TX", - "lat": 33.11, - "lon": -98.55528 - }, - "KRWV": { - "id": "KRWV", - "city": "Caldwell, Caldwell Municipal Airport", - "state": "TX", - "lat": 30.51528, - "lon": -96.70389 - }, - "KRYW": { - "id": "KRYW", - "city": "Lago Vista TX, Rusty Allen Airport", - "state": "TX", - "lat": 30.4967, - "lon": -97.9659 - }, - "KSAT": { - "id": "KSAT", - "city": "San Antonio, San Antonio International Airport", - "state": "TX", - "lat": 29.53278, - "lon": -98.46361 - }, - "KSEP": { - "id": "KSEP", - "city": "Stephenville, Clark Field Municipal Airport", - "state": "TX", - "lat": 32.21667, - "lon": -98.18333 - }, - "KSEQ": { - "id": "KSEQ", - "city": "Seguin - Randolph AFB Auxiliary Field", - "state": "TX", - "lat": 29.56579, - "lon": -97.90834 - }, - "KSGR": { - "id": "KSGR", - "city": "Houston, Sugar Land Municipal / Hull Field Airport", - "state": "TX", - "lat": 29.62222, - "lon": -95.65667 - }, - "KSHP": { - "id": "KSHP", - "city": "Sheppard Air Force Base", - "state": "TX", - "lat": 33.96667, - "lon": -98.48333 - }, - "KSJT": { - "id": "KSJT", - "city": "San Angelo, Mathis Field", - "state": "TX", - "lat": 31.35139, - "lon": -100.4938899 - }, - "KSKF": { - "id": "KSKF", - "city": "San Antonio - Kelly Field", - "state": "TX", - "lat": 29.38333, - "lon": -98.58333 - }, - "KSLR": { - "id": "KSLR", - "city": "Sulphur Springs, Sulphur Springs Municipal Airport", - "state": "TX", - "lat": 33.16111, - "lon": -95.62111 - }, - "KSNK": { - "id": "KSNK", - "city": "Snyder, Winston Field Airport", - "state": "TX", - "lat": 32.69333, - "lon": -100.95028 - }, - "KSOA": { - "id": "KSOA", - "city": "Sonora, Sonora Municipal Airport", - "state": "TX", - "lat": 30.58556, - "lon": -100.64833 - }, - "KSPS": { - "id": "KSPS", - "city": "Wichita Falls, Sheppard Air Force Base", - "state": "TX", - "lat": 33.97861, - "lon": -98.49278 - }, - "KSSF": { - "id": "KSSF", - "city": "San Antonio, Stinson Municipal Airport", - "state": "TX", - "lat": 29.33889, - "lon": -98.47167 - }, - "KSWW": { - "id": "KSWW", - "city": "Sweetwater, Avenger Field Airport", - "state": "TX", - "lat": 32.46722, - "lon": -100.46639 - }, - "KTFP": { - "id": "KTFP", - "city": "Mc Campbell", - "state": "TX", - "lat": 27.913, - "lon": -97.2115 - }, - "KTKI": { - "id": "KTKI", - "city": "McKinney - McKinney National Airport", - "state": "TX", - "lat": 33.17778, - "lon": -96.59028 - }, - "KTME": { - "id": "KTME", - "city": "Houston Executive Airport", - "state": "TX", - "lat": 29.80717, - "lon": -95.89791 - }, - "KTPL": { - "id": "KTPL", - "city": "Temple, Draughon-Miller Central Texas Regional Airport", - "state": "TX", - "lat": 31.15, - "lon": -97.4 - }, - "KTRL": { - "id": "KTRL", - "city": "Terrell, Terrell Municipal Airport", - "state": "TX", - "lat": 32.71361, - "lon": -96.26833 - }, - "KTXW": { - "id": "KTXW", - "city": "Mid Valley Airport", - "state": "TX", - "lat": 26.17871, - "lon": -97.97401 - }, - "KTYR": { - "id": "KTYR", - "city": "Tyler, Tyler Pounds Field", - "state": "TX", - "lat": 32.35861, - "lon": -95.40389 - }, - "KUTS": { - "id": "KUTS", - "city": "Huntsville, Huntsville Municipal Airport", - "state": "TX", - "lat": 30.74389, - "lon": -95.58611 - }, - "KUVA": { - "id": "KUVA", - "city": "Uvalde, Garner Field Airport", - "state": "TX", - "lat": 29.21111, - "lon": -99.74333 - }, - "KVAF": { - "id": "KVAF", - "city": "East Breaks 643/Boomvang Spar", - "state": "TX", - "lat": 27.354, - "lon": -94.625 - }, - "KVCT": { - "id": "KVCT", - "city": "Victoria, Victoria Regional Airport", - "state": "TX", - "lat": 28.8625, - "lon": -96.92972 - }, - "KVHN": { - "id": "KVHN", - "city": "Culberson County Airport", - "state": "TX", - "lat": 31.05783, - "lon": -104.78381 - }, - "KXBP": { - "id": "KXBP", - "city": "Bridgeport, Bridgeport Municipal Airport", - "state": "TX", - "lat": 33.17528, - "lon": -97.8283299 - }, - "KAST": { - "id": "KAST", - "city": "Astoria, Astoria Regional Airport", - "state": "OR", - "lat": 46.15694, - "lon": -123.8825 - }, - "KBDN": { - "id": "KBDN", - "city": "Bend Airport AWOS", - "state": "OR", - "lat": 44.0948, - "lon": -121.2006 - }, - "KBKE": { - "id": "KBKE", - "city": "Baker Municipal Airport", - "state": "OR", - "lat": 44.84302, - "lon": -117.80987 - }, - "KBNO": { - "id": "KBNO", - "city": "Burns Municipal Airport", - "state": "OR", - "lat": 43.59488, - "lon": -118.95791 - }, - "KBOK": { - "id": "KBOK", - "city": "Brookings, Brookings Airport", - "state": "OR", - "lat": 42.07444, - "lon": -124.29 - }, - "KCVO": { - "id": "KCVO", - "city": "Corvallis, Corvallis Municipal Airport", - "state": "OR", - "lat": 44.5, - "lon": -123.28333 - }, - "KEUG": { - "id": "KEUG", - "city": "Eugene, Mahlon Sweet Field", - "state": "OR", - "lat": 44.13333, - "lon": -123.21444 - }, - "KGCD": { - "id": "KGCD", - "city": "Grant County Regional Airport", - "state": "OR", - "lat": 44.40287, - "lon": -118.96715 - }, - "KHIO": { - "id": "KHIO", - "city": "Portland-Hillsboro Airport", - "state": "OR", - "lat": 45.54765, - "lon": -122.95568 - }, - "KHRI": { - "id": "KHRI", - "city": "Hermiston, Hermiston Municipal Airport", - "state": "OR", - "lat": 45.82583, - "lon": -119.26111 - }, - "KJSY": { - "id": "KJSY", - "city": "Joseph State Airport AWOS", - "state": "OR", - "lat": 45.355889, - "lon": -117.254083 - }, - "KLGD": { - "id": "KLGD", - "city": "La Grande/Union County Airport", - "state": "OR", - "lat": 45.29066, - "lon": -118.00884 - }, - "KLKV": { - "id": "KLKV", - "city": "Lake County Airport", - "state": "OR", - "lat": 42.15664, - "lon": -120.39721 - }, - "KLMT": { - "id": "KLMT", - "city": "Klamath Falls International Airport", - "state": "OR", - "lat": 42.14703, - "lon": -121.72548 - }, - "KMEH": { - "id": "KMEH", - "city": "Meacham", - "state": "OR", - "lat": 45.51176, - "lon": -118.42466 - }, - "KMFR": { - "id": "KMFR", - "city": "Rogue Valley International Airport", - "state": "OR", - "lat": 42.37503, - "lon": -122.87696 - }, - "KMMV": { - "id": "KMMV", - "city": "McMinnville, McMinnville Municipal Airport", - "state": "OR", - "lat": 45.19611, - "lon": -123.13222 - }, - "KONO": { - "id": "KONO", - "city": "Ontario Municipal Airport", - "state": "OR", - "lat": 44.01424, - "lon": -117.00808 - }, - "KONP": { - "id": "KONP", - "city": "Newport, Newport Municipal Airport", - "state": "OR", - "lat": 44.58028, - "lon": -124.05806 - }, - "KOTH": { - "id": "KOTH", - "city": "Southwest Oregon Regional Airport", - "state": "OR", - "lat": 43.41948, - "lon": -124.2437 - }, - "KPDT": { - "id": "KPDT", - "city": "Eastern Oregon Regional Airport at Pendleton", - "state": "OR", - "lat": 45.69757, - "lon": -118.83444 - }, - "KPDX": { - "id": "KPDX", - "city": "Portland, Portland International Airport", - "state": "OR", - "lat": 45.59578, - "lon": -122.60917 - }, - "KRBG": { - "id": "KRBG", - "city": "Roseburg Regional Airport", - "state": "OR", - "lat": 43.23368, - "lon": -123.3577 - }, - "KRDM": { - "id": "KRDM", - "city": "Redmond Roberts Field", - "state": "OR", - "lat": 44.25588, - "lon": -121.14059 - }, - "KREO": { - "id": "KREO", - "city": "Rome State Airport", - "state": "OR", - "lat": 42.57766, - "lon": -117.88543 - }, - "KSLE": { - "id": "KSLE", - "city": "Salem - McNary Field", - "state": "OR", - "lat": 44.90493, - "lon": -123.00096 - }, - "KSPB": { - "id": "KSPB", - "city": "Scappoose Industrial Airpark", - "state": "OR", - "lat": 45.7691, - "lon": -122.86365 - }, - "KSXT": { - "id": "KSXT", - "city": "Sexton Summit", - "state": "OR", - "lat": 42.6, - "lon": -123.3656 - }, - "KTMK": { - "id": "KTMK", - "city": "Tillamook, Tillamook Airport", - "state": "OR", - "lat": 45.4180599, - "lon": -123.81444 - }, - "KTTD": { - "id": "KTTD", - "city": "Portland, Portland-Troutdale Airport", - "state": "OR", - "lat": 45.55111, - "lon": -122.40889 - }, - "KUAO": { - "id": "KUAO", - "city": "Aurora State Airport", - "state": "OR", - "lat": 45.24658, - "lon": -122.77095 - }, - "KAAT": { - "id": "KAAT", - "city": "Alturas", - "state": "CA", - "lat": 41.48362, - "lon": -120.5615 - }, - "KACV": { - "id": "KACV", - "city": "Arcata / Eureka, Arcata Airport", - "state": "CA", - "lat": 40.97806, - "lon": -124.10861 - }, - "KAJO": { - "id": "KAJO", - "city": "Corona Airport", - "state": "CA", - "lat": 33.8977, - "lon": -117.6024 - }, - "KAPC": { - "id": "KAPC", - "city": "Napa, Napa County Airport", - "state": "CA", - "lat": 38.2075, - "lon": -122.27944 - }, - "KAPV": { - "id": "KAPV", - "city": "APPLEVALLEY", - "state": "CA", - "lat": 34.57533, - "lon": -117.18619 - }, - "KAUN": { - "id": "KAUN", - "city": "Auburn Municipal Airport", - "state": "CA", - "lat": 38.95535, - "lon": -121.08636 - }, - "KAVX": { - "id": "KAVX", - "city": "Avalon Catalina Airport", - "state": "CA", - "lat": 33.40421, - "lon": -118.41456 - }, - "KBAB": { - "id": "KBAB", - "city": "Marysville, Beale Air Force Base", - "state": "CA", - "lat": 39.13333, - "lon": -121.43333 - }, - "KBAN": { - "id": "KBAN", - "city": "MCMWTC BRIDGEPORT", - "state": "CA", - "lat": 38.3557, - "lon": -119.5188 - }, - "KBFL": { - "id": "KBFL", - "city": "Bakersfield, Meadows Field Airport", - "state": "CA", - "lat": 35.43361, - "lon": -119.05667 - }, - "KBIH": { - "id": "KBIH", - "city": "Bishop, Bishop Airport", - "state": "CA", - "lat": 37.37111, - "lon": -118.35806 - }, - "KBLH": { - "id": "KBLH", - "city": "Blythe, Blythe Airport", - "state": "CA", - "lat": 33.6191699, - "lon": -114.71694 - }, - "KBLU": { - "id": "KBLU", - "city": "Emigrant Gap, Blue Canyon Nyack Airport", - "state": "CA", - "lat": 39.27611, - "lon": -120.70806 - }, - "KBUR": { - "id": "KBUR", - "city": "Burbank - Bob Hope Airport", - "state": "CA", - "lat": 34.19967, - "lon": -118.36538 - }, - "KBYS": { - "id": "KBYS", - "city": "Fort Irwin/Barstow, Bicycle Lake Army Airfield", - "state": "CA", - "lat": 35.28333, - "lon": -116.61667 - }, - "KCCB": { - "id": "KCCB", - "city": "Cable Airport", - "state": "CA", - "lat": 34.11161, - "lon": -117.68739 - }, - "KCCR": { - "id": "KCCR", - "city": "Concord, Buchanan Field", - "state": "CA", - "lat": 37.99167, - "lon": -122.05194 - }, - "KCEC": { - "id": "KCEC", - "city": "Crescent City, Jack McNamara Field Airport", - "state": "CA", - "lat": 41.78028, - "lon": -124.23667 - }, - "KCIC": { - "id": "KCIC", - "city": "Chico Municipal Airport", - "state": "CA", - "lat": 39.7987899, - "lon": -121.85795 - }, - "KCMA": { - "id": "KCMA", - "city": "Camarillo, Camarillo Airport", - "state": "CA", - "lat": 34.21667, - "lon": -119.08333 - }, - "KCNO": { - "id": "KCNO", - "city": "Chino, Chino Airport", - "state": "CA", - "lat": 33.97556, - "lon": -117.62361 - }, - "KCPU": { - "id": "KCPU", - "city": "San Andreas Calaveras County Airport", - "state": "CA", - "lat": 38.1460999, - "lon": -120.6482 - }, - "KCRQ": { - "id": "KCRQ", - "city": "Carlsbad, McClellan-Palomar Airport", - "state": "CA", - "lat": 33.13, - "lon": -117.27583 - }, - "KCVH": { - "id": "KCVH", - "city": "Hollister, CA", - "state": "CA", - "lat": 36.8933, - "lon": -121.4103 - }, - "KDAG": { - "id": "KDAG", - "city": "Daggett, Barstow-Daggett Airport", - "state": "CA", - "lat": 34.85361, - "lon": -116.78667 - }, - "KDLO": { - "id": "KDLO", - "city": "Delano Municipal Airport", - "state": "CA", - "lat": 35.74556, - "lon": -119.2365 - }, - "KDVO": { - "id": "KDVO", - "city": "Novato / Gnoss Field", - "state": "CA", - "lat": 38.14178, - "lon": -122.55463 - }, - "KDWA": { - "id": "KDWA", - "city": "Yolo County Airport", - "state": "CA", - "lat": 38.5793899, - "lon": -121.85694 - }, - "KEDU": { - "id": "KEDU", - "city": "University Airport", - "state": "CA", - "lat": 38.5315, - "lon": -121.7865 - }, - "KEDW": { - "id": "KEDW", - "city": "Edwards Air Force Base", - "state": "CA", - "lat": 34.918, - "lon": -117.879 - }, - "KEED": { - "id": "KEED", - "city": "Needles, Needles Airport", - "state": "CA", - "lat": 34.76611, - "lon": -114.62333 - }, - "KEMT": { - "id": "KEMT", - "city": "El Monte", - "state": "CA", - "lat": 34.0833299, - "lon": -118.03333 - }, - "KFAT": { - "id": "KFAT", - "city": "Fresno, Fresno Air Terminal", - "state": "CA", - "lat": 36.78, - "lon": -119.71944 - }, - "KFOT": { - "id": "KFOT", - "city": "Fortuna Rohnerville Airport", - "state": "CA", - "lat": 40.55296, - "lon": -124.13338 - }, - "KFUL": { - "id": "KFUL", - "city": "Fullerton, Fullerton Municipal Airport", - "state": "CA", - "lat": 33.87194, - "lon": -117.98472 - }, - "KGOO": { - "id": "KGOO", - "city": "Nevada County Air Park", - "state": "CA", - "lat": 39.2240279, - "lon": -121.003083 - }, - "KHAF": { - "id": "KHAF", - "city": "Half Moon Bay Airport", - "state": "CA", - "lat": 37.5135999, - "lon": -122.4996 - }, - "KHHR": { - "id": "KHHR", - "city": "Hawthorne, Hawthorne Municipal Airport", - "state": "CA", - "lat": 33.9236099, - "lon": -118.33194 - }, - "KHJO": { - "id": "KHJO", - "city": "Hanford Municipal Airport", - "state": "CA", - "lat": 36.31145, - "lon": -119.62315 - }, - "KHMT": { - "id": "KHMT", - "city": "Hemet-Ryan Airport", - "state": "CA", - "lat": 33.73403, - "lon": -117.02231 - }, - "KHWD": { - "id": "KHWD", - "city": "Hayward, Hayward Air Terminal", - "state": "CA", - "lat": 37.66083, - "lon": -122.11833 - }, - "KIPL": { - "id": "KIPL", - "city": "Imperial, Imperial County Airport", - "state": "CA", - "lat": 32.83417, - "lon": -115.57861 - }, - "KIZA": { - "id": "KIZA", - "city": "Santa Ynez, Santa Ynez Airport", - "state": "CA", - "lat": 34.60694, - "lon": -120.07556 - }, - "KJAQ": { - "id": "KJAQ", - "city": "Westover Field - Amador County Airport", - "state": "CA", - "lat": 38.3768, - "lon": -120.79391 - }, - "KLAX": { - "id": "KLAX", - "city": "Los Angeles, Los Angeles International Airport", - "state": "CA", - "lat": 33.93806, - "lon": -118.38889 - }, - "KLGB": { - "id": "KLGB", - "city": "Long Beach, Long Beach Airport", - "state": "CA", - "lat": 33.81167, - "lon": -118.14639 - }, - "KLHM": { - "id": "KLHM", - "city": "Lincoln Regional Karl Harder Field", - "state": "CA", - "lat": 38.9092, - "lon": -121.3513 - }, - "KLPC": { - "id": "KLPC", - "city": "Lompoc, Lompoc Airport", - "state": "CA", - "lat": 34.66667, - "lon": -120.46667 - }, - "KLVK": { - "id": "KLVK", - "city": "Livermore, Livermore Municipal Airport", - "state": "CA", - "lat": 37.69278, - "lon": -121.81444 - }, - "KMAE": { - "id": "KMAE", - "city": "Madera Municipal Airport", - "state": "CA", - "lat": 36.9851, - "lon": -120.11064 - }, - "KMCC": { - "id": "KMCC", - "city": "Sacramento, McClellan Airfield Airport", - "state": "CA", - "lat": 38.66667, - "lon": -121.4 - }, - "KMCE": { - "id": "KMCE", - "city": "Merced Regional Airport", - "state": "CA", - "lat": 37.28306, - "lon": -120.50778 - }, - "KMHR": { - "id": "KMHR", - "city": "Sacramento Mather Airport", - "state": "CA", - "lat": 38.5599599, - "lon": -121.28397 - }, - "KMHS": { - "id": "KMHS", - "city": "Mount Shasta", - "state": "CA", - "lat": 41.31494, - "lon": -122.31702 - }, - "KMHV": { - "id": "KMHV", - "city": "Mojave", - "state": "CA", - "lat": 35.06667, - "lon": -118.15 - }, - "KMMH": { - "id": "KMMH", - "city": "Mammoth Yosemite Airport", - "state": "CA", - "lat": 37.6241, - "lon": -118.8423 - }, - "KMOD": { - "id": "KMOD", - "city": "Modesto City-County Airport - Harry Sham Field", - "state": "CA", - "lat": 37.62549, - "lon": -120.9549 - }, - "KMRY": { - "id": "KMRY", - "city": "Monterey Regional Airport", - "state": "CA", - "lat": 36.59047, - "lon": -121.84875 - }, - "KMWS": { - "id": "KMWS", - "city": "MOUNT WILSON", - "state": "CA", - "lat": 34.22, - "lon": -118.07 - }, - "KMYF": { - "id": "KMYF", - "city": "San Diego, Montgomery Field", - "state": "CA", - "lat": 32.81444, - "lon": -117.13639 - }, - "KMYV": { - "id": "KMYV", - "city": "Marysville, Yuba County Airport", - "state": "CA", - "lat": 39.09778, - "lon": -121.56972 - }, - "KNFG": { - "id": "KNFG", - "city": "Oceanside, Camp Pendleton, Marine Corps Air Station", - "state": "CA", - "lat": 33.30472, - "lon": -117.35389 - }, - "KNID": { - "id": "KNID", - "city": "China Lake, Naval Air Facility", - "state": "CA", - "lat": 35.68639, - "lon": -117.69 - }, - "KNJK": { - "id": "KNJK", - "city": "El Centro, Naval Air Facility", - "state": "CA", - "lat": 32.825, - "lon": -115.66056 - }, - "KNKX": { - "id": "KNKX", - "city": "San Diego, Miramar MCAS/Mitscher Field Airport", - "state": "CA", - "lat": 32.86833, - "lon": -117.1425 - }, - "KNLC": { - "id": "KNLC", - "city": "Lemoore Naval Air Station - Reeves Field", - "state": "CA", - "lat": 36.30244, - "lon": -119.93968 - }, - "KNRS": { - "id": "KNRS", - "city": "Imperial Beach Naval Outlying Field - Ream Field", - "state": "CA", - "lat": 32.56302, - "lon": -117.11091 - }, - "KNSI": { - "id": "KNSI", - "city": "San Nicolas Island Naval Outlying Field", - "state": "CA", - "lat": 33.23379, - "lon": -119.45588 - }, - "KNTD": { - "id": "KNTD", - "city": "Point Mugu, Naval Air Warfare Center", - "state": "CA", - "lat": 34.12389, - "lon": -119.12167 - }, - "KNUC": { - "id": "KNUC", - "city": "San Clemente Island NALF", - "state": "CA", - "lat": 33.0218, - "lon": -118.58266 - }, - "KNUQ": { - "id": "KNUQ", - "city": "Mountain View, Moffett Field", - "state": "CA", - "lat": 37.40583, - "lon": -122.04806 - }, - "KNXP": { - "id": "KNXP", - "city": "Twentynine Palms SELF Airport", - "state": "CA", - "lat": 34.29401, - "lon": -116.14717 - }, - "KNZY": { - "id": "KNZY", - "city": "San Diego, North Island, Naval Air Station", - "state": "CA", - "lat": 32.69083, - "lon": -117.20889 - }, - "KOAK": { - "id": "KOAK", - "city": "San Francisco Bay Oakland International Airport", - "state": "CA", - "lat": 37.72126, - "lon": -122.22115 - }, - "KOAR": { - "id": "KOAR", - "city": "FORT ORD/FRITZSCHE", - "state": "CA", - "lat": 36.68, - "lon": -121.77 - }, - "KOKB": { - "id": "KOKB", - "city": "Oceanside, Oceanside Municipal Airport", - "state": "CA", - "lat": 33.21806, - "lon": -117.35139 - }, - "KONT": { - "id": "KONT", - "city": "Ontario International Airport", - "state": "CA", - "lat": 34.05316, - "lon": -117.57685 - }, - "KOVE": { - "id": "KOVE", - "city": "Oroville Municipal Airport", - "state": "CA", - "lat": 39.49436, - "lon": -121.62223 - }, - "KOXR": { - "id": "KOXR", - "city": "Oxnard, Oxnard Airport", - "state": "CA", - "lat": 34.20056, - "lon": -119.20306 - }, - "KPAO": { - "id": "KPAO", - "city": "Palo Alto Airport", - "state": "CA", - "lat": 37.46667, - "lon": -122.11667 - }, - "KPMD": { - "id": "KPMD", - "city": "Palmdale, Palmdale Production Flight Plant", - "state": "CA", - "lat": 34.62972, - "lon": -118.08139 - }, - "KPOC": { - "id": "KPOC", - "city": "Brackett Field Airport", - "state": "CA", - "lat": 34.09282, - "lon": -117.77937 - }, - "KPRB": { - "id": "KPRB", - "city": "Paso Robles Municipal Airport", - "state": "CA", - "lat": 35.66941, - "lon": -120.62912 - }, - "KPSP": { - "id": "KPSP", - "city": "Palm Springs Regional Airport", - "state": "CA", - "lat": 33.82219, - "lon": -116.50431 - }, - "KPTV": { - "id": "KPTV", - "city": "Porterville, Porterville Municipal Airport", - "state": "CA", - "lat": 36.03333, - "lon": -119.06667 - }, - "KPVF": { - "id": "KPVF", - "city": "Placerville Airport", - "state": "CA", - "lat": 38.7242, - "lon": -120.7533 - }, - "KRAL": { - "id": "KRAL", - "city": "Riverside Municipal Airport", - "state": "CA", - "lat": 33.95189, - "lon": -117.44511 - }, - "KRBL": { - "id": "KRBL", - "city": "Red Bluff, Red Bluff Municipal Airport", - "state": "CA", - "lat": 40.15056, - "lon": -122.25222 - }, - "KRDD": { - "id": "KRDD", - "city": "Redding Municipal Airport", - "state": "CA", - "lat": 40.51461, - "lon": -122.2977 - }, - "KREI": { - "id": "KREI", - "city": "REDLANDS", - "state": "CA", - "lat": 34.08526, - "lon": -117.14637 - }, - "KRHV": { - "id": "KRHV", - "city": "San Jose / Reid / Hillv", - "state": "CA", - "lat": 37.3333299, - "lon": -121.81667 - }, - "KRIV": { - "id": "KRIV", - "city": "March Air Reserve Base", - "state": "CA", - "lat": 33.88194, - "lon": -117.25902 - }, - "KRNM": { - "id": "KRNM", - "city": "Ramona, Ramona Airport", - "state": "CA", - "lat": 33.0375, - "lon": -116.91583 - }, - "KSAC": { - "id": "KSAC", - "city": "Sacramento Executive Airport", - "state": "CA", - "lat": 38.50674, - "lon": -121.49597 - }, - "KSAN": { - "id": "KSAN", - "city": "San Diego International Airport", - "state": "CA", - "lat": 32.73361, - "lon": -117.18306 - }, - "KSBA": { - "id": "KSBA", - "city": "Santa Barbara, Santa Barbara Municipal Airport", - "state": "CA", - "lat": 34.42611, - "lon": -119.84361 - }, - "KSBD": { - "id": "KSBD", - "city": "San Bernardino Intl. Airport", - "state": "CA", - "lat": 34.0902699, - "lon": -117.24705 - }, - "KSBP": { - "id": "KSBP", - "city": "San Luis Obispo, San Luis Obispo County-Mc Chesney Field", - "state": "CA", - "lat": 35.2361099, - "lon": -120.63611 - }, - "KSCK": { - "id": "KSCK", - "city": "Stockton, Stockton Metropolitan Airport", - "state": "CA", - "lat": 37.8897199, - "lon": -121.22361 - }, - "KSDB": { - "id": "KSDB", - "city": "Sandberg", - "state": "CA", - "lat": 34.7436099, - "lon": -118.72444 - }, - "KSDM": { - "id": "KSDM", - "city": "San Diego, Brown Field Municipal Airport", - "state": "CA", - "lat": 32.57528, - "lon": -116.99306 - }, - "KSEE": { - "id": "KSEE", - "city": "Gillespie Field Airport", - "state": "CA", - "lat": 32.82738, - "lon": -116.97369 - }, - "KSFO": { - "id": "KSFO", - "city": "San Francisco, San Francisco International Airport", - "state": "CA", - "lat": 37.61961, - "lon": -122.36558 - }, - "KSIY": { - "id": "KSIY", - "city": "Montague Siskiyou County Airport", - "state": "CA", - "lat": 41.77375, - "lon": -122.46817 - }, - "KSJC": { - "id": "KSJC", - "city": "San Jose, San Jose International Airport", - "state": "CA", - "lat": 37.35917, - "lon": -121.92417 - }, - "KSLI": { - "id": "KSLI", - "city": "Los Alamitos Army Airfield", - "state": "CA", - "lat": 33.79628, - "lon": -118.04179 - }, - "KSMF": { - "id": "KSMF", - "city": "Sacramento International Airport", - "state": "CA", - "lat": 38.70071, - "lon": -121.59479 - }, - "KSMO": { - "id": "KSMO", - "city": "Santa Monica, Santa Monica Municipal Airport", - "state": "CA", - "lat": 34.01583, - "lon": -118.45139 - }, - "KSMX": { - "id": "KSMX", - "city": "Santa Maria Public Airport/Capt G Allan Hancock Field", - "state": "CA", - "lat": 34.89408, - "lon": -120.45212 - }, - "KSNA": { - "id": "KSNA", - "city": "John Wayne-Orange County Airport", - "state": "CA", - "lat": 33.6798, - "lon": -117.8674 - }, - "KSNS": { - "id": "KSNS", - "city": "Salinas, Salinas Municipal Airport", - "state": "CA", - "lat": 36.66361, - "lon": -121.60806 - }, - "KSQL": { - "id": "KSQL", - "city": "San Carlos Airport", - "state": "CA", - "lat": 37.51667, - "lon": -122.25 - }, - "KSTS": { - "id": "KSTS", - "city": "Santa Rosa, Santa Rosa Sonoma County Airport", - "state": "CA", - "lat": 38.5, - "lon": -122.81667 - }, - "KSUU": { - "id": "KSUU", - "city": "Fairfield / Travis Air Force Base", - "state": "CA", - "lat": 38.26667, - "lon": -121.95 - }, - "KSVE": { - "id": "KSVE", - "city": "Susanville Municipal Airport", - "state": "CA", - "lat": 40.37569, - "lon": -120.57269 - }, - "KTCY": { - "id": "KTCY", - "city": "Tracy Municipal Airport", - "state": "CA", - "lat": 37.6888999, - "lon": -121.44158 - }, - "KTOA": { - "id": "KTOA", - "city": "Torrance, Zamperini Field Airport", - "state": "CA", - "lat": 33.8, - "lon": -118.33333 - }, - "KTQS": { - "id": "KTQS", - "city": "Vandenberg SFB - South", - "state": "CA", - "lat": 34.633, - "lon": -120.617 - }, - "KTRK": { - "id": "KTRK", - "city": "Truckee-Tahoe", - "state": "CA", - "lat": 39.31667, - "lon": -120.13333 - }, - "KTRM": { - "id": "KTRM", - "city": "Palm Springs, Jacqueline Cochran Regional Airport", - "state": "CA", - "lat": 33.62667, - "lon": -116.15944 - }, - "KTSP": { - "id": "KTSP", - "city": "Tehachapi Municipal Airport", - "state": "CA", - "lat": 35.135, - "lon": -118.4392 - }, - "KTVL": { - "id": "KTVL", - "city": "South Lake Tahoe, Lake Tahoe Airport", - "state": "CA", - "lat": 38.8983599, - "lon": -119.99615 - }, - "KUKI": { - "id": "KUKI", - "city": "Ukiah Municipal Airport", - "state": "CA", - "lat": 39.12783, - "lon": -123.20011 - }, - "KVBG": { - "id": "KVBG", - "city": "Vandenberg Space Force Base", - "state": "CA", - "lat": 34.7294399, - "lon": -120.57667 - }, - "KVCB": { - "id": "KVCB", - "city": "Vacaville Nut Tree Airport", - "state": "CA", - "lat": 38.37755, - "lon": -121.95853 - }, - "KVCV": { - "id": "KVCV", - "city": "Victorville, Southern California Logistics Airport", - "state": "CA", - "lat": 34.59722, - "lon": -117.38278 - }, - "KVIS": { - "id": "KVIS", - "city": "Visalia, Visalia Municipal Airport", - "state": "CA", - "lat": 36.31667, - "lon": -119.4 - }, - "KVNY": { - "id": "KVNY", - "city": "Van Nuys, Van Nuys Airport", - "state": "CA", - "lat": 34.2125, - "lon": -118.49083 - }, - "KWHP": { - "id": "KWHP", - "city": "Los Angeles, Whiteman Airport", - "state": "CA", - "lat": 34.25, - "lon": -118.4 - }, - "KWJF": { - "id": "KWJF", - "city": "General Wm J Fox Airfield", - "state": "CA", - "lat": 34.74123, - "lon": -118.21251 - }, - "KWVI": { - "id": "KWVI", - "city": "Watsonville, Watsonville Municipal Airport", - "state": "CA", - "lat": 36.93944, - "lon": -121.78889 - }, - "PARO": { - "id": "PARO", - "city": "PARKDALE", - "state": "OR", - "lat": 45.54444, - "lon": -121.61667 - }, - "PCYO": { - "id": "PCYO", - "city": "PRARIE CITY", - "state": "OR", - "lat": 44.44083, - "lon": -118.62778 - }, - "PDTO": { - "id": "PDTO", - "city": "Umatilla River at Pendleton, OR", - "state": "OR", - "lat": 45.6722222, - "lon": -118.7916666 - }, - "PILO": { - "id": "PILO", - "city": "Pilot Rock 11E, OR", - "state": "OR", - "lat": 45.5019444, - "lon": -118.6205555 - }, - "PNGO": { - "id": "PNGO", - "city": "PINEGROVE", - "state": "OR", - "lat": 45.65222, - "lon": -121.50917 - }, - "POBO": { - "id": "POBO", - "city": "POWELL BUTTE", - "state": "OR", - "lat": 44.24833, - "lon": -120.94972 - }, - "PRHO": { - "id": "PRHO", - "city": "Powder River at Hudspeth Lane near Sumpter, OR", - "state": "OR", - "lat": 44.6861111, - "lon": -118.1 - }, - "PRIO": { - "id": "PRIO", - "city": "Prineville 4NW, OR", - "state": "OR", - "lat": 44.3691666, - "lon": -120.9377777 - }, - "PRVO": { - "id": "PRVO", - "city": "Crooked River near Prineville, OR", - "state": "OR", - "lat": 44.1138888, - "lon": -120.7944444 - }, - "PWDO": { - "id": "PWDO", - "city": "Powder River at Baker, OR", - "state": "OR", - "lat": 44.7683333, - "lon": -117.8305555 - } + "KBID": {"id":"KBID","lat":41.1694699,"lon":-71.5787299,"state":"RI","location":"Block Island State Airport","city":"Block Is.","priority":6}, + "KOQU": {"id":"KOQU","lat":41.6,"lon":-71.41667,"state":"RI","location":"N. Kingston / Quonset","city":"N Kingston","priority":99}, + "KPVD": {"id":"KPVD","lat":41.72233,"lon":-71.4277199,"state":"RI","location":"Rhode Island TF Green International Airport","city":"Providence","priority":1}, + "KSFZ": {"id":"KSFZ","lat":41.91667,"lon":-71.5,"state":"RI","location":"Pawtucket, North Central State Airport","city":"Pawtucket","priority":6}, + "KUUU": {"id":"KUUU","lat":41.53,"lon":-71.28361,"state":"RI","location":"Newport, Newport State Airport","city":"Newport","priority":6}, + "KWST": {"id":"KWST","lat":41.34972,"lon":-71.79889,"state":"RI","location":"Westerly, Westerly State Airport","city":"Westerly","priority":6}, + "KDOV": {"id":"KDOV","lat":39.13333,"lon":-75.4666699,"state":"DE","location":"Dover Air Force Base","city":"Dover","priority":14}, + "KGED": {"id":"KGED","lat":38.68974,"lon":-75.36245,"state":"DE","location":"Georgetown - Delaware Coastal Airport","city":"Georgetown","priority":13}, + "KILG": {"id":"KILG","lat":39.67442,"lon":-75.60567,"state":"DE","location":"Wilmington, New Castle County Airport","city":"Wilmington","priority":10}, + "KAFO": {"id":"KAFO","lat":42.7113299,"lon":-110.94217,"state":"WY","location":"Afton WY","city":"Afton","priority":99}, + "KARL": {"id":"KARL","lat":41.5980599,"lon":-106.21487,"state":"WY","location":"I80 - Arlington","city":"Arlington","priority":99}, + "KBFU": {"id":"KBFU","lat":43.93253,"lon":-105.4467,"state":"WY","location":"WY59 - Belle Fourche","city":"Belle Fourche","priority":99}, + "KBIT": {"id":"KBIT","lat":41.64599,"lon":-108.5836,"state":"WY","location":"I80/US30 - Bitter Creek","city":"Bitter Creek","priority":99}, + "KBPI": {"id":"KBPI","lat":42.57805,"lon":-110.10972,"state":"WY","location":"Big Piney - Marbleton Airport","city":"Big Piney","priority":13}, + "KBRX": {"id":"KBRX","lat":41.93066,"lon":-104.9436,"state":"WY","location":"I25/US87 - Bordeaux Interchange","city":"Bordeaux Interchange","priority":99}, + "KBVR": {"id":"KBVR","lat":42.58565,"lon":-108.28199,"state":"WY","location":"US287/WY789 - Beaver Rim","city":"Beaver Rim","priority":99}, + "KBYG": {"id":"KBYG","lat":44.38122,"lon":-106.71947,"state":"WY","location":"Buffalo - Johnson County Airport","city":"Buffalo","priority":10}, + "KCHJ": {"id":"KCHJ","lat":44.73997,"lon":-109.38088,"state":"WY","location":"WY296 - Chief Joseph","city":"Chief Joseph","priority":99}, + "KCMS": {"id":"KCMS","lat":41.54958,"lon":-109.60197,"state":"WY","location":"I80/US30 - Peru Hill","city":"Peru Hill","priority":99}, + "KCOD": {"id":"KCOD","lat":44.51667,"lon":-109.01667,"state":"WY","location":"Cody","city":"Cody","priority":99}, + "KCPR": {"id":"KCPR","lat":42.8975,"lon":-106.47306,"state":"WY","location":"Casper, Natrona County International Airport","city":"Casper","priority":1}, + "KCTD": {"id":"KCTD","lat":41.71586,"lon":-107.78256,"state":"WY","location":"I80/US30 - Continental Divide","city":"Continental Divide","priority":99}, + "KCYS": {"id":"KCYS","lat":41.15789,"lon":-104.80812,"state":"WY","location":"Cheyenne, Cheyenne Airport","city":"Cheyenne","priority":13}, + "KDGW": {"id":"KDGW","lat":42.79417,"lon":-105.38194,"state":"WY","location":"Douglas, Converse County Airport","city":"Douglas","priority":10}, + "KDHS": {"id":"KDHS","lat":44.21906,"lon":-106.10478,"state":"WY","location":"I90 - Dead Horse","city":"Dead Horse","priority":99}, + "KDRC": {"id":"KDRC","lat":42.83687,"lon":-105.86063,"state":"WY","location":"I25 - Deer Creek","city":"Deer Creek","priority":99}, + "KDUB": {"id":"KDUB","lat":43.5484,"lon":-109.6903,"state":"WY","location":"Dubois Municipal Airport","city":"Dubois","priority":9}, + "KDWX": {"id":"KDWX","lat":41.03704,"lon":-107.49976,"state":"WY","location":"Dixon Airport","city":"Dixon","priority":13}, + "KEAN": {"id":"KEAN","lat":42.05472,"lon":-104.93711,"state":"WY","location":"Phifer Airfield - Wheatland","city":"Phifer","priority":99}, + "KECS": {"id":"KECS","lat":43.8854,"lon":-104.3179,"state":"WY","location":"Mondell Field","city":"Mondell","priority":12}, + "KEHY": {"id":"KEHY","lat":41.7253,"lon":-106.4594,"state":"WY","location":"Elk Mountain AWOS","city":"Elk Mtn AWOS","priority":99}, + "KEMM": {"id":"KEMM","lat":41.82,"lon":-110.56,"state":"WY","location":"KEMMERER","city":"Kemmerer","priority":99}, + "KEVW": {"id":"KEVW","lat":41.27306,"lon":-111.03056,"state":"WY","location":"Evanston-Uinta County Airport - Burns Field","city":"Evanston","priority":10}, + "KFBR": {"id":"KFBR","lat":41.392,"lon":-110.40683,"state":"WY","location":"Fort Bridger WY","city":"Ft Bridger","priority":99}, + "KFEW": {"id":"KFEW","lat":41.13332,"lon":-104.8671899,"state":"WY","location":"Francis E Warren Air Force Base Heliport","city":"Francis E Warren","priority":14}, + "KFIR": {"id":"KFIR","lat":41.27649,"lon":-110.80066,"state":"WY","location":"I80/US189 - First Divide","city":"First Divide","priority":99}, + "KGCC": {"id":"KGCC","lat":44.33944,"lon":-105.54194,"state":"WY","location":"Gillette, Gillette-Campbell County Airport","city":"Gillette","priority":10}, + "KGEY": {"id":"KGEY","lat":44.5174,"lon":-108.0752,"state":"WY","location":"South Big Horn County Airport","city":"South Big","priority":10}, + "KGUN": {"id":"KGUN","lat":41.44368,"lon":-104.34428,"state":"WY","location":"US85 - Gun Barrel","city":"Gun Barrel","priority":99}, + "KGUR": {"id":"KGUR","lat":42.2597,"lon":-104.7283,"state":"WY","location":"Camp Guernsey","city":"Camp Guernsey","priority":99}, + "KHLD": {"id":"KHLD","lat":43.0923,"lon":-107.32198,"state":"WY","location":"US20/US26 - Hiland","city":"Hiland","priority":99}, + "KHSG": {"id":"KHSG","lat":43.7136,"lon":-108.3897,"state":"WY","location":"Hot Springs County Airport","city":"Hot Springs Co.","priority":10}, + "KIDV": {"id":"KIDV","lat":43.89864,"lon":-106.63833,"state":"WY","location":"I25/US87 - I-25 Divide","city":"I-25 Divide","priority":99}, + "KIKA": {"id":"KIKA","lat":44.29414,"lon":-104.62926,"state":"WY","location":"I90 - Inyan Kara","city":"Inyan Kara","priority":99}, + "KJAC": {"id":"KJAC","lat":43.6,"lon":-110.73333,"state":"WY","location":"Jackson, Jackson Hole Airport","city":"Jackson","priority":13}, + "KLAR": {"id":"KLAR","lat":41.3165,"lon":-105.67287,"state":"WY","location":"Laramie Regional Airport","city":"Laramie","priority":3}, + "KLND": {"id":"KLND","lat":42.81472,"lon":-108.72806,"state":"WY","location":"Lander","city":"Lander","priority":99}, + "KMTR": {"id":"KMTR","lat":44.27011,"lon":-108.87343,"state":"WY","location":"WY120 - Meeteetse Rim","city":"Meeteetse Rim","priority":99}, + "KPAT": {"id":"KPAT","lat":42.5581,"lon":-106.8453399,"state":"WY","location":"WY220 - Pathfinder","city":"Pathfinder","priority":99}, + "KPER": {"id":"KPER","lat":41.53186,"lon":-109.45995,"state":"WY","location":"I80/US30 - Green River Tunnel East","city":"Green River Tunnel East","priority":99}, + "KPNA": {"id":"KPNA","lat":42.79528,"lon":-109.80694,"state":"WY","location":"Pinedale, Ralph Wenz Field Airport","city":"Pinedale","priority":12}, + "KPOY": {"id":"KPOY","lat":44.8671999,"lon":-108.7934,"state":"WY","location":"Powell Municipal Airport","city":"Powell","priority":9}, + "KPUM": {"id":"KPUM","lat":41.05218,"lon":-105.46906,"state":"WY","location":"US287 - Pumpkin Vine","city":"Pumpkin Vine","priority":99}, + "KREC": {"id":"KREC","lat":42.61795,"lon":-108.61093,"state":"WY","location":"WY28 - Lower Red Canyon","city":"Lower Red Canyon","priority":99}, + "KRIW": {"id":"KRIW","lat":43.06219,"lon":-108.44701,"state":"WY","location":"Riverton Regional Airport","city":"Riverton","priority":3}, + "KRKS": {"id":"KRKS","lat":41.59417,"lon":-109.06528,"state":"WY","location":"Rock Springs, Rock Springs-Sweetwater County Airport","city":"Rock Springs","priority":10}, + "KRWL": {"id":"KRWL","lat":41.80648,"lon":-107.19516,"state":"WY","location":"Rawlins Municipal Airport","city":"Rawlins","priority":9}, + "KSAA": {"id":"KSAA","lat":41.44483,"lon":-106.8235,"state":"WY","location":"Saratoga WY","city":"Saratoga","priority":99}, + "KSGE": {"id":"KSGE","lat":41.82447,"lon":-110.90764,"state":"WY","location":"US30 - Sage Junction","city":"Sage Junction","priority":99}, + "KSHC": {"id":"KSHC","lat":41.94409,"lon":-110.00399,"state":"WY","location":"WY372 - Shute Creek","city":"Shute Creek","priority":99}, + "KSHR": {"id":"KSHR","lat":44.7603099,"lon":-106.97411,"state":"WY","location":"Sheridan County Airport","city":"Sheridan Co.","priority":10}, + "KSKL": {"id":"KSKL","lat":41.13753,"lon":-106.57687,"state":"WY","location":"WY230 - Skyline","city":"Skyline","priority":99}, + "KSOU": {"id":"KSOU","lat":42.47752,"lon":-108.8444,"state":"WY","location":"WY28 - South Pass","city":"South Pass","priority":99}, + "KTBX": {"id":"KTBX","lat":43.4667,"lon":-108.2333,"state":"WY","location":"Boysen","city":"Boysen","priority":99}, + "KTET": {"id":"KTET","lat":43.49873,"lon":-110.9562,"state":"WY","location":"WY22 - Teton Pass","city":"Teton Pass","priority":99}, + "KTMH": {"id":"KTMH","lat":43.12271,"lon":-106.33705,"state":"WY","location":"I25/US87 - Twenty Mile Hill","city":"Twenty Mile Hill","priority":99}, + "KTOR": {"id":"KTOR","lat":42.06134,"lon":-104.15842,"state":"WY","location":"Torrington Municipal Airport","city":"Torrington","priority":9}, + "KVDW": {"id":"KVDW","lat":41.15687,"lon":-105.40237,"state":"WY","location":"I80/US30 - Vedauwoo","city":"Vedauwoo","priority":99}, + "KWRL": {"id":"KWRL","lat":43.9658299,"lon":-107.95083,"state":"WY","location":"Worland, Worland Municipal Airport","city":"Worland","priority":9}, + "KWTR": {"id":"KWTR","lat":41.41772,"lon":-104.87502,"state":"WY","location":"I25/US87 - Whitaker","city":"Whitaker","priority":99}, + "KWYH": {"id":"KWYH","lat":41.04746,"lon":-104.8901,"state":"WY","location":"I25/US87 - Wyo Hill","city":"Wyo Hill","priority":99}, + "KACK": {"id":"KACK","lat":41.25389,"lon":-70.05972,"state":"MA","location":"Nantucket, Nantucket Memorial Airport","city":"Nantucket","priority":11}, + "KAQW": {"id":"KAQW","lat":42.69731,"lon":-73.16955,"state":"MA","location":"North Adams Harriman-and-West Airport","city":"North Adams Harriman","priority":13}, + "KBAF": {"id":"KBAF","lat":42.15972,"lon":-72.71278,"state":"MA","location":"Westfield, Barnes Municipal Airport","city":"Westfield","priority":9}, + "KBED": {"id":"KBED","lat":42.46811,"lon":-71.29463,"state":"MA","location":"Laurence G Hanscom Field Airport","city":"Laurence G Hanscom","priority":12}, + "KBOS": {"id":"KBOS","lat":42.36056,"lon":-71.01056,"state":"MA","location":"Boston, Logan International Airport","city":"Boston","priority":1}, + "KBVY": {"id":"KBVY","lat":42.58361,"lon":-70.91639,"state":"MA","location":"Beverly, Beverly Municipal Airport","city":"Beverly","priority":9}, + "KCEF": {"id":"KCEF","lat":42.2,"lon":-72.53333,"state":"MA","location":"Chicopee Falls / Westover Air Force Base","city":"Chicopee Falls","priority":14}, + "KCQX": {"id":"KCQX","lat":41.6875,"lon":-69.99333,"state":"MA","location":"Chatham, Chatham Municipal Airport","city":"Chatham","priority":9}, + "KEWB": {"id":"KEWB","lat":41.67528,"lon":-70.95694,"state":"MA","location":"New Bedford, New Bedford Regional Airport","city":"New Bedford","priority":3}, + "KFIT": {"id":"KFIT","lat":42.55194,"lon":-71.75583,"state":"MA","location":"Fitchburg, Fitchburg Municipal Airport","city":"Fitchburg","priority":9}, + "KFMH": {"id":"KFMH","lat":41.65,"lon":-70.51667,"state":"MA","location":"Otis Air National Guard Base","city":"Otis","priority":2}, + "KGHG": {"id":"KGHG","lat":42.0983,"lon":-70.6722,"state":"MA","location":"Marshfield Airport","city":"Marshfield","priority":13}, + "KHYA": {"id":"KHYA","lat":41.67194,"lon":-70.26972,"state":"MA","location":"Hyannis, Barnstable Municipal-Boardman Airport","city":"Hyannis","priority":9}, + "KLWM": {"id":"KLWM","lat":42.7126,"lon":-71.12553,"state":"MA","location":"Lawrence Municipal Airport","city":"Lawrence","priority":9}, + "KMVY": {"id":"KMVY","lat":41.39298,"lon":-70.61588,"state":"MA","location":"Marthas Vineyard Airport","city":"Marthas Vineyard","priority":13}, + "KORE": {"id":"KORE","lat":42.57,"lon":-72.28693,"state":"MA","location":"Orange Municipal Airport","city":"Orange","priority":9}, + "KORH": {"id":"KORH","lat":42.27056,"lon":-71.87306,"state":"MA","location":"Worcester, Worcester Regional Airport","city":"Worcester","priority":3}, + "KOWD": {"id":"KOWD","lat":42.19083,"lon":-71.17389,"state":"MA","location":"Norwood, Norwood Memorial Airport","city":"Norwood","priority":11}, + "KPSF": {"id":"KPSF","lat":42.42691,"lon":-73.28897,"state":"MA","location":"Pittsfield Municipal Airport","city":"Pittsfield","priority":9}, + "KPVC": {"id":"KPVC","lat":42.07436,"lon":-70.21816,"state":"MA","location":"Provincetown Municipal Airport","city":"Provincetown","priority":9}, + "KPYM": {"id":"KPYM","lat":41.90861,"lon":-70.72806,"state":"MA","location":"Plymouth, Plymouth Municipal Airport","city":"Plymouth","priority":9}, + "KTAN": {"id":"KTAN","lat":41.87556,"lon":-71.0211099,"state":"MA","location":"Taunton, Taunton Municipal Airport","city":"Taunton","priority":9}, + "KADF": {"id":"KADF","lat":34.0998,"lon":-93.0661,"state":"AR","location":"Dexter B Florence Memorial Field","city":"Dexter B Florence","priority":11}, + "KAGO": {"id":"KAGO","lat":33.2274699,"lon":-93.217,"state":"AR","location":"Ralph C Weiser Field Airport","city":"Ralph C Weiser","priority":12}, + "KARG": {"id":"KARG","lat":36.12562,"lon":-90.92148,"state":"AR","location":"Walnut Ridge Regional Airport","city":"Walnut Ridge","priority":3}, + "KASG": {"id":"KASG","lat":36.18333,"lon":-94.11667,"state":"AR","location":"Springdale Municipal","city":"Springdale","priority":9}, + "KAWM": {"id":"KAWM","lat":35.13333,"lon":-90.23333,"state":"AR","location":"West Memphis, West Memphis Municipal Airport","city":"West Memphis","priority":9}, + "KBPK": {"id":"KBPK","lat":36.37056,"lon":-92.47194,"state":"AR","location":"Baxter County Airport","city":"Baxter Co.","priority":10}, + "KBVX": {"id":"KBVX","lat":35.73333,"lon":-91.65,"state":"AR","location":"Batesville, Batesville Regional Airport","city":"Batesville","priority":3}, + "KCCA": {"id":"KCCA","lat":35.598,"lon":-92.4516,"state":"AR","location":"Clinton Memorial Airfield","city":"Clinton","priority":11}, + "KCDH": {"id":"KCDH","lat":33.61667,"lon":-92.76667,"state":"AR","location":"Camden / Harrell Field","city":"Camden","priority":12}, + "KCXW": {"id":"KCXW","lat":35.0199,"lon":-92.5551,"state":"AR","location":"Conway - Cantrell Field","city":"Conway","priority":12}, + "KDEQ": {"id":"KDEQ","lat":34.04694,"lon":-94.39944,"state":"AR","location":"De Queen, J Lynn Helms Sevier County Airport","city":"De Queen","priority":10}, + "KDRP": {"id":"KDRP","lat":35.12005,"lon":-90.8265,"state":"AR","location":"Delta Regional Airport","city":"Delta","priority":3}, + "KELD": {"id":"KELD","lat":33.22075,"lon":-92.8139999,"state":"AR","location":"South Arkansas Regional Airport","city":"South Arkansas","priority":3}, + "KFLP": {"id":"KFLP","lat":36.3,"lon":-92.58333,"state":"AR","location":"Flippin, Marion County Regional Airport","city":"Flippin","priority":10}, + "KFSM": {"id":"KFSM","lat":35.3335,"lon":-94.36524,"state":"AR","location":"Fort Smith Regional Airport","city":"Ft Smith","priority":3}, + "KFYV": {"id":"KFYV","lat":36.01028,"lon":-94.1677799,"state":"AR","location":"Fayetteville, Drake Field","city":"Fayetteville","priority":12}, + "KHKA": {"id":"KHKA","lat":35.93889,"lon":-89.8325,"state":"AR","location":"Blytheville, Blytheville Municipal Airport","city":"Blytheville","priority":9}, + "KHOT": {"id":"KHOT","lat":34.47806,"lon":-93.09611,"state":"AR","location":"Hot Springs, Memorial Field Airport","city":"Hot Springs","priority":11}, + "KHRO": {"id":"KHRO","lat":36.26167,"lon":-93.15472,"state":"AR","location":"Harrison, Boone County Airport","city":"Harrison","priority":10}, + "KJBR": {"id":"KJBR","lat":35.83722,"lon":-90.64306,"state":"AR","location":"Jonesboro, Jonesboro Municipal Airport","city":"Jonesboro","priority":9}, + "KLIT": {"id":"KLIT","lat":34.72667,"lon":-92.23611,"state":"AR","location":"Little Rock, Adams Field","city":"Little Rock","priority":12}, + "KLLQ": {"id":"KLLQ","lat":33.63833,"lon":-91.75111,"state":"AR","location":"Monticello, Monticello Municipal Airport/Ellis Field","city":"Monticello","priority":9}, + "KLRF": {"id":"KLRF","lat":34.91667,"lon":-92.15,"state":"AR","location":"Little Rock Air Force Base","city":"Little Rock AFB","priority":14}, + "KMEZ": {"id":"KMEZ","lat":34.54528,"lon":-94.2025,"state":"AR","location":"Mena, Mena Intermountain Municipal Airport","city":"Mena","priority":9}, + "KMWT": {"id":"KMWT","lat":34.55,"lon":-93.58333,"state":"AR","location":"Mount Ida","city":"Mt Ida","priority":99}, + "KORK": {"id":"KORK","lat":34.83314,"lon":-92.25414,"state":"AR","location":"North Little Rock Municipal Airport","city":"North Little Rock","priority":9}, + "KPBF": {"id":"KPBF","lat":34.175,"lon":-91.93472,"state":"AR","location":"Pine Bluff, Grider Field Airport","city":"Pine Bluff","priority":12}, + "KROG": {"id":"KROG","lat":36.36667,"lon":-94.1,"state":"AR","location":"Rogers - Rogers Executive Airport - Carter Field","city":"Rogers","priority":5}, + "KRUE": {"id":"KRUE","lat":35.25737,"lon":-93.0949399,"state":"AR","location":"Russelville Municipal Airport","city":"Russelville","priority":9}, + "KSGT": {"id":"KSGT","lat":34.6,"lon":-91.56667,"state":"AR","location":"Stuttgart, Stuttgart Municipal Airport","city":"Stuttgart","priority":9}, + "KSLG": {"id":"KSLG","lat":36.2,"lon":-94.48333,"state":"AR","location":"Siloam Springs, Smith Field Airport","city":"Siloam Springs","priority":12}, + "KSRC": {"id":"KSRC","lat":35.21349,"lon":-91.7392799,"state":"AR","location":"Searcy Municipal Airport","city":"Searcy","priority":9}, + "KSUZ": {"id":"KSUZ","lat":34.59039,"lon":-92.47944,"state":"AR","location":"Saline County Regional Airport","city":"Saline Co.","priority":10}, + "KTXK": {"id":"KTXK","lat":33.45611,"lon":-93.9875,"state":"AR","location":"Texarkana, Texarkana Regional-Webb Field","city":"Texarkana","priority":3}, + "KVBT": {"id":"KVBT","lat":36.35,"lon":-94.2166699,"state":"AR","location":"Bentonville, Bentonville Municipal Airport/Louise M Thaden Field","city":"Bentonville","priority":9}, + "KXNA": {"id":"KXNA","lat":36.28977,"lon":-94.3114499,"state":"AR","location":"Northwest Arkansas Regional Airport","city":"Northwest Arkansas","priority":3}, + "KACQ": {"id":"KACQ","lat":44.07024,"lon":-93.55342,"state":"MN","location":"Waseca Municipal Airport","city":"Waseca","priority":9}, + "KADC": {"id":"KADC","lat":46.45022,"lon":-95.21353,"state":"MN","location":"Wadena Municipal Airport","city":"Wadena","priority":9}, + "KAEL": {"id":"KAEL","lat":43.68333,"lon":-93.36667,"state":"MN","location":"Albert Lea, Albert Lea Municipal Airport","city":"Albert Lea","priority":9}, + "KAIT": {"id":"KAIT","lat":46.54899,"lon":-93.67573,"state":"MN","location":"Aitkin Municipal Airport - Steve Kurtz Field","city":"Aitkin","priority":9}, + "KANE": {"id":"KANE","lat":45.14258,"lon":-93.21272,"state":"MN","location":"Minneapolis / Blaine","city":"Blaine","priority":99}, + "KAQP": {"id":"KAQP","lat":45.22488,"lon":-96.00412,"state":"MN","location":"Appleton Municipal Airport","city":"Appleton","priority":9}, + "KAUM": {"id":"KAUM","lat":43.66667,"lon":-92.93333,"state":"MN","location":"Austin Municipal","city":"Austin","priority":9}, + "KAXN": {"id":"KAXN","lat":45.8686099,"lon":-95.39417,"state":"MN","location":"Alexandria, Chandler Field","city":"Alexandria","priority":12}, + "KBBB": {"id":"KBBB","lat":45.3309799,"lon":-95.64692,"state":"MN","location":"Benson Municipal Airport","city":"Benson","priority":9}, + "KBDE": {"id":"KBDE","lat":48.72605,"lon":-94.61215,"state":"MN","location":"Baudette International Airport","city":"Baudette","priority":1}, + "KBDH": {"id":"KBDH","lat":45.11113,"lon":-95.1258299,"state":"MN","location":"Willmar Municipal Airport - John L. Rice Field","city":"Willmar","priority":9}, + "KBJI": {"id":"KBJI","lat":47.50762,"lon":-94.92783,"state":"MN","location":"Bemidji","city":"Bemidji","priority":99}, + "KBRD": {"id":"KBRD","lat":46.40205,"lon":-94.12734,"state":"MN","location":"Brainerd - Crow Wing County Airport","city":"Brainerd","priority":10}, + "KCBG": {"id":"KCBG","lat":45.56275,"lon":-93.26436,"state":"MN","location":"Cambridge Municipal Airport","city":"Cambridge","priority":9}, + "KCDD": {"id":"KCDD","lat":48.26014,"lon":-92.47485,"state":"MN","location":"Crane Lake - Scotts Seaplane Base","city":"Crane Lake","priority":99}, + "KCFE": {"id":"KCFE","lat":45.15889,"lon":-93.84306,"state":"MN","location":"Buffalo, Buffalo Municipal Airport","city":"Buffalo","priority":9}, + "KCKC": {"id":"KCKC","lat":47.83665,"lon":-90.3864399,"state":"MN","location":"Grand Marais/Cook County Airport","city":"Grand Marais","priority":10}, + "KCKN": {"id":"KCKN","lat":47.84042,"lon":-96.6200999,"state":"MN","location":"Crookston Municipal Field","city":"Crookston","priority":9}, + "KCNB": {"id":"KCNB","lat":44.7295,"lon":-96.266,"state":"MN","location":"Canby Airfield","city":"Canby","priority":99}, + "KCOQ": {"id":"KCOQ","lat":46.69869,"lon":-92.5034,"state":"MN","location":"Cloquet Carlton County Airport","city":"Cloquet","priority":10}, + "KCQM": {"id":"KCQM","lat":47.81997,"lon":-92.68169,"state":"MN","location":"Cook Municipal Airport","city":"Cook","priority":9}, + "KDLH": {"id":"KDLH","lat":46.84347,"lon":-92.1866,"state":"MN","location":"Duluth International Airport","city":"Duluth","priority":1}, + "KDTL": {"id":"KDTL","lat":46.8285399,"lon":-95.88567,"state":"MN","location":"Detroit Lakes Airport-Wething Field","city":"Detroit Lakes","priority":12}, + "KDVP": {"id":"KDVP","lat":43.99055,"lon":-95.78102,"state":"MN","location":"Slayton Municipal Airport","city":"Slayton","priority":9}, + "KDXX": {"id":"KDXX","lat":44.9839399,"lon":-96.1788399,"state":"MN","location":"Madison, Madison-Lac Qui Parle County Airport","city":"Madison","priority":10}, + "KDYT": {"id":"KDYT","lat":46.72452,"lon":-92.0444799,"state":"MN","location":"Duluth - Sky Harbor Airport","city":"Sky Harbor","priority":13}, + "KBIX": {"id":"KBIX","lat":30.41667,"lon":-88.91667,"state":"MS","location":"Keesler Air Force Base / Biloxi","city":"Biloxi","priority":14}, + "KCBM": {"id":"KCBM","lat":33.65,"lon":-88.45,"state":"MS","location":"Columbus Air Force Base","city":"Columbus AFB","priority":14}, + "KCKM": {"id":"KCKM","lat":34.2997,"lon":-90.5123,"state":"MS","location":"Fletcher Field, Clarksdale","city":"Clarksdale","priority":12}, + "KCRX": {"id":"KCRX","lat":34.915,"lon":-88.6035,"state":"MS","location":"Corinth","city":"Corinth","priority":99}, + "KGLH": {"id":"KGLH","lat":33.48278,"lon":-90.98556,"state":"MS","location":"Greenville, Mid Delta Regional Airport","city":"Greenville","priority":3}, + "KGPT": {"id":"KGPT","lat":30.41194,"lon":-89.08083,"state":"MS","location":"Gulfport - Gulfport-Biloxi International Airport","city":"Gulfport","priority":1}, + "KGTR": {"id":"KGTR","lat":33.45,"lon":-88.58333,"state":"MS","location":"Columbus/West Point/Starkville, Golden Triangle Regional Airport","city":"Columbus","priority":3}, + "KGWO": {"id":"KGWO","lat":33.4925,"lon":-90.0836099,"state":"MS","location":"Greenwood, Greenwood-LeFlore Airport","city":"Greenwood","priority":13}, + "KHBG": {"id":"KHBG","lat":31.26945,"lon":-89.25613,"state":"MS","location":"Hattiesburg, Bobby L Chain Municipal Airport","city":"Bobby L Chain","priority":9}, + "KHEZ": {"id":"KHEZ","lat":31.61593,"lon":-91.29724,"state":"MS","location":"Natchez, Hardy-Anders Field Natchez-Adams County Airport","city":"Natchez","priority":10}, + "KHKS": {"id":"KHKS","lat":32.33472,"lon":-90.2225,"state":"MS","location":"Jackson, Hawkins Field Airport","city":"Hawkins","priority":12}, + "KHSA": {"id":"KHSA","lat":30.36778,"lon":-89.45472,"state":"MS","location":"Bay St. Louis, Stennis International Airport","city":"Bay St Louis","priority":1}, + "KIKT": {"id":"KIKT","lat":28.5208,"lon":-88.2889,"state":"MS","location":"Nakika Subsea Development Platform","city":"Nakika SDP","priority":99}, + "KJAN": {"id":"KJAN","lat":32.3197199,"lon":-90.0775,"state":"MS","location":"Jackson, Jackson International Airport","city":"Jackson","priority":1}, + "KJVW": {"id":"KJVW","lat":32.30447,"lon":-90.41053,"state":"MS","location":"JB Williams Airport","city":"JB Williams","priority":13}, + "KLMS": {"id":"KLMS","lat":33.14599,"lon":-89.06245,"state":"MS","location":"Louisville/Winston County Airport","city":"Louisville","priority":10}, + "KLUL": {"id":"KLUL","lat":31.67,"lon":-89.17,"state":"MS","location":"LAUREL/NOBLE FIELD","city":"Laurel","priority":12}, + "KMBO": {"id":"KMBO","lat":32.4384,"lon":-90.1014,"state":"MS","location":"Madison Bruce Campbell Field Airport","city":"Madison","priority":12}, + "KMCB": {"id":"KMCB","lat":31.17833,"lon":-90.47194,"state":"MS","location":"McComb, McComb / Pike County / John E Lewis Field Airport","city":"McComb","priority":10}, + "KMEI": {"id":"KMEI","lat":32.33806,"lon":-88.74778,"state":"MS","location":"Meridian, Key Field","city":"Meridian","priority":12}, + "KMJD": {"id":"KMJD","lat":30.48747,"lon":-89.65119,"state":"MS","location":"Picayune Municipal Airport","city":"Picayune","priority":9}, + "KMPE": {"id":"KMPE","lat":32.79921,"lon":-89.12599,"state":"MS","location":"Philadelphia Municipal Airport","city":"Philadelphia","priority":9}, + "KNJW": {"id":"KNJW","lat":32.79611,"lon":-88.83167,"state":"MS","location":"Meridian, Joe Williams Naval Outlying Field","city":"Joe Williams NOF","priority":14}, + "KNMM": {"id":"KNMM","lat":32.55194,"lon":-88.55528,"state":"MS","location":"Meridian, Meridian Naval Air Station - McCain Field","city":"Meridian NAS","priority":14}, + "KOLV": {"id":"KOLV","lat":34.97889,"lon":-89.78694,"state":"MS","location":"Olive Branch, Olive Branch Airport","city":"Olive Branch","priority":13}, + "KPIB": {"id":"KPIB","lat":31.46667,"lon":-89.33333,"state":"MS","location":"Hattiesburg/Laurel, Hattiesburg-Laurel Regional Airport","city":"Hattiesburg","priority":3}, + "KPMU": {"id":"KPMU","lat":34.3635,"lon":-89.8929,"state":"MS","location":"Batesville Panola County","city":"Batesville","priority":10}, + "KPQL": {"id":"KPQL","lat":30.46305,"lon":-88.53155,"state":"MS","location":"Moss Point - Trent Lott International Airport","city":"Moss Point","priority":1}, + "KRNV": {"id":"KRNV","lat":33.7611,"lon":-90.7579,"state":"MS","location":"Cleveland Municipal Airport","city":"Cleveland","priority":9}, + "KSTF": {"id":"KSTF","lat":33.4331,"lon":-88.8486,"state":"MS","location":"George M Bryan Airport, Starkville","city":"Starkville","priority":13}, + "KTUP": {"id":"KTUP","lat":34.26806,"lon":-88.77,"state":"MS","location":"Tupelo, Tupelo Regional Airport","city":"Tupelo","priority":3}, + "KUOX": {"id":"KUOX","lat":34.38444,"lon":-89.53556,"state":"MS","location":"Oxford, University-Oxford Airport","city":"Oxford","priority":13}, + "KUTA": {"id":"KUTA","lat":34.68083,"lon":-90.34639,"state":"MS","location":"Tunica, Tunica Municipal Airport","city":"Tunica","priority":9}, + "KVKS": {"id":"KVKS","lat":32.23333,"lon":-90.93333,"state":"MS","location":"Vicksburg Municipal","city":"Vicksburg","priority":9}, + "KBDL": {"id":"KBDL","lat":41.93806,"lon":-72.6825,"state":"CT","location":"Windsor Locks, Bradley International Airport","city":"Windsor Locks","priority":1}, + "KBDR": {"id":"KBDR","lat":41.16421,"lon":-73.12663,"state":"CT","location":"Bridgeport, Sikorsky Memorial Airport","city":"Bridgeport","priority":11}, + "KDXR": {"id":"KDXR","lat":41.37167,"lon":-73.48444,"state":"CT","location":"Danbury, Danbury Municipal Airport","city":"Danbury","priority":9}, + "KGON": {"id":"KGON","lat":41.3275,"lon":-72.04944,"state":"CT","location":"Groton / New London, Groton / New London Airport","city":"Groton","priority":13}, + "KHFD": {"id":"KHFD","lat":41.735,"lon":-72.65167,"state":"CT","location":"Hartford, Hartford-Brainard Airport","city":"Hartford","priority":13}, + "KHVN": {"id":"KHVN","lat":41.26389,"lon":-72.88722,"state":"CT","location":"New Haven, Tweed-New Haven Airport","city":"New Haven","priority":13}, + "KIJD": {"id":"KIJD","lat":41.74194,"lon":-72.18361,"state":"CT","location":"Willimantic, Windham Airport","city":"Willimantic","priority":13}, + "KLZD": {"id":"KLZD","lat":41.8197,"lon":-71.90096,"state":"CT","location":"DANIELSON","city":"Danielson","priority":99}, + "KMMK": {"id":"KMMK","lat":41.50972,"lon":-72.82778,"state":"CT","location":"Meriden, Meriden Markham Municipal Airport","city":"Meriden","priority":9}, + "KOXC": {"id":"KOXC","lat":41.48333,"lon":-73.13333,"state":"CT","location":"Oxford, Waterbury-Oxford Airport","city":"Oxford","priority":13}, + "KSNC": {"id":"KSNC","lat":41.38389,"lon":-72.50583,"state":"CT","location":"Chester, Chester Airport","city":"Chester","priority":13}, + "KAFK": {"id":"KAFK","lat":40.6,"lon":-95.85,"state":"NE","location":"Nebraska City, Nebraska City Municipal Airport","city":"Nebraska City","priority":9}, + "KAHQ": {"id":"KAHQ","lat":41.2406,"lon":-96.5946,"state":"NE","location":"Wahoo","city":"Wahoo","priority":99}, + "KAIA": {"id":"KAIA","lat":42.05722,"lon":-102.8,"state":"NE","location":"Alliance, Alliance Municipal Airport","city":"Alliance","priority":9}, + "KANW": {"id":"KANW","lat":42.57484,"lon":-99.99832,"state":"NE","location":"Ainsworth Regional Airport","city":"Ainsworth","priority":3}, + "KAUH": {"id":"KAUH","lat":40.89389,"lon":-97.99444,"state":"NE","location":"Aurora, Aurora Municipal Airport","city":"Aurora","priority":9}, + "KBBW": {"id":"KBBW","lat":41.43333,"lon":-99.65,"state":"NE","location":"Broken Bow, Broken Bow Municipal Airport","city":"Broken Bow","priority":9}, + "KBFF": {"id":"KBFF","lat":41.86694,"lon":-103.58583,"state":"NE","location":"Scottsbluff, Heilig Field","city":"Scottsbluff","priority":12}, + "KBIE": {"id":"KBIE","lat":40.3,"lon":-96.75,"state":"NE","location":"Beatrice Municipal","city":"Beatrice","priority":9}, + "KBTA": {"id":"KBTA","lat":41.4148,"lon":-96.109,"state":"NE","location":"Blair Municipal Airport","city":"Blair","priority":9}, + "KBVN": {"id":"KBVN","lat":41.73016,"lon":-98.05453,"state":"NE","location":"Albion Municipal Airport","city":"Albion","priority":9}, + "KCDR": {"id":"KCDR","lat":42.8375,"lon":-103.09528,"state":"NE","location":"Chadron, Chadron Municipal Airport","city":"Chadron","priority":9}, + "KCSB": {"id":"KCSB","lat":40.3065799,"lon":-100.16207,"state":"NE","location":"Cambridge Municipal Airport","city":"Cambridge","priority":9}, + "KEAR": {"id":"KEAR","lat":40.73333,"lon":-99,"state":"NE","location":"Kearney, Kearney Municipal Airport","city":"Kearney","priority":9}, + "KFET": {"id":"KFET","lat":41.45,"lon":-96.51667,"state":"NE","location":"Fremont Municipal Airport","city":"Fremont","priority":9}, + "KFNB": {"id":"KFNB","lat":40.07889,"lon":-95.5919399,"state":"NE","location":"Falls City, Brenner Field Airport","city":"Falls City","priority":12}, + "KGGF": {"id":"KGGF","lat":40.87066,"lon":-101.73388,"state":"NE","location":"Grant Municipal Airport","city":"Grant","priority":9}, + "KGRI": {"id":"KGRI","lat":40.9583299,"lon":-98.3125,"state":"NE","location":"Grand Island, Central Nebraska Regional Airport","city":"Grand Is.","priority":3}, + "KGRN": {"id":"KGRN","lat":42.8,"lon":-102.16667,"state":"NE","location":"Gordon Municipal","city":"Gordon","priority":9}, + "KHDE": {"id":"KHDE","lat":40.45,"lon":-99.33333,"state":"NE","location":"Brewster Field Airport","city":"Brewster","priority":12}, + "KHJH": {"id":"KHJH","lat":40.15222,"lon":-97.58694,"state":"NE","location":"Hebron, Hebron Municipal Airport","city":"Hebron","priority":9}, + "KHSI": {"id":"KHSI","lat":40.60056,"lon":-98.42583,"state":"NE","location":"Hastings, Hastings Municipal Airport","city":"Hastings","priority":9}, + "KIBM": {"id":"KIBM","lat":41.18333,"lon":-103.66667,"state":"NE","location":"Kimball, Kimball Municipal Airport/Robert E Arraj Field","city":"Kimball","priority":9}, + "KIML": {"id":"KIML","lat":40.51667,"lon":-101.61667,"state":"NE","location":"Imperial, Imperial Municipal Airport","city":"Imperial","priority":9}, + "KJYR": {"id":"KJYR","lat":40.89667,"lon":-97.62278,"state":"NE","location":"York, York Municipal Airport","city":"York","priority":9}, + "KLBF": {"id":"KLBF","lat":41.12194,"lon":-100.66833,"state":"NE","location":"North Platte, North Platte Regional Airport","city":"North Platte","priority":3}, + "KLCG": {"id":"KLCG","lat":42.24167,"lon":-96.98139,"state":"NE","location":"Wayne, Wayne Municipal Airport","city":"Wayne","priority":9}, + "KLNK": {"id":"KLNK","lat":40.83111,"lon":-96.7644399,"state":"NE","location":"Lincoln, Lincoln Municipal Airport","city":"Lincoln","priority":9}, + "KLXN": {"id":"KLXN","lat":40.79111,"lon":-99.77722,"state":"NE","location":"Lexington, Jim Kelly Field Airport","city":"Lexington","priority":12}, + "KMCK": {"id":"KMCK","lat":40.20306,"lon":-100.58833,"state":"NE","location":"McCook, McCook Municipal Airport","city":"McCook","priority":9}, + "KMLE": {"id":"KMLE","lat":41.19583,"lon":-96.1122199,"state":"NE","location":"Omaha, Millard Airport","city":"Omaha","priority":13}, + "KODX": {"id":"KODX","lat":41.62417,"lon":-98.9525,"state":"NE","location":"Ord, Evelyn Sharp Field Airport","city":"Ord","priority":12}, + "KOFF": {"id":"KOFF","lat":41.11667,"lon":-95.9,"state":"NE","location":"Omaha / Offutt Air Force Base","city":"Offutt AFB","priority":14}, + "KOFK": {"id":"KOFK","lat":41.9805599,"lon":-97.43694,"state":"NE","location":"Norfolk, Stefan Memorial Airport","city":"Norfolk","priority":11}, + "KOGA": {"id":"KOGA","lat":41.11972,"lon":-101.76889,"state":"NE","location":"Ogallala, Searle Field Airport","city":"Ogallala","priority":12}, + "KOLU": {"id":"KOLU","lat":41.45,"lon":-97.33333,"state":"NE","location":"Columbus, Columbus Municipal Airport","city":"Columbus","priority":9}, + "KOMA": {"id":"KOMA","lat":41.3119,"lon":-95.90185,"state":"NE","location":"Omaha - Eppley Airfield","city":"Eppley","priority":99}, + "KONL": {"id":"KONL","lat":42.46667,"lon":-98.68333,"state":"NE","location":"O'Neill / Baker Field","city":"O'Neill","priority":12}, + "KPMV": {"id":"KPMV","lat":40.95,"lon":-95.9177799,"state":"NE","location":"Plattsmouth, Plattsmouth Municipal Airport","city":"Plattsmouth","priority":9}, + "KSNY": {"id":"KSNY","lat":41.09944,"lon":-102.98556,"state":"NE","location":"Sidney, Sidney Municipal Airport","city":"Sidney","priority":9}, + "KTIF": {"id":"KTIF","lat":41.96194,"lon":-100.56889,"state":"NE","location":"Thedford, Thomas County Airport","city":"Thedford","priority":10}, + "KTQE": {"id":"KTQE","lat":41.76694,"lon":-96.17778,"state":"NE","location":"Tekamah, Tekamah Municipal Airport","city":"Tekamah","priority":9}, + "KVTN": {"id":"KVTN","lat":42.85861,"lon":-100.55139,"state":"NE","location":"Valentine, Miller Field","city":"Valentine","priority":12}, + "KBTV": {"id":"KBTV","lat":44.46806,"lon":-73.15028,"state":"VT","location":"Burlington, Burlington International Airport","city":"Burlington","priority":1}, + "KCDA": {"id":"KCDA","lat":44.5691142,"lon":-72.0179789,"state":"VT","location":"Caledonia County Airport","city":"Caledonia Co.","priority":10}, + "KDDH": {"id":"KDDH","lat":42.89355,"lon":-73.2486,"state":"VT","location":"Bennington Morse State Airport","city":"Bennington Morse","priority":6}, + "KEFK": {"id":"KEFK","lat":44.88846,"lon":-72.23593,"state":"VT","location":"Northeast Kingdom International Airport","city":"Northeast Kingdom","priority":1}, + "KFSO": {"id":"KFSO","lat":44.9402807,"lon":-73.09746,"state":"VT","location":"Franklin County State Airport","city":"Franklin Co.","priority":10}, + "KMPV": {"id":"KMPV","lat":44.20472,"lon":-72.56611,"state":"VT","location":"Barre / Montpelier, Knapp State Airport","city":"Barre","priority":6}, + "KMVL": {"id":"KMVL","lat":44.53589,"lon":-72.6162499,"state":"VT","location":"Morrisville-Stowe State Airport","city":"Morrisville","priority":6}, + "KRUT": {"id":"KRUT","lat":43.53333,"lon":-72.95,"state":"VT","location":"Rutland-Southern Vermont Regional Airport","city":"Rutland","priority":3}, + "KVSF": {"id":"KVSF","lat":43.3425,"lon":-72.52167,"state":"VT","location":"Springfield, Hartness State Springfield Airport","city":"Springfield","priority":6}, + "KAIZ": {"id":"KAIZ","lat":38.1,"lon":-92.55,"state":"MO","location":"Kaiser Lake Ozark, Lee C Fine Memorial Airport","city":"Kaiser Lake Ozark","priority":11}, + "KBBG": {"id":"KBBG","lat":36.5321,"lon":-93.2005,"state":"MO","location":"Branson","city":"Branson","priority":99}, + "KCDJ": {"id":"KCDJ","lat":39.81667,"lon":-93.58333,"state":"MO","location":"Chillicothe, Chillicothe Agri-Science Center","city":"Chillicothe","priority":99}, + "KCGI": {"id":"KCGI","lat":37.22556,"lon":-89.5783299,"state":"MO","location":"Cape Girardeau, Cape Girardeau Regional Airport","city":"Cape Girardeau","priority":3}, + "KCOU": {"id":"KCOU","lat":38.81694,"lon":-92.21833,"state":"MO","location":"Columbia, Columbia Regional Airport","city":"Columbia","priority":3}, + "KDMO": {"id":"KDMO","lat":38.71222,"lon":-93.17444,"state":"MO","location":"Sedalia, Sedalia Memorial Airport","city":"Sedalia","priority":11}, + "KEOS": {"id":"KEOS","lat":36.8108,"lon":-94.39169,"state":"MO","location":"NEOSHOAIRPORT","city":"Neosho","priority":99}, + "KEVU": {"id":"KEVU","lat":40.3525,"lon":-94.915,"state":"MO","location":"Maryville Northwest Missouri Regional Airport","city":"Maryville Northwest Missouri","priority":3}, + "KEZZ": {"id":"KEZZ","lat":39.7275599,"lon":-94.27639,"state":"MO","location":"Cameron Memorial Airport","city":"Cameron","priority":11}, + "KFAM": {"id":"KFAM","lat":37.76667,"lon":-90.43333,"state":"MO","location":"Farmington Airport","city":"Farmington","priority":13}, + "KFWB": {"id":"KFWB","lat":36.6985,"lon":-93.4021999,"state":"MO","location":"Branson West Muni - Emerson Field","city":"Branson West Muni","priority":12}, + "KGLY": {"id":"KGLY","lat":38.3566,"lon":-93.6842,"state":"MO","location":"Clinton, MO","city":"Clinton","priority":99}, + "KGPH": {"id":"KGPH","lat":39.3325,"lon":-94.3096,"state":"MO","location":"Mosby Midwest National Air Center Airport","city":"Mosby Midwest","priority":2}, + "KHAE": {"id":"KHAE","lat":39.7252,"lon":-91.4439,"state":"MO","location":"Hannibal Regional Airport","city":"Hannibal","priority":3}, + "KHFJ": {"id":"KHFJ","lat":36.9062,"lon":-94.0128,"state":"MO","location":"Monett","city":"Monett","priority":99}, + "KIRK": {"id":"KIRK","lat":40.09722,"lon":-92.54333,"state":"MO","location":"Kirksville, Kirksville Regional Airport","city":"Kirksville","priority":3}, + "KJEF": {"id":"KJEF","lat":38.59444,"lon":-92.15583,"state":"MO","location":"Jefferson City, Jefferson City Memorial Airport","city":"Jefferson City","priority":11}, + "KJLN": {"id":"KJLN","lat":37.15611,"lon":-94.5005599,"state":"MO","location":"Joplin, Joplin Regional Airport","city":"Joplin","priority":3}, + "KLBO": {"id":"KLBO","lat":37.64833,"lon":-92.6525,"state":"MO","location":"LEBANON","city":"Lebanon","priority":99}, + "KAAS": {"id":"KAAS","lat":37.35828,"lon":-85.30942,"state":"KY","location":"Taylor County Airport","city":"Taylor Co.","priority":10}, + "KBRY": {"id":"KBRY","lat":37.81433,"lon":-85.49964,"state":"KY","location":"Samuels Field Airport","city":"Samuels","priority":12}, + "KBWG": {"id":"KBWG","lat":36.96444,"lon":-86.41944,"state":"KY","location":"Bowling Green, Bowling Green-Warren County Regional Airport","city":"Bowling Green","priority":10}, + "KBYL": {"id":"KBYL","lat":36.7954099,"lon":-84.2012699,"state":"KY","location":"Williamsburg-Whitley County Airport","city":"Williamsburg","priority":10}, + "KCEY": {"id":"KCEY","lat":36.6646,"lon":-88.3728,"state":"KY","location":"Murray Kyle Oakley Field, KY","city":"Murray","priority":12}, + "KCPF": {"id":"KCPF","lat":37.38736,"lon":-83.26161,"state":"KY","location":"Wendell H Ford Airport","city":"Wendell H Ford","priority":13}, + "KCVG": {"id":"KCVG","lat":39.04456,"lon":-84.67229,"state":"KY","location":"Cincinnati/Northern Kentucky International Airport","city":"Cincinnati","priority":1}, + "KDVK": {"id":"KDVK","lat":37.5775751,"lon":-84.7694978,"state":"KY","location":"Stuart Powell Field Airport","city":"Stuart Powell","priority":12}, + "KDWU": {"id":"KDWU","lat":38.5545,"lon":-82.738,"state":"KY","location":"Ashland Regional Airport","city":"Ashland","priority":3}, + "KEHR": {"id":"KEHR","lat":37.81667,"lon":-87.68333,"state":"KY","location":"Henderson City","city":"Henderson City","priority":99}, + "KEKQ": {"id":"KEKQ","lat":36.85528,"lon":-84.85611,"state":"KY","location":"Monticello, Wayne County Airport","city":"Monticello","priority":10}, + "KEKX": {"id":"KEKX","lat":37.686,"lon":-85.925,"state":"KY","location":"Elizabethtown Addington Field Airport","city":"Elizabethtown","priority":12}, + "KFFT": {"id":"KFFT","lat":38.18472,"lon":-84.90333,"state":"KY","location":"Frankfort, Capital City Airport","city":"Frankfort","priority":13}, + "KFGX": {"id":"KFGX","lat":38.5418,"lon":-83.7434,"state":"KY","location":"Flemingsburg Fleming-Mason Airport","city":"Flemingsburg Fleming","priority":13}, + "KFTK": {"id":"KFTK","lat":37.9,"lon":-85.9666699,"state":"KY","location":"Fort Knox","city":"Ft Knox","priority":99}, + "KGDA": {"id":"KGDA","lat":37.3333,"lon":-88.1,"state":"KY","location":"MARION","city":"Marion","priority":99}, + "KGLW": {"id":"KGLW","lat":37.03167,"lon":-85.95361,"state":"KY","location":"Glasgow, Glasgow Municipal Airport","city":"Glasgow","priority":9}, + "KHOP": {"id":"KHOP","lat":36.66667,"lon":-87.5,"state":"KY","location":"Fort Campbell U. S. Army Airfield","city":"Ft Campbell","priority":14}, + "KHVC": {"id":"KHVC","lat":36.8569699,"lon":-87.45508,"state":"KY","location":"Hopkinsville-Christian County Airport","city":"Hopkinsville","priority":10}, + "KIOB": {"id":"KIOB","lat":38.0575,"lon":-83.9829,"state":"KY","location":"Mount Sterling-Montgomery County Airport","city":"Mt Sterling","priority":10}, + "KJKL": {"id":"KJKL","lat":37.5913899,"lon":-83.31444,"state":"KY","location":"Jackson, Carroll Airport","city":"Jackson","priority":13}, + "KLEX": {"id":"KLEX","lat":38.0339,"lon":-84.6114599,"state":"KY","location":"Lexington Blue Grass Airport","city":"Lexington Blue Grass","priority":13}, + "KLOU": {"id":"KLOU","lat":38.22778,"lon":-85.66361,"state":"KY","location":"Louisville, Bowman Field Airport","city":"Bowman","priority":12}, + "KLOZ": {"id":"KLOZ","lat":37.08944,"lon":-84.06861,"state":"KY","location":"London, London-Corbin Airport-Magee Field","city":"London","priority":12}, + "KOWB": {"id":"KOWB","lat":37.74,"lon":-87.16667,"state":"KY","location":"Owensboro, Owensboro-Daviess County Airport","city":"Owensboro","priority":10}, + "KPAH": {"id":"KPAH","lat":37.05639,"lon":-88.77389,"state":"KY","location":"Paducah, Barkley Regional Airport","city":"Paducah","priority":3}, + "KPBX": {"id":"KPBX","lat":37.5587,"lon":-82.5674,"state":"KY","location":"Pikeville Pike County Airport and Hatcher Field","city":"Pikeville","priority":10}, + "KRGA": {"id":"KRGA","lat":37.6308475,"lon":-84.3323372,"state":"KY","location":"Central Kentucky Regional Airport","city":"Central Kentucky","priority":3}, + "KSDF": {"id":"KSDF","lat":38.17406,"lon":-85.7365,"state":"KY","location":"Louisville Muhammad Ali International Airport","city":"Louisville","priority":1}, + "KSJS": {"id":"KSJS","lat":37.751,"lon":-82.6367,"state":"KY","location":"Big Sandy Regional Airport","city":"Big Sandy","priority":3}, + "KSME": {"id":"KSME","lat":37.05417,"lon":-84.615,"state":"KY","location":"Somerset, Somerset-Pulaski County - J.T. Wilson Field Airport","city":"Somerset","priority":10}, + "KSYM": {"id":"KSYM","lat":38.215,"lon":-83.5874,"state":"KY","location":"Clyde A. Thomas Regional Airport","city":"Clyde A Thomas","priority":3}, + "KTWT": {"id":"KTWT","lat":37.54083,"lon":-87.9516699,"state":"KY","location":"Sturgis, Sturgis Municipal Airport","city":"Sturgis","priority":9}, + "KACB": {"id":"KACB","lat":44.98833,"lon":-85.19833,"state":"MI","location":"Bellaire, Antrim County Airport","city":"Bellaire","priority":10}, + "KADG": {"id":"KADG","lat":41.86778,"lon":-84.07944,"state":"MI","location":"Adrian, Lenawee County Airport","city":"Adrian","priority":10}, + "KAMN": {"id":"KAMN","lat":43.32194,"lon":-84.68778,"state":"MI","location":"Alma, Gratiot Community Airport","city":"Alma","priority":13}, + "KANJ": {"id":"KANJ","lat":46.4794399,"lon":-84.35722,"state":"MI","location":"Sault Ste. Marie","city":"Sault Ste Marie","priority":99}, + "KAPN": {"id":"KAPN","lat":45.07167,"lon":-83.56444,"state":"MI","location":"Alpena, Alpena County Regional Airport","city":"Alpena","priority":10}, + "KARB": {"id":"KARB","lat":42.22389,"lon":-83.74,"state":"MI","location":"Ann Arbor, Ann Arbor Municipal Airport","city":"Ann Arbor","priority":9}, + "KAZO": {"id":"KAZO","lat":42.2283,"lon":-85.54595,"state":"MI","location":"Kalamazoo/Battle Creek International Airport","city":"Kalamazoo","priority":1}, + "KBAX": {"id":"KBAX","lat":43.77741,"lon":-82.98271,"state":"MI","location":"Huron County Memorial Airport","city":"Huron Co.","priority":10}, + "KBEH": {"id":"KBEH","lat":42.12896,"lon":-86.41515,"state":"MI","location":"Southwest Michigan Regional Airport","city":"Southwest Michigan","priority":3}, + "KBFA": {"id":"KBFA","lat":45.16584,"lon":-84.92411,"state":"MI","location":"Boyne Mountain Airport","city":"Boyne Mtn","priority":13}, + "KBIV": {"id":"KBIV","lat":42.74611,"lon":-86.09667,"state":"MI","location":"Holland - West Michigan Regional Airport","city":"Holland","priority":3}, + "KBTL": {"id":"KBTL","lat":42.31197,"lon":-85.24144,"state":"MI","location":"Battle Creek Executive Airport","city":"Battle Creek","priority":5}, + "KCAD": {"id":"KCAD","lat":44.27847,"lon":-85.4206899,"state":"MI","location":"Wexford County Airport","city":"Wexford Co.","priority":10}, + "KCFS": {"id":"KCFS","lat":43.45861,"lon":-83.44528,"state":"MI","location":"Caro, Tuscola Area Airport","city":"Caro","priority":13}, + "KCIU": {"id":"KCIU","lat":46.25,"lon":-84.4666699,"state":"MI","location":"Sault Ste Marie, Chippewa County International Airport","city":"Sault Ste Marie","priority":1}, + "KCMX": {"id":"KCMX","lat":47.16597,"lon":-88.48072,"state":"MI","location":"Houghton County Memorial Airport","city":"Houghton Co.","priority":10}, + "KCVX": {"id":"KCVX","lat":45.30472,"lon":-85.27472,"state":"MI","location":"Charlevoix, Charlevoix Municipal Airport","city":"Charlevoix","priority":9}, + "KALX": {"id":"KALX","lat":32.91472,"lon":-85.96278,"state":"AL","location":"Alexander City, Thomas C Russell Field Airport","city":"Alexander City","priority":12}, + "KANB": {"id":"KANB","lat":33.59045,"lon":-85.84789,"state":"AL","location":"Anniston Metro Airport","city":"Anniston Metro","priority":13}, + "KASN": {"id":"KASN","lat":33.5695,"lon":-86.0512,"state":"AL","location":"Talladega Municipal Airport","city":"Talladega","priority":9}, + "KAUO": {"id":"KAUO","lat":32.61667,"lon":-85.43333,"state":"AL","location":"Auburn-Opelika Airport","city":"Auburn","priority":13}, + "KBFM": {"id":"KBFM","lat":30.61389,"lon":-88.0633299,"state":"AL","location":"Mobile, Mobile Downtown Airport","city":"Mobile Downtown","priority":13}, + "KBFZ": {"id":"KBFZ","lat":34.22911,"lon":-86.25575,"state":"AL","location":"Albertville Regional Airport-Thomas J Brumlik Field","city":"Albertville","priority":3}, + "KBHM": {"id":"KBHM","lat":33.56556,"lon":-86.745,"state":"AL","location":"Birmingham, Birmingham International Airport","city":"Birmingham","priority":1}, + "KCMD": {"id":"KCMD","lat":34.2687,"lon":-86.858,"state":"AL","location":"Cullman Regional Folsom Field","city":"Cullman Regional Folsom","priority":3}, + "KCQF": {"id":"KCQF","lat":30.461,"lon":-87.877,"state":"AL","location":"Sonny Callahan Airport","city":"Sonny Callahan","priority":13}, + "KDCU": {"id":"KDCU","lat":34.65806,"lon":-86.94333,"state":"AL","location":"Decatur, Pryor Field","city":"Decatur","priority":12}, + "KDHN": {"id":"KDHN","lat":31.32139,"lon":-85.44972,"state":"AL","location":"Dothan, Dothan Regional Airport","city":"Dothan","priority":3}, + "KDYA": {"id":"KDYA","lat":32.4638,"lon":-87.9541,"state":"AL","location":"Demopolis Municipal Airport","city":"Demopolis","priority":9}, + "KEDN": {"id":"KEDN","lat":31.2982,"lon":-85.9048,"state":"AL","location":"Enterprise Municipal Airport","city":"Enterprise","priority":9}, + "KEET": {"id":"KEET","lat":33.17833,"lon":-86.78167,"state":"AL","location":"Alabaster, Shelby County Airport","city":"Alabaster","priority":10}, + "KEKY": {"id":"KEKY","lat":33.3126,"lon":-86.9263,"state":"AL","location":"Bessemer Airport","city":"Bessemer","priority":13}, + "KEUF": {"id":"KEUF","lat":31.951,"lon":-85.129,"state":"AL","location":"Eufaula Municipal Airport","city":"Eufaula","priority":9}, + "KGAD": {"id":"KGAD","lat":33.96667,"lon":-86.08333,"state":"AL","location":"Gadsden, Gadsden Municipal Airport","city":"Gadsden","priority":9}, + "KGZH": {"id":"KGZH","lat":31.41889,"lon":-87.04806,"state":"AL","location":"Evergreen, Middleton Field","city":"Evergreen","priority":12}, + "KHDL": {"id":"KHDL","lat":31.36414,"lon":-85.31253,"state":"AL","location":"Headland Municipal Airport","city":"Headland","priority":9}, + "KHEY": {"id":"KHEY","lat":31.35,"lon":-85.66667,"state":"AL","location":"Hanchey AHP / Ozark","city":"Ozark","priority":14}, + "KHSV": {"id":"KHSV","lat":34.64361,"lon":-86.78556,"state":"AL","location":"Huntsville, Huntsville International / Jones Field","city":"Huntsville","priority":1}, + "KHUA": {"id":"KHUA","lat":34.6786,"lon":-86.6847,"state":"AL","location":"Redstone Airfield","city":"Redstone","priority":99}, + "KJFX": {"id":"KJFX","lat":33.902,"lon":-87.31417,"state":"AL","location":"Jasper Walker County Airport & Bevill Field","city":"Jasper","priority":10}, + "KJKA": {"id":"KJKA","lat":30.2896,"lon":-87.6718,"state":"AL","location":"Jack Edwards Airport","city":"Jack Edwards","priority":13}, + "KLOR": {"id":"KLOR","lat":31.35889,"lon":-85.74833,"state":"AL","location":"Fort Rucker, Lowe Army Heliport","city":"Ft Rucker","priority":99}, + "KMDQ": {"id":"KMDQ","lat":34.86139,"lon":-86.55722,"state":"AL","location":"Huntsville, Madison County Executive Airport","city":"Madison Co.","priority":10}, + "KMGM": {"id":"KMGM","lat":32.30028,"lon":-86.40611,"state":"AL","location":"Montgomery, Dannelly Field","city":"Montgomery","priority":12}, + "KMOB": {"id":"KMOB","lat":30.68833,"lon":-88.24556,"state":"AL","location":"Mobile, Mobile Regional Airport","city":"Mobile","priority":3}, + "KMSL": {"id":"KMSL","lat":34.74389,"lon":-87.59944,"state":"AL","location":"Muscle Shoals, North West Alabama Regional Airport","city":"Muscle Shoals","priority":3}, + "KMXF": {"id":"KMXF","lat":32.38333,"lon":-86.36667,"state":"AL","location":"Maxwell Air Force Base / Montgomery","city":"Maxwell AFB","priority":14}, + "KOZR": {"id":"KOZR","lat":31.27672,"lon":-85.71099,"state":"AL","location":"Cairns Army Air Field / Ozark","city":"Cairns AAF","priority":14}, + "KPLR": {"id":"KPLR","lat":33.5588,"lon":-86.2491,"state":"AL","location":"St Clair County Airport","city":"St Clair Co.","priority":10}, + "KPRN": {"id":"KPRN","lat":31.8457,"lon":-86.6107,"state":"AL","location":"Mac Crenshaw Memorial Airport","city":"Mac Crenshaw","priority":11}, + "KSCD": {"id":"KSCD","lat":33.1718,"lon":-86.3055,"state":"AL","location":"Merkel Field Sylacauga Municipal Airport","city":"Merkel","priority":9}, + "KSEM": {"id":"KSEM","lat":32.35,"lon":-86.98333,"state":"AL","location":"Craig Field / Selma","city":"Craig","priority":12}, + "KSXS": {"id":"KSXS","lat":31.35,"lon":-85.85,"state":"AL","location":"SCHELL AHP","city":"Schell","priority":14}, + "KTCL": {"id":"KTCL","lat":33.21215,"lon":-87.61554,"state":"AL","location":"Tuscaloosa Regional Airport","city":"Tuscaloosa","priority":3}, + "KTOI": {"id":"KTOI","lat":31.86056,"lon":-86.01222,"state":"AL","location":"Troy, Troy Municipal Airport","city":"Troy","priority":9}, + "KAFN": {"id":"KAFN","lat":42.8066699,"lon":-72.00127,"state":"NH","location":"Jaffrey Airport-Silver Ranch","city":"Jaffrey","priority":13}, + "KASH": {"id":"KASH","lat":42.77981,"lon":-71.51409,"state":"NH","location":"Nashua - Boire Field Airport","city":"Nashua","priority":12}, + "KBML": {"id":"KBML","lat":44.57611,"lon":-71.17861,"state":"NH","location":"Berlin, Berlin Municipal Airport","city":"Berlin","priority":9}, + "KCON": {"id":"KCON","lat":43.20489,"lon":-71.50257,"state":"NH","location":"Concord Municipal Airport","city":"Concord","priority":9}, + "KDAW": {"id":"KDAW","lat":43.27939,"lon":-70.92426,"state":"NH","location":"Rochester - Skyhaven Airport","city":"Rochester","priority":13}, + "KEEN": {"id":"KEEN","lat":42.9,"lon":-72.26667,"state":"NH","location":"Keene, Dillant-Hopkins Airport","city":"Keene","priority":13}, + "KHIE": {"id":"KHIE","lat":44.36595,"lon":-71.55218,"state":"NH","location":"Whitefield - Mount Washington Regional Airport","city":"Whitefield","priority":3}, + "KLCI": {"id":"KLCI","lat":43.56667,"lon":-71.41667,"state":"NH","location":"Laconia, Laconia Municipal Airport","city":"Laconia","priority":9}, + "KLEB": {"id":"KLEB","lat":43.6271,"lon":-72.30537,"state":"NH","location":"Lebanon Municipal Airport","city":"Lebanon","priority":9}, + "KMHT": {"id":"KMHT","lat":42.92964,"lon":-71.43559,"state":"NH","location":"Manchester Airport","city":"Manchester","priority":13}, + "KMWN": {"id":"KMWN","lat":44.27086,"lon":-71.30337,"state":"NH","location":"Mount Washington","city":"Mt Washington","priority":99}, + "KPSM": {"id":"KPSM","lat":43.0833299,"lon":-70.81667,"state":"NH","location":"Pease Air Force Base / Portsmouth","city":"Portsmouth","priority":14}, + "PHBK": {"id":"PHBK","lat":22.03639,"lon":-159.78639,"state":"HI","location":"Kekaha, Pacific Missile Test Facility Barking Sands","city":"Kekaha","priority":50}, + "PHHI": {"id":"PHHI","lat":21.48333,"lon":-158.03333,"state":"HI","location":"Wheeler Air Force Base / Oahu","city":"Oahu","priority":50}, + "PHHN": {"id":"PHHN","lat":20.79563,"lon":-156.01444,"state":"HI","location":"HANA","city":"Hana","priority":50}, + "PHJR": {"id":"PHJR","lat":21.30833,"lon":-158.06806,"state":"HI","location":"Oahu, Kalaeloa Airport","city":"Kalaeloa","priority":50}, + "PHKO": {"id":"PHKO","lat":19.74083,"lon":-156.05056,"state":"HI","location":"Kailua / Kona, Keahole Airport","city":"Kailua","priority":50}, + "PHLI": {"id":"PHLI","lat":21.98389,"lon":-159.3411099,"state":"HI","location":"Lihue, Lihue Airport","city":"Lihue","priority":50}, + "PHMK": {"id":"PHMK","lat":21.15,"lon":-157.1,"state":"HI","location":"Kaunakakai, Molokai Airport","city":"Kaunakakai","priority":50}, + "PHMU": {"id":"PHMU","lat":20.00133,"lon":-155.66817,"state":"HI","location":"KAMUELA","city":"Kamuela","priority":50}, + "PHNG": {"id":"PHNG","lat":21.45389,"lon":-157.76556,"state":"HI","location":"Kaneohe, Marine Corps Air Station","city":"Kaneohe","priority":50}, + "PHNL": {"id":"PHNL","lat":21.3275,"lon":-157.94306,"state":"HI","location":"Daniel K Inouye International Airport","city":"Honolulu","priority":1}, + "PHNY": {"id":"PHNY","lat":20.78556,"lon":-156.95139,"state":"HI","location":"Lanai City, Lanai Airport","city":"Lanai City","priority":50}, + "PHOG": {"id":"PHOG","lat":20.8924999,"lon":-156.43694,"state":"HI","location":"Kahului, Kahului Airport","city":"Kahului","priority":50}, + "PHSF": {"id":"PHSF","lat":19.78333,"lon":-155.55,"state":"HI","location":"Bradshaw Army Air Field / Hawaii","city":"Hawaii","priority":50}, + "PHTO": {"id":"PHTO","lat":19.72222,"lon":-155.0558299,"state":"HI","location":"Hilo, Hilo International Airport","city":"Hilo","priority":1}, + "KADU": {"id":"KADU","lat":41.70111,"lon":-94.92028,"state":"IA","location":"Audubon, Audubon County Airport","city":"Audubon","priority":10}, + "KAIO": {"id":"KAIO","lat":41.4,"lon":-95.05,"state":"IA","location":"Atlantic","city":"Atlantic","priority":99}, + "KALO": {"id":"KALO","lat":42.55444,"lon":-92.40111,"state":"IA","location":"Waterloo, Waterloo Municipal Airport","city":"Waterloo","priority":9}, + "KAMW": {"id":"KAMW","lat":41.99056,"lon":-93.6188899,"state":"IA","location":"Ames, Ames Municipal Airport","city":"Ames","priority":9}, + "KAWG": {"id":"KAWG","lat":41.28333,"lon":-91.66667,"state":"IA","location":"Washington","city":"Washington","priority":99}, + "KAXA": {"id":"KAXA","lat":43.0833299,"lon":-94.26667,"state":"IA","location":"Algona","city":"Algona","priority":99}, + "KBNW": {"id":"KBNW","lat":42.05,"lon":-93.85,"state":"IA","location":"Boone Municipal","city":"Boone","priority":9}, + "KBRL": {"id":"KBRL","lat":40.77293,"lon":-91.12543,"state":"IA","location":"Burlington Regional Airport","city":"Burlington","priority":3}, + "KCAV": {"id":"KCAV","lat":42.75,"lon":-93.76667,"state":"IA","location":"Clarion","city":"Clarion","priority":99}, + "KCBF": {"id":"KCBF","lat":41.2612499,"lon":-95.7604,"state":"IA","location":"Council Bluffs","city":"Council Bluffs","priority":99}, + "KCCY": {"id":"KCCY","lat":43.06667,"lon":-92.61667,"state":"IA","location":"Charles City","city":"Charles City","priority":99}, + "KCID": {"id":"KCID","lat":41.88295,"lon":-91.72456,"state":"IA","location":"Cedar Rapids Airport","city":"Cedar Rapids","priority":13}, + "KCIN": {"id":"KCIN","lat":42.05,"lon":-94.78333,"state":"IA","location":"Carroll","city":"Carroll","priority":99}, + "KCKP": {"id":"KCKP","lat":42.73167,"lon":-95.55583,"state":"IA","location":"Cherokee, Cherokee Municipal Airport","city":"Cherokee","priority":9}, + "KCNC": {"id":"KCNC","lat":41.03333,"lon":-93.36667,"state":"IA","location":"Chariton","city":"Chariton","priority":99}, + "KCSQ": {"id":"KCSQ","lat":41.0188599,"lon":-94.361,"state":"IA","location":"Creston Municipal Airport","city":"Creston","priority":9}, + "KCWI": {"id":"KCWI","lat":41.82954,"lon":-90.33279,"state":"IA","location":"Clinton Municipal Airport","city":"Clinton","priority":9}, + "KDBQ": {"id":"KDBQ","lat":42.39837,"lon":-90.7091,"state":"IA","location":"Dubuque Regional Airport","city":"Dubuque","priority":3}, + "KDEH": {"id":"KDEH","lat":43.28333,"lon":-91.73333,"state":"IA","location":"Decorah","city":"Decorah","priority":99}, + "KDNS": {"id":"KDNS","lat":41.98333,"lon":-95.38333,"state":"IA","location":"Denison","city":"Denison","priority":99}, + "KDSM": {"id":"KDSM","lat":41.53399,"lon":-93.65307,"state":"IA","location":"Des Moines International Airport","city":"Des Moines","priority":1}, + "KDVN": {"id":"KDVN","lat":41.61338,"lon":-90.59479,"state":"IA","location":"Davenport Municipal Airport","city":"Davenport","priority":9}, + "KEBS": {"id":"KEBS","lat":42.43724,"lon":-93.87237,"state":"IA","location":"Webster City Municipal Airport","city":"Webster City","priority":9}, + "KEOK": {"id":"KEOK","lat":40.46149,"lon":-91.42739,"state":"IA","location":"Keokuk Municipal Airport","city":"Keokuk","priority":9}, + "KEST": {"id":"KEST","lat":43.40111,"lon":-94.74722,"state":"IA","location":"Estherville, Estherville Municipal Airport","city":"Estherville","priority":9}, + "KFFL": {"id":"KFFL","lat":41.0521,"lon":-91.98339,"state":"IA","location":"Fairfield Municipal Airport","city":"Fairfield","priority":9}, + "KFOD": {"id":"KFOD","lat":42.55,"lon":-94.18333,"state":"IA","location":"Fort Dodge","city":"Ft Dodge","priority":99}, + "KFSW": {"id":"KFSW","lat":40.66154,"lon":-91.32672,"state":"IA","location":"Fort Madison Municipal Airport","city":"Ft Madison","priority":9}, + "KFXY": {"id":"KFXY","lat":43.235,"lon":-93.624,"state":"IA","location":"Forest City Municipal Airport","city":"Forest City","priority":9}, + "KGGI": {"id":"KGGI","lat":41.7092,"lon":-92.7349,"state":"IA","location":"Grinnell Municipal Airfield","city":"Grinnell","priority":9}, + "KHNR": {"id":"KHNR","lat":41.58444,"lon":-95.33972,"state":"IA","location":"Harlan, Harlan Municipal Airport","city":"Harlan","priority":9}, + "KHPT": {"id":"KHPT","lat":42.72369,"lon":-93.22633,"state":"IA","location":"Hampton Municipal Airport","city":"Hampton","priority":9}, + "KICL": {"id":"KICL","lat":40.72421,"lon":-95.02224,"state":"IA","location":"Schenck Field Airport","city":"Schenck","priority":12}, + "KIFA": {"id":"KIFA","lat":42.4709999,"lon":-93.27,"state":"IA","location":"Iowa Falls Municipal Airport","city":"Iowa Falls","priority":9}, + "KIIB": {"id":"KIIB","lat":42.45,"lon":-91.93333,"state":"IA","location":"Independence, Independence Municipal Airport","city":"Independence","priority":9}, + "KIKV": {"id":"KIKV","lat":41.68782,"lon":-93.56944,"state":"IA","location":"Ankeny Regional Airport","city":"Ankeny","priority":3}, + "KIOW": {"id":"KIOW","lat":41.6394499,"lon":-91.5445,"state":"IA","location":"Iowa City Municipal Airport","city":"Iowa City","priority":9}, + "KLRJ": {"id":"KLRJ","lat":42.77478,"lon":-96.19239,"state":"IA","location":"Le Mars Municipal Airport","city":"Le Mars","priority":9}, + "KLWD": {"id":"KLWD","lat":40.63056,"lon":-93.90083,"state":"IA","location":"Lamoni, Lamoni Municipal Airport","city":"Lamoni","priority":9}, + "KMCW": {"id":"KMCW","lat":43.15442,"lon":-93.32607,"state":"IA","location":"Mason City Municipal Airport","city":"Mason City","priority":9}, + "KMIW": {"id":"KMIW","lat":42.11056,"lon":-92.91611,"state":"IA","location":"Marshalltown, Marshalltown Municipal Airport","city":"Marshalltown","priority":9}, + "KMPZ": {"id":"KMPZ","lat":40.94667,"lon":-91.51111,"state":"IA","location":"Mount Pleasant, Mount Pleasant Municipal Airport","city":"Mt Pleasant","priority":9}, + "KMUT": {"id":"KMUT","lat":41.36667,"lon":-91.15,"state":"IA","location":"Muscatine","city":"Muscatine","priority":99}, + "KMXO": {"id":"KMXO","lat":42.22035,"lon":-91.16041,"state":"IA","location":"Monticello Regional Airport","city":"Monticello","priority":3}, + "KOLZ": {"id":"KOLZ","lat":42.68316,"lon":-91.97595,"state":"IA","location":"Oelwein Municipal Airport","city":"Oelwein","priority":9}, + "KOOA": {"id":"KOOA","lat":41.22611,"lon":-92.49361,"state":"IA","location":"Oskaloosa, Oskaloosa Municipal Airport","city":"Oskaloosa","priority":9}, + "KOTM": {"id":"KOTM","lat":41.10082,"lon":-92.4445099,"state":"IA","location":"Ottumwa Regional Airport","city":"Ottumwa","priority":3}, + "KOXV": {"id":"KOXV","lat":41.3,"lon":-93.11667,"state":"IA","location":"Knoxville","city":"Knoxville","priority":99}, + "KPEA": {"id":"KPEA","lat":41.4,"lon":-92.93333,"state":"IA","location":"Pella, Pella Municipal Airport","city":"Pella","priority":9}, + "KPRO": {"id":"KPRO","lat":41.828,"lon":-94.1598999,"state":"IA","location":"Perry Municipal Airport","city":"Perry","priority":9}, + "KRDK": {"id":"KRDK","lat":41.01667,"lon":-95.26667,"state":"IA","location":"Red Oak","city":"Red Oak","priority":99}, + "KSDA": {"id":"KSDA","lat":40.75,"lon":-95.41667,"state":"IA","location":"Shenandoah Municipal","city":"Shenandoah","priority":9}, + "KSHL": {"id":"KSHL","lat":43.21667,"lon":-95.83333,"state":"IA","location":"Sheldon","city":"Sheldon","priority":99}, + "KSLB": {"id":"KSLB","lat":42.6,"lon":-95.23333,"state":"IA","location":"Storm Lake","city":"Storm Lake","priority":99}, + "KSPW": {"id":"KSPW","lat":43.16825,"lon":-95.21008,"state":"IA","location":"Spencer Municipal Airport","city":"Spencer","priority":9}, + "KSUX": {"id":"KSUX","lat":42.4025,"lon":-96.38444,"state":"IA","location":"Sioux City, Sioux Gateway Airport","city":"Sioux City","priority":13}, + "KSXK": {"id":"KSXK","lat":42.98583,"lon":-96.1614,"state":"IA","location":"Sioux County Regional Airport","city":"Sioux Co.","priority":10}, + "KTNU": {"id":"KTNU","lat":41.67014,"lon":-93.01902,"state":"IA","location":"Newton Municipal Airport - Earl Johnson Field","city":"Newton","priority":9}, + "KTVK": {"id":"KTVK","lat":40.6839,"lon":-92.901,"state":"IA","location":"Centerville Municipal Airport","city":"Centerville","priority":9}, + "KVTI": {"id":"KVTI","lat":42.21861,"lon":-92.02583,"state":"IA","location":"Vinton, Vinton Veterans Memorial Airpark Airport","city":"Vinton","priority":15}, + "KACP": {"id":"KACP","lat":30.75056,"lon":-92.68861,"state":"LA","location":"Oakdale, Allen Parish Airport","city":"Oakdale","priority":13}, + "KAEX": {"id":"KAEX","lat":31.33472,"lon":-92.55861,"state":"LA","location":"Alexandria, Alexandria International Airport","city":"Alexandria","priority":1}, + "KAPS": {"id":"KAPS","lat":30.08747,"lon":-90.58283,"state":"LA","location":"Port of South Louisiana Executive Regional Airport","city":"Port of South Louisiana","priority":5}, + "KAQV": {"id":"KAQV","lat":31.4,"lon":-93.2833,"state":"LA","location":"Ft. Polk - Peason Ridge","city":"Ft Polk","priority":99}, + "KARA": {"id":"KARA","lat":30.02918,"lon":-91.88451,"state":"LA","location":"Acadiana Regional Airport","city":"Acadiana","priority":3}, + "KASD": {"id":"KASD","lat":30.34306,"lon":-89.82194,"state":"LA","location":"Slidell, Slidell Airport","city":"Slidell","priority":13}, + "KATP": {"id":"KATP","lat":27.195,"lon":-90.027,"state":"LA","location":"Green Canyon 787 Atlantis","city":"Green Canyon 787 Atlantis","priority":99}, + "KBAD": {"id":"KBAD","lat":32.5,"lon":-93.66667,"state":"LA","location":"Barksdale Air Force Base","city":"Barksdale","priority":14}, + "KBKB": {"id":"KBKB","lat":31.0217,"lon":-92.9107,"state":"LA","location":"Ft. Polk - Fullerton Landing Strip","city":"Fullerton","priority":99}, + "KBQP": {"id":"KBQP","lat":32.75583,"lon":-91.88056,"state":"LA","location":"Bastrop, Morehouse Memorial Airport","city":"Bastrop","priority":11}, + "KBTR": {"id":"KBTR","lat":30.53722,"lon":-91.14694,"state":"LA","location":"Baton Rouge, Baton Rouge Metropolitan, Ryan Field","city":"Baton Rouge","priority":12}, + "KBXA": {"id":"KBXA","lat":30.81361,"lon":-89.86472,"state":"LA","location":"Bogalusa, George R Carr Memorial Air Field","city":"Bogalusa","priority":11}, + "KCWF": {"id":"KCWF","lat":30.21667,"lon":-93.15,"state":"LA","location":"Chenault Airpark","city":"Chenault","priority":15}, + "KCYD": {"id":"KCYD","lat":28.17,"lon":-89.22,"state":"LA","location":"MISS CANYAN 807","city":"Miss Canyan","priority":99}, + "KDRI": {"id":"KDRI","lat":30.83167,"lon":-93.33972,"state":"LA","location":"De Ridder, Beauregard Parish Airport","city":"De Ridder","priority":13}, + "KDSF": {"id":"KDSF","lat":28.35,"lon":-88.26667,"state":"LA","location":"Mississippi Canyon","city":"Mississippi Canyon","priority":99}, + "KDTN": {"id":"KDTN","lat":32.5424999,"lon":-93.74472,"state":"LA","location":"Shreveport, Shreveport Downtown Airport","city":"Shreveport Downtown","priority":13}, + "KESF": {"id":"KESF","lat":31.39634,"lon":-92.28273,"state":"LA","location":"Alexandria Esler Regional Airport","city":"Alexandria Esler","priority":3}, + "KGAO": {"id":"KGAO","lat":29.44472,"lon":-90.26111,"state":"LA","location":"Galliano, South Lafourche Airport","city":"Galliano","priority":13}, + "KGBK": {"id":"KGBK","lat":27.2,"lon":-92.2,"state":"LA","location":"MAGNOLIA OIL PLATFORM","city":"Magnolia Oil Platform","priority":99}, + "KGHB": {"id":"KGHB","lat":27.84,"lon":-91.988,"state":"LA","location":"GB172/Salsa (Shell E-P)","city":"GB172","priority":99}, + "KHDC": {"id":"KHDC","lat":30.52083,"lon":-90.4175,"state":"LA","location":"Hammond, Hammond Municipal Airport","city":"Hammond","priority":9}, + "KHUM": {"id":"KHUM","lat":29.56341,"lon":-90.66283,"state":"LA","location":"Houma-Terrebonne Airport","city":"Houma","priority":13}, + "KHZR": {"id":"KHZR","lat":30.7183,"lon":-91.4787,"state":"LA","location":"New Roads False River Regional Airport","city":"New Roads False River","priority":3}, + "KIER": {"id":"KIER","lat":31.73583,"lon":-93.09917,"state":"LA","location":"Natchitoches, Natchitoches Regional Airport","city":"Natchitoches","priority":3}, + "KIYA": {"id":"KIYA","lat":29.97578,"lon":-92.08422,"state":"LA","location":"Abbeville Chris Crusta Memorial Airport","city":"Abbeville","priority":11}, + "KLCH": {"id":"KLCH","lat":30.12556,"lon":-93.22767,"state":"LA","location":"Lake Charles Regional Airport","city":"Lake Charles","priority":3}, + "KLFT": {"id":"KLFT","lat":30.20222,"lon":-91.99306,"state":"LA","location":"Lafayette, Lafayette Regional Airport","city":"Lafayette","priority":3}, + "KMLU": {"id":"KMLU","lat":32.5155699,"lon":-92.02995,"state":"LA","location":"Monroe Regional Airport","city":"Monroe","priority":3}, + "KMNE": {"id":"KMNE","lat":32.64603,"lon":-93.29808,"state":"LA","location":"Minden Airport","city":"Minden","priority":13}, + "KMSY": {"id":"KMSY","lat":29.99278,"lon":-90.2508299,"state":"LA","location":"New Orleans, New Orleans International Airport","city":"New Orleans","priority":1}, + "KNBG": {"id":"KNBG","lat":29.83736,"lon":-90.02445,"state":"LA","location":"New Orleans Naval Air Station - Alvin Callender Field","city":"New Orleans NAS","priority":14}, + "KNEW": {"id":"KNEW","lat":30.04944,"lon":-90.02889,"state":"LA","location":"New Orleans, New Orleans Lakefront Airport","city":"New Orleans Lakefront","priority":13}, + "KOPL": {"id":"KOPL","lat":30.5584,"lon":-92.0994,"state":"LA","location":"Opelousas St Landry Parish Airport","city":"Opelousas St Landry Parish","priority":13}, + "KPOE": {"id":"KPOE","lat":31.05,"lon":-93.19389,"state":"LA","location":"Fort Polk, Polk AAF Ft Polk","city":"Ft Polk","priority":14}, + "KPTN": {"id":"KPTN","lat":29.71667,"lon":-91.33333,"state":"LA","location":"Patterson Memorial","city":"Patterson","priority":11}, + "KREG": {"id":"KREG","lat":30.1714,"lon":-90.9404,"state":"LA","location":"Louisiana Regional Airport","city":"Louisiana","priority":3}, + "KRSN": {"id":"KRSN","lat":32.51444,"lon":-92.58833,"state":"LA","location":"Ruston, Ruston Regional Airport","city":"Ruston","priority":3}, + "KSHV": {"id":"KSHV","lat":32.44694,"lon":-93.82417,"state":"LA","location":"Shreveport, Shreveport Regional Airport","city":"Shreveport","priority":3}, + "KTVR": {"id":"KTVR","lat":32.3480599,"lon":-91.03,"state":"LA","location":"Vicksburg, Vicksburg / Tallulah Regional Airport","city":"Vicksburg","priority":3}, + "KUXL": {"id":"KUXL","lat":30.1314,"lon":-93.3760999,"state":"LA","location":"Southland Field","city":"Southland","priority":12}, + "KVOA": {"id":"KVOA","lat":29.229,"lon":-87.781,"state":"LA","location":"VK 786/Petronius (Chevron)","city":"VK 786","priority":99}, + "KABQ": {"id":"KABQ","lat":35.04167,"lon":-106.61472,"state":"NM","location":"Albuquerque, Albuquerque International Airport","city":"Albuquerque","priority":1}, + "KAEG": {"id":"KAEG","lat":35.145,"lon":-106.795,"state":"NM","location":"Albuquerque, Double Eagle II Airport","city":"Double Eagle II","priority":13}, + "KALM": {"id":"KALM","lat":32.83512,"lon":-105.99408,"state":"NM","location":"Alamogordo-White","city":"Alamogordo","priority":99}, + "KATS": {"id":"KATS","lat":32.85239,"lon":-104.46444,"state":"NM","location":"Artesia Municipal Airport","city":"Artesia","priority":9}, + "KAXX": {"id":"KAXX","lat":36.42586,"lon":-105.29028,"state":"NM","location":"Angel Fire Airport","city":"Angel Fire","priority":13}, + "KBRG": {"id":"KBRG","lat":34.64586,"lon":-106.83634,"state":"NM","location":"Belen Regional Airport","city":"Belen","priority":3}, + "KCAO": {"id":"KCAO","lat":36.44834,"lon":-103.15367,"state":"NM","location":"Clayton Municipal Airpark","city":"Clayton","priority":15}, + "KCNM": {"id":"KCNM","lat":32.3375,"lon":-104.26333,"state":"NM","location":"Carlsbad, Cavern City Air Terminal Airport","city":"Carlsbad","priority":13}, + "KCQC": {"id":"KCQC","lat":35,"lon":-105.66667,"state":"NM","location":"Clines Corners","city":"Clines Corners","priority":99}, + "KCVN": {"id":"KCVN","lat":34.42274,"lon":-103.0802,"state":"NM","location":"Clovis Municipal Airport","city":"Clovis","priority":9}, + "KCVS": {"id":"KCVS","lat":34.38333,"lon":-103.31667,"state":"NM","location":"Cannon Air Force Base / Clovis","city":"Cannon AFB","priority":14}, + "KDMN": {"id":"KDMN","lat":32.25927,"lon":-107.72051,"state":"NM","location":"Deming Municipal Airport","city":"Deming","priority":9}, + "KDNA": {"id":"KDNA","lat":31.87495,"lon":-106.69385,"state":"NM","location":"Dona Ana County Jetport, Santa Teresa","city":"Santa Teresa","priority":10}, + "KFMN": {"id":"KFMN","lat":36.7436099,"lon":-108.22917,"state":"NM","location":"Farmington, Four Corners Regional Airport","city":"Farmington","priority":3}, + "KGNT": {"id":"KGNT","lat":35.16528,"lon":-107.90222,"state":"NM","location":"Grants, Grants-Milan Municipal Airport","city":"Grants","priority":9}, + "KGUP": {"id":"KGUP","lat":35.50859,"lon":-108.79316,"state":"NM","location":"Gallup Municipal Airport","city":"Gallup","priority":9}, + "KHMN": {"id":"KHMN","lat":32.85,"lon":-106.1,"state":"NM","location":"Holloman Air Force Base","city":"Holloman","priority":14}, + "KHOB": {"id":"KHOB","lat":32.68333,"lon":-103.2166699,"state":"NM","location":"Hobbs / Lea County","city":"Hobbs","priority":10}, + "KLAM": {"id":"KLAM","lat":35.8796899,"lon":-106.26869,"state":"NM","location":"Los Alamos Airport","city":"Los Alamos","priority":13}, + "KLRU": {"id":"KLRU","lat":32.28944,"lon":-106.92194,"state":"NM","location":"Las Cruces, Las Cruces International Airport","city":"Las Cruces","priority":1}, + "KLSB": {"id":"KLSB","lat":32.33346,"lon":-108.69174,"state":"NM","location":"Lordsburg Municipal Airport","city":"Lordsburg","priority":9}, + "KLVS": {"id":"KLVS","lat":35.65584,"lon":-105.13852,"state":"NM","location":"Las Vegas Municipal Airport","city":"Las Vegas","priority":9}, + "KONM": {"id":"KONM","lat":34.02633,"lon":-106.90372,"state":"NM","location":"Socorro Municipal Airport","city":"Socorro","priority":9}, + "KROW": {"id":"KROW","lat":33.30737,"lon":-104.50816,"state":"NM","location":"Roswell International Air Center Airport","city":"Roswell","priority":1}, + "KRTN": {"id":"KRTN","lat":36.741528,"lon":-104.502183,"state":"NM","location":"Raton Municipal - Crews Field Airport","city":"Raton Municipal","priority":9}, + "KSAF": {"id":"KSAF","lat":35.61097,"lon":-106.09573,"state":"NM","location":"Santa Fe County Municipal Airport","city":"Santa Fe Co.","priority":10}, + "KSKX": {"id":"KSKX","lat":36.45,"lon":-105.66667,"state":"NM","location":"Taos, Taos Regional Airport","city":"Taos","priority":3}, + "KSRR": {"id":"KSRR","lat":33.4667699,"lon":-105.52778,"state":"NM","location":"Sierra Blanca Regional Airport","city":"Sierra Blanca","priority":3}, + "KSVC": {"id":"KSVC","lat":32.63099,"lon":-108.14658,"state":"NM","location":"Grant County Airport","city":"Grant Co.","priority":10}, + "KSXU": {"id":"KSXU","lat":34.93567,"lon":-104.64256,"state":"NM","location":"Santa Rosa Route 66 Airport","city":"Santa Rosa Route 66","priority":13}, + "KTCC": {"id":"KTCC","lat":35.18053,"lon":-103.60145,"state":"NM","location":"Tucumcari Municipal Airport","city":"Tucumcari","priority":9}, + "KTCS": {"id":"KTCS","lat":33.2366699,"lon":-107.26806,"state":"NM","location":"Truth Or Consequences, Truth Or Consequences Municipal Airport","city":"Truth Or Consequences","priority":9}, + "KXNI": {"id":"KXNI","lat":35.06068,"lon":-108.93759,"state":"NM","location":"Andrew Othole Memorial Airport","city":"Andrew Othole","priority":11}, + "KADW": {"id":"KADW","lat":38.81667,"lon":-76.85,"state":"MD","location":"Camp Springs / Andrews Air Force Base","city":"Camp Springs","priority":14}, + "KANP": {"id":"KANP","lat":38.94287,"lon":-76.5683899,"state":"MD","location":"LEEAIRPORT","city":"Lee","priority":99}, + "KAPG": {"id":"KAPG","lat":39.46667,"lon":-76.16667,"state":"MD","location":"Phillips Army Air Field / Aberdeen","city":"Aberdeen","priority":14}, + "KBWI": {"id":"KBWI","lat":39.17329,"lon":-76.68404,"state":"MD","location":"Baltimore, Baltimore-Washington International Airport","city":"Baltimore","priority":1}, + "KCGE": {"id":"KCGE","lat":38.5393,"lon":-76.0304,"state":"MD","location":"Cambridge-Dorchester Airport","city":"Cambridge","priority":13}, + "KCGS": {"id":"KCGS","lat":38.9806,"lon":-76.9223,"state":"MD","location":"College Park Airport","city":"College Park","priority":13}, + "KDMH": {"id":"KDMH","lat":39.28333,"lon":-76.61667,"state":"MD","location":"Baltimore, Inner Harbor","city":"Inner Harbor","priority":99}, + "KDMW": {"id":"KDMW","lat":39.6083,"lon":-77.0077,"state":"MD","location":"Carroll County Regional Jack B Poage Field","city":"Carroll Co.","priority":10}, + "KEDG": {"id":"KEDG","lat":39.39205,"lon":-76.29106,"state":"MD","location":"WEIDE","city":"Weide","priority":99}, + "KESN": {"id":"KESN","lat":38.8,"lon":-76.06667,"state":"MD","location":"Easton / Newman Field","city":"Easton","priority":12}, + "KFDK": {"id":"KFDK","lat":39.41775,"lon":-77.36982,"state":"MD","location":"Frederick Municipal Airport","city":"Frederick","priority":9}, + "KFME": {"id":"KFME","lat":39.0833299,"lon":-76.76667,"state":"MD","location":"Fort Meade / Tipton","city":"Ft Meade","priority":99}, + "KGAI": {"id":"KGAI","lat":39.16957,"lon":-77.16551,"state":"MD","location":"Gaithersburg - Montgomery County Airport","city":"Gaithersburg","priority":10}, + "KHGR": {"id":"KHGR","lat":39.70583,"lon":-77.73,"state":"MD","location":"Hagerstown, Washington County Regional Airport","city":"Hagerstown","priority":10}, + "KMTN": {"id":"KMTN","lat":39.3333299,"lon":-76.41667,"state":"MD","location":"Baltimore / Martin","city":"Martin","priority":99}, + "KNAK": {"id":"KNAK","lat":38.99125,"lon":-76.48907,"state":"MD","location":"Annapolis, United States Naval Academy","city":"Annapolis","priority":99}, + "KNHK": {"id":"KNHK","lat":38.27861,"lon":-76.41389,"state":"MD","location":"Patuxent River, Naval Air Station","city":"Patuxent River","priority":14}, + "KNUI": {"id":"KNUI","lat":38.14889,"lon":-76.42,"state":"MD","location":"St. Inigoes, Webster Field, Naval Electronic Systems Engineering Activity","city":"St Inigoes","priority":12}, + "KOXB": {"id":"KOXB","lat":38.31056,"lon":-75.12389,"state":"MD","location":"Ocean City, Ocean City Municipal Airport","city":"Ocean City","priority":9}, + "KRSP": {"id":"KRSP","lat":39.645,"lon":-77.468,"state":"MD","location":"Camp David","city":"Camp David","priority":99}, + "KSBY": {"id":"KSBY","lat":38.34056,"lon":-75.51028,"state":"MD","location":"Salisbury, Salisbury-Ocean City Wicomico County Regional Airport","city":"Salisbury","priority":10}, + "KVKX": {"id":"KVKX","lat":38.74761,"lon":-76.95719,"state":"MD","location":"POTOMAC","city":"Potomac","priority":99}, + "KAUG": {"id":"KAUG","lat":44.32056,"lon":-69.79722,"state":"ME","location":"Augusta, Augusta State Airport","city":"Augusta","priority":6}, + "KBGR": {"id":"KBGR","lat":44.79722,"lon":-68.81861,"state":"ME","location":"Bangor, Bangor International Airport","city":"Bangor","priority":1}, + "KBHB": {"id":"KBHB","lat":44.45,"lon":-68.36667,"state":"ME","location":"Bar Harbor, Hancock County-Bar Harbor Airport","city":"Bar Harbor","priority":10}, + "KBXM": {"id":"KBXM","lat":43.8923599,"lon":-69.93883,"state":"ME","location":"BRUNSWICK","city":"Brunswick","priority":99}, + "KCAR": {"id":"KCAR","lat":46.86722,"lon":-68.01333,"state":"ME","location":"Caribou, Caribou Municipal Airport","city":"Caribou","priority":9}, + "KFVE": {"id":"KFVE","lat":47.2849999,"lon":-68.30722,"state":"ME","location":"Frenchville, Northern Aroostook Regional Airport","city":"Frenchville","priority":3}, + "KGNR": {"id":"KGNR","lat":45.4646199,"lon":-69.5538,"state":"ME","location":"Greenville","city":"Greenville","priority":99}, + "KHUL": {"id":"KHUL","lat":46.12306,"lon":-67.79194,"state":"ME","location":"Houlton, Houlton International Airport","city":"Houlton","priority":1}, + "KIWI": {"id":"KIWI","lat":43.96401,"lon":-69.7107599,"state":"ME","location":"Wiscasset Airport","city":"Wiscasset","priority":13}, + "KIZG": {"id":"KIZG","lat":43.98917,"lon":-70.95028,"state":"ME","location":"Fryeburg, Eastern Slopes Regional Airport","city":"Fryeburg","priority":3}, + "KLEW": {"id":"KLEW","lat":44.05,"lon":-70.28333,"state":"ME","location":"Auburn-Lewiston","city":"Auburn","priority":99}, + "KMLT": {"id":"KMLT","lat":45.64778,"lon":-68.69194,"state":"ME","location":"Millinocket, Millinocket Municipal Airport","city":"Millinocket","priority":9}, + "KPQI": {"id":"KPQI","lat":46.68333,"lon":-68.05,"state":"ME","location":"Presque Isle","city":"Presque Isle","priority":99}, + "KPWM": {"id":"KPWM","lat":43.64222,"lon":-70.30444,"state":"ME","location":"Portland, Portland International Jetport","city":"Portland","priority":1}, + "KRKD": {"id":"KRKD","lat":44.06667,"lon":-69.1,"state":"ME","location":"Rockland, Knox County Regional Airport","city":"Rockland","priority":10}, + "KSFM": {"id":"KSFM","lat":43.4,"lon":-70.7166699,"state":"ME","location":"Sanford, Sanford Regional Airport","city":"Sanford","priority":3}, + "KWVL": {"id":"KWVL","lat":44.53333,"lon":-69.68333,"state":"ME","location":"Waterville, Waterville Robert LaFleur Airport","city":"Waterville","priority":13}, + "KABR": {"id":"KABR","lat":45.44333,"lon":-98.41306,"state":"SD","location":"Aberdeen, Aberdeen Regional Airport","city":"Aberdeen","priority":3}, + "KAGZ": {"id":"KAGZ","lat":43.06332,"lon":-98.29618,"state":"SD","location":"WAGNERMUNC","city":"Wagnermunc","priority":99}, + "KATY": {"id":"KATY","lat":44.90472,"lon":-97.14944,"state":"SD","location":"Watertown, Watertown Municipal Airport","city":"Watertown","priority":9}, + "KBKX": {"id":"KBKX","lat":44.3,"lon":-96.81667,"state":"SD","location":"Brookings, Brookings Municipal Airport","city":"Brookings","priority":9}, + "KBTN": {"id":"KBTN","lat":45.8152199,"lon":-97.7431299,"state":"SD","location":"BRITTON","city":"Britton","priority":99}, + "KCUT": {"id":"KCUT","lat":43.73306,"lon":-103.6175,"state":"SD","location":"Custer, Custer County Airport","city":"Custer","priority":10}, + "KEFC": {"id":"KEFC","lat":44.7342,"lon":-103.86199,"state":"SD","location":"BELLEFCHE","city":"Bellefche","priority":99}, + "KFSD": {"id":"KFSD","lat":43.57694,"lon":-96.75361,"state":"SD","location":"Sioux Falls, Foss Field","city":"Sioux Falls","priority":12}, + "KHON": {"id":"KHON","lat":44.38806,"lon":-98.22833,"state":"SD","location":"Huron, Huron Regional Airport","city":"Huron","priority":3}, + "KHSR": {"id":"KHSR","lat":43.36824,"lon":-103.38813,"state":"SD","location":"HOTSPRINGS","city":"Hotsprings","priority":99}, + "KICR": {"id":"KICR","lat":43.39056,"lon":-99.8425,"state":"SD","location":"Winner, Bob Wiley Field Airport","city":"Winner","priority":12}, + "KIEN": {"id":"KIEN","lat":43.02556,"lon":-102.52306,"state":"SD","location":"Pine Ridge, Pine Ridge Airport","city":"Pine Ridge","priority":13}, + "KLEM": {"id":"KLEM","lat":45.91869,"lon":-102.10617,"state":"SD","location":"LEMMON","city":"Lemmon","priority":99}, + "KMBG": {"id":"KMBG","lat":45.55,"lon":-100.40861,"state":"SD","location":"Mobridge, Mobridge Municipal Airport","city":"Mobridge","priority":9}, + "KMDS": {"id":"KMDS","lat":44.0164147,"lon":-97.0855992,"state":"SD","location":"Madison Municipal Airport","city":"Madison","priority":9}, + "KMHE": {"id":"KMHE","lat":43.76667,"lon":-98.03333,"state":"SD","location":"Mitchell, Mitchell Municipal Airport","city":"Mitchell","priority":9}, + "KMKA": {"id":"KMKA","lat":44.5252399,"lon":-98.95811,"state":"SD","location":"MILLERMUNC","city":"Millermunc","priority":99}, + "KPHP": {"id":"KPHP","lat":44.05111,"lon":-101.60111,"state":"SD","location":"Philip, Philip Airport","city":"Philip","priority":13}, + "KPIR": {"id":"KPIR","lat":44.3827799,"lon":-100.28583,"state":"SD","location":"Pierre, Pierre Regional Airport","city":"Pierre","priority":3}, + "KRAP": {"id":"KRAP","lat":44.04556,"lon":-103.05389,"state":"SD","location":"Rapid City, Rapid City Regional Airport","city":"Rapid City","priority":3}, + "KRCA": {"id":"KRCA","lat":44.15,"lon":-103.1,"state":"SD","location":"Ellsworth Air Force Base","city":"Ellsworth","priority":14}, + "KSPF": {"id":"KSPF","lat":44.48333,"lon":-103.78333,"state":"SD","location":"Spearfish / Clyde Ice","city":"Spearfish","priority":99}, + "KSUO": {"id":"KSUO","lat":43.25846,"lon":-100.8594899,"state":"SD","location":"Rosebud Sioux Tribal Airport","city":"Rosebud Sioux Tribal","priority":13}, + "KVMR": {"id":"KVMR","lat":42.76528,"lon":-96.93425,"state":"SD","location":"VERMILLION","city":"Vermillion","priority":99}, + "KYKN": {"id":"KYKN","lat":42.91667,"lon":-97.38333,"state":"SD","location":"Yankton, Chan Gurney Municipal Airport","city":"Yankton","priority":9}, + "KAID": {"id":"KAID","lat":40.10612,"lon":-85.60977,"state":"IN","location":"Anderson Municipal Airport","city":"Anderson","priority":9}, + "KANQ": {"id":"KANQ","lat":41.6404,"lon":-85.0851,"state":"IN","location":"Angola Tri-State Steuben County Airport","city":"Angola Tri-State","priority":10}, + "KASW": {"id":"KASW","lat":41.27444,"lon":-85.84,"state":"IN","location":"Warsaw, Warsaw Municipal Airport","city":"Warsaw","priority":9}, + "KBAK": {"id":"KBAK","lat":39.26667,"lon":-85.9,"state":"IN","location":"Columbus / Bakalar","city":"Columbus","priority":99}, + "KBFR": {"id":"KBFR","lat":38.84003,"lon":-86.4453599,"state":"IN","location":"Virgil I Grissom Municipal Airport","city":"Virgil I Grissom","priority":9}, + "KBMG": {"id":"KBMG","lat":39.14306,"lon":-86.61667,"state":"IN","location":"Bloomington, Monroe County Airport","city":"Bloomington","priority":10}, + "KCFJ": {"id":"KCFJ","lat":39.9756,"lon":-86.9199,"state":"IN","location":"Crawfordsville Municipal Airport","city":"Crawfordsville","priority":9}, + "KDCY": {"id":"KDCY","lat":38.7004,"lon":-87.1297,"state":"IN","location":"Daviess County Airport","city":"Daviess Co.","priority":10}, + "KEKM": {"id":"KEKM","lat":41.71667,"lon":-86,"state":"IN","location":"Elkhart Municipal","city":"Elkhart","priority":9}, + "KEVV": {"id":"KEVV","lat":38.0430599,"lon":-87.52028,"state":"IN","location":"Evansville, Evansville Regional Airport","city":"Evansville","priority":3}, + "KEYE": {"id":"KEYE","lat":39.825,"lon":-86.29583,"state":"IN","location":"Indianapolis, Eagle Creek Airpark","city":"Eagle Creek","priority":15}, + "KFKR": {"id":"KFKR","lat":40.2734,"lon":-86.5622,"state":"IN","location":"Frankfort Municipal Airport","city":"Frankfort","priority":9}, + "KFRH": {"id":"KFRH","lat":38.50622,"lon":-86.63694,"state":"IN","location":"French Lick Municipal Airport","city":"French Lick","priority":9}, + "KFWA": {"id":"KFWA","lat":40.97251,"lon":-85.20637,"state":"IN","location":"Fort Wayne International Airport","city":"Ft Wayne","priority":1}, + "KGEZ": {"id":"KGEZ","lat":39.58546,"lon":-85.79982,"state":"IN","location":"Shelbyville Municipal Airport","city":"Shelbyville","priority":9}, + "KGGP": {"id":"KGGP","lat":40.711,"lon":-86.373,"state":"IN","location":"Logansport/Cass County Airport","city":"Logansport","priority":10}, + "KGPC": {"id":"KGPC","lat":39.6354,"lon":-86.8155,"state":"IN","location":"Putnam County Regional Airport","city":"Putnam Co.","priority":10}, + "KGSH": {"id":"KGSH","lat":41.52611,"lon":-85.78667,"state":"IN","location":"Goshen, Goshen Municipal Airport","city":"Goshen","priority":9}, + "KGUS": {"id":"KGUS","lat":40.65,"lon":-86.15,"state":"IN","location":"Grissom Air Force Base / Peru","city":"Peru","priority":14}, + "KGWB": {"id":"KGWB","lat":41.307,"lon":-85.0639999,"state":"IN","location":"Auburn De Kalb County Airport","city":"Auburn De","priority":10}, + "KGYY": {"id":"KGYY","lat":41.61212,"lon":-87.40908,"state":"IN","location":"Gary Regional Airport","city":"Gary","priority":3}, + "KHFY": {"id":"KHFY","lat":39.6276,"lon":-86.0879999,"state":"IN","location":"Greenwood Municipal Airport","city":"Greenwood","priority":9}, + "KHHG": {"id":"KHHG","lat":40.8529,"lon":-85.4571,"state":"IN","location":"Huntington Municipal Airport","city":"Huntington","priority":9}, + "KHLB": {"id":"KHLB","lat":39.34313,"lon":-85.25843,"state":"IN","location":"Batesville Airport","city":"Batesville","priority":13}, + "KHNB": {"id":"KHNB","lat":38.25,"lon":-86.95,"state":"IN","location":"Huntingburg","city":"Huntingburg","priority":99}, + "KHUF": {"id":"KHUF","lat":39.4429,"lon":-87.32207,"state":"IN","location":"Terre Haute Regional Airport","city":"Terre Haute","priority":3}, + "KIMS": {"id":"KIMS","lat":38.7589,"lon":-85.4655,"state":"IN","location":"Madison Municipal Airport","city":"Madison","priority":9}, + "KIND": {"id":"KIND","lat":39.72518,"lon":-86.2816,"state":"IN","location":"Indianapolis International Airport","city":"Indianapolis","priority":1}, + "KJVY": {"id":"KJVY","lat":38.36661,"lon":-85.73814,"state":"IN","location":"Clark Regional Airport","city":"Clark","priority":3}, + "KLAF": {"id":"KLAF","lat":40.4125,"lon":-86.9475,"state":"IN","location":"Lafayette, Purdue University Airport","city":"Lafayette","priority":13}, + "KMCX": {"id":"KMCX","lat":40.7087999,"lon":-86.7668,"state":"IN","location":"Monticello White County Airport","city":"Monticello","priority":10}, + "KMGC": {"id":"KMGC","lat":41.7033,"lon":-86.8212,"state":"IN","location":"Michigan City Municipal Airport","city":"Michigan City","priority":9}, + "KMIE": {"id":"KMIE","lat":40.23417,"lon":-85.39361,"state":"IN","location":"Muncie, Delaware County-Johnson Field","city":"Muncie","priority":10}, + "KMQJ": {"id":"KMQJ","lat":39.84314,"lon":-85.89774,"state":"IN","location":"Indianapolis Regional Airport","city":"Indianapolis Regional","priority":3}, + "KMZZ": {"id":"KMZZ","lat":40.49,"lon":-85.68,"state":"IN","location":"Marion Municipal Airport","city":"Marion","priority":9}, + "KOKK": {"id":"KOKK","lat":40.53333,"lon":-86.06667,"state":"IN","location":"Kokomo, Kokomo Municipal Airport","city":"Kokomo","priority":9}, + "KOXI": {"id":"KOXI","lat":41.33,"lon":-86.665,"state":"IN","location":"Starke County Airport","city":"Starke Co.","priority":10}, + "KPLD": {"id":"KPLD","lat":40.45158,"lon":-84.98903,"state":"IN","location":"Portland Municipal Airport","city":"Portland","priority":9}, + "KPPO": {"id":"KPPO","lat":41.5725,"lon":-86.7345,"state":"IN","location":"La Porte Municipal Airport","city":"La Porte","priority":9}, + "KRCR": {"id":"KRCR","lat":41.06553,"lon":-86.18169,"state":"IN","location":"Rochester Fulton County Airport","city":"Rochester","priority":10}, + "KRID": {"id":"KRID","lat":39.7572,"lon":-84.8428,"state":"IN","location":"Richmond Municipal Airport","city":"Richmond","priority":9}, + "KRZL": {"id":"KRZL","lat":40.94789,"lon":-87.18258,"state":"IN","location":"Rensselaer Jasper County Airport","city":"Rensselaer","priority":10}, + "KSBN": {"id":"KSBN","lat":41.7088899,"lon":-86.31861,"state":"IN","location":"South Bend International Airport","city":"South Bend","priority":1}, + "KSMD": {"id":"KSMD","lat":41.14336,"lon":-85.15277,"state":"IN","location":"Smith Field Airport","city":"Smith","priority":12}, + "KTYQ": {"id":"KTYQ","lat":40.03066,"lon":-86.2514999,"state":"IN","location":"INDIANAPOLIS","city":"TYQ","priority":99}, + "KUMP": {"id":"KUMP","lat":39.9354,"lon":-86.04507,"state":"IN","location":"Indianapolis Metro Airport","city":"Indianapolis Metro","priority":13}, + "KUWL": {"id":"KUWL","lat":39.87672,"lon":-85.32527,"state":"IN","location":"New Castle Henry County Airport","city":"New Castle","priority":10}, + "KVPZ": {"id":"KVPZ","lat":41.45349,"lon":-86.99805,"state":"IN","location":"Valparaiso Porter County Municipal Airport","city":"Valparaiso","priority":10}, + "KBAC": {"id":"KBAC","lat":46.9412,"lon":-98.018,"state":"ND","location":"Valley City","city":"Valley City","priority":99}, + "KBIS": {"id":"KBIS","lat":46.7825,"lon":-100.75722,"state":"ND","location":"Bismarck, Bismarck Municipal Airport","city":"Bismarck","priority":9}, + "KBWP": {"id":"KBWP","lat":46.24389,"lon":-96.60722,"state":"ND","location":"Wahpeton, Harry Stern Airport","city":"Wahpeton","priority":13}, + "KBWW": {"id":"KBWW","lat":46.16551,"lon":-103.30074,"state":"ND","location":"Bowman Regional Airport","city":"Bowman","priority":3}, + "KDIK": {"id":"KDIK","lat":46.79722,"lon":-102.80194,"state":"ND","location":"Dickinson, Dickinson Municipal Airport","city":"Dickinson","priority":9}, + "KDVL": {"id":"KDVL","lat":48.11667,"lon":-98.91667,"state":"ND","location":"Devils Lake, Devils Lake Municipal Airport","city":"Devils Lake","priority":9}, + "KFAR": {"id":"KFAR","lat":46.92528,"lon":-96.81111,"state":"ND","location":"Fargo, Hector International Airport","city":"Fargo","priority":1}, + "KGAF": {"id":"KGAF","lat":48.4,"lon":-97.37,"state":"ND","location":"GRAFTON","city":"Grafton","priority":99}, + "KGFK": {"id":"KGFK","lat":47.94806,"lon":-97.1825,"state":"ND","location":"Grand Forks, Grand Forks International Airport","city":"Grand Forks","priority":1}, + "KGWR": {"id":"KGWR","lat":46.2187,"lon":-97.6435,"state":"ND","location":"Gwinner","city":"Gwinner","priority":99}, + "KHEI": {"id":"KHEI","lat":46.01056,"lon":-102.64972,"state":"ND","location":"Hettinger, Hettinger Municipal Airport","city":"Hettinger","priority":9}, + "KHZE": {"id":"KHZE","lat":47.28,"lon":-101.58,"state":"ND","location":"HAZEN","city":"Hazen","priority":99}, + "KJMS": {"id":"KJMS","lat":46.92972,"lon":-98.67833,"state":"ND","location":"Jamestown, Jamestown Municipal Airport","city":"Jamestown","priority":9}, + "KMIB": {"id":"KMIB","lat":48.41667,"lon":-101.35,"state":"ND","location":"Minot Air Force Base","city":"Minot AFB","priority":14}, + "KMOT": {"id":"KMOT","lat":48.25203,"lon":-101.2689,"state":"ND","location":"Minot International Airport","city":"Minot","priority":1}, + "KRDR": {"id":"KRDR","lat":47.96667,"lon":-97.4,"state":"ND","location":"Grand Forks Air Force Base","city":"Grand Forks AFB","priority":14}, + "KRUG": {"id":"KRUG","lat":48.38,"lon":-100.02,"state":"ND","location":"RUGBY","city":"Rugby","priority":99}, + "KXWA": {"id":"KXWA","lat":48.26086,"lon":-103.75114,"state":"ND","location":"Williston Basin International Airport","city":"Williston Basin","priority":1}, + "KBAM": {"id":"KBAM","lat":40.5989999,"lon":-116.8743,"state":"NV","location":"Battle Mountain - Lander County Airport","city":"Battle Mtn","priority":10}, + "KBVU": {"id":"KBVU","lat":35.9475,"lon":-114.8611,"state":"NV","location":"Boulder City Municipal Airport","city":"Boulder City","priority":9}, + "KCXP": {"id":"KCXP","lat":39.19056,"lon":-119.73191,"state":"NV","location":"Carson City Airport","city":"Carson City","priority":13}, + "KDRA": {"id":"KDRA","lat":36.6207,"lon":-116.02868,"state":"NV","location":"Mercury, Desert Rock Airport","city":"Mercury","priority":13}, + "KEKO": {"id":"KEKO","lat":40.8240399,"lon":-115.78635,"state":"NV","location":"Elko, Elko Regional Airport","city":"Elko","priority":3}, + "KELY": {"id":"KELY","lat":39.295,"lon":-114.84528,"state":"NV","location":"Ely, Ely Airport","city":"Ely","priority":13}, + "KHND": {"id":"KHND","lat":35.97665,"lon":-115.13221,"state":"NV","location":"Las Vegas - Henderson Executive Airport","city":"Henderson","priority":5}, + "KHTH": {"id":"KHTH","lat":38.54482,"lon":-118.63137,"state":"NV","location":"Hawthorne Industrial Airport","city":"Hawthorne Industrial","priority":13}, + "KINS": {"id":"KINS","lat":36.58573,"lon":-115.69008,"state":"NV","location":"Nellis AFB - Indian Springs Auxiliary Airfield","city":"Nellis","priority":14}, + "KLAS": {"id":"KLAS","lat":36.07188,"lon":-115.1634,"state":"NV","location":"Harry Reid International Airport","city":"Las Vegas","priority":1}, + "KLOL": {"id":"KLOL","lat":40.0683999,"lon":-118.57017,"state":"NV","location":"Lovelock, Derby Field Airport","city":"Lovelock","priority":12}, + "KLSV": {"id":"KLSV","lat":36.23333,"lon":-115.03333,"state":"NV","location":"Nellis Air Force Base","city":"Nellis AFB","priority":14}, + "KMEV": {"id":"KMEV","lat":38.9963,"lon":-119.75,"state":"NV","location":"Minden-Tahoe Airport","city":"Minden","priority":13}, + "KNFL": {"id":"KNFL","lat":39.43222,"lon":-118.68556,"state":"NV","location":"Fallon, Naval Air Station","city":"Fallon","priority":14}, + "KRNO": {"id":"KRNO","lat":39.50776,"lon":-119.76819,"state":"NV","location":"Reno, Reno Tahoe International Airport","city":"Reno","priority":1}, + "KRTS": {"id":"KRTS","lat":39.6682,"lon":-119.8764,"state":"NV","location":"Reno/Stead","city":"Stead","priority":99}, + "KTMT": {"id":"KTMT","lat":39.46794,"lon":-117.19745,"state":"NV","location":"Austin Airport","city":"Austin","priority":13}, + "KTPH": {"id":"KTPH","lat":38.06028,"lon":-117.08722,"state":"NV","location":"Tonopah, Tonopah Airport","city":"Tonopah","priority":13}, + "KVGT": {"id":"KVGT","lat":36.21205,"lon":-115.19395,"state":"NV","location":"Las Vegas, North Las Vegas Airport","city":"North Las Vegas","priority":13}, + "KWMC": {"id":"KWMC","lat":40.90194,"lon":-117.80722,"state":"NV","location":"Winnemucca, Winnemucca Municipal Airport","city":"Winnemucca","priority":9}, + "KADH": {"id":"KADH","lat":34.80444,"lon":-96.67139,"state":"OK","location":"Ada, Ada Municipal Airport","city":"Ada","priority":9}, + "KADM": {"id":"KADM","lat":34.30306,"lon":-97.01944,"state":"OK","location":"Ardmore, Ardmore Municipal Airport","city":"Ardmore","priority":9}, + "KAVK": {"id":"KAVK","lat":36.77306,"lon":-98.67,"state":"OK","location":"Alva, Alva Regional Airport","city":"Alva","priority":3}, + "KAXS": {"id":"KAXS","lat":34.69861,"lon":-99.33806,"state":"OK","location":"Altus, Altus/Quartz Mountain Regional Airport","city":"Altus","priority":3}, + "KBKN": {"id":"KBKN","lat":36.7451099,"lon":-97.34958,"state":"OK","location":"Blackwell-Tonkawa Municipal Airport","city":"Blackwell","priority":9}, + "KBVO": {"id":"KBVO","lat":36.76833,"lon":-96.02611,"state":"OK","location":"Bartlesville, Bartlesville Municipal Airport","city":"Bartlesville","priority":9}, + "KCHK": {"id":"KCHK","lat":35.09611,"lon":-97.96611,"state":"OK","location":"Chickasha, Chickasha Municipal Airport","city":"Chickasha","priority":9}, + "KCLK": {"id":"KCLK","lat":35.53806,"lon":-98.92139,"state":"OK","location":"Clinton, Clinton Regional Airport","city":"Clinton","priority":3}, + "KCQB": {"id":"KCQB","lat":35.72389,"lon":-96.82028,"state":"OK","location":"Chandler, Chandler Municipal Airport","city":"Chandler","priority":9}, + "KCSM": {"id":"KCSM","lat":35.35667,"lon":-99.20361,"state":"OK","location":"Clinton, Clinton-Sherman Airport","city":"Sherman","priority":13}, + "KCUH": {"id":"KCUH","lat":35.94972,"lon":-96.77278,"state":"OK","location":"Cushing, Cushing Municipal Airport","city":"Cushing","priority":9}, + "KDUA": {"id":"KDUA","lat":33.94222,"lon":-96.39444,"state":"OK","location":"Durant, Eaker Field Airport","city":"Durant","priority":12}, + "KDUC": {"id":"KDUC","lat":34.47083,"lon":-97.9599999,"state":"OK","location":"Duncan, Halliburton Field Airport","city":"Duncan","priority":12}, + "KELK": {"id":"KELK","lat":35.4308,"lon":-99.3943,"state":"OK","location":"Elk City Regional Business Airport","city":"Elk City","priority":7}, + "KEND": {"id":"KEND","lat":36.3333299,"lon":-97.91667,"state":"OK","location":"Vance Air Force Base / Enid","city":"Vance AFB","priority":14}, + "KFDR": {"id":"KFDR","lat":34.34444,"lon":-98.98306,"state":"OK","location":"Frederick, Frederick Municipal Airport","city":"Frederick","priority":9}, + "KFSI": {"id":"KFSI","lat":34.6,"lon":-98.4,"state":"OK","location":"Fort Sill","city":"Ft Sill","priority":99}, + "KGAG": {"id":"KGAG","lat":36.29667,"lon":-99.76889,"state":"OK","location":"Gage, Gage Airport","city":"Gage","priority":13}, + "KGCM": {"id":"KGCM","lat":36.29444,"lon":-95.47972,"state":"OK","location":"Claremore, Claremore Regional Airport","city":"Claremore","priority":3}, + "KGMJ": {"id":"KGMJ","lat":36.60528,"lon":-94.73861,"state":"OK","location":"Grove, Grove Municipal Airport","city":"Grove","priority":9}, + "KGOK": {"id":"KGOK","lat":35.85194,"lon":-97.4075,"state":"OK","location":"Guthrie, Guthrie Municipal Airport","city":"Guthrie","priority":9}, + "KGUY": {"id":"KGUY","lat":36.6816699,"lon":-101.50528,"state":"OK","location":"Guymon / Guymon Municipal Airport","city":"Guymon","priority":9}, + "KGZL": {"id":"KGZL","lat":35.2891,"lon":-95.0939,"state":"OK","location":"Stigler","city":"Stigler","priority":99}, + "KHBR": {"id":"KHBR","lat":34.98944,"lon":-99.0525,"state":"OK","location":"Hobart, Hobart Municipal Airport","city":"Hobart","priority":9}, + "KHHW": {"id":"KHHW","lat":34.0348,"lon":-95.5419,"state":"OK","location":"Hugo Stan Stamper Municipal Airport","city":"Hugo Stan Stamper","priority":9}, + "KHMY": {"id":"KHMY","lat":35.02638,"lon":-97.23163,"state":"OK","location":"MULDROWARMY","city":"Muldrowarmy","priority":99}, + "KHSD": {"id":"KHSD","lat":35.60183,"lon":-97.70616,"state":"OK","location":"Sundance Airport","city":"Sundance","priority":13}, + "KJSV": {"id":"KJSV","lat":35.43806,"lon":-94.80278,"state":"OK","location":"Sallisaw, Sallisaw Municipal Airport","city":"Sallisaw","priority":9}, + "KJWG": {"id":"KJWG","lat":35.86472,"lon":-98.42083,"state":"OK","location":"Watonga, Watonga Airport","city":"Watonga","priority":13}, + "KLAW": {"id":"KLAW","lat":34.5575,"lon":-98.41667,"state":"OK","location":"Lawton, Lawton Municipal Airport","city":"Lawton","priority":9}, + "KLTS": {"id":"KLTS","lat":34.65,"lon":-99.26667,"state":"OK","location":"Altus Air Force Base","city":"Altus AFB","priority":14}, + "KMIO": {"id":"KMIO","lat":36.90922,"lon":-94.8875,"state":"OK","location":"Miami Regional Airport","city":"Miami","priority":3}, + "KMKO": {"id":"KMKO","lat":35.65694,"lon":-95.35972,"state":"OK","location":"Muskogee-Davis Regional Airport","city":"Muskogee","priority":3}, + "KMLC": {"id":"KMLC","lat":34.8822199,"lon":-95.78306,"state":"OK","location":"McAlester, McAlester Regional Airport","city":"McAlester","priority":3}, + "KOJA": {"id":"KOJA","lat":35.54472,"lon":-98.66833,"state":"OK","location":"Weatherford, Thomas P Stafford Airport","city":"Weatherford","priority":13}, + "KOKC": {"id":"KOKC","lat":35.38861,"lon":-97.60028,"state":"OK","location":"Oklahoma City, Will Rogers World Airport","city":"Oklahoma City","priority":13}, + "KOKM": {"id":"KOKM","lat":35.6680599,"lon":-95.94861,"state":"OK","location":"Okmulgee, Okmulgee Municipal Airport","city":"Okmulgee","priority":9}, + "KOUN": {"id":"KOUN","lat":35.2435,"lon":-97.4708,"state":"OK","location":"Norman / Max Westheimer","city":"Norman","priority":99}, + "KOWP": {"id":"KOWP","lat":36.1753,"lon":-96.1518,"state":"OK","location":"William R Pogue Municipal Airport","city":"William R Pogue","priority":9}, + "KPNC": {"id":"KPNC","lat":36.7305599,"lon":-97.09972,"state":"OK","location":"Ponca City, Ponca City Municipal Airport","city":"Ponca City","priority":9}, + "KPVJ": {"id":"KPVJ","lat":34.71111,"lon":-97.22333,"state":"OK","location":"Pauls Valley, Pauls Valley Municipal Airport","city":"Pauls Valley","priority":9}, + "KPWA": {"id":"KPWA","lat":35.54111,"lon":-97.64667,"state":"OK","location":"Oklahoma City, Wiley Post Airport","city":"Wiley Post","priority":13}, + "KRCE": {"id":"KRCE","lat":35.4880799,"lon":-97.82356,"state":"OK","location":"Clarence E Page Municipal Airport","city":"Clarence E Page","priority":9}, + "KRKR": {"id":"KRKR","lat":35.02167,"lon":-94.62139,"state":"OK","location":"Poteau, Robert S Kerr Airport","city":"Poteau","priority":13}, + "KRQO": {"id":"KRQO","lat":35.4724999,"lon":-98.00556,"state":"OK","location":"El Reno, El Reno Regional Airport","city":"El Reno","priority":3}, + "KRVS": {"id":"KRVS","lat":36.04255,"lon":-95.99005,"state":"OK","location":"Tulsa - Jones Jr. Airport","city":"Jones Jr.","priority":13}, + "KSNL": {"id":"KSNL","lat":35.35722,"lon":-96.94278,"state":"OK","location":"Shawnee, Shawnee Municipal Airport","city":"Shawnee","priority":9}, + "KSRE": {"id":"KSRE","lat":35.27444,"lon":-96.675,"state":"OK","location":"Seminole, Seminole Municipal Airport","city":"Seminole","priority":9}, + "KSWO": {"id":"KSWO","lat":36.16222,"lon":-97.08917,"state":"OK","location":"Stillwater, Stillwater Regional Airport","city":"Stillwater","priority":3}, + "KTIK": {"id":"KTIK","lat":35.41667,"lon":-97.38333,"state":"OK","location":"Tinker Air Force Base","city":"Tinker","priority":14}, + "KTQH": {"id":"KTQH","lat":35.92889,"lon":-95.00444,"state":"OK","location":"Tahlequah, Tahlequah Municipal Airport","city":"Tahlequah","priority":9}, + "KTUL": {"id":"KTUL","lat":36.1975,"lon":-95.88639,"state":"OK","location":"Tulsa, Tulsa International Airport","city":"Tulsa","priority":1}, + "KWDG": {"id":"KWDG","lat":36.37917,"lon":-97.79111,"state":"OK","location":"Enid, Enid Woodring Regional Airport","city":"Enid","priority":3}, + "KWWR": {"id":"KWWR","lat":36.43667,"lon":-99.5211099,"state":"OK","location":"Woodward, West Woodward Airport","city":"Woodward","priority":13}, + "KBKW": {"id":"KBKW","lat":37.795,"lon":-81.12472,"state":"WV","location":"Beckley, Raleigh County Memorial Airport","city":"Beckley","priority":10}, + "KBLF": {"id":"KBLF","lat":37.29583,"lon":-81.20778,"state":"WV","location":"Bluefield, Mercer County Airport","city":"Bluefield","priority":10}, + "KCBE": {"id":"KCBE","lat":39.61528,"lon":-78.76083,"state":"WV","location":"Cumberland, Greater Cumberland Regional Airport","city":"Cumberland","priority":3}, + "KCKB": {"id":"KCKB","lat":39.3,"lon":-80.22472,"state":"WV","location":"Clarksburg, Clarksburg Benedum Airport","city":"Clarksburg","priority":13}, + "KCRW": {"id":"KCRW","lat":38.37944,"lon":-81.59139,"state":"WV","location":"Charleston, Yeager Airport","city":"Charleston","priority":13}, + "KEKN": {"id":"KEKN","lat":38.88528,"lon":-79.85278,"state":"WV","location":"Elkins, Elkins-Randolph County-Jennings Randolph Field","city":"Elkins","priority":10}, + "KHLG": {"id":"KHLG","lat":40.17028,"lon":-80.64444,"state":"WV","location":"Wheeling, Wheeling Ohio County Airport","city":"Wheeling","priority":10}, + "KHTS": {"id":"KHTS","lat":38.365,"lon":-82.555,"state":"WV","location":"Huntington, Tri-State Airport","city":"Huntington","priority":13}, + "KLWB": {"id":"KLWB","lat":37.86667,"lon":-80.4,"state":"WV","location":"Lewisburg / Greenbrier","city":"Lewisburg","priority":99}, + "KMGW": {"id":"KMGW","lat":39.64985,"lon":-79.92065,"state":"WV","location":"Morgantown Municipal-Hart Field","city":"Morgantown","priority":9}, + "KMRB": {"id":"KMRB","lat":39.40372,"lon":-77.975,"state":"WV","location":"Eastern WV Regional Airport/Shepherd Field","city":"Eastern WV","priority":3}, + "KPKB": {"id":"KPKB","lat":39.345,"lon":-81.43917,"state":"WV","location":"Parkersburg, Mid-Ohio Valley Regional Airport","city":"Parkersburg","priority":3}, + "KBGF": {"id":"KBGF","lat":35.1775,"lon":-86.0662,"state":"TN","location":"Winchester Municipal Airport","city":"Winchester","priority":9}, + "KBNA": {"id":"KBNA","lat":36.11889,"lon":-86.68917,"state":"TN","location":"Nashville, Nashville International Airport","city":"Nashville","priority":1}, + "KCHA": {"id":"KCHA","lat":35.03333,"lon":-85.2,"state":"TN","location":"Chattanooga, Lovell Field","city":"Chattanooga","priority":12}, + "KCKV": {"id":"KCKV","lat":36.61689,"lon":-87.41174,"state":"TN","location":"Clarksville Outlaw Field","city":"Clarksville Outlaw","priority":12}, + "KCSV": {"id":"KCSV","lat":35.95139,"lon":-85.0849999,"state":"TN","location":"Crossville, Crossville Memorial-Whitson Field Airport","city":"Crossville","priority":11}, + "KDKX": {"id":"KDKX","lat":35.96581,"lon":-83.87169,"state":"TN","location":"Knoxville Downtown Airport","city":"Knoxville Downtown","priority":13}, + "KDYR": {"id":"KDYR","lat":36,"lon":-89.4,"state":"TN","location":"Dyersburg, Dyersburg Municipal Airport","city":"Dyersburg","priority":9}, + "KFYE": {"id":"KFYE","lat":35.2061,"lon":-89.3929,"state":"TN","location":"Somerville - Fayette County Airport","city":"Somerville","priority":10}, + "KFYM": {"id":"KFYM","lat":35.0597,"lon":-86.5639999,"state":"TN","location":"Fayetteville Municipal Airport","city":"Fayetteville","priority":9}, + "KGCY": {"id":"KGCY","lat":36.19601,"lon":-82.81099,"state":"TN","location":"Greeneville-Greene County Municipal Airport","city":"Greeneville","priority":10}, + "KGKT": {"id":"KGKT","lat":35.85681,"lon":-83.53334,"state":"TN","location":"Sevierville Gatlinburg - Pigeon Forge Airport","city":"Sevierville Gatlinburg","priority":13}, + "KGZS": {"id":"KGZS","lat":35.1537,"lon":-87.0568,"state":"TN","location":"Pulaski Abernathy Field Airport","city":"Pulaski Abernathy","priority":12}, + "KHZD": {"id":"KHZD","lat":36.08896,"lon":-88.46538,"state":"TN","location":"Huntingdon Carroll County Airport","city":"Huntingdon","priority":10}, + "KJAU": {"id":"KJAU","lat":36.3341,"lon":-84.163,"state":"TN","location":"Jacksboro Campbell County Airport","city":"Jacksboro","priority":10}, + "KJWN": {"id":"KJWN","lat":36.18521,"lon":-86.88331,"state":"TN","location":"John C Tune Airport","city":"John C Tune","priority":13}, + "KLUG": {"id":"KLUG","lat":35.50697,"lon":-86.80389,"state":"TN","location":"Ellington Airport","city":"Ellington","priority":13}, + "KMBT": {"id":"KMBT","lat":35.87866,"lon":-86.37749,"state":"TN","location":"Murfreesboro Municipal Airport","city":"Murfreesboro","priority":9}, + "KMEM": {"id":"KMEM","lat":35.05644,"lon":-89.98634,"state":"TN","location":"Memphis International Airport","city":"Memphis","priority":1}, + "KMKL": {"id":"KMKL","lat":35.59306,"lon":-88.91667,"state":"TN","location":"Jackson, McKellar-Sipes Regional Airport","city":"Jackson","priority":3}, + "KMMI": {"id":"KMMI","lat":35.3973,"lon":-84.5626,"state":"TN","location":"Athens McMinn County Airport","city":"Athens","priority":10}, + "KAIK": {"id":"KAIK","lat":33.649,"lon":-81.685,"state":"SC","location":"Aiken Municipal Airport","city":"Aiken","priority":9}, + "KAND": {"id":"KAND","lat":34.49778,"lon":-82.70972,"state":"SC","location":"Anderson, Anderson County Airport","city":"Anderson","priority":10}, + "KAQX": {"id":"KAQX","lat":32.9951,"lon":-81.2703,"state":"SC","location":"Allendale County Airport","city":"Allendale Co.","priority":10}, + "KARW": {"id":"KARW","lat":32.412,"lon":-80.634,"state":"SC","location":"Beaufort County Airport","city":"Beaufort Co.","priority":10}, + "KBBP": {"id":"KBBP","lat":34.622,"lon":-79.734,"state":"SC","location":"Marlboro County Jetport","city":"Marlboro Co.","priority":10}, + "KBNL": {"id":"KBNL","lat":33.258,"lon":-81.388,"state":"SC","location":"Barnwell Regional Airport","city":"Barnwell","priority":3}, + "KCAE": {"id":"KCAE","lat":33.94194,"lon":-81.11806,"state":"SC","location":"Columbia, Columbia Metropolitan Airport","city":"Columbia","priority":13}, + "KCDN": {"id":"KCDN","lat":34.284,"lon":-80.565,"state":"SC","location":"Camden Woodward Field","city":"Camden Woodward","priority":12}, + "KCEU": {"id":"KCEU","lat":34.67222,"lon":-82.88139,"state":"SC","location":"Clemson, Clemson-Oconee County Airport","city":"Clemson","priority":10}, + "KCHS": {"id":"KCHS","lat":32.89889,"lon":-80.04056,"state":"SC","location":"Charleston, Charleston Air Force Base","city":"Charleston AFB","priority":14}, + "KCKI": {"id":"KCKI","lat":33.717,"lon":-79.857,"state":"SC","location":"Kingstree Williamsburg Regional Airport","city":"Kingstree Williamsburg","priority":3}, + "KCQW": {"id":"KCQW","lat":34.713,"lon":-79.9569999,"state":"SC","location":"Cheraw Municipal Lynch Bellinger Field","city":"Cheraw","priority":9}, + "KCRE": {"id":"KCRE","lat":33.81619,"lon":-78.7204299,"state":"SC","location":"North Myrtle Beach Grand Strand Airport","city":"North Myrtle Beach Grand Strand","priority":13}, + "KCUB": {"id":"KCUB","lat":33.97083,"lon":-80.99444,"state":"SC","location":"Columbia - Jim Hamilton L.B. Owens Airport","city":"Jim Hamilton LB Owens","priority":13}, + "KDCM": {"id":"KDCM","lat":34.789,"lon":-81.196,"state":"SC","location":"Chester Catawba Regional Airport","city":"Chester Catawba","priority":3}, + "KDYB": {"id":"KDYB","lat":33.063,"lon":-80.279,"state":"SC","location":"Summerville Airport","city":"Summerville","priority":13}, + "KEOE": {"id":"KEOE","lat":34.309,"lon":-81.64,"state":"SC","location":"Newberry County Airport","city":"Newberry Co.","priority":10}, + "KFDW": {"id":"KFDW","lat":34.315,"lon":-81.109,"state":"SC","location":"Winnsboro/Fairfield County Airport","city":"Winnsboro","priority":10}, + "KFLO": {"id":"KFLO","lat":34.1877799,"lon":-79.73083,"state":"SC","location":"Florence - Florence Regional Airport","city":"Florence","priority":3}, + "KGGE": {"id":"KGGE","lat":33.3117,"lon":-79.3196,"state":"SC","location":"Georgetown County Airport ","city":"Georgetown Co.","priority":10}, + "KGMU": {"id":"KGMU","lat":34.84873,"lon":-82.35004,"state":"SC","location":"Greenville Downtown Airport","city":"Greenville Downtown","priority":13}, + "KGRD": {"id":"KGRD","lat":34.24722,"lon":-82.15472,"state":"SC","location":"Greenwood, Greenwood County Airport","city":"Greenwood","priority":10}, + "KGSP": {"id":"KGSP","lat":34.90611,"lon":-82.2125499,"state":"SC","location":"Greenville Spartanburg International Airport","city":"Greenville","priority":1}, + "KGYH": {"id":"KGYH","lat":34.7583,"lon":-82.3764,"state":"SC","location":"Greenville-Donaldson Center Airport","city":"Donaldson Center","priority":13}, + "KHVS": {"id":"KHVS","lat":34.403,"lon":-80.119,"state":"SC","location":"Hartsville Regional Airport","city":"Hartsville","priority":3}, + "KHXD": {"id":"KHXD","lat":32.21667,"lon":-80.7,"state":"SC","location":"Hilton Head Island, Hilton Head Airport","city":"Hilton Head Is.","priority":13}, + "KHYW": {"id":"KHYW","lat":33.829,"lon":-79.122,"state":"SC","location":"Conway Horry County Airport","city":"Conway","priority":10}, + "KJZI": {"id":"KJZI","lat":32.701,"lon":-80.003,"state":"SC","location":"Charleston Executive Airport","city":"Charleston","priority":5}, + "KLKR": {"id":"KLKR","lat":34.723,"lon":-80.855,"state":"SC","location":"Lancaster County-mc Whirter Field","city":"Lancaster Co.","priority":10}, + "KLQK": {"id":"KLQK","lat":34.80997,"lon":-82.70289,"state":"SC","location":"Pickens County Airport","city":"Pickens Co.","priority":10}, + "KLRO": {"id":"KLRO","lat":32.898,"lon":-79.783,"state":"SC","location":"Mount Pleasant Regional-Faison Field","city":"Mt Pleasant","priority":3}, + "KLUX": {"id":"KLUX","lat":34.507,"lon":-81.947,"state":"SC","location":"Laurens County Airport","city":"Laurens Co.","priority":10}, + "KMAO": {"id":"KMAO","lat":34.181,"lon":-79.3349999,"state":"SC","location":"Marion County Airport","city":"Marion Co.","priority":10}, + "KMKS": {"id":"KMKS","lat":33.1855,"lon":-80.0361999,"state":"SC","location":"Moncks Corner Berkeley County","city":"Moncks Corner","priority":10}, + "KMMT": {"id":"KMMT","lat":33.91667,"lon":-80.8,"state":"SC","location":"McEntire Air National Guard Weather Facility Base","city":"McEntire","priority":2}, + "KMNI": {"id":"KMNI","lat":33.5833299,"lon":-80.2166699,"state":"SC","location":"Manning / Cooper Regional","city":"Manning","priority":3}, + "KMYR": {"id":"KMYR","lat":33.67975,"lon":-78.92833,"state":"SC","location":"Myrtle Beach International Airport","city":"Myrtle Beach","priority":1}, + "KNBC": {"id":"KNBC","lat":32.4936099,"lon":-80.7030599,"state":"SC","location":"Beaufort, Marine Corps Air Station","city":"Beaufort","priority":14}, + "KOGB": {"id":"KOGB","lat":33.46389,"lon":-80.85361,"state":"SC","location":"Orangeburg, Orangeburg Municipal Airport","city":"Orangeburg","priority":9}, + "KRBW": {"id":"KRBW","lat":32.921,"lon":-80.641,"state":"SC","location":"Walterboro Lowcountry Regional Airport","city":"Walterboro Lowcountry","priority":3}, + "KSMS": {"id":"KSMS","lat":33.995,"lon":-80.361,"state":"SC","location":"Sumter Airport","city":"Sumter","priority":13}, + "KSPA": {"id":"KSPA","lat":34.91667,"lon":-81.95,"state":"SC","location":"Spartanburg Memorial","city":"Spartanburg","priority":11}, + "KSSC": {"id":"KSSC","lat":33.96667,"lon":-80.48333,"state":"SC","location":"Shaw Air Force Base","city":"Shaw","priority":14}, + "KUDG": {"id":"KUDG","lat":34.44917,"lon":-79.89028,"state":"SC","location":"Darlington, Darlington County Jetport Airport","city":"Darlington","priority":10}, + "KUZA": {"id":"KUZA","lat":34.98389,"lon":-81.05583,"state":"SC","location":"Rock Hill, Rock Hill - York County Airport","city":"Rock Hill","priority":10}, + "KXNO": {"id":"KXNO","lat":33.60949,"lon":-81.08118,"state":"SC","location":"North Air Force Auxiliary Field","city":"North Air Force","priority":12}, + "KAIG": {"id":"KAIG","lat":45.15659,"lon":-89.11144,"state":"WI","location":"Langlade County Airport","city":"Langlade Co.","priority":10}, + "KARV": {"id":"KARV","lat":45.93333,"lon":-89.73333,"state":"WI","location":"Minocqua/Woodruff, Lakeland Airport/Noble F. Lee Memorial Field","city":"Minocqua","priority":11}, + "KASX": {"id":"KASX","lat":46.54679,"lon":-90.91841,"state":"WI","location":"John F Kennedy Memorial Airport","city":"John F Kennedy","priority":11}, + "KATW": {"id":"KATW","lat":44.2595,"lon":-88.51567,"state":"WI","location":"Appleton-Outagamie","city":"Appleton","priority":99}, + "KAUW": {"id":"KAUW","lat":44.92759,"lon":-89.62512,"state":"WI","location":"Wausau Downtown Airport","city":"Wausau Downtown","priority":13}, + "KBCK": {"id":"KBCK","lat":44.24996,"lon":-90.84999,"state":"WI","location":"Black River Falls Area Airport","city":"Black River Falls Area","priority":13}, + "KBUU": {"id":"KBUU","lat":42.69088,"lon":-88.308,"state":"WI","location":"Burlington Municipal Airport","city":"Burlington","priority":9}, + "KCLI": {"id":"KCLI","lat":44.61526,"lon":-88.73129,"state":"WI","location":"Clintonville Municipal Airport","city":"Clintonville","priority":9}, + "KCMY": {"id":"KCMY","lat":43.9583299,"lon":-90.73778,"state":"WI","location":"Sparta, Sparta / Fort McCoy Airport","city":"Sparta","priority":13}, + "KCWA": {"id":"KCWA","lat":44.77944,"lon":-89.67098,"state":"WI","location":"Mosinee","city":"Mosinee","priority":99}, + "KDLL": {"id":"KDLL","lat":43.52372,"lon":-89.77345,"state":"WI","location":"Baraboo Wisconsin Dells Airport","city":"Baraboo Wisconsin Dells","priority":13}, + "KEAU": {"id":"KEAU","lat":44.86668,"lon":-91.488,"state":"WI","location":"Chippewa Valley Regional Airport","city":"Chippewa Valley","priority":3}, + "KEFT": {"id":"KEFT","lat":42.61959,"lon":-89.59309,"state":"WI","location":"Monroe Municipal Airport","city":"Monroe","priority":9}, + "KEGV": {"id":"KEGV","lat":45.9309299,"lon":-89.26702,"state":"WI","location":"Eagle River Union Airport","city":"Eagle River Union","priority":13}, + "KENW": {"id":"KENW","lat":42.595,"lon":-87.9380599,"state":"WI","location":"Kenosha, Kenosha Regional Airport","city":"Kenosha","priority":3}, + "KETB": {"id":"KETB","lat":43.42256,"lon":-88.1326,"state":"WI","location":"West Bend Municipal Airport","city":"West Bend","priority":9}, + "KEZS": {"id":"KEZS","lat":44.787,"lon":-88.56,"state":"WI","location":"Shawano Municipal Airport","city":"Shawano","priority":9}, + "KFLD": {"id":"KFLD","lat":43.76955,"lon":-88.49072,"state":"WI","location":"Fond Du Lac County Airport","city":"Fond Du","priority":10}, + "KGRB": {"id":"KGRB","lat":44.4794399,"lon":-88.13667,"state":"WI","location":"Green Bay, Austin Straubel International Airport","city":"Green Bay","priority":1}, + "KHYR": {"id":"KHYR","lat":46.03029,"lon":-91.44259,"state":"WI","location":"Sawyer County Airport","city":"Sawyer Co.","priority":10}, + "KISW": {"id":"KISW","lat":44.35917,"lon":-89.83694,"state":"WI","location":"Wisconsin Rapids, Alexander Field South Wood County Airport","city":"Wisconsin Rapids","priority":10}, + "KJVL": {"id":"KJVL","lat":42.62135,"lon":-89.04186,"state":"WI","location":"Janesville-Rock County","city":"Janesville","priority":10}, + "KLNL": {"id":"KLNL","lat":46.1538899,"lon":-89.21194,"state":"WI","location":"Land O' Lakes, Kings Land O' Lakes Airport","city":"Land O' Lakes","priority":13}, + "KLNR": {"id":"KLNR","lat":43.21108,"lon":-90.18735,"state":"WI","location":"Lone Rock Tri-County Regional Airport","city":"Lone Rock Tri-County","priority":3}, + "KLSE": {"id":"KLSE","lat":43.87944,"lon":-91.25667,"state":"WI","location":"La Crosse - La Crosse Regional Airport","city":"La Crosse","priority":3}, + "KLUM": {"id":"KLUM","lat":44.89363,"lon":-91.86652,"state":"WI","location":"Menomonie Municipal Airport-Score Field","city":"Menomonie","priority":9}, + "KMDZ": {"id":"KMDZ","lat":45.10462,"lon":-90.30253,"state":"WI","location":"Taylor County Airport","city":"Taylor Co.","priority":10}, + "KMFI": {"id":"KMFI","lat":44.63806,"lon":-90.1875,"state":"WI","location":"Marshfield, Marshfield Municipal Airport","city":"Marshfield","priority":9}, + "KMKE": {"id":"KMKE","lat":42.955,"lon":-87.9044399,"state":"WI","location":"Milwaukee, General Mitchell International Airport","city":"Milwaukee","priority":1}, + "KMRJ": {"id":"KMRJ","lat":42.88754,"lon":-90.23147,"state":"WI","location":"Iowa County Airport","city":"Iowa Co.","priority":10}, + "KMSN": {"id":"KMSN","lat":43.14056,"lon":-89.34528,"state":"WI","location":"Madison, Dane County Regional-Truax Field","city":"Madison","priority":10}, + "KMTW": {"id":"KMTW","lat":44.13333,"lon":-87.68333,"state":"WI","location":"Manitowoc, Manitowoc County Airport","city":"Manitowoc","priority":10}, + "KMWC": {"id":"KMWC","lat":43.10961,"lon":-88.03048,"state":"WI","location":"Milwaukee-Timmerman","city":"Timmerman","priority":99}, + "KOCQ": {"id":"KOCQ","lat":44.8742,"lon":-87.9096,"state":"WI","location":"Oconto J. Douglas Bake Municipal Airport","city":"Oconto","priority":9}, + "KOEO": {"id":"KOEO","lat":45.31084,"lon":-92.6948,"state":"WI","location":"L O Simenstad Municipal Airport","city":"L O Simenstad","priority":9}, + "KOLG": {"id":"KOLG","lat":46.3148,"lon":-91.8164,"state":"WI","location":"Solon Springs Municipal Airport","city":"Solon Springs","priority":9}, + "KOSH": {"id":"KOSH","lat":43.96701,"lon":-88.55814,"state":"WI","location":"Wittman Regional Airport","city":"Wittman","priority":3}, + "KOVS": {"id":"KOVS","lat":43.15611,"lon":-90.6775,"state":"WI","location":"Boscobel, Boscobel Airport","city":"Boscobel","priority":13}, + "KPBH": {"id":"KPBH","lat":45.7,"lon":-90.4,"state":"WI","location":"Phillips / Price County","city":"Phillips","priority":10}, + "KPCZ": {"id":"KPCZ","lat":44.33425,"lon":-89.02023,"state":"WI","location":"Waupaca Municipal Airport","city":"Waupaca","priority":9}, + "KPDC": {"id":"KPDC","lat":43.01938,"lon":-91.12112,"state":"WI","location":"Prairie Du Chien Municipal Airport","city":"Prairie Du Chien","priority":9}, + "KPVB": {"id":"KPVB","lat":42.69092,"lon":-90.4412399,"state":"WI","location":"Platteville Municipal Airport","city":"Platteville","priority":9}, + "KRAC": {"id":"KRAC","lat":42.75861,"lon":-87.81778,"state":"WI","location":"Racine, Batten International Airport","city":"Racine","priority":1}, + "KRCX": {"id":"KRCX","lat":45.4935,"lon":-90.9985,"state":"WI","location":"Ladysmith - Rusk County Airport","city":"Ladysmith","priority":10}, + "KRGK": {"id":"KRGK","lat":44.5926,"lon":-92.48439,"state":"WI","location":"Red Wing - Red Wing Regional Airport","city":"Red Wing","priority":3}, + "KRHI": {"id":"KRHI","lat":45.63167,"lon":-89.48222,"state":"WI","location":"Rhinelander, Rhinelander-Oneida County Airport","city":"Rhinelander","priority":10}, + "KRNH": {"id":"KRNH","lat":45.14762,"lon":-92.53349,"state":"WI","location":"New Richmond Municipal Airport","city":"New Richmond","priority":9}, + "KRPD": {"id":"KRPD","lat":45.4180599,"lon":-91.77361,"state":"WI","location":"Rice Lake, Rice Lake Regional-Carl's Field Airport","city":"Rice Lake","priority":3}, + "KRRL": {"id":"KRRL","lat":45.19844,"lon":-89.70996,"state":"WI","location":"Merrill, Merrill Municipal Airport","city":"Merrill","priority":9}, + "KRYV": {"id":"KRYV","lat":43.17016,"lon":-88.72497,"state":"WI","location":"Watertown","city":"Watertown","priority":99}, + "KRZN": {"id":"KRZN","lat":45.82278,"lon":-92.3725,"state":"WI","location":"Siren, Burnett County Airport","city":"Siren","priority":10}, + "KSBM": {"id":"KSBM","lat":43.77483,"lon":-87.84897,"state":"WI","location":"Sheboygan County Memorial Airport","city":"Sheboygan Co.","priority":10}, + "KSTE": {"id":"KSTE","lat":44.54371,"lon":-89.53468,"state":"WI","location":"Stevens Point Municipal Airport","city":"Stevens Point","priority":9}, + "KSUE": {"id":"KSUE","lat":44.83941,"lon":-87.42188,"state":"WI","location":"Door County Cherryland Airport","city":"Door Co.","priority":10}, + "KSUW": {"id":"KSUW","lat":46.68335,"lon":-92.09254,"state":"WI","location":"Richard I. Bong Airport","city":"Richard I Bong","priority":13}, + "KTKV": {"id":"KTKV","lat":45.46801,"lon":-89.80962,"state":"WI","location":"Tomahawk Regional Airport","city":"Tomahawk","priority":3}, + "KUBE": {"id":"KUBE","lat":45.506,"lon":-91.9811,"state":"WI","location":"Cumberland","city":"Cumberland","priority":99}, + "KUES": {"id":"KUES","lat":43.04245,"lon":-88.24607,"state":"WI","location":"Waukesha County Airport","city":"Waukesha Co.","priority":10}, + "KUNU": {"id":"KUNU","lat":43.42667,"lon":-88.7033299,"state":"WI","location":"Juneau, Dodge County Airport","city":"Juneau","priority":10}, + "KVOK": {"id":"KVOK","lat":43.93333,"lon":-90.26667,"state":"WI","location":"Volk / Camp Douglas","city":"Volk","priority":99}, + "KACY": {"id":"KACY","lat":39.45202,"lon":-74.56699,"state":"NJ","location":"Atlantic City, Atlantic City International Airport","city":"Atlantic City","priority":1}, + "KBLM": {"id":"KBLM","lat":40.18333,"lon":-74.13333,"state":"NJ","location":"Belmar-Farmingdale","city":"Belmar","priority":99}, + "KCDW": {"id":"KCDW","lat":40.87639,"lon":-74.28306,"state":"NJ","location":"Caldwell, Essex County Airport","city":"Caldwell","priority":10}, + "KEWR": {"id":"KEWR","lat":40.6825,"lon":-74.16944,"state":"NJ","location":"Newark, Newark International Airport","city":"Newark","priority":1}, + "KFWN": {"id":"KFWN","lat":41.19925,"lon":-74.62594,"state":"NJ","location":"Sussex, Sussex Airport","city":"Sussex","priority":13}, + "KLDJ": {"id":"KLDJ","lat":40.6174,"lon":-74.2446,"state":"NJ","location":"Linden Airport","city":"Linden","priority":13}, + "KMIV": {"id":"KMIV","lat":39.36623,"lon":-75.0778,"state":"NJ","location":"Millville, Millville Municipal Airport","city":"Millville","priority":9}, + "KMJX": {"id":"KMJX","lat":39.927,"lon":-74.292,"state":"NJ","location":"Miller Air Park","city":"Miller","priority":15}, + "KMMU": {"id":"KMMU","lat":40.8,"lon":-74.41667,"state":"NJ","location":"Morristown Municipal","city":"Morristown","priority":9}, + "KNEL": {"id":"KNEL","lat":40.03661,"lon":-74.35251,"state":"NJ","location":"Lakehurst Naval Air Station","city":"Lakehurst","priority":14}, + "KOBI": {"id":"KOBI","lat":39.2191,"lon":-74.7948,"state":"NJ","location":"CAPE MAY","city":"Cape May","priority":99}, + "KSMQ": {"id":"KSMQ","lat":40.6240499,"lon":-74.66898,"state":"NJ","location":"Somerville, Somerset Airport","city":"Somerville","priority":13}, + "KTEB": {"id":"KTEB","lat":40.85889,"lon":-74.05667,"state":"NJ","location":"Teterboro, Teterboro Airport","city":"Teterboro","priority":13}, + "KTTN": {"id":"KTTN","lat":40.27639,"lon":-74.81639,"state":"NJ","location":"Trenton, Mercer County Airport","city":"Trenton","priority":10}, + "KVAY": {"id":"KVAY","lat":39.94076,"lon":-74.84071,"state":"NJ","location":"Mount Holly, South Jersey Regional Airport","city":"Mt Holly","priority":3}, + "KWRI": {"id":"KWRI","lat":40.01667,"lon":-74.6,"state":"NJ","location":"Mcguire Air Force Base","city":"Mcguire","priority":14}, + "KWWD": {"id":"KWWD","lat":39.01667,"lon":-74.91667,"state":"NJ","location":"Wildwood, Cape May County Airport","city":"Wildwood","priority":10}, + "KELO": {"id":"KELO","lat":47.81667,"lon":-91.83333,"state":"MN","location":"Ely, Ely Municipal Airport","city":"Ely","priority":9}, + "KEVM": {"id":"KEVM","lat":47.4274,"lon":-92.49717,"state":"MN","location":"Eveleth-Virginia Municipal Airport","city":"Eveleth","priority":9}, + "KFBL": {"id":"KFBL","lat":44.32983,"lon":-93.31186,"state":"MN","location":"Faribault, Faribault Municipal Airport","city":"Faribault","priority":9}, + "KFCM": {"id":"KFCM","lat":44.83217,"lon":-93.47051,"state":"MN","location":"Minneapolis - Flying Cloud Airport","city":"Flying Cloud","priority":13}, + "KFFM": {"id":"KFFM","lat":46.28655,"lon":-96.15338,"state":"MN","location":"Fergus Falls Municipal Airport-Einar Mickel","city":"Fergus Falls","priority":9}, + "KFGN": {"id":"KFGN","lat":49.31667,"lon":-94.9,"state":"MN","location":"Flag Island","city":"Flag Is.","priority":99}, + "KFKA": {"id":"KFKA","lat":43.67701,"lon":-92.17422,"state":"MN","location":"Preston, Fillmore County Airport","city":"Preston","priority":10}, + "KFOZ": {"id":"KFOZ","lat":47.78317,"lon":-93.65326,"state":"MN","location":"Bigfork Municipal Airport","city":"Bigfork","priority":9}, + "KFRM": {"id":"KFRM","lat":43.65,"lon":-94.41667,"state":"MN","location":"Fairmont, Fairmont Municipal Airport","city":"Fairmont","priority":9}, + "KFSE": {"id":"KFSE","lat":47.59278,"lon":-95.77333,"state":"MN","location":"Fosston, Fosston Municipal Airport","city":"Fosston","priority":9}, + "KGDB": {"id":"KGDB","lat":44.75306,"lon":-95.55583,"state":"MN","location":"Granite Falls, Granite Falls Municipal Airport/Lenzen-Roe Memorial Field","city":"Granite Falls","priority":9}, + "KGHW": {"id":"KGHW","lat":45.64564,"lon":-95.31876,"state":"MN","location":"Glenwood Municipal Airport","city":"Glenwood","priority":9}, + "KGNA": {"id":"KGNA","lat":47.7472,"lon":-90.3443999,"state":"MN","location":"Grand Marais, The Bay of Grand Marais","city":"Bay of Grand Marais","priority":99}, + "KGPZ": {"id":"KGPZ","lat":47.21667,"lon":-93.51667,"state":"MN","location":"Grand Rapids, Grand Rapids/Itasca County Airport-Gordon Newstrom Field","city":"Grand Rapids","priority":10}, + "KGYL": {"id":"KGYL","lat":44.7588,"lon":-94.0905,"state":"MN","location":"Glencoe Municipal Airport","city":"Glencoe","priority":9}, + "KHCD": {"id":"KHCD","lat":44.85961,"lon":-94.38551,"state":"MN","location":"Hutchinson, Hutchinson Municipal Airport-Butler Field","city":"Hutchinson","priority":9}, + "KHCO": {"id":"KHCO","lat":48.75245,"lon":-96.93759,"state":"MN","location":"Hallock Municipal Airport","city":"Hallock","priority":9}, + "KHIB": {"id":"KHIB","lat":47.38039,"lon":-92.83245,"state":"MN","location":"Chisholm-Hibbing Airport","city":"Chisholm","priority":13}, + "KHZX": {"id":"KHZX","lat":46.61904,"lon":-93.31267,"state":"MN","location":"Mc Gregor - Isedor Iverson Airport","city":"Mc Gregor","priority":13}, + "KINL": {"id":"KINL","lat":48.55944,"lon":-93.39556,"state":"MN","location":"Falls International Airport","city":"Falls","priority":1}, + "KJKJ": {"id":"KJKJ","lat":46.8404,"lon":-96.65442,"state":"MN","location":"Moorhead Municipal Airport","city":"Moorhead","priority":9}, + "KJMR": {"id":"KJMR","lat":45.88863,"lon":-93.26901,"state":"MN","location":"Mora Municipal Airport","city":"Mora","priority":9}, + "KJYG": {"id":"KJYG","lat":43.98558,"lon":-94.55299,"state":"MN","location":"St. James Municipal Airport","city":"St James","priority":9}, + "KLJF": {"id":"KLJF","lat":45.09485,"lon":-94.50837,"state":"MN","location":"Litchfield Municipal Airport","city":"Litchfield","priority":9}, + "KLVN": {"id":"KLVN","lat":44.62778,"lon":-93.22806,"state":"MN","location":"Minneapolis, Airlake Airport","city":"Airlake","priority":13}, + "KLXL": {"id":"KLXL","lat":45.95,"lon":-94.35,"state":"MN","location":"Little Falls, Little Falls/Morrison County Airport-Lindbergh Field","city":"Little Falls","priority":10}, + "KLYV": {"id":"KLYV","lat":43.62166,"lon":-96.2139399,"state":"MN","location":"Quentin Aanenson Field Airport","city":"Quentin Aanenson","priority":12}, + "KMGG": {"id":"KMGG","lat":45.2353499,"lon":-93.98959,"state":"MN","location":"Maple Lake, Maple Lake Municipal Airport","city":"Maple Lake","priority":9}, + "KMIC": {"id":"KMIC","lat":45.0625,"lon":-93.35083,"state":"MN","location":"Minneapolis, Crystal Airport","city":"Crystal","priority":13}, + "KMJQ": {"id":"KMJQ","lat":43.65,"lon":-94.98333,"state":"MN","location":"Jackson, Jackson Municipal Airport","city":"Jackson","priority":9}, + "KMKT": {"id":"KMKT","lat":44.21667,"lon":-93.91667,"state":"MN","location":"Mankato, Mankato Regional Airport","city":"Mankato","priority":3}, + "KMML": {"id":"KMML","lat":44.45,"lon":-95.81667,"state":"MN","location":"Marshall, Southwest Minnesota Regional Airport - Marshall/Ryan Field","city":"Marshall","priority":3}, + "KMOX": {"id":"KMOX","lat":45.56667,"lon":-95.9666699,"state":"MN","location":"Morris, Morris Municipal Airport","city":"Morris","priority":9}, + "KMSP": {"id":"KMSP","lat":44.88306,"lon":-93.22889,"state":"MN","location":"Minneapolis, Minneapolis-St. Paul International Airport","city":"Minneapolis","priority":1}, + "KMVE": {"id":"KMVE","lat":44.96749,"lon":-95.71159,"state":"MN","location":"Montevideo-Chippewa County Airport","city":"Montevideo","priority":10}, + "KMWM": {"id":"KMWM","lat":43.90999,"lon":-95.10723,"state":"MN","location":"Windom Municipal Airport","city":"Windom","priority":9}, + "KMZH": {"id":"KMZH","lat":46.41632,"lon":-92.80491,"state":"MN","location":"Moose Lake Carlton County Airport","city":"Moose Lake","priority":10}, + "KONA": {"id":"KONA","lat":44.0833299,"lon":-91.7,"state":"MN","location":"Winona, Winona Municipal Airport-Max Conrad Field","city":"Winona","priority":9}, + "KORB": {"id":"KORB","lat":48.0170699,"lon":-92.85376,"state":"MN","location":"Orr Regional Airport","city":"Orr","priority":3}, + "KOTG": {"id":"KOTG","lat":43.65,"lon":-95.58333,"state":"MN","location":"Worthington, Worthington Municipal Airport","city":"Worthington","priority":9}, + "KOVL": {"id":"KOVL","lat":44.77923,"lon":-95.03033,"state":"MN","location":"Olivia Regional Airport","city":"Olivia","priority":3}, + "KOWA": {"id":"KOWA","lat":44.11907,"lon":-93.25687,"state":"MN","location":"Owatonna Degner Regional Airport","city":"Owatonna Degner","priority":3}, + "KPEX": {"id":"KPEX","lat":45.37247,"lon":-94.73878,"state":"MN","location":"Paynesville, Paynesville Municipal Airport","city":"Paynesville","priority":9}, + "KPKD": {"id":"KPKD","lat":46.8996799,"lon":-95.06681,"state":"MN","location":"Park Rapids Municipal Airport","city":"Park Rapids","priority":9}, + "KPNM": {"id":"KPNM","lat":45.56425,"lon":-93.6080099,"state":"MN","location":"Princeton","city":"Princeton","priority":99}, + "KPWC": {"id":"KPWC","lat":46.72654,"lon":-94.38485,"state":"MN","location":"Pine River Regional Airport","city":"Pine River","priority":3}, + "KROS": {"id":"KROS","lat":45.69628,"lon":-92.95424,"state":"MN","location":"Rush City Regional Airport","city":"Rush City","priority":3}, + "KROX": {"id":"KROX","lat":48.85,"lon":-95.7,"state":"MN","location":"Roseau, Roseau Municipal Airport/Rudy Billberg Field","city":"Roseau","priority":9}, + "KRRT": {"id":"KRRT","lat":48.93183,"lon":-95.3404599,"state":"MN","location":"Warroad International Memorial Airport","city":"Warroad","priority":1}, + "KRST": {"id":"KRST","lat":43.90417,"lon":-92.49167,"state":"MN","location":"Rochester, Rochester International Airport","city":"Rochester","priority":1}, + "KRWF": {"id":"KRWF","lat":44.54828,"lon":-95.08042,"state":"MN","location":"Redwood Falls Municipal Airport","city":"Redwood Falls","priority":9}, + "KSAZ": {"id":"KSAZ","lat":46.38083,"lon":-94.80667,"state":"MN","location":"Staples, Staples Municipal Airport","city":"Staples","priority":9}, + "KSGS": {"id":"KSGS","lat":44.86006,"lon":-93.03203,"state":"MN","location":"South St. Paul Municipal-Richard E. Flemi","city":"South St Paul","priority":9}, + "KSTC": {"id":"KSTC","lat":45.54415,"lon":-94.05165,"state":"MN","location":"St. Cloud Regional Airport","city":"St Cloud","priority":3}, + "KSTP": {"id":"KSTP","lat":44.93237,"lon":-93.05588,"state":"MN","location":"Downtown Holman Field","city":"Downtown Holman","priority":12}, + "KSYN": {"id":"KSYN","lat":44.4736199,"lon":-93.01448,"state":"MN","location":"Stanton Airfield","city":"Stanton","priority":99}, + "KTKC": {"id":"KTKC","lat":44.24951,"lon":-95.61189,"state":"MN","location":"Tracy, Tracy Municipal Airport","city":"Tracy","priority":9}, + "KTOB": {"id":"KTOB","lat":44.02026,"lon":-92.8295,"state":"MN","location":"Dodge Center Airport","city":"Dodge Center","priority":13}, + "KTVF": {"id":"KTVF","lat":48.06667,"lon":-96.18333,"state":"MN","location":"Thief River Falls, Thief River Falls Regional Airport","city":"Thief River Falls","priority":3}, + "KTWM": {"id":"KTWM","lat":47.05,"lon":-91.75,"state":"MN","location":"Two Harbors","city":"Two Harbors","priority":99}, + "KULM": {"id":"KULM","lat":44.32274,"lon":-94.50244,"state":"MN","location":"New Ulm Municipal Airport","city":"New Ulm","priority":9}, + "KVVV": {"id":"KVVV","lat":45.30556,"lon":-96.42444,"state":"MN","location":"Ortonville, Ortonville Muncipal-Martinson Field Airport","city":"Ortonville","priority":12}, + "KVWU": {"id":"KVWU","lat":48.15014,"lon":-94.512,"state":"MN","location":"Waskish Municipal Airport","city":"Waskish","priority":9}, + "KXVG": {"id":"KXVG","lat":46.99028,"lon":-94.20389,"state":"MN","location":"Longville, Longville Municipal Airport","city":"Longville","priority":9}, + "PCKY": {"id":"PCKY","lat":43.8502777,"lon":-110.5177777,"state":"WY","location":"Pacific Creek at Moran, WY","city":"Moran","priority":50}, + "KBCE": {"id":"KBCE","lat":37.7012799,"lon":-112.14897,"state":"UT","location":"Bryce Canyon Airport","city":"Bryce Canyon","priority":13}, + "KBDG": {"id":"KBDG","lat":37.586,"lon":-109.482,"state":"UT","location":"Blanding Municipal Airport","city":"Blanding","priority":9}, + "KBMC": {"id":"KBMC","lat":41.5464,"lon":-112.0601,"state":"UT","location":"Brigham City Regional Airport","city":"Brigham City","priority":3}, + "KCDC": {"id":"KCDC","lat":37.70675,"lon":-113.09695,"state":"UT","location":"Cedar City Municipal Airport","city":"Cedar City","priority":9}, + "KCNY": {"id":"KCNY","lat":38.76,"lon":-109.74472,"state":"UT","location":"Moab, Canyonlands Field","city":"Moab","priority":12}, + "KDPG": {"id":"KDPG","lat":40.18376,"lon":-112.9217,"state":"UT","location":"Michael Army Airfield - Dugway Proving Ground","city":"Michael","priority":14}, + "KDTA": {"id":"KDTA","lat":39.38333,"lon":-112.50967,"state":"UT","location":"Delta, Delta Municipal Airport","city":"Delta","priority":9}, + "KENV": {"id":"KENV","lat":40.72056,"lon":-114.03583,"state":"UT","location":"Wendover Airport","city":"Wendover","priority":13}, + "KFOM": {"id":"KFOM","lat":38.95814,"lon":-112.36314,"state":"UT","location":"Fillmore","city":"Fillmore","priority":99}, + "KHCR": {"id":"KHCR","lat":40.47742,"lon":-111.43295,"state":"UT","location":"Heber Valley Airport","city":"Heber Valley","priority":13}, + "KHIF": {"id":"KHIF","lat":41.11112,"lon":-111.96229,"state":"UT","location":"Hill Air Force Base","city":"Hill","priority":14}, + "KHVE": {"id":"KHVE","lat":38.418037,"lon":-110.704038,"state":"UT","location":"Hanksville","city":"Hanksville","priority":99}, + "KKNB": {"id":"KKNB","lat":37.01,"lon":-112.53,"state":"UT","location":"KANAB MUNICIPAL AIRPORT","city":"Kanab","priority":9}, + "KLGU": {"id":"KLGU","lat":41.78652,"lon":-111.85187,"state":"UT","location":"Logan-Cache Airport","city":"Logan","priority":13}, + "KMLF": {"id":"KMLF","lat":38.42252,"lon":-113.01089,"state":"UT","location":"Milford Municipal Airport","city":"Milford","priority":9}, + "KOGD": {"id":"KOGD","lat":41.19406,"lon":-112.01681,"state":"UT","location":"Ogden-Hinckley Airport","city":"Ogden","priority":13}, + "KPUC": {"id":"KPUC","lat":39.60886,"lon":-110.75548,"state":"UT","location":"Price - Carbon County Regional Airport","city":"Price","priority":10}, + "KPVU": {"id":"KPVU","lat":40.2239,"lon":-111.7253,"state":"UT","location":"Provo Municipal Airport","city":"Provo","priority":9}, + "KRIF": {"id":"KRIF","lat":38.73411,"lon":-112.10158,"state":"UT","location":"Richfield Municipal Airport","city":"Richfield","priority":9}, + "KSGU": {"id":"KSGU","lat":37.0451,"lon":-113.50561,"state":"UT","location":"St George Regional Airport","city":"St George","priority":3}, + "KSLC": {"id":"KSLC","lat":40.77069,"lon":-111.96503,"state":"UT","location":"Salt Lake City, Salt Lake City International Airport","city":"Salt Lake City","priority":1}, + "KSPK": {"id":"KSPK","lat":40.145,"lon":-111.6677,"state":"UT","location":"Spanish Fork Municipal Airport","city":"Spanish Fork","priority":9}, + "KSVR": {"id":"KSVR","lat":40.6196,"lon":-111.99016,"state":"UT","location":"South Valley Regional Airport","city":"South Valley","priority":3}, + "KTVY": {"id":"KTVY","lat":40.61269,"lon":-112.35362,"state":"UT","location":"Bolinder Field-Tooele Valley Airport","city":"Bolinder","priority":12}, + "KVEL": {"id":"KVEL","lat":40.44295,"lon":-109.51273,"state":"UT","location":"Vernal Airport","city":"Vernal","priority":13}, + "KAAO": {"id":"KAAO","lat":37.74969,"lon":-97.21908,"state":"KS","location":"Wichita Jabara Airport","city":"Wichita Jabara","priority":13}, + "KADT": {"id":"KADT","lat":39.84034,"lon":-101.04248,"state":"KS","location":"Atwood-Rawlins County City-County Airport","city":"Atwood","priority":10}, + "KBEC": {"id":"KBEC","lat":37.69392,"lon":-97.21492,"state":"KS","location":"Beech Factory Airport","city":"Beech Factory","priority":13}, + "KCBK": {"id":"KCBK","lat":39.42746,"lon":-101.04662,"state":"KS","location":"Shalz Field Airport","city":"Shalz","priority":12}, + "KCFV": {"id":"KCFV","lat":37.09111,"lon":-95.56639,"state":"KS","location":"Coffeyville, Coffeyville Municipal Airport","city":"Coffeyville","priority":9}, + "KCNK": {"id":"KCNK","lat":39.55139,"lon":-97.65056,"state":"KS","location":"Concordia, Blosser Municipal Airport","city":"Concordia","priority":9}, + "KCNU": {"id":"KCNU","lat":37.67028,"lon":-95.48417,"state":"KS","location":"Chanute, Chanute Martin Johnson Airport","city":"Chanute","priority":13}, + "KDDC": {"id":"KDDC","lat":37.77278,"lon":-99.96972,"state":"KS","location":"Dodge City, Dodge City Regional Airport","city":"Dodge City","priority":3}, + "KEGT": {"id":"KEGT","lat":37.32361,"lon":-97.38834,"state":"KS","location":"WELLINGTON","city":"Wellington","priority":99}, + "KEHA": {"id":"KEHA","lat":37,"lon":-101.88333,"state":"KS","location":"Elkhart, Elkhart-Morton County Airport","city":"Elkhart","priority":10}, + "KEMP": {"id":"KEMP","lat":38.32889,"lon":-96.19389,"state":"KS","location":"Emporia, Emporia Municipal Airport","city":"Emporia","priority":9}, + "KEQA": {"id":"KEQA","lat":37.77534,"lon":-96.81449,"state":"KS","location":"El Dorado Captain Jack Thomas Airport","city":"El Dorado","priority":13}, + "KEWK": {"id":"KEWK","lat":38.05,"lon":-97.28333,"state":"KS","location":"Newton, Newton City/County Airport","city":"Newton","priority":13}, + "KFOE": {"id":"KFOE","lat":38.94139,"lon":-95.65056,"state":"KS","location":"Topeka, Forbes Field","city":"Forbes","priority":12}, + "KFRI": {"id":"KFRI","lat":39.05586,"lon":-96.76166,"state":"KS","location":"Fort Riley - Marshall AAF","city":"Ft Riley","priority":14}, + "KFSK": {"id":"KFSK","lat":37.79833,"lon":-94.76933,"state":"KS","location":"FORT SCOTT","city":"Ft Scott","priority":99}, + "KGBD": {"id":"KGBD","lat":38.35,"lon":-98.86667,"state":"KS","location":"Great Bend, Great Bend Municipal Airport","city":"Great Bend","priority":9}, + "KGCK": {"id":"KGCK","lat":37.9275,"lon":-100.72444,"state":"KS","location":"Garden City Regional Airport","city":"Garden City","priority":3}, + "KGLD": {"id":"KGLD","lat":39.3675,"lon":-101.69306,"state":"KS","location":"Goodland, Renner Field","city":"Goodland","priority":12}, + "KHLC": {"id":"KHLC","lat":39.37472,"lon":-99.82972,"state":"KS","location":"Hill City, Hill City Municipal Airport","city":"Hill City","priority":9}, + "KHQG": {"id":"KHQG","lat":37.16308,"lon":-101.37052,"state":"KS","location":"Hugoton Municipal Airport","city":"Hugoton","priority":9}, + "KHUT": {"id":"KHUT","lat":38.06806,"lon":-97.86056,"state":"KS","location":"Hutchinson, Hutchinson Municipal Airport","city":"Hutchinson","priority":9}, + "KHYS": {"id":"KHYS","lat":38.85,"lon":-99.26667,"state":"KS","location":"Hays, Hays Regional Airport","city":"Hays","priority":3}, + "KIAB": {"id":"KIAB","lat":37.61667,"lon":-97.26667,"state":"KS","location":"McConnell Air Force Base","city":"McConnell","priority":14}, + "KICT": {"id":"KICT","lat":37.64722,"lon":-97.42944,"state":"KS","location":"Wichita - Wichita Dwight D. Eisenhower National Airport","city":"Wichita","priority":2}, + "KIDP": {"id":"KIDP","lat":37.1584,"lon":-95.7784,"state":"KS","location":"INDEPENDENCE","city":"Independence","priority":99}, + "KIXD": {"id":"KIXD","lat":38.82444,"lon":-94.88694,"state":"KS","location":"Olathe, New Century Aircenter","city":"Olathe","priority":5}, + "KJHN": {"id":"KJHN","lat":37.5782,"lon":-101.7304,"state":"KS","location":"Stanton County Municipal Airport","city":"Stanton Co.","priority":10}, + "KLBL": {"id":"KLBL","lat":37.05,"lon":-100.9666699,"state":"KS","location":"Liberal, Liberal Municipal Airport","city":"Liberal","priority":9}, + "KLWC": {"id":"KLWC","lat":39.00833,"lon":-95.21167,"state":"KS","location":"Lawrence, Lawrence Municipal Airport","city":"Lawrence","priority":9}, + "KLYO": {"id":"KLYO","lat":38.34025,"lon":-98.22856,"state":"KS","location":"Lyons-Rice County Municipal Airport","city":"Lyons","priority":10}, + "KMHK": {"id":"KMHK","lat":39.13528,"lon":-96.67778,"state":"KS","location":"Manhattan, Manhattan Municipal Airport","city":"Manhattan","priority":9}, + "KMPR": {"id":"KMPR","lat":38.35244,"lon":-97.6913299,"state":"KS","location":"MCPHERSON","city":"Mcpherson","priority":99}, + "KMYZ": {"id":"KMYZ","lat":39.8553,"lon":-96.6306,"state":"KS","location":"Marysville Municipal Airport","city":"Marysville","priority":9}, + "KNRN": {"id":"KNRN","lat":39.85047,"lon":-99.89469,"state":"KS","location":"Norton Municipal Airport","city":"Norton","priority":9}, + "KOEL": {"id":"KOEL","lat":39.11178,"lon":-100.81667,"state":"KS","location":"Oakley Municipal Airport","city":"Oakley","priority":9}, + "KOIN": {"id":"KOIN","lat":39.83489,"lon":-100.5397799,"state":"KS","location":"Oberlin Municipal Airport","city":"Oberlin","priority":9}, + "KOJC": {"id":"KOJC","lat":38.85,"lon":-94.73917,"state":"KS","location":"Olathe, Johnson County Executive Airport","city":"Johnson Co.","priority":10}, + "KOWI": {"id":"KOWI","lat":38.5409,"lon":-95.2542,"state":"KS","location":"Ottawa Municipal Airport","city":"Ottawa","priority":9}, + "KPHG": {"id":"KPHG","lat":39.735,"lon":-99.3171,"state":"KS","location":"PHILLIPSBURG","city":"Phillipsburg","priority":99}, + "KPPF": {"id":"KPPF","lat":37.32778,"lon":-95.50417,"state":"KS","location":"Parsons, Tri-City Airport","city":"Parsons","priority":13}, + "KPTS": {"id":"KPTS","lat":37.4494,"lon":-94.7311,"state":"KS","location":"Atkinson Municipal Airport","city":"Atkinson","priority":9}, + "KPTT": {"id":"KPTT","lat":37.7,"lon":-98.75,"state":"KS","location":"Pratt Municipal","city":"Pratt","priority":9}, + "KRSL": {"id":"KRSL","lat":38.87278,"lon":-98.8130599,"state":"KS","location":"Russell, Russell Municipal Airport","city":"Russell","priority":9}, + "KSLN": {"id":"KSLN","lat":38.78,"lon":-97.64417,"state":"KS","location":"Salina, Salina Municipal Airport","city":"Salina","priority":9}, + "KSYF": {"id":"KSYF","lat":39.763884,"lon":-101.797861,"state":"KS","location":"ST FRANCIS","city":"St Francis","priority":99}, + "KTOP": {"id":"KTOP","lat":39.0725,"lon":-95.6258299,"state":"KS","location":"Topeka, Philip Billard Municipal Airport","city":"Topeka","priority":9}, + "KTQK": {"id":"KTQK","lat":38.47502,"lon":-100.88444,"state":"KS","location":"Scott City Municipal Airport","city":"Scott City","priority":9}, + "KUKL": {"id":"KUKL","lat":38.30247,"lon":-95.72497,"state":"KS","location":"Coffey County Airport","city":"Coffey Co.","priority":10}, + "KULS": {"id":"KULS","lat":37.604,"lon":-101.37356,"state":"KS","location":"Ulysses Airport","city":"Ulysses","priority":13}, + "KWLD": {"id":"KWLD","lat":37.1680599,"lon":-97.03694,"state":"KS","location":"Winfield / Arkansas City, Strother Field","city":"Winfield","priority":12}, + "KALW": {"id":"KALW","lat":46.09462,"lon":-118.2858,"state":"WA","location":"Walla Walla Regional Airport","city":"Walla Walla","priority":3}, + "KAWO": {"id":"KAWO","lat":48.1584999,"lon":-122.15909,"state":"WA","location":"Arlington Municipal Airport","city":"Arlington","priority":9}, + "KBFI": {"id":"KBFI","lat":47.54548,"lon":-122.3147,"state":"WA","location":"Boeing Field - King County International Airport","city":"Boeing Field","priority":1}, + "KBLI": {"id":"KBLI","lat":48.79911,"lon":-122.54064,"state":"WA","location":"Bellingham, Bellingham International Airport","city":"Bellingham","priority":1}, + "KBVS": {"id":"KBVS","lat":48.47083,"lon":-122.42083,"state":"WA","location":"Burlington/Mount Vernon, Skagit Regional Airport","city":"Burlington","priority":3}, + "KCLM": {"id":"KCLM","lat":48.12194,"lon":-123.50661,"state":"WA","location":"Port Angeles Fairchild International Airport","city":"Port Angeles Fairchild","priority":1}, + "KCLS": {"id":"KCLS","lat":46.677,"lon":-122.9827,"state":"WA","location":"Chehalis-Centralia Airport","city":"Chehalis","priority":13}, + "KDEW": {"id":"KDEW","lat":47.97417,"lon":-117.42833,"state":"WA","location":"Deer Park, Deer Park Airport","city":"Deer Park","priority":13}, + "KDLS": {"id":"KDLS","lat":45.61901,"lon":-121.16572,"state":"WA","location":"The Dalles Municipal Airport","city":"The Dalles","priority":9}, + "KEAT": {"id":"KEAT","lat":47.39749,"lon":-120.20121,"state":"WA","location":"Wenatchee - Pangborn Memorial Airport","city":"Wenatchee","priority":11}, + "KELN": {"id":"KELN","lat":47.0337699,"lon":-120.53132,"state":"WA","location":"Ellensburg, Ellensburg Bowers Field","city":"Ellensburg","priority":12}, + "KEPH": {"id":"KEPH","lat":47.3075,"lon":-119.51583,"state":"WA","location":"Ephrata, Ephrata Municipal Airport","city":"Ephrata","priority":9}, + "KFHR": {"id":"KFHR","lat":48.52,"lon":-123.02637,"state":"WA","location":"Friday Harbor Airport","city":"Friday Harbor","priority":13}, + "KFLW": {"id":"KFLW","lat":48.595,"lon":-118.12417,"state":"WA","location":"Kettle Falls","city":"Kettle Falls","priority":99}, + "KGEG": {"id":"KGEG","lat":47.62139,"lon":-117.52778,"state":"WA","location":"Spokane, Spokane International Airport","city":"Spokane","priority":1}, + "KGRF": {"id":"KGRF","lat":47.11667,"lon":-122.55,"state":"WA","location":"Fort Lewis / Gray U. S. Army Airfield","city":"Ft Lewis","priority":14}, + "KHQM": {"id":"KHQM","lat":46.97111,"lon":-123.92,"state":"WA","location":"Hoquiam, Bowerman Airport","city":"Hoquiam","priority":13}, + "KKLS": {"id":"KKLS","lat":46.11553,"lon":-122.89273,"state":"WA","location":"Southwest Washington Regional Airport","city":"Southwest Washington","priority":3}, + "KMWH": {"id":"KMWH","lat":47.19299,"lon":-119.31451,"state":"WA","location":"Grant County Airport","city":"Grant Co.","priority":10}, + "KNCW": {"id":"KNCW","lat":46.2652777,"lon":-119.5694444,"state":"WA","location":"KENNEWICK CANAL","city":"Kennewick Canal","priority":99}, + "KNOW": {"id":"KNOW","lat":48.13333,"lon":-123.4,"state":"WA","location":"Port Angeles Coast Guard Air Station","city":"Port Angeles","priority":14}, + "KNRA": {"id":"KNRA","lat":48.19056,"lon":-122.63056,"state":"WA","location":"Coupeville, Outlying Landing Field","city":"Coupeville","priority":12}, + "KNUW": {"id":"KNUW","lat":48.35525,"lon":-122.66352,"state":"WA","location":"Whidbey Island Naval Air Station - Ault Field","city":"Whidbey Is.","priority":14}, + "KOLM": {"id":"KOLM","lat":46.97333,"lon":-122.90333,"state":"WA","location":"Olympia, Olympia Airport","city":"Olympia","priority":13}, + "KOMK": {"id":"KOMK","lat":48.46116,"lon":-119.52086,"state":"WA","location":"Omak Airport","city":"Omak","priority":13}, + "KORS": {"id":"KORS","lat":48.70806,"lon":-122.91028,"state":"WA","location":"Eastsound, Orcas Island Airport","city":"Eastsound","priority":13}, + "KPAE": {"id":"KPAE","lat":47.92331,"lon":-122.28305,"state":"WA","location":"Everett Snohomish County","city":"Everett","priority":10}, + "KPLU": {"id":"KPLU","lat":47.104,"lon":-122.287,"state":"WA","location":"Pierce County-Thun Field","city":"Pierce Co.","priority":10}, + "KPSC": {"id":"KPSC","lat":46.26955,"lon":-119.11813,"state":"WA","location":"Tri-Cities Airport","city":"Tri-Cities","priority":13}, + "KPUW": {"id":"KPUW","lat":46.74377,"lon":-117.11579,"state":"WA","location":"Pullman / Moscow Regional Airport","city":"Pullman","priority":3}, + "KPWT": {"id":"KPWT","lat":47.5,"lon":-122.75,"state":"WA","location":"Bremerton, Bremerton National Airport","city":"Bremerton","priority":2}, + "KRLD": {"id":"KRLD","lat":46.30859,"lon":-119.3058,"state":"WA","location":"Richland Airport","city":"Richland","priority":13}, + "KRNT": {"id":"KRNT","lat":47.49509,"lon":-122.21437,"state":"WA","location":"Renton Municipal Airport","city":"Renton","priority":9}, + "KSEA": {"id":"KSEA","lat":47.4447199,"lon":-122.31361,"state":"WA","location":"Seattle, Seattle-Tacoma International Airport","city":"Seattle","priority":1}, + "KSFF": {"id":"KSFF","lat":47.68556,"lon":-117.32028,"state":"WA","location":"Spokane, Felts Field","city":"Felts","priority":12}, + "KSHN": {"id":"KSHN","lat":47.23806,"lon":-123.14083,"state":"WA","location":"Shelton, Shelton Sanderson Field","city":"Shelton","priority":12}, + "KSKA": {"id":"KSKA","lat":47.61667,"lon":-117.65,"state":"WA","location":"Fairchild Air Force Base","city":"Fairchild","priority":14}, + "KSMP": {"id":"KSMP","lat":47.27648,"lon":-121.33817,"state":"WA","location":"Stampede Pass","city":"Stampede Pass","priority":99}, + "KTCM": {"id":"KTCM","lat":47.15,"lon":-122.48333,"state":"WA","location":"Tacoma / McChord Air Force Base","city":"McChord AFB","priority":14}, + "KTCW": {"id":"KTCW","lat":47.2388888,"lon":-121.1833333,"state":"WA","location":"KITTITAS CANAL","city":"Kittitas Canal","priority":99}, + "KTIW": {"id":"KTIW","lat":47.2675,"lon":-122.57611,"state":"WA","location":"Tacoma, Tacoma Narrows Airport","city":"Tacoma","priority":13}, + "KUIL": {"id":"KUIL","lat":47.9375,"lon":-124.555,"state":"WA","location":"Quillayute, Quillayute State Airport","city":"Quillayute","priority":6}, + "KVUO": {"id":"KVUO","lat":45.62103,"lon":-122.65419,"state":"WA","location":"Pearson Airfield","city":"Pearson","priority":99}, + "KYKM": {"id":"KYKM","lat":46.56402,"lon":-120.53484,"state":"WA","location":"Yakima Air Terminal - McAllister Field","city":"Yakima Air Terminal","priority":12}, + "KABE": {"id":"KABE","lat":40.64985,"lon":-75.44771,"state":"PA","location":"Allentown, Lehigh Valley International Airport","city":"Allentown","priority":1}, + "KAFJ": {"id":"KAFJ","lat":40.13624,"lon":-80.28512,"state":"PA","location":"Washington County Airport","city":"Washington Co.","priority":10}, + "KAGC": {"id":"KAGC","lat":40.35521,"lon":-79.92144,"state":"PA","location":"Pittsburgh - Allegheny County Airport","city":"Allegheny Co.","priority":10}, + "KAOO": {"id":"KAOO","lat":40.29994,"lon":-78.3168,"state":"PA","location":"Altoona - Blair County Airport","city":"Altoona","priority":10}, + "KAVP": {"id":"KAVP","lat":41.33889,"lon":-75.72667,"state":"PA","location":"Wilkes-Barre - Scranton, Wilkes-Barre / Scranton International Airport","city":"Wilkes-Barre - Scranton","priority":1}, + "KBFD": {"id":"KBFD","lat":41.79838,"lon":-78.63539,"state":"PA","location":"Bradford Regional Airport","city":"Bradford","priority":3}, + "KBTP": {"id":"KBTP","lat":40.77658,"lon":-79.95672,"state":"PA","location":"Pittsburgh/Butler Regional Airport","city":"Butler","priority":3}, + "KBVI": {"id":"KBVI","lat":40.77351,"lon":-80.38248,"state":"PA","location":"Beaver County Airport","city":"Beaver Co.","priority":10}, + "KCKZ": {"id":"KCKZ","lat":40.38919,"lon":-75.29047,"state":"PA","location":"Pennridge Airport","city":"Pennridge","priority":13}, + "KCXY": {"id":"KCXY","lat":40.21843,"lon":-76.8552,"state":"PA","location":"Harrisburg, Capital City Airport","city":"Capital City","priority":13}, + "KDUJ": {"id":"KDUJ","lat":41.17948,"lon":-78.89326,"state":"PA","location":"Du Bois - Jefferson County Airport","city":"Du Bois","priority":10}, + "KDYL": {"id":"KDYL","lat":40.33016,"lon":-75.12286,"state":"PA","location":"Doylestown, Doylestown Airport","city":"Doylestown","priority":13}, + "KERI": {"id":"KERI","lat":42.08,"lon":-80.1825,"state":"PA","location":"Erie, Erie International Airport","city":"Erie","priority":1}, + "KFIG": {"id":"KFIG","lat":41.04667,"lon":-78.41167,"state":"PA","location":"Clearfield, Clearfield-Lawrence Airport","city":"Clearfield","priority":13}, + "KFKL": {"id":"KFKL","lat":41.38051,"lon":-79.86029,"state":"PA","location":"Venango Regional Airport","city":"Venango","priority":3}, + "KGKJ": {"id":"KGKJ","lat":41.6258399,"lon":-80.21231,"state":"PA","location":"Port Meadville Airport","city":"Port Meadville","priority":13}, + "KHMZ": {"id":"KHMZ","lat":40.08528,"lon":-78.51222,"state":"PA","location":"Bedford, Bedford County Airport","city":"Bedford","priority":10}, + "KHZL": {"id":"KHZL","lat":40.98447,"lon":-75.99005,"state":"PA","location":"Hazleton Municipal Airport","city":"Hazleton","priority":9}, + "KIDI": {"id":"KIDI","lat":40.6337199,"lon":-79.10362,"state":"PA","location":"Indiana County Airport - Jimmy Stewart Field","city":"Indiana Co.","priority":10}, + "KIPT": {"id":"KIPT","lat":41.24298,"lon":-76.92173,"state":"PA","location":"Williamsport - Lycoming County Airport","city":"Williamsport","priority":10}, + "KJST": {"id":"KJST","lat":40.3149,"lon":-78.83074,"state":"PA","location":"Johnstown - Cambria County Airport","city":"Johnstown","priority":10}, + "KLBE": {"id":"KLBE","lat":40.2767399,"lon":-79.40393,"state":"PA","location":"Arnold Palmer Regional Airport","city":"Arnold Palmer","priority":3}, + "KLNS": {"id":"KLNS","lat":40.1205799,"lon":-76.29446,"state":"PA","location":"Lancaster, Lancaster Airport","city":"Lancaster","priority":13}, + "KLOM": {"id":"KLOM","lat":40.13758,"lon":-75.2684,"state":"PA","location":"Philadelphia - Wings Field Airport","city":"Wings","priority":12}, + "KMDT": {"id":"KMDT","lat":40.19361,"lon":-76.76333,"state":"PA","location":"Harrisburg, Harrisburg International Airport","city":"Harrisburg","priority":1}, + "KMPO": {"id":"KMPO","lat":41.13821,"lon":-75.37971,"state":"PA","location":"Mount Pocono, Pocono Mountains Municipal Airport","city":"Mt Pocono","priority":9}, + "KMQS": {"id":"KMQS","lat":39.98333,"lon":-75.86667,"state":"PA","location":"Chester County Airport","city":"Chester Co.","priority":10}, + "KMUI": {"id":"KMUI","lat":40.43808,"lon":-76.56434,"state":"PA","location":"Muir Army Air Field / Indiantown","city":"Indiantown","priority":14}, + "KOQN": {"id":"KOQN","lat":39.99011,"lon":-75.5819,"state":"PA","location":"Brandywine Regional Airport","city":"Brandywine","priority":3}, + "KOYM": {"id":"KOYM","lat":41.41248,"lon":-78.50263,"state":"PA","location":"St Marys Municipal Airport","city":"St Marys","priority":9}, + "KPHL": {"id":"KPHL","lat":39.87327,"lon":-75.22678,"state":"PA","location":"Philadelphia, Philadelphia International Airport","city":"Philadelphia","priority":1}, + "KPIT": {"id":"KPIT","lat":40.4846,"lon":-80.21447,"state":"PA","location":"Pittsburgh International Airport","city":"Pittsburgh","priority":1}, + "KPJC": {"id":"KPJC","lat":40.80095,"lon":-80.16242,"state":"PA","location":"Zelienople Municipal Airport","city":"Zelienople","priority":9}, + "KPNE": {"id":"KPNE","lat":40.07889,"lon":-75.01361,"state":"PA","location":"Philadelphia, Northeast Philadelphia Airport","city":"Northeast Philadelphia","priority":13}, + "KPTW": {"id":"KPTW","lat":40.23802,"lon":-75.5548699,"state":"PA","location":"Pottstown, Pottstown Limerick Airport","city":"Pottstown","priority":13}, + "KRDG": {"id":"KRDG","lat":40.37333,"lon":-75.95944,"state":"PA","location":"Reading, Reading Regional Airport","city":"Reading","priority":3}, + "KRVL": {"id":"KRVL","lat":40.68333,"lon":-77.63333,"state":"PA","location":"Reedsville / Mifflin","city":"Reedsville","priority":99}, + "KSEG": {"id":"KSEG","lat":40.81929,"lon":-76.86582,"state":"PA","location":"Selinsgrove Penn Valley Airport","city":"Selinsgrove Penn Valley","priority":13}, + "KTHV": {"id":"KTHV","lat":39.91944,"lon":-76.87694,"state":"PA","location":"York, York Airport","city":"York","priority":13}, + "KUCP": {"id":"KUCP","lat":41.02282,"lon":-80.41533,"state":"PA","location":"New Castle Municipal Airport","city":"New Castle","priority":9}, + "KUKT": {"id":"KUKT","lat":40.4368,"lon":-75.38016,"state":"PA","location":"Quakertown Airport","city":"Quakertown","priority":13}, + "KUNV": {"id":"KUNV","lat":40.85,"lon":-77.8475799,"state":"PA","location":"State College Regional Airport","city":"State College","priority":6}, + "KVVS": {"id":"KVVS","lat":39.95906,"lon":-79.65742,"state":"PA","location":"Joseph A Hardy Connellsville Airport","city":"Connellsville","priority":13}, + "KXLL": {"id":"KXLL","lat":40.57,"lon":-75.488,"state":"PA","location":"Allentown Queen City Municipal Airport","city":"Allentown Queen City","priority":9}, + "KZER": {"id":"KZER","lat":40.70675,"lon":-76.37375,"state":"PA","location":"Schuylkill County/Joe Zerbey Airport","city":"Schuylkill Co.","priority":13}, + "KABY": {"id":"KABY","lat":31.53652,"lon":-84.19571,"state":"GA","location":"Southwest Georgia Regional Airport","city":"Southwest Georgia","priority":3}, + "KACJ": {"id":"KACJ","lat":32.11081,"lon":-84.18886,"state":"GA","location":"Americus Souther Field Airport","city":"Americus Souther","priority":12}, + "KAGS": {"id":"KAGS","lat":33.36444,"lon":-81.96333,"state":"GA","location":"Augusta, Bush Field","city":"Augusta","priority":12}, + "KAHN": {"id":"KAHN","lat":33.95083,"lon":-83.3280599,"state":"GA","location":"Athens, Athens Airport","city":"Athens","priority":13}, + "KAJR": {"id":"KAJR","lat":34.4998,"lon":-83.5567,"state":"GA","location":"Cornelia Habersham County Airport","city":"Cornelia","priority":10}, + "KAMG": {"id":"KAMG","lat":31.53611,"lon":-82.50667,"state":"GA","location":"Alma, Bacon County Airport","city":"Alma","priority":10}, + "KATL": {"id":"KATL","lat":33.64028,"lon":-84.42694,"state":"GA","location":"Atlanta, Hartsfield - Jackson Atlanta International Airport","city":"Atlanta","priority":1}, + "KAYS": {"id":"KAYS","lat":31.25,"lon":-82.4,"state":"GA","location":"Waycross / Ware County, Ga","city":"Waycross","priority":99}, + "KAZE": {"id":"KAZE","lat":31.8847,"lon":-82.6474,"state":"GA","location":"Hazlehurst Airport","city":"Hazlehurst","priority":13}, + "KBGE": {"id":"KBGE","lat":30.96667,"lon":-84.63333,"state":"GA","location":"Bainbridge, Decatur County Industrial Air Park Airport","city":"Bainbridge","priority":15}, + "KBHC": {"id":"KBHC","lat":31.7138,"lon":-82.3938,"state":"GA","location":"Baxley Municipal Airport","city":"Baxley","priority":9}, + "KBIJ": {"id":"KBIJ","lat":31.39694,"lon":-84.895,"state":"GA","location":"Blakely, Early County Airport","city":"Blakely","priority":10}, + "KBQK": {"id":"KBQK","lat":31.25,"lon":-81.4666699,"state":"GA","location":"Brunswick / Glynco","city":"Glynco","priority":99}, + "KCCO": {"id":"KCCO","lat":33.31222,"lon":-84.77028,"state":"GA","location":"Newnan, Newnan Coweta County Airport","city":"Newnan","priority":10}, + "KCNI": {"id":"KCNI","lat":34.31056,"lon":-84.42389,"state":"GA","location":"Canton, Cherokee County Airport","city":"Canton","priority":10}, + "KCPP": {"id":"KCPP","lat":33.5979699,"lon":-83.13826,"state":"GA","location":"Greene County Regional Airport","city":"Greene Co.","priority":10}, + "KCSG": {"id":"KCSG","lat":32.51611,"lon":-84.94222,"state":"GA","location":"Columbus, Columbus Metropolitan Airport","city":"Columbus","priority":13}, + "KCTJ": {"id":"KCTJ","lat":33.63,"lon":-85.15,"state":"GA","location":"Carrollton West Georgia Regional Airport","city":"Carrollton West Georgia","priority":3}, + "KCVC": {"id":"KCVC","lat":33.632,"lon":-83.85,"state":"GA","location":"Covington Municipal Airport","city":"Covington","priority":9}, + "KCWV": {"id":"KCWV","lat":32.1950999,"lon":-81.8696,"state":"GA","location":"Claxton Evans County Airport","city":"Claxton","priority":10}, + "KCXU": {"id":"KCXU","lat":31.2132,"lon":-84.2352,"state":"GA","location":"Camilla-Mitchell County Airport","city":"Camilla","priority":10}, + "KCZL": {"id":"KCZL","lat":34.4554,"lon":-84.9392,"state":"GA","location":"Calhoun Tom B. David Field Airport","city":"Calhoun","priority":12}, + "KDBN": {"id":"KDBN","lat":32.56444,"lon":-82.985,"state":"GA","location":"Dublin, W H 'Bud' Barron Airport","city":"Dublin","priority":13}, + "KDNL": {"id":"KDNL","lat":33.4669,"lon":-82.03836,"state":"GA","location":"Augusta Daniel Field","city":"Augusta Daniel","priority":12}, + "KDNN": {"id":"KDNN","lat":34.72167,"lon":-84.86917,"state":"GA","location":"Dalton, Dalton Municipal Airport","city":"Dalton","priority":9}, + "KDQH": {"id":"KDQH","lat":31.47667,"lon":-82.86028,"state":"GA","location":"Douglas, Douglas Municipal Airport","city":"Douglas","priority":9}, + "KDZJ": {"id":"KDZJ","lat":34.8544,"lon":-83.9973,"state":"GA","location":"Blairsville Airport","city":"Blairsville","priority":13}, + "KEBA": {"id":"KEBA","lat":34.095,"lon":-82.81583,"state":"GA","location":"Elbert County - Patz Field","city":"Elbert Co.","priority":10}, + "KEZM": {"id":"KEZM","lat":32.21417,"lon":-83.12778,"state":"GA","location":"Eastman, Heart of Georgia Regional Airport","city":"Eastman","priority":3}, + "KFFC": {"id":"KFFC","lat":33.35436,"lon":-84.56893,"state":"GA","location":"Atlanta Regional Airport-Falcon Field","city":"Atlanta Regional","priority":3}, + "KFTY": {"id":"KFTY","lat":33.77764,"lon":-84.52461,"state":"GA","location":"Fulton County Airport-Brown Field","city":"Fulton Co.","priority":10}, + "KFZG": {"id":"KFZG","lat":31.6839,"lon":-83.2709,"state":"GA","location":"Fitzgerald Municipal Airport","city":"Fitzgerald","priority":9}, + "KGVL": {"id":"KGVL","lat":34.27194,"lon":-83.83028,"state":"GA","location":"Gainesville, Gilmer Memorial Airport","city":"Gainesville","priority":11}, + "KHMP": {"id":"KHMP","lat":33.3899,"lon":-84.331,"state":"GA","location":"Henry County Airport","city":"Henry Co.","priority":10}, + "KHOE": {"id":"KHOE","lat":31.0559,"lon":-82.7741,"state":"GA","location":"Homerville Airport","city":"Homerville","priority":13}, + "KHQU": {"id":"KHQU","lat":33.52944,"lon":-82.51639,"state":"GA","location":"Thomson, Thomson-McDuffie County Airport","city":"Thomson","priority":10}, + "KIIY": {"id":"KIIY","lat":33.77972,"lon":-82.81639,"state":"GA","location":"Washington, Washington-Wilkes County Airport","city":"Washington","priority":10}, + "KJCA": {"id":"KJCA","lat":34.17586,"lon":-83.5616,"state":"GA","location":"Jackson County Airport","city":"Jackson Co.","priority":10}, + "KJES": {"id":"KJES","lat":31.554,"lon":-81.8824999,"state":"GA","location":"Jesup-Wayne County Airport","city":"Jesup","priority":10}, + "KJYL": {"id":"KJYL","lat":32.64528,"lon":-81.59639,"state":"GA","location":"Sylvania, Plantation Airpark","city":"Sylvania","priority":15}, + "KJZP": {"id":"KJZP","lat":34.45417,"lon":-84.45971,"state":"GA","location":"Jasper Pickens County Airport","city":"Jasper","priority":10}, + "KLGC": {"id":"KLGC","lat":33.00617,"lon":-85.06609,"state":"GA","location":"LaGrange-Callaway Airport","city":"LaGrange","priority":13}, + "KLHW": {"id":"KLHW","lat":31.88724,"lon":-81.56244,"state":"GA","location":"Wright Army Airfield (Fort Stewart)/Midcoast Regional Airport","city":"Midcoast","priority":14}, + "KLSF": {"id":"KLSF","lat":32.3333299,"lon":-84.83333,"state":"GA","location":"Fort Benning","city":"Ft Benning","priority":99}, + "KLZU": {"id":"KLZU","lat":33.98288,"lon":-83.95842,"state":"GA","location":"Gwinnett County Airport-Briscoe Field","city":"Gwinnett Co.","priority":10}, + "KMCN": {"id":"KMCN","lat":32.68892,"lon":-83.65293,"state":"GA","location":"Middle Georgia Regional Airport","city":"Middle Georgia","priority":3}, + "KMGE": {"id":"KMGE","lat":33.91667,"lon":-84.51667,"state":"GA","location":"Marietta / Dobbins Air Force Base","city":"Marietta","priority":14}, + "KMGR": {"id":"KMGR","lat":31.08472,"lon":-83.80306,"state":"GA","location":"Moultrie, Moultrie Municipal Airport","city":"Moultrie","priority":9}, + "KMHP": {"id":"KMHP","lat":32.37397,"lon":-82.08144,"state":"GA","location":"Metter Municipal Airport","city":"Metter","priority":9}, + "KMLJ": {"id":"KMLJ","lat":33.15417,"lon":-83.24056,"state":"GA","location":"Milledgeville, Baldwin County Airport","city":"Milledgeville","priority":10}, + "KMQW": {"id":"KMQW","lat":32.09699,"lon":-82.8794099,"state":"GA","location":"Telfair-Wheeler Airport","city":"Telfair","priority":13}, + "KOPN": {"id":"KOPN","lat":32.955,"lon":-84.2644399,"state":"GA","location":"Thomaston, Thomaston-Upson County Airport","city":"Thomaston","priority":10}, + "KPDK": {"id":"KPDK","lat":33.87833,"lon":-84.29806,"state":"GA","location":"Atlanta, De Kalb-Peachtree Airport","city":"De Kalb-Peachtree","priority":13}, + "KPIM": {"id":"KPIM","lat":32.8407,"lon":-84.8824,"state":"GA","location":"Pine Mountain Harris County Airport","city":"Pine Mtn","priority":10}, + "KPUJ": {"id":"KPUJ","lat":33.9189999,"lon":-84.952,"state":"GA","location":"Dallas Paulding County Regional Airport","city":"Dallas","priority":10}, + "KPXE": {"id":"KPXE","lat":32.5105999,"lon":-83.7673,"state":"GA","location":"Perry-Houston County Airport","city":"Perry","priority":10}, + "KRMG": {"id":"KRMG","lat":34.34778,"lon":-85.1611099,"state":"GA","location":"Rome, R. B. Russell Airport","city":"Rome","priority":13}, + "KRVJ": {"id":"KRVJ","lat":32.0594899,"lon":-82.15358,"state":"GA","location":"Swinton Smith Field at Reidsville Municipal Airport","city":"Reidsville","priority":9}, + "KRYY": {"id":"KRYY","lat":34.01467,"lon":-84.59635,"state":"GA","location":"Cobb County International Airport - McCollum Field","city":"Cobb Co.","priority":1}, + "KSAV": {"id":"KSAV","lat":32.1313699,"lon":-81.20226,"state":"GA","location":"Savannah-Hilton Head International Airport","city":"Savannah","priority":1}, + "KSBO": {"id":"KSBO","lat":32.6091,"lon":-82.3699,"state":"GA","location":"Swainsboro Emanuel County Airport","city":"Swainsboro","priority":10}, + "KSSI": {"id":"KSSI","lat":31.15167,"lon":-81.39139,"state":"GA","location":"Brunswick, Malcolm McKinnon Airport","city":"Brunswick","priority":13}, + "KSVN": {"id":"KSVN","lat":32.01667,"lon":-81.15,"state":"GA","location":"Hunter U. S. Army Airfield","city":"Hunter","priority":14}, + "KTBR": {"id":"KTBR","lat":32.48306,"lon":-81.7372199,"state":"GA","location":"Statesboro, Statesboro-Bulloch County Airport","city":"Statesboro","priority":10}, + "KTMA": {"id":"KTMA","lat":31.429,"lon":-83.4885,"state":"GA","location":"Tifton Henry Tift Myers","city":"Tifton","priority":99}, + "KTOC": {"id":"KTOC","lat":34.5927999,"lon":-83.2964,"state":"GA","location":"Toccoa Le Tourneau Airport","city":"Toccoa","priority":13}, + "KTVI": {"id":"KTVI","lat":30.90179,"lon":-83.88113,"state":"GA","location":"Thomasville Regional Airport","city":"Thomasville","priority":3}, + "KVAD": {"id":"KVAD","lat":30.97913,"lon":-83.19247,"state":"GA","location":"Moody Air Force Base","city":"Moody","priority":14}, + "KVDI": {"id":"KVDI","lat":32.1925,"lon":-82.37194,"state":"GA","location":"Vidalia, Vidalia Municipal Airport","city":"Vidalia","priority":9}, + "KVLD": {"id":"KVLD","lat":30.77632,"lon":-83.27389,"state":"GA","location":"Valdosta Regional Airport","city":"Valdosta","priority":3}, + "KVPC": {"id":"KVPC","lat":34.11589,"lon":-84.85064,"state":"GA","location":"Cartersville Airport","city":"Cartersville","priority":13}, + "KWDR": {"id":"KWDR","lat":33.98222,"lon":-83.66806,"state":"GA","location":"Winder, Winder-Barrow Airport","city":"Winder","priority":13}, + "KWRB": {"id":"KWRB","lat":32.63333,"lon":-83.6,"state":"GA","location":"Warner Robins Air Force Base","city":"Warner Robins","priority":14}, + "KMNV": {"id":"KMNV","lat":35.54522,"lon":-84.38039,"state":"TN","location":"Monroe County Airport","city":"Monroe Co.","priority":10}, + "KMOR": {"id":"KMOR","lat":36.1794,"lon":-83.3754,"state":"TN","location":"Morristown Moore-Murrell Airport","city":"Morristown Moore","priority":13}, + "KMQY": {"id":"KMQY","lat":36.00889,"lon":-86.52,"state":"TN","location":"Smyrna, Smyrna Airport","city":"Smyrna","priority":13}, + "KMRC": {"id":"KMRC","lat":35.55,"lon":-87.18333,"state":"TN","location":"Columbia / Maury County","city":"Columbia","priority":10}, + "KNQA": {"id":"KNQA","lat":35.35667,"lon":-89.8702799,"state":"TN","location":"Millington, Millington Municipal Airport","city":"Millington","priority":9}, + "KOQT": {"id":"KOQT","lat":36.02278,"lon":-84.23333,"state":"TN","location":"Oak Ridge","city":"Oak Ridge","priority":99}, + "KPHT": {"id":"KPHT","lat":36.34,"lon":-88.38,"state":"TN","location":"Paris - Henry County Airport","city":"Paris","priority":10}, + "KRKW": {"id":"KRKW","lat":35.92501,"lon":-84.691,"state":"TN","location":"Rockwood Municipal Airport","city":"Rockwood","priority":9}, + "KRNC": {"id":"KRNC","lat":35.6991,"lon":-85.8402,"state":"TN","location":"McMinnville Warren County Memorial Airport","city":"McMinnville","priority":10}, + "KRZR": {"id":"KRZR","lat":35.2115,"lon":-84.7998,"state":"TN","location":"Cleveland Regional Jetport","city":"Cleveland","priority":3}, + "KSCX": {"id":"KSCX","lat":36.45569,"lon":-84.58575,"state":"TN","location":"Scott Municipal Airport","city":"Scott","priority":9}, + "KSNH": {"id":"KSNH","lat":35.17,"lon":-88.22,"state":"TN","location":"SAVANNAH/HARDIN CO","city":"Savannah","priority":99}, + "KSRB": {"id":"KSRB","lat":36.0559,"lon":-85.5307,"state":"TN","location":"Sparta Upper Cumberland Regional Airport","city":"Sparta Upper Cumberland","priority":3}, + "KSYI": {"id":"KSYI","lat":35.5593999,"lon":-86.4425,"state":"TN","location":"Shelbyville Bomar Field & Shelbyville Municipal Airport","city":"Shelbyville Bomar","priority":9}, + "KSZY": {"id":"KSZY","lat":35.2,"lon":-88.5,"state":"TN","location":"SELMER/ROBERT SIBLEY","city":"Selmer","priority":99}, + "KTHA": {"id":"KTHA","lat":35.38,"lon":-86.2467,"state":"TN","location":"Tullahoma Regional Airport/William Northern Field","city":"Tullahoma","priority":3}, + "KTRI": {"id":"KTRI","lat":36.47972,"lon":-82.39889,"state":"TN","location":"Bristol / Johnson / Kingsport, Tri-City Regional Airport","city":"Bristol","priority":3}, + "KTYS": {"id":"KTYS","lat":35.81806,"lon":-83.98583,"state":"TN","location":"Knoxville, McGhee Tyson Airport","city":"Knoxville","priority":13}, + "KUCY": {"id":"KUCY","lat":36.38,"lon":-88.98,"state":"TN","location":"Union City - Everett-Stewart Regional Airport","city":"Union City","priority":3}, + "KXNX": {"id":"KXNX","lat":36.3750799,"lon":-86.40842,"state":"TN","location":"Sumner County Regional Airport","city":"Sumner Co.","priority":10}, + "KAKR": {"id":"KAKR","lat":41.0375,"lon":-81.46417,"state":"OH","location":"Akron, Akron Fulton International Airport","city":"Akron","priority":1}, + "KAOH": {"id":"KAOH","lat":40.70806,"lon":-84.02139,"state":"OH","location":"Lima, Lima Allen County Airport","city":"Lima","priority":10}, + "KAXV": {"id":"KAXV","lat":40.49356,"lon":-84.29808,"state":"OH","location":"Neil Armstrong Airport","city":"Neil Armstrong","priority":13}, + "KBJJ": {"id":"KBJJ","lat":40.87306,"lon":-81.88667,"state":"OH","location":"Wooster, Wayne County Airport","city":"Wooster","priority":10}, + "KBKL": {"id":"KBKL","lat":41.52556,"lon":-81.66889,"state":"OH","location":"Cleveland, Burke Lakefront Airport","city":"Burke Lakefront","priority":13}, + "KCAK": {"id":"KCAK","lat":40.91811,"lon":-81.44343,"state":"OH","location":"Akron Canton Regional Airport","city":"Akron Canton","priority":3}, + "KCDI": {"id":"KCDI","lat":39.97393,"lon":-81.5807899,"state":"OH","location":"Cambridge Municipal Airport","city":"Cambridge","priority":9}, + "KCGF": {"id":"KCGF","lat":41.56667,"lon":-81.48333,"state":"OH","location":"Cleveland / Cuyahoga","city":"Cuyahoga","priority":99}, + "KCLE": {"id":"KCLE","lat":41.40569,"lon":-81.85193,"state":"OH","location":"Cleveland Hopkins International Airport","city":"Cleveland","priority":1}, + "KCMH": {"id":"KCMH","lat":39.9906999,"lon":-82.87691,"state":"OH","location":"John Glenn Columbus International Airport","city":"Columbus","priority":1}, + "KDAY": {"id":"KDAY","lat":39.90611,"lon":-84.21861,"state":"OH","location":"Dayton, Cox Dayton International Airport","city":"Dayton","priority":1}, + "KDFI": {"id":"KDFI","lat":41.33639,"lon":-84.42944,"state":"OH","location":"Defiance, Defiance Memorial Airport","city":"Defiance","priority":11}, + "KDLZ": {"id":"KDLZ","lat":40.2797,"lon":-83.1148,"state":"OH","location":"Delaware Municipal Airport","city":"Delaware","priority":9}, + "KEDJ": {"id":"KEDJ","lat":40.3723,"lon":-83.8192,"state":"OH","location":"Bellefontaine Regional Airport","city":"Bellefontaine","priority":3}, + "KFDY": {"id":"KFDY","lat":41.01361,"lon":-83.66861,"state":"OH","location":"Findlay, Findlay Airport","city":"Findlay","priority":13}, + "KFFO": {"id":"KFFO","lat":39.8333299,"lon":-84.05,"state":"OH","location":"Dayton / Wright-Patterson Air Force Base","city":"Wright-Patterson AFB","priority":14}, + "KGDK": {"id":"KGDK","lat":39.69072,"lon":-83.99278,"state":"OH","location":"Greene County - Lewis A Jackson Regional Airport","city":"Greene Co.","priority":10}, + "KHAO": {"id":"KHAO","lat":39.36121,"lon":-84.52061,"state":"OH","location":"Butler County Regional Airport","city":"Butler Co.","priority":10}, + "KHOC": {"id":"KHOC","lat":39.18876,"lon":-83.53879,"state":"OH","location":"HILLSBORO","city":"Hillsboro","priority":99}, + "KHZY": {"id":"KHZY","lat":41.77944,"lon":-80.69667,"state":"OH","location":"Ashtabula - Northeast Ohio Regional Airport","city":"Ashtabula","priority":3}, + "KILN": {"id":"KILN","lat":39.42833,"lon":-83.7791699,"state":"OH","location":"Wilmington, Airborne Airpark Airport","city":"Wilmington","priority":15}, + "KJRO": {"id":"KJRO","lat":38.9833,"lon":-82.5833,"state":"OH","location":"JACKSON","city":"Jackson","priority":99}, + "KLCK": {"id":"KLCK","lat":39.81667,"lon":-82.93333,"state":"OH","location":"Rickenbacker Air National Guard Base","city":"Rickenbacker","priority":2}, + "KLHQ": {"id":"KLHQ","lat":39.7572199,"lon":-82.66333,"state":"OH","location":"Lancaster, Fairfield County Airport","city":"Lancaster","priority":10}, + "KLNN": {"id":"KLNN","lat":41.68333,"lon":-81.38333,"state":"OH","location":"Willoughby","city":"Willoughby","priority":99}, + "KLPR": {"id":"KLPR","lat":41.34611,"lon":-82.17944,"state":"OH","location":"Lorain / Elyria, Lorain County Regional Airport","city":"Lorain","priority":10}, + "KLUK": {"id":"KLUK","lat":39.10583,"lon":-84.41583,"state":"OH","location":"Cincinnati, Cincinnati Municipal Airport Lunken Field","city":"Cincinnati","priority":9}, + "KMFD": {"id":"KMFD","lat":40.8202799,"lon":-82.51778,"state":"OH","location":"Mansfield - Mansfield Lahm Regional Airport","city":"Mansfield","priority":3}, + "KMGY": {"id":"KMGY","lat":39.58889,"lon":-84.22472,"state":"OH","location":"Dayton, Dayton-Wright Brothers Airport","city":"Wright Brothers","priority":13}, + "KMNN": {"id":"KMNN","lat":40.61667,"lon":-83.06833,"state":"OH","location":"Marion, Marion Municipal Airport","city":"Marion","priority":9}, + "KMRT": {"id":"KMRT","lat":40.2247,"lon":-83.3516,"state":"OH","location":"Marysville Union County Airport","city":"Marysville","priority":10}, + "KMWO": {"id":"KMWO","lat":39.531,"lon":-84.3953,"state":"OH","location":"Hook Field Municipal Airport","city":"Hook","priority":9}, + "KOSU": {"id":"KOSU","lat":40.07806,"lon":-83.0780599,"state":"OH","location":"Columbus, Ohio State University Airport","city":"Ohio State University","priority":6}, + "KOWX": {"id":"KOWX","lat":41.0356,"lon":-83.982,"state":"OH","location":"Ottawa Putnam County Airport","city":"Ottawa","priority":10}, + "KOXD": {"id":"KOXD","lat":39.5022499,"lon":-84.78436,"state":"OH","location":"Miami University Airport","city":"Miami University","priority":13}, + "KPCW": {"id":"KPCW","lat":41.5163,"lon":-82.8687,"state":"OH","location":"Port Clinton Carl R Keller Field Airport","city":"Port Clinton","priority":12}, + "KPHD": {"id":"KPHD","lat":40.47032,"lon":-81.42178,"state":"OH","location":"Harry Clever Field Airport","city":"Harry Clever","priority":12}, + "KPMH": {"id":"KPMH","lat":38.84047,"lon":-82.8473099,"state":"OH","location":"Greater Portsmouth Regional Airport","city":"Greater Portsmouth","priority":3}, + "KPOV": {"id":"KPOV","lat":41.21,"lon":-81.252,"state":"OH","location":"Portage County Airport","city":"Portage Co.","priority":10}, + "KRZT": {"id":"KRZT","lat":39.4403999,"lon":-83.0231,"state":"OH","location":"Chillicothe Ross County Airport","city":"Chillicothe","priority":10}, + "KSGH": {"id":"KSGH","lat":39.84028,"lon":-83.84,"state":"OH","location":"Springfield, Springfield-Beckley Municipal Airport","city":"Springfield","priority":9}, + "KTDZ": {"id":"KTDZ","lat":41.56306,"lon":-83.47639,"state":"OH","location":"Toledo - Toledo Executive Airport","city":"TDZ","priority":5}, + "KTOL": {"id":"KTOL","lat":41.58704,"lon":-83.80539,"state":"OH","location":"Toledo - Toledo Express Airport","city":"Toledo","priority":4}, + "KTZR": {"id":"KTZR","lat":39.90083,"lon":-83.13722,"state":"OH","location":"Columbus, Bolton Field Airport","city":"Bolton","priority":12}, + "KUNI": {"id":"KUNI","lat":39.22,"lon":-82.23,"state":"OH","location":"OHIO U/ATHEN-ALBANY","city":"Ohio U","priority":99}, + "KUSE": {"id":"KUSE","lat":41.6101,"lon":-84.1272,"state":"OH","location":"Wauseon Fulton County Airport","city":"Wauseon","priority":10}, + "KUYF": {"id":"KUYF","lat":39.9326999,"lon":-83.462,"state":"OH","location":"London Madison County Airport","city":"London","priority":10}, + "KVES": {"id":"KVES","lat":40.2044,"lon":-84.5318999,"state":"OH","location":"Versailles Darke County Airport","city":"Versailles","priority":10}, + "KVNW": {"id":"KVNW","lat":40.86383,"lon":-84.60636,"state":"OH","location":"Van Wert County Airport","city":"Van Wert Co.","priority":10}, + "KVTA": {"id":"KVTA","lat":40.02278,"lon":-82.4625,"state":"OH","location":"Newark, Newark Heath Airport","city":"Newark","priority":13}, + "KYNG": {"id":"KYNG","lat":41.25444,"lon":-80.67389,"state":"OH","location":"Youngstown, Youngstown-Warren Regional Airport","city":"Youngstown","priority":3}, + "KZZV": {"id":"KZZV","lat":39.94609,"lon":-81.89315,"state":"OH","location":"Zanesville Municipal Airport","city":"Zanesville","priority":9}, + "KBOI": {"id":"KBOI","lat":43.56704,"lon":-116.24053,"state":"ID","location":"Boise Air Terminal","city":"Boise Air Terminal","priority":99}, + "KBYI": {"id":"KBYI","lat":42.54525,"lon":-113.7686,"state":"ID","location":"Burley Municipal Airport","city":"Burley","priority":9}, + "KCOE": {"id":"KCOE","lat":47.76667,"lon":-116.81667,"state":"ID","location":"Coeur d'Alene Airport - Pappy Boyington Field","city":"Coeur d'Alene","priority":12}, + "KDIJ": {"id":"KDIJ","lat":43.74167,"lon":-111.09778,"state":"ID","location":"Driggs, Driggs-Reed Memorial Airport","city":"Driggs","priority":11}, + "KETI": {"id":"KETI","lat":43.6816666,"lon":-114.3627777,"state":"ID","location":"Ketchum Ranger Station","city":"Ketchum","priority":99}, + "KEUL": {"id":"KEUL","lat":43.64055,"lon":-116.63017,"state":"ID","location":"Caldwell - Caldwell Industrial Airport","city":"Caldwell","priority":13}, + "KGIC": {"id":"KGIC","lat":45.94111,"lon":-116.13257,"state":"ID","location":"Grangeville - Idaho County Airport","city":"Grangeville","priority":10}, + "KGNG": {"id":"KGNG","lat":42.91716,"lon":-114.76516,"state":"ID","location":"Gooding Municipal Airport","city":"Gooding","priority":9}, + "KIDA": {"id":"KIDA","lat":43.5208299,"lon":-112.06611,"state":"ID","location":"Idaho Falls Regional Airport","city":"Idaho Falls","priority":3}, + "KJER": {"id":"KJER","lat":42.72736,"lon":-114.45469,"state":"ID","location":"Jerome County Airport","city":"Jerome Co.","priority":10}, + "KLLJ": {"id":"KLLJ","lat":44.523,"lon":-114.21611,"state":"ID","location":"Challis - Challis Airport","city":"Challis","priority":13}, + "KLWS": {"id":"KLWS","lat":46.37472,"lon":-117.01444,"state":"ID","location":"Lewiston, Lewiston-Nez Perce County Airport","city":"Lewiston","priority":10}, + "KMAN": {"id":"KMAN","lat":43.5813,"lon":-116.5231,"state":"ID","location":"Nampa Municipal Airport","city":"Nampa","priority":9}, + "KMUO": {"id":"KMUO","lat":43.05,"lon":-115.86667,"state":"ID","location":"Mountain Home Air Force Base","city":"Mountain Home","priority":14}, + "KMYL": {"id":"KMYL","lat":44.89425,"lon":-116.09978,"state":"ID","location":"McCall Airport","city":"McCall","priority":13}, + "KPIH": {"id":"KPIH","lat":42.92028,"lon":-112.57111,"state":"ID","location":"Pocatello, Pocatello Regional Airport","city":"Pocatello","priority":3}, + "KRXE": {"id":"KRXE","lat":43.83167,"lon":-111.80611,"state":"ID","location":"Rexburg, Rexburg-Madison County Airport","city":"Rexburg","priority":10}, + "KSMN": {"id":"KSMN","lat":45.11667,"lon":-113.88333,"state":"ID","location":"Salmon, Lemhi County Airport","city":"Salmon","priority":10}, + "KSNT": {"id":"KSNT","lat":44.20861,"lon":-114.93444,"state":"ID","location":"Stanley, Stanley Ranger Station","city":"Stanley","priority":99}, + "KSUN": {"id":"KSUN","lat":43.5,"lon":-114.3,"state":"ID","location":"Hailey, Friedman Memorial Airport","city":"Hailey","priority":11}, + "KSZT": {"id":"KSZT","lat":48.29944,"lon":-116.56,"state":"ID","location":"Sandpoint, Sandpoint Airport","city":"Sandpoint","priority":13}, + "KTBI": {"id":"KTBI","lat":43.5486099,"lon":-112.32583,"state":"ID","location":"Kettle Butte","city":"Kettle Butte","priority":99}, + "KTWF": {"id":"KTWF","lat":42.4784999,"lon":-114.47739,"state":"ID","location":"Joslin Field - Magic Valley Regional Airport","city":"Joslin","priority":3}, + "PALI": {"id":"PALI","lat":43.3508333,"lon":-111.2183333,"state":"ID","location":"Snake River near Irwin, ID","city":"Irwin","priority":50}, + "PARI": {"id":"PARI","lat":43.7816666,"lon":-116.9713888,"state":"ID","location":"Boise River near Parma, ID","city":"Parma","priority":50}, + "PAYI": {"id":"PAYI","lat":44.9083333,"lon":-116.1194444,"state":"ID","location":"North Fork Payette River at McCall, Idaho","city":"PAYI","priority":50}, + "PECI": {"id":"PECI","lat":43.2841666,"lon":-112.25,"state":"ID","location":"Peoples Canal","city":"Peoples Canal","priority":50}, + "PICI": {"id":"PICI","lat":43.31167,"lon":-114.16583,"state":"ID","location":"PICABO","city":"Picabo","priority":50}, + "PLCI": {"id":"PLCI","lat":43.7458333,"lon":-112.1027777,"state":"ID","location":"Palisades Canal near Irwin, ID","city":"PLCI","priority":50}, + "PLEI": {"id":"PLEI","lat":43.8963888,"lon":-116.6258333,"state":"ID","location":"Payette River near Letha, ID","city":"Letha","priority":50}, + "PMAI": {"id":"PMAI","lat":43.8,"lon":-116.93333,"state":"ID","location":"PARMA","city":"Parma PMAI","priority":50}, + "PNRI": {"id":"PNRI","lat":43.6225,"lon":-116.1933333,"state":"ID","location":"PN Region USBR Hydromet Test Site - Boise, ID","city":"PN Region USBR Hydromet Test Site","priority":50}, + "POCI": {"id":"POCI","lat":43.5030555,"lon":-112.0480555,"state":"ID","location":"Porter Canal","city":"Porter Canal","priority":50}, + "PRKI": {"id":"PRKI","lat":43.6888888,"lon":-111.8661111,"state":"ID","location":"Parks and Lewisville Canal near Rigby, ID","city":"Rigby","priority":50}, + "PRLI": {"id":"PRLI","lat":44.0847222,"lon":-115.6027777,"state":"ID","location":"South Fork Payette River at Lowman, ID","city":"Lowman","priority":50}, + "PRPI": {"id":"PRPI","lat":44.0424999,"lon":-116.9241666,"state":"ID","location":"Payette River near Payette, ID","city":"Payette","priority":50}, + "PSFI": {"id":"PSFI","lat":47.71366,"lon":-116.9701,"state":"ID","location":"Post Falls","city":"Post Falls","priority":50}, + "KACZ": {"id":"KACZ","lat":34.71786,"lon":-78.00389,"state":"NC","location":"Henderson Field Airport","city":"Henderson","priority":12}, + "KAFP": {"id":"KAFP","lat":35.01944,"lon":-80.07836,"state":"NC","location":"Anson County Airport","city":"Anson Co.","priority":10}, + "KAKH": {"id":"KAKH","lat":35.1968699,"lon":-81.15545,"state":"NC","location":"Gastonia Municipal Airport","city":"Gastonia","priority":9}, + "KASJ": {"id":"KASJ","lat":36.2975,"lon":-77.17083,"state":"NC","location":"Ahoskie, Tri-County Airport","city":"Ahoskie","priority":13}, + "KAVL": {"id":"KAVL","lat":35.43194,"lon":-82.5375,"state":"NC","location":"Asheville, Asheville Regional Airport","city":"Asheville","priority":3}, + "KBUY": {"id":"KBUY","lat":36.04753,"lon":-79.47375,"state":"NC","location":"Burlington Alamance Regional Airport","city":"Burlington Alamance","priority":3}, + "KCLT": {"id":"KCLT","lat":35.2083299,"lon":-80.96139,"state":"NC","location":"Charlotte/Douglas International Airport","city":"Charlotte","priority":1}, + "KCPC": {"id":"KCPC","lat":34.27278,"lon":-78.715,"state":"NC","location":"Whiteville, Columbus County Municipal Airport","city":"Whiteville","priority":10}, + "KCTZ": {"id":"KCTZ","lat":34.97522,"lon":-78.36276,"state":"NC","location":"Sampson County Airport","city":"Sampson Co.","priority":10}, + "KDPL": {"id":"KDPL","lat":34.99942,"lon":-77.97995,"state":"NC","location":"Duplin County Airport","city":"Duplin Co.","priority":10}, + "KECG": {"id":"KECG","lat":36.25771,"lon":-76.1716,"state":"NC","location":"Elizabeth City C/G Regional Airport","city":"Elizabeth City C","priority":3}, + "KEDE": {"id":"KEDE","lat":36.02778,"lon":-76.56722,"state":"NC","location":"Edenton, Northeastern Regional Airport","city":"Edenton","priority":3}, + "KEHO": {"id":"KEHO","lat":35.2556299,"lon":-81.59858,"state":"NC","location":"Shelby Municipal Airport","city":"Shelby","priority":9}, + "KEQY": {"id":"KEQY","lat":35.01694,"lon":-80.62056,"state":"NC","location":"Monroe, Monroe Airport","city":"Monroe","priority":13}, + "KETC": {"id":"KETC","lat":35.9373,"lon":-77.54648,"state":"NC","location":"Tarboro-Edgecombe Airport","city":"Tarboro","priority":13}, + "KEWN": {"id":"KEWN","lat":35.0675,"lon":-77.04722,"state":"NC","location":"New Bern, Craven County Regional Airport","city":"New Bern","priority":10}, + "KEXX": {"id":"KEXX","lat":35.78111,"lon":-80.30389,"state":"NC","location":"Lexington, Davidson County Airport","city":"Lexington","priority":10}, + "KEYF": {"id":"KEYF","lat":34.60418,"lon":-78.57902,"state":"NC","location":"Curtis L Brown Jr. Field Airport","city":"Curtis L Brown Jr.","priority":12}, + "KFAY": {"id":"KFAY","lat":34.98944,"lon":-78.88,"state":"NC","location":"Fayetteville, Fayetteville Regional Airport","city":"Fayetteville","priority":3}, + "KFBG": {"id":"KFBG","lat":35.1314,"lon":-78.93158,"state":"NC","location":"Fort Bragg / Simmons Army Airfield","city":"Ft Bragg","priority":14}, + "KFFA": {"id":"KFFA","lat":36.01667,"lon":-75.66667,"state":"NC","location":"Kill Devil Hills, First Flight Airport","city":"Kill Devil Hills","priority":13}, + "KFQD": {"id":"KFQD","lat":35.42833,"lon":-81.935,"state":"NC","location":"Rutherfordton, Rutherford County-Marchman Field Airport","city":"Rutherfordton","priority":10}, + "KGEV": {"id":"KGEV","lat":36.43333,"lon":-81.41667,"state":"NC","location":"Jefferson - Ashe County Airport","city":"Jefferson","priority":10}, + "KGSB": {"id":"KGSB","lat":35.34457,"lon":-77.94583,"state":"NC","location":"Seymour-Johnson Air Force Base","city":"Seymour-Johnson","priority":14}, + "KGSO": {"id":"KGSO","lat":36.0974999,"lon":-79.94361,"state":"NC","location":"Greensboro, Piedmont Triad International Airport","city":"Greensboro","priority":1}, + "KGWW": {"id":"KGWW","lat":35.46056,"lon":-77.965,"state":"NC","location":"Goldsboro, Goldsboro-Wayne Municipal Airport","city":"Goldsboro","priority":9}, + "KHBI": {"id":"KHBI","lat":35.6538899,"lon":-79.895,"state":"NC","location":"Asheboro, Asheboro Municipal Airport","city":"Asheboro","priority":9}, + "KHFF": {"id":"KHFF","lat":35.03333,"lon":-79.5,"state":"NC","location":"Mackall U. S. Army Airfield","city":"Mackall","priority":14}, + "KHKY": {"id":"KHKY","lat":35.74222,"lon":-81.38222,"state":"NC","location":"Hickory, Hickory Regional Airport","city":"Hickory","priority":3}, + "KHNZ": {"id":"KHNZ","lat":36.36352,"lon":-78.52889,"state":"NC","location":"Henderson-Oxford Airport","city":"Oxford","priority":13}, + "KHRJ": {"id":"KHRJ","lat":35.37861,"lon":-78.73361,"state":"NC","location":"Erwin, Harnett County Airport","city":"Erwin","priority":10}, + "KHSE": {"id":"KHSE","lat":35.23222,"lon":-75.6225,"state":"NC","location":"Hatteras, Mitchell Field","city":"Hatteras","priority":12}, + "KILM": {"id":"KILM","lat":34.26681,"lon":-77.89987,"state":"NC","location":"Wilmington International Airport","city":"Wilmington","priority":1}, + "KINT": {"id":"KINT","lat":36.13333,"lon":-80.22472,"state":"NC","location":"Winston Salem, Smith Reynolds Airport","city":"Winston Salem","priority":13}, + "KIPJ": {"id":"KIPJ","lat":35.48306,"lon":-81.16139,"state":"NC","location":"Lincolnton, Lincolnton-Lincoln County Regional Airport","city":"Lincolnton","priority":10}, + "KISO": {"id":"KISO","lat":35.3333299,"lon":-77.61667,"state":"NC","location":"Kinston, Kinston Regional Jetport at Stallings Field","city":"Stallings","priority":3}, + "KIXA": {"id":"KIXA","lat":36.33,"lon":-77.635,"state":"NC","location":"Halifax-Northampton Regional Airport","city":"Halifax","priority":3}, + "KJNX": {"id":"KJNX","lat":35.54083,"lon":-78.39028,"state":"NC","location":"Smithfield, Johnston County Airport","city":"Smithfield","priority":10}, + "KJQF": {"id":"KJQF","lat":35.3896299,"lon":-80.70735,"state":"NC","location":"Concord Regional Airport","city":"Concord","priority":3}, + "KLBT": {"id":"KLBT","lat":34.60817,"lon":-79.059,"state":"NC","location":"Lumberton Municipal Airport","city":"Lumberton","priority":9}, + "KLHZ": {"id":"KLHZ","lat":36.02288,"lon":-78.33405,"state":"NC","location":"Franklin County Airport","city":"Franklin Co.","priority":10}, + "KMCZ": {"id":"KMCZ","lat":35.86219,"lon":-77.1782,"state":"NC","location":"Martin County Airport","city":"Martin Co.","priority":10}, + "KMEB": {"id":"KMEB","lat":34.79132,"lon":-79.3683,"state":"NC","location":"Laurinburg Maxton Airport","city":"Laurinburg Maxton","priority":13}, + "KMQI": {"id":"KMQI","lat":35.91667,"lon":-75.7,"state":"NC","location":"Manteo / Dare County Regional","city":"Manteo","priority":10}, + "KMRH": {"id":"KMRH","lat":34.73259,"lon":-76.6566,"state":"NC","location":"Beaufort Smith Field","city":"Beaufort Smith","priority":12}, + "KMRN": {"id":"KMRN","lat":35.81922,"lon":-81.60971,"state":"NC","location":"Morganton-Lenoir Airport","city":"Morganton","priority":13}, + "KMWK": {"id":"KMWK","lat":36.45675,"lon":-80.55483,"state":"NC","location":"Mount Airy/Surry County Airport","city":"Mt Airy","priority":10}, + "KNBT": {"id":"KNBT","lat":35.02222,"lon":-76.4625,"state":"NC","location":"Piney Island, Bt-11 Bombing Range","city":"Piney Is.","priority":99}, + "KNCA": {"id":"KNCA","lat":34.70627,"lon":-77.44066,"state":"NC","location":"MCAS New River","city":"MCAS New River","priority":14}, + "KNJM": {"id":"KNJM","lat":34.69403,"lon":-77.02945,"state":"NC","location":"Bogue Field Marine Corps Auxiliary Field","city":"Bogue","priority":12}, + "KNKT": {"id":"KNKT","lat":34.89719,"lon":-76.88135,"state":"NC","location":"Cherry Point Marine Corps Air Station","city":"Cherry Point","priority":14}, + "KOAJ": {"id":"KOAJ","lat":34.8333299,"lon":-77.61667,"state":"NC","location":"Jacksonville, Albert J Ellis Airport","city":"Jacksonville","priority":13}, + "KOCW": {"id":"KOCW","lat":35.57056,"lon":-77.0497199,"state":"NC","location":"Washington, Warren Field Airport","city":"Washington","priority":12}, + "KONX": {"id":"KONX","lat":36.39889,"lon":-76.01611,"state":"NC","location":"Currituck, Currituck County Airport","city":"Currituck","priority":10}, + "KPGV": {"id":"KPGV","lat":35.63742,"lon":-77.38506,"state":"NC","location":"Pitt-Greenville Airport","city":"Pitt","priority":13}, + "KPOB": {"id":"KPOB","lat":35.17531,"lon":-79.00771,"state":"NC","location":"Pope Air Force Base","city":"Pope","priority":14}, + "KRCZ": {"id":"KRCZ","lat":34.8954499,"lon":-79.75755,"state":"NC","location":"Rockingham-Hamlet Airport","city":"Rockingham","priority":13}, + "KRDU": {"id":"KRDU","lat":35.89223,"lon":-78.78185,"state":"NC","location":"Raleigh / Durham, Raleigh-Durham International Airport","city":"Raleigh","priority":1}, + "KRHP": {"id":"KRHP","lat":35.19394,"lon":-83.86182,"state":"NC","location":"Andrews-Murphy Airport","city":"Andrews","priority":13}, + "KRUQ": {"id":"KRUQ","lat":35.64417,"lon":-80.52359,"state":"NC","location":"Rowan County Airport","city":"Rowan Co.","priority":10}, + "KRWI": {"id":"KRWI","lat":35.8549999,"lon":-77.89306,"state":"NC","location":"Rocky Mount, Rocky Mount-Wilson Regional Airport","city":"Rocky Mount","priority":3}, + "KSCR": {"id":"KSCR","lat":35.7043,"lon":-79.5043,"state":"NC","location":"Siler City Municipal Airport","city":"Siler City","priority":9}, + "KSIF": {"id":"KSIF","lat":36.43722,"lon":-79.85083,"state":"NC","location":"Reidsville, Rockingham County NC Shiloh Airport","city":"Reidsville","priority":10}, + "KSOP": {"id":"KSOP","lat":35.23333,"lon":-79.4,"state":"NC","location":"Pinehurst/Southern Pines, Moore County Airport","city":"Pinehurst","priority":10}, + "KSUT": {"id":"KSUT","lat":33.92921,"lon":-78.07223,"state":"NC","location":"Brunswick County Airport","city":"Brunswick Co.","priority":10}, + "KSVH": {"id":"KSVH","lat":35.76362,"lon":-80.9473,"state":"NC","location":"Statesville Municipal Airport","city":"Statesville","priority":9}, + "KTDF": {"id":"KTDF","lat":36.2849999,"lon":-78.98417,"state":"NC","location":"Roxboro, Person County Airport","city":"Roxboro","priority":10}, + "KTNB": {"id":"KTNB","lat":36.19856,"lon":-81.65171,"state":"NC","location":"Watauga County Hospital Heliport","city":"Watauga Co.","priority":10}, + "KTQV": {"id":"KTQV","lat":36,"lon":-78.9333,"state":"NC","location":"DURHAM/DUKE","city":"Durham","priority":99}, + "KTTA": {"id":"KTTA","lat":35.5825,"lon":-79.10139,"state":"NC","location":"Sanford, Sanford-Lee County Regional Airport","city":"Sanford","priority":10}, + "KUKF": {"id":"KUKF","lat":36.21667,"lon":-81.08333,"state":"NC","location":"North Wilkesboro, Wilkes County Airport","city":"North Wilkesboro","priority":10}, + "KVUJ": {"id":"KVUJ","lat":35.41667,"lon":-80.15083,"state":"NC","location":"Albemarle, Stanly County Airport","city":"Albemarle","priority":10}, + "KLRY": {"id":"KLRY","lat":38.611,"lon":-94.3421,"state":"MO","location":"Harrisonville Lawrence Smith Memorial Airport","city":"Harrisonville","priority":11}, + "KLXT": {"id":"KLXT","lat":38.95972,"lon":-94.37167,"state":"MO","location":"Lee's Summit, Lee's Summit Municipal Airport","city":"Lee's Summit","priority":9}, + "KMAW": {"id":"KMAW","lat":36.6004999,"lon":-89.9922,"state":"MO","location":"Malden Municipal Airport","city":"Malden","priority":9}, + "KMBY": {"id":"KMBY","lat":39.46341,"lon":-92.42638,"state":"MO","location":"Omar N Bradley Airport","city":"Omar N Bradley","priority":13}, + "KMCI": {"id":"KMCI","lat":39.29722,"lon":-94.73056,"state":"MO","location":"Kansas City, Kansas City International Airport","city":"Kansas City","priority":1}, + "KMHL": {"id":"KMHL","lat":39.0955,"lon":-93.2028,"state":"MO","location":"Marshall Memorial Municipal Airport","city":"Marshall","priority":11}, + "KMKC": {"id":"KMKC","lat":39.12083,"lon":-94.59694,"state":"MO","location":"Kansas City, Kansas City Downtown Airport","city":"Kansas City Downtown","priority":13}, + "KMYJ": {"id":"KMYJ","lat":39.1575,"lon":-91.8182999,"state":"MO","location":"Mexico Memorial Airport","city":"Mexico","priority":11}, + "KOZS": {"id":"KOZS","lat":37.9739999,"lon":-92.6912,"state":"MO","location":"Camdenton Memorial Airport","city":"Camdenton","priority":11}, + "KPCD": {"id":"KPCD","lat":37.86867,"lon":-89.86214,"state":"MO","location":"Perryville Regional Airport","city":"Perryville","priority":3}, + "KPOF": {"id":"KPOF","lat":36.77056,"lon":-90.32222,"state":"MO","location":"Poplar Bluff, Poplar Bluff Municipal Airport","city":"Poplar Bluff","priority":9}, + "KRCM": {"id":"KRCM","lat":38.7842,"lon":-93.8028999,"state":"MO","location":"Skyhaven Airport","city":"Skyhaven","priority":13}, + "KSET": {"id":"KSET","lat":38.93056,"lon":-90.4325,"state":"MO","location":"St. Charles, St. Charles County Smartt Airport","city":"St Charles","priority":10}, + "KSGF": {"id":"KSGF","lat":37.23972,"lon":-93.38972,"state":"MO","location":"Springfield-Branson National Airport","city":"Springfield","priority":2}, + "KSIK": {"id":"KSIK","lat":36.8989,"lon":-89.5618,"state":"MO","location":"Sikeston Memorial Municipal Airport","city":"Sikeston","priority":11}, + "KSTJ": {"id":"KSTJ","lat":39.76806,"lon":-94.90917,"state":"MO","location":"St. Joseph, Rosecrans Memorial Airport","city":"St Joseph","priority":11}, + "KSTL": {"id":"KSTL","lat":38.7525,"lon":-90.37361,"state":"MO","location":"St. Louis Lambert International Airport","city":"St Louis","priority":1}, + "KSUS": {"id":"KSUS","lat":38.65722,"lon":-90.65583,"state":"MO","location":"St. Louis, Spirit Of St. Louis Airport","city":"Spirit Of St Louis","priority":13}, + "KSZL": {"id":"KSZL","lat":38.73333,"lon":-93.55,"state":"MO","location":"Whiteman Air Force Base","city":"Whiteman","priority":14}, + "KTBN": {"id":"KTBN","lat":37.73333,"lon":-92.13333,"state":"MO","location":"Fort Leonard Wood","city":"Ft Leonard Wood","priority":99}, + "KTKX": {"id":"KTKX","lat":36.22256,"lon":-90.03671,"state":"MO","location":"Kennett - Kennett Memorial Airport","city":"Kennett","priority":11}, + "KUNO": {"id":"KUNO","lat":36.87917,"lon":-91.905,"state":"MO","location":"West Plains, West Plains Municipal Airport","city":"West Plains","priority":9}, + "KUUV": {"id":"KUUV","lat":38.2335,"lon":-91.16433,"state":"MO","location":"SULLIVAN","city":"Sullivan","priority":99}, + "KVER": {"id":"KVER","lat":38.94672,"lon":-92.68267,"state":"MO","location":"Jesse Viertel Memorial Airport","city":"Jesse Viertel","priority":11}, + "KVIH": {"id":"KVIH","lat":38.13194,"lon":-91.76528,"state":"MO","location":"Rolla / Vichy, Rolla National Airport","city":"Rolla","priority":2}, + "KALB": {"id":"KALB","lat":42.74722,"lon":-73.79912,"state":"NY","location":"Albany International Airport","city":"Albany","priority":1}, + "KART": {"id":"KART","lat":43.99194,"lon":-76.02167,"state":"NY","location":"Watertown, Watertown International Airport","city":"Watertown","priority":1}, + "KBGM": {"id":"KBGM","lat":42.20778,"lon":-75.98139,"state":"NY","location":"Greater Binghamton Airport","city":"Greater Binghamton","priority":13}, + "KBUF": {"id":"KBUF","lat":42.93998,"lon":-78.73604,"state":"NY","location":"Buffalo, Greater Buffalo International Airport","city":"Buffalo","priority":1}, + "KCZG": {"id":"KCZG","lat":42.0785,"lon":-76.09633,"state":"NY","location":"ENDICOTT","city":"Endicott","priority":99}, + "KDKK": {"id":"KDKK","lat":42.49306,"lon":-79.27583,"state":"NY","location":"Dunkirk, Chautauqua County / Dunkirk Airport","city":"Dunkirk","priority":10}, + "KDSV": {"id":"KDSV","lat":42.56944,"lon":-77.71444,"state":"NY","location":"Dansville, Dansville Municipal Airport","city":"Dansville","priority":9}, + "KELM": {"id":"KELM","lat":42.15639,"lon":-76.90278,"state":"NY","location":"Elmira, Elmira / Corning Regional Airport","city":"Elmira","priority":3}, + "KELZ": {"id":"KELZ","lat":42.1075,"lon":-77.98444,"state":"NY","location":"Wellsville, Wellsville Municipal Airport","city":"Wellsville","priority":9}, + "KFOK": {"id":"KFOK","lat":40.85053,"lon":-72.61927,"state":"NY","location":"The Gabreski Airport","city":"Gabreski","priority":13}, + "KFRG": {"id":"KFRG","lat":40.73443,"lon":-73.41639,"state":"NY","location":"Farmingdale - Republic Airport","city":"Farmingdale","priority":13}, + "KFZY": {"id":"KFZY","lat":43.35083,"lon":-76.38806,"state":"NY","location":"Fulton, Oswego County Airport","city":"Fulton","priority":10}, + "KGFL": {"id":"KGFL","lat":43.34111,"lon":-73.61056,"state":"NY","location":"Glens Falls, Floyd Bennett Memorial Airport","city":"Glens Falls","priority":11}, + "KGTB": {"id":"KGTB","lat":44.05,"lon":-75.73333,"state":"NY","location":"Fort Drum / Wheeler-Sack U. S. Army Airfield","city":"Ft Drum","priority":14}, + "KGVQ": {"id":"KGVQ","lat":43.03175,"lon":-78.16967,"state":"NY","location":"Genesee County Airport","city":"Genesee Co.","priority":10}, + "KHPN": {"id":"KHPN","lat":41.06237,"lon":-73.70456,"state":"NY","location":"White Plains - Westchester County Airport","city":"White Plains","priority":10}, + "KHTF": {"id":"KHTF","lat":42.38216,"lon":-77.68216,"state":"NY","location":"HORNELL","city":"Hornell","priority":99}, + "KHWV": {"id":"KHWV","lat":40.82167,"lon":-72.8688899,"state":"NY","location":"Shirley, Brookhaven Airport","city":"Shirley","priority":13}, + "KIAG": {"id":"KIAG","lat":43.1082899,"lon":-78.93818,"state":"NY","location":"Niagara Falls, Niagara Falls International Airport","city":"Niagara Falls","priority":1}, + "KISP": {"id":"KISP","lat":40.79389,"lon":-73.10167,"state":"NY","location":"Islip, Long Island Mac Arthur Airport","city":"Islip","priority":13}, + "KITH": {"id":"KITH","lat":42.49083,"lon":-76.45833,"state":"NY","location":"Ithaca Tompkins International Airport","city":"Ithaca Tompkins","priority":1}, + "KIUA": {"id":"KIUA","lat":42.9089,"lon":-77.32523,"state":"NY","location":"Canandaigua Airport","city":"Canandaigua","priority":13}, + "KJFK": {"id":"KJFK","lat":40.63915,"lon":-73.76393,"state":"NY","location":"New York, Kennedy International Airport","city":"New York","priority":1}, + "KJHW": {"id":"KJHW","lat":42.15,"lon":-79.26667,"state":"NY","location":"Jamestown, Chautauqua County/Jamestown Airport","city":"Jamestown","priority":13}, + "KJPX": {"id":"KJPX","lat":40.95942,"lon":-72.25167,"state":"NY","location":"East Hampton Town Airport","city":"East Hampton Town","priority":13}, + "KJRB": {"id":"KJRB","lat":40.7012,"lon":-74.009,"state":"NY","location":"New York Downtown Manhattan","city":"New York Downtown Manhattan","priority":99}, + "KLGA": {"id":"KLGA","lat":40.77917,"lon":-73.88,"state":"NY","location":"New York, La Guardia Airport","city":"La Guardia","priority":13}, + "KLKP": {"id":"KLKP","lat":44.26448,"lon":-73.96187,"state":"NY","location":"Lake Placid Airport","city":"Lake Placid","priority":13}, + "KMGJ": {"id":"KMGJ","lat":41.50917,"lon":-74.265,"state":"NY","location":"Montgomery, Orange County Airport","city":"Montgomery","priority":10}, + "KMSS": {"id":"KMSS","lat":44.93583,"lon":-74.84556,"state":"NY","location":"Massena, Massena International-Richards Field","city":"Massena","priority":1}, + "KMTP": {"id":"KMTP","lat":41.07306,"lon":-71.92333,"state":"NY","location":"Montauk, Montauk Airport","city":"Montauk","priority":13}, + "KNYC": {"id":"KNYC","lat":40.78333,"lon":-73.9666699,"state":"NY","location":"New York City, Central Park","city":"New York City","priority":99}, + "KOGS": {"id":"KOGS","lat":44.68186,"lon":-75.4655,"state":"NY","location":"Ogdensburg International Airport","city":"Ogdensburg","priority":1}, + "KOIC": {"id":"KOIC","lat":42.5665,"lon":-75.52416,"state":"NY","location":"NORWICH","city":"Norwich","priority":99}, + "KOLE": {"id":"KOLE","lat":42.24119,"lon":-78.37136,"state":"NY","location":"Cattaraugus County-Olean Airport","city":"Cattaraugus Co.","priority":10}, + "KPBG": {"id":"KPBG","lat":44.65,"lon":-73.4666699,"state":"NY","location":"Plattsburgh International Airport ","city":"Plattsburgh","priority":1}, + "KPEO": {"id":"KPEO","lat":42.64306,"lon":-77.04944,"state":"NY","location":"Penn Yan, Penn Yan Airport","city":"Penn Yan","priority":13}, + "KPOU": {"id":"KPOU","lat":41.62667,"lon":-73.88417,"state":"NY","location":"Poughkeepsie, Dutchess County Airport","city":"Poughkeepsie","priority":10}, + "KPTD": {"id":"KPTD","lat":44.67667,"lon":-74.94844,"state":"NY","location":"Potsdam Municipal Airport/Damon Field","city":"Potsdam","priority":9}, + "KRME": {"id":"KRME","lat":43.23333,"lon":-75.4,"state":"NY","location":"Griffiss International Airport","city":"Griffiss","priority":1}, + "KROC": {"id":"KROC","lat":43.11667,"lon":-77.67667,"state":"NY","location":"Rochester, Greater Rochester International Airport","city":"Rochester","priority":1}, + "KSCH": {"id":"KSCH","lat":42.85,"lon":-73.93333,"state":"NY","location":"Schenectady Airport","city":"Schenectady","priority":13}, + "KSDC": {"id":"KSDC","lat":43.23459,"lon":-77.11946,"state":"NY","location":"Williamson-Sodus Airport","city":"Williamson","priority":13}, + "KSLK": {"id":"KSLK","lat":44.39306,"lon":-74.20278,"state":"NY","location":"Saranac Lake, Adirondack Regional Airport","city":"Saranac Lake","priority":3}, + "KSWF": {"id":"KSWF","lat":41.5,"lon":-74.1,"state":"NY","location":"Newburgh / Stewart","city":"Newburgh","priority":99}, + "KSYR": {"id":"KSYR","lat":43.10917,"lon":-76.10333,"state":"NY","location":"Syracuse, Syracuse Hancock International Airport","city":"Syracuse","priority":1}, + "KVGC": {"id":"KVGC","lat":42.84344,"lon":-75.56119,"state":"NY","location":"Hamilton Municipal Airport","city":"Hamilton","priority":9}, + "KAKQ": {"id":"KAKQ","lat":36.98274,"lon":-77.00137,"state":"VA","location":"Wakefield Municipal Airport","city":"Wakefield","priority":9}, + "KAVC": {"id":"KAVC","lat":36.68861,"lon":-78.05417,"state":"VA","location":"South Hill, Mecklenburg-Brunswick Regional Airport","city":"South Hill","priority":3}, + "KBCB": {"id":"KBCB","lat":37.21667,"lon":-80.41667,"state":"VA","location":"Virginia Tech Airport","city":"Virginia Tech","priority":13}, + "KBKT": {"id":"KBKT","lat":37.0833299,"lon":-77.95,"state":"VA","location":"Ft. Pickett / Blackstone","city":"Ft Pickett","priority":99}, + "KCHO": {"id":"KCHO","lat":38.13738,"lon":-78.45516,"state":"VA","location":"Charlottesville-Albemarle Airport","city":"Charlottesville","priority":13}, + "KCJR": {"id":"KCJR","lat":38.52607,"lon":-77.85738,"state":"VA","location":"Culpeper Regional Airport","city":"Culpeper","priority":3}, + "KCPK": {"id":"KCPK","lat":36.66556,"lon":-76.32056,"state":"VA","location":"Chesapeake, Chesapeake Municipal Airport","city":"Chesapeake","priority":9}, + "KCXE": {"id":"KCXE","lat":36.7883,"lon":-78.5016,"state":"VA","location":"Chase City Municipal Airport","city":"Chase City","priority":9}, + "KDAA": {"id":"KDAA","lat":38.71667,"lon":-77.18333,"state":"VA","location":"Fort Belvoir","city":"Ft Belvoir","priority":99}, + "KDAN": {"id":"KDAN","lat":36.57278,"lon":-79.33611,"state":"VA","location":"Danville, Danville Regional Airport","city":"Danville","priority":3}, + "KDCA": {"id":"KDCA","lat":38.84833,"lon":-77.03417,"state":"VA","location":"Washington/Reagan National Airport, DC","city":"Washington","priority":2}, + "KEMV": {"id":"KEMV","lat":36.68694,"lon":-77.48278,"state":"VA","location":"Emporia, Emporia-Greensville Regional Airport","city":"Emporia","priority":3}, + "KEZF": {"id":"KEZF","lat":38.26667,"lon":-77.45,"state":"VA","location":"Fredericksburg, Shannon Airport","city":"Fredericksburg","priority":13}, + "KFAF": {"id":"KFAF","lat":37.13333,"lon":-76.61667,"state":"VA","location":"Fort Eustis / Felker","city":"Ft Eustis","priority":99}, + "KFCI": {"id":"KFCI","lat":37.406444,"lon":-77.524833,"state":"VA","location":"Chesterfield County Airport","city":"Chesterfield Co.","priority":10}, + "KFKN": {"id":"KFKN","lat":36.7,"lon":-76.9,"state":"VA","location":"Franklin / J B Rose","city":"Franklin","priority":99}, + "KFRR": {"id":"KFRR","lat":38.9174999,"lon":-78.2535,"state":"VA","location":"Front Royal-warren County Airport","city":"Front Royal","priority":10}, + "KFVX": {"id":"KFVX","lat":37.35,"lon":-78.43333,"state":"VA","location":"Farmville","city":"Farmville","priority":99}, + "KFYJ": {"id":"KFYJ","lat":37.52111,"lon":-76.7644399,"state":"VA","location":"West Point, Middle Peninsula Regional Airport","city":"West Point","priority":3}, + "KGVE": {"id":"KGVE","lat":38.156,"lon":-78.1658,"state":"VA","location":"Gordonsville Municipal Airport","city":"Gordonsville","priority":9}, + "KHEF": {"id":"KHEF","lat":38.71667,"lon":-77.51667,"state":"VA","location":"Manassas, Manassas Regional Airport/Harry P. Davis Field","city":"Manassas","priority":3}, + "KHLX": {"id":"KHLX","lat":36.76667,"lon":-80.81667,"state":"VA","location":"Hillsville","city":"Hillsville","priority":99}, + "KHSP": {"id":"KHSP","lat":37.95,"lon":-79.83333,"state":"VA","location":"Hot Springs / Ingalls","city":"Hot Springs","priority":99}, + "KHWY": {"id":"KHWY","lat":38.5876499,"lon":-77.71501,"state":"VA","location":"Warrenton-Fauquier Airport","city":"Warrenton","priority":13}, + "KIAD": {"id":"KIAD","lat":38.93472,"lon":-77.4475,"state":"VA","location":"Washington/Dulles International Airport, DC","city":"Dulles","priority":1}, + "KJFZ": {"id":"KJFZ","lat":37.064,"lon":-81.798,"state":"VA","location":"Tazewell County Airport","city":"Tazewell Co.","priority":10}, + "KJGG": {"id":"KJGG","lat":37.24157,"lon":-76.71672,"state":"VA","location":"Williamsburg-Jamestown Airport","city":"Williamsburg","priority":13}, + "KJYO": {"id":"KJYO","lat":39.0833299,"lon":-77.56667,"state":"VA","location":"Leesburg / Godfrey","city":"Leesburg","priority":99}, + "KLFI": {"id":"KLFI","lat":37.0833299,"lon":-76.35,"state":"VA","location":"Langley Air Force Base","city":"Langley","priority":14}, + "KLKU": {"id":"KLKU","lat":38.00972,"lon":-77.97028,"state":"VA","location":"Louisa, Louisa County Airport/Freeman Field","city":"Louisa","priority":10}, + "KLNP": {"id":"KLNP","lat":36.98333,"lon":-82.53333,"state":"VA","location":"Wise / Lonesome Pine","city":"Wise","priority":99}, + "KLUA": {"id":"KLUA","lat":38.6671,"lon":-78.5006,"state":"VA","location":"Luray Caverns","city":"Luray Caverns","priority":99}, + "KLVL": {"id":"KLVL","lat":36.7727999,"lon":-77.7943,"state":"VA","location":"Lawrenceville/Brunswick Municipal Airport","city":"Lawrenceville","priority":9}, + "KLYH": {"id":"KLYH","lat":37.32083,"lon":-79.20667,"state":"VA","location":"Lynchburg, Lynchburg Regional Airport","city":"Lynchburg","priority":3}, + "KMKJ": {"id":"KMKJ","lat":36.9,"lon":-81.35,"state":"VA","location":"Marion / Wytheville","city":"Marion","priority":99}, + "KMTV": {"id":"KMTV","lat":36.63333,"lon":-80.01667,"state":"VA","location":"Martinsville","city":"Martinsville","priority":99}, + "KNFE": {"id":"KNFE","lat":36.70083,"lon":-76.12833,"state":"VA","location":"Fentress, Naval Auxiliary Landing Field","city":"Fentress","priority":14}, + "KNGU": {"id":"KNGU","lat":36.93361,"lon":-76.29583,"state":"VA","location":"Norfolk, Naval Air Station","city":"Norfolk NAS","priority":14}, + "KNTU": {"id":"KNTU","lat":36.82111,"lon":-76.02833,"state":"VA","location":"Virginia Beach, Oceana, Naval Air Station","city":"Virginia Beach","priority":14}, + "KNYG": {"id":"KNYG","lat":38.50326,"lon":-77.30129,"state":"VA","location":"Quantico Marine Corps Airfield - Turner Field","city":"Quantico","priority":14}, + "KOFP": {"id":"KOFP","lat":37.70806,"lon":-77.43444,"state":"VA","location":"Ashland, Hanover County Municipal Airport","city":"Ashland","priority":10}, + "KOKV": {"id":"KOKV","lat":39.15,"lon":-78.15,"state":"VA","location":"Winchester Regional","city":"Winchester","priority":3}, + "KOMH": {"id":"KOMH","lat":38.24722,"lon":-78.04556,"state":"VA","location":"Orange, Orange County Airport","city":"Orange","priority":10}, + "KORF": {"id":"KORF","lat":36.90361,"lon":-76.19194,"state":"VA","location":"Norfolk, Norfolk International Airport","city":"Norfolk","priority":1}, + "KPHF": {"id":"KPHF","lat":37.13194,"lon":-76.49306,"state":"VA","location":"Newport News, Newport News / Williamsburg International Airport","city":"Newport News","priority":1}, + "KPSK": {"id":"KPSK","lat":37.13333,"lon":-80.68333,"state":"VA","location":"Dublin / New River Valley","city":"Dublin","priority":99}, + "KPTB": {"id":"KPTB","lat":37.18333,"lon":-77.51667,"state":"VA","location":"Petersburg, Dinwiddie County Airport","city":"Petersburg","priority":10}, + "KPVG": {"id":"KPVG","lat":36.7801,"lon":-76.4488,"state":"VA","location":"Norfolk Hampton Roads Executive Airport","city":"Norfolk Hampton Roads","priority":5}, + "KRIC": {"id":"KRIC","lat":37.51111,"lon":-77.32333,"state":"VA","location":"Richmond, Richmond International Airport","city":"Richmond","priority":1}, + "KRMN": {"id":"KRMN","lat":38.39806,"lon":-77.45528,"state":"VA","location":"Stafford, Stafford Regional Airport","city":"Stafford","priority":3}, + "KROA": {"id":"KROA","lat":37.31694,"lon":-79.97417,"state":"VA","location":"Roanoke, Roanoke Regional Airport","city":"Roanoke","priority":3}, + "KSFQ": {"id":"KSFQ","lat":36.68222,"lon":-76.60194,"state":"VA","location":"Suffolk, Suffolk Municipal Airport","city":"Suffolk","priority":9}, + "KSHD": {"id":"KSHD","lat":38.26667,"lon":-78.9,"state":"VA","location":"Staunton / Shenandoah","city":"Staunton","priority":99}, + "KTGI": {"id":"KTGI","lat":37.82587,"lon":-75.99766,"state":"VA","location":"Tangier Island Airport","city":"Tangier Is.","priority":13}, + "KVBW": {"id":"KVBW","lat":38.36674,"lon":-78.96033,"state":"VA","location":"Bridgewater Air Park","city":"Bridgewater","priority":15}, + "KVJI": {"id":"KVJI","lat":36.68333,"lon":-82.03333,"state":"VA","location":"Abingdon","city":"Abingdon","priority":99}, + "KWAL": {"id":"KWAL","lat":37.9372,"lon":-75.46619,"state":"VA","location":"Wallops Flight Facility Airport","city":"Wallops Flight Facility","priority":13}, + "KXSA": {"id":"KXSA","lat":37.859611,"lon":-76.894111,"state":"VA","location":"Tappahannock-Essex County Airport","city":"Tappahannock","priority":10}, + "PAAD": {"id":"PAAD","lat":70.136,"lon":-146.2901,"state":"AK","location":"Point Thomson Airstrip","city":"Point Thomson","priority":50}, + "PAAK": {"id":"PAAK","lat":52.22028,"lon":-174.20639,"state":"AK","location":"Atka, Atka Airport","city":"Atka","priority":50}, + "PAAQ": {"id":"PAAQ","lat":61.6,"lon":-149.08333,"state":"AK","location":"Palmer, Palmer Municipal Airport","city":"Palmer","priority":50}, + "PABA": {"id":"PABA","lat":70.1338899,"lon":-143.57694,"state":"AK","location":"Barter Island, Barter Island LRRS Airport","city":"Barter Is.","priority":50}, + "PABE": {"id":"PABE","lat":60.77972,"lon":-161.83778,"state":"AK","location":"Bethel, Bethel Airport","city":"Bethel","priority":50}, + "PABI": {"id":"PABI","lat":64,"lon":-145.73333,"state":"AK","location":"Delta Junction/Ft Greely, Allen Army Airfield","city":"Delta Junction","priority":50}, + "PABL": {"id":"PABL","lat":65.98222,"lon":-161.15194,"state":"AK","location":"Buckland, Buckland Airport","city":"Buckland","priority":50}, + "PABR": {"id":"PABR","lat":71.28528,"lon":-156.76583,"state":"AK","location":"Wiley Post-Will Rogers Memorial Airport","city":"Wiley Post","priority":50}, + "PABT": {"id":"PABT","lat":66.91667,"lon":-151.51667,"state":"AK","location":"Bettles, Bettles Airport","city":"Bettles","priority":50}, + "PABV": {"id":"PABV","lat":61.41667,"lon":-149.51667,"state":"AK","location":"Birchwood, Birchwood Airport","city":"Birchwood","priority":50}, + "PACD": {"id":"PACD","lat":55.22083,"lon":-162.72778,"state":"AK","location":"Cold Bay, Cold Bay Airport","city":"Cold Bay","priority":50}, + "PACV": {"id":"PACV","lat":60.49167,"lon":-145.47778,"state":"AK","location":"Cordova, Merle K (Mudhole) Smith Airport","city":"Cordova","priority":50}, + "PACX": {"id":"PACX","lat":67.25217,"lon":-150.20391,"state":"AK","location":"Coldfoot Airport","city":"Coldfoot","priority":50}, + "PACZ": {"id":"PACZ","lat":61.78333,"lon":-166.03333,"state":"AK","location":"Cape Romanzof, Cape Romanzof LRRS Airport","city":"Cape Romanzof","priority":50}, + "PADE": {"id":"PADE","lat":66.08333,"lon":-162.75,"state":"AK","location":"Deering, Deering/New Airport","city":"Deering","priority":50}, + "PADG": {"id":"PADG","lat":68.0321,"lon":-162.8992,"state":"AK","location":"Red Dog","city":"Red Dog","priority":50}, + "PADK": {"id":"PADK","lat":51.87778,"lon":-176.64583,"state":"AK","location":"Adak Island, Adak Airport","city":"Adak Is.","priority":50}, + "PADL": {"id":"PADL","lat":59.05,"lon":-158.51667,"state":"AK","location":"Dillingham, Dillingham Airport","city":"Dillingham","priority":50}, + "PADM": {"id":"PADM","lat":61.8643,"lon":-162.0261,"state":"AK","location":"Marshall","city":"Marshall","priority":50}, + "PADQ": {"id":"PADQ","lat":57.75,"lon":-152.5,"state":"AK","location":"Kodiak, Kodiak Airport","city":"Kodiak","priority":50}, + "PADU": {"id":"PADU","lat":53.9,"lon":-166.53333,"state":"AK","location":"Unalaska, Unalaska Airport","city":"Unalaska","priority":50}, + "PAED": {"id":"PAED","lat":61.25306,"lon":-149.79389,"state":"AK","location":"Anchorage, Elmendorf Air Force Base","city":"Elmendorf AFB","priority":50}, + "PAEG": {"id":"PAEG","lat":64.77639,"lon":-141.15083,"state":"AK","location":"Eagle, Eagle Airport","city":"Eagle","priority":50}, + "PAEH": {"id":"PAEH","lat":58.65,"lon":-162.0666699,"state":"AK","location":"Cape Newenham, Cape Newenham LRRS Airport","city":"Cape Newenham","priority":50}, + "PAEI": {"id":"PAEI","lat":64.65,"lon":-147.1,"state":"AK","location":"Fairbanks, Eielson Air Force Base","city":"Eielson AFB","priority":50}, + "PAEL": {"id":"PAEL","lat":58.19467,"lon":-136.34663,"state":"AK","location":"Elfin Cove - Elfin Cove Seaplane Base","city":"Elfin Cove","priority":50}, + "PAEM": {"id":"PAEM","lat":62.78333,"lon":-164.5,"state":"AK","location":"Emmonak, Emmonak Airport","city":"Emmonak","priority":50}, + "PAEN": {"id":"PAEN","lat":60.57306,"lon":-151.245,"state":"AK","location":"Kenai, Kenai Municipal Airport","city":"Kenai","priority":50}, + "PAFA": {"id":"PAFA","lat":64.80389,"lon":-147.87611,"state":"AK","location":"Fairbanks, Fairbanks International Airport","city":"Fairbanks","priority":1}, + "PAFB": {"id":"PAFB","lat":64.83667,"lon":-147.59556,"state":"AK","location":"Fort Wainwright AAF","city":"Ft Wainwright","priority":50}, + "PAFE": {"id":"PAFE","lat":56.964,"lon":-133.913,"state":"AK","location":"Kake - Kake Airport","city":"Kake","priority":50}, + "PAFR": {"id":"PAFR","lat":61.26667,"lon":-149.65,"state":"AK","location":"Ft. Richardson / Bryant U. S. Army Heliport, Ak","city":"Ft Richardson","priority":50}, + "PAFS": {"id":"PAFS","lat":63.019,"lon":-154.358,"state":"AK","location":"Nikolai","city":"Nikolai","priority":50}, + "PAGA": {"id":"PAGA","lat":64.73333,"lon":-156.93333,"state":"AK","location":"Galena, Edward G. Pitka Sr. Airport","city":"Galena","priority":50}, + "PAGB": {"id":"PAGB","lat":68.48333,"lon":-149.48333,"state":"AK","location":"Galbraith Lake, Galbraith Lake Airport","city":"Galbraith Lake","priority":50}, + "PAGH": {"id":"PAGH","lat":66.8881,"lon":-157.1624,"state":"AK","location":"Shungnak Airport","city":"Shungnak","priority":50}, + "PAGK": {"id":"PAGK","lat":62.15,"lon":-145.45,"state":"AK","location":"Gulkana, Gulkana Airport","city":"Gulkana","priority":50}, + "PAGL": {"id":"PAGL","lat":64.54333,"lon":-163.03944,"state":"AK","location":"Golovin, Golovin Airport","city":"Golovin","priority":50}, + "PAGM": {"id":"PAGM","lat":63.76667,"lon":-171.73333,"state":"AK","location":"Gambell, Gambell Airport","city":"Gambell","priority":50}, + "PAGN": {"id":"PAGN","lat":57.5,"lon":-134.58333,"state":"AK","location":"Angoon","city":"Angoon","priority":50}, + "PAGS": {"id":"PAGS","lat":58.41667,"lon":-135.7,"state":"AK","location":"Gustavus, Gustavus Airport","city":"Gustavus","priority":50}, + "PAGY": {"id":"PAGY","lat":59.4544,"lon":-135.3263,"state":"AK","location":"Skagway","city":"Skagway","priority":50}, + "PAHC": {"id":"PAHC","lat":62.1873,"lon":-159.77657,"state":"AK","location":"Holy Cross","city":"Holy Cross","priority":50}, + "PAHL": {"id":"PAHL","lat":65.6975,"lon":-156.35111,"state":"AK","location":"Huslia, Huslia Airport","city":"Huslia","priority":50}, + "PAHN": {"id":"PAHN","lat":59.2429,"lon":-135.5114,"state":"AK","location":"Haines - Haines Airport","city":"Haines","priority":50}, + "PAHO": {"id":"PAHO","lat":59.65,"lon":-151.48333,"state":"AK","location":"Homer, Homer Airport","city":"Homer","priority":50}, + "PAHX": {"id":"PAHX","lat":62.6923,"lon":-159.5692,"state":"AK","location":"Shageluk Airport","city":"Shageluk","priority":50}, + "PAHY": {"id":"PAHY","lat":55.2,"lon":-132.83333,"state":"AK","location":"Hydaburg - Hydaburg Seaplane Base","city":"Hydaburg","priority":50}, + "PAIG": {"id":"PAIG","lat":59.32395,"lon":-155.90235,"state":"AK","location":"Igiugig","city":"Igiugig","priority":50}, + "PAII": {"id":"PAII","lat":58.18528,"lon":-157.38556,"state":"AK","location":"Egegik, Egegik Airport","city":"Egegik","priority":50}, + "PAIK": {"id":"PAIK","lat":66.98333,"lon":-160.43333,"state":"AK","location":"Kinana / Bob Baker Me","city":"Kinana","priority":50}, + "PAIL": {"id":"PAIL","lat":59.75,"lon":-154.9,"state":"AK","location":"Iliamna, Iliamna Airport","city":"Iliamna","priority":50}, + "PAIM": {"id":"PAIM","lat":66,"lon":-153.7,"state":"AK","location":"Utopia Creek, Indian Mountain LRRS Airport","city":"Utopia Creek","priority":50}, + "PAIN": {"id":"PAIN","lat":63.73333,"lon":-148.91667,"state":"AK","location":"McKinley Park, McKinley National Park Airport","city":"McKinley Park","priority":2}, + "PAIW": {"id":"PAIW","lat":65.6226,"lon":-168.0949,"state":"AK","location":"Wales","city":"Wales","priority":50}, + "PAJC": {"id":"PAJC","lat":56.31139,"lon":-158.37333,"state":"AK","location":"Chignik, Chignik Airport","city":"Chignik","priority":50}, + "PAJK": {"id":"PAJK","lat":58.4,"lon":-134.57001,"state":"AK","location":"NWS Office: Juneau","city":"NWS Juneau","priority":50}, + "PAJN": {"id":"PAJN","lat":58.35472,"lon":-134.57611,"state":"AK","location":"Juneau, Juneau International Airport","city":"Juneau","priority":1}, + "PAJZ": {"id":"PAJZ","lat":59.727,"lon":-157.2589999,"state":"AK","location":"Koliganek","city":"Koliganek","priority":50}, + "PAKF": {"id":"PAKF","lat":54.847,"lon":-163.41,"state":"AK","location":"False Pass Airport","city":"False Pass","priority":50}, + "PAKH": {"id":"PAKH","lat":56.9387,"lon":-154.1826,"state":"AK","location":"Akhiok","city":"Akhiok","priority":50}, + "PAKK": {"id":"PAKK","lat":64.93389,"lon":-161.15806,"state":"AK","location":"Koyuk, Koyuk Airport","city":"Koyuk","priority":50}, + "PAKN": {"id":"PAKN","lat":58.67667,"lon":-156.64917,"state":"AK","location":"King Salmon, King Salmon Airport","city":"King Salmon","priority":50}, + "PAKP": {"id":"PAKP","lat":68.13361,"lon":-151.7433299,"state":"AK","location":"Anaktuvuk Pass, Anaktuvuk Pass Airport","city":"Anaktuvuk Pass","priority":50}, + "PAKT": {"id":"PAKT","lat":55.35556,"lon":-131.71361,"state":"AK","location":"Ketchikan, Ketchikan International Airport","city":"Ketchikan","priority":1}, + "PAKU": {"id":"PAKU","lat":70.31667,"lon":-149.58333,"state":"AK","location":"Kuparuk, Ugnu-Kuparuk Airport","city":"Kuparuk","priority":50}, + "PAKV": {"id":"PAKV","lat":64.31667,"lon":-158.73333,"state":"AK","location":"Kaltag, Kaltag Airport","city":"Kaltag","priority":50}, + "PAKW": {"id":"PAKW","lat":55.5839,"lon":-133.067,"state":"AK","location":"Klawock - Klawock Airport","city":"Klawock","priority":50}, + "PAKX": {"id":"PAKX","lat":60.2,"lon":-154.3166,"state":"AK","location":"WILDER NATWICK","city":"Wilder Natwick","priority":50}, + "PALG": {"id":"PALG","lat":61.5364,"lon":-160.3414,"state":"AK","location":"Kalskag","city":"Kalskag","priority":50}, + "PALH": {"id":"PALH","lat":61.18333,"lon":-149.96667,"state":"AK","location":"Anchorage, Lake Hood Seaplane Base","city":"Lake Hood","priority":50}, + "PALP": {"id":"PALP","lat":70.33333,"lon":-150.93333,"state":"AK","location":"Deadhorse, Alpine Airstrip","city":"Deadhorse","priority":50}, + "PALU": {"id":"PALU","lat":68.88333,"lon":-166.1,"state":"AK","location":"Cape Lisburne, Cape Lisburne LRRS Airport","city":"Cape Lisburne","priority":50}, + "PAMB": {"id":"PAMB","lat":58.9902,"lon":-159.0499,"state":"AK","location":"Manokotak","city":"Manokotak","priority":50}, + "PAMC": {"id":"PAMC","lat":62.96667,"lon":-155.61667,"state":"AK","location":"McGrath, McGrath Airport","city":"McGrath","priority":50}, + "PAMD": {"id":"PAMD","lat":59.4423,"lon":-146.3166,"state":"AK","location":"Middleton Island Airport","city":"Middleton Is.","priority":50}, + "PAMH": {"id":"PAMH","lat":63.88056,"lon":-152.30056,"state":"AK","location":"Minchumina, Minchumina Airport","city":"Minchumina","priority":50}, + "PAMK": {"id":"PAMK","lat":63.49006,"lon":-162.11039,"state":"AK","location":"St Michael Airport","city":"St Michael","priority":50}, + "PAMM": {"id":"PAMM","lat":55.13111,"lon":-131.57806,"state":"AK","location":"Metlakatla, Metlakatla Seaplane Base","city":"Metlakatla","priority":50}, + "PAMO": {"id":"PAMO","lat":62.0953,"lon":-163.6819,"state":"AK","location":"Mountain Village","city":"Mountain Village","priority":50}, + "PAMR": {"id":"PAMR","lat":61.21667,"lon":-149.85,"state":"AK","location":"Anchorage, Merrill Field Airport","city":"Merrill","priority":50}, + "PAMY": {"id":"PAMY","lat":60.36667,"lon":-166.26667,"state":"AK","location":"Mekoryuk, Mekoryuk Airport","city":"Mekoryuk","priority":50}, + "PANA": {"id":"PANA","lat":60.6903,"lon":-161.9785,"state":"AK","location":"Napakiak Airport","city":"Napakiak","priority":50}, + "PANC": {"id":"PANC","lat":61.17444,"lon":-149.9961099,"state":"AK","location":"Anchorage, Ted Stevens Anchorage International Airport","city":"Anchorage","priority":1}, + "PANI": {"id":"PANI","lat":61.58139,"lon":-159.54278,"state":"AK","location":"Aniak, Aniak Airport","city":"Aniak","priority":50}, + "PANN": {"id":"PANN","lat":64.54796,"lon":-149.08398,"state":"AK","location":"Nenana Municipal Airport","city":"Nenana","priority":50}, + "PANU": {"id":"PANU","lat":64.72933,"lon":-158.07422,"state":"AK","location":"Nulato Airport","city":"Nulato","priority":50}, + "PANV": {"id":"PANV","lat":62.64833,"lon":-160.18972,"state":"AK","location":"Anvik, Anvik Airport","city":"Anvik","priority":50}, + "PANW": {"id":"PANW","lat":59.45,"lon":-157.328,"state":"AK","location":"New Stuyahok","city":"New Stuyahok","priority":50}, + "PAOH": {"id":"PAOH","lat":58.097,"lon":-135.4139999,"state":"AK","location":"Hoonah - Hoonah Seaplane Base","city":"Hoonah","priority":50}, + "PAOM": {"id":"PAOM","lat":64.51194,"lon":-165.445,"state":"AK","location":"Nome, Nome Airport","city":"Nome","priority":50}, + "PAOR": {"id":"PAOR","lat":62.96111,"lon":-141.92889,"state":"AK","location":"Northway, Northway Airport","city":"Northway","priority":50}, + "PAOT": {"id":"PAOT","lat":66.88576,"lon":-162.60624,"state":"AK","location":"Ralph Wien Memorial Airport","city":"Ralph Wien","priority":50}, + "PAOU": {"id":"PAOU","lat":56.008,"lon":-161.16,"state":"AK","location":"Nelson Lagoon","city":"Nelson Lagoon","priority":50}, + "PAPB": {"id":"PAPB","lat":56.57861,"lon":-169.66139,"state":"AK","location":"St. George, St. George Airport","city":"St George","priority":50}, + "PAPG": {"id":"PAPG","lat":56.8017,"lon":-132.9453,"state":"AK","location":"Petersburg","city":"Petersburg","priority":50}, + "PAPH": {"id":"PAPH","lat":56.95,"lon":-158.63333,"state":"AK","location":"Port Heiden, Port Heiden Airport","city":"Port Heiden","priority":50}, + "PAPM": {"id":"PAPM","lat":59.01667,"lon":-161.8166699,"state":"AK","location":"Platinum","city":"Platinum","priority":50}, + "PAPN": {"id":"PAPN","lat":57.58,"lon":-157.572,"state":"AK","location":"Pilot Point Airport","city":"Pilot Point","priority":50}, + "PAPO": {"id":"PAPO","lat":68.35,"lon":-166.8,"state":"AK","location":"Point Hope, Point Hope Airport","city":"Point Hope","priority":50}, + "PAPR": {"id":"PAPR","lat":66.81278,"lon":-150.64389,"state":"AK","location":"Prospect Creek, Prospect Creek Airport","city":"Prospect Creek","priority":50}, + "PAPT": {"id":"PAPT","lat":62.1,"lon":-152.75,"state":"AK","location":"Puntilla","city":"Puntilla","priority":50}, + "PAQH": {"id":"PAQH","lat":59.7551,"lon":-161.8454,"state":"AK","location":"Quinhagak Airport","city":"Quinhagak","priority":50}, + "PAQT": {"id":"PAQT","lat":70.2099999,"lon":-151.00556,"state":"AK","location":"Nuiqsut, Nuiqsut Airport","city":"Nuiqsut","priority":50}, + "PARC": {"id":"PARC","lat":68.11444,"lon":-145.57917,"state":"AK","location":"Arctic Village, Arctic Village Airport","city":"Arctic Village","priority":50}, + "PARS": {"id":"PARS","lat":61.775,"lon":-161.3194,"state":"AK","location":"Russian Mission","city":"Russian Mission","priority":50}, + "PARY": {"id":"PARY","lat":64.7272,"lon":-155.4697,"state":"AK","location":"Ruby","city":"Ruby","priority":50}, + "PASA": {"id":"PASA","lat":63.68333,"lon":-170.5,"state":"AK","location":"Savoonga Airport","city":"Savoonga","priority":50}, + "PASC": {"id":"PASC","lat":70.2,"lon":-148.46667,"state":"AK","location":"Deadhorse, Deadhorse Airport","city":"PASC","priority":50}, + "PASD": {"id":"PASD","lat":55.31667,"lon":-160.51667,"state":"AK","location":"Sand Point","city":"Sand Point","priority":50}, + "PASH": {"id":"PASH","lat":66.26667,"lon":-166.08333,"state":"AK","location":"Shishmaref, Shishmaref Airport","city":"Shishmaref","priority":50}, + "PASI": {"id":"PASI","lat":57.048,"lon":-135.3647,"state":"AK","location":"Sitka - Sitka Airport","city":"Sitka","priority":50}, + "PASK": {"id":"PASK","lat":66.61667,"lon":-160,"state":"AK","location":"Selawik","city":"Selawik","priority":50}, + "PASL": {"id":"PASL","lat":61.69735,"lon":-157.16712,"state":"AK","location":"Sleetmute","city":"Sleetmute","priority":50}, + "PASM": {"id":"PASM","lat":62.05,"lon":-163.3,"state":"AK","location":"St. Mary's, St. Mary's Airport","city":"St Mary's","priority":50}, + "PASN": {"id":"PASN","lat":57.16667,"lon":-170.21667,"state":"AK","location":"St. Paul Island, St. Paul Island Airport","city":"St Paul Is.","priority":50}, + "PASO": {"id":"PASO","lat":59.45,"lon":-151.7,"state":"AK","location":"Seldovia, Seldovia Airport","city":"Seldovia","priority":50}, + "PASV": {"id":"PASV","lat":61.1,"lon":-155.5666699,"state":"AK","location":"Sparrevohn Airways Facilities Sector","city":"Sparrevohn","priority":50}, + "PASX": {"id":"PASX","lat":60.48333,"lon":-151.03333,"state":"AK","location":"Soldotna","city":"Soldotna","priority":50}, + "PASY": {"id":"PASY","lat":52.71667,"lon":174.11667,"state":"AK","location":"Shemya, Eareckson AFB","city":"Shemya","priority":50}, + "PATA": {"id":"PATA","lat":65.16667,"lon":-152.1,"state":"AK","location":"Tanana, Calhoun Memorial Airport","city":"Tanana","priority":50}, + "PATC": {"id":"PATC","lat":65.56667,"lon":-167.91667,"state":"AK","location":"Tin City Airways Facilities Sector","city":"Tin City","priority":50}, + "PATE": {"id":"PATE","lat":65.2403999,"lon":-166.3393,"state":"AK","location":"Teller","city":"Teller","priority":50}, + "PATG": {"id":"PATG","lat":59.05,"lon":-160.4,"state":"AK","location":"Togiac Village, Togiak Airport","city":"Togiac Village","priority":50}, + "PATK": {"id":"PATK","lat":62.32056,"lon":-150.09361,"state":"AK","location":"Talkeetna, Talkeetna Airport","city":"Talkeetna","priority":50}, + "PATL": {"id":"PATL","lat":62.9,"lon":-155.98333,"state":"AK","location":"Takotna, Tatalina LRRS Airport","city":"Takotna","priority":50}, + "PATO": {"id":"PATO","lat":60.78333,"lon":-148.83333,"state":"AK","location":"Portage, Portage Glacier","city":"Portage","priority":50}, + "PATQ": {"id":"PATQ","lat":70.4673,"lon":-157.4357,"state":"AK","location":"Atqasuk","city":"Atqasuk","priority":50}, + "PAUN": {"id":"PAUN","lat":63.88333,"lon":-160.8,"state":"AK","location":"Unalakleet","city":"Unalakleet","priority":50}, + "PAVA": {"id":"PAVA","lat":61.5408,"lon":-165.6009,"state":"AK","location":"Chevak Airport","city":"Chevak","priority":50}, + "PAVC": {"id":"PAVC","lat":55.116,"lon":-162.266,"state":"AK","location":"King Cove","city":"King Cove","priority":50}, + "PAVD": {"id":"PAVD","lat":61.13333,"lon":-146.26667,"state":"AK","location":"Valdez 2","city":"Valdez","priority":50}, + "PAVL": {"id":"PAVL","lat":67.73333,"lon":-164.55,"state":"AK","location":"Kivalina, Kivalina Airport","city":"Kivalina","priority":50}, + "PAWD": {"id":"PAWD","lat":60.11667,"lon":-149.45,"state":"AK","location":"Seward","city":"Seward","priority":50}, + "PAWG": {"id":"PAWG","lat":56.48333,"lon":-132.36667,"state":"AK","location":"Wrangell","city":"Wrangell","priority":50}, + "PAWM": {"id":"PAWM","lat":64.6892,"lon":-163.4127,"state":"AK","location":"White Mountain Airport","city":"White Mtn","priority":50}, + "PAWN": {"id":"PAWN","lat":67.56667,"lon":-162.98333,"state":"AK","location":"Noatak, Noatak Airport","city":"Noatak","priority":50}, + "PAWS": {"id":"PAWS","lat":61.57194,"lon":-149.54056,"state":"AK","location":"Wasilla, Wasilla Airport","city":"Wasilla","priority":50}, + "PAYA": {"id":"PAYA","lat":59.51667,"lon":-139.66667,"state":"AK","location":"Yakutat","city":"Yakutat","priority":50}, + "PAZK": {"id":"PAZK","lat":61.93333,"lon":-147.16667,"state":"AK","location":"Eureka, Skelton Airport","city":"Eureka","priority":50}, + "PFCB": {"id":"PFCB","lat":60.07856,"lon":-147.99473,"state":"AK","location":"Chenega Bay Airport","city":"Chenega Bay","priority":50}, + "PFCL": {"id":"PFCL","lat":58.8337,"lon":-158.5294,"state":"AK","location":"Clarks Point Airport","city":"Clarks Point","priority":50}, + "PFEL": {"id":"PFEL","lat":64.615,"lon":-162.2705,"state":"AK","location":"Elim Airport","city":"Elim","priority":50}, + "PFKO": {"id":"PFKO","lat":63.03058,"lon":-163.5326399,"state":"AK","location":"Kotlik Airport","city":"Kotlik","priority":50}, + "PFKT": {"id":"PFKT","lat":65.3313,"lon":-166.4657,"state":"AK","location":"Brevig Mission Airport","city":"Brevig Mission","priority":50}, + "PFKW": {"id":"PFKW","lat":60.7903,"lon":-161.4437,"state":"AK","location":"Kwethluk Airport","city":"Kwethluk","priority":50}, + "PFNO": {"id":"PFNO","lat":66.8175,"lon":-161.0223,"state":"AK","location":"Noorvik","city":"Noorvik","priority":50}, + "PFSH": {"id":"PFSH","lat":64.3711,"lon":-161.224,"state":"AK","location":"Shaktoolik Airport","city":"Shaktoolik","priority":50}, + "PFTO": {"id":"PFTO","lat":63.32951,"lon":-142.95368,"state":"AK","location":"Tok Junction Airport","city":"Tok Junction","priority":50}, + "PFWS": {"id":"PFWS","lat":58.7021,"lon":-157.0026,"state":"AK","location":"South Naknek Nr 2 Airport","city":"South Naknek Nr 2","priority":50}, + "PFYU": {"id":"PFYU","lat":66.56667,"lon":-145.26667,"state":"AK","location":"Fort Yukon, Fort Yukon Airport","city":"Ft Yukon","priority":50}, + "PFZK": {"id":"PFZK","lat":60.91381,"lon":-161.4933299,"state":"AK","location":"Akiachak Airport","city":"Akiachak","priority":50}, + "POKA": {"id":"POKA","lat":60.56953,"lon":-165.24628,"state":"AK","location":"Tununak Airport","city":"Tununak","priority":50}, + "PPIT": {"id":"PPIT","lat":60.906,"lon":-162.4406,"state":"AK","location":"Nunapitchuk Airport","city":"Nunapitchuk","priority":50}, + "PPIZ": {"id":"PPIZ","lat":69.7166699,"lon":-163,"state":"AK","location":"Point Lay, Point Lay LRRS Airport","city":"Point Lay","priority":50}, + "KDET": {"id":"KDET","lat":42.40729,"lon":-83.00894,"state":"MI","location":"Coleman A Young Municipal Airport","city":"Coleman A Young","priority":9}, + "KDRM": {"id":"KDRM","lat":46.0072,"lon":-83.7427,"state":"MI","location":"Drummond Island Airport","city":"Drummond Is.","priority":13}, + "KDTW": {"id":"KDTW","lat":42.23139,"lon":-83.33083,"state":"MI","location":"Detroit, Detroit Metropolitan Wayne County Airport","city":"Detroit","priority":1}, + "KDUH": {"id":"KDUH","lat":41.73583,"lon":-83.65528,"state":"MI","location":"Lambertville, Toledo Suburban Airport","city":"Lambertville","priority":13}, + "KERY": {"id":"KERY","lat":46.31111,"lon":-85.45722,"state":"MI","location":"Newberry, Luce County Airport","city":"Newberry","priority":10}, + "KESC": {"id":"KESC","lat":45.7226799,"lon":-87.09372,"state":"MI","location":"Delta County Airport","city":"Delta Co.","priority":10}, + "KFFX": {"id":"KFFX","lat":43.43933,"lon":-85.9948299,"state":"MI","location":"Fremont Municipal Airport","city":"Fremont","priority":9}, + "KFKS": {"id":"KFKS","lat":44.625,"lon":-86.20056,"state":"MI","location":"Frankfort, Frankfort Dow Memorial Field Airport","city":"Frankfort","priority":11}, + "KFNT": {"id":"KFNT","lat":42.96667,"lon":-83.74944,"state":"MI","location":"Flint, Bishop International Airport","city":"Flint","priority":1}, + "KFPK": {"id":"KFPK","lat":42.57444,"lon":-84.81139,"state":"MI","location":"Charlotte, Fitch H Beach Airport","city":"Charlotte","priority":13}, + "KGLR": {"id":"KGLR","lat":45.01658,"lon":-84.68937,"state":"MI","location":"Gaylord Regional Airport","city":"Gaylord","priority":3}, + "KGOV": {"id":"KGOV","lat":44.68028,"lon":-84.72889,"state":"MI","location":"Grayling, Grayling Army Airfield","city":"Grayling","priority":14}, + "KGRR": {"id":"KGRR","lat":42.88083,"lon":-85.52278,"state":"MI","location":"Grand Rapids, Gerald R. Ford International Airport","city":"Grand Rapids","priority":1}, + "KHAI": {"id":"KHAI","lat":41.9598,"lon":-85.5934,"state":"MI","location":"Haines Memorial Airport","city":"Haines","priority":11}, + "KHTL": {"id":"KHTL","lat":44.35111,"lon":-84.67417,"state":"MI","location":"Houghton Lake, Roscommon County Airport","city":"Houghton Lake","priority":10}, + "KHYX": {"id":"KHYX","lat":43.43191,"lon":-83.86476,"state":"MI","location":"Saginaw County H W Browne Airport","city":"Saginaw Co.","priority":10}, + "KIKW": {"id":"KIKW","lat":43.6624,"lon":-84.26213,"state":"MI","location":"Jack Barstow Airport","city":"Jack Barstow","priority":13}, + "KIMT": {"id":"KIMT","lat":45.81417,"lon":-88.10889,"state":"MI","location":"Iron Mountain / Kingsford, Ford Airport","city":"Iron Mtn","priority":13}, + "KIRS": {"id":"KIRS","lat":41.8127799,"lon":-85.43917,"state":"MI","location":"Sturgis, Kirsch Municipal Airport","city":"Sturgis","priority":9}, + "KISQ": {"id":"KISQ","lat":45.97472,"lon":-86.17194,"state":"MI","location":"Manistique, Schoolcraft County Airport","city":"Manistique","priority":10}, + "KIWD": {"id":"KIWD","lat":46.53333,"lon":-90.13333,"state":"MI","location":"Ironwood, Gogebic-Iron County Airport","city":"Ironwood","priority":10}, + "KJXN": {"id":"KJXN","lat":42.26171,"lon":-84.46147,"state":"MI","location":"Jackson County Airport - Reynolds Field","city":"Jackson Co.","priority":10}, + "KJYM": {"id":"KJYM","lat":41.91972,"lon":-84.58528,"state":"MI","location":"Hillsdale Municipal Airport","city":"Hillsdale","priority":9}, + "KLAN": {"id":"KLAN","lat":42.77616,"lon":-84.5997,"state":"MI","location":"Capital Region International Airport","city":"Lansing","priority":1}, + "KLDM": {"id":"KLDM","lat":43.96667,"lon":-86.4,"state":"MI","location":"Ludington, Mason County Airport","city":"Ludington","priority":10}, + "KLWA": {"id":"KLWA","lat":42.35083,"lon":-86.25611,"state":"MI","location":"South Haven, South Haven Area Regional Airport","city":"South Haven","priority":3}, + "KMBL": {"id":"KMBL","lat":44.27142,"lon":-86.23773,"state":"MI","location":"Manistee County - Blacker Airport","city":"Manistee Co.","priority":10}, + "KMBS": {"id":"KMBS","lat":43.5281,"lon":-84.08129,"state":"MI","location":"MBS International Airport","city":"Saginaw","priority":1}, + "KMCD": {"id":"KMCD","lat":45.86628,"lon":-84.63437,"state":"MI","location":"Mackinac Island Airport","city":"Mackinac Is.","priority":13}, + "KMGN": {"id":"KMGN","lat":45.42556,"lon":-84.91333,"state":"MI","location":"Harbor Springs, Harbor Springs Airport","city":"Harbor Springs","priority":13}, + "KMKG": {"id":"KMKG","lat":43.17111,"lon":-86.23667,"state":"MI","location":"Muskegon, Muskegon County Airport","city":"Muskegon","priority":10}, + "KMNM": {"id":"KMNM","lat":45.12628,"lon":-87.64438,"state":"MI","location":"Menominee - Marinette Twin County Airport","city":"Menominee","priority":10}, + "KMOP": {"id":"KMOP","lat":43.61667,"lon":-84.73333,"state":"MI","location":"Mount Pleasant, Mount Pleasant Municipal Airport","city":"Mt Pleasant","priority":9}, + "KMTC": {"id":"KMTC","lat":42.60458,"lon":-82.83528,"state":"MI","location":"Selfridge Air National Guard Base","city":"Selfridge","priority":2}, + "KOEB": {"id":"KOEB","lat":41.93085,"lon":-85.05429,"state":"MI","location":"Branch County Memorial Airport","city":"Branch Co.","priority":10}, + "KONZ": {"id":"KONZ","lat":42.09861,"lon":-83.1611099,"state":"MI","location":"Detroit/Grosse Ile, Grosse Ile Airport","city":"Grosse Ile","priority":13}, + "KOSC": {"id":"KOSC","lat":44.45,"lon":-83.36667,"state":"MI","location":"Oscoda, Oscoda-Wurtsmith Airport","city":"Oscoda","priority":13}, + "KOZW": {"id":"KOZW","lat":42.62944,"lon":-83.98417,"state":"MI","location":"Howell, Livingston County Airport","city":"Howell","priority":10}, + "KPHN": {"id":"KPHN","lat":42.91031,"lon":-82.53315,"state":"MI","location":"St Clair County International Airport","city":"St Clair Co.","priority":1}, + "KPLN": {"id":"KPLN","lat":45.56443,"lon":-84.7928699,"state":"MI","location":"Pellston Regional Airport of Emmet County","city":"Pellston","priority":3}, + "KPTK": {"id":"KPTK","lat":42.66306,"lon":-83.41,"state":"MI","location":"Pontiac, Oakland County International Airport","city":"Pontiac","priority":1}, + "KPZQ": {"id":"KPZQ","lat":45.40694,"lon":-83.81278,"state":"MI","location":"Rogers City, Presque Isle County Airport","city":"Rogers City","priority":10}, + "KRMY": {"id":"KRMY","lat":42.25238,"lon":-84.95253,"state":"MI","location":"Brooks Field Airport","city":"Brooks","priority":12}, + "KRNP": {"id":"KRNP","lat":42.99278,"lon":-84.13889,"state":"MI","location":"Owosso, Owosso Community Airport","city":"Owosso","priority":13}, + "KRQB": {"id":"KRQB","lat":43.7224999,"lon":-85.50417,"state":"MI","location":"Big Rapids, Roben-Hood Airport","city":"Big Rapids","priority":13}, + "KSAW": {"id":"KSAW","lat":46.35361,"lon":-87.39528,"state":"MI","location":"Marquette, Sawyer International Airport","city":"Marquette","priority":1}, + "KSJX": {"id":"KSJX","lat":45.69222,"lon":-85.56639,"state":"MI","location":"Beaver Island, Beaver Island Airport","city":"Beaver Is.","priority":13}, + "KSLH": {"id":"KSLH","lat":45.65361,"lon":-84.51917,"state":"MI","location":"Cheboygan, Cheboygan County Airport","city":"Cheboygan","priority":10}, + "KTEW": {"id":"KTEW","lat":42.56583,"lon":-84.42333,"state":"MI","location":"Mason, Mason Jewett Field Airport","city":"Mason","priority":12}, + "KTTF": {"id":"KTTF","lat":41.94,"lon":-83.43472,"state":"MI","location":"Monroe, Custer Airport","city":"Monroe","priority":13}, + "KTVC": {"id":"KTVC","lat":44.73898,"lon":-85.56788,"state":"MI","location":"Cherry Capital Airport","city":"Cherry Capital","priority":13}, + "KVLL": {"id":"KVLL","lat":42.54278,"lon":-83.17778,"state":"MI","location":"Troy, Oakland/Troy Airport","city":"Troy","priority":13}, + "KYIP": {"id":"KYIP","lat":42.2366699,"lon":-83.52611,"state":"MI","location":"Detroit, Willow Run Airport","city":"Willow Run","priority":13}, + "KBHK": {"id":"KBHK","lat":46.34778,"lon":-104.2574999,"state":"MT","location":"Baker, Baker Municipal Airport","city":"Baker","priority":9}, + "KBIL": {"id":"KBIL","lat":45.80694,"lon":-108.54222,"state":"MT","location":"Billings, Billings Logan International Airport","city":"Billings","priority":1}, + "KBTM": {"id":"KBTM","lat":45.95472,"lon":-112.4975,"state":"MT","location":"Butte, Bert Mooney Airport","city":"Butte","priority":13}, + "KBZN": {"id":"KBZN","lat":45.78806,"lon":-111.16083,"state":"MT","location":"Bozeman, Gallatin Field","city":"Bozeman","priority":12}, + "KCTB": {"id":"KCTB","lat":48.60833,"lon":-112.37611,"state":"MT","location":"Cut Bank, Cut Bank Municipal Airport","city":"Cut Bank","priority":9}, + "KDLN": {"id":"KDLN","lat":45.2575,"lon":-112.55444,"state":"MT","location":"Dillon, Dillon Airport","city":"Dillon","priority":13}, + "KEKS": {"id":"KEKS","lat":45.27436,"lon":-111.64886,"state":"MT","location":"Ennis - Big Sky Airport","city":"Ennis","priority":13}, + "KGDV": {"id":"KGDV","lat":47.13333,"lon":-104.8,"state":"MT","location":"Glendive, Dawson Community Airport","city":"Glendive","priority":13}, + "KGFA": {"id":"KGFA","lat":47.5,"lon":-111.18333,"state":"MT","location":"Malmstrom Air Force Base","city":"Malmstrom","priority":14}, + "KGGW": {"id":"KGGW","lat":48.21389,"lon":-106.62139,"state":"MT","location":"Glasgow, Glasgow International Airport","city":"Glasgow","priority":1}, + "KGPI": {"id":"KGPI","lat":48.30417,"lon":-114.26361,"state":"MT","location":"Kalispell, Glacier Park International Airport","city":"Kalispell","priority":1}, + "KGTF": {"id":"KGTF","lat":47.47333,"lon":-111.38222,"state":"MT","location":"Great Falls, Great Falls International Airport","city":"Great Falls","priority":1}, + "KHLN": {"id":"KHLN","lat":46.60445,"lon":-111.9892,"state":"MT","location":"Helena Regional Airport","city":"Helena","priority":3}, + "KHRF": {"id":"KHRF","lat":46.25463,"lon":-114.1246,"state":"MT","location":"Ravalli County Airport","city":"Ravalli Co.","priority":10}, + "KHVR": {"id":"KHVR","lat":48.54278,"lon":-109.76333,"state":"MT","location":"Havre, Havre City-County Airport","city":"Havre","priority":13}, + "KJDN": {"id":"KJDN","lat":47.32583,"lon":-106.9475,"state":"MT","location":"Jordan, Jordan Airport","city":"Jordan","priority":13}, + "KLVM": {"id":"KLVM","lat":45.69944,"lon":-110.44833,"state":"MT","location":"Livingston, Mission Field Airport","city":"Livingston","priority":12}, + "KLWT": {"id":"KLWT","lat":47.0491699,"lon":-109.46639,"state":"MT","location":"Lewistown, Lewistown Municipal Airport","city":"Lewistown","priority":9}, + "KMLP": {"id":"KMLP","lat":47.45417,"lon":-115.66972,"state":"MT","location":"Mullan Pass, Mullan Pass Vor","city":"Mullan Pass","priority":99}, + "KMLS": {"id":"KMLS","lat":46.42806,"lon":-105.88639,"state":"MT","location":"Miles City, Frank Wiley Field Airport","city":"Miles City","priority":12}, + "KMSO": {"id":"KMSO","lat":46.92083,"lon":-114.0925,"state":"MT","location":"Missoula, Missoula International Airport","city":"Missoula","priority":1}, + "KMVH": {"id":"KMVH","lat":46.8381,"lon":-108.9368,"state":"MT","location":"N BAR Ranch Airport","city":"N BAR Ranch","priority":13}, + "KOLF": {"id":"KOLF","lat":48.09444,"lon":-105.57722,"state":"MT","location":"Wolf Point, Clayton Airport","city":"Wolf Point","priority":13}, + "KPWD": {"id":"KPWD","lat":48.789,"lon":-104.52297,"state":"MT","location":"Sher-Wood Airport","city":"Sher","priority":13}, + "KRVF": {"id":"KRVF","lat":45.53542,"lon":-112.30228,"state":"MT","location":"Ruby Valley Field Airport","city":"Ruby Valley","priority":12}, + "KSBX": {"id":"KSBX","lat":48.54069,"lon":-111.87125,"state":"MT","location":"Shelby Airport","city":"Shelby","priority":13}, + "KSDY": {"id":"KSDY","lat":47.7,"lon":-104.2,"state":"MT","location":"Sidney-Richland","city":"Sidney","priority":99}, + "KWYS": {"id":"KWYS","lat":44.68333,"lon":-111.11667,"state":"MT","location":"West Yellowstone","city":"West Yellowstone","priority":99}, + "KAAA": {"id":"KAAA","lat":40.15885,"lon":-89.33891,"state":"IL","location":"Logan County Airport","city":"Logan Co.","priority":10}, + "KAJG": {"id":"KAJG","lat":38.60928,"lon":-87.72508,"state":"IL","location":"Mount Carmel, Mount Carmel Municipal Airport","city":"Mt Carmel","priority":9}, + "KALN": {"id":"KALN","lat":38.88968,"lon":-90.03163,"state":"IL","location":"St. Louis Regional Airport","city":"St Louis","priority":3}, + "KARR": {"id":"KARR","lat":41.77132,"lon":-88.48147,"state":"IL","location":"Aurora Municipal Airport","city":"Aurora","priority":9}, + "KBLV": {"id":"KBLV","lat":38.55,"lon":-89.85,"state":"IL","location":"Belleville, Scott AFB/MidAmerica Airport","city":"Belleville","priority":14}, + "KBMI": {"id":"KBMI","lat":40.47694,"lon":-88.91583,"state":"IL","location":"Bloomington/Normal, Central Illinois Regional Airport at Bloomington-Normal","city":"Bloomington","priority":3}, + "KCIR": {"id":"KCIR","lat":37.06388,"lon":-89.2232,"state":"IL","location":"Cairo Regional Airport","city":"Cairo","priority":3}, + "KCMI": {"id":"KCMI","lat":40.03245,"lon":-88.27547,"state":"IL","location":"University of Illinois - Willard","city":"University of Illinois","priority":99}, + "KCPS": {"id":"KCPS","lat":38.56403,"lon":-90.14871,"state":"IL","location":"St. Louis Downtown Airport","city":"St Louis Downtown","priority":13}, + "KDEC": {"id":"KDEC","lat":39.8308,"lon":-88.87192,"state":"IL","location":"Decatur Airport","city":"Decatur","priority":13}, + "KDKB": {"id":"KDKB","lat":41.93381,"lon":-88.70657,"state":"IL","location":"De Kalb Taylor Municipal Airport","city":"De Kalb Taylor","priority":9}, + "KDNV": {"id":"KDNV","lat":40.19944,"lon":-87.59556,"state":"IL","location":"Danville, Vermilion County Airport","city":"Danville","priority":10}, + "KDPA": {"id":"KDPA","lat":41.8963899,"lon":-88.25111,"state":"IL","location":"Chicago / West Chicago, Dupage Airport","city":"West Chicago","priority":13}, + "KENL": {"id":"KENL","lat":38.50951,"lon":-89.08996,"state":"IL","location":"Centralia Municipal Airport","city":"Centralia","priority":9}, + "KFOA": {"id":"KFOA","lat":38.66726,"lon":-88.4526999,"state":"IL","location":"Flora Municipal Airport","city":"Flora","priority":9}, + "KFWC": {"id":"KFWC","lat":38.37861,"lon":-88.41278,"state":"IL","location":"Fairfield, Fairfield Municipal Airport","city":"Fairfield","priority":9}, + "KGBG": {"id":"KGBG","lat":40.9328999,"lon":-90.43339,"state":"IL","location":"Galesburg Municipal Airport","city":"Galesburg","priority":9}, + "KHSB": {"id":"KHSB","lat":37.81281,"lon":-88.54486,"state":"IL","location":"Harrisburg-Raleigh Airport","city":"Harrisburg","priority":13}, + "KIGQ": {"id":"KIGQ","lat":41.54125,"lon":-87.52822,"state":"IL","location":"Lansing Municipal Airport","city":"Lansing","priority":9}, + "KIJX": {"id":"KIJX","lat":39.7740099,"lon":-90.24187,"state":"IL","location":"Jacksonville Municipal Airport","city":"Jacksonville","priority":9}, + "KIKK": {"id":"KIKK","lat":41.06871,"lon":-87.85372,"state":"IL","location":"Greater Kankakee Airport","city":"Greater Kankakee","priority":13}, + "KJOT": {"id":"KJOT","lat":41.51755,"lon":-88.17903,"state":"IL","location":"Joliet Regional Airport","city":"Joliet","priority":3}, + "KLOT": {"id":"KLOT","lat":41.60307,"lon":-88.10164,"state":"IL","location":"Lewis University Airport","city":"Lewis University","priority":13}, + "KLWV": {"id":"KLWV","lat":38.76046,"lon":-87.59903,"state":"IL","location":"Lawrenceville-Vincennes International Airport","city":"Lawrenceville","priority":1}, + "KMDH": {"id":"KMDH","lat":37.78328,"lon":-89.24532,"state":"IL","location":"Southern Illinois Airport","city":"Southern Illinois","priority":13}, + "KMDW": {"id":"KMDW","lat":41.78417,"lon":-87.75528,"state":"IL","location":"Chicago, Chicago Midway Airport","city":"Chicago Midway","priority":13}, + "KMLI": {"id":"KMLI","lat":41.4482,"lon":-90.52359,"state":"IL","location":"Moline Quad-City Airport","city":"Moline Quad-City","priority":13}, + "KMQB": {"id":"KMQB","lat":40.5176299,"lon":-90.64807,"state":"IL","location":"Macomb Municipal Airport","city":"Macomb","priority":9}, + "KMTO": {"id":"KMTO","lat":39.47806,"lon":-88.2791699,"state":"IL","location":"Mattoon / Charleston, Coles County Memorial Airport","city":"Mattoon","priority":10}, + "KMVN": {"id":"KMVN","lat":38.32842,"lon":-88.85292,"state":"IL","location":"Mount Vernon Airport","city":"Mt Vernon","priority":13}, + "KMWA": {"id":"KMWA","lat":37.76671,"lon":-89.00993,"state":"IL","location":"Marion - Williamson County Regional Airport","city":"Marion","priority":10}, + "KOLY": {"id":"KOLY","lat":38.72133,"lon":-88.1799,"state":"IL","location":"Olney-Noble Airport","city":"Olney","priority":13}, + "KORD": {"id":"KORD","lat":41.97972,"lon":-87.9044399,"state":"IL","location":"Chicago, Chicago-O'Hare International Airport","city":"Chicago","priority":1}, + "KPIA": {"id":"KPIA","lat":40.6674999,"lon":-89.68389,"state":"IL","location":"Peoria - General Downing-Peoria International Airport","city":"Peoria","priority":1}, + "KPNT": {"id":"KPNT","lat":40.92327,"lon":-88.6213,"state":"IL","location":"Pontiac Municipal Airport","city":"Pontiac","priority":9}, + "KPPQ": {"id":"KPPQ","lat":39.63889,"lon":-90.77833,"state":"IL","location":"Pittsfield, Pittsfield Penstone Municipal Airport","city":"Pittsfield","priority":9}, + "KPRG": {"id":"KPRG","lat":39.69817,"lon":-87.6669,"state":"IL","location":"Edgar County Airport","city":"Edgar Co.","priority":10}, + "KPWK": {"id":"KPWK","lat":42.12083,"lon":-87.90472,"state":"IL","location":"Chicago / Wheeling, Pal-Waukee Airport","city":"Wheeling","priority":13}, + "KRFD": {"id":"KRFD","lat":42.19278,"lon":-89.09333,"state":"IL","location":"Rockford, Greater Rockford Airport","city":"Rockford","priority":13}, + "KRPJ": {"id":"KRPJ","lat":41.8905699,"lon":-89.08175,"state":"IL","location":"Rochelle, Rochelle Municipal-Koritz Field Airport","city":"Rochelle","priority":9}, + "KSAR": {"id":"KSAR","lat":38.14624,"lon":-89.70243,"state":"IL","location":"Sparta Community-Hunter Field Airport","city":"Sparta Community","priority":12}, + "KSLO": {"id":"KSLO","lat":38.64278,"lon":-88.96417,"state":"IL","location":"Salem, Salem-Leckrone Airport","city":"Salem","priority":13}, + "KSPI": {"id":"KSPI","lat":39.84527,"lon":-89.68405,"state":"IL","location":"Springfield - Abraham Lincoln Capital Airport","city":"Springfield","priority":13}, + "KSQI": {"id":"KSQI","lat":41.7432,"lon":-89.66547,"state":"IL","location":"Sterling Rockfalls","city":"Sterling Rockfalls","priority":99}, + "KTAZ": {"id":"KTAZ","lat":39.53417,"lon":-89.32778,"state":"IL","location":"Taylorville, Taylorville Municipal Airport","city":"Taylorville","priority":9}, + "KTIP": {"id":"KTIP","lat":40.28952,"lon":-88.1473,"state":"IL","location":"Rantoul National Aviation Center Airport","city":"Rantoul","priority":2}, + "KUGN": {"id":"KUGN","lat":42.42546,"lon":-87.86339,"state":"IL","location":"Chicago/Waukegan Regional Airport","city":"Waukegan","priority":3}, + "KUIN": {"id":"KUIN","lat":39.9371,"lon":-91.19659,"state":"IL","location":"Quincy Regional Airport-Baldwin Field","city":"Quincy","priority":3}, + "KVYS": {"id":"KVYS","lat":41.35175,"lon":-89.14963,"state":"IL","location":"Illinois Valley Regional Airport","city":"Illinois Valley","priority":3}, + "KALK": {"id":"KALK","lat":31.60564,"lon":-110.4281,"state":"AZ","location":"Pioneer Airfield","city":"Pioneer","priority":99}, + "KAVQ": {"id":"KAVQ","lat":32.4096,"lon":-111.2184,"state":"AZ","location":"Tucson Marana Regional Airport","city":"Tucson Marana","priority":3}, + "KAZC": {"id":"KAZC","lat":36.95,"lon":-113,"state":"AZ","location":"Colorado City, Colorado City Municipal Airport","city":"Colorado City","priority":9}, + "KBXK": {"id":"KBXK","lat":33.4204,"lon":-112.6862,"state":"AZ","location":"Buckeye Municipal Airport","city":"Buckeye","priority":9}, + "KCGZ": {"id":"KCGZ","lat":32.95,"lon":-111.76667,"state":"AZ","location":"Casa Grande, Casa Grande Municipal Airport","city":"Casa Grande","priority":9}, + "KCHD": {"id":"KCHD","lat":33.26917,"lon":-111.81111,"state":"AZ","location":"Chandler, Chandler Municipal Airport","city":"Chandler","priority":9}, + "KCMR": {"id":"KCMR","lat":35.3054721,"lon":-112.1943889,"state":"AZ","location":"Williams/Clark Memorial Airport","city":"Williams","priority":11}, + "KDMA": {"id":"KDMA","lat":32.16667,"lon":-110.88333,"state":"AZ","location":"Davis-Monthan Air Force Base","city":"Davis-Monthan","priority":14}, + "KDUG": {"id":"KDUG","lat":31.45838,"lon":-109.60676,"state":"AZ","location":"Bisbee Douglas International Airport","city":"Bisbee Douglas","priority":1}, + "KDVT": {"id":"KDVT","lat":33.69026,"lon":-112.06618,"state":"AZ","location":"Phoenix, Phoenix-Deer Valley Municipal Airport","city":"Deer Valley","priority":9}, + "KFFZ": {"id":"KFFZ","lat":33.46667,"lon":-111.73333,"state":"AZ","location":"Mesa / Falcon Field","city":"Mesa","priority":12}, + "KFHU": {"id":"KFHU","lat":31.58333,"lon":-110.33333,"state":"AZ","location":"Fort Huachuca, Libby AAF Ft Huachuca","city":"Ft Huachuca","priority":14}, + "KFLG": {"id":"KFLG","lat":35.1443299,"lon":-111.66637,"state":"AZ","location":"Flagstaff Pulliam Airport","city":"Flagstaff Pulliam","priority":13}, + "KGCN": {"id":"KGCN","lat":35.94582,"lon":-112.15538,"state":"AZ","location":"Grand Canyon National Park Airport","city":"Grand Canyon","priority":2}, + "KGEU": {"id":"KGEU","lat":33.52722,"lon":-112.29528,"state":"AZ","location":"Glendale, Glendale Municipal Airport","city":"Glendale","priority":9}, + "KGXF": {"id":"KGXF","lat":32.8875,"lon":-112.72,"state":"AZ","location":"Gila Bend Air Force Auxiliary Field","city":"Gila Bend Air Force","priority":12}, + "KGYR": {"id":"KGYR","lat":33.41667,"lon":-112.38333,"state":"AZ","location":"Goodyear Municipal","city":"Goodyear","priority":9}, + "KHII": {"id":"KHII","lat":34.56595,"lon":-114.35224,"state":"AZ","location":"Havasu City Airport","city":"Havasu City","priority":13}, + "KIFP": {"id":"KIFP","lat":35.1575,"lon":-114.55944,"state":"AZ","location":"Bullhead City, Laughlin/Bullhead International Airport","city":"Bullhead City","priority":1}, + "KIGM": {"id":"KIGM","lat":35.2577799,"lon":-113.93306,"state":"AZ","location":"Kingman, Kingman Airport","city":"Kingman","priority":13}, + "KINW": {"id":"KINW","lat":35.02806,"lon":-110.72083,"state":"AZ","location":"Winslow, Winslow Municipal Airport","city":"Winslow","priority":9}, + "KIWA": {"id":"KIWA","lat":33.31667,"lon":-111.65,"state":"AZ","location":"Phoenix-Mesa Gateway Airport","city":"Mesa Gateway","priority":13}, + "KJTC": {"id":"KJTC","lat":34.1293999,"lon":-109.3109,"state":"AZ","location":"Springerville Municipal Airport","city":"Springerville","priority":9}, + "KLGF": {"id":"KLGF","lat":32.86459,"lon":-114.39298,"state":"AZ","location":"Laguna Army Airfield","city":"Laguna","priority":14}, + "KLUF": {"id":"KLUF","lat":33.53333,"lon":-112.38333,"state":"AZ","location":"Luke Air Force Base / Phoenix","city":"Luke AFB","priority":14}, + "KMZJ": {"id":"KMZJ","lat":32.50983,"lon":-111.32533,"state":"AZ","location":"Pinal Airpark","city":"Pinal","priority":15}, + "KNOZ": {"id":"KNOZ","lat":32.5,"lon":-114.45,"state":"AZ","location":"Yuma Auxiliary Airfield","city":"Yuma","priority":99}, + "KNYL": {"id":"KNYL","lat":32.6594399,"lon":-114.59306,"state":"AZ","location":"Yuma, Marine Corps Air Station","city":"Yuma MCAS","priority":14}, + "KOLS": {"id":"KOLS","lat":31.42083,"lon":-110.84583,"state":"AZ","location":"Nogales, Nogales International Airport","city":"Nogales","priority":1}, + "KPAN": {"id":"KPAN","lat":34.2568364,"lon":-111.3392558,"state":"AZ","location":"Payson Airport","city":"Payson","priority":13}, + "KPGA": {"id":"KPGA","lat":36.92056,"lon":-111.44806,"state":"AZ","location":"Page, Page Municipal Airport","city":"Page","priority":9}, + "KPHX": {"id":"KPHX","lat":33.427799,"lon":-112.003465,"state":"AZ","location":"Phoenix, Phoenix Sky Harbor International Airport","city":"Phoenix","priority":1}, + "KPRC": {"id":"KPRC","lat":34.64917,"lon":-112.42222,"state":"AZ","location":"Prescott, Love Field","city":"Prescott","priority":12}, + "KRQE": {"id":"KRQE","lat":35.65,"lon":-109.06667,"state":"AZ","location":"Window Rock, Window Rock Airport","city":"Window Rock","priority":13}, + "KRYN": {"id":"KRYN","lat":32.1422,"lon":-111.1746,"state":"AZ","location":"Tucson Ryan Field Airport","city":"Tucson Ryan","priority":12}, + "KSAD": {"id":"KSAD","lat":32.85722,"lon":-109.63556,"state":"AZ","location":"Safford, Safford Municipal Airport","city":"Safford","priority":9}, + "KSDL": {"id":"KSDL","lat":33.61235,"lon":-111.92316,"state":"AZ","location":"Scottsdale Airport","city":"Scottsdale","priority":13}, + "KSEZ": {"id":"KSEZ","lat":34.85,"lon":-111.78333,"state":"AZ","location":"Sedona Airport","city":"Sedona","priority":13}, + "KSJN": {"id":"KSJN","lat":34.51833,"lon":-109.37917,"state":"AZ","location":"St. Johns, St. Johns Industrial Airpark","city":"St Johns","priority":15}, + "KSOW": {"id":"KSOW","lat":34.26528,"lon":-110.00556,"state":"AZ","location":"Show Low, Show Low Regional Airport","city":"Show Low","priority":3}, + "KTUS": {"id":"KTUS","lat":32.13153,"lon":-110.95635,"state":"AZ","location":"Tucson, Tucson International Airport","city":"Tucson","priority":1}, + "KTYL": {"id":"KTYL","lat":34.45272,"lon":-110.11503,"state":"AZ","location":"Taylor Airport","city":"Taylor","priority":13}, + "KAAF": {"id":"KAAF","lat":29.72694,"lon":-85.02472,"state":"FL","location":"Apalachicola, Apalachicola","city":"Apalachicola","priority":99}, + "KAPF": {"id":"KAPF","lat":26.15,"lon":-81.76667,"state":"FL","location":"Naples, Naples Municipal Airport","city":"Naples","priority":9}, + "KBCR": {"id":"KBCR","lat":30.84389,"lon":-85.60175,"state":"FL","location":"Tri-County Airport","city":"Tri-County","priority":13}, + "KBCT": {"id":"KBCT","lat":26.3786099,"lon":-80.10778,"state":"FL","location":"Boca Raton, Boca Raton Airport","city":"Boca Raton","priority":13}, + "KBKV": {"id":"KBKV","lat":28.47361,"lon":-82.45444,"state":"FL","location":"Brooksville-Tampa Bay Regional Airport","city":"Brooksville","priority":3}, + "KBOW": {"id":"KBOW","lat":27.95,"lon":-81.78333,"state":"FL","location":"Bartow Municipal","city":"Bartow","priority":9}, + "KCEW": {"id":"KCEW","lat":30.77222,"lon":-86.52,"state":"FL","location":"Crestview, Sikes Airport","city":"Crestview","priority":13}, + "KCGC": {"id":"KCGC","lat":28.8673,"lon":-82.5712999,"state":"FL","location":"Crystal River Airport","city":"Crystal River","priority":13}, + "KCLW": {"id":"KCLW","lat":27.9742,"lon":-82.7563,"state":"FL","location":"Clearwater Air Park","city":"Clearwater","priority":15}, + "KCOF": {"id":"KCOF","lat":28.24219,"lon":-80.60799,"state":"FL","location":"Cocoa - Patrick Air Force Base","city":"Cocoa","priority":14}, + "KCOI": {"id":"KCOI","lat":28.3422,"lon":-80.68407,"state":"FL","location":"Merritt Island Airport","city":"Merritt Is.","priority":13}, + "KCRG": {"id":"KCRG","lat":30.33709,"lon":-81.51275,"state":"FL","location":"Jacksonville Craig Municipal Airport","city":"Jacksonville Craig","priority":9}, + "KCTY": {"id":"KCTY","lat":29.633326,"lon":-83.105458,"state":"FL","location":"Cross City Airport","city":"Cross City","priority":13}, + "KDAB": {"id":"KDAB","lat":29.17354,"lon":-81.07186,"state":"FL","location":"Daytona Beach International Airport","city":"Daytona Beach","priority":1}, + "KDED": {"id":"KDED","lat":29.067,"lon":-81.2837,"state":"FL","location":"DeLand Municipal Airport","city":"DeLand","priority":9}, + "KDTS": {"id":"KDTS","lat":30.39333,"lon":-86.4675,"state":"FL","location":"Destin, Destin-Ft. Walton Beach Airport","city":"Destin","priority":13}, + "KECP": {"id":"KECP","lat":30.3582,"lon":-85.7955999,"state":"FL","location":"Panama City - Northwest Florida Beaches International Airport","city":"Panama City","priority":1}, + "KEGI": {"id":"KEGI","lat":30.65,"lon":-86.51667,"state":"FL","location":"Duke Field / Eglin Auxiliary","city":"Duke","priority":12}, + "KEVB": {"id":"KEVB","lat":29.05687,"lon":-80.94909,"state":"FL","location":"New Smyrna Beach Municipal Airport","city":"New Smyrna Beach","priority":9}, + "KEYW": {"id":"KEYW","lat":24.55707,"lon":-81.75539,"state":"FL","location":"Key West International Airport","city":"Key West","priority":1}, + "KFHB": {"id":"KFHB","lat":30.61183,"lon":-81.46119,"state":"FL","location":"Fernandina Beach Municipal Airport","city":"Fernandina Beach","priority":9}, + "KFIN": {"id":"KFIN","lat":29.4657,"lon":-81.20872,"state":"FL","location":"Flagler County Airport","city":"Flagler Co.","priority":10}, + "KFLL": {"id":"KFLL","lat":26.07874,"lon":-80.1622,"state":"FL","location":"Fort Lauderdale/Hollywood International Airport","city":"Ft Lauderdale","priority":1}, + "KFMY": {"id":"KFMY","lat":26.58417,"lon":-81.8625,"state":"FL","location":"Fort Myers, Page Field","city":"Page","priority":12}, + "KFPR": {"id":"KFPR","lat":27.49806,"lon":-80.37667,"state":"FL","location":"Fort Pierce, St. Lucie County International Airport","city":"Ft Pierce","priority":1}, + "KFPY": {"id":"KFPY","lat":30.07081,"lon":-83.58154,"state":"FL","location":"Perry-Foley Airport","city":"Perry","priority":13}, + "KFXE": {"id":"KFXE","lat":26.2,"lon":-80.18333,"state":"FL","location":"Fort Lauderdale, Fort Lauderdale Executive Airport","city":"FXE","priority":5}, + "KGIF": {"id":"KGIF","lat":28.06138,"lon":-81.75684,"state":"FL","location":"Winter Havens Gilbert Airport","city":"Winter Havens Gilbert","priority":13}, + "KGNV": {"id":"KGNV","lat":29.69194,"lon":-82.27556,"state":"FL","location":"Gainesville, Gainesville Regional Airport","city":"Gainesville","priority":3}, + "KHEG": {"id":"KHEG","lat":30.27778,"lon":-81.80594,"state":"FL","location":"Herlong Recreational Airport","city":"Herlong Recreational","priority":13}, + "KHRT": {"id":"KHRT","lat":30.41667,"lon":-86.68333,"state":"FL","location":"Hurlburt Field","city":"Hurlburt","priority":12}, + "KHST": {"id":"KHST","lat":25.4948799,"lon":-80.37324,"state":"FL","location":"Homestead Air Reserve Base","city":"Homestead","priority":14}, + "KHWO": {"id":"KHWO","lat":25.99889,"lon":-80.24111,"state":"FL","location":"Hollywood, North Perry Airport","city":"Hollywood","priority":13}, + "KIMM": {"id":"KIMM","lat":26.43,"lon":-81.4,"state":"FL","location":"IMMOKALEE","city":"Immokalee","priority":99}, + "KINF": {"id":"KINF","lat":28.8086,"lon":-82.3165,"state":"FL","location":"Inverness Airport","city":"Inverness","priority":13}, + "KISM": {"id":"KISM","lat":28.29236,"lon":-81.43716,"state":"FL","location":"Kissimmee Gateway Airport","city":"Kissimmee Gateway","priority":13}, + "KJAX": {"id":"KJAX","lat":30.49534,"lon":-81.6937,"state":"FL","location":"Jacksonville International Airport","city":"Jacksonville","priority":1}, + "KLAL": {"id":"KLAL","lat":27.98333,"lon":-82.01667,"state":"FL","location":"Lakeland Linder International Airport","city":"Lakeland","priority":1}, + "KLCQ": {"id":"KLCQ","lat":30.1821,"lon":-82.5769,"state":"FL","location":"Lake City Municipal Airport","city":"Lake City","priority":9}, + "KLEE": {"id":"KLEE","lat":28.82142,"lon":-81.80964,"state":"FL","location":"Leesburg International Airport","city":"Leesburg","priority":1}, + "KLNA": {"id":"KLNA","lat":26.59305,"lon":-80.08506,"state":"FL","location":"Palm Beach County Park Airport","city":"Palm Beach Co.","priority":10}, + "KMAI": {"id":"KMAI","lat":30.83698,"lon":-85.18347,"state":"FL","location":"Marianna Municipal Airport","city":"Marianna","priority":9}, + "KMCF": {"id":"KMCF","lat":27.85,"lon":-82.5,"state":"FL","location":"Macdill Air Force Base, Fl.","city":"Macdill","priority":14}, + "KMCO": {"id":"KMCO","lat":28.41826,"lon":-81.32413,"state":"FL","location":"Orlando International Airport","city":"Orlando","priority":1}, + "KMIA": {"id":"KMIA","lat":25.79056,"lon":-80.31639,"state":"FL","location":"Miami, Miami International Airport","city":"Miami","priority":1}, + "KMLB": {"id":"KMLB","lat":28.09973,"lon":-80.6356,"state":"FL","location":"Melbourne International Airport","city":"Melbourne","priority":1}, + "KMTH": {"id":"KMTH","lat":24.72626,"lon":-81.04765,"state":"FL","location":"The Florida Keys - Marathon International Airport","city":"Marathon","priority":1}, + "KNDZ": {"id":"KNDZ","lat":30.69722,"lon":-87.02,"state":"FL","location":"Milton, Whiting Field South","city":"Milton","priority":12}, + "KNEN": {"id":"KNEN","lat":30.35,"lon":-81.88,"state":"FL","location":"WHITEHOUSE NOF","city":"Whitehouse","priority":14}, + "KNIP": {"id":"KNIP","lat":30.23468,"lon":-81.67462,"state":"FL","location":"Jacksonville Naval Air Station","city":"Jacksonville NAS","priority":14}, + "KNPA": {"id":"KNPA","lat":30.35641,"lon":-87.32326,"state":"FL","location":"Pensacola Naval Air Station","city":"Pensacola NAS","priority":14}, + "KNQX": {"id":"KNQX","lat":24.5800899,"lon":-81.68293,"state":"FL","location":"Key West Naval Air Station","city":"Key West NAS","priority":14}, + "KNRB": {"id":"KNRB","lat":30.39589,"lon":-81.42286,"state":"FL","location":"Mayport Naval Station - Adm David L. McDonald Field","city":"Mayport","priority":14}, + "KNSE": {"id":"KNSE","lat":30.72848,"lon":-87.02192,"state":"FL","location":"Milton - Whiting Field Naval Air Station North","city":"Whiting","priority":14}, + "KOBE": {"id":"KOBE","lat":27.2628,"lon":-80.8498,"state":"FL","location":"Okeechobee County Airport","city":"Okeechobee Co.","priority":10}, + "KOCF": {"id":"KOCF","lat":29.16372,"lon":-82.22097,"state":"FL","location":"Ocala International Airport - Jim Taylor Field","city":"Ocala","priority":1}, + "KOMN": {"id":"KOMN","lat":29.30111,"lon":-81.11361,"state":"FL","location":"Ormond Beach, Ormond Beach Municipal Airport","city":"Ormond Beach","priority":9}, + "KOPF": {"id":"KOPF","lat":25.91,"lon":-80.28306,"state":"FL","location":"Miami, Opa Locka Airport","city":"Opa Locka","priority":13}, + "KORL": {"id":"KORL","lat":28.54655,"lon":-81.33543,"state":"FL","location":"Orlando Executive Airport","city":"Orlando Executive","priority":5}, + "KPAM": {"id":"KPAM","lat":30.06444,"lon":-85.5637,"state":"FL","location":"Tyndall Air Force Base","city":"Tyndall","priority":14}, + "KPBI": {"id":"KPBI","lat":26.6850999,"lon":-80.0991899,"state":"FL","location":"West Palm Beach - Palm Beach International Airport","city":"West Palm Beach","priority":1}, + "KPCM": {"id":"KPCM","lat":28,"lon":-82.15,"state":"FL","location":"Plant City, Plant City Municipal Airport","city":"Plant City","priority":9}, + "KPGD": {"id":"KPGD","lat":26.91778,"lon":-81.99361,"state":"FL","location":"Punta Gorda, Charlotte County Airport","city":"Punta Gorda","priority":10}, + "KPIE": {"id":"KPIE","lat":27.91259,"lon":-82.68554,"state":"FL","location":"St. Petersburg/Clearwater Airport","city":"St Petersburg","priority":13}, + "KPMP": {"id":"KPMP","lat":26.24556,"lon":-80.11139,"state":"FL","location":"Pompano Beach, Pompano Beach Airpark","city":"Pompano Beach","priority":15}, + "KPNS": {"id":"KPNS","lat":30.47806,"lon":-87.18694,"state":"FL","location":"Pensacola - Pensacola International Airport","city":"Pensacola","priority":1}, + "KRSW": {"id":"KRSW","lat":26.52694,"lon":-81.76639,"state":"FL","location":"Fort Myers, Southwest Florida International Airport","city":"Ft Myers","priority":1}, + "KSEF": {"id":"KSEF","lat":27.45639,"lon":-81.34239,"state":"FL","location":"Sebring Regional Airport","city":"Sebring","priority":3}, + "KSFB": {"id":"KSFB","lat":28.78333,"lon":-81.25,"state":"FL","location":"Orlando / Sanford Airport","city":"Sanford","priority":13}, + "KSGJ": {"id":"KSGJ","lat":29.95924,"lon":-81.34105,"state":"FL","location":"Northeast Florida Regional Airport","city":"Northeast Florida","priority":3}, + "KSPG": {"id":"KSPG","lat":27.76852,"lon":-82.62564,"state":"FL","location":"Albert Whitted Airport","city":"Albert Whitted","priority":13}, + "KSRQ": {"id":"KSRQ","lat":27.40139,"lon":-82.55861,"state":"FL","location":"Sarasota / Bradenton, Sarasota-Bradenton International Airport","city":"Sarasota","priority":1}, + "KSUA": {"id":"KSUA","lat":27.18157,"lon":-80.22519,"state":"FL","location":"Witham Field Airport","city":"Witham","priority":12}, + "KTDR": {"id":"KTDR","lat":30.0333,"lon":-85.5333,"state":"FL","location":"Tyndall Drone Runway","city":"TDR","priority":99}, + "KTIX": {"id":"KTIX","lat":28.51667,"lon":-80.8,"state":"FL","location":"Titusville","city":"Titusville","priority":99}, + "KTLH": {"id":"KTLH","lat":30.39675,"lon":-84.35087,"state":"FL","location":"Tallahassee International Airport","city":"Tallahassee","priority":1}, + "KTMB": {"id":"KTMB","lat":25.64194,"lon":-80.43472,"state":"FL","location":"Miami, Kendall-Tamiami Executive Airport","city":"Kendall-Tamiami","priority":5}, + "KTPA": {"id":"KTPA","lat":27.96139,"lon":-82.54028,"state":"FL","location":"Tampa, Tampa International Airport","city":"Tampa","priority":1}, + "KTPF": {"id":"KTPF","lat":27.91556,"lon":-82.44917,"state":"FL","location":"Tampa, Peter O Knight Airport","city":"Peter O Knight","priority":13}, + "KTTS": {"id":"KTTS","lat":28.61667,"lon":-80.7,"state":"FL","location":"Titusville, NASA Shuttle Landing Facility","city":"NASA SLF","priority":99}, + "KVDF": {"id":"KVDF","lat":28.01983,"lon":-82.3415,"state":"FL","location":"Tampa, Vandenberg Airport","city":"Vandenberg","priority":13}, + "KVNC": {"id":"KVNC","lat":27.0716,"lon":-82.44033,"state":"FL","location":"Venice Municipal Airport","city":"Venice","priority":9}, + "KVPS": {"id":"KVPS","lat":30.48333,"lon":-86.51667,"state":"FL","location":"Valparaiso / Eglin Air Force Base","city":"Valparaiso","priority":14}, + "KVQQ": {"id":"KVQQ","lat":30.21292,"lon":-81.8707,"state":"FL","location":"Cecil Airport","city":"Cecil","priority":13}, + "KVRB": {"id":"KVRB","lat":27.65556,"lon":-80.41806,"state":"FL","location":"Vero Beach, Vero Beach Municipal Airport","city":"Vero Beach","priority":9}, + "KXMR": {"id":"KXMR","lat":28.46667,"lon":-80.56667,"state":"FL","location":"Cocoa Beach, Cape Canaveral Air Force Station Skid Strip","city":"Cocoa Beach","priority":99}, + "KZPH": {"id":"KZPH","lat":28.2281,"lon":-82.1559,"state":"FL","location":"Zephyrhills Airport","city":"Zephyrhills","priority":13}, + "KABH": {"id":"KABH","lat":38.7578,"lon":-104.3013,"state":"CO","location":"ELLICOTT-B AFA","city":"Ellicott","priority":99}, + "KAFF": {"id":"KAFF","lat":38.96667,"lon":-104.81667,"state":"CO","location":"Air Force Academy","city":"Air Force Academy","priority":99}, + "KAIB": {"id":"KAIB","lat":38.23875,"lon":-108.563277,"state":"CO","location":"Nucla Hopkins Field Airport","city":"Nucla","priority":12}, + "KAJZ": {"id":"KAJZ","lat":38.7868799,"lon":-108.06584,"state":"CO","location":"Delta/Blake Field Airport","city":"Delta","priority":12}, + "KAKO": {"id":"KAKO","lat":40.17428,"lon":-103.21459,"state":"CO","location":"Colorado Plains Regional Airport","city":"Colorado Plains","priority":3}, + "KALS": {"id":"KALS","lat":37.43933,"lon":-105.8618,"state":"CO","location":"San Luis Valley Regional Airport","city":"San Luis Valley","priority":3}, + "KANK": {"id":"KANK","lat":38.53828,"lon":-106.04864,"state":"CO","location":"Harriet Alexander Field Airport","city":"Harriet Alexander","priority":12}, + "KAPA": {"id":"KAPA","lat":39.55991,"lon":-104.84841,"state":"CO","location":"Denver - Centennial Airport","city":"Centennial","priority":13}, + "KASE": {"id":"KASE","lat":39.22992,"lon":-106.87051,"state":"CO","location":"Aspen-Pitkin County Airport","city":"Aspen","priority":10}, + "KBDU": {"id":"KBDU","lat":40.0394297,"lon":-105.2258217,"state":"CO","location":"Boulder Municipal Airport","city":"Boulder","priority":9}, + "KBJC": {"id":"KBJC","lat":39.90085,"lon":-105.10417,"state":"CO","location":"Broomfield / Jeffco","city":"Broomfield","priority":99}, + "KBKF": {"id":"KBKF","lat":39.71331,"lon":-104.75806,"state":"CO","location":"Buckley Space Force Base","city":"Buckley","priority":14}, + "KCAG": {"id":"KCAG","lat":40.49297,"lon":-107.52394,"state":"CO","location":"Craig-Moffat Airport","city":"Craig","priority":13}, + "KCCU": {"id":"KCCU","lat":39.47523,"lon":-106.15228,"state":"CO","location":"Copper Mountain - Red Cliff Pass","city":"Copper Mtn","priority":99}, + "KCEZ": {"id":"KCEZ","lat":37.30706,"lon":-108.62644,"state":"CO","location":"Cortez-Montezuma County Airport","city":"Cortez","priority":10}, + "KCFO": {"id":"KCFO","lat":39.78419,"lon":-104.53764,"state":"CO","location":"Colorado Air and Space Port Airport","city":"Colorado","priority":14}, + "KCOS": {"id":"KCOS","lat":38.8094899,"lon":-104.68873,"state":"CO","location":"City of Colorado Springs Municipal Airport","city":"Colorado Springs","priority":9}, + "KCPW": {"id":"KCPW","lat":37.45139,"lon":-106.80028,"state":"CO","location":"Pagosa Springs, Wolf Creek Pass","city":"Wolf Creek Pass","priority":99}, + "KCWN": {"id":"KCWN","lat":38.7434299,"lon":-104.84334,"state":"CO","location":"Cheyenne Mountain","city":"Cheyenne Mtn","priority":99}, + "KDEN": {"id":"KDEN","lat":39.84658,"lon":-104.65622,"state":"CO","location":"Denver, Denver International Airport","city":"Denver","priority":1}, + "KDRO": {"id":"KDRO","lat":37.14312,"lon":-107.76023,"state":"CO","location":"Durango-La Plata County Airport","city":"Durango","priority":10}, + "KEEO": {"id":"KEEO","lat":40.0444,"lon":-107.88832,"state":"CO","location":"Meeker Airport","city":"Meeker","priority":13}, + "KEGE": {"id":"KEGE","lat":39.65,"lon":-106.91667,"state":"CO","location":"Eagle County Regional","city":"Eagle County","priority":10}, + "KEIK": {"id":"KEIK","lat":40.01169,"lon":-105.05033,"state":"CO","location":"Erie Municipal Airport","city":"Erie","priority":9}, + "KFCS": {"id":"KFCS","lat":38.68312,"lon":-104.75977,"state":"CO","location":"Butts Army Airfield (Fort Carson)","city":"Butts AAF (Ft Carson)","priority":14}, + "KFLY": {"id":"KFLY","lat":38.94391,"lon":-104.5684,"state":"CO","location":"Meadow Lake Airport","city":"Meadow Lake","priority":13}, + "KFMM": {"id":"KFMM","lat":40.33148,"lon":-103.80704,"state":"CO","location":"Fort Morgan Municipal Airport","city":"Ft Morgan","priority":9}, + "KFNL": {"id":"KFNL","lat":40.45,"lon":-105.01667,"state":"CO","location":"Fort Collins/Loveland - Northern Colorado Regional Airport","city":"Ft Collins/Loveland","priority":3}, + "KGJT": {"id":"KGJT","lat":39.13389,"lon":-108.53861,"state":"CO","location":"Grand Junction Regional Airport","city":"Grand Junction","priority":3}, + "KGNB": {"id":"KGNB","lat":40.09006,"lon":-105.91664,"state":"CO","location":"Granby-Grand County Airport","city":"Granby","priority":10}, + "KGUC": {"id":"KGUC","lat":38.53333,"lon":-106.93333,"state":"CO","location":"Gunnison, Gunnison-Crested Butte Regional Airport","city":"Gunnison","priority":3}, + "KGXY": {"id":"KGXY","lat":40.43333,"lon":-104.63333,"state":"CO","location":"Greeley, Greeley-Weld County Airport","city":"Greeley","priority":10}, + "KHEQ": {"id":"KHEQ","lat":40.57155,"lon":-102.27676,"state":"CO","location":"Holyoke Airport","city":"Holyoke","priority":13}, + "KITR": {"id":"KITR","lat":39.24149,"lon":-102.2818999,"state":"CO","location":"Burlington - Carson County Airport","city":"Burlington","priority":10}, + "KLAA": {"id":"KLAA","lat":38.0717799,"lon":-102.68745,"state":"CO","location":"Lamar Municipal Airport","city":"Lamar","priority":9}, + "KLHX": {"id":"KLHX","lat":38.04949,"lon":-103.51334,"state":"CO","location":"La Junta Municipal Airport","city":"La Junta","priority":9}, + "KLIC": {"id":"KLIC","lat":39.27334,"lon":-103.66738,"state":"CO","location":"Limon Municipal Airport","city":"Limon","priority":9}, + "KLMO": {"id":"KLMO","lat":40.16115,"lon":-105.16042,"state":"CO","location":"Vance Brand Airport","city":"Vance Brand","priority":13}, + "KLXV": {"id":"KLXV","lat":39.22806,"lon":-106.31611,"state":"CO","location":"Leadville, Lake County Airport","city":"Leadville","priority":10}, + "KMNH": {"id":"KMNH","lat":39.22317,"lon":-104.6422599,"state":"CO","location":"Elbert Mountain - Monument Pass","city":"Elbert Mtn","priority":99}, + "KMTJ": {"id":"KMTJ","lat":38.505,"lon":-107.8975,"state":"CO","location":"Montrose, Montrose Regional Airport","city":"Montrose","priority":3}, + "KMYP": {"id":"KMYP","lat":38.4972,"lon":-106.3197,"state":"CO","location":"Salida - Monarch Pass","city":"Salida","priority":99}, + "KPSO": {"id":"KPSO","lat":37.2862,"lon":-107.056,"state":"CO","location":"Stevens Field, Pagosa Springs","city":"Pagosa Springs","priority":12}, + "KPUB": {"id":"KPUB","lat":38.28869,"lon":-104.5057,"state":"CO","location":"Pueblo Memorial Airport","city":"Pueblo","priority":11}, + "KRCV": {"id":"KRCV","lat":37.7138,"lon":-106.352,"state":"CO","location":"Astronaut Kent Rominger - Del Norte","city":"Del Norte","priority":99}, + "KRIL": {"id":"KRIL","lat":39.52793,"lon":-107.71961,"state":"CO","location":"Garfield County Regional Airport","city":"Garfield Co.","priority":10}, + "KSBS": {"id":"KSBS","lat":40.5153,"lon":-106.86767,"state":"CO","location":"Steamboat Springs","city":"Steamboat Springs","priority":99}, + "KSHM": {"id":"KSHM","lat":38.8,"lon":-104.5167,"state":"CO","location":"Schriever AFB","city":"Schriever","priority":14}, + "KSPD": {"id":"KSPD","lat":37.28333,"lon":-102.61667,"state":"CO","location":"Springfield, Comanche National Grassland","city":"Springfield","priority":2}, + "KSTK": {"id":"KSTK","lat":40.61331,"lon":-103.26109,"state":"CO","location":"Sterling Municipal Airport","city":"Sterling","priority":9}, + "KTAD": {"id":"KTAD","lat":37.26218,"lon":-104.33184,"state":"CO","location":"Perry Stokes Airport","city":"Perry Stokes","priority":13}, + "KTEX": {"id":"KTEX","lat":37.95389,"lon":-107.90861,"state":"CO","location":"Telluride, Telluride Regional Airport","city":"Telluride","priority":3}, + "KVTP": {"id":"KVTP","lat":37.50111,"lon":-105.16694,"state":"CO","location":"La Veta Mountain, La Veta Pass","city":"La Veta Mtn","priority":99}, + "PARW": {"id":"PARW","lat":46.5061111,"lon":-120.4519444,"state":"WA","location":"YAKIMA RIVER NEAR PARKER, WA.","city":"Parker","priority":50}, + "QSPW": {"id":"QSPW","lat":47.0672222,"lon":-121.0788888,"state":"WA","location":"QUARTZ MTN","city":"Quartz Mtn","priority":99}, + "KABI": {"id":"KABI","lat":32.41028,"lon":-99.68167,"state":"TX","location":"Abilene, Abilene Regional Airport","city":"Abilene","priority":3}, + "KACT": {"id":"KACT","lat":31.61722,"lon":-97.22778,"state":"TX","location":"Waco, Waco Regional Airport","city":"Waco","priority":3}, + "KADS": {"id":"KADS","lat":32.96667,"lon":-96.83333,"state":"TX","location":"Dallas / Addison Airport","city":"Addison","priority":13}, + "KAFW": {"id":"KAFW","lat":32.97333,"lon":-97.31806,"state":"TX","location":"Fort Worth, Fort Worth Alliance Airport","city":"Ft Worth Alliance","priority":13}, + "KALI": {"id":"KALI","lat":27.74111,"lon":-98.02694,"state":"TX","location":"Alice, Alice International Airport","city":"Alice","priority":1}, + "KAMA": {"id":"KAMA","lat":35.22,"lon":-101.71722,"state":"TX","location":"Amarillo, Amarillo International Airport","city":"Amarillo","priority":1}, + "KAPY": {"id":"KAPY","lat":26.969,"lon":-99.249,"state":"TX","location":"Zapata, TX","city":"Zapata","priority":99}, + "KAQO": {"id":"KAQO","lat":30.78361,"lon":-98.66194,"state":"TX","location":"Llano, Llano Municipal Airport","city":"Llano","priority":9}, + "KARM": {"id":"KARM","lat":29.25417,"lon":-96.1541699,"state":"TX","location":"Wharton, Wharton Regional Airport","city":"Wharton","priority":3}, + "KASL": {"id":"KASL","lat":32.5205,"lon":-94.3078,"state":"TX","location":"Marshall","city":"Marshall","priority":99}, + "KATT": {"id":"KATT","lat":30.31667,"lon":-97.76667,"state":"TX","location":"Austin City, Austin Camp Mabry","city":"Austin City","priority":99}, + "KAUS": {"id":"KAUS","lat":30.18304,"lon":-97.6798699,"state":"TX","location":"Austin-Bergstrom International Airport","city":"Austin","priority":1}, + "KAXH": {"id":"KAXH","lat":29.50613,"lon":-95.47692,"state":"TX","location":"Houston Southwest Airport","city":"Houston Southwest","priority":13}, + "KBAZ": {"id":"KBAZ","lat":29.70575,"lon":-98.04322,"state":"TX","location":"New Braunfels National Airport","city":"New Braunfels","priority":2}, + "KBBD": {"id":"KBBD","lat":31.17917,"lon":-99.32389,"state":"TX","location":"Brady, Curtis Field Airport","city":"Brady","priority":12}, + "KBEA": {"id":"KBEA","lat":28.362,"lon":-97.791,"state":"TX","location":"Beeville Municipal Airport","city":"Beeville","priority":9}, + "KBGD": {"id":"KBGD","lat":35.695,"lon":-101.395,"state":"TX","location":"Borger, Hutchinson County Airport","city":"Borger","priority":10}, + "KBIF": {"id":"KBIF","lat":31.86119,"lon":-106.3691599,"state":"TX","location":"Biggs Army Air Field - Fort Bliss","city":"Biggs","priority":14}, + "KBKD": {"id":"KBKD","lat":32.719,"lon":-98.891,"state":"TX","location":"Stephens County Airport","city":"Stephens Co.","priority":10}, + "KBKS": {"id":"KBKS","lat":27.20667,"lon":-98.12111,"state":"TX","location":"Falfurrias, Brooks County Airport","city":"Falfurrias","priority":10}, + "KBMQ": {"id":"KBMQ","lat":30.74056,"lon":-98.23528,"state":"TX","location":"Burnet, Burnet Municipal Craddock Field","city":"Burnet","priority":9}, + "KBMT": {"id":"KBMT","lat":30.0702,"lon":-94.2151,"state":"TX","location":"Beaumont Municipal Airport","city":"Beaumont Municipal","priority":9}, + "KBPC": {"id":"KBPC","lat":35.889,"lon":-101.03,"state":"TX","location":"Mesa Vista Ranch AP","city":"Mesa Vista Ranch","priority":99}, + "KBPG": {"id":"KBPG","lat":32.2,"lon":-101.51667,"state":"TX","location":"Big Spring, Big Spring McMahon-Wrinkle Airport","city":"Big Spring","priority":13}, + "KBPT": {"id":"KBPT","lat":29.9521,"lon":-94.0261,"state":"TX","location":"Beaumont/Port Arthur Southeast Texas Regional Airport","city":"Beaumont","priority":3}, + "KBQX": {"id":"KBQX","lat":28.5,"lon":-95.72,"state":"TX","location":"BRAZOS 451 OIL PLATFORM","city":"Brazos 451 Oil Platform","priority":99}, + "KBRO": {"id":"KBRO","lat":25.91417,"lon":-97.42306,"state":"TX","location":"Brownsville, Brownsville / South Padre Island International Airport","city":"Brownsville","priority":1}, + "KBWD": {"id":"KBWD","lat":31.8,"lon":-98.95,"state":"TX","location":"Brownwood, Brownwood Regional Airport","city":"Brownwood","priority":3}, + "KBYY": {"id":"KBYY","lat":28.97306,"lon":-95.86333,"state":"TX","location":"Bay City, Bay City Municipal Airport","city":"Bay City","priority":9}, + "KCDS": {"id":"KCDS","lat":34.4275,"lon":-100.28333,"state":"TX","location":"Childress, Childress Municipal Airport","city":"Childress","priority":9}, + "KCFD": {"id":"KCFD","lat":30.7157,"lon":-96.3314,"state":"TX","location":"Bryan Coulter Field","city":"Bryan Coulter","priority":12}, + "KCLL": {"id":"KCLL","lat":30.58222,"lon":-96.36167,"state":"TX","location":"College Station, Easterwood Field","city":"College Station","priority":12}, + "KCNW": {"id":"KCNW","lat":31.6378,"lon":-97.0741,"state":"TX","location":"Waco-James Connally Airport","city":"James Connally","priority":13}, + "KCOM": {"id":"KCOM","lat":31.84,"lon":-99.4,"state":"TX","location":"COLEMAN","city":"Coleman","priority":99}, + "KCOT": {"id":"KCOT","lat":28.45833,"lon":-99.22028,"state":"TX","location":"Cotulla, Cotulla-La Salle County Airport","city":"Cotulla","priority":10}, + "KCPT": {"id":"KCPT","lat":32.35361,"lon":-97.43361,"state":"TX","location":"Cleburne, Cleburne Municipal Airport","city":"Cleburne","priority":9}, + "KCRP": {"id":"KCRP","lat":27.77306,"lon":-97.51278,"state":"TX","location":"Corpus Christi, Corpus Christi International Airport","city":"Corpus Christi","priority":1}, + "KCRS": {"id":"KCRS","lat":32.03111,"lon":-96.39889,"state":"TX","location":"Corsicana, Campbell Field-Corsicana Municipal Airport","city":"Corsicana","priority":9}, + "KCVB": {"id":"KCVB","lat":29.34192,"lon":-98.8509,"state":"TX","location":"Castroville Municipal Airport","city":"Castroville","priority":9}, + "KCWC": {"id":"KCWC","lat":33.8606,"lon":-98.4903999,"state":"TX","location":"Kickapoo Downtown Airport","city":"Kickapoo Downtown","priority":13}, + "KCXO": {"id":"KCXO","lat":30.35667,"lon":-95.41389,"state":"TX","location":"Conroe, Montgomery County Airport","city":"Conroe","priority":10}, + "KCZT": {"id":"KCZT","lat":28.5222,"lon":-99.8236,"state":"TX","location":"Carrizo Springs Dimmit County Airport","city":"Carrizo Springs","priority":10}, + "KDAL": {"id":"KDAL","lat":32.85416,"lon":-96.85506,"state":"TX","location":"Dallas Love Field","city":"Dallas Love","priority":12}, + "KDFW": {"id":"KDFW","lat":32.89743,"lon":-97.02196,"state":"TX","location":"Dallas/Fort Worth International Airport","city":"Dallas","priority":1}, + "KDHT": {"id":"KDHT","lat":36.02333,"lon":-102.54722,"state":"TX","location":"Dalhart, Dalhart Municipal Airport","city":"Dalhart","priority":9}, + "KDKR": {"id":"KDKR","lat":31.30694,"lon":-95.40361,"state":"TX","location":"Crockett, Houston County Airport","city":"Crockett","priority":10}, + "KDLF": {"id":"KDLF","lat":29.36652,"lon":-100.78469,"state":"TX","location":"Laughlin Air Force Base Auxiliary Airfield","city":"Laughlin","priority":14}, + "KDRT": {"id":"KDRT","lat":29.37472,"lon":-100.92361,"state":"TX","location":"Del Rio, Del Rio International Airport","city":"Del Rio","priority":1}, + "KDTO": {"id":"KDTO","lat":33.20505,"lon":-97.20061,"state":"TX","location":"Denton Enterprise Airport","city":"Denton Enterprise","priority":13}, + "KDUX": {"id":"KDUX","lat":35.85778,"lon":-102.01306,"state":"TX","location":"Dumas, Moore County Airport","city":"Dumas","priority":10}, + "KDWH": {"id":"KDWH","lat":30.0675,"lon":-95.55611,"state":"TX","location":"Houston, Hooks Memorial Airport","city":"Hooks","priority":11}, + "KDYS": {"id":"KDYS","lat":32.42,"lon":-99.85694,"state":"TX","location":"Abilene, Dyess Air Force Base","city":"Dyess AFB","priority":14}, + "KDZB": {"id":"KDZB","lat":30.5271,"lon":-98.3588,"state":"TX","location":"Horseshoe Bay Resort Airpark","city":"Horseshoe Bay Resort","priority":15}, + "KEBG": {"id":"KEBG","lat":26.44194,"lon":-98.12944,"state":"TX","location":"Edinburg, Edinburg International Airport","city":"Edinburg","priority":1}, + "KECU": {"id":"KECU","lat":29.94667,"lon":-100.17361,"state":"TX","location":"Rocksprings, Edwards County Airport","city":"Rocksprings","priority":10}, + "KEDC": {"id":"KEDC","lat":30.3925,"lon":-97.5621,"state":"TX","location":"Austin Executive Airport","city":"Austin Executive","priority":5}, + "KEFD": {"id":"KEFD","lat":29.6,"lon":-95.16667,"state":"TX","location":"Houston / Ellington","city":"Ellington","priority":99}, + "KELA": {"id":"KELA","lat":29.6006,"lon":-96.3219,"state":"TX","location":"Eagle Lake","city":"Eagle Lake","priority":99}, + "KELP": {"id":"KELP","lat":31.81111,"lon":-106.3758299,"state":"TX","location":"El Paso, El Paso International Airport","city":"El Paso","priority":1}, + "KERV": {"id":"KERV","lat":29.96667,"lon":-99.08333,"state":"TX","location":"Kerrville, Kerrville Municipal Airport/Louis Schreiner Field","city":"Kerrville","priority":9}, + "KETN": {"id":"KETN","lat":32.41489,"lon":-98.80969,"state":"TX","location":"Eastland Municipal Airport","city":"Eastland","priority":9}, + "KFST": {"id":"KFST","lat":30.91194,"lon":-102.91667,"state":"TX","location":"Fort Stockton, Fort Stockton-Pecos County Airport","city":"Ft Stockton","priority":10}, + "KFTN": {"id":"KFTN","lat":28.2086,"lon":-100.0188,"state":"TX","location":"Faith Ranch Airport","city":"Faith Ranch","priority":13}, + "KFTW": {"id":"KFTW","lat":32.82528,"lon":-97.36417,"state":"TX","location":"Fort Worth, Meacham International Airport","city":"Ft Worth","priority":1}, + "KFWS": {"id":"KFWS","lat":32.56537,"lon":-97.30837,"state":"TX","location":"Fort Worth Spinks Airport","city":"Ft Worth Spinks","priority":13}, + "KGDJ": {"id":"KGDJ","lat":32.44417,"lon":-97.81667,"state":"TX","location":"Granbury, Granbury Municipal Airport","city":"Granbury","priority":9}, + "KGGG": {"id":"KGGG","lat":32.39056,"lon":-94.71389,"state":"TX","location":"Longview - East Texas Regional Airport","city":"Longview","priority":3}, + "KGKY": {"id":"KGKY","lat":32.65829,"lon":-97.09509,"state":"TX","location":"Arlington Municipal Airport","city":"Arlington","priority":9}, + "KGLS": {"id":"KGLS","lat":29.27028,"lon":-94.86417,"state":"TX","location":"Galveston, Scholes Field","city":"Galveston","priority":12}, + "KGNC": {"id":"KGNC","lat":32.67528,"lon":-102.6525,"state":"TX","location":"Seminole, Gaines County Airport","city":"Seminole","priority":10}, + "KGOP": {"id":"KGOP","lat":31.42111,"lon":-97.79694,"state":"TX","location":"Gatesville, City-County Airport","city":"Gatesville","priority":13}, + "KGPM": {"id":"KGPM","lat":32.69861,"lon":-97.04667,"state":"TX","location":"Grand Prairie, Grand Prairie Municipal Airport","city":"Grand Prairie","priority":9}, + "KGRK": {"id":"KGRK","lat":31.06667,"lon":-97.81667,"state":"TX","location":"Fort Hood, Robert Gray AAF Ft Hood","city":"Ft Hood","priority":14}, + "KGTU": {"id":"KGTU","lat":30.68333,"lon":-97.68333,"state":"TX","location":"Georgetown, Georgetown Municipal Airport","city":"Georgetown","priority":9}, + "KGUL": {"id":"KGUL","lat":27.3,"lon":-93.53,"state":"TX","location":"GUNNISON OIL PLATFORM","city":"Gunnison Oil Platform","priority":99}, + "KGVT": {"id":"KGVT","lat":33.06667,"lon":-96.06667,"state":"TX","location":"Greenville / Majors","city":"Greenville","priority":99}, + "KGVW": {"id":"KGVW","lat":29.13,"lon":-94.55,"state":"TX","location":"Galveston 209A","city":"Galveston 209A","priority":99}, + "KGYB": {"id":"KGYB","lat":30.16917,"lon":-96.98,"state":"TX","location":"Giddings, Giddings-Lee County Airport","city":"Giddings","priority":10}, + "KGYI": {"id":"KGYI","lat":33.71667,"lon":-96.66667,"state":"TX","location":"Sherman/Denison, Grayson County Airport","city":"Sherman","priority":10}, + "KGZN": {"id":"KGZN","lat":32.3658,"lon":-99.0237,"state":"TX","location":"Gregory M Simmons Memorial Airport","city":"Gregory M Simmons","priority":11}, + "KHDO": {"id":"KHDO","lat":29.35944,"lon":-99.17417,"state":"TX","location":"Hondo, Hondo Municipal Airport","city":"Hondo","priority":9}, + "KHHF": {"id":"KHHF","lat":35.9,"lon":-100.4,"state":"TX","location":"Canadian, Hemphill County Airport","city":"Canadian","priority":10}, + "KHHV": {"id":"KHHV","lat":26.939,"lon":-94.6889999,"state":"TX","location":"Alaminos Canyon 25/H-D (ExxonMobil)","city":"Alaminos Canyon 25","priority":99}, + "KHLR": {"id":"KHLR","lat":31.13333,"lon":-97.7,"state":"TX","location":"Fort Hood, Hood AAF Ft Hood","city":"Hood AAF Ft Hood","priority":14}, + "KHOU": {"id":"KHOU","lat":29.6375,"lon":-95.2825,"state":"TX","location":"Houston, Houston Hobby Airport","city":"Houston Hobby","priority":13}, + "KHQZ": {"id":"KHQZ","lat":32.74694,"lon":-96.53028,"state":"TX","location":"Mesquite, Mesquite Metro Airport","city":"Mesquite","priority":13}, + "KHRL": {"id":"KHRL","lat":26.22972,"lon":-97.65528,"state":"TX","location":"Harlingen, Rio Grande Valley International Airport","city":"Harlingen","priority":1}, + "KHRX": {"id":"KHRX","lat":34.8578,"lon":-102.3264,"state":"TX","location":"Hereford Municipal Airport","city":"Hereford","priority":9}, + "KHYI": {"id":"KHYI","lat":29.89361,"lon":-97.86472,"state":"TX","location":"San Marcos, San Marcos Municipal Airport","city":"San Marcos","priority":9}, + "KIAH": {"id":"KIAH","lat":29.9844,"lon":-95.36074,"state":"TX","location":"Houston Intercontinental Airport","city":"Houston","priority":1}, + "KIKG": {"id":"KIKG","lat":27.5509,"lon":-98.0309,"state":"TX","location":"Kleberg County Airport","city":"Kleberg Co.","priority":10}, + "KILE": {"id":"KILE","lat":31.08333,"lon":-97.68333,"state":"TX","location":"Killeen, Skylark Field Airport","city":"Killeen","priority":12}, + "KINJ": {"id":"KINJ","lat":32.0833299,"lon":-97.0972199,"state":"TX","location":"Hillsboro, Hillsboro Municipal Airport","city":"Hillsboro","priority":9}, + "KINK": {"id":"KINK","lat":31.77972,"lon":-103.20139,"state":"TX","location":"Wink, Winkler County Airport","city":"Wink","priority":10}, + "KJAS": {"id":"KJAS","lat":30.88556,"lon":-94.0347199,"state":"TX","location":"Jasper, Jasper County-Bell Field Airport","city":"Jasper","priority":10}, + "KJCT": {"id":"KJCT","lat":30.51083,"lon":-99.76639,"state":"TX","location":"Junction, Kimble County Airport","city":"Junction","priority":10}, + "KJDD": {"id":"KJDD","lat":32.74194,"lon":-95.49639,"state":"TX","location":"Mineola/Quitman, Wood County Airport","city":"Mineola","priority":10}, + "KJSO": {"id":"KJSO","lat":31.86917,"lon":-95.21722,"state":"TX","location":"Jacksonville, Cherokee County Airport","city":"Jacksonville","priority":10}, + "KJWY": {"id":"KJWY","lat":32.45583,"lon":-96.91222,"state":"TX","location":"Midlothian/Waxahachie, Mid-Way Regional Airport","city":"Midlothian","priority":3}, + "KJXI": {"id":"KJXI","lat":32.69889,"lon":-94.94861,"state":"TX","location":"Gilmer, Fox Stephens Field - Gilmer Municipal Airport","city":"Gilmer","priority":9}, + "KLBB": {"id":"KLBB","lat":33.6674999,"lon":-101.8213899,"state":"TX","location":"Lubbock, Lubbock International Airport","city":"Lubbock","priority":1}, + "KLFK": {"id":"KLFK","lat":31.23389,"lon":-94.75,"state":"TX","location":"Lufkin, Angelina County Airport","city":"Lufkin","priority":10}, + "KLHB": {"id":"KLHB","lat":30.87167,"lon":-96.62222,"state":"TX","location":"Hearne, Hearne Municipal Airport","city":"Hearne","priority":9}, + "KLLN": {"id":"KLLN","lat":33.55253,"lon":-102.37253,"state":"TX","location":"Levelland Municipal Airport","city":"Levelland","priority":9}, + "KLNC": {"id":"KLNC","lat":32.58323,"lon":-96.72091,"state":"TX","location":"Lancaster Airport","city":"Lancaster","priority":13}, + "KLRD": {"id":"KLRD","lat":27.54361,"lon":-99.46139,"state":"TX","location":"Laredo, Laredo International Airport","city":"Laredo","priority":1}, + "KLUD": {"id":"KLUD","lat":33.25444,"lon":-97.58056,"state":"TX","location":"Decatur, Decatur Municipal Airport","city":"Decatur","priority":9}, + "KLUV": {"id":"KLUV","lat":32.75631,"lon":-101.92022,"state":"TX","location":"Lamesa Municipal Airport","city":"Lamesa","priority":9}, + "KLVJ": {"id":"KLVJ","lat":29.52111,"lon":-95.24194,"state":"TX","location":"Houston, Pearland Regional Airport","city":"Pearland","priority":3}, + "KLXY": {"id":"KLXY","lat":31.6412,"lon":-96.5145,"state":"TX","location":"Mexia Limestone County Airport","city":"Mexia","priority":10}, + "KMAF": {"id":"KMAF","lat":31.94778,"lon":-102.2086099,"state":"TX","location":"Midland, Midland International Airport","city":"Midland","priority":1}, + "KMCJ": {"id":"KMCJ","lat":29.714,"lon":-95.395,"state":"TX","location":"John Dunn Helistop","city":"John Dunn Helistop","priority":99}, + "KMDD": {"id":"KMDD","lat":32.03639,"lon":-102.10083,"state":"TX","location":"Midland, Midland Airpark","city":"MDD","priority":15}, + "KMFE": {"id":"KMFE","lat":26.17972,"lon":-98.24444,"state":"TX","location":"McAllen, Miller International Airport","city":"McAllen","priority":1}, + "KMKN": {"id":"KMKN","lat":31.91667,"lon":-98.60028,"state":"TX","location":"Comanche, Comanche County-City Airport","city":"Comanche","priority":10}, + "KMNZ": {"id":"KMNZ","lat":31.6659,"lon":-98.1486,"state":"TX","location":"Hamilton Municipal Airport","city":"Hamilton","priority":9}, + "KMWL": {"id":"KMWL","lat":32.78167,"lon":-98.06028,"state":"TX","location":"Mineral Wells, Mineral Wells Airport","city":"Mineral Wells","priority":13}, + "KNFW": {"id":"KNFW","lat":32.76583,"lon":-97.43333,"state":"TX","location":"Fort Worth, Naval Air Station","city":"Ft Worth NAS","priority":14}, + "KNGP": {"id":"KNGP","lat":27.6925,"lon":-97.29111,"state":"TX","location":"Corpus Christi, Corpus Christi Naval Air Station/Truax Field","city":"NGP","priority":14}, + "KNOG": {"id":"KNOG","lat":27.8947,"lon":-98.0425099,"state":"TX","location":"Orange Grove NALF","city":"Orange Grove","priority":14}, + "KNQI": {"id":"KNQI","lat":27.50306,"lon":-97.81167,"state":"TX","location":"Kingsville, Naval Air Station","city":"Kingsville","priority":14}, + "KOCH": {"id":"KOCH","lat":31.58333,"lon":-94.7166699,"state":"TX","location":"Nacogdoches, A L Mangham Jr. Regional Airport","city":"Nacogdoches","priority":3}, + "KODO": {"id":"KODO","lat":31.92139,"lon":-102.39167,"state":"TX","location":"Odessa, Odessa-Schlemeyer Field","city":"Odessa","priority":12}, + "KORG": {"id":"KORG","lat":30.06917,"lon":-93.80361,"state":"TX","location":"Orange, Orange County Airport","city":"Orange","priority":10}, + "KOSA": {"id":"KOSA","lat":33.09528,"lon":-94.96139,"state":"TX","location":"Mount Pleasant, Mount Pleasant Regional Airport","city":"Mt Pleasant","priority":3}, + "KOZA": {"id":"KOZA","lat":30.7353,"lon":-101.203,"state":"TX","location":"Ozona Municipal Airport","city":"Ozona","priority":9}, + "KPEZ": {"id":"KPEZ","lat":28.9562,"lon":-98.5184,"state":"TX","location":"Pleasanton Municipal Airport","city":"Pleasanton","priority":9}, + "KPIL": {"id":"KPIL","lat":26.15917,"lon":-97.3375,"state":"TX","location":"Port Isabel, Port Isabel-Cameron County Airport","city":"Port Isabel","priority":10}, + "KPKV": {"id":"KPKV","lat":28.65159,"lon":-96.68196,"state":"TX","location":"Port Lavaca - Calhoun County Airport","city":"Port Lavaca","priority":10}, + "KPPA": {"id":"KPPA","lat":35.61278,"lon":-100.99611,"state":"TX","location":"Pampa, Perry Lefors Field Airport","city":"Pampa","priority":12}, + "KPRS": {"id":"KPRS","lat":29.6341,"lon":-104.3616,"state":"TX","location":"Presidio Lely International Airport","city":"Presidio Lely","priority":1}, + "KPRX": {"id":"KPRX","lat":33.63333,"lon":-95.45,"state":"TX","location":"Paris / Cox Field","city":"Paris","priority":12}, + "KPSN": {"id":"KPSN","lat":31.77944,"lon":-95.70611,"state":"TX","location":"Palestine, Palestine Municipal Airport","city":"Palestine","priority":9}, + "KPVW": {"id":"KPVW","lat":34.1680599,"lon":-101.71722,"state":"TX","location":"Plainview, Hale County Airport","city":"Plainview","priority":10}, + "KPWG": {"id":"KPWG","lat":31.48333,"lon":-97.31667,"state":"TX","location":"Waco, Mc Gregor Executive Airport","city":"Mc Gregor","priority":5}, + "KPYX": {"id":"KPYX","lat":36.4,"lon":-100.73333,"state":"TX","location":"Perryton, Perryton Ochiltree County Airport","city":"Perryton","priority":10}, + "KRAS": {"id":"KRAS","lat":27.81167,"lon":-97.08861,"state":"TX","location":"Port Aransas, Mustang Beach Airport","city":"Port Aransas","priority":13}, + "KRBD": {"id":"KRBD","lat":32.67583,"lon":-96.86389,"state":"TX","location":"Dallas, Redbird Airport","city":"Redbird","priority":13}, + "KRBO": {"id":"KRBO","lat":27.77833,"lon":-97.69028,"state":"TX","location":"Robstown, Nueces County Airport","city":"Robstown","priority":10}, + "KRFI": {"id":"KRFI","lat":32.1417,"lon":-94.8516999,"state":"TX","location":"Rusk County Airport","city":"Rusk Co.","priority":10}, + "KRKP": {"id":"KRKP","lat":28.08371,"lon":-97.04664,"state":"TX","location":"Rockport Aransas County Airport","city":"Rockport","priority":10}, + "KRND": {"id":"KRND","lat":29.53333,"lon":-98.28333,"state":"TX","location":"Randolph Air Force Base","city":"Randolph","priority":14}, + "KRPH": {"id":"KRPH","lat":33.11,"lon":-98.55528,"state":"TX","location":"Graham, Graham Municipal Airport","city":"Graham","priority":9}, + "KRWV": {"id":"KRWV","lat":30.51528,"lon":-96.70389,"state":"TX","location":"Caldwell, Caldwell Municipal Airport","city":"Caldwell","priority":9}, + "KRYW": {"id":"KRYW","lat":30.4967,"lon":-97.9659,"state":"TX","location":"Lago Vista TX, Rusty Allen Airport","city":"Lago Vista","priority":13}, + "KSAT": {"id":"KSAT","lat":29.53278,"lon":-98.46361,"state":"TX","location":"San Antonio, San Antonio International Airport","city":"San Antonio","priority":1}, + "KSEP": {"id":"KSEP","lat":32.21667,"lon":-98.18333,"state":"TX","location":"Stephenville, Clark Field Municipal Airport","city":"Stephenville","priority":9}, + "KSEQ": {"id":"KSEQ","lat":29.56579,"lon":-97.90834,"state":"TX","location":"Seguin - Randolph AFB Auxiliary Field","city":"Seguin","priority":14}, + "KSGR": {"id":"KSGR","lat":29.62222,"lon":-95.65667,"state":"TX","location":"Houston, Sugar Land Municipal / Hull Field Airport","city":"Hull","priority":9}, + "KSHP": {"id":"KSHP","lat":33.96667,"lon":-98.48333,"state":"TX","location":"Sheppard Air Force Base","city":"Sheppard","priority":14}, + "KSJT": {"id":"KSJT","lat":31.35139,"lon":-100.4938899,"state":"TX","location":"San Angelo, Mathis Field","city":"San Angelo","priority":12}, + "KSKF": {"id":"KSKF","lat":29.38333,"lon":-98.58333,"state":"TX","location":"San Antonio - Kelly Field","city":"Kelly","priority":12}, + "KSLR": {"id":"KSLR","lat":33.16111,"lon":-95.62111,"state":"TX","location":"Sulphur Springs, Sulphur Springs Municipal Airport","city":"Sulphur Springs","priority":9}, + "KSNK": {"id":"KSNK","lat":32.69333,"lon":-100.95028,"state":"TX","location":"Snyder, Winston Field Airport","city":"Snyder","priority":12}, + "KSOA": {"id":"KSOA","lat":30.58556,"lon":-100.64833,"state":"TX","location":"Sonora, Sonora Municipal Airport","city":"Sonora","priority":9}, + "KSPS": {"id":"KSPS","lat":33.97861,"lon":-98.49278,"state":"TX","location":"Wichita Falls, Sheppard Air Force Base","city":"Wichita Falls","priority":14}, + "KSSF": {"id":"KSSF","lat":29.33889,"lon":-98.47167,"state":"TX","location":"San Antonio, Stinson Municipal Airport","city":"Stinson","priority":9}, + "KSWW": {"id":"KSWW","lat":32.46722,"lon":-100.46639,"state":"TX","location":"Sweetwater, Avenger Field Airport","city":"Sweetwater","priority":12}, + "KTFP": {"id":"KTFP","lat":27.913,"lon":-97.2115,"state":"TX","location":"Mc Campbell","city":"Mc Campbell","priority":99}, + "KTKI": {"id":"KTKI","lat":33.17778,"lon":-96.59028,"state":"TX","location":"McKinney - McKinney National Airport","city":"McKinney","priority":2}, + "KTME": {"id":"KTME","lat":29.80717,"lon":-95.89791,"state":"TX","location":"Houston Executive Airport","city":"Houston Executive","priority":5}, + "KTPL": {"id":"KTPL","lat":31.15,"lon":-97.4,"state":"TX","location":"Temple, Draughon-Miller Central Texas Regional Airport","city":"Temple","priority":3}, + "KTRL": {"id":"KTRL","lat":32.71361,"lon":-96.26833,"state":"TX","location":"Terrell, Terrell Municipal Airport","city":"Terrell","priority":9}, + "KTXW": {"id":"KTXW","lat":26.17871,"lon":-97.97401,"state":"TX","location":"Mid Valley Airport","city":"Mid Valley","priority":13}, + "KTYR": {"id":"KTYR","lat":32.35861,"lon":-95.40389,"state":"TX","location":"Tyler, Tyler Pounds Field","city":"Tyler","priority":12}, + "KUTS": {"id":"KUTS","lat":30.74389,"lon":-95.58611,"state":"TX","location":"Huntsville, Huntsville Municipal Airport","city":"Huntsville","priority":9}, + "KUVA": {"id":"KUVA","lat":29.21111,"lon":-99.74333,"state":"TX","location":"Uvalde, Garner Field Airport","city":"Uvalde","priority":12}, + "KVAF": {"id":"KVAF","lat":27.354,"lon":-94.625,"state":"TX","location":"East Breaks 643/Boomvang Spar","city":"East Breaks 643","priority":99}, + "KVCT": {"id":"KVCT","lat":28.8625,"lon":-96.92972,"state":"TX","location":"Victoria, Victoria Regional Airport","city":"Victoria","priority":3}, + "KVHN": {"id":"KVHN","lat":31.05783,"lon":-104.78381,"state":"TX","location":"Culberson County Airport","city":"Culberson Co.","priority":10}, + "KXBP": {"id":"KXBP","lat":33.17528,"lon":-97.8283299,"state":"TX","location":"Bridgeport, Bridgeport Municipal Airport","city":"Bridgeport","priority":9}, + "KAST": {"id":"KAST","lat":46.15694,"lon":-123.8825,"state":"OR","location":"Astoria, Astoria Regional Airport","city":"Astoria","priority":3}, + "KBDN": {"id":"KBDN","lat":44.0948,"lon":-121.2006,"state":"OR","location":"Bend Airport AWOS","city":"Bend","priority":13}, + "KBKE": {"id":"KBKE","lat":44.84302,"lon":-117.80987,"state":"OR","location":"Baker Municipal Airport","city":"Baker","priority":9}, + "KBNO": {"id":"KBNO","lat":43.59488,"lon":-118.95791,"state":"OR","location":"Burns Municipal Airport","city":"Burns","priority":9}, + "KBOK": {"id":"KBOK","lat":42.07444,"lon":-124.29,"state":"OR","location":"Brookings, Brookings Airport","city":"Brookings","priority":13}, + "KCVO": {"id":"KCVO","lat":44.5,"lon":-123.28333,"state":"OR","location":"Corvallis, Corvallis Municipal Airport","city":"Corvallis","priority":9}, + "KEUG": {"id":"KEUG","lat":44.13333,"lon":-123.21444,"state":"OR","location":"Eugene, Mahlon Sweet Field","city":"Eugene","priority":12}, + "KGCD": {"id":"KGCD","lat":44.40287,"lon":-118.96715,"state":"OR","location":"Grant County Regional Airport","city":"Grant Co.","priority":10}, + "KHIO": {"id":"KHIO","lat":45.54765,"lon":-122.95568,"state":"OR","location":"Portland-Hillsboro Airport","city":"Hillsboro","priority":13}, + "KHRI": {"id":"KHRI","lat":45.82583,"lon":-119.26111,"state":"OR","location":"Hermiston, Hermiston Municipal Airport","city":"Hermiston","priority":9}, + "KJSY": {"id":"KJSY","lat":45.355889,"lon":-117.254083,"state":"OR","location":"Joseph State Airport AWOS","city":"Joseph","priority":6}, + "KLGD": {"id":"KLGD","lat":45.29066,"lon":-118.00884,"state":"OR","location":"La Grande/Union County Airport","city":"La Grande","priority":10}, + "KLKV": {"id":"KLKV","lat":42.15664,"lon":-120.39721,"state":"OR","location":"Lake County Airport","city":"Lake Co.","priority":10}, + "KLMT": {"id":"KLMT","lat":42.14703,"lon":-121.72548,"state":"OR","location":"Klamath Falls International Airport","city":"Klamath Falls","priority":1}, + "KMEH": {"id":"KMEH","lat":45.51176,"lon":-118.42466,"state":"OR","location":"Meacham","city":"Meacham","priority":99}, + "KMFR": {"id":"KMFR","lat":42.37503,"lon":-122.87696,"state":"OR","location":"Rogue Valley International Airport","city":"Rogue Valley","priority":1}, + "KMMV": {"id":"KMMV","lat":45.19611,"lon":-123.13222,"state":"OR","location":"McMinnville, McMinnville Municipal Airport","city":"McMinnville","priority":9}, + "KONO": {"id":"KONO","lat":44.01424,"lon":-117.00808,"state":"OR","location":"Ontario Municipal Airport","city":"Ontario","priority":9}, + "KONP": {"id":"KONP","lat":44.58028,"lon":-124.05806,"state":"OR","location":"Newport, Newport Municipal Airport","city":"Newport","priority":9}, + "KOTH": {"id":"KOTH","lat":43.41948,"lon":-124.2437,"state":"OR","location":"Southwest Oregon Regional Airport","city":"Southwest Oregon","priority":3}, + "KPDT": {"id":"KPDT","lat":45.69757,"lon":-118.83444,"state":"OR","location":"Eastern Oregon Regional Airport at Pendleton","city":"Pendleton","priority":3}, + "KPDX": {"id":"KPDX","lat":45.59578,"lon":-122.60917,"state":"OR","location":"Portland, Portland International Airport","city":"Portland","priority":1}, + "KRBG": {"id":"KRBG","lat":43.23368,"lon":-123.3577,"state":"OR","location":"Roseburg Regional Airport","city":"Roseburg","priority":3}, + "KRDM": {"id":"KRDM","lat":44.25588,"lon":-121.14059,"state":"OR","location":"Redmond Roberts Field","city":"Redmond Roberts","priority":12}, + "KREO": {"id":"KREO","lat":42.57766,"lon":-117.88543,"state":"OR","location":"Rome State Airport","city":"Rome","priority":6}, + "KSLE": {"id":"KSLE","lat":44.90493,"lon":-123.00096,"state":"OR","location":"Salem - McNary Field","city":"Salem","priority":12}, + "KSPB": {"id":"KSPB","lat":45.7691,"lon":-122.86365,"state":"OR","location":"Scappoose Industrial Airpark","city":"Scappoose Industrial","priority":15}, + "KSXT": {"id":"KSXT","lat":42.6,"lon":-123.3656,"state":"OR","location":"Sexton Summit","city":"Sexton Summit","priority":99}, + "KTMK": {"id":"KTMK","lat":45.4180599,"lon":-123.81444,"state":"OR","location":"Tillamook, Tillamook Airport","city":"Tillamook","priority":13}, + "KTTD": {"id":"KTTD","lat":45.55111,"lon":-122.40889,"state":"OR","location":"Portland, Portland-Troutdale Airport","city":"Troutdale","priority":13}, + "KUAO": {"id":"KUAO","lat":45.24658,"lon":-122.77095,"state":"OR","location":"Aurora State Airport","city":"Aurora","priority":6}, + "KAAT": {"id":"KAAT","lat":41.48362,"lon":-120.5615,"state":"CA","location":"Alturas","city":"Alturas","priority":99}, + "KACV": {"id":"KACV","lat":40.97806,"lon":-124.10861,"state":"CA","location":"Arcata / Eureka, Arcata Airport","city":"Arcata","priority":13}, + "KAJO": {"id":"KAJO","lat":33.8977,"lon":-117.6024,"state":"CA","location":"Corona Airport","city":"Corona","priority":13}, + "KAPC": {"id":"KAPC","lat":38.2075,"lon":-122.27944,"state":"CA","location":"Napa, Napa County Airport","city":"Napa","priority":10}, + "KAPV": {"id":"KAPV","lat":34.57533,"lon":-117.18619,"state":"CA","location":"APPLEVALLEY","city":"Applevalley","priority":99}, + "KAUN": {"id":"KAUN","lat":38.95535,"lon":-121.08636,"state":"CA","location":"Auburn Municipal Airport","city":"Auburn","priority":9}, + "KAVX": {"id":"KAVX","lat":33.40421,"lon":-118.41456,"state":"CA","location":"Avalon Catalina Airport","city":"Avalon Catalina","priority":13}, + "KBAB": {"id":"KBAB","lat":39.13333,"lon":-121.43333,"state":"CA","location":"Marysville, Beale Air Force Base","city":"Beale AFB","priority":14}, + "KBAN": {"id":"KBAN","lat":38.3557,"lon":-119.5188,"state":"CA","location":"MCMWTC BRIDGEPORT","city":"MCMWTC Bridgeport","priority":14}, + "KBFL": {"id":"KBFL","lat":35.43361,"lon":-119.05667,"state":"CA","location":"Bakersfield, Meadows Field Airport","city":"Bakersfield","priority":12}, + "KBIH": {"id":"KBIH","lat":37.37111,"lon":-118.35806,"state":"CA","location":"Bishop, Bishop Airport","city":"Bishop","priority":13}, + "KBLH": {"id":"KBLH","lat":33.6191699,"lon":-114.71694,"state":"CA","location":"Blythe, Blythe Airport","city":"Blythe","priority":13}, + "KBLU": {"id":"KBLU","lat":39.27611,"lon":-120.70806,"state":"CA","location":"Emigrant Gap, Blue Canyon Nyack Airport","city":"Emigrant Gap","priority":13}, + "KBUR": {"id":"KBUR","lat":34.19967,"lon":-118.36538,"state":"CA","location":"Burbank - Bob Hope Airport","city":"Burbank","priority":13}, + "KBYS": {"id":"KBYS","lat":35.28333,"lon":-116.61667,"state":"CA","location":"Fort Irwin/Barstow, Bicycle Lake Army Airfield","city":"Ft Irwin","priority":14}, + "KCCB": {"id":"KCCB","lat":34.11161,"lon":-117.68739,"state":"CA","location":"Cable Airport","city":"Cable","priority":13}, + "KCCR": {"id":"KCCR","lat":37.99167,"lon":-122.05194,"state":"CA","location":"Concord, Buchanan Field","city":"Concord","priority":12}, + "KCEC": {"id":"KCEC","lat":41.78028,"lon":-124.23667,"state":"CA","location":"Crescent City, Jack McNamara Field Airport","city":"Crescent City","priority":12}, + "KCIC": {"id":"KCIC","lat":39.7987899,"lon":-121.85795,"state":"CA","location":"Chico Municipal Airport","city":"Chico","priority":9}, + "KCMA": {"id":"KCMA","lat":34.21667,"lon":-119.08333,"state":"CA","location":"Camarillo, Camarillo Airport","city":"Camarillo","priority":13}, + "KCNO": {"id":"KCNO","lat":33.97556,"lon":-117.62361,"state":"CA","location":"Chino, Chino Airport","city":"Chino","priority":13}, + "KCPU": {"id":"KCPU","lat":38.1460999,"lon":-120.6482,"state":"CA","location":"San Andreas Calaveras County Airport","city":"San Andreas","priority":10}, + "KCRQ": {"id":"KCRQ","lat":33.13,"lon":-117.27583,"state":"CA","location":"Carlsbad, McClellan-Palomar Airport","city":"Carlsbad","priority":13}, + "KCVH": {"id":"KCVH","lat":36.8933,"lon":-121.4103,"state":"CA","location":"Hollister, CA","city":"Hollister","priority":99}, + "KDAG": {"id":"KDAG","lat":34.85361,"lon":-116.78667,"state":"CA","location":"Daggett, Barstow-Daggett Airport","city":"Daggett","priority":13}, + "KDLO": {"id":"KDLO","lat":35.74556,"lon":-119.2365,"state":"CA","location":"Delano Municipal Airport","city":"Delano","priority":9}, + "KDVO": {"id":"KDVO","lat":38.14178,"lon":-122.55463,"state":"CA","location":"Novato / Gnoss Field","city":"Novato","priority":12}, + "KDWA": {"id":"KDWA","lat":38.5793899,"lon":-121.85694,"state":"CA","location":"Yolo County Airport","city":"Yolo Co.","priority":10}, + "KEDU": {"id":"KEDU","lat":38.5315,"lon":-121.7865,"state":"CA","location":"University Airport","city":"University","priority":13}, + "KEDW": {"id":"KEDW","lat":34.918,"lon":-117.879,"state":"CA","location":"Edwards Air Force Base","city":"Edwards","priority":14}, + "KEED": {"id":"KEED","lat":34.76611,"lon":-114.62333,"state":"CA","location":"Needles, Needles Airport","city":"Needles","priority":13}, + "KEMT": {"id":"KEMT","lat":34.0833299,"lon":-118.03333,"state":"CA","location":"El Monte","city":"El Monte","priority":99}, + "KFAT": {"id":"KFAT","lat":36.78,"lon":-119.71944,"state":"CA","location":"Fresno, Fresno Air Terminal","city":"Fresno","priority":99}, + "KFOT": {"id":"KFOT","lat":40.55296,"lon":-124.13338,"state":"CA","location":"Fortuna Rohnerville Airport","city":"Fortuna Rohnerville","priority":13}, + "KFUL": {"id":"KFUL","lat":33.87194,"lon":-117.98472,"state":"CA","location":"Fullerton, Fullerton Municipal Airport","city":"Fullerton","priority":9}, + "KGOO": {"id":"KGOO","lat":39.2240279,"lon":-121.003083,"state":"CA","location":"Nevada County Air Park","city":"Nevada Co.","priority":15}, + "KHAF": {"id":"KHAF","lat":37.5135999,"lon":-122.4996,"state":"CA","location":"Half Moon Bay Airport","city":"Half Moon Bay","priority":13}, + "KHHR": {"id":"KHHR","lat":33.9236099,"lon":-118.33194,"state":"CA","location":"Hawthorne, Hawthorne Municipal Airport","city":"Hawthorne","priority":9}, + "KHJO": {"id":"KHJO","lat":36.31145,"lon":-119.62315,"state":"CA","location":"Hanford Municipal Airport","city":"Hanford","priority":9}, + "KHMT": {"id":"KHMT","lat":33.73403,"lon":-117.02231,"state":"CA","location":"Hemet-Ryan Airport","city":"Hemet","priority":13}, + "KHWD": {"id":"KHWD","lat":37.66083,"lon":-122.11833,"state":"CA","location":"Hayward, Hayward Air Terminal","city":"Hayward","priority":99}, + "KIPL": {"id":"KIPL","lat":32.83417,"lon":-115.57861,"state":"CA","location":"Imperial, Imperial County Airport","city":"Imperial","priority":10}, + "KIZA": {"id":"KIZA","lat":34.60694,"lon":-120.07556,"state":"CA","location":"Santa Ynez, Santa Ynez Airport","city":"Santa Ynez","priority":13}, + "KJAQ": {"id":"KJAQ","lat":38.3768,"lon":-120.79391,"state":"CA","location":"Westover Field - Amador County Airport","city":"Westover Field","priority":10}, + "KLAX": {"id":"KLAX","lat":33.93806,"lon":-118.38889,"state":"CA","location":"Los Angeles, Los Angeles International Airport","city":"Los Angeles","priority":1}, + "KLGB": {"id":"KLGB","lat":33.81167,"lon":-118.14639,"state":"CA","location":"Long Beach, Long Beach Airport","city":"Long Beach","priority":13}, + "KLHM": {"id":"KLHM","lat":38.9092,"lon":-121.3513,"state":"CA","location":"Lincoln Regional Karl Harder Field","city":"Lincoln","priority":3}, + "KLPC": {"id":"KLPC","lat":34.66667,"lon":-120.46667,"state":"CA","location":"Lompoc, Lompoc Airport","city":"Lompoc","priority":13}, + "KLVK": {"id":"KLVK","lat":37.69278,"lon":-121.81444,"state":"CA","location":"Livermore, Livermore Municipal Airport","city":"Livermore","priority":9}, + "KMAE": {"id":"KMAE","lat":36.9851,"lon":-120.11064,"state":"CA","location":"Madera Municipal Airport","city":"Madera","priority":9}, + "KMCC": {"id":"KMCC","lat":38.66667,"lon":-121.4,"state":"CA","location":"Sacramento, McClellan Airfield Airport","city":"McClellan","priority":13}, + "KMCE": {"id":"KMCE","lat":37.28306,"lon":-120.50778,"state":"CA","location":"Merced Regional Airport","city":"Merced","priority":3}, + "KMHR": {"id":"KMHR","lat":38.5599599,"lon":-121.28397,"state":"CA","location":"Sacramento Mather Airport","city":"Sacramento Mather","priority":13}, + "KMHS": {"id":"KMHS","lat":41.31494,"lon":-122.31702,"state":"CA","location":"Mount Shasta","city":"Mt Shasta","priority":99}, + "KMHV": {"id":"KMHV","lat":35.06667,"lon":-118.15,"state":"CA","location":"Mojave","city":"Mojave","priority":99}, + "KMMH": {"id":"KMMH","lat":37.6241,"lon":-118.8423,"state":"CA","location":"Mammoth Yosemite Airport","city":"Mammoth Yosemite","priority":13}, + "KMOD": {"id":"KMOD","lat":37.62549,"lon":-120.9549,"state":"CA","location":"Modesto City-County Airport - Harry Sham Field","city":"Modesto City","priority":12}, + "KMRY": {"id":"KMRY","lat":36.59047,"lon":-121.84875,"state":"CA","location":"Monterey Regional Airport","city":"Monterey","priority":3}, + "KMWS": {"id":"KMWS","lat":34.22,"lon":-118.07,"state":"CA","location":"MOUNT WILSON","city":"Mt Wilson","priority":99}, + "KMYF": {"id":"KMYF","lat":32.81444,"lon":-117.13639,"state":"CA","location":"San Diego, Montgomery Field","city":"Montgomery","priority":12}, + "KMYV": {"id":"KMYV","lat":39.09778,"lon":-121.56972,"state":"CA","location":"Marysville, Yuba County Airport","city":"Marysville","priority":10}, + "KNFG": {"id":"KNFG","lat":33.30472,"lon":-117.35389,"state":"CA","location":"Oceanside, Camp Pendleton, Marine Corps Air Station","city":"Camp Pendleton","priority":14}, + "KNID": {"id":"KNID","lat":35.68639,"lon":-117.69,"state":"CA","location":"China Lake, Naval Air Facility","city":"China Lake","priority":99}, + "KNJK": {"id":"KNJK","lat":32.825,"lon":-115.66056,"state":"CA","location":"El Centro, Naval Air Facility","city":"El Centro","priority":99}, + "KNKX": {"id":"KNKX","lat":32.86833,"lon":-117.1425,"state":"CA","location":"San Diego, Miramar MCAS/Mitscher Field Airport","city":"Miramar","priority":14}, + "KNLC": {"id":"KNLC","lat":36.30244,"lon":-119.93968,"state":"CA","location":"Lemoore Naval Air Station - Reeves Field","city":"Lemoore","priority":14}, + "KNRS": {"id":"KNRS","lat":32.56302,"lon":-117.11091,"state":"CA","location":"Imperial Beach Naval Outlying Field - Ream Field","city":"Imperial Beach","priority":14}, + "KNSI": {"id":"KNSI","lat":33.23379,"lon":-119.45588,"state":"CA","location":"San Nicolas Island Naval Outlying Field","city":"San Nicolas Is.","priority":14}, + "KNTD": {"id":"KNTD","lat":34.12389,"lon":-119.12167,"state":"CA","location":"Point Mugu, Naval Air Warfare Center","city":"Point Mugu","priority":99}, + "KNUC": {"id":"KNUC","lat":33.0218,"lon":-118.58266,"state":"CA","location":"San Clemente Island NALF","city":"San Clemente Is.","priority":14}, + "KNUQ": {"id":"KNUQ","lat":37.40583,"lon":-122.04806,"state":"CA","location":"Mountain View, Moffett Field","city":"Mountain View","priority":12}, + "KNXP": {"id":"KNXP","lat":34.29401,"lon":-116.14717,"state":"CA","location":"Twentynine Palms SELF Airport","city":"Twentynine Palms","priority":14}, + "KNZY": {"id":"KNZY","lat":32.69083,"lon":-117.20889,"state":"CA","location":"San Diego, North Island, Naval Air Station","city":"North Is.","priority":14}, + "KOAK": {"id":"KOAK","lat":37.72126,"lon":-122.22115,"state":"CA","location":"San Francisco Bay Oakland International Airport","city":"Oakland","priority":1}, + "KOAR": {"id":"KOAR","lat":36.68,"lon":-121.77,"state":"CA","location":"FORT ORD/FRITZSCHE","city":"Ft Ord","priority":99}, + "KOKB": {"id":"KOKB","lat":33.21806,"lon":-117.35139,"state":"CA","location":"Oceanside, Oceanside Municipal Airport","city":"Oceanside","priority":9}, + "KONT": {"id":"KONT","lat":34.05316,"lon":-117.57685,"state":"CA","location":"Ontario International Airport","city":"Ontario","priority":1}, + "KOVE": {"id":"KOVE","lat":39.49436,"lon":-121.62223,"state":"CA","location":"Oroville Municipal Airport","city":"Oroville","priority":9}, + "KOXR": {"id":"KOXR","lat":34.20056,"lon":-119.20306,"state":"CA","location":"Oxnard, Oxnard Airport","city":"Oxnard","priority":13}, + "KPAO": {"id":"KPAO","lat":37.46667,"lon":-122.11667,"state":"CA","location":"Palo Alto Airport","city":"Palo Alto","priority":13}, + "KPMD": {"id":"KPMD","lat":34.62972,"lon":-118.08139,"state":"CA","location":"Palmdale, Palmdale Production Flight Plant","city":"Palmdale","priority":99}, + "KPOC": {"id":"KPOC","lat":34.09282,"lon":-117.77937,"state":"CA","location":"Brackett Field Airport","city":"Brackett","priority":12}, + "KPRB": {"id":"KPRB","lat":35.66941,"lon":-120.62912,"state":"CA","location":"Paso Robles Municipal Airport","city":"Paso Robles","priority":9}, + "KPSP": {"id":"KPSP","lat":33.82219,"lon":-116.50431,"state":"CA","location":"Palm Springs Regional Airport","city":"Palm Springs","priority":3}, + "KPTV": {"id":"KPTV","lat":36.03333,"lon":-119.06667,"state":"CA","location":"Porterville, Porterville Municipal Airport","city":"Porterville","priority":9}, + "KPVF": {"id":"KPVF","lat":38.7242,"lon":-120.7533,"state":"CA","location":"Placerville Airport","city":"Placerville","priority":13}, + "KRAL": {"id":"KRAL","lat":33.95189,"lon":-117.44511,"state":"CA","location":"Riverside Municipal Airport","city":"Riverside","priority":9}, + "KRBL": {"id":"KRBL","lat":40.15056,"lon":-122.25222,"state":"CA","location":"Red Bluff, Red Bluff Municipal Airport","city":"Red Bluff","priority":9}, + "KRDD": {"id":"KRDD","lat":40.51461,"lon":-122.2977,"state":"CA","location":"Redding Municipal Airport","city":"Redding","priority":9}, + "KREI": {"id":"KREI","lat":34.08526,"lon":-117.14637,"state":"CA","location":"REDLANDS","city":"Redlands","priority":99}, + "KRHV": {"id":"KRHV","lat":37.3333299,"lon":-121.81667,"state":"CA","location":"San Jose / Reid / Hillv","city":"Reid","priority":99}, + "KRIV": {"id":"KRIV","lat":33.88194,"lon":-117.25902,"state":"CA","location":"March Air Reserve Base","city":"March","priority":14}, + "KRNM": {"id":"KRNM","lat":33.0375,"lon":-116.91583,"state":"CA","location":"Ramona, Ramona Airport","city":"Ramona","priority":13}, + "KSAC": {"id":"KSAC","lat":38.50674,"lon":-121.49597,"state":"CA","location":"Sacramento Executive Airport","city":"Sacramento Executive","priority":5}, + "KSAN": {"id":"KSAN","lat":32.73361,"lon":-117.18306,"state":"CA","location":"San Diego International Airport","city":"San Diego","priority":1}, + "KSBA": {"id":"KSBA","lat":34.42611,"lon":-119.84361,"state":"CA","location":"Santa Barbara, Santa Barbara Municipal Airport","city":"Santa Barbara","priority":9}, + "KSBD": {"id":"KSBD","lat":34.0902699,"lon":-117.24705,"state":"CA","location":"San Bernardino Intl. Airport","city":"San Bernardino","priority":13}, + "KSBP": {"id":"KSBP","lat":35.2361099,"lon":-120.63611,"state":"CA","location":"San Luis Obispo, San Luis Obispo County-Mc Chesney Field","city":"San Luis Obispo","priority":10}, + "KSCK": {"id":"KSCK","lat":37.8897199,"lon":-121.22361,"state":"CA","location":"Stockton, Stockton Metropolitan Airport","city":"Stockton","priority":13}, + "KSDB": {"id":"KSDB","lat":34.7436099,"lon":-118.72444,"state":"CA","location":"Sandberg","city":"Sandberg","priority":99}, + "KSDM": {"id":"KSDM","lat":32.57528,"lon":-116.99306,"state":"CA","location":"San Diego, Brown Field Municipal Airport","city":"Brown","priority":9}, + "KSEE": {"id":"KSEE","lat":32.82738,"lon":-116.97369,"state":"CA","location":"Gillespie Field Airport","city":"Gillespie","priority":12}, + "KSFO": {"id":"KSFO","lat":37.61961,"lon":-122.36558,"state":"CA","location":"San Francisco, San Francisco International Airport","city":"San Francisco","priority":1}, + "KSIY": {"id":"KSIY","lat":41.77375,"lon":-122.46817,"state":"CA","location":"Montague Siskiyou County Airport","city":"Montague","priority":10}, + "KSJC": {"id":"KSJC","lat":37.35917,"lon":-121.92417,"state":"CA","location":"San Jose, San Jose International Airport","city":"San Jose","priority":1}, + "KSLI": {"id":"KSLI","lat":33.79628,"lon":-118.04179,"state":"CA","location":"Los Alamitos Army Airfield","city":"Los Alamitos","priority":14}, + "KSMF": {"id":"KSMF","lat":38.70071,"lon":-121.59479,"state":"CA","location":"Sacramento International Airport","city":"Sacramento","priority":1}, + "KSMO": {"id":"KSMO","lat":34.01583,"lon":-118.45139,"state":"CA","location":"Santa Monica, Santa Monica Municipal Airport","city":"Santa Monica","priority":9}, + "KSMX": {"id":"KSMX","lat":34.89408,"lon":-120.45212,"state":"CA","location":"Santa Maria Public Airport/Capt G Allan Hancock Field","city":"Santa Maria","priority":12}, + "KSNA": {"id":"KSNA","lat":33.6798,"lon":-117.8674,"state":"CA","location":"John Wayne-Orange County Airport","city":"John Wayne","priority":10}, + "KSNS": {"id":"KSNS","lat":36.66361,"lon":-121.60806,"state":"CA","location":"Salinas, Salinas Municipal Airport","city":"Salinas","priority":9}, + "KSQL": {"id":"KSQL","lat":37.51667,"lon":-122.25,"state":"CA","location":"San Carlos Airport","city":"San Carlos","priority":13}, + "KSTS": {"id":"KSTS","lat":38.5,"lon":-122.81667,"state":"CA","location":"Santa Rosa, Santa Rosa Sonoma County Airport","city":"Santa Rosa","priority":10}, + "KSUU": {"id":"KSUU","lat":38.26667,"lon":-121.95,"state":"CA","location":"Fairfield / Travis Air Force Base","city":"Fairfield","priority":14}, + "KSVE": {"id":"KSVE","lat":40.37569,"lon":-120.57269,"state":"CA","location":"Susanville Municipal Airport","city":"Susanville","priority":9}, + "KTCY": {"id":"KTCY","lat":37.6888999,"lon":-121.44158,"state":"CA","location":"Tracy Municipal Airport","city":"Tracy","priority":9}, + "KTOA": {"id":"KTOA","lat":33.8,"lon":-118.33333,"state":"CA","location":"Torrance, Zamperini Field Airport","city":"Torrance","priority":12}, + "KTQS": {"id":"KTQS","lat":34.633,"lon":-120.617,"state":"CA","location":"Vandenberg SFB - South","city":"Vandenberg","priority":14}, + "KTRK": {"id":"KTRK","lat":39.31667,"lon":-120.13333,"state":"CA","location":"Truckee-Tahoe","city":"Truckee","priority":99}, + "KTRM": {"id":"KTRM","lat":33.62667,"lon":-116.15944,"state":"CA","location":"Palm Springs, Jacqueline Cochran Regional Airport","city":"Jacqueline Cochran","priority":3}, + "KTSP": {"id":"KTSP","lat":35.135,"lon":-118.4392,"state":"CA","location":"Tehachapi Municipal Airport","city":"Tehachapi","priority":9}, + "KTVL": {"id":"KTVL","lat":38.8983599,"lon":-119.99615,"state":"CA","location":"South Lake Tahoe, Lake Tahoe Airport","city":"South Lake Tahoe","priority":13}, + "KUKI": {"id":"KUKI","lat":39.12783,"lon":-123.20011,"state":"CA","location":"Ukiah Municipal Airport","city":"Ukiah","priority":9}, + "KVBG": {"id":"KVBG","lat":34.7294399,"lon":-120.57667,"state":"CA","location":"Vandenberg Space Force Base","city":"Vandenberg SFB","priority":14}, + "KVCB": {"id":"KVCB","lat":38.37755,"lon":-121.95853,"state":"CA","location":"Vacaville Nut Tree Airport","city":"Vacaville Nut Tree","priority":13}, + "KVCV": {"id":"KVCV","lat":34.59722,"lon":-117.38278,"state":"CA","location":"Victorville, Southern California Logistics Airport","city":"Victorville","priority":13}, + "KVIS": {"id":"KVIS","lat":36.31667,"lon":-119.4,"state":"CA","location":"Visalia, Visalia Municipal Airport","city":"Visalia","priority":9}, + "KVNY": {"id":"KVNY","lat":34.2125,"lon":-118.49083,"state":"CA","location":"Van Nuys, Van Nuys Airport","city":"Van Nuys","priority":13}, + "KWHP": {"id":"KWHP","lat":34.25,"lon":-118.4,"state":"CA","location":"Los Angeles, Whiteman Airport","city":"Whiteman","priority":13}, + "KWJF": {"id":"KWJF","lat":34.74123,"lon":-118.21251,"state":"CA","location":"General Wm J Fox Airfield","city":"General Wm J Fox","priority":99}, + "KWVI": {"id":"KWVI","lat":36.93944,"lon":-121.78889,"state":"CA","location":"Watsonville, Watsonville Municipal Airport","city":"Watsonville","priority":9}, + "PARO": {"id":"PARO","lat":45.54444,"lon":-121.61667,"state":"OR","location":"PARKDALE","city":"Parkdale","priority":50}, + "PCYO": {"id":"PCYO","lat":44.44083,"lon":-118.62778,"state":"OR","location":"PRARIE CITY","city":"Prarie City","priority":50}, + "PDTO": {"id":"PDTO","lat":45.6722222,"lon":-118.7916666,"state":"OR","location":"Umatilla River at Pendleton, OR","city":"PDTO","priority":50}, + "PILO": {"id":"PILO","lat":45.5019444,"lon":-118.6205555,"state":"OR","location":"Pilot Rock 11E, OR","city":"Pilot Rock","priority":50}, + "PNGO": {"id":"PNGO","lat":45.65222,"lon":-121.50917,"state":"OR","location":"PINEGROVE","city":"Pinegrove","priority":50}, + "POBO": {"id":"POBO","lat":44.24833,"lon":-120.94972,"state":"OR","location":"POWELL BUTTE","city":"Powell Butte","priority":50}, + "PRHO": {"id":"PRHO","lat":44.6861111,"lon":-118.1,"state":"OR","location":"Powder River at Hudspeth Lane near Sumpter, OR","city":"Sumpter","priority":50}, + "PRIO": {"id":"PRIO","lat":44.3691666,"lon":-120.9377777,"state":"OR","location":"Prineville 4NW, OR","city":"Prineville","priority":50}, + "PRVO": {"id":"PRVO","lat":44.1138888,"lon":-120.7944444,"state":"OR","location":"Crooked River near Prineville, OR","city":"PRVO","priority":50}, + "PWDO": {"id":"PWDO","lat":44.7683333,"lon":-117.8305555,"state":"OR","location":"Powder River at Baker, OR","city":"PWDO","priority":50} } \ No newline at end of file diff --git a/datagenerators/stations-postprocessor.mjs b/datagenerators/stations-postprocessor.mjs new file mode 100644 index 0000000..be9bd27 --- /dev/null +++ b/datagenerators/stations-postprocessor.mjs @@ -0,0 +1,1247 @@ +#!/usr/bin/env node + +import { readFileSync, writeFileSync } from 'fs'; + +// Load station data +const stationInfo = JSON.parse(readFileSync('./datagenerators/output/stations-raw.json', 'utf8')); +// const regionalCities = JSON.parse(readFileSync('./datagenerators/output/regionalcities.json', 'utf8')); + +// Airport exceptions for stations that require external knowledge NOT present in the original name +const airportNamingExceptions = { + KLAS: 'Las Vegas', // Harry Reid International Airport - city requires external knowledge + PHNL: 'Honolulu', // Daniel K Inouye International Airport - city requires external knowledge + KMTH: 'Marathon', // The Florida Keys - Marathon International Airport - otherwise parsed as "The Florida Keys" + KPVD: 'Providence', // Rhode Island TF Green International Airport - city requires external knowledge + KIAD: 'Dulles', // Washington/Dulles International Airport, DC - "Dulles" is shorter/common name + KLAN: 'Lansing', // Capital Region International Airport - city requires external knowledge + KMBS: 'Saginaw', // MBS Internation Airport - city requires external knowledge + KOAK: 'Oakland', // San Francisco Bay Oakland International Airport - otherwise parsed as "San Francisco Bay Oakland" + KGSP: 'Greenville', // Greenville Spartanburg International Airport - otherwise parsed as "Greenville Spartanburg" + KNKX: 'Miramar', // San Diego, Miramar MCAS/Mitscher Field Airport - otherwise parsed as "Mitscher Field" +}; + +const airportPriorityExceptions = { + KDTW: 'international', // Detroit Metropolitan is a major international airport +}; + +// Proper names that are removed to improve extraction algorithm +const namesToRemove = [ + 'Addington', + 'Astronaut Kent Rominger', + 'Bruce Campbell', + 'Captain Jack Thomas', + 'Carl R Keller', + 'Chris Crusta', + 'Henry Tift Myers', + 'Hopkins', + 'J. Douglas Bake', + 'John Glenn', + 'Joseph A Hardy', + 'Karl Harder', + 'Kyle Oakley', + 'Lambert', + 'Lawrence Smith', + 'Le Tourneau', + 'Linder', + 'Lynch Bellinger', + 'Muhammad Ali', + 'Tom B. David', +]; + +const militaryAbbreviations = { + 'Air and Space Port': 'A&SP', + 'Air Force Base': 'AFB', + 'Air National Guard Base': 'ANGB', + 'Air National Guard Weather Facility Base': 'ANGB', + 'Air Reserve Base': 'ARB', + 'Airport Heliport': 'AHP', + 'Army Air Field': 'AAF', + 'Army Airfield': 'AAF', + 'Coast Guard Air Station': 'CGAS', + 'Marine Corps Air Station': 'MCAS', + 'Marine Corps Airfield': 'MCAF', + 'Marine Corps Mountain Warfare Training Center': 'MCMWTC', + 'National Air Center': 'NAC', + 'National Aviation Center': 'NAC', + 'Naval Air Station': 'NAS', + 'Naval Auxiliary Landing Field': 'NALF', + 'Naval Outlying Field': 'NOF', + 'Naval Station': 'NS', + 'Space Force Base': 'SFB', + 'Strategic Expeditionary Landing Field': 'SELF', +}; + +const generalSubstitutions = { + 'Airways Facilities Sector': '', + 'City of': '', + 'Drone Runway': '', + Fort: 'Ft', + 'Intl.': 'International', + Island: 'Is.', + 'National Park': '', + 'NWS Office: ': 'NWS ', + 'Public ': '', + 'Ranger Station': '', + 'Shuttle Landing Facility': 'SLF', + 'Subsea Development Platform': 'SDP', + 'U. S. ': '', +}; + +const substitutions = { ...militaryAbbreviations, ...generalSubstitutions }; + +// Extract the replacement part of substitution patterns (if it's not a "removal" substitution) +const substitutionValues = [ + ...Object.values(militaryAbbreviations), + ...new Set(Object.values(generalSubstitutions).filter((v) => v !== '')), +]; +const startOfMatchSubstitutionValuePattern = new RegExp(`^(${substitutionValues.join('|')})$`); +const wordBreakSubstitutionValuePattern = new RegExp(`\\b(${substitutionValues.join('|')})\\b`); + +// Centralized airport suffix patterns for consistency +const airportPatterns = { + // Basic facility types + facilityTypes: ['Airport', 'Airfield', 'Field', 'Jetport', 'Heliport', 'Landing Strip', 'Air Park', 'Airpark', 'Seaplane Base', 'Auxiliary Field', 'Auxiliary Airfield', 'Auxiliary Landing Field', 'Airstrip', 'Aircenter', 'Air Center'], + // Airport classifications (order matters - more specific patterns first) + classifications: ['Regional Business', 'Intercontinental', 'International', 'Regional', 'Municipal', 'Executive', 'Memorial', 'Express', 'Business', 'County', 'State', 'National'], + // Military designations + military: [...Object.values(militaryAbbreviations)], + + // Generate pattern for highway detection (Interstate, US Highway, State Highway) + get highwayPattern() { + return /^(I\d+|US\d+|[A-Z]{2}\d+)/; + }, + + // Generate pattern for military facility detection (includes both full names and abbreviations) + get militaryPattern() { + const fullMilitaryNames = Object.keys(militaryAbbreviations); + return new RegExp(`\\b(${fullMilitaryNames.join('|')}|${this.military.join('|')})\\b`, 'i'); + }, + + // Generate pattern for comprehensive suffix removal (includes classifications) + get fullSuffixPattern() { + return new RegExp(`\\s+(?:${classificationsPattern})?\\s*(?:${facilityTypesPattern}|(?:-\\s*[A-Za-z\\s]+(?:${facilityTypesPattern}))).*$|(?:\\s+|\\b)(${classificationsPattern})(?=-[A-Za-z]).*$`, 'i'); + }, + + // Generate pattern for airport type detection + get classificationDetectionPattern() { + return new RegExp(`(?:^|\\s)(${classificationsPattern})(?:\\s|$|-)`, 'i'); + }, + + get simpleCountyPattern() { + return new RegExp(`^(.+\\s+County)(?:\\s+(?:${facilityTypesPattern}))?$`, 'i'); + }, +}; + +// Pre-compute regex patterns for airport types and classifications with proper word boundaries +// Each pattern: 1) escapes special regex chars, 2) adds word boundaries, 3) joins with alternation (|) +// Both patterns use standard word boundaries since substitutions handle punctuation conversion beforehand +const facilityTypesPattern = airportPatterns.facilityTypes.map((type) => `\\b${type.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).join('|'); +const classificationsPattern = airportPatterns.classifications.map((cls) => `\\b${cls.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`).join('|'); + +// Helper function to handle "City, City-..." pattern normalization +function normalizeDuplicateCityPattern(cityName) { + // Handle "City, City-..." pattern where city name is duplicated + // Examples: "Phoenix, Phoenix-Deer Valley Municipal Airport" → "Phoenix, Deer Valley Municipal Airport" + const duplicateCityMatch = cityName.match(/^([^,]+),\s*\1-(.+)$/); + if (duplicateCityMatch) { + const cityPart = duplicateCityMatch[1].trim(); + const afterHyphen = duplicateCityMatch[2].trim(); + return `${cityPart}, ${afterHyphen}`; + } + return cityName; +} +function cleanupHyphenatedCityPattern(text, options = {}) { + if (!text || !text.includes('-') || text.includes(' - ')) return text; + + const dashParts = text.split('-'); + const firstPart = dashParts[0].trim(); + const secondPart = dashParts[1] ? dashParts[1].trim() : ''; + + // Special case: if first part is "SomeWord County", convert to "SomeWord Co" + if (options.handleCounty && firstPart.match(/\bCounty$/i)) { + return processingUtils.abbreviateCounty(firstPart); + } + + // Skip military facility names (preserve compound military base names like "Wright-Patterson AFB") + if (airportPatterns.militaryPattern.test(text)) { + return text; + } + + // Only apply this if it looks like "City-City" or "City-Geographic Area" pattern + // Skip if first part looks like a compound word or if it contains "County" + if (secondPart + && !firstPart.match(/^(Tri|Quad|Multi|New|Old|North|South|East|West|St|Saint)$/i) + && !text.match(/County|Co\./i) + && firstPart.length >= 3 && secondPart.length >= 3 + && firstPart.match(/^[A-Za-z\s]+$/) && secondPart.match(/^[A-Za-z\s]+$/)) { + return firstPart; + } + + return text; +} + +// Helper function for title casing +function toTitleCase(str) { + const lowercaseWords = new Set(['at', 'near', 'of', 'the', 'and', 'or', 'in', 'on']); + + return str.toLowerCase().split(/\s+/).map((word, index) => { + if (index === 0 || !lowercaseWords.has(word)) { + return word.charAt(0).toUpperCase() + word.slice(1); + } + return word; + }).join(' '); +} + +// Consolidated text cleaning function +function cleanCityText(cityName) { + if (!cityName) return ''; + + // State abbreviation should already be removed by extractBaseCityName + let cleaned = cityName.trim(); + + // Handle ALL CAPS entries before any substitutions + if (cleaned === cleaned.toUpperCase() && cleaned.length > 2) { + const likelyAcronym = cleaned.length <= 4 || cleaned.match(wordBreakSubstitutionValuePattern); + if (!likelyAcronym) { + cleaned = toTitleCase(cleaned); + } else { + // For things like "SCHELL AHP", title case the non-acronym parts + const parts = cleaned.split(/\s+/); + cleaned = parts.map((part) => { + if (part.match(startOfMatchSubstitutionValuePattern)) { + return part; + } + return toTitleCase(part); + }).join(' '); + } + } + + // Apply substitutions (longest first to avoid partial matches) + Object.entries(substitutions) + .sort((a, b) => b[0].length - a[0].length) + .forEach(([full, abbr]) => { + let regex; + if (full.endsWith('.')) { + // For patterns ending with period, ensure we don't match if followed by word characters + const escapedPattern = full.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + regex = new RegExp(`\\b${escapedPattern}(?!\\w)`, 'gi'); + } else { + regex = new RegExp(`\\b${full}\\b`, 'gi'); + } + cleaned = cleaned.replace(regex, abbr); + }); + + // Handle concatenated airport names (like "NEOSHOAIRPORT" -> "NEOSHO") + cleaned = processingUtils.removeConcatenatedAirport(cleaned); + + // Remove periods from the cleaned name unless it's at the end ("Co." or "Is.") + // cleaned = cleaned.replace(/\./g, ''); + + // Replace "Mount " with "Mt " (except for city names like "Mount Pleasant") + cleaned = cleaned.replace(/\bMount\s/, 'Mt '); + + // Replace "Mountain " with "Mtn " if NOT at the beginning of the string + cleaned = cleaned.replace(/(? "Starkville, George M Bryan Airport" -> Starkville + const airportCityMatch = cityName.match(new RegExp(`^([^,]+(?:${facilityTypesPattern})), ([A-Za-z\\s]+)$`)); + if (airportCityMatch) { + cityName = `${airportCityMatch[2]}, ${airportCityMatch[1]}`; + } + + let cleaned = cleanCityText(cityName); + + // Handle "at/near" patterns - find rightmost occurrence + const atNearMatch = cleaned.match(/.*\b(at|near)\s+([^,]+?)$/i); + if (atNearMatch) { + const location = atNearMatch[2].trim(); + if (!location.match(/\b(Lane|Road|Street|Highway|Route|Drive|Avenue|Blvd)\b/i) && !location.includes(' at ') && !location.includes(' near ')) { + cleaned = location; + } + } + + // Handle comma patterns + const commaParts = patternMatchers.extractCommaParts(cleaned); + if (commaParts) { + const { before: beforeComma } = commaParts; + if (beforeComma.includes('/')) { + return beforeComma.split('/')[0].trim(); + } + return processTextFragment(beforeComma); + } + + // Handle compound hyphenated names (like "Tri-County", "Quad-City") - after comma handling + if (cleaned.match(/\b(Tri|Quad)-(County|State|City)\b/i)) { + // Extract just the compound part WITHOUT abbreviating (per user preference) + const triMatch = cleaned.match(new RegExp(`^(.*?)(\\b(Tri|Quad)-(?:County|State|City))(?:\\s+Regional)?(?:\\s+(?:${facilityTypesPattern}))?.*$`, 'i')); + if (triMatch) { + const prefix = triMatch[1].trim(); + const compound = triMatch[2]; + return prefix ? `${prefix} ${compound}`.trim() : compound; + } + // For simple cases, just return the Tri-County/Tri-State/Quad-City part + const simpleMatch = cleaned.match(/^(Tri|Quad)-(?:County|State|City)/i); + if (simpleMatch) { + return simpleMatch[1]; + } + return cleaned; + } + + // Handle dash patterns BEFORE slash patterns (highway logic needs priority) + const dashParts = patternMatchers.extractDashParts(cleaned); + if (dashParts) { + const { + before: beforeDash, after: afterDash, isBeforeHighway, isAfterCounty, + } = dashParts; + + // Check for highway patterns + if (!isBeforeHighway) { + // For "City - County ..." patterns, prefer the city name + // e.g., "Pittsburgh - Allegheny County Airport" → "Pittsburgh" + // But for named facilities like "Boeing Field - King County", prefer the facility name + if (isAfterCounty) { + return beforeDash; + } + + // Only prefer after-dash for very specific cases like "Las Vegas - Henderson Executive" + // where the after-dash is clearly a more specific city location, not a regional descriptor + const afterDashMatch = afterDash.match(/^([A-Z][a-z]+)\s+(Executive|Municipal)\s+Airport$/i); + if (afterDashMatch && !afterDash.match(/County|Regional|State/i)) { + // Extract specific city name only for clearly city-specific facilities + // e.g., "Henderson Executive Airport" but NOT "West Michigan Regional Airport" + return afterDashMatch[1].trim(); + } + // Default: use before dash for most cases + return processTextFragment(beforeDash); + } + // For highway patterns, return what's after the dash + return afterDash.replace(/\s+(?:${facilityTypesPattern}).*$/i, '').trim(); + } + + // Handle hyphenated county patterns (like "Aspen-Pitkin County", "Lancaster County-Facility") + if (cleaned.includes('-') && !cleaned.includes(' - ')) { + // Check for "County-Facility" patterns (where first part contains "County") + if (cleaned.match(/^([^-]+\s+County)-/i)) { + const firstPart = cleaned.split('-')[0].trim(); + return processingUtils.abbreviateCounty(firstPart); + } + + // For "City-County" patterns (where second part contains "County"), take the first part + if (cleaned.match(/^([^-]+)-.*County/i)) { + const firstPart = cleaned.split('-')[0].trim(); + // Remove "County" from the first part only if it ends with it AND the second part also has county info + if (firstPart.match(/\s+County$/i) && cleaned.match(/^[^-]+-.*County/i)) { + return processingUtils.removeCountySuffix(firstPart) || firstPart; + } + // Process the first part to remove airport classifications like "Regional" + return processTextFragment(firstPart); + } + } + + // Handle slash patterns + const slashParts = patternMatchers.extractSlashParts(cleaned); + if (slashParts) { + const { + first: firstPart, second: secondPart, firstIsMilitary, secondIsMilitary, + } = slashParts; + + // If we have two parts, check for military facility patterns + if (secondPart) { + // If first part is military facility and second part is not, prefer second (city) + // e.g., "Craig Field / Selma" → "Selma", "Keesler Air Force Base / Biloxi" → "Biloxi" + if (firstIsMilitary && !secondIsMilitary) { + return processTextFragment(secondPart); + } + + // If second part is military facility and first part is not, prefer first (city) + // e.g., "Eastern WV Regional Airport / Shepherd Field" → "Eastern WV" + if (secondIsMilitary && !firstIsMilitary) { + return processTextFragment(firstPart); + } + } + + // Default: process the first part to remove any airport suffixes + return processTextFragment(firstPart); + } + + // Handle simple county patterns early - if it matches this pattern, keep County and stop processing + // This should only match direct county patterns like "Delta County Airport", not "City Regional Airport of County" + const simpleCountyMatch = cleaned.match(airportPatterns.simpleCountyPattern); + if (simpleCountyMatch && !cleaned.match(/\s+(Regional\s+)?Airport\s+of\s+/i)) { + const fullCountyName = simpleCountyMatch[1].trim(); + + // Use utility function for county pattern handling + return processingUtils.handleCountyPattern(fullCountyName, { preferCity: true }); + } + + // Handle county facilities with descriptive names (e.g., "Carroll County Regional Jack B Poage Field") + const countyFacilityMatch = cleaned.match(new RegExp(`^([A-Za-z\\s]+\\s+County)\\s+.*(?:${facilityTypesPattern}).*$`, 'i')); + if (countyFacilityMatch) { + const countyName = countyFacilityMatch[1].trim(); + const words = countyName.split(/\s+/); + + // Check if this looks like "City County" (e.g., "Pikeville Pike County", "Jasper Walker County") + if (words.length === 3 && words[2].toLowerCase() === 'county') { + const extractedCityName = words[0]; + const countyWord = words[1]; + + // Only apply "City County" logic if the county word is likely a proper county name + // that's different from common multi-word place names + // Examples where we DO want city: Pikeville Pike, Jasper Walker, Dallas Paulding + // Examples where we DON'T want city: Santa Fe, Palm Beach, St Clair (these are proper place names) + if (!['fe', 'beach', 'del', 'la', 'los', 'las', 'san', 'saint', 'st', 'clair', 'le', 'du'].includes(countyWord.toLowerCase())) { + return extractedCityName; + } + } + + // For true county-named facilities (like "Carroll County Regional"), keep the county + return processingUtils.abbreviateCounty(countyName); + } + + // Remove airport suffixes + const baseMatch = cleaned.match(new RegExp(`^(.+?)\\s+(?:(?:${classificationsPattern})\\s+)*(?:${facilityTypesPattern}).*$`, 'i')); + if (baseMatch) { + let result = baseMatch[1].trim(); + + // Handle "City Classification-Name" pattern by removing the classification + result = result.replace(new RegExp(`\\s+(${classificationsPattern})(?=-[A-Za-z]).*$`, 'i'), ''); + + // Apply dash cleanup for city-city patterns (with county handling) + return cleanupHyphenatedCityPattern(result, { handleCounty: true }); + } + + // Match classification at the end: "Cleveland Municipal" + const municipalMatch = cleaned.match(new RegExp(`^(.+?)\\s+(${classificationsPattern})$`, 'i')); + if (municipalMatch) { + return municipalMatch[1].trim(); + } + + // Match classification followed by additional qualifiers: "South St. Paul Municipal-Richard E. Flemi" + const municipalWithQualifierMatch = cleaned.match(new RegExp(`^(.+?)\\s+(${classificationsPattern})[-\\s]`, 'i')); + if (municipalWithQualifierMatch) { + return municipalWithQualifierMatch[1].trim(); + } + + // Clean up common patterns + cleaned = processingUtils.removeCoordinates(cleaned); + + // Handle hyphenated city-city patterns by taking the first city + // e.g., "Eveleth-Virginia" → "Eveleth", "Halifax-Northampton" → "Halifax" + // But preserve legitimate hyphenated names like multi-word cities + cleaned = cleanupHyphenatedCityPattern(cleaned); + + // Ensure no leading/trailing spaces from substitutions + cleaned = cleaned.trim(); + + return cleaned; +} + +// Extract display name with qualifier when needed +function extractDisplayNameWithQualifier(cityName, baseName, stationId = '') { + if (!cityName) return baseName || ''; + + // Remove proper names first, then state abbreviation, like in extractBaseCityName + let cleanedCityName = processingUtils.removeProperNames(cityName); + cleanedCityName = processingUtils.removeState(cleanedCityName); + + // Pre-cleaning: Handle "City, City-..." pattern where city name is duplicated + cleanedCityName = normalizeDuplicateCityPattern(cleanedCityName); + + const cleaned = cleanCityText(cleanedCityName); + + // Handle simple hyphenated patterns first (like "Milwaukee-Timmerman") + if (cleaned.includes('-') && !cleaned.includes(' - ')) { + const hyphenParts = cleaned.split('-').map((p) => p.trim()); + if (hyphenParts.length === 2 && hyphenParts[0].toLowerCase() === baseName.toLowerCase()) { + // "Milwaukee-Timmerman" with baseName "Milwaukee" → return "Timmerman" + // "Henderson-Oxford Airport" with baseName "Henderson" → return "Oxford" (remove Airport suffix) + return processTextFragment(hyphenParts[1]); + } + } + + // Handle dash patterns for qualifiers (e.g., "Pittsburgh - Allegheny County Airport" → "Allegheny Co") + const dashParts = patternMatchers.extractDashParts(cleaned); + if (dashParts) { + const { before: beforeDash, after: afterDash } = dashParts; + + // If before dash matches our base name, use the after-dash part as qualifier + if (beforeDash.toLowerCase() === baseName.toLowerCase()) { + // Process the after-dash part to get a clean qualifier + const qualifier = processTextFragment(afterDash); + return qualifier; + } + + // For military facilities, if before dash starts with base name and contains military terms, return the military name + const baseNameWithSpace = `${baseName.toLowerCase()} `; + if (beforeDash.toLowerCase().startsWith(baseNameWithSpace) && airportPatterns.militaryPattern.test(beforeDash)) { + return processTextFragment(beforeDash); + } + } + + // For slash patterns like "Detroit/Grosse Ile, Grosse Ile Airport" + const slashParts = patternMatchers.extractSlashParts(cleaned); + if (slashParts) { + const { + first: firstPart, second: secondPart, firstIsMilitary, secondIsMilitary, + } = slashParts; + + // Check for military facility patterns first + if (secondPart) { + // Pattern: "Luke Air Force Base / Phoenix" with baseName "Phoenix" → return "Luke AFB" + if (firstIsMilitary && !secondIsMilitary && secondPart.toLowerCase() === baseName.toLowerCase()) { + return processTextFragment(firstPart); + } + + // Pattern: "Dayton / Wright-Patterson Air Force Base" with baseName "Dayton" → return "Wright-Patterson AFB" + if (!firstIsMilitary && secondIsMilitary && firstPart.toLowerCase() === baseName.toLowerCase()) { + return processTextFragment(secondPart); + } + + // If this is a military facility pattern but neither matches baseName, just return the base name + if ((firstIsMilitary && !secondIsMilitary) || (secondIsMilitary && !firstIsMilitary)) { + return baseName; + } + } + + // Original logic for non-military patterns + // If the first part matches our base name, use the second part as qualifier + if (firstPart.toLowerCase() === baseName.toLowerCase() || firstPart.toLowerCase().includes(baseName.toLowerCase())) { + // Handle cases like "Detroit/Grosse Ile, Grosse Ile Airport" + if (secondPart.includes(',')) { + return processTextFragment(secondPart.split(',')[0].trim()); + } + return processTextFragment(secondPart); + } + } + + // For comma patterns like "Detroit, Willow Run Airport" + const commaParts = patternMatchers.extractCommaParts(cleaned); + if (commaParts) { + const { before: beforeComma, after: afterComma } = commaParts; + + // If before comma is just the base city name, use what's after + if (beforeComma.toLowerCase() === baseName.toLowerCase()) { + // "Detroit, Willow Run Airport" → "Willow Run" + let cleanedAfter = afterComma.replace(airportPatterns.fullSuffixPattern, '').trim(); + + // Handle multiple qualifiers separated by commas - take the first meaningful one + if (cleanedAfter.includes(',')) { + const qualifierParts = cleanedAfter.split(',').map((p) => p.trim()); + // Take the first non-empty, non-generic part + const excludePattern = new RegExp(`^(${airportPatterns.facilityTypes.concat(airportPatterns.classifications, airportPatterns.military).join('|')})$`, 'i'); + const meaningfulPart = qualifierParts.find((part) => part && !part.match(excludePattern)); + if (meaningfulPart) { + cleanedAfter = meaningfulPart; + } + } + + // For military designations that got abbreviated, combine with base name + if (cleanedAfter.match(new RegExp(`^(${airportPatterns.military.join('|')})$`, 'i'))) { + return `${baseName} ${cleanedAfter}`; + } + + // Abbreviate county names in qualifiers + if (cleanedAfter.match(/\bCounty$/i)) { + cleanedAfter = processingUtils.abbreviateCounty(cleanedAfter); + } + + return cleanedAfter; + } + + // "Cleveland, Burke Lakefront Airport" → "Cleveland Burke" or "Burke Lakefront" + // Handle qualifiers that may have descriptive words + const qualifierMatch = afterComma.match(new RegExp(`^([A-Za-z\\s]+?)(?:\\s+(?:${facilityTypesPattern}))?$`, 'i')); + if (qualifierMatch) { + const qualifier = qualifierMatch[1].trim(); + // Don't combine if qualifier is just facility types or classifications + if (!qualifier.match(new RegExp(`^(${airportPatterns.facilityTypes.concat(airportPatterns.classifications).join('|')})$`, 'i'))) { + // For single-word qualifiers, combine with base name + const qualifierWords = qualifier.split(/\s+/); + if (qualifierWords.length === 1) { + return `${baseName} ${qualifier}`; + } + // For multi-word qualifiers, return as-is if it makes sense + return qualifier; + } + } + } + + // Direct patterns like "Cleveland Municipal Airport" or extract type qualifier from anywhere in the name + const lowerCleaned = cleaned.toLowerCase(); + const lowerBaseName = baseName.toLowerCase(); + + // Check for type qualifiers in the name + const typeMatch = cleaned.match(new RegExp(`\\b(${airportPatterns.classifications.slice(2).join('|')})\\b`, 'i')); + if (typeMatch) { + return `${baseName} ${typeMatch[1]}`; + } + + if (lowerCleaned.startsWith(lowerBaseName)) { + const suffix = cleaned.substring(baseName.length).trim(); + // Check for airport type qualifiers in suffix + const suffixTypeMatch = suffix.match(new RegExp(`^(${airportPatterns.classifications.slice(2).join('|')})(?:\\s+(?:${airportPatterns.facilityTypes.slice(0, 4).join('|')}))?`, 'i')); + if (suffixTypeMatch) { + return `${baseName} ${suffixTypeMatch[1]}`; + } + } + + // Check once if this is an "at/near" pattern + const isAtNearPattern = cleaned.match(/\b(at|near)\b/i); + + // For "at/near" patterns, just use the baseName (they're handled in extractBaseCityName) + if (isAtNearPattern) { + return baseName; + } + + // For patterns like "Detroit Lakes Airport-Wething Field" → "Detroit Lakes" + const fullBaseMatch = cleaned.match(new RegExp(`^([^,-]+?)(?:\\s+(?:${facilityTypesPattern}))?$`, 'i')); + if (fullBaseMatch && fullBaseMatch[1].toLowerCase() !== baseName.toLowerCase() && fullBaseMatch[1].toLowerCase().includes(baseName.toLowerCase())) { + return fullBaseMatch[1].trim(); + } + + // For slash patterns like "Cleveland / Cuyahoga" + if (cleaned.includes('/')) { + const parts = cleaned.split('/').map((p) => p.trim()); + if (parts[0].toLowerCase() === baseName.toLowerCase() && parts[1]) { + return parts[1]; + } + } + + // Default: just return the base name, but check if we need a fallback qualifier + // If the extracted name would be the same as the base name, we need to differentiate + if (cleaned.toLowerCase().trim() === baseName.toLowerCase()) { + // For stations without clear airport type information, use the 3-letter ICAO code as fallback + // This handles cases like KANJ "Sault Ste. Marie" vs KCIU "Sault Ste Marie, Chippewa County International" + // Extract the 3-letter code from station IDs like KCIU -> CIU, KANJ -> ANJ + if (stationId && stationId.length === 4 && stationId.startsWith('K')) { + const icaoCode = stationId.substring(1); // Remove the 'K' prefix + return icaoCode; + } + // Final fallback + return `${baseName} ${stationId}`; + } + + return baseName; +} + +const patternMatchers = { + // Extract parts from dash patterns with validation + extractDashParts: (text) => { + if (!text.includes(' - ')) return null; + const parts = text.split(' - '); + const beforePart = parts[0].trim(); + const afterPart = parts[1].trim(); + return { + before: beforePart, + after: afterPart, + isBeforeHighway: airportPatterns.highwayPattern.test(beforePart), + isAfterCounty: /^[A-Za-z\s]+\s+County\s+/i.test(afterPart), + }; + }, + + // Extract parts from slash patterns with military detection + extractSlashParts: (text) => { + if (!text.includes('/')) return null; + const parts = text.split('/').map((p) => p.trim()); + const firstPart = parts[0]; + const secondPart = parts[1] || ''; + return { + first: firstPart, + second: secondPart, + firstIsMilitary: airportPatterns.militaryPattern.test(firstPart), + secondIsMilitary: secondPart ? airportPatterns.militaryPattern.test(secondPart) : false, + }; + }, + + // Extract parts from comma patterns + extractCommaParts: (text) => { + if (!text.includes(',')) return null; + const commaIndex = text.indexOf(','); + return { + before: text.substring(0, commaIndex).trim(), + after: text.substring(commaIndex + 1).trim(), + }; + }, +}; + +// Utility functions for common processing patterns +const processingUtils = { + // Remove proper names from city names to improve extraction accuracy + removeProperNames: (cityName) => { + const namesToRemovePattern = new RegExp(`\\b(${namesToRemove.join('|')})([ -]+|$)`, 'g'); + return cityName.replace(namesToRemovePattern, ''); + }, + + // Remove state abbreviations (or Idaho) at the end of city names or before a comma ("Lago Vista, TX") + removeState: (text) => text.replace(/,?\s+(?:(?:[A-Z]{2}|[A-Z][a-z])\.?|Idaho)(,|$)/, '$1').trim(), + + // Standardize county name abbreviation + abbreviateCounty: (countyName) => countyName.replace(/\bCounty\b/g, 'Co.'), + + // Remove concatenated "AIRPORT" suffix (like "NEOSHOAIRPORT" -> "NEOSHO") + removeConcatenatedAirport: (text) => text.replace(/([A-Za-z])AIRPORT$/i, '$1'), + + // Remove "International" and everything after it + removeInternationalSuffix: (text) => text.replace(/\s*International.*$/i, '').trim(), + + // Remove "County" suffix only (not the word "County" in the middle) + removeCountySuffix: (text) => text.replace(/\s+County$/i, '').trim(), + + // Remove geographic coordinate patterns + removeCoordinates: (text) => text + .replace(/\s+\d+[NSEW]{1,2}$/, '') // Remove patterns like "12N", "34SW" + .replace(/\s+\d+[A-Z]?$/, ''), // Remove patterns like "15", "8A" + + // Remove military abbreviations when not needed for differentiation + removeMilitaryAbbreviations: (text) => { + const endPattern = new RegExp(`\\s+(${airportPatterns.military.join('|')})$`, 'g'); + return text.replace(endPattern, '').trim(); + }, + + // Process county patterns and return appropriate city/county name + handleCountyPattern: (text, options = {}) => { + const { preferCity = false } = options; + + // Check for "City CountyName County" patterns + const words = text.split(/\s+/); + if (words.length === 3 && words[2].toLowerCase() === 'county') { + const firstWord = words[0].toLowerCase(); + + // If first word is very short or looks like an article/prefix, likely a multi-word city + if (firstWord.length <= 3 || ['hot', 'van', 'st', 'fort', 'new', 'old', 'big', 'du', 'lac'].includes(firstWord)) { + return processingUtils.abbreviateCounty(text); // Keep the full "Multi Word County" + } + + if (preferCity) { + return words[0]; // Just return the city name for "City County County" + } + } + + // Check for multi-word city + county patterns (e.g., "New Castle Henry County") + if (words.length === 4 && words[3].toLowerCase() === 'county') { + if (preferCity) { + return `${words[0]} ${words[1]}`; + } + } + + // Default: abbreviate county + return processingUtils.abbreviateCounty(text); + }, + + // Remove periods from the cleaned name unless it's at the end ("Co." or "Is.") and any leading "The"'s + finalCleanup: (text) => text + .replace(/\.(?!$)/g, '') + .replace(/^The\s+(?!Dalles)/i, ''), +}; + +// Main entry point +function processAllStations(stationsObject) { + // Process all stations + const stationsByStateAndCity = {}; + const displayNames = {}; + + // Group all stations by city + Object.entries(stationsObject).forEach(([stationId, station]) => { + if (!station || !station.city || !station.state) return; + + const { state } = station; + const baseName = extractBaseCityName(station.city, stationId); + + if (!baseName) return; + + // For grouping purposes, normalize military base names to their city name + // This ensures "Little Rock" and "Little Rock AFB" are grouped together + const groupingBaseName = processingUtils.removeMilitaryAbbreviations(baseName); + + const normalizedBase = groupingBaseName.trim().toLowerCase(); + const groupKey = `${state}:${normalizedBase}`; + + if (!stationsByStateAndCity[groupKey]) { + stationsByStateAndCity[groupKey] = { + state, + baseName: normalizedBase, + originalBaseName: baseName, + stations: [], + }; + } + + stationsByStateAndCity[groupKey].stations.push({ + ...station, + stationId, + type: getAirportType(station.city, stationId), + priority: getAirportPriority(getAirportType(station.city, stationId)), + }); + }); + + // Process each city group using priority-based conflict resolution + Object.values(stationsByStateAndCity).forEach((group) => { + const cityStations = group.stations; + + if (cityStations.length === 1) { + // Only station for this city - use simple name without military abbreviations + const cleanedName = processingUtils.removeMilitaryAbbreviations(group.originalBaseName); + displayNames[cityStations[0].stationId] = cleanedName; + } else { + // Multiple stations - use priority to assign names + const sortedStations = [...cityStations].sort((a, b) => a.priority - b.priority); + + // Give the highest priority station the simple base name + // Use the clean base name from the highest priority station to preserve original capitalization + const primaryStation = sortedStations[0]; + const primaryBaseName = extractBaseCityName(primaryStation.city, primaryStation.stationId); + const cleanPrimaryBaseName = processingUtils.removeMilitaryAbbreviations(primaryBaseName); + + // Highest priority station gets the simple name + displayNames[primaryStation.stationId] = cleanPrimaryBaseName; + + // All other stations get qualifiers + sortedStations.slice(1).forEach((station) => { + displayNames[station.stationId] = extractDisplayNameWithQualifier( + station.city, + cleanPrimaryBaseName, + station.stationId, + ); + }); + } + }); + + return displayNames; +} + +// Priority-based deduplication phase +function resolveDuplicatesByPriority(displayNames, stationsObject) { + // Group stations by state and cleaned name to find duplicates + const duplicateGroups = {}; + + Object.entries(displayNames).forEach(([stationId, cleanedName]) => { + const station = stationsObject[stationId]; + if (!station) return; + + const key = `${station.state}:${cleanedName.toLowerCase()}`; + + if (!duplicateGroups[key]) { + duplicateGroups[key] = []; + } + + duplicateGroups[key].push({ + stationId, + station, + cleanedName, + type: getAirportType(station.city, stationId), + priority: getAirportPriority(getAirportType(station.city, stationId)), + }); + }); + + // Process groups with duplicates + Object.values(duplicateGroups).forEach((group) => { + if (group.length <= 1) return; // Skip non-duplicates + + // Sort by priority (lower number = higher priority) + const sortedGroup = [...group].sort((a, b) => a.priority - b.priority); + + // Check if we can resolve this conflict using priorities + const priorities = sortedGroup.map((item) => item.priority); + const uniquePriorities = [...new Set(priorities)]; + + // Helper function to assign qualifiers to a group of stations + const assignQualifiers = (stations, baseNameSource) => { + stations.forEach((item) => { + const qualifier = extractDisplayNameWithQualifier(item.station.city, baseNameSource.cleanedName, item.stationId); + if (qualifier.toLowerCase() === baseNameSource.cleanedName.toLowerCase()) { + const fallbackName = item.stationId.startsWith('K') ? item.stationId.substring(1) : item.stationId; + displayNames[item.stationId] = fallbackName; + } else { + displayNames[item.stationId] = qualifier; + } + }); + }; + + if (uniquePriorities.length > 1) { + // We have different priorities, try to use them to resolve + + // Check if the highest priority station has a very descriptive original name that should be preserved + const primaryStation = sortedGroup[0]; + const primaryOriginal = primaryStation.station.city; + const hasDescriptiveName = primaryOriginal.includes(','); + + if (hasDescriptiveName) { + // Give the descriptive name to the primary station + const descriptiveName = extractDisplayNameWithQualifier(primaryOriginal, primaryStation.cleanedName, primaryStation.stationId); + if (descriptiveName !== primaryStation.cleanedName) { + displayNames[primaryStation.stationId] = descriptiveName; + + // Give the simple name to the next highest priority station + if (sortedGroup.length > 1) { + displayNames[sortedGroup[1].stationId] = sortedGroup[0].cleanedName; + + // All remaining stations get qualifiers + assignQualifiers(sortedGroup.slice(2), sortedGroup[0]); + } + } else { + // Fallback to normal logic if descriptive name extraction didn't work + displayNames[primaryStation.stationId] = primaryStation.cleanedName; + + // Give qualifiers to all other stations + assignQualifiers(sortedGroup.slice(1), sortedGroup[0]); + } + } else { + // Normal logic: Give the simple name to the highest priority station + displayNames[primaryStation.stationId] = primaryStation.cleanedName; + + // Give qualifiers to all other stations + assignQualifiers(sortedGroup.slice(1), sortedGroup[0]); + } + } else if (group.length > 1) { + // All have same priority - use secondary criteria for tie-breaking + // Prefer weather stations (P-prefix), then alphabetical by station ID + const tieBreakingSorted = [...sortedGroup].sort((a, b) => { + // Weather stations (P-prefix) win ties + const aIsWeatherStation = a.stationId.startsWith('P'); + const bIsWeatherStation = b.stationId.startsWith('P'); + + if (aIsWeatherStation && !bIsWeatherStation) return -1; + if (!aIsWeatherStation && bIsWeatherStation) return 1; + + // If both are same type, use alphabetical order + return a.stationId.localeCompare(b.stationId); + }); + + // Give the simple name to the tie-breaker winner + const primaryStation = tieBreakingSorted[0]; + displayNames[primaryStation.stationId] = primaryStation.cleanedName; + + // Give qualifiers to all other stations + assignQualifiers(tieBreakingSorted.slice(1), primaryStation); + } + }); + + return displayNames; +} + +function compactStringifyToArray(arr) { + const entries = arr.map((value, _index) => { + const compactValue = JSON.stringify(value); + return ` ${compactValue}`; + }); + + return `[\n${entries.join(',\n')}\n]`; +} + +function compactStringifyToObject(data) { + const obj = {}; + data.forEach((item) => { + obj[item.id] = item; + }); + + const entries = Object.entries(obj).map(([key, value]) => { + const compactValue = JSON.stringify(value); + return ` "${key}": ${compactValue}`; + }); + + return `{\n${entries.join(',\n')}\n}`; +} + +/* +Command line arguments for filtering output + +Before making changes to this file, created a baseline: + node station-name-processor.mjs --diff > baseline.json +and then after any change, run: + diff baseline.json <(node station-name-processor.mjs --diff) +to easily confirm the change (and also make sure it didn't have any unexpected impact!) + +jq is also very useful, you can do queries like this: + node ./datagenerators/stations-postprocessor.mjs | jq -c '.[] | select(.city | test("Phoenix")) | {state, city, name, priority}' +or to look for names over 20 characters: + jq -c '.[] | select(.potentialIssues | index("reallyLong")) | {state, city, name, priority}' +or to see places where this algorithm differs from the original algorithm: + jq -c '.[] | select(.name != .simple) | {state, city, simple, name}' +or where the fallback to the ICAO airport code occurred: + jq -c '.[] | select(.name | test("^[A-Z]{3}$")) | {state, city, simple, name}' +*/ + +const diffMode = process.argv.includes('--diff'); +const onlyProblems = process.argv.includes('--only-problems'); +const noProblems = process.argv.includes('--no-problems'); +const onlyDuplicates = process.argv.includes('--only-dupes'); +const noPriority = process.argv.includes('--no-priority'); +const noSimple = process.argv.includes('--no-simple'); +const noCoordinates = process.argv.includes('--no-coords'); +const writeFile = process.argv.includes('--write'); + +// Process ALL stations at once to get the display name map +let displayNameMap = processAllStations(stationInfo); + +// Apply priority-based deduplication +displayNameMap = resolveDuplicatesByPriority(displayNameMap, stationInfo); + +const results = []; + +// Now iterate through stations and use the pre-computed display names +const stations = Object.values(stationInfo); +stations.forEach((station) => { + const originalName = station.city; + const processedName = processingUtils.finalCleanup(displayNameMap[station.id]); // Look up by station ID + + // Get airport type and priority for this station + const airportType = getAirportType(originalName, station.id); // Pass station ID for enhanced detection + const priority = getAirportPriority(airportType); + + const potentialIssues = []; + // Check if the processed name contains punctuation (a period at the end is OK) + if (/[,;!?/:.]/.test(processedName) && !processedName.endsWith('.')) { + potentialIssues.push('punctuation'); + } + if (processedName.length > 12) { + potentialIssues.push('long'); + } + if (processedName.length > 20) { + potentialIssues.push('reallyLong'); + } + // check if it contains any digits + if (/\d/.test(processedName)) { + potentialIssues.push('digits'); + } + + results.push({ + id: station.id, + lat: station.lat, + lon: station.lon, + state: station.state, + location: originalName, // original full location name + city: processedName, // processed city name for display + simple: originalName.match(/[^,/;\\-]*/)[0].substr(0, 12).trim(), + type: airportType, + priority, + potentialIssues, + }); +}); + +// Check for duplicates by state +const cleanedMapByState = new Map(); + +results.forEach((result) => { + const { state } = result; + if (!cleanedMapByState.has(state)) { + cleanedMapByState.set(state, new Map()); + } + const stateMap = cleanedMapByState.get(state); + if (stateMap.has(result.city)) { + stateMap.get(result.city).push(result); + } else { + stateMap.set(result.city, [result]); + } +}); + +cleanedMapByState.forEach((stateMap, _state) => { + stateMap.forEach((originals, _cleaned) => { + if (originals.length > 1) { + originals.forEach((original) => { + if (!original.potentialIssues.includes('duplicate')) { + original.potentialIssues.push('duplicate'); + } + }); + } + }); +}); + +// Filter results if requested +let finalResults = results; +if (onlyProblems) { + finalResults = results.filter((r) => r.potentialIssues.length > 0); +} +if (onlyDuplicates) { + finalResults = finalResults.filter((r) => r.potentialIssues.includes('duplicate')); +} + +const outputResult = finalResults.map((result) => { + let outputItem = result; + + // Don't include lat or long in diff mode + if (noCoordinates || diffMode) { + const { + lat: _lat, lon: _lon, ...resultWithoutLocation + } = result; + outputItem = resultWithoutLocation; + } + + // Don't include potentialIssues when --no-problems is specified + if (noProblems || diffMode) { + const { potentialIssues: _potentialIssues, ...resultWithoutIssues } = outputItem; + outputItem = resultWithoutIssues; + } + + // Remove type and priority if --no-priority is specified + if (noPriority || diffMode) { + const { type: _type, priority: _priority, ...resultWithoutPriority } = outputItem; + outputItem = resultWithoutPriority; + } + + // remove simple field if --no-simple is specified + if (noSimple || diffMode) { + const { simple: _simple, ...resultWithoutSimple } = outputItem; + outputItem = resultWithoutSimple; + } + + return outputItem; +}); + +if (writeFile) { + const fileResults = results.map(({ + simple: _simple, type: _type, potentialIssues: _potentialIssues, ...rest + }) => rest); + + writeFileSync('./datagenerators/output/stations.json', compactStringifyToObject(fileResults)); + console.log(`Wrote ${fileResults.length} processed stations to datagenerators/output/stations.json`); +} else { + console.log(compactStringifyToArray(outputResult)); +} diff --git a/datagenerators/stations.mjs b/datagenerators/stations.mjs index cb1bc76..9ed1678 100644 --- a/datagenerators/stations.mjs +++ b/datagenerators/stations.mjs @@ -59,7 +59,7 @@ for (let i = 0; i < chunkStates.length; i += 1) { next = stations?.pagination?.next; round += 1; // write the output - writeFileSync('./datagenerators/output/stations.json', JSON.stringify(output, null, 2)); + writeFileSync('./datagenerators/output/stations-raw.json', JSON.stringify(output, null, 2)); } while (next && stations.features.length > 0); console.log(`Complete: ${state}`); diff --git a/eslint.config.mjs b/eslint.config.mjs index aeeaba8..8e021c5 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -90,6 +90,14 @@ export default [{ allowSamePrecedence: true, }, ], + 'no-unused-vars': [ + 'error', + { + argsIgnorePattern: '^_', + varsIgnorePattern: '^_', + caughtErrorsIgnorePattern: '^_', + }, + ], 'import/extensions': [ 'error', { @@ -97,6 +105,21 @@ export default [{ json: 'always', }, ], + 'import/no-extraneous-dependencies': [ + 'error', + { + devDependencies: [ + 'eslint.config.*', + '**/*.config.*', + '**/*.test.*', + '**/*.spec.*', + 'gulpfile.*', + 'tests/**/*', + 'gulp/**/*', + 'datagenerators/**/*', + ], + }, + ], }, ignorePatterns: [ '*.min.js', diff --git a/gulp/publish-frontend.mjs b/gulp/publish-frontend.mjs index 024dc51..f2d3f30 100644 --- a/gulp/publish-frontend.mjs +++ b/gulp/publish-frontend.mjs @@ -26,11 +26,7 @@ const cloudfront = new CloudFrontClient({ region: 'us-east-1' }); const RESOURCES_PATH = './dist/resources'; -const jsSourcesData = [ - 'server/scripts/data/travelcities.js', - 'server/scripts/data/regionalcities.js', - 'server/scripts/data/stations.js', -]; +// Data is now served as JSON files to avoid redundancy const webpackOptions = { mode: 'production', @@ -56,17 +52,21 @@ const webpackOptions = { }, }; -const compressJsData = () => src(jsSourcesData) - .pipe(concat('data.min.js')) - .pipe(terser()) - .pipe(dest(RESOURCES_PATH)); - const jsVendorSources = [ 'server/scripts/vendor/auto/nosleep.js', 'server/scripts/vendor/auto/swiped-events.js', 'server/scripts/vendor/auto/suncalc.js', ]; +// Copy metar-taf-parser separately since it's an ES module with locale dependencies +const metarVendorSources = [ + 'server/scripts/vendor/auto/metar-taf-parser.mjs', + 'server/scripts/vendor/auto/locale/en.js', +]; + +const copyMetarVendor = () => src(metarVendorSources, { base: 'server/scripts/vendor/auto' }) + .pipe(dest(`${RESOURCES_PATH}/vendor/auto`)); + const compressJsVendor = () => src(jsVendorSources) .pipe(concat('vendor.min.js')) .pipe(terser()) @@ -114,8 +114,10 @@ const compressHtml = async () => { return src(htmlSources) .pipe(ejs({ production: version, + serverAvailable: false, version, OVERRIDES, + query: {}, })) .pipe(rename({ extname: '.html' })) .pipe(htmlmin({ collapseWhitespace: true })) @@ -130,6 +132,13 @@ const otherFiles = [ const copyOtherFiles = () => src(otherFiles, { base: 'server/', encoding: false }) .pipe(dest('./dist')); +// Copy JSON data files for static hosting +const copyDataFiles = () => src([ + 'datagenerators/output/travelcities.json', + 'datagenerators/output/regionalcities.json', + 'datagenerators/output/stations.json', +]).pipe(dest('./dist/data')); + const s3 = s3Upload({ useIAM: true, }, { @@ -201,7 +210,7 @@ const buildPlaylist = async () => { return file('playlist.json', JSON.stringify(playlist)).pipe(dest('./dist')); }; -const buildDist = series(clean, parallel(buildJs, compressJsData, compressJsVendor, copyCss, compressHtml, copyOtherFiles, copyImageSources, buildPlaylist)); +const buildDist = series(clean, parallel(buildJs, compressJsVendor, copyMetarVendor, copyCss, compressHtml, copyOtherFiles, copyDataFiles, copyImageSources, buildPlaylist)); // upload_images could be in parallel with upload, but _images logs a lot and has little changes // by running upload last the majority of the changes will be at the bottom of the log for easy viewing diff --git a/gulp/update-vendor.mjs b/gulp/update-vendor.mjs index 18b952e..550ff21 100644 --- a/gulp/update-vendor.mjs +++ b/gulp/update-vendor.mjs @@ -13,6 +13,12 @@ const vendorFiles = [ './node_modules/swiped-events/src/swiped-events.js', ]; +// Special handling for metar-taf-parser - only copy main file and English locale +const metarFiles = [ + './node_modules/metar-taf-parser/metar-taf-parser.js', + './node_modules/metar-taf-parser/locale/en.js', +]; + const copy = () => src(vendorFiles) .pipe(rename((path) => { path.dirname = path.dirname.toLowerCase(); @@ -22,6 +28,14 @@ const copy = () => src(vendorFiles) })) .pipe(dest('./server/scripts/vendor/auto')); -const updateVendor = series(clean, copy); +const copyMetar = () => src(metarFiles, { base: './node_modules/metar-taf-parser' }) + .pipe(rename((path) => { + path.basename = path.basename.toLowerCase(); + path.extname = path.extname.toLowerCase(); + if (path.basename === 'metar-taf-parser') path.extname = '.mjs'; + })) + .pipe(dest('./server/scripts/vendor/auto')); + +const updateVendor = series(clean, copy, copyMetar); export default updateVendor; diff --git a/index.mjs b/index.mjs index 471134a..7d487ed 100644 --- a/index.mjs +++ b/index.mjs @@ -1,12 +1,27 @@ import 'dotenv/config'; import express from 'express'; import fs from 'fs'; +import { readFile } from 'fs/promises'; +import { + weatherProxy, radarProxy, outlookProxy, mesonetProxy, forecastProxy, +} from './proxy/handlers.mjs'; import playlist from './src/playlist.mjs'; import OVERRIDES from './src/overrides.mjs'; +import cache from './proxy/cache.mjs'; + +const travelCities = JSON.parse(await readFile('./datagenerators/output/travelcities.json')); +const regionalCities = JSON.parse(await readFile('./datagenerators/output/regionalcities.json')); +const stationInfo = JSON.parse(await readFile('./datagenerators/output/stations.json')); const app = express(); const port = process.env.WS4KP_PORT ?? 8080; +// Set X-Weatherstar header globally for playlist fallback detection +app.use((req, res, next) => { + res.setHeader('X-Weatherstar', 'true'); + next(); +}); + // template engine app.set('view engine', 'ejs'); @@ -36,6 +51,16 @@ const hasQsVars = Object.entries(qsVars).length > 0; // turn the environment query string into search params const defaultSearchParams = (new URLSearchParams(qsVars)).toString(); +const renderIndex = (req, res, production = false) => { + res.render('index', { + production, + serverAvailable: !process.env?.STATIC, // Disable caching proxy server in static mode + version, + OVERRIDES, + query: req.query, + }); +}; + const index = (req, res) => { // test for no query string in request and if environment query string values were provided if (hasQsVars && Object.keys(req.query).length === 0) { @@ -45,12 +70,8 @@ const index = (req, res) => { res.redirect(307, url.toString()); return; } - // return the standard page - res.render('index', { - production: false, - version, - OVERRIDES, - }); + // return the EJS template page in development mode (serve files from server directory directly) + renderIndex(req, res, false); }; const geoip = (req, res) => { @@ -69,21 +90,85 @@ const geoip = (req, res) => { res.json({}); }; -// debugging +// Configure static asset caching with proper ETags and cache validation +const staticOptions = { + etag: true, // Enable ETag generation + lastModified: true, // Enable Last-Modified headers + setHeaders: (res, path, stat) => { + // Generate ETag based on file modification time and size for better cache validation + const etag = `"${stat.mtime.getTime().toString(16)}-${stat.size.toString(16)}"`; + res.setHeader('ETag', etag); + + if (path.match(/\.(png|jpg|jpeg|gif|webp|ico|woff|woff2|ttf|eot)$/i)) { + // Images and fonts - cache for 1 year (immutable content) + res.setHeader('Cache-Control', 'public, max-age=31536000, immutable'); + } else if (path.match(/\.(css|js|mjs)$/i)) { + // Scripts and styles - use cache validation instead of no-cache + // This allows browsers to use cached version if ETag matches (304 response) + res.setHeader('Cache-Control', 'public, max-age=0, must-revalidate'); + } else { + // Other files - cache for 1 hour with validation + res.setHeader('Cache-Control', 'public, max-age=3600, must-revalidate'); + } + }, +}; + +// Weather.gov API proxy (catch-all for any Weather.gov API endpoint) +// Skip setting up routes for the caching proxy server in static mode +if (!process.env?.STATIC) { + app.use('/api/', weatherProxy); + + // Cache management DELETE endpoint to allow "uncaching" specific URLs + app.delete(/^\/cache\/.*/, (req, res) => { + const path = req.url.replace('/cache', ''); + const cleared = cache.clearEntry(path); + res.json({ cleared, path }); + }); + + // specific proxies for other services + app.use('/radar/', radarProxy); + app.use('/spc/', outlookProxy); + app.use('/mesonet/', mesonetProxy); + app.use('/forecast/', forecastProxy); + + // Playlist route is available in server mode (not in static mode) + app.get('/playlist.json', playlist); +} + +// Data endpoints - serve JSON data with long-term caching +const dataEndpoints = { + travelcities: travelCities, + regionalcities: regionalCities, + stations: stationInfo, +}; + +Object.entries(dataEndpoints).forEach(([name, data]) => { + app.get(`/data/${name}.json`, (req, res) => { + res.set({ + 'Cache-Control': 'public, max-age=31536000, immutable', + 'Content-Type': 'application/json', + }); + res.json(data); + }); +}); + if (process.env?.DIST === '1') { - // distribution - app.use('/scripts', express.static('./server/scripts')); + // Production ("distribution") mode uses pre-baked files in the dist directory + // 'npm run build' and then 'DIST=1 npm start' + app.use('/scripts', express.static('./server/scripts', staticOptions)); app.use('/geoip', geoip); - app.use('/', express.static('./dist')); + + // render the EJS template in production mode (serve compressed files from dist directory) + app.get('/', (req, res) => { renderIndex(req, res, true); }); + + app.use('/', express.static('./dist', staticOptions)); } else { - // debugging + // Development mode serves files from the server directory: 'npm start' app.get('/index.html', index); app.use('/geoip', geoip); app.use('/resources', express.static('./server/scripts/modules')); app.get('/', index); - app.get('*name', express.static('./server')); - // cors pass-thru to api.weather.gov - app.get('/playlist.json', playlist); + app.get('*name', express.static('./server', staticOptions)); } const server = app.listen(port, () => { @@ -94,6 +179,7 @@ const server = app.listen(port, () => { const gracefulShutdown = () => { server.close(() => { console.log('Server closed'); + process.exit(0); }); }; diff --git a/package-lock.json b/package-lock.json index fab77e6..cfadda2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,7 +11,8 @@ "dependencies": { "dotenv": "^17.0.1", "ejs": "^3.1.5", - "express": "^5.1.0" + "express": "^5.1.0", + "metar-taf-parser": "^6.1.2" }, "devDependencies": { "@aws-sdk/client-cloudfront": "^3.609.0", @@ -7272,6 +7273,12 @@ "node": ">= 8" } }, + "node_modules/metar-taf-parser": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/metar-taf-parser/-/metar-taf-parser-6.1.2.tgz", + "integrity": "sha512-NwsIQAlojiHhaGsF9tW/LxEEqAADTj4xy6B4RQiyaBtw9+IInOVMJwi9378iRHg6dGB+WlKRALRiX/vLu9fZjA==", + "license": "MIT" + }, "node_modules/micromatch": { "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", diff --git a/package.json b/package.json index 98929d1..6099a11 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,15 @@ "main": "index.mjs", "type": "module", "scripts": { + "start": "node index.mjs", + "stop": "pkill -f 'node index.mjs' || echo 'No process found'", "test": "echo \"Error: no test specified\" && exit 1", "build:css": "sass --style=compressed ./server/styles/scss/main.scss ./server/styles/main.css", "build": "gulp buildDist", - "lint": "eslint ./server/scripts/**/*.mjs", - "lint:fix": "eslint --fix ./server/scripts/**/*.mjs" + "lint": "eslint ./server/scripts/**/*.mjs ./proxy/**/*.mjs ./src/**/*.mjs *.mjs", + "lint:fix": "eslint --fix ./server/scripts/**/*.mjs ./proxy/**/*.mjs ./src/**/*.mjs *.mjs", + "lintall": "eslint ./server/scripts/**/*.mjs ./proxy/**/*.mjs ./src/**/*.mjs *.mjs ./datagenerators/**/*.mjs ./gulp/**/*.mjs ./tests/**/*.mjs", + "lintall:fix": "eslint --fix ./server/scripts/**/*.mjs ./proxy/**/*.mjs ./src/**/*.mjs *.mjs ./datagenerators/**/*.mjs ./gulp/**/*.mjs ./tests/**/*.mjs" }, "repository": { "type": "git", @@ -51,6 +55,7 @@ "dependencies": { "dotenv": "^17.0.1", "ejs": "^3.1.5", - "express": "^5.1.0" + "express": "^5.1.0", + "metar-taf-parser": "^6.1.2" } } diff --git a/proxy/cache.mjs b/proxy/cache.mjs new file mode 100644 index 0000000..8786645 --- /dev/null +++ b/proxy/cache.mjs @@ -0,0 +1,502 @@ +/** + * HTTP cache implementation for API proxy that respects cache-control headers + * (without external dependencies) + * + * Features: + * - Respects HTTP cache-control headers (s-maxage, max-age) + * - Heuristic caching based on Last-Modified headers when no explicit cache directives exist + * - Conditional requests using ETags and If-Modified-Since headers to validate stale content + * - In-flight request deduplication to prevent multiple simultaneous requests for the same resource + * - Comprehensive logging with cache hit/miss statistics and timing information + * - Timeout handling and error recovery mechanisms + * + * The cache uses a three-state system: + * - 'fresh': Content is within its TTL and served immediately + * - 'stale': Content has expired but can be revalidated with conditional requests (304 Not Modified) + * - 'miss': No cached content exists + * + * @class HttpCache + */ + +import https from 'https'; + +// Default timeout for upstream requests (matches client-side default) +const DEFAULT_REQUEST_TIMEOUT = 15000; + +class HttpCache { + constructor() { + this.cache = new Map(); + this.inFlight = new Map(); + this.cleanupInterval = null; + this.startCleanup(); + } + + // Parse cache-control header to extract s-maxage or max-age + static parseCacheControl(cacheControlHeader) { + if (!cacheControlHeader) return 0; + + // Look for s-maxage first (preferred for proxy caches), then max-age + const sMaxAgeMatch = cacheControlHeader.match(/s-maxage=(\d+)/i); + if (sMaxAgeMatch) { + return parseInt(sMaxAgeMatch[1], 10); + } + + const maxAgeMatch = cacheControlHeader.match(/max-age=(\d+)/i); + if (maxAgeMatch) { + return parseInt(maxAgeMatch[1], 10); + } + + return 0; // No cache if no cache directives found + } + + // Helper method to set filtered headers and our cache policy + static setFilteredHeaders(res, headers) { + // Strip cache-related headers and pass through others + Object.entries(headers || {}).forEach(([key, value]) => { + const lowerKey = key.toLowerCase(); + // Skip cache-related headers that should be controlled by our proxy + if (!['cache-control', 'expires', 'etag', 'last-modified'].includes(lowerKey)) { + res.header(lowerKey, value); + } + }); + + // Set our own cache policy - short cache to ensure browser checks back with our server + res.header('cache-control', 'public, max-age=30'); + } + + // Generate cache key from request + static generateKey(req) { + const path = req.path || req.url || '/'; + const url = req.url || req.path || '/'; + + // Since this cache is intended only by the frontend, we can use a simple URL-based key + return `${path}${url.includes('?') ? url.substring(url.indexOf('?')) : ''}`; + } + + // High-level method to handle caching for HTTP proxies + async handleRequest(req, res, upstreamUrl, options = {}) { + // Check cache status + const cacheResult = this.getCachedRequest(req); + + if (cacheResult.status === 'fresh') { + const cached = cacheResult.data; + res.status(cached.statusCode); + HttpCache.setFilteredHeaders(res, cached.headers); + res.send(cached.data); + return true; // Indicates cache hit + } + // For 'miss' or 'stale', proceed to upstream request + + // Generate cache key for in-flight tracking + const cacheKey = HttpCache.generateKey(req); + + // Build the full URL + const queryParams = Object.keys(req.query || {}).reduce((acc, key) => { + if (options.skipParams && options.skipParams.includes(key)) return acc; + acc[key] = req.query[key]; + return acc; + }, {}); + const queryString = new URLSearchParams(queryParams).toString(); + const fullUrl = `${upstreamUrl}${req.path}${queryString ? `?${queryString}` : ''}`; + + // Check if there's already a request in flight for this resource + if (this.inFlight.has(cacheKey)) { + console.log(`🛫 Wait | ${fullUrl} (request already in flight)`); + + // Track when we start waiting for latency measurement + const waitStartTime = Date.now(); + + // Wait for the in-flight request to complete + try { + await this.inFlight.get(cacheKey); + + // After waiting, try cache again (should be populated now if the request was successful) + const key = HttpCache.generateKey(req); + const cached = this.cache.get(key); + + if (cached && Date.now() <= cached.expiry) { + const waitLatency = Date.now() - waitStartTime; + + // Log cache hit with wait latency + const age = Math.round((Date.now() - cached.timestamp) / 1000); + const remainingTTL = Math.round((cached.expiry - Date.now()) / 1000); + const url = cached.url || `${upstreamUrl}${req.path}`; + console.log(`🛬 Continue | ${url} (age: ${age}s, remaining: ${remainingTTL}s, waited: ${waitLatency}ms)`); + + res.status(cached.statusCode); + HttpCache.setFilteredHeaders(res, cached.headers); + res.send(cached.data); + return true; // Served from cache after waiting + } + + // Fallthrough to make request if cache miss (shouldn't happen but safety net) + console.warn(`⚠️ Redo | Cache miss after waiting for in-flight request: ${fullUrl}`); + } catch (_error) { + // If the in-flight request failed, we'll make our own request + console.warn(`⚠️ Redo | In-flight request failed, making new request: ${fullUrl}`); + } + } + + // Create promise for this request + const requestPromise = this.makeUpstreamRequest(req, res, fullUrl, options, cacheResult); + + // Store a wrapped promise that doesn't reject for waiters - they just need to know when it's done + + const inflightPromise = requestPromise.catch(() => null); + this.inFlight.set(cacheKey, inflightPromise); + + try { + // Send the request to the upstream service + const result = await requestPromise; + return result; + } catch (error) { + // All errors are handled directly by makeUpstreamRequest so this is a safety net + console.error(`💥 Error | Unhandled error in handleRequest: ${error.message}`); + return false; + } finally { + // Always clean up the in-flight tracking + this.inFlight.delete(cacheKey); + } + } + + // Make the upstream request, handling caching and conditional requests + async makeUpstreamRequest(req, res, fullUrl, options = {}, cacheResult = null) { + return new Promise((resolve) => { + const headers = { + 'user-agent': options.userAgent || '(WeatherStar 4000+, ws4000@netbymatt.com)', + accept: req.headers?.accept || '*/*', + ...options.headers, + }; + + // Use the cache result passed from handleRequest (no additional cache call) + let staleCache = null; + + if (cacheResult && cacheResult.status === 'stale' && cacheResult.data?.originalHeaders) { + staleCache = cacheResult.data; + // Add conditional headers based on cached etag or last-modified header + if (staleCache.originalHeaders.etag) { + headers['if-none-match'] = staleCache.originalHeaders.etag; + // console.log(`🏷️ Added | If-None-Match: ${staleCache.originalHeaders.etag} for ${fullUrl}`); + } else if (staleCache.originalHeaders['last-modified']) { + headers['if-modified-since'] = staleCache.originalHeaders['last-modified']; + // console.log(`📅 Added | If-Modified-Since: ${staleCache.originalHeaders['last-modified']} for ${fullUrl}`); + } + } + + let responseHandled = false; // Track if we've already sent a response + + const upstreamReq = https.get(fullUrl, { headers }, (getRes) => { + const { statusCode } = getRes; + + // Handle 304 Not Modified responses - refresh stale cache and serve + if (statusCode === 304) { + if (responseHandled) return; // Prevent double response + responseHandled = true; + + if (staleCache) { + const newCacheControl = getRes.headers['cache-control']; + const newMaxAge = HttpCache.parseCacheControl(newCacheControl); + if (newMaxAge > 0) { + staleCache.expiry = Date.now() + (newMaxAge * 1000); + staleCache.timestamp = Date.now(); // Reset age counter for 304 refresh + console.log(`〰️ NoChange | ${fullUrl} (got 304 Not Modified; refreshing cache expiry by ${newMaxAge}s)`); + } else { + console.log(`📉 NoCache | ${fullUrl} (no valid cache directives in 304, not updating expiry)`); + } + + res.status(staleCache.statusCode); + HttpCache.setFilteredHeaders(res, staleCache.headers); + res.send(staleCache.data); + resolve(true); // Cache hit after 304 validation + return; + } + // No stale entry for 304 response (this shouldn't happen!) + console.error(`💥 Error | 304 response but no stale cache entry for ${fullUrl}`); + res.status(500).json({ error: 'Cache inconsistency error' }); + resolve(false); // Error handled, response sent + return; + } + + // Helper function to handle response after data collection + const handleResponse = (data) => { + if (responseHandled) return; // Prevent double response + responseHandled = true; + + // Log HTTP error status codes + if (statusCode >= 400) { + console.error(`🚫 ${statusCode} | ${fullUrl}`); + } + + // Filter out cache headers before storing - we don't need them in our cache + const filteredHeaders = {}; + Object.entries(getRes.headers || {}).forEach(([key, value]) => { + const lowerKey = key.toLowerCase(); + if (!['cache-control', 'expires', 'etag', 'last-modified'].includes(lowerKey)) { + filteredHeaders[key] = value; + } + }); + + const response = { + statusCode, + headers: filteredHeaders, + data, + }; + + // Check if this is a server error (5xx) or client error that shouldn't be cached + if (statusCode >= 500 && statusCode <= 599) { + // For 5xx errors, send response (don't cache, but don't reject since response is sent) + res.status(statusCode); + HttpCache.setFilteredHeaders(res, getRes.headers); + res.send(response.data); + resolve(false); // Error response sent successfully + return; + } + + // For 4xx errors, don't cache but send the response + if (statusCode >= 400 && statusCode <= 499) { + res.status(statusCode); + HttpCache.setFilteredHeaders(res, getRes.headers); + res.send(response.data); + resolve(true); // Successful HTTP transaction (client error, but valid response; don't retry) + return; + } + + // Store in cache (pass original headers for cache logic, but store filtered headers) + this.storeCachedResponse(req, response, fullUrl, getRes.headers); + + // Send response to client + res.status(statusCode); + + // Set filtered headers and our cache policy + HttpCache.setFilteredHeaders(res, getRes.headers); + + res.send(response.data); + resolve(true); // Indicates successful response from upstream + }; + + if (options.encoding === 'binary') { + // For binary data, collect as Buffer chunks + const chunks = []; + getRes.on('data', (chunk) => chunks.push(chunk)); + getRes.on('end', () => handleResponse(Buffer.concat(chunks))); + getRes.on('error', (err) => { + if (responseHandled) return; + responseHandled = true; + console.error(`💥 Error | with stream ${fullUrl}: ${err.message}`); + res.status(500).json({ error: `Stream error: ${err.message}` }); + resolve(false); // Error handled, response sent + }); + } else { + // For text data, use string encoding + let data = ''; + getRes.setEncoding(options.encoding || 'utf8'); + getRes.on('data', (chunk) => { + data += chunk; + }); + getRes.on('end', () => handleResponse(data)); + getRes.on('error', (err) => { + if (responseHandled) return; + responseHandled = true; + console.error(`💥 Error | with stream ${fullUrl}: ${err.message}`); + res.status(500).json({ error: `Stream error: ${err.message}` }); + resolve(false); // Error handled, response sent + }); + } + }); + + upstreamReq.on('error', (err) => { + if (responseHandled) return; // Prevent double response + responseHandled = true; + console.error(`💥 Error | ${fullUrl}: ${err.message}`); + res.status(500).json({ error: `Failed to fetch data from ${options.serviceName || 'upstream API'}` }); + resolve(false); // Error handled, response sent + }); + + upstreamReq.setTimeout(options.timeout || DEFAULT_REQUEST_TIMEOUT, () => { + if (responseHandled) return; // Prevent double response + responseHandled = true; + + console.error(`⏲️ Timeout | ${fullUrl} (after ${options.timeout || DEFAULT_REQUEST_TIMEOUT}ms)`); + + // Send timeout response to client + res.status(504).json({ error: 'Gateway timeout' }); + + // Don't destroy the request immediately - let the response be sent first + // Then destroy to clean up the upstream connection + setImmediate(() => { + if (!upstreamReq.destroyed) { + upstreamReq.destroy(); + } + }); + + resolve(false); // Timeout handled, response sent + }); + }); + } + + getCachedRequest(req) { + const key = HttpCache.generateKey(req); + const cached = this.cache.get(key); + + if (!cached) { + return { status: 'miss', data: null }; + } + + const isExpired = Date.now() > cached.expiry; + + // If fresh, return immediately + if (!isExpired) { + const age = Math.round((Date.now() - cached.timestamp) / 1000); + const remainingTTL = Math.round((cached.expiry - Date.now()) / 1000); + console.log(`🎯 Hit | ${cached.url} (age: ${age}s, remaining: ${remainingTTL}s)`); + return { status: 'fresh', data: cached }; + } + + // If stale, return for potential conditional request + // const staleAge = Math.round((Date.now() - cached.expiry) / 1000); + // console.log(`🕐 Stale | ${cached.url} (expired ${staleAge}s ago, will check upstream)`); + return { status: 'stale', data: cached }; + } + + storeCachedResponse(req, response, url, originalHeaders) { + const key = HttpCache.generateKey(req); + + const cacheControl = (originalHeaders || {})['cache-control']; + let maxAge = HttpCache.parseCacheControl(cacheControl); + let cacheType = ''; + + // If no explicit cache directives, try heuristic caching for Last-Modified + if (maxAge <= 0) { + const lastModified = (originalHeaders || {})['last-modified']; + if (lastModified) { + maxAge = HttpCache.calculateHeuristicMaxAge(lastModified); + cacheType = 'heuristic'; + } + } else { + cacheType = 'explicit'; + } + + // Don't cache if still no valid max-age + if (maxAge <= 0) { + console.log(`📤 Sent | ${url} (no cache directives; not cached)`); + return; + } + + const cached = { + statusCode: response.statusCode, + headers: { ...(response.headers || {}) }, + data: response.data, + expiry: Date.now() + (maxAge * 1000), + timestamp: Date.now(), + url, // Store the URL for logging + originalHeaders: { // Store original headers for conditional requests + etag: (originalHeaders || {}).etag, + 'last-modified': (originalHeaders || {})['last-modified'], + }, + }; + + this.cache.set(key, cached); + + console.log(`🌐 Add | ${url} (${cacheType} ${maxAge}s TTL, expires: ${new Date(cached.expiry).toISOString()})`); + } + + // Calculate heuristic max-age based on Last-Modified header + // RFC 7234: A cache can use heuristic freshness calculation + // Common heuristic: 10% of the age of the resource, with limits + static calculateHeuristicMaxAge(lastModifiedHeader) { + try { + const lastModified = new Date(lastModifiedHeader); + const now = new Date(); + const age = (now.getTime() - lastModified.getTime()) / 1000; // age in seconds + + if (age <= 0) return 0; + + // Use 10% of age, but limit between 1 hour and 4 hours + const heuristicAge = Math.floor(age * 0.1); + const minAge = 60 * 60; // 1 hour + const maxAge = 4 * 60 * 60; // 4 hours + + return Math.max(minAge, Math.min(maxAge, heuristicAge)); + } catch (_error) { + return 0; // Invalid date format + } + } + + // Periodic cleanup of expired entries + startCleanup() { + if (this.cleanupInterval) return; + + this.cleanupInterval = setInterval(() => { + const now = Date.now(); + let removedCount = 0; + + Array.from(this.cache.entries()).forEach(([key, cached]) => { + // Allow stale entries to persist for up to 3 hours before cleanup + // This gives us time to make conditional requests and potentially refresh them + const staleTimeLimit = 3 * 60 * 60 * 1000; + if (now > cached.expiry + staleTimeLimit) { + this.cache.delete(key); + removedCount += 1; + } + }); + + if (removedCount > 0) { + console.log(`🧹 Clean | Removed ${removedCount} stale entries (${this.cache.size} remaining)`); + } + }, 5 * 60 * 1000); // Cleanup every 5 minutes + } + + // Cache statistics + getStats() { + const now = Date.now(); + let expired = 0; + let valid = 0; + + Array.from(this.cache.values()).forEach((cached) => { + if (now > cached.expiry) { + expired += 1; + } else { + valid += 1; + } + }); + + return { + total: this.cache.size, + valid, + expired, + inFlight: this.inFlight.size, + }; + } + + // Clear all cache entries + clear() { + this.cache.clear(); + console.log('🗑️ Clear | Cache cleared'); + } + + // Clear a specific cache entry by path + clearEntry(path) { + const key = path; + const deleted = this.cache.delete(key); + if (deleted) { + console.log(`🗑️ Clear | ${path} removed from cache`); + return true; + } + return false; + } + + // Stop cleanup interval + destroy() { + if (this.cleanupInterval) { + clearInterval(this.cleanupInterval); + this.cleanupInterval = null; + } + this.clear(); + this.inFlight.clear(); + } +} + +// Create singleton instance of our cache +const cache = new HttpCache(); + +export default cache; diff --git a/proxy/handlers.mjs b/proxy/handlers.mjs new file mode 100644 index 0000000..7440064 --- /dev/null +++ b/proxy/handlers.mjs @@ -0,0 +1,52 @@ +// Consolidated proxy handlers for all external API requests with caching + +import cache from './cache.mjs'; +import OVERRIDES from '../src/overrides.mjs'; + +// Weather.gov API proxy (catch-all for any Weather.gov API endpoint) +export const weatherProxy = async (req, res) => { + await cache.handleRequest(req, res, 'https://api.weather.gov', { + serviceName: 'Weather.gov', + skipParams: ['u'], + }); +}; + +// Radar proxy for weather radar images +export const radarProxy = async (req, res) => { + await cache.handleRequest(req, res, 'https://radar.weather.gov', { + serviceName: 'Radar', + skipParams: ['u'], + encoding: 'binary', // Radar images are binary data + }); +}; + +// SPC (Storm Prediction Center) outlook proxy +export const outlookProxy = async (req, res) => { + await cache.handleRequest(req, res, 'https://www.spc.noaa.gov', { + serviceName: 'SPC Outlook', + skipParams: ['u'], + }); +}; + +// Iowa State Mesonet proxy with configurable host +export const mesonetProxy = async (req, res) => { + // Determine if this is a binary file (images) + const isBinary = req.path.match(/\.(png|jpg|jpeg|gif|webp|ico)$/i); + + // Use override radar host if provided, otherwise default to mesonet + const radarHost = OVERRIDES.RADAR_HOST || 'mesonet.agron.iastate.edu'; + + await cache.handleRequest(req, res, `https://${radarHost}`, { + serviceName: `Iowa State Mesonet (${radarHost})`, + skipParams: [], // No parameters to skip for Mesonet + encoding: isBinary ? 'binary' : 'utf8', // Use binary encoding for images + }); +}; + +// Legacy forecast.weather.gov API proxy +export const forecastProxy = async (req, res) => { + await cache.handleRequest(req, res, 'https://forecast.weather.gov', { + serviceName: 'Forecast.weather.gov', + skipParams: ['u'], + }); +}; diff --git a/server/images/logos/app-icon-180.png b/server/images/logos/app-icon-180.png new file mode 100644 index 0000000..8f42321 Binary files /dev/null and b/server/images/logos/app-icon-180.png differ diff --git a/server/scripts/data/regionalcities.js b/server/scripts/data/regionalcities.js deleted file mode 100644 index 66bcd4c..0000000 --- a/server/scripts/data/regionalcities.js +++ /dev/null @@ -1,1163 +0,0 @@ -// eslint-disable-next-line no-unused-vars -const RegionalCities = [ - { - city: 'Atlanta', - lat: 33.749, - lon: -84.388, - point: { - x: 51, - y: 87, - wfo: 'FFC', - }, - }, - { - city: 'Boston', - lat: 42.3584, - lon: -71.0598, - point: { - x: 71, - y: 90, - wfo: 'BOX', - }, - }, - { - city: 'Chicago', - lat: 41.9796, - lon: -87.9045, - point: { - x: 66, - y: 77, - wfo: 'LOT', - }, - }, - { - city: 'Cleveland', - lat: 41.4995, - lon: -81.6954, - point: { - x: 83, - y: 65, - wfo: 'CLE', - }, - }, - { - city: 'Dallas', - lat: 32.8959, - lon: -97.0372, - point: { - x: 80, - y: 109, - wfo: 'FWD', - }, - }, - { - city: 'Denver', - lat: 39.7391, - lon: -104.9847, - point: { - x: 63, - y: 61, - wfo: 'BOU', - }, - }, - { - city: 'Detroit', - lat: 42.3314, - lon: -83.0457, - point: { - x: 66, - y: 34, - wfo: 'DTX', - }, - }, - { - city: 'Hartford', - lat: 41.7637, - lon: -72.6851, - point: { - x: 21, - y: 54, - wfo: 'BOX', - }, - }, - { - city: 'Houston', - lat: 29.7633, - lon: -95.3633, - point: { - x: 65, - y: 97, - wfo: 'HGX', - }, - }, - { - city: 'Indianapolis', - lat: 39.7684, - lon: -86.158, - point: { - x: 58, - y: 69, - wfo: 'IND', - }, - }, - { - city: 'Los Angeles', - lat: 34.0522, - lon: -118.2437, - point: { - x: 155, - y: 45, - wfo: 'LOX', - }, - }, - { - city: 'Miami', - lat: 25.7743, - lon: -80.1937, - point: { - x: 110, - y: 51, - wfo: 'MFL', - }, - }, - { - city: 'Minneapolis', - lat: 44.98, - lon: -93.2638, - point: { - x: 108, - y: 72, - wfo: 'MPX', - }, - }, - { - city: 'New York', - lat: 40.78, - lon: -73.88, - point: { - x: 37, - y: 39, - wfo: 'OKX', - }, - }, - { - city: 'Norfolk', - lat: 36.8468, - lon: -76.2852, - point: { - x: 90, - y: 52, - wfo: 'AKQ', - }, - }, - { - city: 'Orlando', - lat: 28.5383, - lon: -81.3792, - point: { - x: 26, - y: 68, - wfo: 'MLB', - }, - }, - { - city: 'Philadelphia', - lat: 39.9523, - lon: -75.1638, - point: { - x: 50, - y: 76, - wfo: 'PHI', - }, - }, - { - city: 'Pittsburgh', - lat: 40.4406, - lon: -79.9959, - point: { - x: 78, - y: 66, - wfo: 'PBZ', - }, - }, - { - city: 'St. Louis', - lat: 38.6273, - lon: -90.1979, - point: { - x: 95, - y: 74, - wfo: 'LSX', - }, - }, - { - city: 'San Francisco', - lat: 37.6148, - lon: -122.3918, - point: { - x: 84, - y: 98, - wfo: 'MTR', - }, - }, - { - city: 'Seattle', - lat: 47.6062, - lon: -122.3321, - point: { - x: 125, - y: 68, - wfo: 'SEW', - }, - }, - { - city: 'Syracuse', - lat: 43.0481, - lon: -76.1474, - point: { - x: 52, - y: 99, - wfo: 'BGM', - }, - }, - { - city: 'Tampa', - lat: 27.9756, - lon: -82.5329, - point: { - x: 68, - y: 98, - wfo: 'TBW', - }, - }, - { - city: 'Washington DC', - lat: 38.8951, - lon: -77.0364, - point: { - x: 97, - y: 71, - wfo: 'LWX', - }, - }, - { - city: 'Albany', - lat: 42.6526, - lon: -73.7562, - point: { - x: 72, - y: 63, - wfo: 'ALY', - }, - }, - { - city: 'Albuquerque', - lat: 35.0845, - lon: -106.6511, - point: { - x: 98, - y: 121, - wfo: 'ABQ', - }, - }, - { - city: 'Amarillo', - lat: 35.222, - lon: -101.8313, - point: { - x: 48, - y: 26, - wfo: 'AMA', - }, - }, - { - city: 'Anchorage', - lat: 61.2181, - lon: -149.9003, - point: { - x: 125, - y: 236, - wfo: 'AER', - }, - }, - { - city: 'Austin', - lat: 30.2671, - lon: -97.7431, - point: { - x: 156, - y: 91, - wfo: 'EWX', - }, - }, - { - city: 'Baker', - lat: 44.7502, - lon: -117.6677, - point: { - x: 94, - y: 146, - wfo: 'BOI', - }, - }, - { - city: 'Baltimore', - lat: 39.2904, - lon: -76.6122, - point: { - x: 109, - y: 91, - wfo: 'LWX', - }, - }, - { - city: 'Bangor', - lat: 44.8012, - lon: -68.7778, - point: { - x: 66, - y: 62, - wfo: 'CAR', - }, - }, - { - city: 'Birmingham', - lat: 33.5207, - lon: -86.8025, - point: { - x: 59, - y: 84, - wfo: 'BMX', - }, - }, - { - city: 'Bismarck', - lat: 46.8083, - lon: -100.7837, - point: { - x: 110, - y: 47, - wfo: 'BIS', - }, - }, - { - city: 'Boise', - lat: 43.6135, - lon: -116.2034, - point: { - x: 133, - y: 86, - wfo: 'BOI', - }, - }, - { - city: 'Buffalo', - lat: 42.8864, - lon: -78.8784, - point: { - x: 36, - y: 47, - wfo: 'BUF', - }, - }, - { - city: 'Carlsbad', - lat: 32.4207, - lon: -104.2288, - point: { - x: 44, - y: 156, - wfo: 'MAF', - }, - }, - { - city: 'Charleston', - lat: 32.7766, - lon: -79.9309, - point: { - x: 87, - y: 77, - wfo: 'CHS', - }, - }, - { - city: 'Charleston', - lat: 38.3498, - lon: -81.6326, - point: { - x: 63, - y: 67, - wfo: 'RLX', - }, - }, - { - city: 'Charlotte', - lat: 35.2271, - lon: -80.8431, - point: { - x: 119, - y: 65, - wfo: 'GSP', - }, - }, - { - city: 'Cheyenne', - lat: 41.14, - lon: -104.8202, - point: { - x: 110, - y: 14, - wfo: 'CYS', - }, - }, - { - city: 'Cincinnati', - lat: 39.162, - lon: -84.4569, - point: { - x: 37, - y: 41, - wfo: 'ILN', - }, - }, - { - city: 'Columbia', - lat: 34.0007, - lon: -81.0348, - point: { - x: 65, - y: 61, - wfo: 'CAE', - }, - }, - { - city: 'Columbus', - lat: 39.9612, - lon: -82.9988, - point: { - x: 85, - y: 81, - wfo: 'ILN', - }, - }, - { - city: 'Des Moines', - lat: 41.6005, - lon: -93.6091, - point: { - x: 74, - y: 50, - wfo: 'DMX', - }, - }, - { - city: 'Dubuque', - lat: 42.5006, - lon: -90.6646, - point: { - x: 63, - y: 111, - wfo: 'DVN', - }, - }, - { - city: 'Duluth', - lat: 46.7833, - lon: -92.1066, - point: { - x: 91, - y: 69, - wfo: 'DLH', - }, - }, - { - city: 'Eastport', - lat: 44.9062, - lon: -66.99, - point: { - x: 123, - y: 79, - wfo: 'CAR', - }, - }, - { - city: 'El Centro', - lat: 32.792, - lon: -115.563, - point: { - x: 27, - y: 47, - wfo: 'PSR', - }, - }, - { - city: 'El Paso', - lat: 31.7587, - lon: -106.4869, - point: { - x: 100, - y: 56, - wfo: 'EPZ', - }, - }, - { - city: 'Eugene', - lat: 44.0521, - lon: -123.0867, - point: { - x: 85, - y: 39, - wfo: 'PQR', - }, - }, - { - city: 'Fargo', - lat: 46.8772, - lon: -96.7898, - point: { - x: 100, - y: 57, - wfo: 'FGF', - }, - }, - { - city: 'Flagstaff', - lat: 35.1981, - lon: -111.6513, - point: { - x: 74, - y: 89, - wfo: 'FGZ', - }, - }, - { - city: 'Fresno', - lat: 36.7477, - lon: -119.7724, - point: { - x: 53, - y: 100, - wfo: 'HNX', - }, - }, - { - city: 'Grand Junction', - lat: 39.0639, - lon: -108.5506, - point: { - x: 95, - y: 102, - wfo: 'GJT', - }, - }, - { - city: 'Grand Rapids', - lat: 42.9634, - lon: -85.6681, - point: { - x: 41, - y: 47, - wfo: 'GRR', - }, - }, - { - city: 'Havre', - lat: 48.55, - lon: -109.6841, - point: { - x: 155, - y: 188, - wfo: 'TFX', - }, - }, - { - city: 'Helena', - lat: 46.5927, - lon: -112.0361, - point: { - x: 69, - y: 104, - wfo: 'TFX', - }, - }, - { - city: 'Honolulu', - lat: 21.3069, - lon: -157.8583, - point: { - x: 154, - y: 145, - wfo: 'HFO', - }, - }, - { - city: 'Hot Springs', - lat: 34.5037, - lon: -93.0552, - point: { - x: 54, - y: 61, - wfo: 'LZK', - }, - }, - { - city: 'Idaho Falls', - lat: 43.4666, - lon: -112.0341, - point: { - x: 124, - y: 73, - wfo: 'PIH', - }, - }, - { - city: 'Jackson', - lat: 32.2988, - lon: -90.1848, - point: { - x: 76, - y: 63, - wfo: 'JAN', - }, - }, - { - city: 'Jacksonville', - lat: 30.3322, - lon: -81.6556, - point: { - x: 66, - y: 65, - wfo: 'JAX', - }, - }, - { - city: 'Juneau', - lat: 58.3019, - lon: -134.4197, - point: { - x: 194, - y: 163, - wfo: 'AJK', - }, - }, - { - city: 'Kansas City', - lat: 39.1142, - lon: -94.6275, - point: { - x: 42, - y: 51, - wfo: 'EAX', - }, - }, - { - city: 'Key West', - lat: 24.5557, - lon: -81.7826, - point: { - x: 62, - y: 48, - wfo: 'KEY', - }, - }, - { - city: 'Klamath Falls', - lat: 42.2249, - lon: -121.7817, - point: { - x: 141, - y: 61, - wfo: 'MFR', - }, - }, - { - city: 'Knoxville', - lat: 35.9606, - lon: -83.9207, - point: { - x: 71, - y: 51, - wfo: 'MRX', - }, - }, - { - city: 'Las Vegas', - lat: 36.175, - lon: -115.1372, - point: { - x: 123, - y: 98, - wfo: 'VEF', - }, - }, - { - city: 'Lewiston', - lat: 46.4165, - lon: -117.0177, - point: { - x: 144, - y: 30, - wfo: 'OTX', - }, - }, - { - city: 'Lincoln', - lat: 40.8, - lon: -96.667, - point: { - x: 57, - y: 39, - wfo: 'OAX', - }, - }, - { - city: 'Long Beach', - lat: 33.767, - lon: -118.1892, - point: { - x: 155, - y: 32, - wfo: 'LOX', - }, - }, - { - city: 'Louisville', - lat: 38.2542, - lon: -85.7594, - point: { - x: 50, - y: 78, - wfo: 'LMK', - }, - }, - { - city: 'Manchester', - lat: 42.9956, - lon: -71.4548, - point: { - x: 42, - y: 21, - wfo: 'GYX', - }, - }, - { - city: 'Memphis', - lat: 35.1495, - lon: -90.049, - point: { - x: 42, - y: 67, - wfo: 'MEG', - }, - }, - { - city: 'Milwaukee', - lat: 43.0389, - lon: -87.9065, - point: { - x: 88, - y: 65, - wfo: 'MKX', - }, - }, - { - city: 'Mobile', - lat: 30.6944, - lon: -88.043, - point: { - x: 52, - y: 67, - wfo: 'MOB', - }, - }, - { - city: 'Montgomery', - lat: 32.3668, - lon: -86.3, - point: { - x: 81, - y: 35, - wfo: 'BMX', - }, - }, - { - city: 'Montpelier', - lat: 44.2601, - lon: -72.5754, - point: { - x: 111, - y: 50, - wfo: 'BTV', - }, - }, - { - city: 'Nashville', - lat: 36.1659, - lon: -86.7844, - point: { - x: 50, - y: 57, - wfo: 'OHX', - }, - }, - { - city: 'Newark', - lat: 40.7357, - lon: -74.1724, - point: { - x: 27, - y: 35, - wfo: 'OKX', - }, - }, - { - city: 'New Haven', - lat: 41.3081, - lon: -72.9282, - point: { - x: 66, - y: 68, - wfo: 'OKX', - }, - }, - { - city: 'New Orleans', - lat: 29.9546, - lon: -90.0751, - point: { - x: 68, - y: 88, - wfo: 'LIX', - }, - }, - { - city: 'Nome', - lat: 64.5011, - lon: -165.4064, - point: { - x: 217, - y: 139, - wfo: 'AFG', - }, - }, - { - city: 'Oklahoma City', - lat: 35.4676, - lon: -97.5164, - point: { - x: 97, - y: 94, - wfo: 'OUN', - }, - }, - { - city: 'Omaha', - lat: 41.2586, - lon: -95.9378, - point: { - x: 83, - y: 60, - wfo: 'OAX', - }, - }, - { - city: 'Phoenix', - lat: 33.4484, - lon: -112.074, - point: { - x: 159, - y: 58, - wfo: 'PSR', - }, - }, - { - city: 'Pierre', - lat: 44.3683, - lon: -100.351, - point: { - x: 55, - y: 44, - wfo: 'ABR', - }, - }, - { - city: 'Portland', - lat: 43.6615, - lon: -70.2553, - point: { - x: 76, - y: 59, - wfo: 'GYX', - }, - }, - { - city: 'Portland', - lat: 45.5234, - lon: -122.6762, - point: { - x: 113, - y: 104, - wfo: 'PQR', - }, - }, - { - city: 'Providence', - lat: 41.824, - lon: -71.4128, - point: { - x: 64, - y: 64, - wfo: 'BOX', - }, - }, - { - city: 'Raleigh', - lat: 35.7721, - lon: -78.6386, - point: { - x: 75, - y: 57, - wfo: 'RAH', - }, - }, - { - city: 'Reno', - lat: 39.4986, - lon: -119.7681, - point: { - x: 46, - y: 105, - wfo: 'REV', - }, - }, - { - city: 'Richfield', - lat: 38.7725, - lon: -112.0841, - point: { - x: 82, - y: 87, - wfo: 'SLC', - }, - }, - { - city: 'Richmond', - lat: 37.5538, - lon: -77.4603, - point: { - x: 45, - y: 77, - wfo: 'AKQ', - }, - }, - { - city: 'Roanoke', - lat: 37.271, - lon: -79.9414, - point: { - x: 74, - y: 69, - wfo: 'RNK', - }, - }, - { - city: 'Sacramento', - lat: 38.5816, - lon: -121.4944, - point: { - x: 41, - y: 68, - wfo: 'STO', - }, - }, - { - city: 'Salt Lake City', - lat: 40.7608, - lon: -111.891, - point: { - x: 100, - y: 175, - wfo: 'SLC', - }, - }, - { - city: 'San Antonio', - lat: 29.4241, - lon: -98.4936, - point: { - x: 126, - y: 54, - wfo: 'EWX', - }, - }, - { - city: 'San Diego', - lat: 32.7153, - lon: -117.1573, - point: { - x: 57, - y: 14, - wfo: 'SGX', - }, - }, - { - city: 'San Jose', - lat: 37.3394, - lon: -121.895, - point: { - x: 99, - y: 82, - wfo: 'MTR', - }, - }, - { - city: 'Santa Fe', - lat: 35.687, - lon: -105.9378, - point: { - x: 126, - y: 146, - wfo: 'ABQ', - }, - }, - { - city: 'Savannah', - lat: 32.0835, - lon: -81.0998, - point: { - x: 47, - y: 41, - wfo: 'CHS', - }, - }, - { - city: 'Shreveport', - lat: 32.5251, - lon: -93.7502, - point: { - x: 74, - y: 69, - wfo: 'SHV', - }, - }, - { - city: 'Sioux Falls', - lat: 43.55, - lon: -96.7003, - point: { - x: 99, - y: 65, - wfo: 'FSD', - }, - }, - { - city: 'Sitka', - lat: 57.0531, - lon: -135.33, - point: { - x: 188, - y: 112, - wfo: 'AJK', - }, - }, - { - city: 'Spokane', - lat: 47.6597, - lon: -117.4291, - point: { - x: 140, - y: 90, - wfo: 'OTX', - }, - }, - { - city: 'Springfield', - lat: 39.8017, - lon: -89.6437, - point: { - x: 48, - y: 56, - wfo: 'ILX', - }, - }, - { - city: 'Springfield', - lat: 42.1015, - lon: -72.5898, - point: { - x: 22, - y: 69, - wfo: 'BOX', - }, - }, - { - city: 'Springfield', - lat: 37.2153, - lon: -93.2982, - point: { - x: 67, - y: 35, - wfo: 'SGF', - }, - }, - { - city: 'Toledo', - lat: 41.6639, - lon: -83.5552, - point: { - x: 19, - y: 67, - wfo: 'CLE', - }, - }, - { - city: 'Tulsa', - lat: 36.154, - lon: -95.9928, - point: { - x: 41, - y: 105, - wfo: 'TSA', - }, - }, - { - city: 'Virginia Beach', - lat: 36.8529, - lon: -75.978, - point: { - x: 101, - y: 53, - wfo: 'AKQ', - }, - }, - { - city: 'Wichita', - lat: 37.6922, - lon: -97.3375, - point: { - x: 62, - y: 34, - wfo: 'ICT', - }, - }, - { - city: 'Wilmington', - lat: 34.2257, - lon: -77.9447, - point: { - x: 89, - y: 68, - wfo: 'ILM', - }, - }, - { - city: 'Tucson', - lat: 32.2216, - lon: -110.9698, - point: { - x: 91, - y: 49, - wfo: 'TWC', - }, - }, -]; diff --git a/server/scripts/data/stations.js b/server/scripts/data/stations.js deleted file mode 100644 index ae05430..0000000 --- a/server/scripts/data/stations.js +++ /dev/null @@ -1,16132 +0,0 @@ -// cspell: disable -// eslint-disable-next-line no-unused-vars -const StationInfo = { - KBID: { - id: 'KBID', - city: 'Block Island State Airport', - state: 'RI', - lat: 41.1694699, - lon: -71.5787299, - }, - KOQU: { - id: 'KOQU', - city: 'N. Kingston / Quonset', - state: 'RI', - lat: 41.6, - lon: -71.41667, - }, - KPVD: { - id: 'KPVD', - city: 'Rhode Island TF Green International Airport', - state: 'RI', - lat: 41.72233, - lon: -71.4277199, - }, - KSFZ: { - id: 'KSFZ', - city: 'Pawtucket, North Central State Airport', - state: 'RI', - lat: 41.91667, - lon: -71.5, - }, - KUUU: { - id: 'KUUU', - city: 'Newport, Newport State Airport', - state: 'RI', - lat: 41.53, - lon: -71.28361, - }, - KWST: { - id: 'KWST', - city: 'Westerly, Westerly State Airport', - state: 'RI', - lat: 41.34972, - lon: -71.79889, - }, - KDOV: { - id: 'KDOV', - city: 'Dover Air Force Base', - state: 'DE', - lat: 39.13333, - lon: -75.4666699, - }, - KGED: { - id: 'KGED', - city: 'Georgetown - Delaware Coastal Airport', - state: 'DE', - lat: 38.68974, - lon: -75.36245, - }, - KILG: { - id: 'KILG', - city: 'Wilmington, New Castle County Airport', - state: 'DE', - lat: 39.67442, - lon: -75.60567, - }, - KAFO: { - id: 'KAFO', - city: 'Afton WY', - state: 'WY', - lat: 42.7113299, - lon: -110.94217, - }, - KARL: { - id: 'KARL', - city: 'I80 - Arlington', - state: 'WY', - lat: 41.5980599, - lon: -106.21487, - }, - KBFU: { - id: 'KBFU', - city: 'WY59 - Belle Fourche', - state: 'WY', - lat: 43.93253, - lon: -105.4467, - }, - KBIT: { - id: 'KBIT', - city: 'I80/US30 - Bitter Creek', - state: 'WY', - lat: 41.64599, - lon: -108.5836, - }, - KBPI: { - id: 'KBPI', - city: 'Big Piney - Marbleton Airport', - state: 'WY', - lat: 42.57805, - lon: -110.10972, - }, - KBRX: { - id: 'KBRX', - city: 'I25/US87 - Bordeaux Interchange', - state: 'WY', - lat: 41.93066, - lon: -104.9436, - }, - KBVR: { - id: 'KBVR', - city: 'US287/WY789 - Beaver Rim', - state: 'WY', - lat: 42.58565, - lon: -108.28199, - }, - KBYG: { - id: 'KBYG', - city: 'Buffalo - Johnson County Airport', - state: 'WY', - lat: 44.38122, - lon: -106.71947, - }, - KCHJ: { - id: 'KCHJ', - city: 'WY296 - Chief Joseph', - state: 'WY', - lat: 44.73997, - lon: -109.38088, - }, - KCMS: { - id: 'KCMS', - city: 'I80/US30 - Peru Hill', - state: 'WY', - lat: 41.54958, - lon: -109.60197, - }, - KCOD: { - id: 'KCOD', - city: 'Cody', - state: 'WY', - lat: 44.51667, - lon: -109.01667, - }, - KCPR: { - id: 'KCPR', - city: 'Casper, Natrona County International Airport', - state: 'WY', - lat: 42.8975, - lon: -106.47306, - }, - KCTD: { - id: 'KCTD', - city: 'I80/US30 - Continental Divide', - state: 'WY', - lat: 41.71586, - lon: -107.78256, - }, - KCYS: { - id: 'KCYS', - city: 'Cheyenne, Cheyenne Airport', - state: 'WY', - lat: 41.15789, - lon: -104.80812, - }, - KDGW: { - id: 'KDGW', - city: 'Douglas, Converse County Airport', - state: 'WY', - lat: 42.79417, - lon: -105.38194, - }, - KDHS: { - id: 'KDHS', - city: 'I90 - Dead Horse', - state: 'WY', - lat: 44.21906, - lon: -106.10478, - }, - KDRC: { - id: 'KDRC', - city: 'I25 - Deer Creek', - state: 'WY', - lat: 42.83687, - lon: -105.86063, - }, - KDUB: { - id: 'KDUB', - city: 'Dubois Municipal Airport', - state: 'WY', - lat: 43.5484, - lon: -109.6903, - }, - KDWX: { - id: 'KDWX', - city: 'Dixon Airport', - state: 'WY', - lat: 41.03704, - lon: -107.49976, - }, - KEAN: { - id: 'KEAN', - city: 'Phifer Airfield - Wheatland', - state: 'WY', - lat: 42.05472, - lon: -104.93711, - }, - KECS: { - id: 'KECS', - city: 'Mondell Field', - state: 'WY', - lat: 43.8854, - lon: -104.3179, - }, - KEHY: { - id: 'KEHY', - city: 'Elk Mountain AWOS', - state: 'WY', - lat: 41.7253, - lon: -106.4594, - }, - KEMM: { - id: 'KEMM', - city: 'KEMMERER', - state: 'WY', - lat: 41.82, - lon: -110.56, - }, - KEVW: { - id: 'KEVW', - city: 'Evanston-Uinta County Airport - Burns Field', - state: 'WY', - lat: 41.27306, - lon: -111.03056, - }, - KFBR: { - id: 'KFBR', - city: 'Fort Bridger WY', - state: 'WY', - lat: 41.392, - lon: -110.40683, - }, - KFEW: { - id: 'KFEW', - city: 'Francis E Warren Air Force Base Heliport', - state: 'WY', - lat: 41.13332, - lon: -104.8671899, - }, - KFIR: { - id: 'KFIR', - city: 'I80/US189 - First Divide', - state: 'WY', - lat: 41.27649, - lon: -110.80066, - }, - KGCC: { - id: 'KGCC', - city: 'Gillette, Gillette-Campbell County Airport', - state: 'WY', - lat: 44.33944, - lon: -105.54194, - }, - KGEY: { - id: 'KGEY', - city: 'South Big Horn County Airport', - state: 'WY', - lat: 44.5174, - lon: -108.0752, - }, - KGUN: { - id: 'KGUN', - city: 'US85 - Gun Barrel', - state: 'WY', - lat: 41.44368, - lon: -104.34428, - }, - KGUR: { - id: 'KGUR', - city: 'Camp Guernsey', - state: 'WY', - lat: 42.2597, - lon: -104.7283, - }, - KHLD: { - id: 'KHLD', - city: 'US20/US26 - Hiland', - state: 'WY', - lat: 43.0923, - lon: -107.32198, - }, - KHSG: { - id: 'KHSG', - city: 'Hot Springs County Airport', - state: 'WY', - lat: 43.7136, - lon: -108.3897, - }, - KIDV: { - id: 'KIDV', - city: 'I25/US87 - I-25 Divide', - state: 'WY', - lat: 43.89864, - lon: -106.63833, - }, - KIKA: { - id: 'KIKA', - city: 'I90 - Inyan Kara', - state: 'WY', - lat: 44.29414, - lon: -104.62926, - }, - KJAC: { - id: 'KJAC', - city: 'Jackson, Jackson Hole Airport', - state: 'WY', - lat: 43.6, - lon: -110.73333, - }, - KLAR: { - id: 'KLAR', - city: 'Laramie Regional Airport', - state: 'WY', - lat: 41.3165, - lon: -105.67287, - }, - KLND: { - id: 'KLND', - city: 'Lander', - state: 'WY', - lat: 42.81472, - lon: -108.72806, - }, - KMTR: { - id: 'KMTR', - city: 'WY120 - Meeteetse Rim', - state: 'WY', - lat: 44.27011, - lon: -108.87343, - }, - KPAT: { - id: 'KPAT', - city: 'WY220 - Pathfinder', - state: 'WY', - lat: 42.5581, - lon: -106.8453399, - }, - KPER: { - id: 'KPER', - city: 'I80/US30 - Green River Tunnel East', - state: 'WY', - lat: 41.53186, - lon: -109.45995, - }, - KPNA: { - id: 'KPNA', - city: 'Pinedale, Ralph Wenz Field Airport', - state: 'WY', - lat: 42.79528, - lon: -109.80694, - }, - KPOY: { - id: 'KPOY', - city: 'Powell Municipal Airport', - state: 'WY', - lat: 44.8671999, - lon: -108.7934, - }, - KPUM: { - id: 'KPUM', - city: 'US287 - Pumpkin Vine', - state: 'WY', - lat: 41.05218, - lon: -105.46906, - }, - KREC: { - id: 'KREC', - city: 'WY28 - Lower Red Canyon', - state: 'WY', - lat: 42.61795, - lon: -108.61093, - }, - KRIW: { - id: 'KRIW', - city: 'Riverton Regional Airport', - state: 'WY', - lat: 43.06219, - lon: -108.44701, - }, - KRKS: { - id: 'KRKS', - city: 'Rock Springs, Rock Springs-Sweetwater County Airport', - state: 'WY', - lat: 41.59417, - lon: -109.06528, - }, - KRWL: { - id: 'KRWL', - city: 'Rawlins Municipal Airport', - state: 'WY', - lat: 41.80648, - lon: -107.19516, - }, - KSAA: { - id: 'KSAA', - city: 'Saratoga WY', - state: 'WY', - lat: 41.44483, - lon: -106.8235, - }, - KSGE: { - id: 'KSGE', - city: 'US30 - Sage Junction', - state: 'WY', - lat: 41.82447, - lon: -110.90764, - }, - KSHC: { - id: 'KSHC', - city: 'WY372 - Shute Creek', - state: 'WY', - lat: 41.94409, - lon: -110.00399, - }, - KSHR: { - id: 'KSHR', - city: 'Sheridan County Airport', - state: 'WY', - lat: 44.7603099, - lon: -106.97411, - }, - KSKL: { - id: 'KSKL', - city: 'WY230 - Skyline', - state: 'WY', - lat: 41.13753, - lon: -106.57687, - }, - KSOU: { - id: 'KSOU', - city: 'WY28 - South Pass', - state: 'WY', - lat: 42.47752, - lon: -108.8444, - }, - KTBX: { - id: 'KTBX', - city: 'Boysen', - state: 'WY', - lat: 43.4667, - lon: -108.2333, - }, - KTET: { - id: 'KTET', - city: 'WY22 - Teton Pass', - state: 'WY', - lat: 43.49873, - lon: -110.9562, - }, - KTMH: { - id: 'KTMH', - city: 'I25/US87 - Twenty Mile Hill', - state: 'WY', - lat: 43.12271, - lon: -106.33705, - }, - KTOR: { - id: 'KTOR', - city: 'Torrington Municipal Airport', - state: 'WY', - lat: 42.06134, - lon: -104.15842, - }, - KVDW: { - id: 'KVDW', - city: 'I80/US30 - Vedauwoo', - state: 'WY', - lat: 41.15687, - lon: -105.40237, - }, - KWRL: { - id: 'KWRL', - city: 'Worland, Worland Municipal Airport', - state: 'WY', - lat: 43.9658299, - lon: -107.95083, - }, - KWTR: { - id: 'KWTR', - city: 'I25/US87 - Whitaker', - state: 'WY', - lat: 41.41772, - lon: -104.87502, - }, - KWYH: { - id: 'KWYH', - city: 'I25/US87 - Wyo Hill', - state: 'WY', - lat: 41.04746, - lon: -104.8901, - }, - KACK: { - id: 'KACK', - city: 'Nantucket, Nantucket Memorial Airport', - state: 'MA', - lat: 41.25389, - lon: -70.05972, - }, - KAQW: { - id: 'KAQW', - city: 'North Adams Harriman-and-West Airport', - state: 'MA', - lat: 42.69731, - lon: -73.16955, - }, - KBAF: { - id: 'KBAF', - city: 'Westfield, Barnes Municipal Airport', - state: 'MA', - lat: 42.15972, - lon: -72.71278, - }, - KBED: { - id: 'KBED', - city: 'Laurence G Hanscom Field Airport', - state: 'MA', - lat: 42.46811, - lon: -71.29463, - }, - KBOS: { - id: 'KBOS', - city: 'Boston, Logan International Airport', - state: 'MA', - lat: 42.36056, - lon: -71.01056, - }, - KBVY: { - id: 'KBVY', - city: 'Beverly, Beverly Municipal Airport', - state: 'MA', - lat: 42.58361, - lon: -70.91639, - }, - KCEF: { - id: 'KCEF', - city: 'Chicopee Falls / Westover Air Force Base', - state: 'MA', - lat: 42.2, - lon: -72.53333, - }, - KCQX: { - id: 'KCQX', - city: 'Chatham, Chatham Municipal Airport', - state: 'MA', - lat: 41.6875, - lon: -69.99333, - }, - KEWB: { - id: 'KEWB', - city: 'New Bedford, New Bedford Regional Airport', - state: 'MA', - lat: 41.67528, - lon: -70.95694, - }, - KFIT: { - id: 'KFIT', - city: 'Fitchburg, Fitchburg Municipal Airport', - state: 'MA', - lat: 42.55194, - lon: -71.75583, - }, - KFMH: { - id: 'KFMH', - city: 'Otis Air National Guard Base', - state: 'MA', - lat: 41.65, - lon: -70.51667, - }, - KGHG: { - id: 'KGHG', - city: 'Marshfield Airport', - state: 'MA', - lat: 42.0983, - lon: -70.6722, - }, - KHYA: { - id: 'KHYA', - city: 'Hyannis, Barnstable Municipal-Boardman Airport', - state: 'MA', - lat: 41.67194, - lon: -70.26972, - }, - KLWM: { - id: 'KLWM', - city: 'Lawrence Municipal Airport', - state: 'MA', - lat: 42.7126, - lon: -71.12553, - }, - KMVY: { - id: 'KMVY', - city: 'Marthas Vineyard Airport', - state: 'MA', - lat: 41.39298, - lon: -70.61588, - }, - KORE: { - id: 'KORE', - city: 'Orange Municipal Airport', - state: 'MA', - lat: 42.57, - lon: -72.28693, - }, - KORH: { - id: 'KORH', - city: 'Worcester, Worcester Regional Airport', - state: 'MA', - lat: 42.27056, - lon: -71.87306, - }, - KOWD: { - id: 'KOWD', - city: 'Norwood, Norwood Memorial Airport', - state: 'MA', - lat: 42.19083, - lon: -71.17389, - }, - KPSF: { - id: 'KPSF', - city: 'Pittsfield Municipal Airport', - state: 'MA', - lat: 42.42691, - lon: -73.28897, - }, - KPVC: { - id: 'KPVC', - city: 'Provincetown Municipal Airport', - state: 'MA', - lat: 42.07436, - lon: -70.21816, - }, - KPYM: { - id: 'KPYM', - city: 'Plymouth, Plymouth Municipal Airport', - state: 'MA', - lat: 41.90861, - lon: -70.72806, - }, - KTAN: { - id: 'KTAN', - city: 'Taunton, Taunton Municipal Airport', - state: 'MA', - lat: 41.87556, - lon: -71.0211099, - }, - KADF: { - id: 'KADF', - city: 'Dexter B Florence Memorial Field', - state: 'AR', - lat: 34.0998, - lon: -93.0661, - }, - KAGO: { - id: 'KAGO', - city: 'Ralph C Weiser Field Airport', - state: 'AR', - lat: 33.2274699, - lon: -93.217, - }, - KARG: { - id: 'KARG', - city: 'Walnut Ridge Regional Airport', - state: 'AR', - lat: 36.12562, - lon: -90.92148, - }, - KASG: { - id: 'KASG', - city: 'Springdale Municipal', - state: 'AR', - lat: 36.18333, - lon: -94.11667, - }, - KAWM: { - id: 'KAWM', - city: 'West Memphis, West Memphis Municipal Airport', - state: 'AR', - lat: 35.13333, - lon: -90.23333, - }, - KBPK: { - id: 'KBPK', - city: 'Baxter County Airport', - state: 'AR', - lat: 36.37056, - lon: -92.47194, - }, - KBVX: { - id: 'KBVX', - city: 'Batesville, Batesville Regional Airport', - state: 'AR', - lat: 35.73333, - lon: -91.65, - }, - KCCA: { - id: 'KCCA', - city: 'Clinton Memorial Airfield', - state: 'AR', - lat: 35.598, - lon: -92.4516, - }, - KCDH: { - id: 'KCDH', - city: 'Camden / Harrell Field', - state: 'AR', - lat: 33.61667, - lon: -92.76667, - }, - KCXW: { - id: 'KCXW', - city: 'Conway - Cantrell Field', - state: 'AR', - lat: 35.0199, - lon: -92.5551, - }, - KDEQ: { - id: 'KDEQ', - city: 'De Queen, J Lynn Helms Sevier County Airport', - state: 'AR', - lat: 34.04694, - lon: -94.39944, - }, - KDRP: { - id: 'KDRP', - city: 'Delta Regional Airport', - state: 'AR', - lat: 35.12005, - lon: -90.8265, - }, - KELD: { - id: 'KELD', - city: 'South Arkansas Regional Airport', - state: 'AR', - lat: 33.22075, - lon: -92.8139999, - }, - KFLP: { - id: 'KFLP', - city: 'Flippin, Marion County Regional Airport', - state: 'AR', - lat: 36.3, - lon: -92.58333, - }, - KFSM: { - id: 'KFSM', - city: 'Fort Smith Regional Airport', - state: 'AR', - lat: 35.3335, - lon: -94.36524, - }, - KFYV: { - id: 'KFYV', - city: 'Fayetteville, Drake Field', - state: 'AR', - lat: 36.01028, - lon: -94.1677799, - }, - KHKA: { - id: 'KHKA', - city: 'Blytheville, Blytheville Municipal Airport', - state: 'AR', - lat: 35.93889, - lon: -89.8325, - }, - KHOT: { - id: 'KHOT', - city: 'Hot Springs, Memorial Field Airport', - state: 'AR', - lat: 34.47806, - lon: -93.09611, - }, - KHRO: { - id: 'KHRO', - city: 'Harrison, Boone County Airport', - state: 'AR', - lat: 36.26167, - lon: -93.15472, - }, - KJBR: { - id: 'KJBR', - city: 'Jonesboro, Jonesboro Municipal Airport', - state: 'AR', - lat: 35.83722, - lon: -90.64306, - }, - KLIT: { - id: 'KLIT', - city: 'Little Rock, Adams Field', - state: 'AR', - lat: 34.72667, - lon: -92.23611, - }, - KLLQ: { - id: 'KLLQ', - city: 'Monticello, Monticello Municipal Airport/Ellis Field', - state: 'AR', - lat: 33.63833, - lon: -91.75111, - }, - KLRF: { - id: 'KLRF', - city: 'Little Rock Air Force Base', - state: 'AR', - lat: 34.91667, - lon: -92.15, - }, - KMEZ: { - id: 'KMEZ', - city: 'Mena, Mena Intermountain Municipal Airport', - state: 'AR', - lat: 34.54528, - lon: -94.2025, - }, - KMWT: { - id: 'KMWT', - city: 'Mount Ida', - state: 'AR', - lat: 34.55, - lon: -93.58333, - }, - KORK: { - id: 'KORK', - city: 'North Little Rock Municipal Airport', - state: 'AR', - lat: 34.83314, - lon: -92.25414, - }, - KPBF: { - id: 'KPBF', - city: 'Pine Bluff, Grider Field Airport', - state: 'AR', - lat: 34.175, - lon: -91.93472, - }, - KROG: { - id: 'KROG', - city: 'Rogers - Rogers Executive Airport - Carter Field', - state: 'AR', - lat: 36.36667, - lon: -94.1, - }, - KRUE: { - id: 'KRUE', - city: 'Russelville Municipal Airport', - state: 'AR', - lat: 35.25737, - lon: -93.0949399, - }, - KSGT: { - id: 'KSGT', - city: 'Stuttgart, Stuttgart Municipal Airport', - state: 'AR', - lat: 34.6, - lon: -91.56667, - }, - KSLG: { - id: 'KSLG', - city: 'Siloam Springs, Smith Field Airport', - state: 'AR', - lat: 36.2, - lon: -94.48333, - }, - KSRC: { - id: 'KSRC', - city: 'Searcy Municipal Airport', - state: 'AR', - lat: 35.21349, - lon: -91.7392799, - }, - KSUZ: { - id: 'KSUZ', - city: 'Saline County Regional Airport', - state: 'AR', - lat: 34.59039, - lon: -92.47944, - }, - KTXK: { - id: 'KTXK', - city: 'Texarkana, Texarkana Regional-Webb Field', - state: 'AR', - lat: 33.45611, - lon: -93.9875, - }, - KVBT: { - id: 'KVBT', - city: 'Bentonville, Bentonville Municipal Airport/Louise M Thaden Field', - state: 'AR', - lat: 36.35, - lon: -94.2166699, - }, - KXNA: { - id: 'KXNA', - city: 'Northwest Arkansas Regional Airport', - state: 'AR', - lat: 36.28977, - lon: -94.3114499, - }, - KACQ: { - id: 'KACQ', - city: 'Waseca Municipal Airport', - state: 'MN', - lat: 44.07024, - lon: -93.55342, - }, - KADC: { - id: 'KADC', - city: 'Wadena Municipal Airport', - state: 'MN', - lat: 46.45022, - lon: -95.21353, - }, - KAEL: { - id: 'KAEL', - city: 'Albert Lea, Albert Lea Municipal Airport', - state: 'MN', - lat: 43.68333, - lon: -93.36667, - }, - KAIT: { - id: 'KAIT', - city: 'Aitkin Municipal Airport - Steve Kurtz Field', - state: 'MN', - lat: 46.54899, - lon: -93.67573, - }, - KANE: { - id: 'KANE', - city: 'Minneapolis / Blaine', - state: 'MN', - lat: 45.14258, - lon: -93.21272, - }, - KAQP: { - id: 'KAQP', - city: 'Appleton Municipal Airport', - state: 'MN', - lat: 45.22488, - lon: -96.00412, - }, - KAUM: { - id: 'KAUM', - city: 'Austin Municipal', - state: 'MN', - lat: 43.66667, - lon: -92.93333, - }, - KAXN: { - id: 'KAXN', - city: 'Alexandria, Chandler Field', - state: 'MN', - lat: 45.8686099, - lon: -95.39417, - }, - KBBB: { - id: 'KBBB', - city: 'Benson Municipal Airport', - state: 'MN', - lat: 45.3309799, - lon: -95.64692, - }, - KBDE: { - id: 'KBDE', - city: 'Baudette International Airport', - state: 'MN', - lat: 48.72605, - lon: -94.61215, - }, - KBDH: { - id: 'KBDH', - city: 'Willmar Municipal Airport - John L. Rice Field', - state: 'MN', - lat: 45.11113, - lon: -95.1258299, - }, - KBJI: { - id: 'KBJI', - city: 'Bemidji', - state: 'MN', - lat: 47.50762, - lon: -94.92783, - }, - KBRD: { - id: 'KBRD', - city: 'Brainerd - Crow Wing County Airport', - state: 'MN', - lat: 46.40205, - lon: -94.12734, - }, - KCBG: { - id: 'KCBG', - city: 'Cambridge Municipal Airport', - state: 'MN', - lat: 45.56275, - lon: -93.26436, - }, - KCDD: { - id: 'KCDD', - city: 'Crane Lake - Scotts Seaplane Base', - state: 'MN', - lat: 48.26014, - lon: -92.47485, - }, - KCFE: { - id: 'KCFE', - city: 'Buffalo, Buffalo Municipal Airport', - state: 'MN', - lat: 45.15889, - lon: -93.84306, - }, - KCKC: { - id: 'KCKC', - city: 'Grand Marais/Cook County Airport', - state: 'MN', - lat: 47.83665, - lon: -90.3864399, - }, - KCKN: { - id: 'KCKN', - city: 'Crookston Municipal Field', - state: 'MN', - lat: 47.84042, - lon: -96.6200999, - }, - KCNB: { - id: 'KCNB', - city: 'Canby Airfield', - state: 'MN', - lat: 44.7295, - lon: -96.266, - }, - KCOQ: { - id: 'KCOQ', - city: 'Cloquet Carlton County Airport', - state: 'MN', - lat: 46.69869, - lon: -92.5034, - }, - KCQM: { - id: 'KCQM', - city: 'Cook Municipal Airport', - state: 'MN', - lat: 47.81997, - lon: -92.68169, - }, - KDLH: { - id: 'KDLH', - city: 'Duluth International Airport', - state: 'MN', - lat: 46.84347, - lon: -92.1866, - }, - KDTL: { - id: 'KDTL', - city: 'Detroit Lakes Airport-Wething Field', - state: 'MN', - lat: 46.8285399, - lon: -95.88567, - }, - KDVP: { - id: 'KDVP', - city: 'Slayton Municipal Airport', - state: 'MN', - lat: 43.99055, - lon: -95.78102, - }, - KDXX: { - id: 'KDXX', - city: 'Madison, Madison-Lac Qui Parle County Airport', - state: 'MN', - lat: 44.9839399, - lon: -96.1788399, - }, - KDYT: { - id: 'KDYT', - city: 'Duluth - Sky Harbor Airport', - state: 'MN', - lat: 46.72452, - lon: -92.0444799, - }, - KBIX: { - id: 'KBIX', - city: 'Keesler Air Force Base / Biloxi', - state: 'MS', - lat: 30.41667, - lon: -88.91667, - }, - KCBM: { - id: 'KCBM', - city: 'Columbus Air Force Base', - state: 'MS', - lat: 33.65, - lon: -88.45, - }, - KCKM: { - id: 'KCKM', - city: 'Fletcher Field, Clarksdale', - state: 'MS', - lat: 34.2997, - lon: -90.5123, - }, - KCRX: { - id: 'KCRX', - city: 'Corinth', - state: 'MS', - lat: 34.915, - lon: -88.6035, - }, - KGLH: { - id: 'KGLH', - city: 'Greenville, Mid Delta Regional Airport', - state: 'MS', - lat: 33.48278, - lon: -90.98556, - }, - KGPT: { - id: 'KGPT', - city: 'Gulfport - Gulfport-Biloxi International Airport', - state: 'MS', - lat: 30.41194, - lon: -89.08083, - }, - KGTR: { - id: 'KGTR', - city: 'Columbus/West Point/Starkville, Golden Triangle Regional Airport', - state: 'MS', - lat: 33.45, - lon: -88.58333, - }, - KGWO: { - id: 'KGWO', - city: 'Greenwood, Greenwood-LeFlore Airport', - state: 'MS', - lat: 33.4925, - lon: -90.0836099, - }, - KHBG: { - id: 'KHBG', - city: 'Hattiesburg, Bobby L Chain Municipal Airport', - state: 'MS', - lat: 31.26945, - lon: -89.25613, - }, - KHEZ: { - id: 'KHEZ', - city: 'Natchez, Hardy-Anders Field Natchez-Adams County Airport', - state: 'MS', - lat: 31.61593, - lon: -91.29724, - }, - KHKS: { - id: 'KHKS', - city: 'Jackson, Hawkins Field Airport', - state: 'MS', - lat: 32.33472, - lon: -90.2225, - }, - KHSA: { - id: 'KHSA', - city: 'Bay St. Louis, Stennis International Airport', - state: 'MS', - lat: 30.36778, - lon: -89.45472, - }, - KIKT: { - id: 'KIKT', - city: 'Nakika Subsea Development Platform', - state: 'MS', - lat: 28.5208, - lon: -88.2889, - }, - KJAN: { - id: 'KJAN', - city: 'Jackson, Jackson International Airport', - state: 'MS', - lat: 32.3197199, - lon: -90.0775, - }, - KJVW: { - id: 'KJVW', - city: 'JB Williams Airport', - state: 'MS', - lat: 32.30447, - lon: -90.41053, - }, - KLMS: { - id: 'KLMS', - city: 'Louisville/Winston County Airport', - state: 'MS', - lat: 33.14599, - lon: -89.06245, - }, - KLUL: { - id: 'KLUL', - city: 'LAUREL/NOBLE FIELD', - state: 'MS', - lat: 31.67, - lon: -89.17, - }, - KMBO: { - id: 'KMBO', - city: 'Madison Bruce Campbell Field Airport', - state: 'MS', - lat: 32.4384, - lon: -90.1014, - }, - KMCB: { - id: 'KMCB', - city: 'McComb, McComb / Pike County / John E Lewis Field Airport', - state: 'MS', - lat: 31.17833, - lon: -90.47194, - }, - KMEI: { - id: 'KMEI', - city: 'Meridian, Key Field', - state: 'MS', - lat: 32.33806, - lon: -88.74778, - }, - KMJD: { - id: 'KMJD', - city: 'Picayune Municipal Airport', - state: 'MS', - lat: 30.48747, - lon: -89.65119, - }, - KMPE: { - id: 'KMPE', - city: 'Philadelphia Municipal Airport', - state: 'MS', - lat: 32.79921, - lon: -89.12599, - }, - KNJW: { - id: 'KNJW', - city: 'Meridian, Joe Williams Naval Outlying Field', - state: 'MS', - lat: 32.79611, - lon: -88.83167, - }, - KNMM: { - id: 'KNMM', - city: 'Meridian, Meridian Naval Air Station - McCain Field', - state: 'MS', - lat: 32.55194, - lon: -88.55528, - }, - KOLV: { - id: 'KOLV', - city: 'Olive Branch, Olive Branch Airport', - state: 'MS', - lat: 34.97889, - lon: -89.78694, - }, - KPIB: { - id: 'KPIB', - city: 'Hattiesburg/Laurel, Hattiesburg-Laurel Regional Airport', - state: 'MS', - lat: 31.46667, - lon: -89.33333, - }, - KPMU: { - id: 'KPMU', - city: 'Batesville Panola County', - state: 'MS', - lat: 34.3635, - lon: -89.8929, - }, - KPQL: { - id: 'KPQL', - city: 'Moss Point - Trent Lott International Airport', - state: 'MS', - lat: 30.46305, - lon: -88.53155, - }, - KRNV: { - id: 'KRNV', - city: 'Cleveland Municipal Airport', - state: 'MS', - lat: 33.7611, - lon: -90.7579, - }, - KSTF: { - id: 'KSTF', - city: 'George M Bryan Airport, Starkville', - state: 'MS', - lat: 33.4331, - lon: -88.8486, - }, - KTUP: { - id: 'KTUP', - city: 'Tupelo, Tupelo Regional Airport', - state: 'MS', - lat: 34.26806, - lon: -88.77, - }, - KUOX: { - id: 'KUOX', - city: 'Oxford, University-Oxford Airport', - state: 'MS', - lat: 34.38444, - lon: -89.53556, - }, - KUTA: { - id: 'KUTA', - city: 'Tunica, Tunica Municipal Airport', - state: 'MS', - lat: 34.68083, - lon: -90.34639, - }, - KVKS: { - id: 'KVKS', - city: 'Vicksburg Municipal', - state: 'MS', - lat: 32.23333, - lon: -90.93333, - }, - KBDL: { - id: 'KBDL', - city: 'Windsor Locks, Bradley International Airport', - state: 'CT', - lat: 41.93806, - lon: -72.6825, - }, - KBDR: { - id: 'KBDR', - city: 'Bridgeport, Sikorsky Memorial Airport', - state: 'CT', - lat: 41.16421, - lon: -73.12663, - }, - KDXR: { - id: 'KDXR', - city: 'Danbury, Danbury Municipal Airport', - state: 'CT', - lat: 41.37167, - lon: -73.48444, - }, - KGON: { - id: 'KGON', - city: 'Groton / New London, Groton / New London Airport', - state: 'CT', - lat: 41.3275, - lon: -72.04944, - }, - KHFD: { - id: 'KHFD', - city: 'Hartford, Hartford-Brainard Airport', - state: 'CT', - lat: 41.735, - lon: -72.65167, - }, - KHVN: { - id: 'KHVN', - city: 'New Haven, Tweed-New Haven Airport', - state: 'CT', - lat: 41.26389, - lon: -72.88722, - }, - KIJD: { - id: 'KIJD', - city: 'Willimantic, Windham Airport', - state: 'CT', - lat: 41.74194, - lon: -72.18361, - }, - KLZD: { - id: 'KLZD', - city: 'DANIELSON', - state: 'CT', - lat: 41.8197, - lon: -71.90096, - }, - KMMK: { - id: 'KMMK', - city: 'Meriden, Meriden Markham Municipal Airport', - state: 'CT', - lat: 41.50972, - lon: -72.82778, - }, - KOXC: { - id: 'KOXC', - city: 'Oxford, Waterbury-Oxford Airport', - state: 'CT', - lat: 41.48333, - lon: -73.13333, - }, - KSNC: { - id: 'KSNC', - city: 'Chester, Chester Airport', - state: 'CT', - lat: 41.38389, - lon: -72.50583, - }, - KAFK: { - id: 'KAFK', - city: 'Nebraska City, Nebraska City Municipal Airport', - state: 'NE', - lat: 40.6, - lon: -95.85, - }, - KAHQ: { - id: 'KAHQ', - city: 'Wahoo', - state: 'NE', - lat: 41.2406, - lon: -96.5946, - }, - KAIA: { - id: 'KAIA', - city: 'Alliance, Alliance Municipal Airport', - state: 'NE', - lat: 42.05722, - lon: -102.8, - }, - KANW: { - id: 'KANW', - city: 'Ainsworth Regional Airport', - state: 'NE', - lat: 42.57484, - lon: -99.99832, - }, - KAUH: { - id: 'KAUH', - city: 'Aurora, Aurora Municipal Airport', - state: 'NE', - lat: 40.89389, - lon: -97.99444, - }, - KBBW: { - id: 'KBBW', - city: 'Broken Bow, Broken Bow Municipal Airport', - state: 'NE', - lat: 41.43333, - lon: -99.65, - }, - KBFF: { - id: 'KBFF', - city: 'Scottsbluff, Heilig Field', - state: 'NE', - lat: 41.86694, - lon: -103.58583, - }, - KBIE: { - id: 'KBIE', - city: 'Beatrice Municipal', - state: 'NE', - lat: 40.3, - lon: -96.75, - }, - KBTA: { - id: 'KBTA', - city: 'Blair Municipal Airport', - state: 'NE', - lat: 41.4148, - lon: -96.109, - }, - KBVN: { - id: 'KBVN', - city: 'Albion Municipal Airport', - state: 'NE', - lat: 41.73016, - lon: -98.05453, - }, - KCDR: { - id: 'KCDR', - city: 'Chadron, Chadron Municipal Airport', - state: 'NE', - lat: 42.8375, - lon: -103.09528, - }, - KCSB: { - id: 'KCSB', - city: 'Cambridge Municipal Airport', - state: 'NE', - lat: 40.3065799, - lon: -100.16207, - }, - KEAR: { - id: 'KEAR', - city: 'Kearney, Kearney Municipal Airport', - state: 'NE', - lat: 40.73333, - lon: -99, - }, - KFET: { - id: 'KFET', - city: 'Fremont Municipal Airport', - state: 'NE', - lat: 41.45, - lon: -96.51667, - }, - KFNB: { - id: 'KFNB', - city: 'Falls City, Brenner Field Airport', - state: 'NE', - lat: 40.07889, - lon: -95.5919399, - }, - KGGF: { - id: 'KGGF', - city: 'Grant Municipal Airport', - state: 'NE', - lat: 40.87066, - lon: -101.73388, - }, - KGRI: { - id: 'KGRI', - city: 'Grand Island, Central Nebraska Regional Airport', - state: 'NE', - lat: 40.9583299, - lon: -98.3125, - }, - KGRN: { - id: 'KGRN', - city: 'Gordon Municipal', - state: 'NE', - lat: 42.8, - lon: -102.16667, - }, - KHDE: { - id: 'KHDE', - city: 'Brewster Field Airport', - state: 'NE', - lat: 40.45, - lon: -99.33333, - }, - KHJH: { - id: 'KHJH', - city: 'Hebron, Hebron Municipal Airport', - state: 'NE', - lat: 40.15222, - lon: -97.58694, - }, - KHSI: { - id: 'KHSI', - city: 'Hastings, Hastings Municipal Airport', - state: 'NE', - lat: 40.60056, - lon: -98.42583, - }, - KIBM: { - id: 'KIBM', - city: 'Kimball, Kimball Municipal Airport/Robert E Arraj Field', - state: 'NE', - lat: 41.18333, - lon: -103.66667, - }, - KIML: { - id: 'KIML', - city: 'Imperial, Imperial Municipal Airport', - state: 'NE', - lat: 40.51667, - lon: -101.61667, - }, - KJYR: { - id: 'KJYR', - city: 'York, York Municipal Airport', - state: 'NE', - lat: 40.89667, - lon: -97.62278, - }, - KLBF: { - id: 'KLBF', - city: 'North Platte, North Platte Regional Airport', - state: 'NE', - lat: 41.12194, - lon: -100.66833, - }, - KLCG: { - id: 'KLCG', - city: 'Wayne, Wayne Municipal Airport', - state: 'NE', - lat: 42.24167, - lon: -96.98139, - }, - KLNK: { - id: 'KLNK', - city: 'Lincoln, Lincoln Municipal Airport', - state: 'NE', - lat: 40.83111, - lon: -96.7644399, - }, - KLXN: { - id: 'KLXN', - city: 'Lexington, Jim Kelly Field Airport', - state: 'NE', - lat: 40.79111, - lon: -99.77722, - }, - KMCK: { - id: 'KMCK', - city: 'McCook, McCook Municipal Airport', - state: 'NE', - lat: 40.20306, - lon: -100.58833, - }, - KMLE: { - id: 'KMLE', - city: 'Omaha, Millard Airport', - state: 'NE', - lat: 41.19583, - lon: -96.1122199, - }, - KODX: { - id: 'KODX', - city: 'Ord, Evelyn Sharp Field Airport', - state: 'NE', - lat: 41.62417, - lon: -98.9525, - }, - KOFF: { - id: 'KOFF', - city: 'Omaha / Offutt Air Force Base', - state: 'NE', - lat: 41.11667, - lon: -95.9, - }, - KOFK: { - id: 'KOFK', - city: 'Norfolk, Stefan Memorial Airport', - state: 'NE', - lat: 41.9805599, - lon: -97.43694, - }, - KOGA: { - id: 'KOGA', - city: 'Ogallala, Searle Field Airport', - state: 'NE', - lat: 41.11972, - lon: -101.76889, - }, - KOLU: { - id: 'KOLU', - city: 'Columbus, Columbus Municipal Airport', - state: 'NE', - lat: 41.45, - lon: -97.33333, - }, - KOMA: { - id: 'KOMA', - city: 'Omaha - Eppley Airfield', - state: 'NE', - lat: 41.3119, - lon: -95.90185, - }, - KONL: { - id: 'KONL', - city: "O'Neill / Baker Field", - state: 'NE', - lat: 42.46667, - lon: -98.68333, - }, - KPMV: { - id: 'KPMV', - city: 'Plattsmouth, Plattsmouth Municipal Airport', - state: 'NE', - lat: 40.95, - lon: -95.9177799, - }, - KSNY: { - id: 'KSNY', - city: 'Sidney, Sidney Municipal Airport', - state: 'NE', - lat: 41.09944, - lon: -102.98556, - }, - KTIF: { - id: 'KTIF', - city: 'Thedford, Thomas County Airport', - state: 'NE', - lat: 41.96194, - lon: -100.56889, - }, - KTQE: { - id: 'KTQE', - city: 'Tekamah, Tekamah Municipal Airport', - state: 'NE', - lat: 41.76694, - lon: -96.17778, - }, - KVTN: { - id: 'KVTN', - city: 'Valentine, Miller Field', - state: 'NE', - lat: 42.85861, - lon: -100.55139, - }, - KBTV: { - id: 'KBTV', - city: 'Burlington, Burlington International Airport', - state: 'VT', - lat: 44.46806, - lon: -73.15028, - }, - KCDA: { - id: 'KCDA', - city: 'Caledonia County Airport', - state: 'VT', - lat: 44.5691142, - lon: -72.0179789, - }, - KDDH: { - id: 'KDDH', - city: 'Bennington Morse State Airport', - state: 'VT', - lat: 42.89355, - lon: -73.2486, - }, - KEFK: { - id: 'KEFK', - city: 'Northeast Kingdom International Airport', - state: 'VT', - lat: 44.88846, - lon: -72.23593, - }, - KFSO: { - id: 'KFSO', - city: 'Franklin County State Airport', - state: 'VT', - lat: 44.9402807, - lon: -73.09746, - }, - KMPV: { - id: 'KMPV', - city: 'Barre / Montpelier, Knapp State Airport', - state: 'VT', - lat: 44.20472, - lon: -72.56611, - }, - KMVL: { - id: 'KMVL', - city: 'Morrisville-Stowe State Airport', - state: 'VT', - lat: 44.53589, - lon: -72.6162499, - }, - KRUT: { - id: 'KRUT', - city: 'Rutland-Southern Vermont Regional Airport', - state: 'VT', - lat: 43.53333, - lon: -72.95, - }, - KVSF: { - id: 'KVSF', - city: 'Springfield, Hartness State Springfield Airport', - state: 'VT', - lat: 43.3425, - lon: -72.52167, - }, - KAIZ: { - id: 'KAIZ', - city: 'Kaiser Lake Ozark, Lee C Fine Memorial Airport', - state: 'MO', - lat: 38.1, - lon: -92.55, - }, - KBBG: { - id: 'KBBG', - city: 'Branson', - state: 'MO', - lat: 36.5321, - lon: -93.2005, - }, - KCDJ: { - id: 'KCDJ', - city: 'Chillicothe, Chillicothe Agri-Science Center', - state: 'MO', - lat: 39.81667, - lon: -93.58333, - }, - KCGI: { - id: 'KCGI', - city: 'Cape Girardeau, Cape Girardeau Regional Airport', - state: 'MO', - lat: 37.22556, - lon: -89.5783299, - }, - KCOU: { - id: 'KCOU', - city: 'Columbia, Columbia Regional Airport', - state: 'MO', - lat: 38.81694, - lon: -92.21833, - }, - KDMO: { - id: 'KDMO', - city: 'Sedalia, Sedalia Memorial Airport', - state: 'MO', - lat: 38.71222, - lon: -93.17444, - }, - KEOS: { - id: 'KEOS', - city: 'NEOSHOAIRPORT', - state: 'MO', - lat: 36.8108, - lon: -94.39169, - }, - KEVU: { - id: 'KEVU', - city: 'Maryville Northwest Missouri Regional Airport', - state: 'MO', - lat: 40.3525, - lon: -94.915, - }, - KEZZ: { - id: 'KEZZ', - city: 'Cameron Memorial Airport', - state: 'MO', - lat: 39.7275599, - lon: -94.27639, - }, - KFAM: { - id: 'KFAM', - city: 'Farmington Airport', - state: 'MO', - lat: 37.76667, - lon: -90.43333, - }, - KFWB: { - id: 'KFWB', - city: 'Branson West Muni - Emerson Field', - state: 'MO', - lat: 36.6985, - lon: -93.4021999, - }, - KGLY: { - id: 'KGLY', - city: 'Clinton, MO', - state: 'MO', - lat: 38.3566, - lon: -93.6842, - }, - KGPH: { - id: 'KGPH', - city: 'Mosby Midwest National Air Center Airport', - state: 'MO', - lat: 39.3325, - lon: -94.3096, - }, - KHAE: { - id: 'KHAE', - city: 'Hannibal Regional Airport', - state: 'MO', - lat: 39.7252, - lon: -91.4439, - }, - KHFJ: { - id: 'KHFJ', - city: 'Monett', - state: 'MO', - lat: 36.9062, - lon: -94.0128, - }, - KIRK: { - id: 'KIRK', - city: 'Kirksville, Kirksville Regional Airport', - state: 'MO', - lat: 40.09722, - lon: -92.54333, - }, - KJEF: { - id: 'KJEF', - city: 'Jefferson City, Jefferson City Memorial Airport', - state: 'MO', - lat: 38.59444, - lon: -92.15583, - }, - KJLN: { - id: 'KJLN', - city: 'Joplin, Joplin Regional Airport', - state: 'MO', - lat: 37.15611, - lon: -94.5005599, - }, - KLBO: { - id: 'KLBO', - city: 'LEBANON', - state: 'MO', - lat: 37.64833, - lon: -92.6525, - }, - KAAS: { - id: 'KAAS', - city: 'Taylor County Airport', - state: 'KY', - lat: 37.35828, - lon: -85.30942, - }, - KBRY: { - id: 'KBRY', - city: 'Samuels Field Airport', - state: 'KY', - lat: 37.81433, - lon: -85.49964, - }, - KBWG: { - id: 'KBWG', - city: 'Bowling Green, Bowling Green-Warren County Regional Airport', - state: 'KY', - lat: 36.96444, - lon: -86.41944, - }, - KBYL: { - id: 'KBYL', - city: 'Williamsburg-Whitley County Airport', - state: 'KY', - lat: 36.7954099, - lon: -84.2012699, - }, - KCEY: { - id: 'KCEY', - city: 'Murray Kyle Oakley Field, KY', - state: 'KY', - lat: 36.6646, - lon: -88.3728, - }, - KCPF: { - id: 'KCPF', - city: 'Wendell H Ford Airport', - state: 'KY', - lat: 37.38736, - lon: -83.26161, - }, - KCVG: { - id: 'KCVG', - city: 'Cincinnati/Northern Kentucky International Airport', - state: 'KY', - lat: 39.04456, - lon: -84.67229, - }, - KDVK: { - id: 'KDVK', - city: 'Stuart Powell Field Airport', - state: 'KY', - lat: 37.5775751, - lon: -84.7694978, - }, - KDWU: { - id: 'KDWU', - city: 'Ashland Regional Airport', - state: 'KY', - lat: 38.5545, - lon: -82.738, - }, - KEHR: { - id: 'KEHR', - city: 'Henderson City', - state: 'KY', - lat: 37.81667, - lon: -87.68333, - }, - KEKQ: { - id: 'KEKQ', - city: 'Monticello, Wayne County Airport', - state: 'KY', - lat: 36.85528, - lon: -84.85611, - }, - KEKX: { - id: 'KEKX', - city: 'Elizabethtown Addington Field Airport', - state: 'KY', - lat: 37.686, - lon: -85.925, - }, - KFFT: { - id: 'KFFT', - city: 'Frankfort, Capital City Airport', - state: 'KY', - lat: 38.18472, - lon: -84.90333, - }, - KFGX: { - id: 'KFGX', - city: 'Flemingsburg Fleming-Mason Airport', - state: 'KY', - lat: 38.5418, - lon: -83.7434, - }, - KFTK: { - id: 'KFTK', - city: 'Fort Knox', - state: 'KY', - lat: 37.9, - lon: -85.9666699, - }, - KGDA: { - id: 'KGDA', - city: 'MARION', - state: 'KY', - lat: 37.3333, - lon: -88.1, - }, - KGLW: { - id: 'KGLW', - city: 'Glasgow, Glasgow Municipal Airport', - state: 'KY', - lat: 37.03167, - lon: -85.95361, - }, - KHOP: { - id: 'KHOP', - city: 'Fort Campbell U. S. Army Airfield', - state: 'KY', - lat: 36.66667, - lon: -87.5, - }, - KHVC: { - id: 'KHVC', - city: 'Hopkinsville-Christian County Airport', - state: 'KY', - lat: 36.8569699, - lon: -87.45508, - }, - KIOB: { - id: 'KIOB', - city: 'Mount Sterling-Montgomery County Airport', - state: 'KY', - lat: 38.0575, - lon: -83.9829, - }, - KJKL: { - id: 'KJKL', - city: 'Jackson, Carroll Airport', - state: 'KY', - lat: 37.5913899, - lon: -83.31444, - }, - KLEX: { - id: 'KLEX', - city: 'Lexington Blue Grass Airport', - state: 'KY', - lat: 38.0339, - lon: -84.6114599, - }, - KLOU: { - id: 'KLOU', - city: 'Louisville, Bowman Field Airport', - state: 'KY', - lat: 38.22778, - lon: -85.66361, - }, - KLOZ: { - id: 'KLOZ', - city: 'London, London-Corbin Airport-Magee Field', - state: 'KY', - lat: 37.08944, - lon: -84.06861, - }, - KOWB: { - id: 'KOWB', - city: 'Owensboro, Owensboro-Daviess County Airport', - state: 'KY', - lat: 37.74, - lon: -87.16667, - }, - KPAH: { - id: 'KPAH', - city: 'Paducah, Barkley Regional Airport', - state: 'KY', - lat: 37.05639, - lon: -88.77389, - }, - KPBX: { - id: 'KPBX', - city: 'Pikeville Pike County Airport and Hatcher Field', - state: 'KY', - lat: 37.5587, - lon: -82.5674, - }, - KRGA: { - id: 'KRGA', - city: 'Central Kentucky Regional Airport', - state: 'KY', - lat: 37.6308475, - lon: -84.3323372, - }, - KSDF: { - id: 'KSDF', - city: 'Louisville Muhammad Ali International Airport', - state: 'KY', - lat: 38.17406, - lon: -85.7365, - }, - KSJS: { - id: 'KSJS', - city: 'Big Sandy Regional Airport', - state: 'KY', - lat: 37.751, - lon: -82.6367, - }, - KSME: { - id: 'KSME', - city: 'Somerset, Somerset-Pulaski County - J.T. Wilson Field Airport', - state: 'KY', - lat: 37.05417, - lon: -84.615, - }, - KSYM: { - id: 'KSYM', - city: 'Clyde A. Thomas Regional Airport', - state: 'KY', - lat: 38.215, - lon: -83.5874, - }, - KTWT: { - id: 'KTWT', - city: 'Sturgis, Sturgis Municipal Airport', - state: 'KY', - lat: 37.54083, - lon: -87.9516699, - }, - KACB: { - id: 'KACB', - city: 'Bellaire, Antrim County Airport', - state: 'MI', - lat: 44.98833, - lon: -85.19833, - }, - KADG: { - id: 'KADG', - city: 'Adrian, Lenawee County Airport', - state: 'MI', - lat: 41.86778, - lon: -84.07944, - }, - KAMN: { - id: 'KAMN', - city: 'Alma, Gratiot Community Airport', - state: 'MI', - lat: 43.32194, - lon: -84.68778, - }, - KANJ: { - id: 'KANJ', - city: 'Sault Ste. Marie', - state: 'MI', - lat: 46.4794399, - lon: -84.35722, - }, - KAPN: { - id: 'KAPN', - city: 'Alpena, Alpena County Regional Airport', - state: 'MI', - lat: 45.07167, - lon: -83.56444, - }, - KARB: { - id: 'KARB', - city: 'Ann Arbor, Ann Arbor Municipal Airport', - state: 'MI', - lat: 42.22389, - lon: -83.74, - }, - KAZO: { - id: 'KAZO', - city: 'Kalamazoo/Battle Creek International Airport', - state: 'MI', - lat: 42.2283, - lon: -85.54595, - }, - KBAX: { - id: 'KBAX', - city: 'Huron County Memorial Airport', - state: 'MI', - lat: 43.77741, - lon: -82.98271, - }, - KBEH: { - id: 'KBEH', - city: 'Southwest Michigan Regional Airport', - state: 'MI', - lat: 42.12896, - lon: -86.41515, - }, - KBFA: { - id: 'KBFA', - city: 'Boyne Mountain Airport', - state: 'MI', - lat: 45.16584, - lon: -84.92411, - }, - KBIV: { - id: 'KBIV', - city: 'Holland - West Michigan Regional Airport', - state: 'MI', - lat: 42.74611, - lon: -86.09667, - }, - KBTL: { - id: 'KBTL', - city: 'Battle Creek Executive Airport', - state: 'MI', - lat: 42.31197, - lon: -85.24144, - }, - KCAD: { - id: 'KCAD', - city: 'Wexford County Airport', - state: 'MI', - lat: 44.27847, - lon: -85.4206899, - }, - KCFS: { - id: 'KCFS', - city: 'Caro, Tuscola Area Airport', - state: 'MI', - lat: 43.45861, - lon: -83.44528, - }, - KCIU: { - id: 'KCIU', - city: 'Sault Ste Marie, Chippewa County International Airport', - state: 'MI', - lat: 46.25, - lon: -84.4666699, - }, - KCMX: { - id: 'KCMX', - city: 'Houghton County Memorial Airport', - state: 'MI', - lat: 47.16597, - lon: -88.48072, - }, - KCVX: { - id: 'KCVX', - city: 'Charlevoix, Charlevoix Municipal Airport', - state: 'MI', - lat: 45.30472, - lon: -85.27472, - }, - KALX: { - id: 'KALX', - city: 'Alexander City, Thomas C Russell Field Airport', - state: 'AL', - lat: 32.91472, - lon: -85.96278, - }, - KANB: { - id: 'KANB', - city: 'Anniston Metro Airport', - state: 'AL', - lat: 33.59045, - lon: -85.84789, - }, - KASN: { - id: 'KASN', - city: 'Talladega Municipal Airport', - state: 'AL', - lat: 33.5695, - lon: -86.0512, - }, - KAUO: { - id: 'KAUO', - city: 'Auburn-Opelika Airport', - state: 'AL', - lat: 32.61667, - lon: -85.43333, - }, - KBFM: { - id: 'KBFM', - city: 'Mobile, Mobile Downtown Airport', - state: 'AL', - lat: 30.61389, - lon: -88.0633299, - }, - KBFZ: { - id: 'KBFZ', - city: 'Albertville Regional Airport-Thomas J Brumlik Field', - state: 'AL', - lat: 34.22911, - lon: -86.25575, - }, - KBHM: { - id: 'KBHM', - city: 'Birmingham, Birmingham International Airport', - state: 'AL', - lat: 33.56556, - lon: -86.745, - }, - KCMD: { - id: 'KCMD', - city: 'Cullman Regional Folsom Field', - state: 'AL', - lat: 34.2687, - lon: -86.858, - }, - KCQF: { - id: 'KCQF', - city: 'Sonny Callahan Airport', - state: 'AL', - lat: 30.461, - lon: -87.877, - }, - KDCU: { - id: 'KDCU', - city: 'Decatur, Pryor Field', - state: 'AL', - lat: 34.65806, - lon: -86.94333, - }, - KDHN: { - id: 'KDHN', - city: 'Dothan, Dothan Regional Airport', - state: 'AL', - lat: 31.32139, - lon: -85.44972, - }, - KDYA: { - id: 'KDYA', - city: 'Demopolis Municipal Airport', - state: 'AL', - lat: 32.4638, - lon: -87.9541, - }, - KEDN: { - id: 'KEDN', - city: 'Enterprise Municipal Airport', - state: 'AL', - lat: 31.2982, - lon: -85.9048, - }, - KEET: { - id: 'KEET', - city: 'Alabaster, Shelby County Airport', - state: 'AL', - lat: 33.17833, - lon: -86.78167, - }, - KEKY: { - id: 'KEKY', - city: 'Bessemer Airport', - state: 'AL', - lat: 33.3126, - lon: -86.9263, - }, - KEUF: { - id: 'KEUF', - city: 'Eufaula Municipal Airport', - state: 'AL', - lat: 31.951, - lon: -85.129, - }, - KGAD: { - id: 'KGAD', - city: 'Gadsden, Gadsden Municipal Airport', - state: 'AL', - lat: 33.96667, - lon: -86.08333, - }, - KGZH: { - id: 'KGZH', - city: 'Evergreen, Middleton Field', - state: 'AL', - lat: 31.41889, - lon: -87.04806, - }, - KHDL: { - id: 'KHDL', - city: 'Headland Municipal Airport', - state: 'AL', - lat: 31.36414, - lon: -85.31253, - }, - KHEY: { - id: 'KHEY', - city: 'Hanchey AHP / Ozark', - state: 'AL', - lat: 31.35, - lon: -85.66667, - }, - KHSV: { - id: 'KHSV', - city: 'Huntsville, Huntsville International / Jones Field', - state: 'AL', - lat: 34.64361, - lon: -86.78556, - }, - KHUA: { - id: 'KHUA', - city: 'Redstone Airfield', - state: 'AL', - lat: 34.6786, - lon: -86.6847, - }, - KJFX: { - id: 'KJFX', - city: 'Jasper Walker County Airport & Bevill Field', - state: 'AL', - lat: 33.902, - lon: -87.31417, - }, - KJKA: { - id: 'KJKA', - city: 'Jack Edwards Airport', - state: 'AL', - lat: 30.2896, - lon: -87.6718, - }, - KLOR: { - id: 'KLOR', - city: 'Fort Rucker, Lowe Army Heliport', - state: 'AL', - lat: 31.35889, - lon: -85.74833, - }, - KMDQ: { - id: 'KMDQ', - city: 'Huntsville, Madison County Executive Airport', - state: 'AL', - lat: 34.86139, - lon: -86.55722, - }, - KMGM: { - id: 'KMGM', - city: 'Montgomery, Dannelly Field', - state: 'AL', - lat: 32.30028, - lon: -86.40611, - }, - KMOB: { - id: 'KMOB', - city: 'Mobile, Mobile Regional Airport', - state: 'AL', - lat: 30.68833, - lon: -88.24556, - }, - KMSL: { - id: 'KMSL', - city: 'Muscle Shoals, North West Alabama Regional Airport', - state: 'AL', - lat: 34.74389, - lon: -87.59944, - }, - KMXF: { - id: 'KMXF', - city: 'Maxwell Air Force Base / Montgomery', - state: 'AL', - lat: 32.38333, - lon: -86.36667, - }, - KOZR: { - id: 'KOZR', - city: 'Cairns Army Air Field / Ozark', - state: 'AL', - lat: 31.27672, - lon: -85.71099, - }, - KPLR: { - id: 'KPLR', - city: 'St Clair County Airport', - state: 'AL', - lat: 33.5588, - lon: -86.2491, - }, - KPRN: { - id: 'KPRN', - city: 'Mac Crenshaw Memorial Airport', - state: 'AL', - lat: 31.8457, - lon: -86.6107, - }, - KSCD: { - id: 'KSCD', - city: 'Merkel Field Sylacauga Municipal Airport', - state: 'AL', - lat: 33.1718, - lon: -86.3055, - }, - KSEM: { - id: 'KSEM', - city: 'Craig Field / Selma', - state: 'AL', - lat: 32.35, - lon: -86.98333, - }, - KSXS: { - id: 'KSXS', - city: 'SCHELL AHP', - state: 'AL', - lat: 31.35, - lon: -85.85, - }, - KTCL: { - id: 'KTCL', - city: 'Tuscaloosa Regional Airport', - state: 'AL', - lat: 33.21215, - lon: -87.61554, - }, - KTOI: { - id: 'KTOI', - city: 'Troy, Troy Municipal Airport', - state: 'AL', - lat: 31.86056, - lon: -86.01222, - }, - KAFN: { - id: 'KAFN', - city: 'Jaffrey Airport-Silver Ranch', - state: 'NH', - lat: 42.8066699, - lon: -72.00127, - }, - KASH: { - id: 'KASH', - city: 'Nashua - Boire Field Airport', - state: 'NH', - lat: 42.77981, - lon: -71.51409, - }, - KBML: { - id: 'KBML', - city: 'Berlin, Berlin Municipal Airport', - state: 'NH', - lat: 44.57611, - lon: -71.17861, - }, - KCON: { - id: 'KCON', - city: 'Concord Municipal Airport', - state: 'NH', - lat: 43.20489, - lon: -71.50257, - }, - KDAW: { - id: 'KDAW', - city: 'Rochester - Skyhaven Airport', - state: 'NH', - lat: 43.27939, - lon: -70.92426, - }, - KEEN: { - id: 'KEEN', - city: 'Keene, Dillant-Hopkins Airport', - state: 'NH', - lat: 42.9, - lon: -72.26667, - }, - KHIE: { - id: 'KHIE', - city: 'Whitefield - Mount Washington Regional Airport', - state: 'NH', - lat: 44.36595, - lon: -71.55218, - }, - KLCI: { - id: 'KLCI', - city: 'Laconia, Laconia Municipal Airport', - state: 'NH', - lat: 43.56667, - lon: -71.41667, - }, - KLEB: { - id: 'KLEB', - city: 'Lebanon Municipal Airport', - state: 'NH', - lat: 43.6271, - lon: -72.30537, - }, - KMHT: { - id: 'KMHT', - city: 'Manchester Airport', - state: 'NH', - lat: 42.92964, - lon: -71.43559, - }, - KMWN: { - id: 'KMWN', - city: 'Mount Washington', - state: 'NH', - lat: 44.27086, - lon: -71.30337, - }, - KPSM: { - id: 'KPSM', - city: 'Pease Air Force Base / Portsmouth', - state: 'NH', - lat: 43.0833299, - lon: -70.81667, - }, - PHBK: { - id: 'PHBK', - city: 'Kekaha, Pacific Missile Test Facility Barking Sands', - state: 'HI', - lat: 22.03639, - lon: -159.78639, - }, - PHHI: { - id: 'PHHI', - city: 'Wheeler Air Force Base / Oahu', - state: 'HI', - lat: 21.48333, - lon: -158.03333, - }, - PHHN: { - id: 'PHHN', - city: 'HANA', - state: 'HI', - lat: 20.79563, - lon: -156.01444, - }, - PHJR: { - id: 'PHJR', - city: 'Oahu, Kalaeloa Airport', - state: 'HI', - lat: 21.30833, - lon: -158.06806, - }, - PHKO: { - id: 'PHKO', - city: 'Kailua / Kona, Keahole Airport', - state: 'HI', - lat: 19.74083, - lon: -156.05056, - }, - PHLI: { - id: 'PHLI', - city: 'Lihue, Lihue Airport', - state: 'HI', - lat: 21.98389, - lon: -159.3411099, - }, - PHMK: { - id: 'PHMK', - city: 'Kaunakakai, Molokai Airport', - state: 'HI', - lat: 21.15, - lon: -157.1, - }, - PHMU: { - id: 'PHMU', - city: 'KAMUELA', - state: 'HI', - lat: 20.00133, - lon: -155.66817, - }, - PHNG: { - id: 'PHNG', - city: 'Kaneohe, Marine Corps Air Station', - state: 'HI', - lat: 21.45389, - lon: -157.76556, - }, - PHNL: { - id: 'PHNL', - city: 'Daniel K Inouye International Airport', - state: 'HI', - lat: 21.3275, - lon: -157.94306, - }, - PHNY: { - id: 'PHNY', - city: 'Lanai City, Lanai Airport', - state: 'HI', - lat: 20.78556, - lon: -156.95139, - }, - PHOG: { - id: 'PHOG', - city: 'Kahului, Kahului Airport', - state: 'HI', - lat: 20.8924999, - lon: -156.43694, - }, - PHSF: { - id: 'PHSF', - city: 'Bradshaw Army Air Field / Hawaii', - state: 'HI', - lat: 19.78333, - lon: -155.55, - }, - PHTO: { - id: 'PHTO', - city: 'Hilo, Hilo International Airport', - state: 'HI', - lat: 19.72222, - lon: -155.0558299, - }, - KADU: { - id: 'KADU', - city: 'Audubon, Audubon County Airport', - state: 'IA', - lat: 41.70111, - lon: -94.92028, - }, - KAIO: { - id: 'KAIO', - city: 'Atlantic', - state: 'IA', - lat: 41.4, - lon: -95.05, - }, - KALO: { - id: 'KALO', - city: 'Waterloo, Waterloo Municipal Airport', - state: 'IA', - lat: 42.55444, - lon: -92.40111, - }, - KAMW: { - id: 'KAMW', - city: 'Ames, Ames Municipal Airport', - state: 'IA', - lat: 41.99056, - lon: -93.6188899, - }, - KAWG: { - id: 'KAWG', - city: 'Washington', - state: 'IA', - lat: 41.28333, - lon: -91.66667, - }, - KAXA: { - id: 'KAXA', - city: 'Algona', - state: 'IA', - lat: 43.0833299, - lon: -94.26667, - }, - KBNW: { - id: 'KBNW', - city: 'Boone Municipal', - state: 'IA', - lat: 42.05, - lon: -93.85, - }, - KBRL: { - id: 'KBRL', - city: 'Burlington Regional Airport', - state: 'IA', - lat: 40.77293, - lon: -91.12543, - }, - KCAV: { - id: 'KCAV', - city: 'Clarion', - state: 'IA', - lat: 42.75, - lon: -93.76667, - }, - KCBF: { - id: 'KCBF', - city: 'Council Bluffs', - state: 'IA', - lat: 41.2612499, - lon: -95.7604, - }, - KCCY: { - id: 'KCCY', - city: 'Charles City', - state: 'IA', - lat: 43.06667, - lon: -92.61667, - }, - KCID: { - id: 'KCID', - city: 'Cedar Rapids Airport', - state: 'IA', - lat: 41.88295, - lon: -91.72456, - }, - KCIN: { - id: 'KCIN', - city: 'Carroll', - state: 'IA', - lat: 42.05, - lon: -94.78333, - }, - KCKP: { - id: 'KCKP', - city: 'Cherokee, Cherokee Municipal Airport', - state: 'IA', - lat: 42.73167, - lon: -95.55583, - }, - KCNC: { - id: 'KCNC', - city: 'Chariton', - state: 'IA', - lat: 41.03333, - lon: -93.36667, - }, - KCSQ: { - id: 'KCSQ', - city: 'Creston Municipal Airport', - state: 'IA', - lat: 41.0188599, - lon: -94.361, - }, - KCWI: { - id: 'KCWI', - city: 'Clinton Municipal Airport', - state: 'IA', - lat: 41.82954, - lon: -90.33279, - }, - KDBQ: { - id: 'KDBQ', - city: 'Dubuque Regional Airport', - state: 'IA', - lat: 42.39837, - lon: -90.7091, - }, - KDEH: { - id: 'KDEH', - city: 'Decorah', - state: 'IA', - lat: 43.28333, - lon: -91.73333, - }, - KDNS: { - id: 'KDNS', - city: 'Denison', - state: 'IA', - lat: 41.98333, - lon: -95.38333, - }, - KDSM: { - id: 'KDSM', - city: 'Des Moines International Airport', - state: 'IA', - lat: 41.53399, - lon: -93.65307, - }, - KDVN: { - id: 'KDVN', - city: 'Davenport Municipal Airport', - state: 'IA', - lat: 41.61338, - lon: -90.59479, - }, - KEBS: { - id: 'KEBS', - city: 'Webster City Municipal Airport', - state: 'IA', - lat: 42.43724, - lon: -93.87237, - }, - KEOK: { - id: 'KEOK', - city: 'Keokuk Municipal Airport', - state: 'IA', - lat: 40.46149, - lon: -91.42739, - }, - KEST: { - id: 'KEST', - city: 'Estherville, Estherville Municipal Airport', - state: 'IA', - lat: 43.40111, - lon: -94.74722, - }, - KFFL: { - id: 'KFFL', - city: 'Fairfield Municipal Airport', - state: 'IA', - lat: 41.0521, - lon: -91.98339, - }, - KFOD: { - id: 'KFOD', - city: 'Fort Dodge', - state: 'IA', - lat: 42.55, - lon: -94.18333, - }, - KFSW: { - id: 'KFSW', - city: 'Fort Madison Municipal Airport', - state: 'IA', - lat: 40.66154, - lon: -91.32672, - }, - KFXY: { - id: 'KFXY', - city: 'Forest City Municipal Airport', - state: 'IA', - lat: 43.235, - lon: -93.624, - }, - KGGI: { - id: 'KGGI', - city: 'Grinnell Municipal Airfield', - state: 'IA', - lat: 41.7092, - lon: -92.7349, - }, - KHNR: { - id: 'KHNR', - city: 'Harlan, Harlan Municipal Airport', - state: 'IA', - lat: 41.58444, - lon: -95.33972, - }, - KHPT: { - id: 'KHPT', - city: 'Hampton Municipal Airport', - state: 'IA', - lat: 42.72369, - lon: -93.22633, - }, - KICL: { - id: 'KICL', - city: 'Schenck Field Airport', - state: 'IA', - lat: 40.72421, - lon: -95.02224, - }, - KIFA: { - id: 'KIFA', - city: 'Iowa Falls Municipal Airport', - state: 'IA', - lat: 42.4709999, - lon: -93.27, - }, - KIIB: { - id: 'KIIB', - city: 'Independence, Independence Municipal Airport', - state: 'IA', - lat: 42.45, - lon: -91.93333, - }, - KIKV: { - id: 'KIKV', - city: 'Ankeny Regional Airport', - state: 'IA', - lat: 41.68782, - lon: -93.56944, - }, - KIOW: { - id: 'KIOW', - city: 'Iowa City Municipal Airport', - state: 'IA', - lat: 41.6394499, - lon: -91.5445, - }, - KLRJ: { - id: 'KLRJ', - city: 'Le Mars Municipal Airport', - state: 'IA', - lat: 42.77478, - lon: -96.19239, - }, - KLWD: { - id: 'KLWD', - city: 'Lamoni, Lamoni Municipal Airport', - state: 'IA', - lat: 40.63056, - lon: -93.90083, - }, - KMCW: { - id: 'KMCW', - city: 'Mason City Municipal Airport', - state: 'IA', - lat: 43.15442, - lon: -93.32607, - }, - KMIW: { - id: 'KMIW', - city: 'Marshalltown, Marshalltown Municipal Airport', - state: 'IA', - lat: 42.11056, - lon: -92.91611, - }, - KMPZ: { - id: 'KMPZ', - city: 'Mount Pleasant, Mount Pleasant Municipal Airport', - state: 'IA', - lat: 40.94667, - lon: -91.51111, - }, - KMUT: { - id: 'KMUT', - city: 'Muscatine', - state: 'IA', - lat: 41.36667, - lon: -91.15, - }, - KMXO: { - id: 'KMXO', - city: 'Monticello Regional Airport', - state: 'IA', - lat: 42.22035, - lon: -91.16041, - }, - KOLZ: { - id: 'KOLZ', - city: 'Oelwein Municipal Airport', - state: 'IA', - lat: 42.68316, - lon: -91.97595, - }, - KOOA: { - id: 'KOOA', - city: 'Oskaloosa, Oskaloosa Municipal Airport', - state: 'IA', - lat: 41.22611, - lon: -92.49361, - }, - KOTM: { - id: 'KOTM', - city: 'Ottumwa Regional Airport', - state: 'IA', - lat: 41.10082, - lon: -92.4445099, - }, - KOXV: { - id: 'KOXV', - city: 'Knoxville', - state: 'IA', - lat: 41.3, - lon: -93.11667, - }, - KPEA: { - id: 'KPEA', - city: 'Pella, Pella Municipal Airport', - state: 'IA', - lat: 41.4, - lon: -92.93333, - }, - KPRO: { - id: 'KPRO', - city: 'Perry Municipal Airport', - state: 'IA', - lat: 41.828, - lon: -94.1598999, - }, - KRDK: { - id: 'KRDK', - city: 'Red Oak', - state: 'IA', - lat: 41.01667, - lon: -95.26667, - }, - KSDA: { - id: 'KSDA', - city: 'Shenandoah Municipal', - state: 'IA', - lat: 40.75, - lon: -95.41667, - }, - KSHL: { - id: 'KSHL', - city: 'Sheldon', - state: 'IA', - lat: 43.21667, - lon: -95.83333, - }, - KSLB: { - id: 'KSLB', - city: 'Storm Lake', - state: 'IA', - lat: 42.6, - lon: -95.23333, - }, - KSPW: { - id: 'KSPW', - city: 'Spencer Municipal Airport', - state: 'IA', - lat: 43.16825, - lon: -95.21008, - }, - KSUX: { - id: 'KSUX', - city: 'Sioux City, Sioux Gateway Airport', - state: 'IA', - lat: 42.4025, - lon: -96.38444, - }, - KSXK: { - id: 'KSXK', - city: 'Sioux County Regional Airport', - state: 'IA', - lat: 42.98583, - lon: -96.1614, - }, - KTNU: { - id: 'KTNU', - city: 'Newton Municipal Airport - Earl Johnson Field', - state: 'IA', - lat: 41.67014, - lon: -93.01902, - }, - KTVK: { - id: 'KTVK', - city: 'Centerville Municipal Airport', - state: 'IA', - lat: 40.6839, - lon: -92.901, - }, - KVTI: { - id: 'KVTI', - city: 'Vinton, Vinton Veterans Memorial Airpark Airport', - state: 'IA', - lat: 42.21861, - lon: -92.02583, - }, - KACP: { - id: 'KACP', - city: 'Oakdale, Allen Parish Airport', - state: 'LA', - lat: 30.75056, - lon: -92.68861, - }, - KAEX: { - id: 'KAEX', - city: 'Alexandria, Alexandria International Airport', - state: 'LA', - lat: 31.33472, - lon: -92.55861, - }, - KAPS: { - id: 'KAPS', - city: 'Port of South Louisiana Executive Regional Airport', - state: 'LA', - lat: 30.08747, - lon: -90.58283, - }, - KAQV: { - id: 'KAQV', - city: 'Ft. Polk - Peason Ridge', - state: 'LA', - lat: 31.4, - lon: -93.2833, - }, - KARA: { - id: 'KARA', - city: 'Acadiana Regional Airport', - state: 'LA', - lat: 30.02918, - lon: -91.88451, - }, - KASD: { - id: 'KASD', - city: 'Slidell, Slidell Airport', - state: 'LA', - lat: 30.34306, - lon: -89.82194, - }, - KATP: { - id: 'KATP', - city: 'Green Canyon 787 Atlantis', - state: 'LA', - lat: 27.195, - lon: -90.027, - }, - KBAD: { - id: 'KBAD', - city: 'Barksdale Air Force Base', - state: 'LA', - lat: 32.5, - lon: -93.66667, - }, - KBKB: { - id: 'KBKB', - city: 'Ft. Polk - Fullerton Landing Strip', - state: 'LA', - lat: 31.0217, - lon: -92.9107, - }, - KBQP: { - id: 'KBQP', - city: 'Bastrop, Morehouse Memorial Airport', - state: 'LA', - lat: 32.75583, - lon: -91.88056, - }, - KBTR: { - id: 'KBTR', - city: 'Baton Rouge, Baton Rouge Metropolitan, Ryan Field', - state: 'LA', - lat: 30.53722, - lon: -91.14694, - }, - KBXA: { - id: 'KBXA', - city: 'Bogalusa, George R Carr Memorial Air Field', - state: 'LA', - lat: 30.81361, - lon: -89.86472, - }, - KCWF: { - id: 'KCWF', - city: 'Chenault Airpark', - state: 'LA', - lat: 30.21667, - lon: -93.15, - }, - KCYD: { - id: 'KCYD', - city: 'MISS CANYAN 807', - state: 'LA', - lat: 28.17, - lon: -89.22, - }, - KDRI: { - id: 'KDRI', - city: 'De Ridder, Beauregard Parish Airport', - state: 'LA', - lat: 30.83167, - lon: -93.33972, - }, - KDSF: { - id: 'KDSF', - city: 'Mississippi Canyon', - state: 'LA', - lat: 28.35, - lon: -88.26667, - }, - KDTN: { - id: 'KDTN', - city: 'Shreveport, Shreveport Downtown Airport', - state: 'LA', - lat: 32.5424999, - lon: -93.74472, - }, - KESF: { - id: 'KESF', - city: 'Alexandria Esler Regional Airport', - state: 'LA', - lat: 31.39634, - lon: -92.28273, - }, - KGAO: { - id: 'KGAO', - city: 'Galliano, South Lafourche Airport', - state: 'LA', - lat: 29.44472, - lon: -90.26111, - }, - KGBK: { - id: 'KGBK', - city: 'MAGNOLIA OIL PLATFORM', - state: 'LA', - lat: 27.2, - lon: -92.2, - }, - KGHB: { - id: 'KGHB', - city: 'GB172/Salsa (Shell E-P)', - state: 'LA', - lat: 27.84, - lon: -91.988, - }, - KHDC: { - id: 'KHDC', - city: 'Hammond, Hammond Municipal Airport', - state: 'LA', - lat: 30.52083, - lon: -90.4175, - }, - KHUM: { - id: 'KHUM', - city: 'Houma-Terrebonne Airport', - state: 'LA', - lat: 29.56341, - lon: -90.66283, - }, - KHZR: { - id: 'KHZR', - city: 'New Roads False River Regional Airport', - state: 'LA', - lat: 30.7183, - lon: -91.4787, - }, - KIER: { - id: 'KIER', - city: 'Natchitoches, Natchitoches Regional Airport', - state: 'LA', - lat: 31.73583, - lon: -93.09917, - }, - KIYA: { - id: 'KIYA', - city: 'Abbeville Chris Crusta Memorial Airport', - state: 'LA', - lat: 29.97578, - lon: -92.08422, - }, - KLCH: { - id: 'KLCH', - city: 'Lake Charles Regional Airport', - state: 'LA', - lat: 30.12556, - lon: -93.22767, - }, - KLFT: { - id: 'KLFT', - city: 'Lafayette, Lafayette Regional Airport', - state: 'LA', - lat: 30.20222, - lon: -91.99306, - }, - KMLU: { - id: 'KMLU', - city: 'Monroe Regional Airport', - state: 'LA', - lat: 32.5155699, - lon: -92.02995, - }, - KMNE: { - id: 'KMNE', - city: 'Minden Airport', - state: 'LA', - lat: 32.64603, - lon: -93.29808, - }, - KMSY: { - id: 'KMSY', - city: 'New Orleans, New Orleans International Airport', - state: 'LA', - lat: 29.99278, - lon: -90.2508299, - }, - KNBG: { - id: 'KNBG', - city: 'New Orleans Naval Air Station - Alvin Callender Field', - state: 'LA', - lat: 29.83736, - lon: -90.02445, - }, - KNEW: { - id: 'KNEW', - city: 'New Orleans, New Orleans Lakefront Airport', - state: 'LA', - lat: 30.04944, - lon: -90.02889, - }, - KOPL: { - id: 'KOPL', - city: 'Opelousas St Landry Parish Airport', - state: 'LA', - lat: 30.5584, - lon: -92.0994, - }, - KPOE: { - id: 'KPOE', - city: 'Fort Polk, Polk AAF Ft Polk', - state: 'LA', - lat: 31.05, - lon: -93.19389, - }, - KPTN: { - id: 'KPTN', - city: 'Patterson Memorial', - state: 'LA', - lat: 29.71667, - lon: -91.33333, - }, - KREG: { - id: 'KREG', - city: 'Louisiana Regional Airport', - state: 'LA', - lat: 30.1714, - lon: -90.9404, - }, - KRSN: { - id: 'KRSN', - city: 'Ruston, Ruston Regional Airport', - state: 'LA', - lat: 32.51444, - lon: -92.58833, - }, - KSHV: { - id: 'KSHV', - city: 'Shreveport, Shreveport Regional Airport', - state: 'LA', - lat: 32.44694, - lon: -93.82417, - }, - KTVR: { - id: 'KTVR', - city: 'Vicksburg, Vicksburg / Tallulah Regional Airport', - state: 'LA', - lat: 32.3480599, - lon: -91.03, - }, - KUXL: { - id: 'KUXL', - city: 'Southland Field', - state: 'LA', - lat: 30.1314, - lon: -93.3760999, - }, - KVOA: { - id: 'KVOA', - city: 'VK 786/Petronius (Chevron)', - state: 'LA', - lat: 29.229, - lon: -87.781, - }, - KABQ: { - id: 'KABQ', - city: 'Albuquerque, Albuquerque International Airport', - state: 'NM', - lat: 35.04167, - lon: -106.61472, - }, - KAEG: { - id: 'KAEG', - city: 'Albuquerque, Double Eagle II Airport', - state: 'NM', - lat: 35.145, - lon: -106.795, - }, - KALM: { - id: 'KALM', - city: 'Alamogordo-White', - state: 'NM', - lat: 32.83512, - lon: -105.99408, - }, - KATS: { - id: 'KATS', - city: 'Artesia Municipal Airport', - state: 'NM', - lat: 32.85239, - lon: -104.46444, - }, - KAXX: { - id: 'KAXX', - city: 'Angel Fire Airport', - state: 'NM', - lat: 36.42586, - lon: -105.29028, - }, - KBRG: { - id: 'KBRG', - city: 'Belen Regional Airport', - state: 'NM', - lat: 34.64586, - lon: -106.83634, - }, - KCAO: { - id: 'KCAO', - city: 'Clayton Municipal Airpark', - state: 'NM', - lat: 36.44834, - lon: -103.15367, - }, - KCNM: { - id: 'KCNM', - city: 'Carlsbad, Cavern City Air Terminal Airport', - state: 'NM', - lat: 32.3375, - lon: -104.26333, - }, - KCQC: { - id: 'KCQC', - city: 'Clines Corners', - state: 'NM', - lat: 35, - lon: -105.66667, - }, - KCVN: { - id: 'KCVN', - city: 'Clovis Municipal Airport', - state: 'NM', - lat: 34.42274, - lon: -103.0802, - }, - KCVS: { - id: 'KCVS', - city: 'Cannon Air Force Base / Clovis', - state: 'NM', - lat: 34.38333, - lon: -103.31667, - }, - KDMN: { - id: 'KDMN', - city: 'Deming Municipal Airport', - state: 'NM', - lat: 32.25927, - lon: -107.72051, - }, - KDNA: { - id: 'KDNA', - city: 'Dona Ana County Jetport, Santa Teresa', - state: 'NM', - lat: 31.87495, - lon: -106.69385, - }, - KFMN: { - id: 'KFMN', - city: 'Farmington, Four Corners Regional Airport', - state: 'NM', - lat: 36.7436099, - lon: -108.22917, - }, - KGNT: { - id: 'KGNT', - city: 'Grants, Grants-Milan Municipal Airport', - state: 'NM', - lat: 35.16528, - lon: -107.90222, - }, - KGUP: { - id: 'KGUP', - city: 'Gallup Municipal Airport', - state: 'NM', - lat: 35.50859, - lon: -108.79316, - }, - KHMN: { - id: 'KHMN', - city: 'Holloman Air Force Base', - state: 'NM', - lat: 32.85, - lon: -106.1, - }, - KHOB: { - id: 'KHOB', - city: 'Hobbs / Lea County', - state: 'NM', - lat: 32.68333, - lon: -103.2166699, - }, - KLAM: { - id: 'KLAM', - city: 'Los Alamos Airport', - state: 'NM', - lat: 35.8796899, - lon: -106.26869, - }, - KLRU: { - id: 'KLRU', - city: 'Las Cruces, Las Cruces International Airport', - state: 'NM', - lat: 32.28944, - lon: -106.92194, - }, - KLSB: { - id: 'KLSB', - city: 'Lordsburg Municipal Airport', - state: 'NM', - lat: 32.33346, - lon: -108.69174, - }, - KLVS: { - id: 'KLVS', - city: 'Las Vegas Municipal Airport', - state: 'NM', - lat: 35.65584, - lon: -105.13852, - }, - KONM: { - id: 'KONM', - city: 'Socorro Municipal Airport', - state: 'NM', - lat: 34.02633, - lon: -106.90372, - }, - KROW: { - id: 'KROW', - city: 'Roswell International Air Center Airport', - state: 'NM', - lat: 33.30737, - lon: -104.50816, - }, - KRTN: { - id: 'KRTN', - city: 'Raton Municipal - Crews Field Airport', - state: 'NM', - lat: 36.741528, - lon: -104.502183, - }, - KSAF: { - id: 'KSAF', - city: 'Santa Fe County Municipal Airport', - state: 'NM', - lat: 35.61097, - lon: -106.09573, - }, - KSKX: { - id: 'KSKX', - city: 'Taos, Taos Regional Airport', - state: 'NM', - lat: 36.45, - lon: -105.66667, - }, - KSRR: { - id: 'KSRR', - city: 'Sierra Blanca Regional Airport', - state: 'NM', - lat: 33.4667699, - lon: -105.52778, - }, - KSVC: { - id: 'KSVC', - city: 'Grant County Airport', - state: 'NM', - lat: 32.63099, - lon: -108.14658, - }, - KSXU: { - id: 'KSXU', - city: 'Santa Rosa Route 66 Airport', - state: 'NM', - lat: 34.93567, - lon: -104.64256, - }, - KTCC: { - id: 'KTCC', - city: 'Tucumcari Municipal Airport', - state: 'NM', - lat: 35.18053, - lon: -103.60145, - }, - KTCS: { - id: 'KTCS', - city: 'Truth Or Consequences, Truth Or Consequences Municipal Airport', - state: 'NM', - lat: 33.2366699, - lon: -107.26806, - }, - KXNI: { - id: 'KXNI', - city: 'Andrew Othole Memorial Airport', - state: 'NM', - lat: 35.06068, - lon: -108.93759, - }, - KADW: { - id: 'KADW', - city: 'Camp Springs / Andrews Air Force Base', - state: 'MD', - lat: 38.81667, - lon: -76.85, - }, - KANP: { - id: 'KANP', - city: 'LEEAIRPORT', - state: 'MD', - lat: 38.94287, - lon: -76.5683899, - }, - KAPG: { - id: 'KAPG', - city: 'Phillips Army Air Field / Aberdeen', - state: 'MD', - lat: 39.46667, - lon: -76.16667, - }, - KBWI: { - id: 'KBWI', - city: 'Baltimore, Baltimore-Washington International Airport', - state: 'MD', - lat: 39.17329, - lon: -76.68404, - }, - KCGE: { - id: 'KCGE', - city: 'Cambridge-Dorchester Airport', - state: 'MD', - lat: 38.5393, - lon: -76.0304, - }, - KCGS: { - id: 'KCGS', - city: 'College Park Airport', - state: 'MD', - lat: 38.9806, - lon: -76.9223, - }, - KDMH: { - id: 'KDMH', - city: 'Baltimore, Inner Harbor', - state: 'MD', - lat: 39.28333, - lon: -76.61667, - }, - KDMW: { - id: 'KDMW', - city: 'Carroll County Regional Jack B Poage Field', - state: 'MD', - lat: 39.6083, - lon: -77.0077, - }, - KEDG: { - id: 'KEDG', - city: 'WEIDE', - state: 'MD', - lat: 39.39205, - lon: -76.29106, - }, - KESN: { - id: 'KESN', - city: 'Easton / Newman Field', - state: 'MD', - lat: 38.8, - lon: -76.06667, - }, - KFDK: { - id: 'KFDK', - city: 'Frederick Municipal Airport', - state: 'MD', - lat: 39.41775, - lon: -77.36982, - }, - KFME: { - id: 'KFME', - city: 'Fort Meade / Tipton', - state: 'MD', - lat: 39.0833299, - lon: -76.76667, - }, - KGAI: { - id: 'KGAI', - city: 'Gaithersburg - Montgomery County Airport', - state: 'MD', - lat: 39.16957, - lon: -77.16551, - }, - KHGR: { - id: 'KHGR', - city: 'Hagerstown, Washington County Regional Airport', - state: 'MD', - lat: 39.70583, - lon: -77.73, - }, - KMTN: { - id: 'KMTN', - city: 'Baltimore / Martin', - state: 'MD', - lat: 39.3333299, - lon: -76.41667, - }, - KNAK: { - id: 'KNAK', - city: 'Annapolis, United States Naval Academy', - state: 'MD', - lat: 38.99125, - lon: -76.48907, - }, - KNHK: { - id: 'KNHK', - city: 'Patuxent River, Naval Air Station', - state: 'MD', - lat: 38.27861, - lon: -76.41389, - }, - KNUI: { - id: 'KNUI', - city: 'St. Inigoes, Webster Field, Naval Electronic Systems Engineering Activity', - state: 'MD', - lat: 38.14889, - lon: -76.42, - }, - KOXB: { - id: 'KOXB', - city: 'Ocean City, Ocean City Municipal Airport', - state: 'MD', - lat: 38.31056, - lon: -75.12389, - }, - KRSP: { - id: 'KRSP', - city: 'Camp David', - state: 'MD', - lat: 39.645, - lon: -77.468, - }, - KSBY: { - id: 'KSBY', - city: 'Salisbury, Salisbury-Ocean City Wicomico County Regional Airport', - state: 'MD', - lat: 38.34056, - lon: -75.51028, - }, - KVKX: { - id: 'KVKX', - city: 'POTOMAC', - state: 'MD', - lat: 38.74761, - lon: -76.95719, - }, - KAUG: { - id: 'KAUG', - city: 'Augusta, Augusta State Airport', - state: 'ME', - lat: 44.32056, - lon: -69.79722, - }, - KBGR: { - id: 'KBGR', - city: 'Bangor, Bangor International Airport', - state: 'ME', - lat: 44.79722, - lon: -68.81861, - }, - KBHB: { - id: 'KBHB', - city: 'Bar Harbor, Hancock County-Bar Harbor Airport', - state: 'ME', - lat: 44.45, - lon: -68.36667, - }, - KBXM: { - id: 'KBXM', - city: 'BRUNSWICK', - state: 'ME', - lat: 43.8923599, - lon: -69.93883, - }, - KCAR: { - id: 'KCAR', - city: 'Caribou, Caribou Municipal Airport', - state: 'ME', - lat: 46.86722, - lon: -68.01333, - }, - KFVE: { - id: 'KFVE', - city: 'Frenchville, Northern Aroostook Regional Airport', - state: 'ME', - lat: 47.2849999, - lon: -68.30722, - }, - KGNR: { - id: 'KGNR', - city: 'Greenville', - state: 'ME', - lat: 45.4646199, - lon: -69.5538, - }, - KHUL: { - id: 'KHUL', - city: 'Houlton, Houlton International Airport', - state: 'ME', - lat: 46.12306, - lon: -67.79194, - }, - KIWI: { - id: 'KIWI', - city: 'Wiscasset Airport', - state: 'ME', - lat: 43.96401, - lon: -69.7107599, - }, - KIZG: { - id: 'KIZG', - city: 'Fryeburg, Eastern Slopes Regional Airport', - state: 'ME', - lat: 43.98917, - lon: -70.95028, - }, - KLEW: { - id: 'KLEW', - city: 'Auburn-Lewiston', - state: 'ME', - lat: 44.05, - lon: -70.28333, - }, - KMLT: { - id: 'KMLT', - city: 'Millinocket, Millinocket Municipal Airport', - state: 'ME', - lat: 45.64778, - lon: -68.69194, - }, - KPQI: { - id: 'KPQI', - city: 'Presque Isle', - state: 'ME', - lat: 46.68333, - lon: -68.05, - }, - KPWM: { - id: 'KPWM', - city: 'Portland, Portland International Jetport', - state: 'ME', - lat: 43.64222, - lon: -70.30444, - }, - KRKD: { - id: 'KRKD', - city: 'Rockland, Knox County Regional Airport', - state: 'ME', - lat: 44.06667, - lon: -69.1, - }, - KSFM: { - id: 'KSFM', - city: 'Sanford, Sanford Regional Airport', - state: 'ME', - lat: 43.4, - lon: -70.7166699, - }, - KWVL: { - id: 'KWVL', - city: 'Waterville, Waterville Robert LaFleur Airport', - state: 'ME', - lat: 44.53333, - lon: -69.68333, - }, - KABR: { - id: 'KABR', - city: 'Aberdeen, Aberdeen Regional Airport', - state: 'SD', - lat: 45.44333, - lon: -98.41306, - }, - KAGZ: { - id: 'KAGZ', - city: 'WAGNERMUNC', - state: 'SD', - lat: 43.06332, - lon: -98.29618, - }, - KATY: { - id: 'KATY', - city: 'Watertown, Watertown Municipal Airport', - state: 'SD', - lat: 44.90472, - lon: -97.14944, - }, - KBKX: { - id: 'KBKX', - city: 'Brookings, Brookings Municipal Airport', - state: 'SD', - lat: 44.3, - lon: -96.81667, - }, - KBTN: { - id: 'KBTN', - city: 'BRITTON', - state: 'SD', - lat: 45.8152199, - lon: -97.7431299, - }, - KCUT: { - id: 'KCUT', - city: 'Custer, Custer County Airport', - state: 'SD', - lat: 43.73306, - lon: -103.6175, - }, - KEFC: { - id: 'KEFC', - city: 'BELLEFCHE', - state: 'SD', - lat: 44.7342, - lon: -103.86199, - }, - KFSD: { - id: 'KFSD', - city: 'Sioux Falls, Foss Field', - state: 'SD', - lat: 43.57694, - lon: -96.75361, - }, - KHON: { - id: 'KHON', - city: 'Huron, Huron Regional Airport', - state: 'SD', - lat: 44.38806, - lon: -98.22833, - }, - KHSR: { - id: 'KHSR', - city: 'HOTSPRINGS', - state: 'SD', - lat: 43.36824, - lon: -103.38813, - }, - KICR: { - id: 'KICR', - city: 'Winner, Bob Wiley Field Airport', - state: 'SD', - lat: 43.39056, - lon: -99.8425, - }, - KIEN: { - id: 'KIEN', - city: 'Pine Ridge, Pine Ridge Airport', - state: 'SD', - lat: 43.02556, - lon: -102.52306, - }, - KLEM: { - id: 'KLEM', - city: 'LEMMON', - state: 'SD', - lat: 45.91869, - lon: -102.10617, - }, - KMBG: { - id: 'KMBG', - city: 'Mobridge, Mobridge Municipal Airport', - state: 'SD', - lat: 45.55, - lon: -100.40861, - }, - KMDS: { - id: 'KMDS', - city: 'Madison Municipal Airport', - state: 'SD', - lat: 44.0164147, - lon: -97.0855992, - }, - KMHE: { - id: 'KMHE', - city: 'Mitchell, Mitchell Municipal Airport', - state: 'SD', - lat: 43.76667, - lon: -98.03333, - }, - KMKA: { - id: 'KMKA', - city: 'MILLERMUNC', - state: 'SD', - lat: 44.5252399, - lon: -98.95811, - }, - KPHP: { - id: 'KPHP', - city: 'Philip, Philip Airport', - state: 'SD', - lat: 44.05111, - lon: -101.60111, - }, - KPIR: { - id: 'KPIR', - city: 'Pierre, Pierre Regional Airport', - state: 'SD', - lat: 44.3827799, - lon: -100.28583, - }, - KRAP: { - id: 'KRAP', - city: 'Rapid City, Rapid City Regional Airport', - state: 'SD', - lat: 44.04556, - lon: -103.05389, - }, - KRCA: { - id: 'KRCA', - city: 'Ellsworth Air Force Base', - state: 'SD', - lat: 44.15, - lon: -103.1, - }, - KSPF: { - id: 'KSPF', - city: 'Spearfish / Clyde Ice', - state: 'SD', - lat: 44.48333, - lon: -103.78333, - }, - KSUO: { - id: 'KSUO', - city: 'Rosebud Sioux Tribal Airport', - state: 'SD', - lat: 43.25846, - lon: -100.8594899, - }, - KVMR: { - id: 'KVMR', - city: 'VERMILLION', - state: 'SD', - lat: 42.76528, - lon: -96.93425, - }, - KYKN: { - id: 'KYKN', - city: 'Yankton, Chan Gurney Municipal Airport', - state: 'SD', - lat: 42.91667, - lon: -97.38333, - }, - KAID: { - id: 'KAID', - city: 'Anderson Municipal Airport', - state: 'IN', - lat: 40.10612, - lon: -85.60977, - }, - KANQ: { - id: 'KANQ', - city: 'Angola Tri-State Steuben County Airport', - state: 'IN', - lat: 41.6404, - lon: -85.0851, - }, - KASW: { - id: 'KASW', - city: 'Warsaw, Warsaw Municipal Airport', - state: 'IN', - lat: 41.27444, - lon: -85.84, - }, - KBAK: { - id: 'KBAK', - city: 'Columbus / Bakalar', - state: 'IN', - lat: 39.26667, - lon: -85.9, - }, - KBFR: { - id: 'KBFR', - city: 'Virgil I Grissom Municipal Airport', - state: 'IN', - lat: 38.84003, - lon: -86.4453599, - }, - KBMG: { - id: 'KBMG', - city: 'Bloomington, Monroe County Airport', - state: 'IN', - lat: 39.14306, - lon: -86.61667, - }, - KCFJ: { - id: 'KCFJ', - city: 'Crawfordsville Municipal Airport', - state: 'IN', - lat: 39.9756, - lon: -86.9199, - }, - KDCY: { - id: 'KDCY', - city: 'Daviess County Airport', - state: 'IN', - lat: 38.7004, - lon: -87.1297, - }, - KEKM: { - id: 'KEKM', - city: 'Elkhart Municipal', - state: 'IN', - lat: 41.71667, - lon: -86, - }, - KEVV: { - id: 'KEVV', - city: 'Evansville, Evansville Regional Airport', - state: 'IN', - lat: 38.0430599, - lon: -87.52028, - }, - KEYE: { - id: 'KEYE', - city: 'Indianapolis, Eagle Creek Airpark', - state: 'IN', - lat: 39.825, - lon: -86.29583, - }, - KFKR: { - id: 'KFKR', - city: 'Frankfort Municipal Airport', - state: 'IN', - lat: 40.2734, - lon: -86.5622, - }, - KFRH: { - id: 'KFRH', - city: 'French Lick Municipal Airport', - state: 'IN', - lat: 38.50622, - lon: -86.63694, - }, - KFWA: { - id: 'KFWA', - city: 'Fort Wayne International Airport', - state: 'IN', - lat: 40.97251, - lon: -85.20637, - }, - KGEZ: { - id: 'KGEZ', - city: 'Shelbyville Municipal Airport', - state: 'IN', - lat: 39.58546, - lon: -85.79982, - }, - KGGP: { - id: 'KGGP', - city: 'Logansport/Cass County Airport', - state: 'IN', - lat: 40.711, - lon: -86.373, - }, - KGPC: { - id: 'KGPC', - city: 'Putnam County Regional Airport', - state: 'IN', - lat: 39.6354, - lon: -86.8155, - }, - KGSH: { - id: 'KGSH', - city: 'Goshen, Goshen Municipal Airport', - state: 'IN', - lat: 41.52611, - lon: -85.78667, - }, - KGUS: { - id: 'KGUS', - city: 'Grissom Air Force Base / Peru', - state: 'IN', - lat: 40.65, - lon: -86.15, - }, - KGWB: { - id: 'KGWB', - city: 'Auburn De Kalb County Airport', - state: 'IN', - lat: 41.307, - lon: -85.0639999, - }, - KGYY: { - id: 'KGYY', - city: 'Gary Regional Airport', - state: 'IN', - lat: 41.61212, - lon: -87.40908, - }, - KHFY: { - id: 'KHFY', - city: 'Greenwood Municipal Airport', - state: 'IN', - lat: 39.6276, - lon: -86.0879999, - }, - KHHG: { - id: 'KHHG', - city: 'Huntington Municipal Airport', - state: 'IN', - lat: 40.8529, - lon: -85.4571, - }, - KHLB: { - id: 'KHLB', - city: 'Batesville Airport', - state: 'IN', - lat: 39.34313, - lon: -85.25843, - }, - KHNB: { - id: 'KHNB', - city: 'Huntingburg', - state: 'IN', - lat: 38.25, - lon: -86.95, - }, - KHUF: { - id: 'KHUF', - city: 'Terre Haute Regional Airport', - state: 'IN', - lat: 39.4429, - lon: -87.32207, - }, - KIMS: { - id: 'KIMS', - city: 'Madison Municipal Airport', - state: 'IN', - lat: 38.7589, - lon: -85.4655, - }, - KIND: { - id: 'KIND', - city: 'Indianapolis International Airport', - state: 'IN', - lat: 39.72518, - lon: -86.2816, - }, - KJVY: { - id: 'KJVY', - city: 'Clark Regional Airport', - state: 'IN', - lat: 38.36661, - lon: -85.73814, - }, - KLAF: { - id: 'KLAF', - city: 'Lafayette, Purdue University Airport', - state: 'IN', - lat: 40.4125, - lon: -86.9475, - }, - KMCX: { - id: 'KMCX', - city: 'Monticello White County Airport', - state: 'IN', - lat: 40.7087999, - lon: -86.7668, - }, - KMGC: { - id: 'KMGC', - city: 'Michigan City Municipal Airport', - state: 'IN', - lat: 41.7033, - lon: -86.8212, - }, - KMIE: { - id: 'KMIE', - city: 'Muncie, Delaware County-Johnson Field', - state: 'IN', - lat: 40.23417, - lon: -85.39361, - }, - KMQJ: { - id: 'KMQJ', - city: 'Indianapolis Regional Airport', - state: 'IN', - lat: 39.84314, - lon: -85.89774, - }, - KMZZ: { - id: 'KMZZ', - city: 'Marion Municipal Airport', - state: 'IN', - lat: 40.49, - lon: -85.68, - }, - KOKK: { - id: 'KOKK', - city: 'Kokomo, Kokomo Municipal Airport', - state: 'IN', - lat: 40.53333, - lon: -86.06667, - }, - KOXI: { - id: 'KOXI', - city: 'Starke County Airport', - state: 'IN', - lat: 41.33, - lon: -86.665, - }, - KPLD: { - id: 'KPLD', - city: 'Portland Municipal Airport', - state: 'IN', - lat: 40.45158, - lon: -84.98903, - }, - KPPO: { - id: 'KPPO', - city: 'La Porte Municipal Airport', - state: 'IN', - lat: 41.5725, - lon: -86.7345, - }, - KRCR: { - id: 'KRCR', - city: 'Rochester Fulton County Airport', - state: 'IN', - lat: 41.06553, - lon: -86.18169, - }, - KRID: { - id: 'KRID', - city: 'Richmond Municipal Airport', - state: 'IN', - lat: 39.7572, - lon: -84.8428, - }, - KRZL: { - id: 'KRZL', - city: 'Rensselaer Jasper County Airport', - state: 'IN', - lat: 40.94789, - lon: -87.18258, - }, - KSBN: { - id: 'KSBN', - city: 'South Bend International Airport', - state: 'IN', - lat: 41.7088899, - lon: -86.31861, - }, - KSMD: { - id: 'KSMD', - city: 'Smith Field Airport', - state: 'IN', - lat: 41.14336, - lon: -85.15277, - }, - KTYQ: { - id: 'KTYQ', - city: 'INDIANAPOLIS', - state: 'IN', - lat: 40.03066, - lon: -86.2514999, - }, - KUMP: { - id: 'KUMP', - city: 'Indianapolis Metro Airport', - state: 'IN', - lat: 39.9354, - lon: -86.04507, - }, - KUWL: { - id: 'KUWL', - city: 'New Castle Henry County Airport', - state: 'IN', - lat: 39.87672, - lon: -85.32527, - }, - KVPZ: { - id: 'KVPZ', - city: 'Valparaiso Porter County Municipal Airport', - state: 'IN', - lat: 41.45349, - lon: -86.99805, - }, - KBAC: { - id: 'KBAC', - city: 'Valley City', - state: 'ND', - lat: 46.9412, - lon: -98.018, - }, - KBIS: { - id: 'KBIS', - city: 'Bismarck, Bismarck Municipal Airport', - state: 'ND', - lat: 46.7825, - lon: -100.75722, - }, - KBWP: { - id: 'KBWP', - city: 'Wahpeton, Harry Stern Airport', - state: 'ND', - lat: 46.24389, - lon: -96.60722, - }, - KBWW: { - id: 'KBWW', - city: 'Bowman Regional Airport', - state: 'ND', - lat: 46.16551, - lon: -103.30074, - }, - KDIK: { - id: 'KDIK', - city: 'Dickinson, Dickinson Municipal Airport', - state: 'ND', - lat: 46.79722, - lon: -102.80194, - }, - KDVL: { - id: 'KDVL', - city: 'Devils Lake, Devils Lake Municipal Airport', - state: 'ND', - lat: 48.11667, - lon: -98.91667, - }, - KFAR: { - id: 'KFAR', - city: 'Fargo, Hector International Airport', - state: 'ND', - lat: 46.92528, - lon: -96.81111, - }, - KGAF: { - id: 'KGAF', - city: 'GRAFTON', - state: 'ND', - lat: 48.4, - lon: -97.37, - }, - KGFK: { - id: 'KGFK', - city: 'Grand Forks, Grand Forks International Airport', - state: 'ND', - lat: 47.94806, - lon: -97.1825, - }, - KGWR: { - id: 'KGWR', - city: 'Gwinner', - state: 'ND', - lat: 46.2187, - lon: -97.6435, - }, - KHEI: { - id: 'KHEI', - city: 'Hettinger, Hettinger Municipal Airport', - state: 'ND', - lat: 46.01056, - lon: -102.64972, - }, - KHZE: { - id: 'KHZE', - city: 'HAZEN', - state: 'ND', - lat: 47.28, - lon: -101.58, - }, - KJMS: { - id: 'KJMS', - city: 'Jamestown, Jamestown Municipal Airport', - state: 'ND', - lat: 46.92972, - lon: -98.67833, - }, - KMIB: { - id: 'KMIB', - city: 'Minot Air Force Base', - state: 'ND', - lat: 48.41667, - lon: -101.35, - }, - KMOT: { - id: 'KMOT', - city: 'Minot International Airport', - state: 'ND', - lat: 48.25203, - lon: -101.2689, - }, - KRDR: { - id: 'KRDR', - city: 'Grand Forks Air Force Base', - state: 'ND', - lat: 47.96667, - lon: -97.4, - }, - KRUG: { - id: 'KRUG', - city: 'RUGBY', - state: 'ND', - lat: 48.38, - lon: -100.02, - }, - KXWA: { - id: 'KXWA', - city: 'Williston Basin International Airport', - state: 'ND', - lat: 48.26086, - lon: -103.75114, - }, - KBAM: { - id: 'KBAM', - city: 'Battle Mountain - Lander County Airport', - state: 'NV', - lat: 40.5989999, - lon: -116.8743, - }, - KBVU: { - id: 'KBVU', - city: 'Boulder City Municipal Airport', - state: 'NV', - lat: 35.9475, - lon: -114.8611, - }, - KCXP: { - id: 'KCXP', - city: 'Carson City Airport', - state: 'NV', - lat: 39.19056, - lon: -119.73191, - }, - KDRA: { - id: 'KDRA', - city: 'Mercury, Desert Rock Airport', - state: 'NV', - lat: 36.6207, - lon: -116.02868, - }, - KEKO: { - id: 'KEKO', - city: 'Elko, Elko Regional Airport', - state: 'NV', - lat: 40.8240399, - lon: -115.78635, - }, - KELY: { - id: 'KELY', - city: 'Ely, Ely Airport', - state: 'NV', - lat: 39.295, - lon: -114.84528, - }, - KHND: { - id: 'KHND', - city: 'Las Vegas - Henderson Executive Airport', - state: 'NV', - lat: 35.97665, - lon: -115.13221, - }, - KHTH: { - id: 'KHTH', - city: 'Hawthorne Industrial Airport', - state: 'NV', - lat: 38.54482, - lon: -118.63137, - }, - KINS: { - id: 'KINS', - city: 'Nellis AFB - Indian Springs Auxiliary Airfield', - state: 'NV', - lat: 36.58573, - lon: -115.69008, - }, - KLAS: { - id: 'KLAS', - city: 'Harry Reid International Airport', - state: 'NV', - lat: 36.07188, - lon: -115.1634, - }, - KLOL: { - id: 'KLOL', - city: 'Lovelock, Derby Field Airport', - state: 'NV', - lat: 40.0683999, - lon: -118.57017, - }, - KLSV: { - id: 'KLSV', - city: 'Nellis Air Force Base', - state: 'NV', - lat: 36.23333, - lon: -115.03333, - }, - KMEV: { - id: 'KMEV', - city: 'Minden-Tahoe Airport', - state: 'NV', - lat: 38.9963, - lon: -119.75, - }, - KNFL: { - id: 'KNFL', - city: 'Fallon, Naval Air Station', - state: 'NV', - lat: 39.43222, - lon: -118.68556, - }, - KRNO: { - id: 'KRNO', - city: 'Reno, Reno Tahoe International Airport', - state: 'NV', - lat: 39.50776, - lon: -119.76819, - }, - KRTS: { - id: 'KRTS', - city: 'Reno/Stead', - state: 'NV', - lat: 39.6682, - lon: -119.8764, - }, - KTMT: { - id: 'KTMT', - city: 'Austin Airport', - state: 'NV', - lat: 39.46794, - lon: -117.19745, - }, - KTPH: { - id: 'KTPH', - city: 'Tonopah, Tonopah Airport', - state: 'NV', - lat: 38.06028, - lon: -117.08722, - }, - KVGT: { - id: 'KVGT', - city: 'Las Vegas, North Las Vegas Airport', - state: 'NV', - lat: 36.21205, - lon: -115.19395, - }, - KWMC: { - id: 'KWMC', - city: 'Winnemucca, Winnemucca Municipal Airport', - state: 'NV', - lat: 40.90194, - lon: -117.80722, - }, - KADH: { - id: 'KADH', - city: 'Ada, Ada Municipal Airport', - state: 'OK', - lat: 34.80444, - lon: -96.67139, - }, - KADM: { - id: 'KADM', - city: 'Ardmore, Ardmore Municipal Airport', - state: 'OK', - lat: 34.30306, - lon: -97.01944, - }, - KAVK: { - id: 'KAVK', - city: 'Alva, Alva Regional Airport', - state: 'OK', - lat: 36.77306, - lon: -98.67, - }, - KAXS: { - id: 'KAXS', - city: 'Altus, Altus/Quartz Mountain Regional Airport', - state: 'OK', - lat: 34.69861, - lon: -99.33806, - }, - KBKN: { - id: 'KBKN', - city: 'Blackwell-Tonkawa Municipal Airport', - state: 'OK', - lat: 36.7451099, - lon: -97.34958, - }, - KBVO: { - id: 'KBVO', - city: 'Bartlesville, Bartlesville Municipal Airport', - state: 'OK', - lat: 36.76833, - lon: -96.02611, - }, - KCHK: { - id: 'KCHK', - city: 'Chickasha, Chickasha Municipal Airport', - state: 'OK', - lat: 35.09611, - lon: -97.96611, - }, - KCLK: { - id: 'KCLK', - city: 'Clinton, Clinton Regional Airport', - state: 'OK', - lat: 35.53806, - lon: -98.92139, - }, - KCQB: { - id: 'KCQB', - city: 'Chandler, Chandler Municipal Airport', - state: 'OK', - lat: 35.72389, - lon: -96.82028, - }, - KCSM: { - id: 'KCSM', - city: 'Clinton, Clinton-Sherman Airport', - state: 'OK', - lat: 35.35667, - lon: -99.20361, - }, - KCUH: { - id: 'KCUH', - city: 'Cushing, Cushing Municipal Airport', - state: 'OK', - lat: 35.94972, - lon: -96.77278, - }, - KDUA: { - id: 'KDUA', - city: 'Durant, Eaker Field Airport', - state: 'OK', - lat: 33.94222, - lon: -96.39444, - }, - KDUC: { - id: 'KDUC', - city: 'Duncan, Halliburton Field Airport', - state: 'OK', - lat: 34.47083, - lon: -97.9599999, - }, - KELK: { - id: 'KELK', - city: 'Elk City Regional Business Airport', - state: 'OK', - lat: 35.4308, - lon: -99.3943, - }, - KEND: { - id: 'KEND', - city: 'Vance Air Force Base / Enid', - state: 'OK', - lat: 36.3333299, - lon: -97.91667, - }, - KFDR: { - id: 'KFDR', - city: 'Frederick, Frederick Municipal Airport', - state: 'OK', - lat: 34.34444, - lon: -98.98306, - }, - KFSI: { - id: 'KFSI', - city: 'Fort Sill', - state: 'OK', - lat: 34.6, - lon: -98.4, - }, - KGAG: { - id: 'KGAG', - city: 'Gage, Gage Airport', - state: 'OK', - lat: 36.29667, - lon: -99.76889, - }, - KGCM: { - id: 'KGCM', - city: 'Claremore, Claremore Regional Airport', - state: 'OK', - lat: 36.29444, - lon: -95.47972, - }, - KGMJ: { - id: 'KGMJ', - city: 'Grove, Grove Municipal Airport', - state: 'OK', - lat: 36.60528, - lon: -94.73861, - }, - KGOK: { - id: 'KGOK', - city: 'Guthrie, Guthrie Municipal Airport', - state: 'OK', - lat: 35.85194, - lon: -97.4075, - }, - KGUY: { - id: 'KGUY', - city: 'Guymon / Guymon Municipal Airport', - state: 'OK', - lat: 36.6816699, - lon: -101.50528, - }, - KGZL: { - id: 'KGZL', - city: 'Stigler', - state: 'OK', - lat: 35.2891, - lon: -95.0939, - }, - KHBR: { - id: 'KHBR', - city: 'Hobart, Hobart Municipal Airport', - state: 'OK', - lat: 34.98944, - lon: -99.0525, - }, - KHHW: { - id: 'KHHW', - city: 'Hugo Stan Stamper Municipal Airport', - state: 'OK', - lat: 34.0348, - lon: -95.5419, - }, - KHMY: { - id: 'KHMY', - city: 'MULDROWARMY', - state: 'OK', - lat: 35.02638, - lon: -97.23163, - }, - KHSD: { - id: 'KHSD', - city: 'Sundance Airport', - state: 'OK', - lat: 35.60183, - lon: -97.70616, - }, - KJSV: { - id: 'KJSV', - city: 'Sallisaw, Sallisaw Municipal Airport', - state: 'OK', - lat: 35.43806, - lon: -94.80278, - }, - KJWG: { - id: 'KJWG', - city: 'Watonga, Watonga Airport', - state: 'OK', - lat: 35.86472, - lon: -98.42083, - }, - KLAW: { - id: 'KLAW', - city: 'Lawton, Lawton Municipal Airport', - state: 'OK', - lat: 34.5575, - lon: -98.41667, - }, - KLTS: { - id: 'KLTS', - city: 'Altus Air Force Base', - state: 'OK', - lat: 34.65, - lon: -99.26667, - }, - KMIO: { - id: 'KMIO', - city: 'Miami Regional Airport', - state: 'OK', - lat: 36.90922, - lon: -94.8875, - }, - KMKO: { - id: 'KMKO', - city: 'Muskogee-Davis Regional Airport', - state: 'OK', - lat: 35.65694, - lon: -95.35972, - }, - KMLC: { - id: 'KMLC', - city: 'McAlester, McAlester Regional Airport', - state: 'OK', - lat: 34.8822199, - lon: -95.78306, - }, - KOJA: { - id: 'KOJA', - city: 'Weatherford, Thomas P Stafford Airport', - state: 'OK', - lat: 35.54472, - lon: -98.66833, - }, - KOKC: { - id: 'KOKC', - city: 'Oklahoma City, Will Rogers World Airport', - state: 'OK', - lat: 35.38861, - lon: -97.60028, - }, - KOKM: { - id: 'KOKM', - city: 'Okmulgee, Okmulgee Municipal Airport', - state: 'OK', - lat: 35.6680599, - lon: -95.94861, - }, - KOUN: { - id: 'KOUN', - city: 'Norman / Max Westheimer', - state: 'OK', - lat: 35.2435, - lon: -97.4708, - }, - KOWP: { - id: 'KOWP', - city: 'William R Pogue Municipal Airport', - state: 'OK', - lat: 36.1753, - lon: -96.1518, - }, - KPNC: { - id: 'KPNC', - city: 'Ponca City, Ponca City Municipal Airport', - state: 'OK', - lat: 36.7305599, - lon: -97.09972, - }, - KPVJ: { - id: 'KPVJ', - city: 'Pauls Valley, Pauls Valley Municipal Airport', - state: 'OK', - lat: 34.71111, - lon: -97.22333, - }, - KPWA: { - id: 'KPWA', - city: 'Oklahoma City, Wiley Post Airport', - state: 'OK', - lat: 35.54111, - lon: -97.64667, - }, - KRCE: { - id: 'KRCE', - city: 'Clarence E Page Municipal Airport', - state: 'OK', - lat: 35.4880799, - lon: -97.82356, - }, - KRKR: { - id: 'KRKR', - city: 'Poteau, Robert S Kerr Airport', - state: 'OK', - lat: 35.02167, - lon: -94.62139, - }, - KRQO: { - id: 'KRQO', - city: 'El Reno, El Reno Regional Airport', - state: 'OK', - lat: 35.4724999, - lon: -98.00556, - }, - KRVS: { - id: 'KRVS', - city: 'Tulsa - Jones Jr. Airport', - state: 'OK', - lat: 36.04255, - lon: -95.99005, - }, - KSNL: { - id: 'KSNL', - city: 'Shawnee, Shawnee Municipal Airport', - state: 'OK', - lat: 35.35722, - lon: -96.94278, - }, - KSRE: { - id: 'KSRE', - city: 'Seminole, Seminole Municipal Airport', - state: 'OK', - lat: 35.27444, - lon: -96.675, - }, - KSWO: { - id: 'KSWO', - city: 'Stillwater, Stillwater Regional Airport', - state: 'OK', - lat: 36.16222, - lon: -97.08917, - }, - KTIK: { - id: 'KTIK', - city: 'Tinker Air Force Base', - state: 'OK', - lat: 35.41667, - lon: -97.38333, - }, - KTQH: { - id: 'KTQH', - city: 'Tahlequah, Tahlequah Municipal Airport', - state: 'OK', - lat: 35.92889, - lon: -95.00444, - }, - KTUL: { - id: 'KTUL', - city: 'Tulsa, Tulsa International Airport', - state: 'OK', - lat: 36.1975, - lon: -95.88639, - }, - KWDG: { - id: 'KWDG', - city: 'Enid, Enid Woodring Regional Airport', - state: 'OK', - lat: 36.37917, - lon: -97.79111, - }, - KWWR: { - id: 'KWWR', - city: 'Woodward, West Woodward Airport', - state: 'OK', - lat: 36.43667, - lon: -99.5211099, - }, - KBKW: { - id: 'KBKW', - city: 'Beckley, Raleigh County Memorial Airport', - state: 'WV', - lat: 37.795, - lon: -81.12472, - }, - KBLF: { - id: 'KBLF', - city: 'Bluefield, Mercer County Airport', - state: 'WV', - lat: 37.29583, - lon: -81.20778, - }, - KCBE: { - id: 'KCBE', - city: 'Cumberland, Greater Cumberland Regional Airport', - state: 'WV', - lat: 39.61528, - lon: -78.76083, - }, - KCKB: { - id: 'KCKB', - city: 'Clarksburg, Clarksburg Benedum Airport', - state: 'WV', - lat: 39.3, - lon: -80.22472, - }, - KCRW: { - id: 'KCRW', - city: 'Charleston, Yeager Airport', - state: 'WV', - lat: 38.37944, - lon: -81.59139, - }, - KEKN: { - id: 'KEKN', - city: 'Elkins, Elkins-Randolph County-Jennings Randolph Field', - state: 'WV', - lat: 38.88528, - lon: -79.85278, - }, - KHLG: { - id: 'KHLG', - city: 'Wheeling, Wheeling Ohio County Airport', - state: 'WV', - lat: 40.17028, - lon: -80.64444, - }, - KHTS: { - id: 'KHTS', - city: 'Huntington, Tri-State Airport', - state: 'WV', - lat: 38.365, - lon: -82.555, - }, - KLWB: { - id: 'KLWB', - city: 'Lewisburg / Greenbrier', - state: 'WV', - lat: 37.86667, - lon: -80.4, - }, - KMGW: { - id: 'KMGW', - city: 'Morgantown Municipal-Hart Field', - state: 'WV', - lat: 39.64985, - lon: -79.92065, - }, - KMRB: { - id: 'KMRB', - city: 'Eastern WV Regional Airport/Shepherd Field', - state: 'WV', - lat: 39.40372, - lon: -77.975, - }, - KPKB: { - id: 'KPKB', - city: 'Parkersburg, Mid-Ohio Valley Regional Airport', - state: 'WV', - lat: 39.345, - lon: -81.43917, - }, - KBGF: { - id: 'KBGF', - city: 'Winchester Municipal Airport', - state: 'TN', - lat: 35.1775, - lon: -86.0662, - }, - KBNA: { - id: 'KBNA', - city: 'Nashville, Nashville International Airport', - state: 'TN', - lat: 36.11889, - lon: -86.68917, - }, - KCHA: { - id: 'KCHA', - city: 'Chattanooga, Lovell Field', - state: 'TN', - lat: 35.03333, - lon: -85.2, - }, - KCKV: { - id: 'KCKV', - city: 'Clarksville Outlaw Field', - state: 'TN', - lat: 36.61689, - lon: -87.41174, - }, - KCSV: { - id: 'KCSV', - city: 'Crossville, Crossville Memorial-Whitson Field Airport', - state: 'TN', - lat: 35.95139, - lon: -85.0849999, - }, - KDKX: { - id: 'KDKX', - city: 'Knoxville Downtown Airport', - state: 'TN', - lat: 35.96581, - lon: -83.87169, - }, - KDYR: { - id: 'KDYR', - city: 'Dyersburg, Dyersburg Municipal Airport', - state: 'TN', - lat: 36, - lon: -89.4, - }, - KFYE: { - id: 'KFYE', - city: 'Somerville - Fayette County Airport', - state: 'TN', - lat: 35.2061, - lon: -89.3929, - }, - KFYM: { - id: 'KFYM', - city: 'Fayetteville Municipal Airport', - state: 'TN', - lat: 35.0597, - lon: -86.5639999, - }, - KGCY: { - id: 'KGCY', - city: 'Greeneville-Greene County Municipal Airport', - state: 'TN', - lat: 36.19601, - lon: -82.81099, - }, - KGKT: { - id: 'KGKT', - city: 'Sevierville Gatlinburg - Pigeon Forge Airport', - state: 'TN', - lat: 35.85681, - lon: -83.53334, - }, - KGZS: { - id: 'KGZS', - city: 'Pulaski Abernathy Field Airport', - state: 'TN', - lat: 35.1537, - lon: -87.0568, - }, - KHZD: { - id: 'KHZD', - city: 'Huntingdon Carroll County Airport', - state: 'TN', - lat: 36.08896, - lon: -88.46538, - }, - KJAU: { - id: 'KJAU', - city: 'Jacksboro Campbell County Airport', - state: 'TN', - lat: 36.3341, - lon: -84.163, - }, - KJWN: { - id: 'KJWN', - city: 'John C Tune Airport', - state: 'TN', - lat: 36.18521, - lon: -86.88331, - }, - KLUG: { - id: 'KLUG', - city: 'Ellington Airport', - state: 'TN', - lat: 35.50697, - lon: -86.80389, - }, - KMBT: { - id: 'KMBT', - city: 'Murfreesboro Municipal Airport', - state: 'TN', - lat: 35.87866, - lon: -86.37749, - }, - KMEM: { - id: 'KMEM', - city: 'Memphis International Airport', - state: 'TN', - lat: 35.05644, - lon: -89.98634, - }, - KMKL: { - id: 'KMKL', - city: 'Jackson, McKellar-Sipes Regional Airport', - state: 'TN', - lat: 35.59306, - lon: -88.91667, - }, - KMMI: { - id: 'KMMI', - city: 'Athens McMinn County Airport', - state: 'TN', - lat: 35.3973, - lon: -84.5626, - }, - KAIK: { - id: 'KAIK', - city: 'Aiken Municipal Airport', - state: 'SC', - lat: 33.649, - lon: -81.685, - }, - KAND: { - id: 'KAND', - city: 'Anderson, Anderson County Airport', - state: 'SC', - lat: 34.49778, - lon: -82.70972, - }, - KAQX: { - id: 'KAQX', - city: 'Allendale County Airport', - state: 'SC', - lat: 32.9951, - lon: -81.2703, - }, - KARW: { - id: 'KARW', - city: 'Beaufort County Airport', - state: 'SC', - lat: 32.412, - lon: -80.634, - }, - KBBP: { - id: 'KBBP', - city: 'Marlboro County Jetport', - state: 'SC', - lat: 34.622, - lon: -79.734, - }, - KBNL: { - id: 'KBNL', - city: 'Barnwell Regional Airport', - state: 'SC', - lat: 33.258, - lon: -81.388, - }, - KCAE: { - id: 'KCAE', - city: 'Columbia, Columbia Metropolitan Airport', - state: 'SC', - lat: 33.94194, - lon: -81.11806, - }, - KCDN: { - id: 'KCDN', - city: 'Camden Woodward Field', - state: 'SC', - lat: 34.284, - lon: -80.565, - }, - KCEU: { - id: 'KCEU', - city: 'Clemson, Clemson-Oconee County Airport', - state: 'SC', - lat: 34.67222, - lon: -82.88139, - }, - KCHS: { - id: 'KCHS', - city: 'Charleston, Charleston Air Force Base', - state: 'SC', - lat: 32.89889, - lon: -80.04056, - }, - KCKI: { - id: 'KCKI', - city: 'Kingstree Williamsburg Regional Airport', - state: 'SC', - lat: 33.717, - lon: -79.857, - }, - KCQW: { - id: 'KCQW', - city: 'Cheraw Municipal Lynch Bellinger Field', - state: 'SC', - lat: 34.713, - lon: -79.9569999, - }, - KCRE: { - id: 'KCRE', - city: 'North Myrtle Beach Grand Strand Airport', - state: 'SC', - lat: 33.81619, - lon: -78.7204299, - }, - KCUB: { - id: 'KCUB', - city: 'Columbia - Jim Hamilton L.B. Owens Airport', - state: 'SC', - lat: 33.97083, - lon: -80.99444, - }, - KDCM: { - id: 'KDCM', - city: 'Chester Catawba Regional Airport', - state: 'SC', - lat: 34.789, - lon: -81.196, - }, - KDYB: { - id: 'KDYB', - city: 'Summerville Airport', - state: 'SC', - lat: 33.063, - lon: -80.279, - }, - KEOE: { - id: 'KEOE', - city: 'Newberry County Airport', - state: 'SC', - lat: 34.309, - lon: -81.64, - }, - KFDW: { - id: 'KFDW', - city: 'Winnsboro/Fairfield County Airport', - state: 'SC', - lat: 34.315, - lon: -81.109, - }, - KFLO: { - id: 'KFLO', - city: 'Florence - Florence Regional Airport', - state: 'SC', - lat: 34.1877799, - lon: -79.73083, - }, - KGGE: { - id: 'KGGE', - city: 'Georgetown County Airport ', - state: 'SC', - lat: 33.3117, - lon: -79.3196, - }, - KGMU: { - id: 'KGMU', - city: 'Greenville Downtown Airport', - state: 'SC', - lat: 34.84873, - lon: -82.35004, - }, - KGRD: { - id: 'KGRD', - city: 'Greenwood, Greenwood County Airport', - state: 'SC', - lat: 34.24722, - lon: -82.15472, - }, - KGSP: { - id: 'KGSP', - city: 'Greenville Spartanburg International Airport', - state: 'SC', - lat: 34.90611, - lon: -82.2125499, - }, - KGYH: { - id: 'KGYH', - city: 'Greenville-Donaldson Center Airport', - state: 'SC', - lat: 34.7583, - lon: -82.3764, - }, - KHVS: { - id: 'KHVS', - city: 'Hartsville Regional Airport', - state: 'SC', - lat: 34.403, - lon: -80.119, - }, - KHXD: { - id: 'KHXD', - city: 'Hilton Head Island, Hilton Head Airport', - state: 'SC', - lat: 32.21667, - lon: -80.7, - }, - KHYW: { - id: 'KHYW', - city: 'Conway Horry County Airport', - state: 'SC', - lat: 33.829, - lon: -79.122, - }, - KJZI: { - id: 'KJZI', - city: 'Charleston Executive Airport', - state: 'SC', - lat: 32.701, - lon: -80.003, - }, - KLKR: { - id: 'KLKR', - city: 'Lancaster County-mc Whirter Field', - state: 'SC', - lat: 34.723, - lon: -80.855, - }, - KLQK: { - id: 'KLQK', - city: 'Pickens County Airport', - state: 'SC', - lat: 34.80997, - lon: -82.70289, - }, - KLRO: { - id: 'KLRO', - city: 'Mount Pleasant Regional-Faison Field', - state: 'SC', - lat: 32.898, - lon: -79.783, - }, - KLUX: { - id: 'KLUX', - city: 'Laurens County Airport', - state: 'SC', - lat: 34.507, - lon: -81.947, - }, - KMAO: { - id: 'KMAO', - city: 'Marion County Airport', - state: 'SC', - lat: 34.181, - lon: -79.3349999, - }, - KMKS: { - id: 'KMKS', - city: 'Moncks Corner Berkeley County', - state: 'SC', - lat: 33.1855, - lon: -80.0361999, - }, - KMMT: { - id: 'KMMT', - city: 'McEntire Air National Guard Weather Facility Base', - state: 'SC', - lat: 33.91667, - lon: -80.8, - }, - KMNI: { - id: 'KMNI', - city: 'Manning / Cooper Regional', - state: 'SC', - lat: 33.5833299, - lon: -80.2166699, - }, - KMYR: { - id: 'KMYR', - city: 'Myrtle Beach International Airport', - state: 'SC', - lat: 33.67975, - lon: -78.92833, - }, - KNBC: { - id: 'KNBC', - city: 'Beaufort, Marine Corps Air Station', - state: 'SC', - lat: 32.4936099, - lon: -80.7030599, - }, - KOGB: { - id: 'KOGB', - city: 'Orangeburg, Orangeburg Municipal Airport', - state: 'SC', - lat: 33.46389, - lon: -80.85361, - }, - KRBW: { - id: 'KRBW', - city: 'Walterboro Lowcountry Regional Airport', - state: 'SC', - lat: 32.921, - lon: -80.641, - }, - KSMS: { - id: 'KSMS', - city: 'Sumter Airport', - state: 'SC', - lat: 33.995, - lon: -80.361, - }, - KSPA: { - id: 'KSPA', - city: 'Spartanburg Memorial', - state: 'SC', - lat: 34.91667, - lon: -81.95, - }, - KSSC: { - id: 'KSSC', - city: 'Shaw Air Force Base', - state: 'SC', - lat: 33.96667, - lon: -80.48333, - }, - KUDG: { - id: 'KUDG', - city: 'Darlington, Darlington County Jetport Airport', - state: 'SC', - lat: 34.44917, - lon: -79.89028, - }, - KUZA: { - id: 'KUZA', - city: 'Rock Hill, Rock Hill - York County Airport', - state: 'SC', - lat: 34.98389, - lon: -81.05583, - }, - KXNO: { - id: 'KXNO', - city: 'North Air Force Auxiliary Field', - state: 'SC', - lat: 33.60949, - lon: -81.08118, - }, - KAIG: { - id: 'KAIG', - city: 'Langlade County Airport', - state: 'WI', - lat: 45.15659, - lon: -89.11144, - }, - KARV: { - id: 'KARV', - city: 'Minocqua/Woodruff, Lakeland Airport/Noble F. Lee Memorial Field', - state: 'WI', - lat: 45.93333, - lon: -89.73333, - }, - KASX: { - id: 'KASX', - city: 'John F Kennedy Memorial Airport', - state: 'WI', - lat: 46.54679, - lon: -90.91841, - }, - KATW: { - id: 'KATW', - city: 'Appleton-Outagamie', - state: 'WI', - lat: 44.2595, - lon: -88.51567, - }, - KAUW: { - id: 'KAUW', - city: 'Wausau Downtown Airport', - state: 'WI', - lat: 44.92759, - lon: -89.62512, - }, - KBCK: { - id: 'KBCK', - city: 'Black River Falls Area Airport', - state: 'WI', - lat: 44.24996, - lon: -90.84999, - }, - KBUU: { - id: 'KBUU', - city: 'Burlington Municipal Airport', - state: 'WI', - lat: 42.69088, - lon: -88.308, - }, - KCLI: { - id: 'KCLI', - city: 'Clintonville Municipal Airport', - state: 'WI', - lat: 44.61526, - lon: -88.73129, - }, - KCMY: { - id: 'KCMY', - city: 'Sparta, Sparta / Fort McCoy Airport', - state: 'WI', - lat: 43.9583299, - lon: -90.73778, - }, - KCWA: { - id: 'KCWA', - city: 'Mosinee', - state: 'WI', - lat: 44.77944, - lon: -89.67098, - }, - KDLL: { - id: 'KDLL', - city: 'Baraboo Wisconsin Dells Airport', - state: 'WI', - lat: 43.52372, - lon: -89.77345, - }, - KEAU: { - id: 'KEAU', - city: 'Chippewa Valley Regional Airport', - state: 'WI', - lat: 44.86668, - lon: -91.488, - }, - KEFT: { - id: 'KEFT', - city: 'Monroe Municipal Airport', - state: 'WI', - lat: 42.61959, - lon: -89.59309, - }, - KEGV: { - id: 'KEGV', - city: 'Eagle River Union Airport', - state: 'WI', - lat: 45.9309299, - lon: -89.26702, - }, - KENW: { - id: 'KENW', - city: 'Kenosha, Kenosha Regional Airport', - state: 'WI', - lat: 42.595, - lon: -87.9380599, - }, - KETB: { - id: 'KETB', - city: 'West Bend Municipal Airport', - state: 'WI', - lat: 43.42256, - lon: -88.1326, - }, - KEZS: { - id: 'KEZS', - city: 'Shawano Municipal Airport', - state: 'WI', - lat: 44.787, - lon: -88.56, - }, - KFLD: { - id: 'KFLD', - city: 'Fond Du Lac County Airport', - state: 'WI', - lat: 43.76955, - lon: -88.49072, - }, - KGRB: { - id: 'KGRB', - city: 'Green Bay, Austin Straubel International Airport', - state: 'WI', - lat: 44.4794399, - lon: -88.13667, - }, - KHYR: { - id: 'KHYR', - city: 'Sawyer County Airport', - state: 'WI', - lat: 46.03029, - lon: -91.44259, - }, - KISW: { - id: 'KISW', - city: 'Wisconsin Rapids, Alexander Field South Wood County Airport', - state: 'WI', - lat: 44.35917, - lon: -89.83694, - }, - KJVL: { - id: 'KJVL', - city: 'Janesville-Rock County', - state: 'WI', - lat: 42.62135, - lon: -89.04186, - }, - KLNL: { - id: 'KLNL', - city: "Land O' Lakes, Kings Land O' Lakes Airport", - state: 'WI', - lat: 46.1538899, - lon: -89.21194, - }, - KLNR: { - id: 'KLNR', - city: 'Lone Rock Tri-County Regional Airport', - state: 'WI', - lat: 43.21108, - lon: -90.18735, - }, - KLSE: { - id: 'KLSE', - city: 'La Crosse - La Crosse Regional Airport', - state: 'WI', - lat: 43.87944, - lon: -91.25667, - }, - KLUM: { - id: 'KLUM', - city: 'Menomonie Municipal Airport-Score Field', - state: 'WI', - lat: 44.89363, - lon: -91.86652, - }, - KMDZ: { - id: 'KMDZ', - city: 'Taylor County Airport', - state: 'WI', - lat: 45.10462, - lon: -90.30253, - }, - KMFI: { - id: 'KMFI', - city: 'Marshfield, Marshfield Municipal Airport', - state: 'WI', - lat: 44.63806, - lon: -90.1875, - }, - KMKE: { - id: 'KMKE', - city: 'Milwaukee, General Mitchell International Airport', - state: 'WI', - lat: 42.955, - lon: -87.9044399, - }, - KMRJ: { - id: 'KMRJ', - city: 'Iowa County Airport', - state: 'WI', - lat: 42.88754, - lon: -90.23147, - }, - KMSN: { - id: 'KMSN', - city: 'Madison, Dane County Regional-Truax Field', - state: 'WI', - lat: 43.14056, - lon: -89.34528, - }, - KMTW: { - id: 'KMTW', - city: 'Manitowoc, Manitowoc County Airport', - state: 'WI', - lat: 44.13333, - lon: -87.68333, - }, - KMWC: { - id: 'KMWC', - city: 'Milwaukee-Timmerman', - state: 'WI', - lat: 43.10961, - lon: -88.03048, - }, - KOCQ: { - id: 'KOCQ', - city: 'Oconto J. Douglas Bake Municipal Airport', - state: 'WI', - lat: 44.8742, - lon: -87.9096, - }, - KOEO: { - id: 'KOEO', - city: 'L O Simenstad Municipal Airport', - state: 'WI', - lat: 45.31084, - lon: -92.6948, - }, - KOLG: { - id: 'KOLG', - city: 'Solon Springs Municipal Airport', - state: 'WI', - lat: 46.3148, - lon: -91.8164, - }, - KOSH: { - id: 'KOSH', - city: 'Wittman Regional Airport', - state: 'WI', - lat: 43.96701, - lon: -88.55814, - }, - KOVS: { - id: 'KOVS', - city: 'Boscobel, Boscobel Airport', - state: 'WI', - lat: 43.15611, - lon: -90.6775, - }, - KPBH: { - id: 'KPBH', - city: 'Phillips / Price County', - state: 'WI', - lat: 45.7, - lon: -90.4, - }, - KPCZ: { - id: 'KPCZ', - city: 'Waupaca Municipal Airport', - state: 'WI', - lat: 44.33425, - lon: -89.02023, - }, - KPDC: { - id: 'KPDC', - city: 'Prairie Du Chien Municipal Airport', - state: 'WI', - lat: 43.01938, - lon: -91.12112, - }, - KPVB: { - id: 'KPVB', - city: 'Platteville Municipal Airport', - state: 'WI', - lat: 42.69092, - lon: -90.4412399, - }, - KRAC: { - id: 'KRAC', - city: 'Racine, Batten International Airport', - state: 'WI', - lat: 42.75861, - lon: -87.81778, - }, - KRCX: { - id: 'KRCX', - city: 'Ladysmith - Rusk County Airport', - state: 'WI', - lat: 45.4935, - lon: -90.9985, - }, - KRGK: { - id: 'KRGK', - city: 'Red Wing - Red Wing Regional Airport', - state: 'WI', - lat: 44.5926, - lon: -92.48439, - }, - KRHI: { - id: 'KRHI', - city: 'Rhinelander, Rhinelander-Oneida County Airport', - state: 'WI', - lat: 45.63167, - lon: -89.48222, - }, - KRNH: { - id: 'KRNH', - city: 'New Richmond Municipal Airport', - state: 'WI', - lat: 45.14762, - lon: -92.53349, - }, - KRPD: { - id: 'KRPD', - city: "Rice Lake, Rice Lake Regional-Carl's Field Airport", - state: 'WI', - lat: 45.4180599, - lon: -91.77361, - }, - KRRL: { - id: 'KRRL', - city: 'Merrill, Merrill Municipal Airport', - state: 'WI', - lat: 45.19844, - lon: -89.70996, - }, - KRYV: { - id: 'KRYV', - city: 'Watertown', - state: 'WI', - lat: 43.17016, - lon: -88.72497, - }, - KRZN: { - id: 'KRZN', - city: 'Siren, Burnett County Airport', - state: 'WI', - lat: 45.82278, - lon: -92.3725, - }, - KSBM: { - id: 'KSBM', - city: 'Sheboygan County Memorial Airport', - state: 'WI', - lat: 43.77483, - lon: -87.84897, - }, - KSTE: { - id: 'KSTE', - city: 'Stevens Point Municipal Airport', - state: 'WI', - lat: 44.54371, - lon: -89.53468, - }, - KSUE: { - id: 'KSUE', - city: 'Door County Cherryland Airport', - state: 'WI', - lat: 44.83941, - lon: -87.42188, - }, - KSUW: { - id: 'KSUW', - city: 'Richard I. Bong Airport', - state: 'WI', - lat: 46.68335, - lon: -92.09254, - }, - KTKV: { - id: 'KTKV', - city: 'Tomahawk Regional Airport', - state: 'WI', - lat: 45.46801, - lon: -89.80962, - }, - KUBE: { - id: 'KUBE', - city: 'Cumberland', - state: 'WI', - lat: 45.506, - lon: -91.9811, - }, - KUES: { - id: 'KUES', - city: 'Waukesha County Airport', - state: 'WI', - lat: 43.04245, - lon: -88.24607, - }, - KUNU: { - id: 'KUNU', - city: 'Juneau, Dodge County Airport', - state: 'WI', - lat: 43.42667, - lon: -88.7033299, - }, - KVOK: { - id: 'KVOK', - city: 'Volk / Camp Douglas', - state: 'WI', - lat: 43.93333, - lon: -90.26667, - }, - KACY: { - id: 'KACY', - city: 'Atlantic City, Atlantic City International Airport', - state: 'NJ', - lat: 39.45202, - lon: -74.56699, - }, - KBLM: { - id: 'KBLM', - city: 'Belmar-Farmingdale', - state: 'NJ', - lat: 40.18333, - lon: -74.13333, - }, - KCDW: { - id: 'KCDW', - city: 'Caldwell, Essex County Airport', - state: 'NJ', - lat: 40.87639, - lon: -74.28306, - }, - KEWR: { - id: 'KEWR', - city: 'Newark, Newark International Airport', - state: 'NJ', - lat: 40.6825, - lon: -74.16944, - }, - KFWN: { - id: 'KFWN', - city: 'Sussex, Sussex Airport', - state: 'NJ', - lat: 41.19925, - lon: -74.62594, - }, - KLDJ: { - id: 'KLDJ', - city: 'Linden Airport', - state: 'NJ', - lat: 40.6174, - lon: -74.2446, - }, - KMIV: { - id: 'KMIV', - city: 'Millville, Millville Municipal Airport', - state: 'NJ', - lat: 39.36623, - lon: -75.0778, - }, - KMJX: { - id: 'KMJX', - city: 'Miller Air Park', - state: 'NJ', - lat: 39.927, - lon: -74.292, - }, - KMMU: { - id: 'KMMU', - city: 'Morristown Municipal', - state: 'NJ', - lat: 40.8, - lon: -74.41667, - }, - KNEL: { - id: 'KNEL', - city: 'Lakehurst Naval Air Station', - state: 'NJ', - lat: 40.03661, - lon: -74.35251, - }, - KOBI: { - id: 'KOBI', - city: 'CAPE MAY', - state: 'NJ', - lat: 39.2191, - lon: -74.7948, - }, - KSMQ: { - id: 'KSMQ', - city: 'Somerville, Somerset Airport', - state: 'NJ', - lat: 40.6240499, - lon: -74.66898, - }, - KTEB: { - id: 'KTEB', - city: 'Teterboro, Teterboro Airport', - state: 'NJ', - lat: 40.85889, - lon: -74.05667, - }, - KTTN: { - id: 'KTTN', - city: 'Trenton, Mercer County Airport', - state: 'NJ', - lat: 40.27639, - lon: -74.81639, - }, - KVAY: { - id: 'KVAY', - city: 'Mount Holly, South Jersey Regional Airport', - state: 'NJ', - lat: 39.94076, - lon: -74.84071, - }, - KWRI: { - id: 'KWRI', - city: 'Mcguire Air Force Base', - state: 'NJ', - lat: 40.01667, - lon: -74.6, - }, - KWWD: { - id: 'KWWD', - city: 'Wildwood, Cape May County Airport', - state: 'NJ', - lat: 39.01667, - lon: -74.91667, - }, - KELO: { - id: 'KELO', - city: 'Ely, Ely Municipal Airport', - state: 'MN', - lat: 47.81667, - lon: -91.83333, - }, - KEVM: { - id: 'KEVM', - city: 'Eveleth-Virginia Municipal Airport', - state: 'MN', - lat: 47.4274, - lon: -92.49717, - }, - KFBL: { - id: 'KFBL', - city: 'Faribault, Faribault Municipal Airport', - state: 'MN', - lat: 44.32983, - lon: -93.31186, - }, - KFCM: { - id: 'KFCM', - city: 'Minneapolis - Flying Cloud Airport', - state: 'MN', - lat: 44.83217, - lon: -93.47051, - }, - KFFM: { - id: 'KFFM', - city: 'Fergus Falls Municipal Airport-Einar Mickel', - state: 'MN', - lat: 46.28655, - lon: -96.15338, - }, - KFGN: { - id: 'KFGN', - city: 'Flag Island', - state: 'MN', - lat: 49.31667, - lon: -94.9, - }, - KFKA: { - id: 'KFKA', - city: 'Preston, Fillmore County Airport', - state: 'MN', - lat: 43.67701, - lon: -92.17422, - }, - KFOZ: { - id: 'KFOZ', - city: 'Bigfork Municipal Airport', - state: 'MN', - lat: 47.78317, - lon: -93.65326, - }, - KFRM: { - id: 'KFRM', - city: 'Fairmont, Fairmont Municipal Airport', - state: 'MN', - lat: 43.65, - lon: -94.41667, - }, - KFSE: { - id: 'KFSE', - city: 'Fosston, Fosston Municipal Airport', - state: 'MN', - lat: 47.59278, - lon: -95.77333, - }, - KGDB: { - id: 'KGDB', - city: 'Granite Falls, Granite Falls Municipal Airport/Lenzen-Roe Memorial Field', - state: 'MN', - lat: 44.75306, - lon: -95.55583, - }, - KGHW: { - id: 'KGHW', - city: 'Glenwood Municipal Airport', - state: 'MN', - lat: 45.64564, - lon: -95.31876, - }, - KGNA: { - id: 'KGNA', - city: 'Grand Marais, The Bay of Grand Marais', - state: 'MN', - lat: 47.7472, - lon: -90.3443999, - }, - KGPZ: { - id: 'KGPZ', - city: 'Grand Rapids, Grand Rapids/Itasca County Airport-Gordon Newstrom Field', - state: 'MN', - lat: 47.21667, - lon: -93.51667, - }, - KGYL: { - id: 'KGYL', - city: 'Glencoe Municipal Airport', - state: 'MN', - lat: 44.7588, - lon: -94.0905, - }, - KHCD: { - id: 'KHCD', - city: 'Hutchinson, Hutchinson Municipal Airport-Butler Field', - state: 'MN', - lat: 44.85961, - lon: -94.38551, - }, - KHCO: { - id: 'KHCO', - city: 'Hallock Municipal Airport', - state: 'MN', - lat: 48.75245, - lon: -96.93759, - }, - KHIB: { - id: 'KHIB', - city: 'Chisholm-Hibbing Airport', - state: 'MN', - lat: 47.38039, - lon: -92.83245, - }, - KHZX: { - id: 'KHZX', - city: 'Mc Gregor - Isedor Iverson Airport', - state: 'MN', - lat: 46.61904, - lon: -93.31267, - }, - KINL: { - id: 'KINL', - city: 'Falls International Airport', - state: 'MN', - lat: 48.55944, - lon: -93.39556, - }, - KJKJ: { - id: 'KJKJ', - city: 'Moorhead Municipal Airport', - state: 'MN', - lat: 46.8404, - lon: -96.65442, - }, - KJMR: { - id: 'KJMR', - city: 'Mora Municipal Airport', - state: 'MN', - lat: 45.88863, - lon: -93.26901, - }, - KJYG: { - id: 'KJYG', - city: 'St. James Municipal Airport', - state: 'MN', - lat: 43.98558, - lon: -94.55299, - }, - KLJF: { - id: 'KLJF', - city: 'Litchfield Municipal Airport', - state: 'MN', - lat: 45.09485, - lon: -94.50837, - }, - KLVN: { - id: 'KLVN', - city: 'Minneapolis, Airlake Airport', - state: 'MN', - lat: 44.62778, - lon: -93.22806, - }, - KLXL: { - id: 'KLXL', - city: 'Little Falls, Little Falls/Morrison County Airport-Lindbergh Field', - state: 'MN', - lat: 45.95, - lon: -94.35, - }, - KLYV: { - id: 'KLYV', - city: 'Quentin Aanenson Field Airport', - state: 'MN', - lat: 43.62166, - lon: -96.2139399, - }, - KMGG: { - id: 'KMGG', - city: 'Maple Lake, Maple Lake Municipal Airport', - state: 'MN', - lat: 45.2353499, - lon: -93.98959, - }, - KMIC: { - id: 'KMIC', - city: 'Minneapolis, Crystal Airport', - state: 'MN', - lat: 45.0625, - lon: -93.35083, - }, - KMJQ: { - id: 'KMJQ', - city: 'Jackson, Jackson Municipal Airport', - state: 'MN', - lat: 43.65, - lon: -94.98333, - }, - KMKT: { - id: 'KMKT', - city: 'Mankato, Mankato Regional Airport', - state: 'MN', - lat: 44.21667, - lon: -93.91667, - }, - KMML: { - id: 'KMML', - city: 'Marshall, Southwest Minnesota Regional Airport - Marshall/Ryan Field', - state: 'MN', - lat: 44.45, - lon: -95.81667, - }, - KMOX: { - id: 'KMOX', - city: 'Morris, Morris Municipal Airport', - state: 'MN', - lat: 45.56667, - lon: -95.9666699, - }, - KMSP: { - id: 'KMSP', - city: 'Minneapolis, Minneapolis-St. Paul International Airport', - state: 'MN', - lat: 44.88306, - lon: -93.22889, - }, - KMVE: { - id: 'KMVE', - city: 'Montevideo-Chippewa County Airport', - state: 'MN', - lat: 44.96749, - lon: -95.71159, - }, - KMWM: { - id: 'KMWM', - city: 'Windom Municipal Airport', - state: 'MN', - lat: 43.90999, - lon: -95.10723, - }, - KMZH: { - id: 'KMZH', - city: 'Moose Lake Carlton County Airport', - state: 'MN', - lat: 46.41632, - lon: -92.80491, - }, - KONA: { - id: 'KONA', - city: 'Winona, Winona Municipal Airport-Max Conrad Field', - state: 'MN', - lat: 44.0833299, - lon: -91.7, - }, - KORB: { - id: 'KORB', - city: 'Orr Regional Airport', - state: 'MN', - lat: 48.0170699, - lon: -92.85376, - }, - KOTG: { - id: 'KOTG', - city: 'Worthington, Worthington Municipal Airport', - state: 'MN', - lat: 43.65, - lon: -95.58333, - }, - KOVL: { - id: 'KOVL', - city: 'Olivia Regional Airport', - state: 'MN', - lat: 44.77923, - lon: -95.03033, - }, - KOWA: { - id: 'KOWA', - city: 'Owatonna Degner Regional Airport', - state: 'MN', - lat: 44.11907, - lon: -93.25687, - }, - KPEX: { - id: 'KPEX', - city: 'Paynesville, Paynesville Municipal Airport', - state: 'MN', - lat: 45.37247, - lon: -94.73878, - }, - KPKD: { - id: 'KPKD', - city: 'Park Rapids Municipal Airport', - state: 'MN', - lat: 46.8996799, - lon: -95.06681, - }, - KPNM: { - id: 'KPNM', - city: 'Princeton', - state: 'MN', - lat: 45.56425, - lon: -93.6080099, - }, - KPWC: { - id: 'KPWC', - city: 'Pine River Regional Airport', - state: 'MN', - lat: 46.72654, - lon: -94.38485, - }, - KROS: { - id: 'KROS', - city: 'Rush City Regional Airport', - state: 'MN', - lat: 45.69628, - lon: -92.95424, - }, - KROX: { - id: 'KROX', - city: 'Roseau, Roseau Municipal Airport/Rudy Billberg Field', - state: 'MN', - lat: 48.85, - lon: -95.7, - }, - KRRT: { - id: 'KRRT', - city: 'Warroad International Memorial Airport', - state: 'MN', - lat: 48.93183, - lon: -95.3404599, - }, - KRST: { - id: 'KRST', - city: 'Rochester, Rochester International Airport', - state: 'MN', - lat: 43.90417, - lon: -92.49167, - }, - KRWF: { - id: 'KRWF', - city: 'Redwood Falls Municipal Airport', - state: 'MN', - lat: 44.54828, - lon: -95.08042, - }, - KSAZ: { - id: 'KSAZ', - city: 'Staples, Staples Municipal Airport', - state: 'MN', - lat: 46.38083, - lon: -94.80667, - }, - KSGS: { - id: 'KSGS', - city: 'South St. Paul Municipal-Richard E. Flemi', - state: 'MN', - lat: 44.86006, - lon: -93.03203, - }, - KSTC: { - id: 'KSTC', - city: 'St. Cloud Regional Airport', - state: 'MN', - lat: 45.54415, - lon: -94.05165, - }, - KSTP: { - id: 'KSTP', - city: 'Downtown Holman Field', - state: 'MN', - lat: 44.93237, - lon: -93.05588, - }, - KSYN: { - id: 'KSYN', - city: 'Stanton Airfield', - state: 'MN', - lat: 44.4736199, - lon: -93.01448, - }, - KTKC: { - id: 'KTKC', - city: 'Tracy, Tracy Municipal Airport', - state: 'MN', - lat: 44.24951, - lon: -95.61189, - }, - KTOB: { - id: 'KTOB', - city: 'Dodge Center Airport', - state: 'MN', - lat: 44.02026, - lon: -92.8295, - }, - KTVF: { - id: 'KTVF', - city: 'Thief River Falls, Thief River Falls Regional Airport', - state: 'MN', - lat: 48.06667, - lon: -96.18333, - }, - KTWM: { - id: 'KTWM', - city: 'Two Harbors', - state: 'MN', - lat: 47.05, - lon: -91.75, - }, - KULM: { - id: 'KULM', - city: 'New Ulm Municipal Airport', - state: 'MN', - lat: 44.32274, - lon: -94.50244, - }, - KVVV: { - id: 'KVVV', - city: 'Ortonville, Ortonville Muncipal-Martinson Field Airport', - state: 'MN', - lat: 45.30556, - lon: -96.42444, - }, - KVWU: { - id: 'KVWU', - city: 'Waskish Municipal Airport', - state: 'MN', - lat: 48.15014, - lon: -94.512, - }, - KXVG: { - id: 'KXVG', - city: 'Longville, Longville Municipal Airport', - state: 'MN', - lat: 46.99028, - lon: -94.20389, - }, - PCKY: { - id: 'PCKY', - city: 'Pacific Creek at Moran, WY', - state: 'WY', - lat: 43.8502777, - lon: -110.5177777, - }, - KBCE: { - id: 'KBCE', - city: 'Bryce Canyon Airport', - state: 'UT', - lat: 37.7012799, - lon: -112.14897, - }, - KBDG: { - id: 'KBDG', - city: 'Blanding Municipal Airport', - state: 'UT', - lat: 37.586, - lon: -109.482, - }, - KBMC: { - id: 'KBMC', - city: 'Brigham City Regional Airport', - state: 'UT', - lat: 41.5464, - lon: -112.0601, - }, - KCDC: { - id: 'KCDC', - city: 'Cedar City Municipal Airport', - state: 'UT', - lat: 37.70675, - lon: -113.09695, - }, - KCNY: { - id: 'KCNY', - city: 'Moab, Canyonlands Field', - state: 'UT', - lat: 38.76, - lon: -109.74472, - }, - KDPG: { - id: 'KDPG', - city: 'Michael Army Airfield - Dugway Proving Ground', - state: 'UT', - lat: 40.18376, - lon: -112.9217, - }, - KDTA: { - id: 'KDTA', - city: 'Delta, Delta Municipal Airport', - state: 'UT', - lat: 39.38333, - lon: -112.50967, - }, - KENV: { - id: 'KENV', - city: 'Wendover Airport', - state: 'UT', - lat: 40.72056, - lon: -114.03583, - }, - KFOM: { - id: 'KFOM', - city: 'Fillmore', - state: 'UT', - lat: 38.95814, - lon: -112.36314, - }, - KHCR: { - id: 'KHCR', - city: 'Heber Valley Airport', - state: 'UT', - lat: 40.47742, - lon: -111.43295, - }, - KHIF: { - id: 'KHIF', - city: 'Hill Air Force Base', - state: 'UT', - lat: 41.11112, - lon: -111.96229, - }, - KHVE: { - id: 'KHVE', - city: 'Hanksville', - state: 'UT', - lat: 38.418037, - lon: -110.704038, - }, - KKNB: { - id: 'KKNB', - city: 'KANAB MUNICIPAL AIRPORT', - state: 'UT', - lat: 37.01, - lon: -112.53, - }, - KLGU: { - id: 'KLGU', - city: 'Logan-Cache Airport', - state: 'UT', - lat: 41.78652, - lon: -111.85187, - }, - KMLF: { - id: 'KMLF', - city: 'Milford Municipal Airport', - state: 'UT', - lat: 38.42252, - lon: -113.01089, - }, - KOGD: { - id: 'KOGD', - city: 'Ogden-Hinckley Airport', - state: 'UT', - lat: 41.19406, - lon: -112.01681, - }, - KPUC: { - id: 'KPUC', - city: 'Price - Carbon County Regional Airport', - state: 'UT', - lat: 39.60886, - lon: -110.75548, - }, - KPVU: { - id: 'KPVU', - city: 'Provo Municipal Airport', - state: 'UT', - lat: 40.2239, - lon: -111.7253, - }, - KRIF: { - id: 'KRIF', - city: 'Richfield Municipal Airport', - state: 'UT', - lat: 38.73411, - lon: -112.10158, - }, - KSGU: { - id: 'KSGU', - city: 'St George Regional Airport', - state: 'UT', - lat: 37.0451, - lon: -113.50561, - }, - KSLC: { - id: 'KSLC', - city: 'Salt Lake City, Salt Lake City International Airport', - state: 'UT', - lat: 40.77069, - lon: -111.96503, - }, - KSPK: { - id: 'KSPK', - city: 'Spanish Fork Municipal Airport', - state: 'UT', - lat: 40.145, - lon: -111.6677, - }, - KSVR: { - id: 'KSVR', - city: 'South Valley Regional Airport', - state: 'UT', - lat: 40.6196, - lon: -111.99016, - }, - KTVY: { - id: 'KTVY', - city: 'Bolinder Field-Tooele Valley Airport', - state: 'UT', - lat: 40.61269, - lon: -112.35362, - }, - KVEL: { - id: 'KVEL', - city: 'Vernal Airport', - state: 'UT', - lat: 40.44295, - lon: -109.51273, - }, - KAAO: { - id: 'KAAO', - city: 'Wichita Jabara Airport', - state: 'KS', - lat: 37.74969, - lon: -97.21908, - }, - KADT: { - id: 'KADT', - city: 'Atwood-Rawlins County City-County Airport', - state: 'KS', - lat: 39.84034, - lon: -101.04248, - }, - KBEC: { - id: 'KBEC', - city: 'Beech Factory Airport', - state: 'KS', - lat: 37.69392, - lon: -97.21492, - }, - KCBK: { - id: 'KCBK', - city: 'Shalz Field Airport', - state: 'KS', - lat: 39.42746, - lon: -101.04662, - }, - KCFV: { - id: 'KCFV', - city: 'Coffeyville, Coffeyville Municipal Airport', - state: 'KS', - lat: 37.09111, - lon: -95.56639, - }, - KCNK: { - id: 'KCNK', - city: 'Concordia, Blosser Municipal Airport', - state: 'KS', - lat: 39.55139, - lon: -97.65056, - }, - KCNU: { - id: 'KCNU', - city: 'Chanute, Chanute Martin Johnson Airport', - state: 'KS', - lat: 37.67028, - lon: -95.48417, - }, - KDDC: { - id: 'KDDC', - city: 'Dodge City, Dodge City Regional Airport', - state: 'KS', - lat: 37.77278, - lon: -99.96972, - }, - KEGT: { - id: 'KEGT', - city: 'WELLINGTON', - state: 'KS', - lat: 37.32361, - lon: -97.38834, - }, - KEHA: { - id: 'KEHA', - city: 'Elkhart, Elkhart-Morton County Airport', - state: 'KS', - lat: 37, - lon: -101.88333, - }, - KEMP: { - id: 'KEMP', - city: 'Emporia, Emporia Municipal Airport', - state: 'KS', - lat: 38.32889, - lon: -96.19389, - }, - KEQA: { - id: 'KEQA', - city: 'El Dorado Captain Jack Thomas Airport', - state: 'KS', - lat: 37.77534, - lon: -96.81449, - }, - KEWK: { - id: 'KEWK', - city: 'Newton, Newton City/County Airport', - state: 'KS', - lat: 38.05, - lon: -97.28333, - }, - KFOE: { - id: 'KFOE', - city: 'Topeka, Forbes Field', - state: 'KS', - lat: 38.94139, - lon: -95.65056, - }, - KFRI: { - id: 'KFRI', - city: 'Fort Riley - Marshall AAF', - state: 'KS', - lat: 39.05586, - lon: -96.76166, - }, - KFSK: { - id: 'KFSK', - city: 'FORT SCOTT', - state: 'KS', - lat: 37.79833, - lon: -94.76933, - }, - KGBD: { - id: 'KGBD', - city: 'Great Bend, Great Bend Municipal Airport', - state: 'KS', - lat: 38.35, - lon: -98.86667, - }, - KGCK: { - id: 'KGCK', - city: 'Garden City Regional Airport', - state: 'KS', - lat: 37.9275, - lon: -100.72444, - }, - KGLD: { - id: 'KGLD', - city: 'Goodland, Renner Field', - state: 'KS', - lat: 39.3675, - lon: -101.69306, - }, - KHLC: { - id: 'KHLC', - city: 'Hill City, Hill City Municipal Airport', - state: 'KS', - lat: 39.37472, - lon: -99.82972, - }, - KHQG: { - id: 'KHQG', - city: 'Hugoton Municipal Airport', - state: 'KS', - lat: 37.16308, - lon: -101.37052, - }, - KHUT: { - id: 'KHUT', - city: 'Hutchinson, Hutchinson Municipal Airport', - state: 'KS', - lat: 38.06806, - lon: -97.86056, - }, - KHYS: { - id: 'KHYS', - city: 'Hays, Hays Regional Airport', - state: 'KS', - lat: 38.85, - lon: -99.26667, - }, - KIAB: { - id: 'KIAB', - city: 'McConnell Air Force Base', - state: 'KS', - lat: 37.61667, - lon: -97.26667, - }, - KICT: { - id: 'KICT', - city: 'Wichita - Wichita Dwight D. Eisenhower National Airport', - state: 'KS', - lat: 37.64722, - lon: -97.42944, - }, - KIDP: { - id: 'KIDP', - city: 'INDEPENDENCE', - state: 'KS', - lat: 37.1584, - lon: -95.7784, - }, - KIXD: { - id: 'KIXD', - city: 'Olathe, New Century Aircenter', - state: 'KS', - lat: 38.82444, - lon: -94.88694, - }, - KJHN: { - id: 'KJHN', - city: 'Stanton County Municipal Airport', - state: 'KS', - lat: 37.5782, - lon: -101.7304, - }, - KLBL: { - id: 'KLBL', - city: 'Liberal, Liberal Municipal Airport', - state: 'KS', - lat: 37.05, - lon: -100.9666699, - }, - KLWC: { - id: 'KLWC', - city: 'Lawrence, Lawrence Municipal Airport', - state: 'KS', - lat: 39.00833, - lon: -95.21167, - }, - KLYO: { - id: 'KLYO', - city: 'Lyons-Rice County Municipal Airport', - state: 'KS', - lat: 38.34025, - lon: -98.22856, - }, - KMHK: { - id: 'KMHK', - city: 'Manhattan, Manhattan Municipal Airport', - state: 'KS', - lat: 39.13528, - lon: -96.67778, - }, - KMPR: { - id: 'KMPR', - city: 'MCPHERSON', - state: 'KS', - lat: 38.35244, - lon: -97.6913299, - }, - KMYZ: { - id: 'KMYZ', - city: 'Marysville Municipal Airport', - state: 'KS', - lat: 39.8553, - lon: -96.6306, - }, - KNRN: { - id: 'KNRN', - city: 'Norton Municipal Airport', - state: 'KS', - lat: 39.85047, - lon: -99.89469, - }, - KOEL: { - id: 'KOEL', - city: 'Oakley Municipal Airport', - state: 'KS', - lat: 39.11178, - lon: -100.81667, - }, - KOIN: { - id: 'KOIN', - city: 'Oberlin Municipal Airport', - state: 'KS', - lat: 39.83489, - lon: -100.5397799, - }, - KOJC: { - id: 'KOJC', - city: 'Olathe, Johnson County Executive Airport', - state: 'KS', - lat: 38.85, - lon: -94.73917, - }, - KOWI: { - id: 'KOWI', - city: 'Ottawa Municipal Airport', - state: 'KS', - lat: 38.5409, - lon: -95.2542, - }, - KPHG: { - id: 'KPHG', - city: 'PHILLIPSBURG', - state: 'KS', - lat: 39.735, - lon: -99.3171, - }, - KPPF: { - id: 'KPPF', - city: 'Parsons, Tri-City Airport', - state: 'KS', - lat: 37.32778, - lon: -95.50417, - }, - KPTS: { - id: 'KPTS', - city: 'Atkinson Municipal Airport', - state: 'KS', - lat: 37.4494, - lon: -94.7311, - }, - KPTT: { - id: 'KPTT', - city: 'Pratt Municipal', - state: 'KS', - lat: 37.7, - lon: -98.75, - }, - KRSL: { - id: 'KRSL', - city: 'Russell, Russell Municipal Airport', - state: 'KS', - lat: 38.87278, - lon: -98.8130599, - }, - KSLN: { - id: 'KSLN', - city: 'Salina, Salina Municipal Airport', - state: 'KS', - lat: 38.78, - lon: -97.64417, - }, - KSYF: { - id: 'KSYF', - city: 'ST FRANCIS', - state: 'KS', - lat: 39.763884, - lon: -101.797861, - }, - KTOP: { - id: 'KTOP', - city: 'Topeka, Philip Billard Municipal Airport', - state: 'KS', - lat: 39.0725, - lon: -95.6258299, - }, - KTQK: { - id: 'KTQK', - city: 'Scott City Municipal Airport', - state: 'KS', - lat: 38.47502, - lon: -100.88444, - }, - KUKL: { - id: 'KUKL', - city: 'Coffey County Airport', - state: 'KS', - lat: 38.30247, - lon: -95.72497, - }, - KULS: { - id: 'KULS', - city: 'Ulysses Airport', - state: 'KS', - lat: 37.604, - lon: -101.37356, - }, - KWLD: { - id: 'KWLD', - city: 'Winfield / Arkansas City, Strother Field', - state: 'KS', - lat: 37.1680599, - lon: -97.03694, - }, - KALW: { - id: 'KALW', - city: 'Walla Walla Regional Airport', - state: 'WA', - lat: 46.09462, - lon: -118.2858, - }, - KAWO: { - id: 'KAWO', - city: 'Arlington Municipal Airport', - state: 'WA', - lat: 48.1584999, - lon: -122.15909, - }, - KBFI: { - id: 'KBFI', - city: 'Boeing Field - King County International Airport', - state: 'WA', - lat: 47.54548, - lon: -122.3147, - }, - KBLI: { - id: 'KBLI', - city: 'Bellingham, Bellingham International Airport', - state: 'WA', - lat: 48.79911, - lon: -122.54064, - }, - KBVS: { - id: 'KBVS', - city: 'Burlington/Mount Vernon, Skagit Regional Airport', - state: 'WA', - lat: 48.47083, - lon: -122.42083, - }, - KCLM: { - id: 'KCLM', - city: 'Port Angeles Fairchild International Airport', - state: 'WA', - lat: 48.12194, - lon: -123.50661, - }, - KCLS: { - id: 'KCLS', - city: 'Chehalis-Centralia Airport', - state: 'WA', - lat: 46.677, - lon: -122.9827, - }, - KDEW: { - id: 'KDEW', - city: 'Deer Park, Deer Park Airport', - state: 'WA', - lat: 47.97417, - lon: -117.42833, - }, - KDLS: { - id: 'KDLS', - city: 'The Dalles Municipal Airport', - state: 'WA', - lat: 45.61901, - lon: -121.16572, - }, - KEAT: { - id: 'KEAT', - city: 'Wenatchee - Pangborn Memorial Airport', - state: 'WA', - lat: 47.39749, - lon: -120.20121, - }, - KELN: { - id: 'KELN', - city: 'Ellensburg, Ellensburg Bowers Field', - state: 'WA', - lat: 47.0337699, - lon: -120.53132, - }, - KEPH: { - id: 'KEPH', - city: 'Ephrata, Ephrata Municipal Airport', - state: 'WA', - lat: 47.3075, - lon: -119.51583, - }, - KFHR: { - id: 'KFHR', - city: 'Friday Harbor Airport', - state: 'WA', - lat: 48.52, - lon: -123.02637, - }, - KFLW: { - id: 'KFLW', - city: 'Kettle Falls', - state: 'WA', - lat: 48.595, - lon: -118.12417, - }, - KGEG: { - id: 'KGEG', - city: 'Spokane, Spokane International Airport', - state: 'WA', - lat: 47.62139, - lon: -117.52778, - }, - KGRF: { - id: 'KGRF', - city: 'Fort Lewis / Gray U. S. Army Airfield', - state: 'WA', - lat: 47.11667, - lon: -122.55, - }, - KHQM: { - id: 'KHQM', - city: 'Hoquiam, Bowerman Airport', - state: 'WA', - lat: 46.97111, - lon: -123.92, - }, - KKLS: { - id: 'KKLS', - city: 'Southwest Washington Regional Airport', - state: 'WA', - lat: 46.11553, - lon: -122.89273, - }, - KMWH: { - id: 'KMWH', - city: 'Grant County Airport', - state: 'WA', - lat: 47.19299, - lon: -119.31451, - }, - KNCW: { - id: 'KNCW', - city: 'KENNEWICK CANAL', - state: 'WA', - lat: 46.2652777, - lon: -119.5694444, - }, - KNOW: { - id: 'KNOW', - city: 'Port Angeles Coast Guard Air Station', - state: 'WA', - lat: 48.13333, - lon: -123.4, - }, - KNRA: { - id: 'KNRA', - city: 'Coupeville, Outlying Landing Field', - state: 'WA', - lat: 48.19056, - lon: -122.63056, - }, - KNUW: { - id: 'KNUW', - city: 'Whidbey Island Naval Air Station - Ault Field', - state: 'WA', - lat: 48.35525, - lon: -122.66352, - }, - KOLM: { - id: 'KOLM', - city: 'Olympia, Olympia Airport', - state: 'WA', - lat: 46.97333, - lon: -122.90333, - }, - KOMK: { - id: 'KOMK', - city: 'Omak Airport', - state: 'WA', - lat: 48.46116, - lon: -119.52086, - }, - KORS: { - id: 'KORS', - city: 'Eastsound, Orcas Island Airport', - state: 'WA', - lat: 48.70806, - lon: -122.91028, - }, - KPAE: { - id: 'KPAE', - city: 'Everett Snohomish County', - state: 'WA', - lat: 47.92331, - lon: -122.28305, - }, - KPLU: { - id: 'KPLU', - city: 'Pierce County-Thun Field', - state: 'WA', - lat: 47.104, - lon: -122.287, - }, - KPSC: { - id: 'KPSC', - city: 'Tri-Cities Airport', - state: 'WA', - lat: 46.26955, - lon: -119.11813, - }, - KPUW: { - id: 'KPUW', - city: 'Pullman / Moscow Regional Airport', - state: 'WA', - lat: 46.74377, - lon: -117.11579, - }, - KPWT: { - id: 'KPWT', - city: 'Bremerton, Bremerton National Airport', - state: 'WA', - lat: 47.5, - lon: -122.75, - }, - KRLD: { - id: 'KRLD', - city: 'Richland Airport', - state: 'WA', - lat: 46.30859, - lon: -119.3058, - }, - KRNT: { - id: 'KRNT', - city: 'Renton Municipal Airport', - state: 'WA', - lat: 47.49509, - lon: -122.21437, - }, - KSEA: { - id: 'KSEA', - city: 'Seattle, Seattle-Tacoma International Airport', - state: 'WA', - lat: 47.4447199, - lon: -122.31361, - }, - KSFF: { - id: 'KSFF', - city: 'Spokane, Felts Field', - state: 'WA', - lat: 47.68556, - lon: -117.32028, - }, - KSHN: { - id: 'KSHN', - city: 'Shelton, Shelton Sanderson Field', - state: 'WA', - lat: 47.23806, - lon: -123.14083, - }, - KSKA: { - id: 'KSKA', - city: 'Fairchild Air Force Base', - state: 'WA', - lat: 47.61667, - lon: -117.65, - }, - KSMP: { - id: 'KSMP', - city: 'Stampede Pass', - state: 'WA', - lat: 47.27648, - lon: -121.33817, - }, - KTCM: { - id: 'KTCM', - city: 'Tacoma / McChord Air Force Base', - state: 'WA', - lat: 47.15, - lon: -122.48333, - }, - KTCW: { - id: 'KTCW', - city: 'KITTITAS CANAL', - state: 'WA', - lat: 47.2388888, - lon: -121.1833333, - }, - KTIW: { - id: 'KTIW', - city: 'Tacoma, Tacoma Narrows Airport', - state: 'WA', - lat: 47.2675, - lon: -122.57611, - }, - KUIL: { - id: 'KUIL', - city: 'Quillayute, Quillayute State Airport', - state: 'WA', - lat: 47.9375, - lon: -124.555, - }, - KVUO: { - id: 'KVUO', - city: 'Pearson Airfield', - state: 'WA', - lat: 45.62103, - lon: -122.65419, - }, - KYKM: { - id: 'KYKM', - city: 'Yakima Air Terminal - McAllister Field', - state: 'WA', - lat: 46.56402, - lon: -120.53484, - }, - KABE: { - id: 'KABE', - city: 'Allentown, Lehigh Valley International Airport', - state: 'PA', - lat: 40.64985, - lon: -75.44771, - }, - KAFJ: { - id: 'KAFJ', - city: 'Washington County Airport', - state: 'PA', - lat: 40.13624, - lon: -80.28512, - }, - KAGC: { - id: 'KAGC', - city: 'Pittsburgh - Allegheny County Airport', - state: 'PA', - lat: 40.35521, - lon: -79.92144, - }, - KAOO: { - id: 'KAOO', - city: 'Altoona - Blair County Airport', - state: 'PA', - lat: 40.29994, - lon: -78.3168, - }, - KAVP: { - id: 'KAVP', - city: 'Wilkes-Barre - Scranton, Wilkes-Barre / Scranton International Airport', - state: 'PA', - lat: 41.33889, - lon: -75.72667, - }, - KBFD: { - id: 'KBFD', - city: 'Bradford Regional Airport', - state: 'PA', - lat: 41.79838, - lon: -78.63539, - }, - KBTP: { - id: 'KBTP', - city: 'Pittsburgh/Butler Regional Airport', - state: 'PA', - lat: 40.77658, - lon: -79.95672, - }, - KBVI: { - id: 'KBVI', - city: 'Beaver County Airport', - state: 'PA', - lat: 40.77351, - lon: -80.38248, - }, - KCKZ: { - id: 'KCKZ', - city: 'Pennridge Airport', - state: 'PA', - lat: 40.38919, - lon: -75.29047, - }, - KCXY: { - id: 'KCXY', - city: 'Harrisburg, Capital City Airport', - state: 'PA', - lat: 40.21843, - lon: -76.8552, - }, - KDUJ: { - id: 'KDUJ', - city: 'Du Bois - Jefferson County Airport', - state: 'PA', - lat: 41.17948, - lon: -78.89326, - }, - KDYL: { - id: 'KDYL', - city: 'Doylestown, Doylestown Airport', - state: 'PA', - lat: 40.33016, - lon: -75.12286, - }, - KERI: { - id: 'KERI', - city: 'Erie, Erie International Airport', - state: 'PA', - lat: 42.08, - lon: -80.1825, - }, - KFIG: { - id: 'KFIG', - city: 'Clearfield, Clearfield-Lawrence Airport', - state: 'PA', - lat: 41.04667, - lon: -78.41167, - }, - KFKL: { - id: 'KFKL', - city: 'Venango Regional Airport', - state: 'PA', - lat: 41.38051, - lon: -79.86029, - }, - KGKJ: { - id: 'KGKJ', - city: 'Port Meadville Airport', - state: 'PA', - lat: 41.6258399, - lon: -80.21231, - }, - KHMZ: { - id: 'KHMZ', - city: 'Bedford, Bedford County Airport', - state: 'PA', - lat: 40.08528, - lon: -78.51222, - }, - KHZL: { - id: 'KHZL', - city: 'Hazleton Municipal Airport', - state: 'PA', - lat: 40.98447, - lon: -75.99005, - }, - KIDI: { - id: 'KIDI', - city: 'Indiana County Airport - Jimmy Stewart Field', - state: 'PA', - lat: 40.6337199, - lon: -79.10362, - }, - KIPT: { - id: 'KIPT', - city: 'Williamsport - Lycoming County Airport', - state: 'PA', - lat: 41.24298, - lon: -76.92173, - }, - KJST: { - id: 'KJST', - city: 'Johnstown - Cambria County Airport', - state: 'PA', - lat: 40.3149, - lon: -78.83074, - }, - KLBE: { - id: 'KLBE', - city: 'Arnold Palmer Regional Airport', - state: 'PA', - lat: 40.2767399, - lon: -79.40393, - }, - KLNS: { - id: 'KLNS', - city: 'Lancaster, Lancaster Airport', - state: 'PA', - lat: 40.1205799, - lon: -76.29446, - }, - KLOM: { - id: 'KLOM', - city: 'Philadelphia - Wings Field Airport', - state: 'PA', - lat: 40.13758, - lon: -75.2684, - }, - KMDT: { - id: 'KMDT', - city: 'Harrisburg, Harrisburg International Airport', - state: 'PA', - lat: 40.19361, - lon: -76.76333, - }, - KMPO: { - id: 'KMPO', - city: 'Mount Pocono, Pocono Mountains Municipal Airport', - state: 'PA', - lat: 41.13821, - lon: -75.37971, - }, - KMQS: { - id: 'KMQS', - city: 'Chester County Airport', - state: 'PA', - lat: 39.98333, - lon: -75.86667, - }, - KMUI: { - id: 'KMUI', - city: 'Muir Army Air Field / Indiantown', - state: 'PA', - lat: 40.43808, - lon: -76.56434, - }, - KOQN: { - id: 'KOQN', - city: 'Brandywine Regional Airport', - state: 'PA', - lat: 39.99011, - lon: -75.5819, - }, - KOYM: { - id: 'KOYM', - city: 'St Marys Municipal Airport', - state: 'PA', - lat: 41.41248, - lon: -78.50263, - }, - KPHL: { - id: 'KPHL', - city: 'Philadelphia, Philadelphia International Airport', - state: 'PA', - lat: 39.87327, - lon: -75.22678, - }, - KPIT: { - id: 'KPIT', - city: 'Pittsburgh International Airport', - state: 'PA', - lat: 40.4846, - lon: -80.21447, - }, - KPJC: { - id: 'KPJC', - city: 'Zelienople Municipal Airport', - state: 'PA', - lat: 40.80095, - lon: -80.16242, - }, - KPNE: { - id: 'KPNE', - city: 'Philadelphia, Northeast Philadelphia Airport', - state: 'PA', - lat: 40.07889, - lon: -75.01361, - }, - KPTW: { - id: 'KPTW', - city: 'Pottstown, Pottstown Limerick Airport', - state: 'PA', - lat: 40.23802, - lon: -75.5548699, - }, - KRDG: { - id: 'KRDG', - city: 'Reading, Reading Regional Airport', - state: 'PA', - lat: 40.37333, - lon: -75.95944, - }, - KRVL: { - id: 'KRVL', - city: 'Reedsville / Mifflin', - state: 'PA', - lat: 40.68333, - lon: -77.63333, - }, - KSEG: { - id: 'KSEG', - city: 'Selinsgrove Penn Valley Airport', - state: 'PA', - lat: 40.81929, - lon: -76.86582, - }, - KTHV: { - id: 'KTHV', - city: 'York, York Airport', - state: 'PA', - lat: 39.91944, - lon: -76.87694, - }, - KUCP: { - id: 'KUCP', - city: 'New Castle Municipal Airport', - state: 'PA', - lat: 41.02282, - lon: -80.41533, - }, - KUKT: { - id: 'KUKT', - city: 'Quakertown Airport', - state: 'PA', - lat: 40.4368, - lon: -75.38016, - }, - KUNV: { - id: 'KUNV', - city: 'State College Regional Airport', - state: 'PA', - lat: 40.85, - lon: -77.8475799, - }, - KVVS: { - id: 'KVVS', - city: 'Joseph A Hardy Connellsville Airport', - state: 'PA', - lat: 39.95906, - lon: -79.65742, - }, - KXLL: { - id: 'KXLL', - city: 'Allentown Queen City Municipal Airport', - state: 'PA', - lat: 40.57, - lon: -75.488, - }, - KZER: { - id: 'KZER', - city: 'Schuylkill County/Joe Zerbey Airport', - state: 'PA', - lat: 40.70675, - lon: -76.37375, - }, - KABY: { - id: 'KABY', - city: 'Southwest Georgia Regional Airport', - state: 'GA', - lat: 31.53652, - lon: -84.19571, - }, - KACJ: { - id: 'KACJ', - city: 'Americus Souther Field Airport', - state: 'GA', - lat: 32.11081, - lon: -84.18886, - }, - KAGS: { - id: 'KAGS', - city: 'Augusta, Bush Field', - state: 'GA', - lat: 33.36444, - lon: -81.96333, - }, - KAHN: { - id: 'KAHN', - city: 'Athens, Athens Airport', - state: 'GA', - lat: 33.95083, - lon: -83.3280599, - }, - KAJR: { - id: 'KAJR', - city: 'Cornelia Habersham County Airport', - state: 'GA', - lat: 34.4998, - lon: -83.5567, - }, - KAMG: { - id: 'KAMG', - city: 'Alma, Bacon County Airport', - state: 'GA', - lat: 31.53611, - lon: -82.50667, - }, - KATL: { - id: 'KATL', - city: 'Atlanta, Hartsfield - Jackson Atlanta International Airport', - state: 'GA', - lat: 33.64028, - lon: -84.42694, - }, - KAYS: { - id: 'KAYS', - city: 'Waycross / Ware County, Ga', - state: 'GA', - lat: 31.25, - lon: -82.4, - }, - KAZE: { - id: 'KAZE', - city: 'Hazlehurst Airport', - state: 'GA', - lat: 31.8847, - lon: -82.6474, - }, - KBGE: { - id: 'KBGE', - city: 'Bainbridge, Decatur County Industrial Air Park Airport', - state: 'GA', - lat: 30.96667, - lon: -84.63333, - }, - KBHC: { - id: 'KBHC', - city: 'Baxley Municipal Airport', - state: 'GA', - lat: 31.7138, - lon: -82.3938, - }, - KBIJ: { - id: 'KBIJ', - city: 'Blakely, Early County Airport', - state: 'GA', - lat: 31.39694, - lon: -84.895, - }, - KBQK: { - id: 'KBQK', - city: 'Brunswick / Glynco', - state: 'GA', - lat: 31.25, - lon: -81.4666699, - }, - KCCO: { - id: 'KCCO', - city: 'Newnan, Newnan Coweta County Airport', - state: 'GA', - lat: 33.31222, - lon: -84.77028, - }, - KCNI: { - id: 'KCNI', - city: 'Canton, Cherokee County Airport', - state: 'GA', - lat: 34.31056, - lon: -84.42389, - }, - KCPP: { - id: 'KCPP', - city: 'Greene County Regional Airport', - state: 'GA', - lat: 33.5979699, - lon: -83.13826, - }, - KCSG: { - id: 'KCSG', - city: 'Columbus, Columbus Metropolitan Airport', - state: 'GA', - lat: 32.51611, - lon: -84.94222, - }, - KCTJ: { - id: 'KCTJ', - city: 'Carrollton West Georgia Regional Airport', - state: 'GA', - lat: 33.63, - lon: -85.15, - }, - KCVC: { - id: 'KCVC', - city: 'Covington Municipal Airport', - state: 'GA', - lat: 33.632, - lon: -83.85, - }, - KCWV: { - id: 'KCWV', - city: 'Claxton Evans County Airport', - state: 'GA', - lat: 32.1950999, - lon: -81.8696, - }, - KCXU: { - id: 'KCXU', - city: 'Camilla-Mitchell County Airport', - state: 'GA', - lat: 31.2132, - lon: -84.2352, - }, - KCZL: { - id: 'KCZL', - city: 'Calhoun Tom B. David Field Airport', - state: 'GA', - lat: 34.4554, - lon: -84.9392, - }, - KDBN: { - id: 'KDBN', - city: "Dublin, W H 'Bud' Barron Airport", - state: 'GA', - lat: 32.56444, - lon: -82.985, - }, - KDNL: { - id: 'KDNL', - city: 'Augusta Daniel Field', - state: 'GA', - lat: 33.4669, - lon: -82.03836, - }, - KDNN: { - id: 'KDNN', - city: 'Dalton, Dalton Municipal Airport', - state: 'GA', - lat: 34.72167, - lon: -84.86917, - }, - KDQH: { - id: 'KDQH', - city: 'Douglas, Douglas Municipal Airport', - state: 'GA', - lat: 31.47667, - lon: -82.86028, - }, - KDZJ: { - id: 'KDZJ', - city: 'Blairsville Airport', - state: 'GA', - lat: 34.8544, - lon: -83.9973, - }, - KEBA: { - id: 'KEBA', - city: 'Elbert County - Patz Field', - state: 'GA', - lat: 34.095, - lon: -82.81583, - }, - KEZM: { - id: 'KEZM', - city: 'Eastman, Heart of Georgia Regional Airport', - state: 'GA', - lat: 32.21417, - lon: -83.12778, - }, - KFFC: { - id: 'KFFC', - city: 'Atlanta Regional Airport-Falcon Field', - state: 'GA', - lat: 33.35436, - lon: -84.56893, - }, - KFTY: { - id: 'KFTY', - city: 'Fulton County Airport-Brown Field', - state: 'GA', - lat: 33.77764, - lon: -84.52461, - }, - KFZG: { - id: 'KFZG', - city: 'Fitzgerald Municipal Airport', - state: 'GA', - lat: 31.6839, - lon: -83.2709, - }, - KGVL: { - id: 'KGVL', - city: 'Gainesville, Gilmer Memorial Airport', - state: 'GA', - lat: 34.27194, - lon: -83.83028, - }, - KHMP: { - id: 'KHMP', - city: 'Henry County Airport', - state: 'GA', - lat: 33.3899, - lon: -84.331, - }, - KHOE: { - id: 'KHOE', - city: 'Homerville Airport', - state: 'GA', - lat: 31.0559, - lon: -82.7741, - }, - KHQU: { - id: 'KHQU', - city: 'Thomson, Thomson-McDuffie County Airport', - state: 'GA', - lat: 33.52944, - lon: -82.51639, - }, - KIIY: { - id: 'KIIY', - city: 'Washington, Washington-Wilkes County Airport', - state: 'GA', - lat: 33.77972, - lon: -82.81639, - }, - KJCA: { - id: 'KJCA', - city: 'Jackson County Airport', - state: 'GA', - lat: 34.17586, - lon: -83.5616, - }, - KJES: { - id: 'KJES', - city: 'Jesup-Wayne County Airport', - state: 'GA', - lat: 31.554, - lon: -81.8824999, - }, - KJYL: { - id: 'KJYL', - city: 'Sylvania, Plantation Airpark', - state: 'GA', - lat: 32.64528, - lon: -81.59639, - }, - KJZP: { - id: 'KJZP', - city: 'Jasper Pickens County Airport', - state: 'GA', - lat: 34.45417, - lon: -84.45971, - }, - KLGC: { - id: 'KLGC', - city: 'LaGrange-Callaway Airport', - state: 'GA', - lat: 33.00617, - lon: -85.06609, - }, - KLHW: { - id: 'KLHW', - city: 'Wright Army Airfield (Fort Stewart)/Midcoast Regional Airport', - state: 'GA', - lat: 31.88724, - lon: -81.56244, - }, - KLSF: { - id: 'KLSF', - city: 'Fort Benning', - state: 'GA', - lat: 32.3333299, - lon: -84.83333, - }, - KLZU: { - id: 'KLZU', - city: 'Gwinnett County Airport-Briscoe Field', - state: 'GA', - lat: 33.98288, - lon: -83.95842, - }, - KMCN: { - id: 'KMCN', - city: 'Middle Georgia Regional Airport', - state: 'GA', - lat: 32.68892, - lon: -83.65293, - }, - KMGE: { - id: 'KMGE', - city: 'Marietta / Dobbins Air Force Base', - state: 'GA', - lat: 33.91667, - lon: -84.51667, - }, - KMGR: { - id: 'KMGR', - city: 'Moultrie, Moultrie Municipal Airport', - state: 'GA', - lat: 31.08472, - lon: -83.80306, - }, - KMHP: { - id: 'KMHP', - city: 'Metter Municipal Airport', - state: 'GA', - lat: 32.37397, - lon: -82.08144, - }, - KMLJ: { - id: 'KMLJ', - city: 'Milledgeville, Baldwin County Airport', - state: 'GA', - lat: 33.15417, - lon: -83.24056, - }, - KMQW: { - id: 'KMQW', - city: 'Telfair-Wheeler Airport', - state: 'GA', - lat: 32.09699, - lon: -82.8794099, - }, - KOPN: { - id: 'KOPN', - city: 'Thomaston, Thomaston-Upson County Airport', - state: 'GA', - lat: 32.955, - lon: -84.2644399, - }, - KPDK: { - id: 'KPDK', - city: 'Atlanta, De Kalb-Peachtree Airport', - state: 'GA', - lat: 33.87833, - lon: -84.29806, - }, - KPIM: { - id: 'KPIM', - city: 'Pine Mountain Harris County Airport', - state: 'GA', - lat: 32.8407, - lon: -84.8824, - }, - KPUJ: { - id: 'KPUJ', - city: 'Dallas Paulding County Regional Airport', - state: 'GA', - lat: 33.9189999, - lon: -84.952, - }, - KPXE: { - id: 'KPXE', - city: 'Perry-Houston County Airport', - state: 'GA', - lat: 32.5105999, - lon: -83.7673, - }, - KRMG: { - id: 'KRMG', - city: 'Rome, R. B. Russell Airport', - state: 'GA', - lat: 34.34778, - lon: -85.1611099, - }, - KRVJ: { - id: 'KRVJ', - city: 'Swinton Smith Field at Reidsville Municipal Airport', - state: 'GA', - lat: 32.0594899, - lon: -82.15358, - }, - KRYY: { - id: 'KRYY', - city: 'Cobb County International Airport - McCollum Field', - state: 'GA', - lat: 34.01467, - lon: -84.59635, - }, - KSAV: { - id: 'KSAV', - city: 'Savannah-Hilton Head International Airport', - state: 'GA', - lat: 32.1313699, - lon: -81.20226, - }, - KSBO: { - id: 'KSBO', - city: 'Swainsboro Emanuel County Airport', - state: 'GA', - lat: 32.6091, - lon: -82.3699, - }, - KSSI: { - id: 'KSSI', - city: 'Brunswick, Malcolm McKinnon Airport', - state: 'GA', - lat: 31.15167, - lon: -81.39139, - }, - KSVN: { - id: 'KSVN', - city: 'Hunter U. S. Army Airfield', - state: 'GA', - lat: 32.01667, - lon: -81.15, - }, - KTBR: { - id: 'KTBR', - city: 'Statesboro, Statesboro-Bulloch County Airport', - state: 'GA', - lat: 32.48306, - lon: -81.7372199, - }, - KTMA: { - id: 'KTMA', - city: 'Tifton Henry Tift Myers', - state: 'GA', - lat: 31.429, - lon: -83.4885, - }, - KTOC: { - id: 'KTOC', - city: 'Toccoa Le Tourneau Airport', - state: 'GA', - lat: 34.5927999, - lon: -83.2964, - }, - KTVI: { - id: 'KTVI', - city: 'Thomasville Regional Airport', - state: 'GA', - lat: 30.90179, - lon: -83.88113, - }, - KVAD: { - id: 'KVAD', - city: 'Moody Air Force Base', - state: 'GA', - lat: 30.97913, - lon: -83.19247, - }, - KVDI: { - id: 'KVDI', - city: 'Vidalia, Vidalia Municipal Airport', - state: 'GA', - lat: 32.1925, - lon: -82.37194, - }, - KVLD: { - id: 'KVLD', - city: 'Valdosta Regional Airport', - state: 'GA', - lat: 30.77632, - lon: -83.27389, - }, - KVPC: { - id: 'KVPC', - city: 'Cartersville Airport', - state: 'GA', - lat: 34.11589, - lon: -84.85064, - }, - KWDR: { - id: 'KWDR', - city: 'Winder, Winder-Barrow Airport', - state: 'GA', - lat: 33.98222, - lon: -83.66806, - }, - KWRB: { - id: 'KWRB', - city: 'Warner Robins Air Force Base', - state: 'GA', - lat: 32.63333, - lon: -83.6, - }, - KMNV: { - id: 'KMNV', - city: 'Monroe County Airport', - state: 'TN', - lat: 35.54522, - lon: -84.38039, - }, - KMOR: { - id: 'KMOR', - city: 'Morristown Moore-Murrell Airport', - state: 'TN', - lat: 36.1794, - lon: -83.3754, - }, - KMQY: { - id: 'KMQY', - city: 'Smyrna, Smyrna Airport', - state: 'TN', - lat: 36.00889, - lon: -86.52, - }, - KMRC: { - id: 'KMRC', - city: 'Columbia / Maury County', - state: 'TN', - lat: 35.55, - lon: -87.18333, - }, - KNQA: { - id: 'KNQA', - city: 'Millington, Millington Municipal Airport', - state: 'TN', - lat: 35.35667, - lon: -89.8702799, - }, - KOQT: { - id: 'KOQT', - city: 'Oak Ridge', - state: 'TN', - lat: 36.02278, - lon: -84.23333, - }, - KPHT: { - id: 'KPHT', - city: 'Paris - Henry County Airport', - state: 'TN', - lat: 36.34, - lon: -88.38, - }, - KRKW: { - id: 'KRKW', - city: 'Rockwood Municipal Airport', - state: 'TN', - lat: 35.92501, - lon: -84.691, - }, - KRNC: { - id: 'KRNC', - city: 'McMinnville Warren County Memorial Airport', - state: 'TN', - lat: 35.6991, - lon: -85.8402, - }, - KRZR: { - id: 'KRZR', - city: 'Cleveland Regional Jetport', - state: 'TN', - lat: 35.2115, - lon: -84.7998, - }, - KSCX: { - id: 'KSCX', - city: 'Scott Municipal Airport', - state: 'TN', - lat: 36.45569, - lon: -84.58575, - }, - KSNH: { - id: 'KSNH', - city: 'SAVANNAH/HARDIN CO', - state: 'TN', - lat: 35.17, - lon: -88.22, - }, - KSRB: { - id: 'KSRB', - city: 'Sparta Upper Cumberland Regional Airport', - state: 'TN', - lat: 36.0559, - lon: -85.5307, - }, - KSYI: { - id: 'KSYI', - city: 'Shelbyville Bomar Field & Shelbyville Municipal Airport', - state: 'TN', - lat: 35.5593999, - lon: -86.4425, - }, - KSZY: { - id: 'KSZY', - city: 'SELMER/ROBERT SIBLEY', - state: 'TN', - lat: 35.2, - lon: -88.5, - }, - KTHA: { - id: 'KTHA', - city: 'Tullahoma Regional Airport/William Northern Field', - state: 'TN', - lat: 35.38, - lon: -86.2467, - }, - KTRI: { - id: 'KTRI', - city: 'Bristol / Johnson / Kingsport, Tri-City Regional Airport', - state: 'TN', - lat: 36.47972, - lon: -82.39889, - }, - KTYS: { - id: 'KTYS', - city: 'Knoxville, McGhee Tyson Airport', - state: 'TN', - lat: 35.81806, - lon: -83.98583, - }, - KUCY: { - id: 'KUCY', - city: 'Union City - Everett-Stewart Regional Airport', - state: 'TN', - lat: 36.38, - lon: -88.98, - }, - KXNX: { - id: 'KXNX', - city: 'Sumner County Regional Airport', - state: 'TN', - lat: 36.3750799, - lon: -86.40842, - }, - KAKR: { - id: 'KAKR', - city: 'Akron, Akron Fulton International Airport', - state: 'OH', - lat: 41.0375, - lon: -81.46417, - }, - KAOH: { - id: 'KAOH', - city: 'Lima, Lima Allen County Airport', - state: 'OH', - lat: 40.70806, - lon: -84.02139, - }, - KAXV: { - id: 'KAXV', - city: 'Neil Armstrong Airport', - state: 'OH', - lat: 40.49356, - lon: -84.29808, - }, - KBJJ: { - id: 'KBJJ', - city: 'Wooster, Wayne County Airport', - state: 'OH', - lat: 40.87306, - lon: -81.88667, - }, - KBKL: { - id: 'KBKL', - city: 'Cleveland, Burke Lakefront Airport', - state: 'OH', - lat: 41.52556, - lon: -81.66889, - }, - KCAK: { - id: 'KCAK', - city: 'Akron Canton Regional Airport', - state: 'OH', - lat: 40.91811, - lon: -81.44343, - }, - KCDI: { - id: 'KCDI', - city: 'Cambridge Municipal Airport', - state: 'OH', - lat: 39.97393, - lon: -81.5807899, - }, - KCGF: { - id: 'KCGF', - city: 'Cleveland / Cuyahoga', - state: 'OH', - lat: 41.56667, - lon: -81.48333, - }, - KCLE: { - id: 'KCLE', - city: 'Cleveland Hopkins International Airport', - state: 'OH', - lat: 41.40569, - lon: -81.85193, - }, - KCMH: { - id: 'KCMH', - city: 'John Glenn Columbus International Airport', - state: 'OH', - lat: 39.9906999, - lon: -82.87691, - }, - KDAY: { - id: 'KDAY', - city: 'Dayton, Cox Dayton International Airport', - state: 'OH', - lat: 39.90611, - lon: -84.21861, - }, - KDFI: { - id: 'KDFI', - city: 'Defiance, Defiance Memorial Airport', - state: 'OH', - lat: 41.33639, - lon: -84.42944, - }, - KDLZ: { - id: 'KDLZ', - city: 'Delaware Municipal Airport', - state: 'OH', - lat: 40.2797, - lon: -83.1148, - }, - KEDJ: { - id: 'KEDJ', - city: 'Bellefontaine Regional Airport', - state: 'OH', - lat: 40.3723, - lon: -83.8192, - }, - KFDY: { - id: 'KFDY', - city: 'Findlay, Findlay Airport', - state: 'OH', - lat: 41.01361, - lon: -83.66861, - }, - KFFO: { - id: 'KFFO', - city: 'Dayton / Wright-Patterson Air Force Base', - state: 'OH', - lat: 39.8333299, - lon: -84.05, - }, - KGDK: { - id: 'KGDK', - city: 'Greene County - Lewis A Jackson Regional Airport', - state: 'OH', - lat: 39.69072, - lon: -83.99278, - }, - KHAO: { - id: 'KHAO', - city: 'Butler County Regional Airport', - state: 'OH', - lat: 39.36121, - lon: -84.52061, - }, - KHOC: { - id: 'KHOC', - city: 'HILLSBORO', - state: 'OH', - lat: 39.18876, - lon: -83.53879, - }, - KHZY: { - id: 'KHZY', - city: 'Ashtabula - Northeast Ohio Regional Airport', - state: 'OH', - lat: 41.77944, - lon: -80.69667, - }, - KILN: { - id: 'KILN', - city: 'Wilmington, Airborne Airpark Airport', - state: 'OH', - lat: 39.42833, - lon: -83.7791699, - }, - KJRO: { - id: 'KJRO', - city: 'JACKSON', - state: 'OH', - lat: 38.9833, - lon: -82.5833, - }, - KLCK: { - id: 'KLCK', - city: 'Rickenbacker Air National Guard Base', - state: 'OH', - lat: 39.81667, - lon: -82.93333, - }, - KLHQ: { - id: 'KLHQ', - city: 'Lancaster, Fairfield County Airport', - state: 'OH', - lat: 39.7572199, - lon: -82.66333, - }, - KLNN: { - id: 'KLNN', - city: 'Willoughby', - state: 'OH', - lat: 41.68333, - lon: -81.38333, - }, - KLPR: { - id: 'KLPR', - city: 'Lorain / Elyria, Lorain County Regional Airport', - state: 'OH', - lat: 41.34611, - lon: -82.17944, - }, - KLUK: { - id: 'KLUK', - city: 'Cincinnati, Cincinnati Municipal Airport Lunken Field', - state: 'OH', - lat: 39.10583, - lon: -84.41583, - }, - KMFD: { - id: 'KMFD', - city: 'Mansfield - Mansfield Lahm Regional Airport', - state: 'OH', - lat: 40.8202799, - lon: -82.51778, - }, - KMGY: { - id: 'KMGY', - city: 'Dayton, Dayton-Wright Brothers Airport', - state: 'OH', - lat: 39.58889, - lon: -84.22472, - }, - KMNN: { - id: 'KMNN', - city: 'Marion, Marion Municipal Airport', - state: 'OH', - lat: 40.61667, - lon: -83.06833, - }, - KMRT: { - id: 'KMRT', - city: 'Marysville Union County Airport', - state: 'OH', - lat: 40.2247, - lon: -83.3516, - }, - KMWO: { - id: 'KMWO', - city: 'Hook Field Municipal Airport', - state: 'OH', - lat: 39.531, - lon: -84.3953, - }, - KOSU: { - id: 'KOSU', - city: 'Columbus, Ohio State University Airport', - state: 'OH', - lat: 40.07806, - lon: -83.0780599, - }, - KOWX: { - id: 'KOWX', - city: 'Ottawa Putnam County Airport', - state: 'OH', - lat: 41.0356, - lon: -83.982, - }, - KOXD: { - id: 'KOXD', - city: 'Miami University Airport', - state: 'OH', - lat: 39.5022499, - lon: -84.78436, - }, - KPCW: { - id: 'KPCW', - city: 'Port Clinton Carl R Keller Field Airport', - state: 'OH', - lat: 41.5163, - lon: -82.8687, - }, - KPHD: { - id: 'KPHD', - city: 'Harry Clever Field Airport', - state: 'OH', - lat: 40.47032, - lon: -81.42178, - }, - KPMH: { - id: 'KPMH', - city: 'Greater Portsmouth Regional Airport', - state: 'OH', - lat: 38.84047, - lon: -82.8473099, - }, - KPOV: { - id: 'KPOV', - city: 'Portage County Airport', - state: 'OH', - lat: 41.21, - lon: -81.252, - }, - KRZT: { - id: 'KRZT', - city: 'Chillicothe Ross County Airport', - state: 'OH', - lat: 39.4403999, - lon: -83.0231, - }, - KSGH: { - id: 'KSGH', - city: 'Springfield, Springfield-Beckley Municipal Airport', - state: 'OH', - lat: 39.84028, - lon: -83.84, - }, - KTDZ: { - id: 'KTDZ', - city: 'Toledo - Toledo Executive Airport', - state: 'OH', - lat: 41.56306, - lon: -83.47639, - }, - KTOL: { - id: 'KTOL', - city: 'Toledo - Toledo Express Airport', - state: 'OH', - lat: 41.58704, - lon: -83.80539, - }, - KTZR: { - id: 'KTZR', - city: 'Columbus, Bolton Field Airport', - state: 'OH', - lat: 39.90083, - lon: -83.13722, - }, - KUNI: { - id: 'KUNI', - city: 'OHIO U/ATHEN-ALBANY', - state: 'OH', - lat: 39.22, - lon: -82.23, - }, - KUSE: { - id: 'KUSE', - city: 'Wauseon Fulton County Airport', - state: 'OH', - lat: 41.6101, - lon: -84.1272, - }, - KUYF: { - id: 'KUYF', - city: 'London Madison County Airport', - state: 'OH', - lat: 39.9326999, - lon: -83.462, - }, - KVES: { - id: 'KVES', - city: 'Versailles Darke County Airport', - state: 'OH', - lat: 40.2044, - lon: -84.5318999, - }, - KVNW: { - id: 'KVNW', - city: 'Van Wert County Airport', - state: 'OH', - lat: 40.86383, - lon: -84.60636, - }, - KVTA: { - id: 'KVTA', - city: 'Newark, Newark Heath Airport', - state: 'OH', - lat: 40.02278, - lon: -82.4625, - }, - KYNG: { - id: 'KYNG', - city: 'Youngstown, Youngstown-Warren Regional Airport', - state: 'OH', - lat: 41.25444, - lon: -80.67389, - }, - KZZV: { - id: 'KZZV', - city: 'Zanesville Municipal Airport', - state: 'OH', - lat: 39.94609, - lon: -81.89315, - }, - KBOI: { - id: 'KBOI', - city: 'Boise Air Terminal', - state: 'ID', - lat: 43.56704, - lon: -116.24053, - }, - KBYI: { - id: 'KBYI', - city: 'Burley Municipal Airport', - state: 'ID', - lat: 42.54525, - lon: -113.7686, - }, - KCOE: { - id: 'KCOE', - city: "Coeur d'Alene Airport - Pappy Boyington Field", - state: 'ID', - lat: 47.76667, - lon: -116.81667, - }, - KDIJ: { - id: 'KDIJ', - city: 'Driggs, Driggs-Reed Memorial Airport', - state: 'ID', - lat: 43.74167, - lon: -111.09778, - }, - KETI: { - id: 'KETI', - city: 'Ketchum Ranger Station', - state: 'ID', - lat: 43.6816666, - lon: -114.3627777, - }, - KEUL: { - id: 'KEUL', - city: 'Caldwell - Caldwell Industrial Airport', - state: 'ID', - lat: 43.64055, - lon: -116.63017, - }, - KGIC: { - id: 'KGIC', - city: 'Grangeville - Idaho County Airport', - state: 'ID', - lat: 45.94111, - lon: -116.13257, - }, - KGNG: { - id: 'KGNG', - city: 'Gooding Municipal Airport', - state: 'ID', - lat: 42.91716, - lon: -114.76516, - }, - KIDA: { - id: 'KIDA', - city: 'Idaho Falls Regional Airport', - state: 'ID', - lat: 43.5208299, - lon: -112.06611, - }, - KJER: { - id: 'KJER', - city: 'Jerome County Airport', - state: 'ID', - lat: 42.72736, - lon: -114.45469, - }, - KLLJ: { - id: 'KLLJ', - city: 'Challis - Challis Airport', - state: 'ID', - lat: 44.523, - lon: -114.21611, - }, - KLWS: { - id: 'KLWS', - city: 'Lewiston, Lewiston-Nez Perce County Airport', - state: 'ID', - lat: 46.37472, - lon: -117.01444, - }, - KMAN: { - id: 'KMAN', - city: 'Nampa Municipal Airport', - state: 'ID', - lat: 43.5813, - lon: -116.5231, - }, - KMUO: { - id: 'KMUO', - city: 'Mountain Home Air Force Base', - state: 'ID', - lat: 43.05, - lon: -115.86667, - }, - KMYL: { - id: 'KMYL', - city: 'McCall Airport', - state: 'ID', - lat: 44.89425, - lon: -116.09978, - }, - KPIH: { - id: 'KPIH', - city: 'Pocatello, Pocatello Regional Airport', - state: 'ID', - lat: 42.92028, - lon: -112.57111, - }, - KRXE: { - id: 'KRXE', - city: 'Rexburg, Rexburg-Madison County Airport', - state: 'ID', - lat: 43.83167, - lon: -111.80611, - }, - KSMN: { - id: 'KSMN', - city: 'Salmon, Lemhi County Airport', - state: 'ID', - lat: 45.11667, - lon: -113.88333, - }, - KSNT: { - id: 'KSNT', - city: 'Stanley, Stanley Ranger Station', - state: 'ID', - lat: 44.20861, - lon: -114.93444, - }, - KSUN: { - id: 'KSUN', - city: 'Hailey, Friedman Memorial Airport', - state: 'ID', - lat: 43.5, - lon: -114.3, - }, - KSZT: { - id: 'KSZT', - city: 'Sandpoint, Sandpoint Airport', - state: 'ID', - lat: 48.29944, - lon: -116.56, - }, - KTBI: { - id: 'KTBI', - city: 'Kettle Butte', - state: 'ID', - lat: 43.5486099, - lon: -112.32583, - }, - KTWF: { - id: 'KTWF', - city: 'Joslin Field - Magic Valley Regional Airport', - state: 'ID', - lat: 42.4784999, - lon: -114.47739, - }, - PALI: { - id: 'PALI', - city: 'Snake River near Irwin, ID', - state: 'ID', - lat: 43.3508333, - lon: -111.2183333, - }, - PARI: { - id: 'PARI', - city: 'Boise River near Parma, ID', - state: 'ID', - lat: 43.7816666, - lon: -116.9713888, - }, - PAYI: { - id: 'PAYI', - city: 'North Fork Payette River at McCall, Idaho', - state: 'ID', - lat: 44.9083333, - lon: -116.1194444, - }, - PECI: { - id: 'PECI', - city: 'Peoples Canal', - state: 'ID', - lat: 43.2841666, - lon: -112.25, - }, - PICI: { - id: 'PICI', - city: 'PICABO', - state: 'ID', - lat: 43.31167, - lon: -114.16583, - }, - PLCI: { - id: 'PLCI', - city: 'Palisades Canal near Irwin, ID', - state: 'ID', - lat: 43.7458333, - lon: -112.1027777, - }, - PLEI: { - id: 'PLEI', - city: 'Payette River near Letha, ID', - state: 'ID', - lat: 43.8963888, - lon: -116.6258333, - }, - PMAI: { - id: 'PMAI', - city: 'PARMA', - state: 'ID', - lat: 43.8, - lon: -116.93333, - }, - PNRI: { - id: 'PNRI', - city: 'PN Region USBR Hydromet Test Site - Boise, ID', - state: 'ID', - lat: 43.6225, - lon: -116.1933333, - }, - POCI: { - id: 'POCI', - city: 'Porter Canal', - state: 'ID', - lat: 43.5030555, - lon: -112.0480555, - }, - PRKI: { - id: 'PRKI', - city: 'Parks and Lewisville Canal near Rigby, ID', - state: 'ID', - lat: 43.6888888, - lon: -111.8661111, - }, - PRLI: { - id: 'PRLI', - city: 'South Fork Payette River at Lowman, ID', - state: 'ID', - lat: 44.0847222, - lon: -115.6027777, - }, - PRPI: { - id: 'PRPI', - city: 'Payette River near Payette, ID', - state: 'ID', - lat: 44.0424999, - lon: -116.9241666, - }, - PSFI: { - id: 'PSFI', - city: 'Post Falls', - state: 'ID', - lat: 47.71366, - lon: -116.9701, - }, - KACZ: { - id: 'KACZ', - city: 'Henderson Field Airport', - state: 'NC', - lat: 34.71786, - lon: -78.00389, - }, - KAFP: { - id: 'KAFP', - city: 'Anson County Airport', - state: 'NC', - lat: 35.01944, - lon: -80.07836, - }, - KAKH: { - id: 'KAKH', - city: 'Gastonia Municipal Airport', - state: 'NC', - lat: 35.1968699, - lon: -81.15545, - }, - KASJ: { - id: 'KASJ', - city: 'Ahoskie, Tri-County Airport', - state: 'NC', - lat: 36.2975, - lon: -77.17083, - }, - KAVL: { - id: 'KAVL', - city: 'Asheville, Asheville Regional Airport', - state: 'NC', - lat: 35.43194, - lon: -82.5375, - }, - KBUY: { - id: 'KBUY', - city: 'Burlington Alamance Regional Airport', - state: 'NC', - lat: 36.04753, - lon: -79.47375, - }, - KCLT: { - id: 'KCLT', - city: 'Charlotte/Douglas International Airport', - state: 'NC', - lat: 35.2083299, - lon: -80.96139, - }, - KCPC: { - id: 'KCPC', - city: 'Whiteville, Columbus County Municipal Airport', - state: 'NC', - lat: 34.27278, - lon: -78.715, - }, - KCTZ: { - id: 'KCTZ', - city: 'Sampson County Airport', - state: 'NC', - lat: 34.97522, - lon: -78.36276, - }, - KDPL: { - id: 'KDPL', - city: 'Duplin County Airport', - state: 'NC', - lat: 34.99942, - lon: -77.97995, - }, - KECG: { - id: 'KECG', - city: 'Elizabeth City C/G Regional Airport', - state: 'NC', - lat: 36.25771, - lon: -76.1716, - }, - KEDE: { - id: 'KEDE', - city: 'Edenton, Northeastern Regional Airport', - state: 'NC', - lat: 36.02778, - lon: -76.56722, - }, - KEHO: { - id: 'KEHO', - city: 'Shelby Municipal Airport', - state: 'NC', - lat: 35.2556299, - lon: -81.59858, - }, - KEQY: { - id: 'KEQY', - city: 'Monroe, Monroe Airport', - state: 'NC', - lat: 35.01694, - lon: -80.62056, - }, - KETC: { - id: 'KETC', - city: 'Tarboro-Edgecombe Airport', - state: 'NC', - lat: 35.9373, - lon: -77.54648, - }, - KEWN: { - id: 'KEWN', - city: 'New Bern, Craven County Regional Airport', - state: 'NC', - lat: 35.0675, - lon: -77.04722, - }, - KEXX: { - id: 'KEXX', - city: 'Lexington, Davidson County Airport', - state: 'NC', - lat: 35.78111, - lon: -80.30389, - }, - KEYF: { - id: 'KEYF', - city: 'Curtis L Brown Jr. Field Airport', - state: 'NC', - lat: 34.60418, - lon: -78.57902, - }, - KFAY: { - id: 'KFAY', - city: 'Fayetteville, Fayetteville Regional Airport', - state: 'NC', - lat: 34.98944, - lon: -78.88, - }, - KFBG: { - id: 'KFBG', - city: 'Fort Bragg / Simmons Army Airfield', - state: 'NC', - lat: 35.1314, - lon: -78.93158, - }, - KFFA: { - id: 'KFFA', - city: 'Kill Devil Hills, First Flight Airport', - state: 'NC', - lat: 36.01667, - lon: -75.66667, - }, - KFQD: { - id: 'KFQD', - city: 'Rutherfordton, Rutherford County-Marchman Field Airport', - state: 'NC', - lat: 35.42833, - lon: -81.935, - }, - KGEV: { - id: 'KGEV', - city: 'Jefferson - Ashe County Airport', - state: 'NC', - lat: 36.43333, - lon: -81.41667, - }, - KGSB: { - id: 'KGSB', - city: 'Seymour-Johnson Air Force Base', - state: 'NC', - lat: 35.34457, - lon: -77.94583, - }, - KGSO: { - id: 'KGSO', - city: 'Greensboro, Piedmont Triad International Airport', - state: 'NC', - lat: 36.0974999, - lon: -79.94361, - }, - KGWW: { - id: 'KGWW', - city: 'Goldsboro, Goldsboro-Wayne Municipal Airport', - state: 'NC', - lat: 35.46056, - lon: -77.965, - }, - KHBI: { - id: 'KHBI', - city: 'Asheboro, Asheboro Municipal Airport', - state: 'NC', - lat: 35.6538899, - lon: -79.895, - }, - KHFF: { - id: 'KHFF', - city: 'Mackall U. S. Army Airfield', - state: 'NC', - lat: 35.03333, - lon: -79.5, - }, - KHKY: { - id: 'KHKY', - city: 'Hickory, Hickory Regional Airport', - state: 'NC', - lat: 35.74222, - lon: -81.38222, - }, - KHNZ: { - id: 'KHNZ', - city: 'Henderson-Oxford Airport', - state: 'NC', - lat: 36.36352, - lon: -78.52889, - }, - KHRJ: { - id: 'KHRJ', - city: 'Erwin, Harnett County Airport', - state: 'NC', - lat: 35.37861, - lon: -78.73361, - }, - KHSE: { - id: 'KHSE', - city: 'Hatteras, Mitchell Field', - state: 'NC', - lat: 35.23222, - lon: -75.6225, - }, - KILM: { - id: 'KILM', - city: 'Wilmington International Airport', - state: 'NC', - lat: 34.26681, - lon: -77.89987, - }, - KINT: { - id: 'KINT', - city: 'Winston Salem, Smith Reynolds Airport', - state: 'NC', - lat: 36.13333, - lon: -80.22472, - }, - KIPJ: { - id: 'KIPJ', - city: 'Lincolnton, Lincolnton-Lincoln County Regional Airport', - state: 'NC', - lat: 35.48306, - lon: -81.16139, - }, - KISO: { - id: 'KISO', - city: 'Kinston, Kinston Regional Jetport at Stallings Field', - state: 'NC', - lat: 35.3333299, - lon: -77.61667, - }, - KIXA: { - id: 'KIXA', - city: 'Halifax-Northampton Regional Airport', - state: 'NC', - lat: 36.33, - lon: -77.635, - }, - KJNX: { - id: 'KJNX', - city: 'Smithfield, Johnston County Airport', - state: 'NC', - lat: 35.54083, - lon: -78.39028, - }, - KJQF: { - id: 'KJQF', - city: 'Concord Regional Airport', - state: 'NC', - lat: 35.3896299, - lon: -80.70735, - }, - KLBT: { - id: 'KLBT', - city: 'Lumberton Municipal Airport', - state: 'NC', - lat: 34.60817, - lon: -79.059, - }, - KLHZ: { - id: 'KLHZ', - city: 'Franklin County Airport', - state: 'NC', - lat: 36.02288, - lon: -78.33405, - }, - KMCZ: { - id: 'KMCZ', - city: 'Martin County Airport', - state: 'NC', - lat: 35.86219, - lon: -77.1782, - }, - KMEB: { - id: 'KMEB', - city: 'Laurinburg Maxton Airport', - state: 'NC', - lat: 34.79132, - lon: -79.3683, - }, - KMQI: { - id: 'KMQI', - city: 'Manteo / Dare County Regional', - state: 'NC', - lat: 35.91667, - lon: -75.7, - }, - KMRH: { - id: 'KMRH', - city: 'Beaufort Smith Field', - state: 'NC', - lat: 34.73259, - lon: -76.6566, - }, - KMRN: { - id: 'KMRN', - city: 'Morganton-Lenoir Airport', - state: 'NC', - lat: 35.81922, - lon: -81.60971, - }, - KMWK: { - id: 'KMWK', - city: 'Mount Airy/Surry County Airport', - state: 'NC', - lat: 36.45675, - lon: -80.55483, - }, - KNBT: { - id: 'KNBT', - city: 'Piney Island, Bt-11 Bombing Range', - state: 'NC', - lat: 35.02222, - lon: -76.4625, - }, - KNCA: { - id: 'KNCA', - city: 'MCAS New River', - state: 'NC', - lat: 34.70627, - lon: -77.44066, - }, - KNJM: { - id: 'KNJM', - city: 'Bogue Field Marine Corps Auxiliary Field', - state: 'NC', - lat: 34.69403, - lon: -77.02945, - }, - KNKT: { - id: 'KNKT', - city: 'Cherry Point Marine Corps Air Station', - state: 'NC', - lat: 34.89719, - lon: -76.88135, - }, - KOAJ: { - id: 'KOAJ', - city: 'Jacksonville, Albert J Ellis Airport', - state: 'NC', - lat: 34.8333299, - lon: -77.61667, - }, - KOCW: { - id: 'KOCW', - city: 'Washington, Warren Field Airport', - state: 'NC', - lat: 35.57056, - lon: -77.0497199, - }, - KONX: { - id: 'KONX', - city: 'Currituck, Currituck County Airport', - state: 'NC', - lat: 36.39889, - lon: -76.01611, - }, - KPGV: { - id: 'KPGV', - city: 'Pitt-Greenville Airport', - state: 'NC', - lat: 35.63742, - lon: -77.38506, - }, - KPOB: { - id: 'KPOB', - city: 'Pope Air Force Base', - state: 'NC', - lat: 35.17531, - lon: -79.00771, - }, - KRCZ: { - id: 'KRCZ', - city: 'Rockingham-Hamlet Airport', - state: 'NC', - lat: 34.8954499, - lon: -79.75755, - }, - KRDU: { - id: 'KRDU', - city: 'Raleigh / Durham, Raleigh-Durham International Airport', - state: 'NC', - lat: 35.89223, - lon: -78.78185, - }, - KRHP: { - id: 'KRHP', - city: 'Andrews-Murphy Airport', - state: 'NC', - lat: 35.19394, - lon: -83.86182, - }, - KRUQ: { - id: 'KRUQ', - city: 'Rowan County Airport', - state: 'NC', - lat: 35.64417, - lon: -80.52359, - }, - KRWI: { - id: 'KRWI', - city: 'Rocky Mount, Rocky Mount-Wilson Regional Airport', - state: 'NC', - lat: 35.8549999, - lon: -77.89306, - }, - KSCR: { - id: 'KSCR', - city: 'Siler City Municipal Airport', - state: 'NC', - lat: 35.7043, - lon: -79.5043, - }, - KSIF: { - id: 'KSIF', - city: 'Reidsville, Rockingham County NC Shiloh Airport', - state: 'NC', - lat: 36.43722, - lon: -79.85083, - }, - KSOP: { - id: 'KSOP', - city: 'Pinehurst/Southern Pines, Moore County Airport', - state: 'NC', - lat: 35.23333, - lon: -79.4, - }, - KSUT: { - id: 'KSUT', - city: 'Brunswick County Airport', - state: 'NC', - lat: 33.92921, - lon: -78.07223, - }, - KSVH: { - id: 'KSVH', - city: 'Statesville Municipal Airport', - state: 'NC', - lat: 35.76362, - lon: -80.9473, - }, - KTDF: { - id: 'KTDF', - city: 'Roxboro, Person County Airport', - state: 'NC', - lat: 36.2849999, - lon: -78.98417, - }, - KTNB: { - id: 'KTNB', - city: 'Watauga County Hospital Heliport', - state: 'NC', - lat: 36.19856, - lon: -81.65171, - }, - KTQV: { - id: 'KTQV', - city: 'DURHAM/DUKE', - state: 'NC', - lat: 36, - lon: -78.9333, - }, - KTTA: { - id: 'KTTA', - city: 'Sanford, Sanford-Lee County Regional Airport', - state: 'NC', - lat: 35.5825, - lon: -79.10139, - }, - KUKF: { - id: 'KUKF', - city: 'North Wilkesboro, Wilkes County Airport', - state: 'NC', - lat: 36.21667, - lon: -81.08333, - }, - KVUJ: { - id: 'KVUJ', - city: 'Albemarle, Stanly County Airport', - state: 'NC', - lat: 35.41667, - lon: -80.15083, - }, - KLRY: { - id: 'KLRY', - city: 'Harrisonville Lawrence Smith Memorial Airport', - state: 'MO', - lat: 38.611, - lon: -94.3421, - }, - KLXT: { - id: 'KLXT', - city: "Lee's Summit, Lee's Summit Municipal Airport", - state: 'MO', - lat: 38.95972, - lon: -94.37167, - }, - KMAW: { - id: 'KMAW', - city: 'Malden Municipal Airport', - state: 'MO', - lat: 36.6004999, - lon: -89.9922, - }, - KMBY: { - id: 'KMBY', - city: 'Omar N Bradley Airport', - state: 'MO', - lat: 39.46341, - lon: -92.42638, - }, - KMCI: { - id: 'KMCI', - city: 'Kansas City, Kansas City International Airport', - state: 'MO', - lat: 39.29722, - lon: -94.73056, - }, - KMHL: { - id: 'KMHL', - city: 'Marshall Memorial Municipal Airport', - state: 'MO', - lat: 39.0955, - lon: -93.2028, - }, - KMKC: { - id: 'KMKC', - city: 'Kansas City, Kansas City Downtown Airport', - state: 'MO', - lat: 39.12083, - lon: -94.59694, - }, - KMYJ: { - id: 'KMYJ', - city: 'Mexico Memorial Airport', - state: 'MO', - lat: 39.1575, - lon: -91.8182999, - }, - KOZS: { - id: 'KOZS', - city: 'Camdenton Memorial Airport', - state: 'MO', - lat: 37.9739999, - lon: -92.6912, - }, - KPCD: { - id: 'KPCD', - city: 'Perryville Regional Airport', - state: 'MO', - lat: 37.86867, - lon: -89.86214, - }, - KPOF: { - id: 'KPOF', - city: 'Poplar Bluff, Poplar Bluff Municipal Airport', - state: 'MO', - lat: 36.77056, - lon: -90.32222, - }, - KRCM: { - id: 'KRCM', - city: 'Skyhaven Airport', - state: 'MO', - lat: 38.7842, - lon: -93.8028999, - }, - KSET: { - id: 'KSET', - city: 'St. Charles, St. Charles County Smartt Airport', - state: 'MO', - lat: 38.93056, - lon: -90.4325, - }, - KSGF: { - id: 'KSGF', - city: 'Springfield-Branson National Airport', - state: 'MO', - lat: 37.23972, - lon: -93.38972, - }, - KSIK: { - id: 'KSIK', - city: 'Sikeston Memorial Municipal Airport', - state: 'MO', - lat: 36.8989, - lon: -89.5618, - }, - KSTJ: { - id: 'KSTJ', - city: 'St. Joseph, Rosecrans Memorial Airport', - state: 'MO', - lat: 39.76806, - lon: -94.90917, - }, - KSTL: { - id: 'KSTL', - city: 'St. Louis Lambert International Airport', - state: 'MO', - lat: 38.7525, - lon: -90.37361, - }, - KSUS: { - id: 'KSUS', - city: 'St. Louis, Spirit Of St. Louis Airport', - state: 'MO', - lat: 38.65722, - lon: -90.65583, - }, - KSZL: { - id: 'KSZL', - city: 'Whiteman Air Force Base', - state: 'MO', - lat: 38.73333, - lon: -93.55, - }, - KTBN: { - id: 'KTBN', - city: 'Fort Leonard Wood', - state: 'MO', - lat: 37.73333, - lon: -92.13333, - }, - KTKX: { - id: 'KTKX', - city: 'Kennett - Kennett Memorial Airport', - state: 'MO', - lat: 36.22256, - lon: -90.03671, - }, - KUNO: { - id: 'KUNO', - city: 'West Plains, West Plains Municipal Airport', - state: 'MO', - lat: 36.87917, - lon: -91.905, - }, - KUUV: { - id: 'KUUV', - city: 'SULLIVAN', - state: 'MO', - lat: 38.2335, - lon: -91.16433, - }, - KVER: { - id: 'KVER', - city: 'Jesse Viertel Memorial Airport', - state: 'MO', - lat: 38.94672, - lon: -92.68267, - }, - KVIH: { - id: 'KVIH', - city: 'Rolla / Vichy, Rolla National Airport', - state: 'MO', - lat: 38.13194, - lon: -91.76528, - }, - KALB: { - id: 'KALB', - city: 'Albany International Airport', - state: 'NY', - lat: 42.74722, - lon: -73.79912, - }, - KART: { - id: 'KART', - city: 'Watertown, Watertown International Airport', - state: 'NY', - lat: 43.99194, - lon: -76.02167, - }, - KBGM: { - id: 'KBGM', - city: 'Greater Binghamton Airport', - state: 'NY', - lat: 42.20778, - lon: -75.98139, - }, - KBUF: { - id: 'KBUF', - city: 'Buffalo, Greater Buffalo International Airport', - state: 'NY', - lat: 42.93998, - lon: -78.73604, - }, - KCZG: { - id: 'KCZG', - city: 'ENDICOTT', - state: 'NY', - lat: 42.0785, - lon: -76.09633, - }, - KDKK: { - id: 'KDKK', - city: 'Dunkirk, Chautauqua County / Dunkirk Airport', - state: 'NY', - lat: 42.49306, - lon: -79.27583, - }, - KDSV: { - id: 'KDSV', - city: 'Dansville, Dansville Municipal Airport', - state: 'NY', - lat: 42.56944, - lon: -77.71444, - }, - KELM: { - id: 'KELM', - city: 'Elmira, Elmira / Corning Regional Airport', - state: 'NY', - lat: 42.15639, - lon: -76.90278, - }, - KELZ: { - id: 'KELZ', - city: 'Wellsville, Wellsville Municipal Airport', - state: 'NY', - lat: 42.1075, - lon: -77.98444, - }, - KFOK: { - id: 'KFOK', - city: 'The Gabreski Airport', - state: 'NY', - lat: 40.85053, - lon: -72.61927, - }, - KFRG: { - id: 'KFRG', - city: 'Farmingdale - Republic Airport', - state: 'NY', - lat: 40.73443, - lon: -73.41639, - }, - KFZY: { - id: 'KFZY', - city: 'Fulton, Oswego County Airport', - state: 'NY', - lat: 43.35083, - lon: -76.38806, - }, - KGFL: { - id: 'KGFL', - city: 'Glens Falls, Floyd Bennett Memorial Airport', - state: 'NY', - lat: 43.34111, - lon: -73.61056, - }, - KGTB: { - id: 'KGTB', - city: 'Fort Drum / Wheeler-Sack U. S. Army Airfield', - state: 'NY', - lat: 44.05, - lon: -75.73333, - }, - KGVQ: { - id: 'KGVQ', - city: 'Genesee County Airport', - state: 'NY', - lat: 43.03175, - lon: -78.16967, - }, - KHPN: { - id: 'KHPN', - city: 'White Plains - Westchester County Airport', - state: 'NY', - lat: 41.06237, - lon: -73.70456, - }, - KHTF: { - id: 'KHTF', - city: 'HORNELL', - state: 'NY', - lat: 42.38216, - lon: -77.68216, - }, - KHWV: { - id: 'KHWV', - city: 'Shirley, Brookhaven Airport', - state: 'NY', - lat: 40.82167, - lon: -72.8688899, - }, - KIAG: { - id: 'KIAG', - city: 'Niagara Falls, Niagara Falls International Airport', - state: 'NY', - lat: 43.1082899, - lon: -78.93818, - }, - KISP: { - id: 'KISP', - city: 'Islip, Long Island Mac Arthur Airport', - state: 'NY', - lat: 40.79389, - lon: -73.10167, - }, - KITH: { - id: 'KITH', - city: 'Ithaca Tompkins International Airport', - state: 'NY', - lat: 42.49083, - lon: -76.45833, - }, - KIUA: { - id: 'KIUA', - city: 'Canandaigua Airport', - state: 'NY', - lat: 42.9089, - lon: -77.32523, - }, - KJFK: { - id: 'KJFK', - city: 'New York, Kennedy International Airport', - state: 'NY', - lat: 40.63915, - lon: -73.76393, - }, - KJHW: { - id: 'KJHW', - city: 'Jamestown, Chautauqua County/Jamestown Airport', - state: 'NY', - lat: 42.15, - lon: -79.26667, - }, - KJPX: { - id: 'KJPX', - city: 'East Hampton Town Airport', - state: 'NY', - lat: 40.95942, - lon: -72.25167, - }, - KJRB: { - id: 'KJRB', - city: 'New York Downtown Manhattan', - state: 'NY', - lat: 40.7012, - lon: -74.009, - }, - KLGA: { - id: 'KLGA', - city: 'New York, La Guardia Airport', - state: 'NY', - lat: 40.77917, - lon: -73.88, - }, - KLKP: { - id: 'KLKP', - city: 'Lake Placid Airport', - state: 'NY', - lat: 44.26448, - lon: -73.96187, - }, - KMGJ: { - id: 'KMGJ', - city: 'Montgomery, Orange County Airport', - state: 'NY', - lat: 41.50917, - lon: -74.265, - }, - KMSS: { - id: 'KMSS', - city: 'Massena, Massena International-Richards Field', - state: 'NY', - lat: 44.93583, - lon: -74.84556, - }, - KMTP: { - id: 'KMTP', - city: 'Montauk, Montauk Airport', - state: 'NY', - lat: 41.07306, - lon: -71.92333, - }, - KNYC: { - id: 'KNYC', - city: 'New York City, Central Park', - state: 'NY', - lat: 40.78333, - lon: -73.9666699, - }, - KOGS: { - id: 'KOGS', - city: 'Ogdensburg International Airport', - state: 'NY', - lat: 44.68186, - lon: -75.4655, - }, - KOIC: { - id: 'KOIC', - city: 'NORWICH', - state: 'NY', - lat: 42.5665, - lon: -75.52416, - }, - KOLE: { - id: 'KOLE', - city: 'Cattaraugus County-Olean Airport', - state: 'NY', - lat: 42.24119, - lon: -78.37136, - }, - KPBG: { - id: 'KPBG', - city: 'Plattsburgh International Airport ', - state: 'NY', - lat: 44.65, - lon: -73.4666699, - }, - KPEO: { - id: 'KPEO', - city: 'Penn Yan, Penn Yan Airport', - state: 'NY', - lat: 42.64306, - lon: -77.04944, - }, - KPOU: { - id: 'KPOU', - city: 'Poughkeepsie, Dutchess County Airport', - state: 'NY', - lat: 41.62667, - lon: -73.88417, - }, - KPTD: { - id: 'KPTD', - city: 'Potsdam Municipal Airport/Damon Field', - state: 'NY', - lat: 44.67667, - lon: -74.94844, - }, - KRME: { - id: 'KRME', - city: 'Griffiss International Airport', - state: 'NY', - lat: 43.23333, - lon: -75.4, - }, - KROC: { - id: 'KROC', - city: 'Rochester, Greater Rochester International Airport', - state: 'NY', - lat: 43.11667, - lon: -77.67667, - }, - KSCH: { - id: 'KSCH', - city: 'Schenectady Airport', - state: 'NY', - lat: 42.85, - lon: -73.93333, - }, - KSDC: { - id: 'KSDC', - city: 'Williamson-Sodus Airport', - state: 'NY', - lat: 43.23459, - lon: -77.11946, - }, - KSLK: { - id: 'KSLK', - city: 'Saranac Lake, Adirondack Regional Airport', - state: 'NY', - lat: 44.39306, - lon: -74.20278, - }, - KSWF: { - id: 'KSWF', - city: 'Newburgh / Stewart', - state: 'NY', - lat: 41.5, - lon: -74.1, - }, - KSYR: { - id: 'KSYR', - city: 'Syracuse, Syracuse Hancock International Airport', - state: 'NY', - lat: 43.10917, - lon: -76.10333, - }, - KVGC: { - id: 'KVGC', - city: 'Hamilton Municipal Airport', - state: 'NY', - lat: 42.84344, - lon: -75.56119, - }, - KAKQ: { - id: 'KAKQ', - city: 'Wakefield Municipal Airport', - state: 'VA', - lat: 36.98274, - lon: -77.00137, - }, - KAVC: { - id: 'KAVC', - city: 'South Hill, Mecklenburg-Brunswick Regional Airport', - state: 'VA', - lat: 36.68861, - lon: -78.05417, - }, - KBCB: { - id: 'KBCB', - city: 'Virginia Tech Airport', - state: 'VA', - lat: 37.21667, - lon: -80.41667, - }, - KBKT: { - id: 'KBKT', - city: 'Ft. Pickett / Blackstone', - state: 'VA', - lat: 37.0833299, - lon: -77.95, - }, - KCHO: { - id: 'KCHO', - city: 'Charlottesville-Albemarle Airport', - state: 'VA', - lat: 38.13738, - lon: -78.45516, - }, - KCJR: { - id: 'KCJR', - city: 'Culpeper Regional Airport', - state: 'VA', - lat: 38.52607, - lon: -77.85738, - }, - KCPK: { - id: 'KCPK', - city: 'Chesapeake, Chesapeake Municipal Airport', - state: 'VA', - lat: 36.66556, - lon: -76.32056, - }, - KCXE: { - id: 'KCXE', - city: 'Chase City Municipal Airport', - state: 'VA', - lat: 36.7883, - lon: -78.5016, - }, - KDAA: { - id: 'KDAA', - city: 'Fort Belvoir', - state: 'VA', - lat: 38.71667, - lon: -77.18333, - }, - KDAN: { - id: 'KDAN', - city: 'Danville, Danville Regional Airport', - state: 'VA', - lat: 36.57278, - lon: -79.33611, - }, - KDCA: { - id: 'KDCA', - city: 'Washington/Reagan National Airport, DC', - state: 'VA', - lat: 38.84833, - lon: -77.03417, - }, - KEMV: { - id: 'KEMV', - city: 'Emporia, Emporia-Greensville Regional Airport', - state: 'VA', - lat: 36.68694, - lon: -77.48278, - }, - KEZF: { - id: 'KEZF', - city: 'Fredericksburg, Shannon Airport', - state: 'VA', - lat: 38.26667, - lon: -77.45, - }, - KFAF: { - id: 'KFAF', - city: 'Fort Eustis / Felker', - state: 'VA', - lat: 37.13333, - lon: -76.61667, - }, - KFCI: { - id: 'KFCI', - city: 'Chesterfield County Airport', - state: 'VA', - lat: 37.406444, - lon: -77.524833, - }, - KFKN: { - id: 'KFKN', - city: 'Franklin / J B Rose', - state: 'VA', - lat: 36.7, - lon: -76.9, - }, - KFRR: { - id: 'KFRR', - city: 'Front Royal-warren County Airport', - state: 'VA', - lat: 38.9174999, - lon: -78.2535, - }, - KFVX: { - id: 'KFVX', - city: 'Farmville', - state: 'VA', - lat: 37.35, - lon: -78.43333, - }, - KFYJ: { - id: 'KFYJ', - city: 'West Point, Middle Peninsula Regional Airport', - state: 'VA', - lat: 37.52111, - lon: -76.7644399, - }, - KGVE: { - id: 'KGVE', - city: 'Gordonsville Municipal Airport', - state: 'VA', - lat: 38.156, - lon: -78.1658, - }, - KHEF: { - id: 'KHEF', - city: 'Manassas, Manassas Regional Airport/Harry P. Davis Field', - state: 'VA', - lat: 38.71667, - lon: -77.51667, - }, - KHLX: { - id: 'KHLX', - city: 'Hillsville', - state: 'VA', - lat: 36.76667, - lon: -80.81667, - }, - KHSP: { - id: 'KHSP', - city: 'Hot Springs / Ingalls', - state: 'VA', - lat: 37.95, - lon: -79.83333, - }, - KHWY: { - id: 'KHWY', - city: 'Warrenton-Fauquier Airport', - state: 'VA', - lat: 38.5876499, - lon: -77.71501, - }, - KIAD: { - id: 'KIAD', - city: 'Washington/Dulles International Airport, DC', - state: 'VA', - lat: 38.93472, - lon: -77.4475, - }, - KJFZ: { - id: 'KJFZ', - city: 'Tazewell County Airport', - state: 'VA', - lat: 37.064, - lon: -81.798, - }, - KJGG: { - id: 'KJGG', - city: 'Williamsburg-Jamestown Airport', - state: 'VA', - lat: 37.24157, - lon: -76.71672, - }, - KJYO: { - id: 'KJYO', - city: 'Leesburg / Godfrey', - state: 'VA', - lat: 39.0833299, - lon: -77.56667, - }, - KLFI: { - id: 'KLFI', - city: 'Langley Air Force Base', - state: 'VA', - lat: 37.0833299, - lon: -76.35, - }, - KLKU: { - id: 'KLKU', - city: 'Louisa, Louisa County Airport/Freeman Field', - state: 'VA', - lat: 38.00972, - lon: -77.97028, - }, - KLNP: { - id: 'KLNP', - city: 'Wise / Lonesome Pine', - state: 'VA', - lat: 36.98333, - lon: -82.53333, - }, - KLUA: { - id: 'KLUA', - city: 'Luray Caverns', - state: 'VA', - lat: 38.6671, - lon: -78.5006, - }, - KLVL: { - id: 'KLVL', - city: 'Lawrenceville/Brunswick Municipal Airport', - state: 'VA', - lat: 36.7727999, - lon: -77.7943, - }, - KLYH: { - id: 'KLYH', - city: 'Lynchburg, Lynchburg Regional Airport', - state: 'VA', - lat: 37.32083, - lon: -79.20667, - }, - KMKJ: { - id: 'KMKJ', - city: 'Marion / Wytheville', - state: 'VA', - lat: 36.9, - lon: -81.35, - }, - KMTV: { - id: 'KMTV', - city: 'Martinsville', - state: 'VA', - lat: 36.63333, - lon: -80.01667, - }, - KNFE: { - id: 'KNFE', - city: 'Fentress, Naval Auxiliary Landing Field', - state: 'VA', - lat: 36.70083, - lon: -76.12833, - }, - KNGU: { - id: 'KNGU', - city: 'Norfolk, Naval Air Station', - state: 'VA', - lat: 36.93361, - lon: -76.29583, - }, - KNTU: { - id: 'KNTU', - city: 'Virginia Beach, Oceana, Naval Air Station', - state: 'VA', - lat: 36.82111, - lon: -76.02833, - }, - KNYG: { - id: 'KNYG', - city: 'Quantico Marine Corps Airfield - Turner Field', - state: 'VA', - lat: 38.50326, - lon: -77.30129, - }, - KOFP: { - id: 'KOFP', - city: 'Ashland, Hanover County Municipal Airport', - state: 'VA', - lat: 37.70806, - lon: -77.43444, - }, - KOKV: { - id: 'KOKV', - city: 'Winchester Regional', - state: 'VA', - lat: 39.15, - lon: -78.15, - }, - KOMH: { - id: 'KOMH', - city: 'Orange, Orange County Airport', - state: 'VA', - lat: 38.24722, - lon: -78.04556, - }, - KORF: { - id: 'KORF', - city: 'Norfolk, Norfolk International Airport', - state: 'VA', - lat: 36.90361, - lon: -76.19194, - }, - KPHF: { - id: 'KPHF', - city: 'Newport News, Newport News / Williamsburg International Airport', - state: 'VA', - lat: 37.13194, - lon: -76.49306, - }, - KPSK: { - id: 'KPSK', - city: 'Dublin / New River Valley', - state: 'VA', - lat: 37.13333, - lon: -80.68333, - }, - KPTB: { - id: 'KPTB', - city: 'Petersburg, Dinwiddie County Airport', - state: 'VA', - lat: 37.18333, - lon: -77.51667, - }, - KPVG: { - id: 'KPVG', - city: 'Norfolk Hampton Roads Executive Airport', - state: 'VA', - lat: 36.7801, - lon: -76.4488, - }, - KRIC: { - id: 'KRIC', - city: 'Richmond, Richmond International Airport', - state: 'VA', - lat: 37.51111, - lon: -77.32333, - }, - KRMN: { - id: 'KRMN', - city: 'Stafford, Stafford Regional Airport', - state: 'VA', - lat: 38.39806, - lon: -77.45528, - }, - KROA: { - id: 'KROA', - city: 'Roanoke, Roanoke Regional Airport', - state: 'VA', - lat: 37.31694, - lon: -79.97417, - }, - KSFQ: { - id: 'KSFQ', - city: 'Suffolk, Suffolk Municipal Airport', - state: 'VA', - lat: 36.68222, - lon: -76.60194, - }, - KSHD: { - id: 'KSHD', - city: 'Staunton / Shenandoah', - state: 'VA', - lat: 38.26667, - lon: -78.9, - }, - KTGI: { - id: 'KTGI', - city: 'Tangier Island Airport', - state: 'VA', - lat: 37.82587, - lon: -75.99766, - }, - KVBW: { - id: 'KVBW', - city: 'Bridgewater Air Park', - state: 'VA', - lat: 38.36674, - lon: -78.96033, - }, - KVJI: { - id: 'KVJI', - city: 'Abingdon', - state: 'VA', - lat: 36.68333, - lon: -82.03333, - }, - KWAL: { - id: 'KWAL', - city: 'Wallops Flight Facility Airport', - state: 'VA', - lat: 37.9372, - lon: -75.46619, - }, - KXSA: { - id: 'KXSA', - city: 'Tappahannock-Essex County Airport', - state: 'VA', - lat: 37.859611, - lon: -76.894111, - }, - PAAD: { - id: 'PAAD', - city: 'Point Thomson Airstrip', - state: 'AK', - lat: 70.136, - lon: -146.2901, - }, - PAAK: { - id: 'PAAK', - city: 'Atka, Atka Airport', - state: 'AK', - lat: 52.22028, - lon: -174.20639, - }, - PAAQ: { - id: 'PAAQ', - city: 'Palmer, Palmer Municipal Airport', - state: 'AK', - lat: 61.6, - lon: -149.08333, - }, - PABA: { - id: 'PABA', - city: 'Barter Island, Barter Island LRRS Airport', - state: 'AK', - lat: 70.1338899, - lon: -143.57694, - }, - PABE: { - id: 'PABE', - city: 'Bethel, Bethel Airport', - state: 'AK', - lat: 60.77972, - lon: -161.83778, - }, - PABI: { - id: 'PABI', - city: 'Delta Junction/Ft Greely, Allen Army Airfield', - state: 'AK', - lat: 64, - lon: -145.73333, - }, - PABL: { - id: 'PABL', - city: 'Buckland, Buckland Airport', - state: 'AK', - lat: 65.98222, - lon: -161.15194, - }, - PABR: { - id: 'PABR', - city: 'Wiley Post-Will Rogers Memorial Airport', - state: 'AK', - lat: 71.28528, - lon: -156.76583, - }, - PABT: { - id: 'PABT', - city: 'Bettles, Bettles Airport', - state: 'AK', - lat: 66.91667, - lon: -151.51667, - }, - PABV: { - id: 'PABV', - city: 'Birchwood, Birchwood Airport', - state: 'AK', - lat: 61.41667, - lon: -149.51667, - }, - PACD: { - id: 'PACD', - city: 'Cold Bay, Cold Bay Airport', - state: 'AK', - lat: 55.22083, - lon: -162.72778, - }, - PACV: { - id: 'PACV', - city: 'Cordova, Merle K (Mudhole) Smith Airport', - state: 'AK', - lat: 60.49167, - lon: -145.47778, - }, - PACX: { - id: 'PACX', - city: 'Coldfoot Airport', - state: 'AK', - lat: 67.25217, - lon: -150.20391, - }, - PACZ: { - id: 'PACZ', - city: 'Cape Romanzof, Cape Romanzof LRRS Airport', - state: 'AK', - lat: 61.78333, - lon: -166.03333, - }, - PADE: { - id: 'PADE', - city: 'Deering, Deering/New Airport', - state: 'AK', - lat: 66.08333, - lon: -162.75, - }, - PADG: { - id: 'PADG', - city: 'Red Dog', - state: 'AK', - lat: 68.0321, - lon: -162.8992, - }, - PADK: { - id: 'PADK', - city: 'Adak Island, Adak Airport', - state: 'AK', - lat: 51.87778, - lon: -176.64583, - }, - PADL: { - id: 'PADL', - city: 'Dillingham, Dillingham Airport', - state: 'AK', - lat: 59.05, - lon: -158.51667, - }, - PADM: { - id: 'PADM', - city: 'Marshall', - state: 'AK', - lat: 61.8643, - lon: -162.0261, - }, - PADQ: { - id: 'PADQ', - city: 'Kodiak, Kodiak Airport', - state: 'AK', - lat: 57.75, - lon: -152.5, - }, - PADU: { - id: 'PADU', - city: 'Unalaska, Unalaska Airport', - state: 'AK', - lat: 53.9, - lon: -166.53333, - }, - PAED: { - id: 'PAED', - city: 'Anchorage, Elmendorf Air Force Base', - state: 'AK', - lat: 61.25306, - lon: -149.79389, - }, - PAEG: { - id: 'PAEG', - city: 'Eagle, Eagle Airport', - state: 'AK', - lat: 64.77639, - lon: -141.15083, - }, - PAEH: { - id: 'PAEH', - city: 'Cape Newenham, Cape Newenham LRRS Airport', - state: 'AK', - lat: 58.65, - lon: -162.0666699, - }, - PAEI: { - id: 'PAEI', - city: 'Fairbanks, Eielson Air Force Base', - state: 'AK', - lat: 64.65, - lon: -147.1, - }, - PAEL: { - id: 'PAEL', - city: 'Elfin Cove - Elfin Cove Seaplane Base', - state: 'AK', - lat: 58.19467, - lon: -136.34663, - }, - PAEM: { - id: 'PAEM', - city: 'Emmonak, Emmonak Airport', - state: 'AK', - lat: 62.78333, - lon: -164.5, - }, - PAEN: { - id: 'PAEN', - city: 'Kenai, Kenai Municipal Airport', - state: 'AK', - lat: 60.57306, - lon: -151.245, - }, - PAFA: { - id: 'PAFA', - city: 'Fairbanks, Fairbanks International Airport', - state: 'AK', - lat: 64.80389, - lon: -147.87611, - }, - PAFB: { - id: 'PAFB', - city: 'Fort Wainwright AAF', - state: 'AK', - lat: 64.83667, - lon: -147.59556, - }, - PAFE: { - id: 'PAFE', - city: 'Kake - Kake Airport', - state: 'AK', - lat: 56.964, - lon: -133.913, - }, - PAFR: { - id: 'PAFR', - city: 'Ft. Richardson / Bryant U. S. Army Heliport, Ak', - state: 'AK', - lat: 61.26667, - lon: -149.65, - }, - PAFS: { - id: 'PAFS', - city: 'Nikolai', - state: 'AK', - lat: 63.019, - lon: -154.358, - }, - PAGA: { - id: 'PAGA', - city: 'Galena, Edward G. Pitka Sr. Airport', - state: 'AK', - lat: 64.73333, - lon: -156.93333, - }, - PAGB: { - id: 'PAGB', - city: 'Galbraith Lake, Galbraith Lake Airport', - state: 'AK', - lat: 68.48333, - lon: -149.48333, - }, - PAGH: { - id: 'PAGH', - city: 'Shungnak Airport', - state: 'AK', - lat: 66.8881, - lon: -157.1624, - }, - PAGK: { - id: 'PAGK', - city: 'Gulkana, Gulkana Airport', - state: 'AK', - lat: 62.15, - lon: -145.45, - }, - PAGL: { - id: 'PAGL', - city: 'Golovin, Golovin Airport', - state: 'AK', - lat: 64.54333, - lon: -163.03944, - }, - PAGM: { - id: 'PAGM', - city: 'Gambell, Gambell Airport', - state: 'AK', - lat: 63.76667, - lon: -171.73333, - }, - PAGN: { - id: 'PAGN', - city: 'Angoon', - state: 'AK', - lat: 57.5, - lon: -134.58333, - }, - PAGS: { - id: 'PAGS', - city: 'Gustavus, Gustavus Airport', - state: 'AK', - lat: 58.41667, - lon: -135.7, - }, - PAGY: { - id: 'PAGY', - city: 'Skagway', - state: 'AK', - lat: 59.4544, - lon: -135.3263, - }, - PAHC: { - id: 'PAHC', - city: 'Holy Cross', - state: 'AK', - lat: 62.1873, - lon: -159.77657, - }, - PAHL: { - id: 'PAHL', - city: 'Huslia, Huslia Airport', - state: 'AK', - lat: 65.6975, - lon: -156.35111, - }, - PAHN: { - id: 'PAHN', - city: 'Haines - Haines Airport', - state: 'AK', - lat: 59.2429, - lon: -135.5114, - }, - PAHO: { - id: 'PAHO', - city: 'Homer, Homer Airport', - state: 'AK', - lat: 59.65, - lon: -151.48333, - }, - PAHX: { - id: 'PAHX', - city: 'Shageluk Airport', - state: 'AK', - lat: 62.6923, - lon: -159.5692, - }, - PAHY: { - id: 'PAHY', - city: 'Hydaburg - Hydaburg Seaplane Base', - state: 'AK', - lat: 55.2, - lon: -132.83333, - }, - PAIG: { - id: 'PAIG', - city: 'Igiugig', - state: 'AK', - lat: 59.32395, - lon: -155.90235, - }, - PAII: { - id: 'PAII', - city: 'Egegik, Egegik Airport', - state: 'AK', - lat: 58.18528, - lon: -157.38556, - }, - PAIK: { - id: 'PAIK', - city: 'Kinana / Bob Baker Me', - state: 'AK', - lat: 66.98333, - lon: -160.43333, - }, - PAIL: { - id: 'PAIL', - city: 'Iliamna, Iliamna Airport', - state: 'AK', - lat: 59.75, - lon: -154.9, - }, - PAIM: { - id: 'PAIM', - city: 'Utopia Creek, Indian Mountain LRRS Airport', - state: 'AK', - lat: 66, - lon: -153.7, - }, - PAIN: { - id: 'PAIN', - city: 'McKinley Park, McKinley National Park Airport', - state: 'AK', - lat: 63.73333, - lon: -148.91667, - }, - PAIW: { - id: 'PAIW', - city: 'Wales', - state: 'AK', - lat: 65.6226, - lon: -168.0949, - }, - PAJC: { - id: 'PAJC', - city: 'Chignik, Chignik Airport', - state: 'AK', - lat: 56.31139, - lon: -158.37333, - }, - PAJK: { - id: 'PAJK', - city: 'NWS Office: Juneau', - state: 'AK', - lat: 58.4, - lon: -134.57001, - }, - PAJN: { - id: 'PAJN', - city: 'Juneau, Juneau International Airport', - state: 'AK', - lat: 58.35472, - lon: -134.57611, - }, - PAJZ: { - id: 'PAJZ', - city: 'Koliganek', - state: 'AK', - lat: 59.727, - lon: -157.2589999, - }, - PAKF: { - id: 'PAKF', - city: 'False Pass Airport', - state: 'AK', - lat: 54.847, - lon: -163.41, - }, - PAKH: { - id: 'PAKH', - city: 'Akhiok', - state: 'AK', - lat: 56.9387, - lon: -154.1826, - }, - PAKK: { - id: 'PAKK', - city: 'Koyuk, Koyuk Airport', - state: 'AK', - lat: 64.93389, - lon: -161.15806, - }, - PAKN: { - id: 'PAKN', - city: 'King Salmon, King Salmon Airport', - state: 'AK', - lat: 58.67667, - lon: -156.64917, - }, - PAKP: { - id: 'PAKP', - city: 'Anaktuvuk Pass, Anaktuvuk Pass Airport', - state: 'AK', - lat: 68.13361, - lon: -151.7433299, - }, - PAKT: { - id: 'PAKT', - city: 'Ketchikan, Ketchikan International Airport', - state: 'AK', - lat: 55.35556, - lon: -131.71361, - }, - PAKU: { - id: 'PAKU', - city: 'Kuparuk, Ugnu-Kuparuk Airport', - state: 'AK', - lat: 70.31667, - lon: -149.58333, - }, - PAKV: { - id: 'PAKV', - city: 'Kaltag, Kaltag Airport', - state: 'AK', - lat: 64.31667, - lon: -158.73333, - }, - PAKW: { - id: 'PAKW', - city: 'Klawock - Klawock Airport', - state: 'AK', - lat: 55.5839, - lon: -133.067, - }, - PAKX: { - id: 'PAKX', - city: 'WILDER NATWICK', - state: 'AK', - lat: 60.2, - lon: -154.3166, - }, - PALG: { - id: 'PALG', - city: 'Kalskag', - state: 'AK', - lat: 61.5364, - lon: -160.3414, - }, - PALH: { - id: 'PALH', - city: 'Anchorage, Lake Hood Seaplane Base', - state: 'AK', - lat: 61.18333, - lon: -149.96667, - }, - PALP: { - id: 'PALP', - city: 'Deadhorse, Alpine Airstrip', - state: 'AK', - lat: 70.33333, - lon: -150.93333, - }, - PALU: { - id: 'PALU', - city: 'Cape Lisburne, Cape Lisburne LRRS Airport', - state: 'AK', - lat: 68.88333, - lon: -166.1, - }, - PAMB: { - id: 'PAMB', - city: 'Manokotak', - state: 'AK', - lat: 58.9902, - lon: -159.0499, - }, - PAMC: { - id: 'PAMC', - city: 'McGrath, McGrath Airport', - state: 'AK', - lat: 62.96667, - lon: -155.61667, - }, - PAMD: { - id: 'PAMD', - city: 'Middleton Island Airport', - state: 'AK', - lat: 59.4423, - lon: -146.3166, - }, - PAMH: { - id: 'PAMH', - city: 'Minchumina, Minchumina Airport', - state: 'AK', - lat: 63.88056, - lon: -152.30056, - }, - PAMK: { - id: 'PAMK', - city: 'St Michael Airport', - state: 'AK', - lat: 63.49006, - lon: -162.11039, - }, - PAMM: { - id: 'PAMM', - city: 'Metlakatla, Metlakatla Seaplane Base', - state: 'AK', - lat: 55.13111, - lon: -131.57806, - }, - PAMO: { - id: 'PAMO', - city: 'Mountain Village', - state: 'AK', - lat: 62.0953, - lon: -163.6819, - }, - PAMR: { - id: 'PAMR', - city: 'Anchorage, Merrill Field Airport', - state: 'AK', - lat: 61.21667, - lon: -149.85, - }, - PAMY: { - id: 'PAMY', - city: 'Mekoryuk, Mekoryuk Airport', - state: 'AK', - lat: 60.36667, - lon: -166.26667, - }, - PANA: { - id: 'PANA', - city: 'Napakiak Airport', - state: 'AK', - lat: 60.6903, - lon: -161.9785, - }, - PANC: { - id: 'PANC', - city: 'Anchorage, Ted Stevens Anchorage International Airport', - state: 'AK', - lat: 61.17444, - lon: -149.9961099, - }, - PANI: { - id: 'PANI', - city: 'Aniak, Aniak Airport', - state: 'AK', - lat: 61.58139, - lon: -159.54278, - }, - PANN: { - id: 'PANN', - city: 'Nenana Municipal Airport', - state: 'AK', - lat: 64.54796, - lon: -149.08398, - }, - PANU: { - id: 'PANU', - city: 'Nulato Airport', - state: 'AK', - lat: 64.72933, - lon: -158.07422, - }, - PANV: { - id: 'PANV', - city: 'Anvik, Anvik Airport', - state: 'AK', - lat: 62.64833, - lon: -160.18972, - }, - PANW: { - id: 'PANW', - city: 'New Stuyahok', - state: 'AK', - lat: 59.45, - lon: -157.328, - }, - PAOH: { - id: 'PAOH', - city: 'Hoonah - Hoonah Seaplane Base', - state: 'AK', - lat: 58.097, - lon: -135.4139999, - }, - PAOM: { - id: 'PAOM', - city: 'Nome, Nome Airport', - state: 'AK', - lat: 64.51194, - lon: -165.445, - }, - PAOR: { - id: 'PAOR', - city: 'Northway, Northway Airport', - state: 'AK', - lat: 62.96111, - lon: -141.92889, - }, - PAOT: { - id: 'PAOT', - city: 'Ralph Wien Memorial Airport', - state: 'AK', - lat: 66.88576, - lon: -162.60624, - }, - PAOU: { - id: 'PAOU', - city: 'Nelson Lagoon', - state: 'AK', - lat: 56.008, - lon: -161.16, - }, - PAPB: { - id: 'PAPB', - city: 'St. George, St. George Airport', - state: 'AK', - lat: 56.57861, - lon: -169.66139, - }, - PAPG: { - id: 'PAPG', - city: 'Petersburg', - state: 'AK', - lat: 56.8017, - lon: -132.9453, - }, - PAPH: { - id: 'PAPH', - city: 'Port Heiden, Port Heiden Airport', - state: 'AK', - lat: 56.95, - lon: -158.63333, - }, - PAPM: { - id: 'PAPM', - city: 'Platinum', - state: 'AK', - lat: 59.01667, - lon: -161.8166699, - }, - PAPN: { - id: 'PAPN', - city: 'Pilot Point Airport', - state: 'AK', - lat: 57.58, - lon: -157.572, - }, - PAPO: { - id: 'PAPO', - city: 'Point Hope, Point Hope Airport', - state: 'AK', - lat: 68.35, - lon: -166.8, - }, - PAPR: { - id: 'PAPR', - city: 'Prospect Creek, Prospect Creek Airport', - state: 'AK', - lat: 66.81278, - lon: -150.64389, - }, - PAPT: { - id: 'PAPT', - city: 'Puntilla', - state: 'AK', - lat: 62.1, - lon: -152.75, - }, - PAQH: { - id: 'PAQH', - city: 'Quinhagak Airport', - state: 'AK', - lat: 59.7551, - lon: -161.8454, - }, - PAQT: { - id: 'PAQT', - city: 'Nuiqsut, Nuiqsut Airport', - state: 'AK', - lat: 70.2099999, - lon: -151.00556, - }, - PARC: { - id: 'PARC', - city: 'Arctic Village, Arctic Village Airport', - state: 'AK', - lat: 68.11444, - lon: -145.57917, - }, - PARS: { - id: 'PARS', - city: 'Russian Mission', - state: 'AK', - lat: 61.775, - lon: -161.3194, - }, - PARY: { - id: 'PARY', - city: 'Ruby', - state: 'AK', - lat: 64.7272, - lon: -155.4697, - }, - PASA: { - id: 'PASA', - city: 'Savoonga Airport', - state: 'AK', - lat: 63.68333, - lon: -170.5, - }, - PASC: { - id: 'PASC', - city: 'Deadhorse, Deadhorse Airport', - state: 'AK', - lat: 70.2, - lon: -148.46667, - }, - PASD: { - id: 'PASD', - city: 'Sand Point', - state: 'AK', - lat: 55.31667, - lon: -160.51667, - }, - PASH: { - id: 'PASH', - city: 'Shishmaref, Shishmaref Airport', - state: 'AK', - lat: 66.26667, - lon: -166.08333, - }, - PASI: { - id: 'PASI', - city: 'Sitka - Sitka Airport', - state: 'AK', - lat: 57.048, - lon: -135.3647, - }, - PASK: { - id: 'PASK', - city: 'Selawik', - state: 'AK', - lat: 66.61667, - lon: -160, - }, - PASL: { - id: 'PASL', - city: 'Sleetmute', - state: 'AK', - lat: 61.69735, - lon: -157.16712, - }, - PASM: { - id: 'PASM', - city: "St. Mary's, St. Mary's Airport", - state: 'AK', - lat: 62.05, - lon: -163.3, - }, - PASN: { - id: 'PASN', - city: 'St. Paul Island, St. Paul Island Airport', - state: 'AK', - lat: 57.16667, - lon: -170.21667, - }, - PASO: { - id: 'PASO', - city: 'Seldovia, Seldovia Airport', - state: 'AK', - lat: 59.45, - lon: -151.7, - }, - PASV: { - id: 'PASV', - city: 'Sparrevohn Airways Facilities Sector', - state: 'AK', - lat: 61.1, - lon: -155.5666699, - }, - PASX: { - id: 'PASX', - city: 'Soldotna', - state: 'AK', - lat: 60.48333, - lon: -151.03333, - }, - PASY: { - id: 'PASY', - city: 'Shemya, Eareckson AFB', - state: 'AK', - lat: 52.71667, - lon: 174.11667, - }, - PATA: { - id: 'PATA', - city: 'Tanana, Calhoun Memorial Airport', - state: 'AK', - lat: 65.16667, - lon: -152.1, - }, - PATC: { - id: 'PATC', - city: 'Tin City Airways Facilities Sector', - state: 'AK', - lat: 65.56667, - lon: -167.91667, - }, - PATE: { - id: 'PATE', - city: 'Teller', - state: 'AK', - lat: 65.2403999, - lon: -166.3393, - }, - PATG: { - id: 'PATG', - city: 'Togiac Village, Togiak Airport', - state: 'AK', - lat: 59.05, - lon: -160.4, - }, - PATK: { - id: 'PATK', - city: 'Talkeetna, Talkeetna Airport', - state: 'AK', - lat: 62.32056, - lon: -150.09361, - }, - PATL: { - id: 'PATL', - city: 'Takotna, Tatalina LRRS Airport', - state: 'AK', - lat: 62.9, - lon: -155.98333, - }, - PATO: { - id: 'PATO', - city: 'Portage, Portage Glacier', - state: 'AK', - lat: 60.78333, - lon: -148.83333, - }, - PATQ: { - id: 'PATQ', - city: 'Atqasuk', - state: 'AK', - lat: 70.4673, - lon: -157.4357, - }, - PAUN: { - id: 'PAUN', - city: 'Unalakleet', - state: 'AK', - lat: 63.88333, - lon: -160.8, - }, - PAVA: { - id: 'PAVA', - city: 'Chevak Airport', - state: 'AK', - lat: 61.5408, - lon: -165.6009, - }, - PAVC: { - id: 'PAVC', - city: 'King Cove', - state: 'AK', - lat: 55.116, - lon: -162.266, - }, - PAVD: { - id: 'PAVD', - city: 'Valdez 2', - state: 'AK', - lat: 61.13333, - lon: -146.26667, - }, - PAVL: { - id: 'PAVL', - city: 'Kivalina, Kivalina Airport', - state: 'AK', - lat: 67.73333, - lon: -164.55, - }, - PAWD: { - id: 'PAWD', - city: 'Seward', - state: 'AK', - lat: 60.11667, - lon: -149.45, - }, - PAWG: { - id: 'PAWG', - city: 'Wrangell', - state: 'AK', - lat: 56.48333, - lon: -132.36667, - }, - PAWM: { - id: 'PAWM', - city: 'White Mountain Airport', - state: 'AK', - lat: 64.6892, - lon: -163.4127, - }, - PAWN: { - id: 'PAWN', - city: 'Noatak, Noatak Airport', - state: 'AK', - lat: 67.56667, - lon: -162.98333, - }, - PAWS: { - id: 'PAWS', - city: 'Wasilla, Wasilla Airport', - state: 'AK', - lat: 61.57194, - lon: -149.54056, - }, - PAYA: { - id: 'PAYA', - city: 'Yakutat', - state: 'AK', - lat: 59.51667, - lon: -139.66667, - }, - PAZK: { - id: 'PAZK', - city: 'Eureka, Skelton Airport', - state: 'AK', - lat: 61.93333, - lon: -147.16667, - }, - PFCB: { - id: 'PFCB', - city: 'Chenega Bay Airport', - state: 'AK', - lat: 60.07856, - lon: -147.99473, - }, - PFCL: { - id: 'PFCL', - city: 'Clarks Point Airport', - state: 'AK', - lat: 58.8337, - lon: -158.5294, - }, - PFEL: { - id: 'PFEL', - city: 'Elim Airport', - state: 'AK', - lat: 64.615, - lon: -162.2705, - }, - PFKO: { - id: 'PFKO', - city: 'Kotlik Airport', - state: 'AK', - lat: 63.03058, - lon: -163.5326399, - }, - PFKT: { - id: 'PFKT', - city: 'Brevig Mission Airport', - state: 'AK', - lat: 65.3313, - lon: -166.4657, - }, - PFKW: { - id: 'PFKW', - city: 'Kwethluk Airport', - state: 'AK', - lat: 60.7903, - lon: -161.4437, - }, - PFNO: { - id: 'PFNO', - city: 'Noorvik', - state: 'AK', - lat: 66.8175, - lon: -161.0223, - }, - PFSH: { - id: 'PFSH', - city: 'Shaktoolik Airport', - state: 'AK', - lat: 64.3711, - lon: -161.224, - }, - PFTO: { - id: 'PFTO', - city: 'Tok Junction Airport', - state: 'AK', - lat: 63.32951, - lon: -142.95368, - }, - PFWS: { - id: 'PFWS', - city: 'South Naknek Nr 2 Airport', - state: 'AK', - lat: 58.7021, - lon: -157.0026, - }, - PFYU: { - id: 'PFYU', - city: 'Fort Yukon, Fort Yukon Airport', - state: 'AK', - lat: 66.56667, - lon: -145.26667, - }, - PFZK: { - id: 'PFZK', - city: 'Akiachak Airport', - state: 'AK', - lat: 60.91381, - lon: -161.4933299, - }, - POKA: { - id: 'POKA', - city: 'Tununak Airport', - state: 'AK', - lat: 60.56953, - lon: -165.24628, - }, - PPIT: { - id: 'PPIT', - city: 'Nunapitchuk Airport', - state: 'AK', - lat: 60.906, - lon: -162.4406, - }, - PPIZ: { - id: 'PPIZ', - city: 'Point Lay, Point Lay LRRS Airport', - state: 'AK', - lat: 69.7166699, - lon: -163, - }, - KDET: { - id: 'KDET', - city: 'Coleman A Young Municipal Airport', - state: 'MI', - lat: 42.40729, - lon: -83.00894, - }, - KDRM: { - id: 'KDRM', - city: 'Drummond Island Airport', - state: 'MI', - lat: 46.0072, - lon: -83.7427, - }, - KDTW: { - id: 'KDTW', - city: 'Detroit, Detroit Metropolitan Wayne County Airport', - state: 'MI', - lat: 42.23139, - lon: -83.33083, - }, - KDUH: { - id: 'KDUH', - city: 'Lambertville, Toledo Suburban Airport', - state: 'MI', - lat: 41.73583, - lon: -83.65528, - }, - KERY: { - id: 'KERY', - city: 'Newberry, Luce County Airport', - state: 'MI', - lat: 46.31111, - lon: -85.45722, - }, - KESC: { - id: 'KESC', - city: 'Delta County Airport', - state: 'MI', - lat: 45.7226799, - lon: -87.09372, - }, - KFFX: { - id: 'KFFX', - city: 'Fremont Municipal Airport', - state: 'MI', - lat: 43.43933, - lon: -85.9948299, - }, - KFKS: { - id: 'KFKS', - city: 'Frankfort, Frankfort Dow Memorial Field Airport', - state: 'MI', - lat: 44.625, - lon: -86.20056, - }, - KFNT: { - id: 'KFNT', - city: 'Flint, Bishop International Airport', - state: 'MI', - lat: 42.96667, - lon: -83.74944, - }, - KFPK: { - id: 'KFPK', - city: 'Charlotte, Fitch H Beach Airport', - state: 'MI', - lat: 42.57444, - lon: -84.81139, - }, - KGLR: { - id: 'KGLR', - city: 'Gaylord Regional Airport', - state: 'MI', - lat: 45.01658, - lon: -84.68937, - }, - KGOV: { - id: 'KGOV', - city: 'Grayling, Grayling Army Airfield', - state: 'MI', - lat: 44.68028, - lon: -84.72889, - }, - KGRR: { - id: 'KGRR', - city: 'Grand Rapids, Gerald R. Ford International Airport', - state: 'MI', - lat: 42.88083, - lon: -85.52278, - }, - KHAI: { - id: 'KHAI', - city: 'Haines Memorial Airport', - state: 'MI', - lat: 41.9598, - lon: -85.5934, - }, - KHTL: { - id: 'KHTL', - city: 'Houghton Lake, Roscommon County Airport', - state: 'MI', - lat: 44.35111, - lon: -84.67417, - }, - KHYX: { - id: 'KHYX', - city: 'Saginaw County H W Browne Airport', - state: 'MI', - lat: 43.43191, - lon: -83.86476, - }, - KIKW: { - id: 'KIKW', - city: 'Jack Barstow Airport', - state: 'MI', - lat: 43.6624, - lon: -84.26213, - }, - KIMT: { - id: 'KIMT', - city: 'Iron Mountain / Kingsford, Ford Airport', - state: 'MI', - lat: 45.81417, - lon: -88.10889, - }, - KIRS: { - id: 'KIRS', - city: 'Sturgis, Kirsch Municipal Airport', - state: 'MI', - lat: 41.8127799, - lon: -85.43917, - }, - KISQ: { - id: 'KISQ', - city: 'Manistique, Schoolcraft County Airport', - state: 'MI', - lat: 45.97472, - lon: -86.17194, - }, - KIWD: { - id: 'KIWD', - city: 'Ironwood, Gogebic-Iron County Airport', - state: 'MI', - lat: 46.53333, - lon: -90.13333, - }, - KJXN: { - id: 'KJXN', - city: 'Jackson County Airport - Reynolds Field', - state: 'MI', - lat: 42.26171, - lon: -84.46147, - }, - KJYM: { - id: 'KJYM', - city: 'Hillsdale Municipal Airport', - state: 'MI', - lat: 41.91972, - lon: -84.58528, - }, - KLAN: { - id: 'KLAN', - city: 'Capital Region International Airport', - state: 'MI', - lat: 42.77616, - lon: -84.5997, - }, - KLDM: { - id: 'KLDM', - city: 'Ludington, Mason County Airport', - state: 'MI', - lat: 43.96667, - lon: -86.4, - }, - KLWA: { - id: 'KLWA', - city: 'South Haven, South Haven Area Regional Airport', - state: 'MI', - lat: 42.35083, - lon: -86.25611, - }, - KMBL: { - id: 'KMBL', - city: 'Manistee County - Blacker Airport', - state: 'MI', - lat: 44.27142, - lon: -86.23773, - }, - KMBS: { - id: 'KMBS', - city: 'MBS International Airport', - state: 'MI', - lat: 43.5281, - lon: -84.08129, - }, - KMCD: { - id: 'KMCD', - city: 'Mackinac Island Airport', - state: 'MI', - lat: 45.86628, - lon: -84.63437, - }, - KMGN: { - id: 'KMGN', - city: 'Harbor Springs, Harbor Springs Airport', - state: 'MI', - lat: 45.42556, - lon: -84.91333, - }, - KMKG: { - id: 'KMKG', - city: 'Muskegon, Muskegon County Airport', - state: 'MI', - lat: 43.17111, - lon: -86.23667, - }, - KMNM: { - id: 'KMNM', - city: 'Menominee - Marinette Twin County Airport', - state: 'MI', - lat: 45.12628, - lon: -87.64438, - }, - KMOP: { - id: 'KMOP', - city: 'Mount Pleasant, Mount Pleasant Municipal Airport', - state: 'MI', - lat: 43.61667, - lon: -84.73333, - }, - KMTC: { - id: 'KMTC', - city: 'Selfridge Air National Guard Base', - state: 'MI', - lat: 42.60458, - lon: -82.83528, - }, - KOEB: { - id: 'KOEB', - city: 'Branch County Memorial Airport', - state: 'MI', - lat: 41.93085, - lon: -85.05429, - }, - KONZ: { - id: 'KONZ', - city: 'Detroit/Grosse Ile, Grosse Ile Airport', - state: 'MI', - lat: 42.09861, - lon: -83.1611099, - }, - KOSC: { - id: 'KOSC', - city: 'Oscoda, Oscoda-Wurtsmith Airport', - state: 'MI', - lat: 44.45, - lon: -83.36667, - }, - KOZW: { - id: 'KOZW', - city: 'Howell, Livingston County Airport', - state: 'MI', - lat: 42.62944, - lon: -83.98417, - }, - KPHN: { - id: 'KPHN', - city: 'St Clair County International Airport', - state: 'MI', - lat: 42.91031, - lon: -82.53315, - }, - KPLN: { - id: 'KPLN', - city: 'Pellston Regional Airport of Emmet County', - state: 'MI', - lat: 45.56443, - lon: -84.7928699, - }, - KPTK: { - id: 'KPTK', - city: 'Pontiac, Oakland County International Airport', - state: 'MI', - lat: 42.66306, - lon: -83.41, - }, - KPZQ: { - id: 'KPZQ', - city: 'Rogers City, Presque Isle County Airport', - state: 'MI', - lat: 45.40694, - lon: -83.81278, - }, - KRMY: { - id: 'KRMY', - city: 'Brooks Field Airport', - state: 'MI', - lat: 42.25238, - lon: -84.95253, - }, - KRNP: { - id: 'KRNP', - city: 'Owosso, Owosso Community Airport', - state: 'MI', - lat: 42.99278, - lon: -84.13889, - }, - KRQB: { - id: 'KRQB', - city: 'Big Rapids, Roben-Hood Airport', - state: 'MI', - lat: 43.7224999, - lon: -85.50417, - }, - KSAW: { - id: 'KSAW', - city: 'Marquette, Sawyer International Airport', - state: 'MI', - lat: 46.35361, - lon: -87.39528, - }, - KSJX: { - id: 'KSJX', - city: 'Beaver Island, Beaver Island Airport', - state: 'MI', - lat: 45.69222, - lon: -85.56639, - }, - KSLH: { - id: 'KSLH', - city: 'Cheboygan, Cheboygan County Airport', - state: 'MI', - lat: 45.65361, - lon: -84.51917, - }, - KTEW: { - id: 'KTEW', - city: 'Mason, Mason Jewett Field Airport', - state: 'MI', - lat: 42.56583, - lon: -84.42333, - }, - KTTF: { - id: 'KTTF', - city: 'Monroe, Custer Airport', - state: 'MI', - lat: 41.94, - lon: -83.43472, - }, - KTVC: { - id: 'KTVC', - city: 'Cherry Capital Airport', - state: 'MI', - lat: 44.73898, - lon: -85.56788, - }, - KVLL: { - id: 'KVLL', - city: 'Troy, Oakland/Troy Airport', - state: 'MI', - lat: 42.54278, - lon: -83.17778, - }, - KYIP: { - id: 'KYIP', - city: 'Detroit, Willow Run Airport', - state: 'MI', - lat: 42.2366699, - lon: -83.52611, - }, - KBHK: { - id: 'KBHK', - city: 'Baker, Baker Municipal Airport', - state: 'MT', - lat: 46.34778, - lon: -104.2574999, - }, - KBIL: { - id: 'KBIL', - city: 'Billings, Billings Logan International Airport', - state: 'MT', - lat: 45.80694, - lon: -108.54222, - }, - KBTM: { - id: 'KBTM', - city: 'Butte, Bert Mooney Airport', - state: 'MT', - lat: 45.95472, - lon: -112.4975, - }, - KBZN: { - id: 'KBZN', - city: 'Bozeman, Gallatin Field', - state: 'MT', - lat: 45.78806, - lon: -111.16083, - }, - KCTB: { - id: 'KCTB', - city: 'Cut Bank, Cut Bank Municipal Airport', - state: 'MT', - lat: 48.60833, - lon: -112.37611, - }, - KDLN: { - id: 'KDLN', - city: 'Dillon, Dillon Airport', - state: 'MT', - lat: 45.2575, - lon: -112.55444, - }, - KEKS: { - id: 'KEKS', - city: 'Ennis - Big Sky Airport', - state: 'MT', - lat: 45.27436, - lon: -111.64886, - }, - KGDV: { - id: 'KGDV', - city: 'Glendive, Dawson Community Airport', - state: 'MT', - lat: 47.13333, - lon: -104.8, - }, - KGFA: { - id: 'KGFA', - city: 'Malmstrom Air Force Base', - state: 'MT', - lat: 47.5, - lon: -111.18333, - }, - KGGW: { - id: 'KGGW', - city: 'Glasgow, Glasgow International Airport', - state: 'MT', - lat: 48.21389, - lon: -106.62139, - }, - KGPI: { - id: 'KGPI', - city: 'Kalispell, Glacier Park International Airport', - state: 'MT', - lat: 48.30417, - lon: -114.26361, - }, - KGTF: { - id: 'KGTF', - city: 'Great Falls, Great Falls International Airport', - state: 'MT', - lat: 47.47333, - lon: -111.38222, - }, - KHLN: { - id: 'KHLN', - city: 'Helena Regional Airport', - state: 'MT', - lat: 46.60445, - lon: -111.9892, - }, - KHRF: { - id: 'KHRF', - city: 'Ravalli County Airport', - state: 'MT', - lat: 46.25463, - lon: -114.1246, - }, - KHVR: { - id: 'KHVR', - city: 'Havre, Havre City-County Airport', - state: 'MT', - lat: 48.54278, - lon: -109.76333, - }, - KJDN: { - id: 'KJDN', - city: 'Jordan, Jordan Airport', - state: 'MT', - lat: 47.32583, - lon: -106.9475, - }, - KLVM: { - id: 'KLVM', - city: 'Livingston, Mission Field Airport', - state: 'MT', - lat: 45.69944, - lon: -110.44833, - }, - KLWT: { - id: 'KLWT', - city: 'Lewistown, Lewistown Municipal Airport', - state: 'MT', - lat: 47.0491699, - lon: -109.46639, - }, - KMLP: { - id: 'KMLP', - city: 'Mullan Pass, Mullan Pass Vor', - state: 'MT', - lat: 47.45417, - lon: -115.66972, - }, - KMLS: { - id: 'KMLS', - city: 'Miles City, Frank Wiley Field Airport', - state: 'MT', - lat: 46.42806, - lon: -105.88639, - }, - KMSO: { - id: 'KMSO', - city: 'Missoula, Missoula International Airport', - state: 'MT', - lat: 46.92083, - lon: -114.0925, - }, - KMVH: { - id: 'KMVH', - city: 'N BAR Ranch Airport', - state: 'MT', - lat: 46.8381, - lon: -108.9368, - }, - KOLF: { - id: 'KOLF', - city: 'Wolf Point, Clayton Airport', - state: 'MT', - lat: 48.09444, - lon: -105.57722, - }, - KPWD: { - id: 'KPWD', - city: 'Sher-Wood Airport', - state: 'MT', - lat: 48.789, - lon: -104.52297, - }, - KRVF: { - id: 'KRVF', - city: 'Ruby Valley Field Airport', - state: 'MT', - lat: 45.53542, - lon: -112.30228, - }, - KSBX: { - id: 'KSBX', - city: 'Shelby Airport', - state: 'MT', - lat: 48.54069, - lon: -111.87125, - }, - KSDY: { - id: 'KSDY', - city: 'Sidney-Richland', - state: 'MT', - lat: 47.7, - lon: -104.2, - }, - KWYS: { - id: 'KWYS', - city: 'West Yellowstone', - state: 'MT', - lat: 44.68333, - lon: -111.11667, - }, - KAAA: { - id: 'KAAA', - city: 'Logan County Airport', - state: 'IL', - lat: 40.15885, - lon: -89.33891, - }, - KAJG: { - id: 'KAJG', - city: 'Mount Carmel, Mount Carmel Municipal Airport', - state: 'IL', - lat: 38.60928, - lon: -87.72508, - }, - KALN: { - id: 'KALN', - city: 'St. Louis Regional Airport', - state: 'IL', - lat: 38.88968, - lon: -90.03163, - }, - KARR: { - id: 'KARR', - city: 'Aurora Municipal Airport', - state: 'IL', - lat: 41.77132, - lon: -88.48147, - }, - KBLV: { - id: 'KBLV', - city: 'Belleville, Scott AFB/MidAmerica Airport', - state: 'IL', - lat: 38.55, - lon: -89.85, - }, - KBMI: { - id: 'KBMI', - city: 'Bloomington/Normal, Central Illinois Regional Airport at Bloomington-Normal', - state: 'IL', - lat: 40.47694, - lon: -88.91583, - }, - KCIR: { - id: 'KCIR', - city: 'Cairo Regional Airport', - state: 'IL', - lat: 37.06388, - lon: -89.2232, - }, - KCMI: { - id: 'KCMI', - city: 'University of Illinois - Willard', - state: 'IL', - lat: 40.03245, - lon: -88.27547, - }, - KCPS: { - id: 'KCPS', - city: 'St. Louis Downtown Airport', - state: 'IL', - lat: 38.56403, - lon: -90.14871, - }, - KDEC: { - id: 'KDEC', - city: 'Decatur Airport', - state: 'IL', - lat: 39.8308, - lon: -88.87192, - }, - KDKB: { - id: 'KDKB', - city: 'De Kalb Taylor Municipal Airport', - state: 'IL', - lat: 41.93381, - lon: -88.70657, - }, - KDNV: { - id: 'KDNV', - city: 'Danville, Vermilion County Airport', - state: 'IL', - lat: 40.19944, - lon: -87.59556, - }, - KDPA: { - id: 'KDPA', - city: 'Chicago / West Chicago, Dupage Airport', - state: 'IL', - lat: 41.8963899, - lon: -88.25111, - }, - KENL: { - id: 'KENL', - city: 'Centralia Municipal Airport', - state: 'IL', - lat: 38.50951, - lon: -89.08996, - }, - KFOA: { - id: 'KFOA', - city: 'Flora Municipal Airport', - state: 'IL', - lat: 38.66726, - lon: -88.4526999, - }, - KFWC: { - id: 'KFWC', - city: 'Fairfield, Fairfield Municipal Airport', - state: 'IL', - lat: 38.37861, - lon: -88.41278, - }, - KGBG: { - id: 'KGBG', - city: 'Galesburg Municipal Airport', - state: 'IL', - lat: 40.9328999, - lon: -90.43339, - }, - KHSB: { - id: 'KHSB', - city: 'Harrisburg-Raleigh Airport', - state: 'IL', - lat: 37.81281, - lon: -88.54486, - }, - KIGQ: { - id: 'KIGQ', - city: 'Lansing Municipal Airport', - state: 'IL', - lat: 41.54125, - lon: -87.52822, - }, - KIJX: { - id: 'KIJX', - city: 'Jacksonville Municipal Airport', - state: 'IL', - lat: 39.7740099, - lon: -90.24187, - }, - KIKK: { - id: 'KIKK', - city: 'Greater Kankakee Airport', - state: 'IL', - lat: 41.06871, - lon: -87.85372, - }, - KJOT: { - id: 'KJOT', - city: 'Joliet Regional Airport', - state: 'IL', - lat: 41.51755, - lon: -88.17903, - }, - KLOT: { - id: 'KLOT', - city: 'Lewis University Airport', - state: 'IL', - lat: 41.60307, - lon: -88.10164, - }, - KLWV: { - id: 'KLWV', - city: 'Lawrenceville-Vincennes International Airport', - state: 'IL', - lat: 38.76046, - lon: -87.59903, - }, - KMDH: { - id: 'KMDH', - city: 'Southern Illinois Airport', - state: 'IL', - lat: 37.78328, - lon: -89.24532, - }, - KMDW: { - id: 'KMDW', - city: 'Chicago, Chicago Midway Airport', - state: 'IL', - lat: 41.78417, - lon: -87.75528, - }, - KMLI: { - id: 'KMLI', - city: 'Moline Quad-City Airport', - state: 'IL', - lat: 41.4482, - lon: -90.52359, - }, - KMQB: { - id: 'KMQB', - city: 'Macomb Municipal Airport', - state: 'IL', - lat: 40.5176299, - lon: -90.64807, - }, - KMTO: { - id: 'KMTO', - city: 'Mattoon / Charleston, Coles County Memorial Airport', - state: 'IL', - lat: 39.47806, - lon: -88.2791699, - }, - KMVN: { - id: 'KMVN', - city: 'Mount Vernon Airport', - state: 'IL', - lat: 38.32842, - lon: -88.85292, - }, - KMWA: { - id: 'KMWA', - city: 'Marion - Williamson County Regional Airport', - state: 'IL', - lat: 37.76671, - lon: -89.00993, - }, - KOLY: { - id: 'KOLY', - city: 'Olney-Noble Airport', - state: 'IL', - lat: 38.72133, - lon: -88.1799, - }, - KORD: { - id: 'KORD', - city: "Chicago, Chicago-O'Hare International Airport", - state: 'IL', - lat: 41.97972, - lon: -87.9044399, - }, - KPIA: { - id: 'KPIA', - city: 'Peoria - General Downing-Peoria International Airport', - state: 'IL', - lat: 40.6674999, - lon: -89.68389, - }, - KPNT: { - id: 'KPNT', - city: 'Pontiac Municipal Airport', - state: 'IL', - lat: 40.92327, - lon: -88.6213, - }, - KPPQ: { - id: 'KPPQ', - city: 'Pittsfield, Pittsfield Penstone Municipal Airport', - state: 'IL', - lat: 39.63889, - lon: -90.77833, - }, - KPRG: { - id: 'KPRG', - city: 'Edgar County Airport', - state: 'IL', - lat: 39.69817, - lon: -87.6669, - }, - KPWK: { - id: 'KPWK', - city: 'Chicago / Wheeling, Pal-Waukee Airport', - state: 'IL', - lat: 42.12083, - lon: -87.90472, - }, - KRFD: { - id: 'KRFD', - city: 'Rockford, Greater Rockford Airport', - state: 'IL', - lat: 42.19278, - lon: -89.09333, - }, - KRPJ: { - id: 'KRPJ', - city: 'Rochelle, Rochelle Municipal-Koritz Field Airport', - state: 'IL', - lat: 41.8905699, - lon: -89.08175, - }, - KSAR: { - id: 'KSAR', - city: 'Sparta Community-Hunter Field Airport', - state: 'IL', - lat: 38.14624, - lon: -89.70243, - }, - KSLO: { - id: 'KSLO', - city: 'Salem, Salem-Leckrone Airport', - state: 'IL', - lat: 38.64278, - lon: -88.96417, - }, - KSPI: { - id: 'KSPI', - city: 'Springfield - Abraham Lincoln Capital Airport', - state: 'IL', - lat: 39.84527, - lon: -89.68405, - }, - KSQI: { - id: 'KSQI', - city: 'Sterling Rockfalls', - state: 'IL', - lat: 41.7432, - lon: -89.66547, - }, - KTAZ: { - id: 'KTAZ', - city: 'Taylorville, Taylorville Municipal Airport', - state: 'IL', - lat: 39.53417, - lon: -89.32778, - }, - KTIP: { - id: 'KTIP', - city: 'Rantoul National Aviation Center Airport', - state: 'IL', - lat: 40.28952, - lon: -88.1473, - }, - KUGN: { - id: 'KUGN', - city: 'Chicago/Waukegan Regional Airport', - state: 'IL', - lat: 42.42546, - lon: -87.86339, - }, - KUIN: { - id: 'KUIN', - city: 'Quincy Regional Airport-Baldwin Field', - state: 'IL', - lat: 39.9371, - lon: -91.19659, - }, - KVYS: { - id: 'KVYS', - city: 'Illinois Valley Regional Airport', - state: 'IL', - lat: 41.35175, - lon: -89.14963, - }, - KALK: { - id: 'KALK', - city: 'Pioneer Airfield', - state: 'AZ', - lat: 31.60564, - lon: -110.4281, - }, - KAVQ: { - id: 'KAVQ', - city: 'Tucson Marana Regional Airport', - state: 'AZ', - lat: 32.4096, - lon: -111.2184, - }, - KAZC: { - id: 'KAZC', - city: 'Colorado City, Colorado City Municipal Airport', - state: 'AZ', - lat: 36.95, - lon: -113, - }, - KBXK: { - id: 'KBXK', - city: 'Buckeye Municipal Airport', - state: 'AZ', - lat: 33.4204, - lon: -112.6862, - }, - KCGZ: { - id: 'KCGZ', - city: 'Casa Grande, Casa Grande Municipal Airport', - state: 'AZ', - lat: 32.95, - lon: -111.76667, - }, - KCHD: { - id: 'KCHD', - city: 'Chandler, Chandler Municipal Airport', - state: 'AZ', - lat: 33.26917, - lon: -111.81111, - }, - KCMR: { - id: 'KCMR', - city: 'Williams/Clark Memorial Airport', - state: 'AZ', - lat: 35.3054721, - lon: -112.1943889, - }, - KDMA: { - id: 'KDMA', - city: 'Davis-Monthan Air Force Base', - state: 'AZ', - lat: 32.16667, - lon: -110.88333, - }, - KDUG: { - id: 'KDUG', - city: 'Bisbee Douglas International Airport', - state: 'AZ', - lat: 31.45838, - lon: -109.60676, - }, - KDVT: { - id: 'KDVT', - city: 'Phoenix, Phoenix-Deer Valley Municipal Airport', - state: 'AZ', - lat: 33.69026, - lon: -112.06618, - }, - KFFZ: { - id: 'KFFZ', - city: 'Mesa / Falcon Field', - state: 'AZ', - lat: 33.46667, - lon: -111.73333, - }, - KFHU: { - id: 'KFHU', - city: 'Fort Huachuca, Libby AAF Ft Huachuca', - state: 'AZ', - lat: 31.58333, - lon: -110.33333, - }, - KFLG: { - id: 'KFLG', - city: 'Flagstaff Pulliam Airport', - state: 'AZ', - lat: 35.1443299, - lon: -111.66637, - }, - KGCN: { - id: 'KGCN', - city: 'Grand Canyon National Park Airport', - state: 'AZ', - lat: 35.94582, - lon: -112.15538, - }, - KGEU: { - id: 'KGEU', - city: 'Glendale, Glendale Municipal Airport', - state: 'AZ', - lat: 33.52722, - lon: -112.29528, - }, - KGXF: { - id: 'KGXF', - city: 'Gila Bend Air Force Auxiliary Field', - state: 'AZ', - lat: 32.8875, - lon: -112.72, - }, - KGYR: { - id: 'KGYR', - city: 'Goodyear Municipal', - state: 'AZ', - lat: 33.41667, - lon: -112.38333, - }, - KHII: { - id: 'KHII', - city: 'Havasu City Airport', - state: 'AZ', - lat: 34.56595, - lon: -114.35224, - }, - KIFP: { - id: 'KIFP', - city: 'Bullhead City, Laughlin/Bullhead International Airport', - state: 'AZ', - lat: 35.1575, - lon: -114.55944, - }, - KIGM: { - id: 'KIGM', - city: 'Kingman, Kingman Airport', - state: 'AZ', - lat: 35.2577799, - lon: -113.93306, - }, - KINW: { - id: 'KINW', - city: 'Winslow, Winslow Municipal Airport', - state: 'AZ', - lat: 35.02806, - lon: -110.72083, - }, - KIWA: { - id: 'KIWA', - city: 'Phoenix-Mesa Gateway Airport', - state: 'AZ', - lat: 33.31667, - lon: -111.65, - }, - KJTC: { - id: 'KJTC', - city: 'Springerville Municipal Airport', - state: 'AZ', - lat: 34.1293999, - lon: -109.3109, - }, - KLGF: { - id: 'KLGF', - city: 'Laguna Army Airfield', - state: 'AZ', - lat: 32.86459, - lon: -114.39298, - }, - KLUF: { - id: 'KLUF', - city: 'Luke Air Force Base / Phoenix', - state: 'AZ', - lat: 33.53333, - lon: -112.38333, - }, - KMZJ: { - id: 'KMZJ', - city: 'Pinal Airpark', - state: 'AZ', - lat: 32.50983, - lon: -111.32533, - }, - KNOZ: { - id: 'KNOZ', - city: 'Yuma Auxiliary Airfield', - state: 'AZ', - lat: 32.5, - lon: -114.45, - }, - KNYL: { - id: 'KNYL', - city: 'Yuma, Marine Corps Air Station', - state: 'AZ', - lat: 32.6594399, - lon: -114.59306, - }, - KOLS: { - id: 'KOLS', - city: 'Nogales, Nogales International Airport', - state: 'AZ', - lat: 31.42083, - lon: -110.84583, - }, - KPAN: { - id: 'KPAN', - city: 'Payson Airport', - state: 'AZ', - lat: 34.2568364, - lon: -111.3392558, - }, - KPGA: { - id: 'KPGA', - city: 'Page, Page Municipal Airport', - state: 'AZ', - lat: 36.92056, - lon: -111.44806, - }, - KPHX: { - id: 'KPHX', - city: 'Phoenix, Phoenix Sky Harbor International Airport', - state: 'AZ', - lat: 33.427799, - lon: -112.003465, - }, - KPRC: { - id: 'KPRC', - city: 'Prescott, Love Field', - state: 'AZ', - lat: 34.64917, - lon: -112.42222, - }, - KRQE: { - id: 'KRQE', - city: 'Window Rock, Window Rock Airport', - state: 'AZ', - lat: 35.65, - lon: -109.06667, - }, - KRYN: { - id: 'KRYN', - city: 'Tucson Ryan Field Airport', - state: 'AZ', - lat: 32.1422, - lon: -111.1746, - }, - KSAD: { - id: 'KSAD', - city: 'Safford, Safford Municipal Airport', - state: 'AZ', - lat: 32.85722, - lon: -109.63556, - }, - KSDL: { - id: 'KSDL', - city: 'Scottsdale Airport', - state: 'AZ', - lat: 33.61235, - lon: -111.92316, - }, - KSEZ: { - id: 'KSEZ', - city: 'Sedona Airport', - state: 'AZ', - lat: 34.85, - lon: -111.78333, - }, - KSJN: { - id: 'KSJN', - city: 'St. Johns, St. Johns Industrial Airpark', - state: 'AZ', - lat: 34.51833, - lon: -109.37917, - }, - KSOW: { - id: 'KSOW', - city: 'Show Low, Show Low Regional Airport', - state: 'AZ', - lat: 34.26528, - lon: -110.00556, - }, - KTUS: { - id: 'KTUS', - city: 'Tucson, Tucson International Airport', - state: 'AZ', - lat: 32.13153, - lon: -110.95635, - }, - KTYL: { - id: 'KTYL', - city: 'Taylor Airport', - state: 'AZ', - lat: 34.45272, - lon: -110.11503, - }, - KAAF: { - id: 'KAAF', - city: 'Apalachicola, Apalachicola', - state: 'FL', - lat: 29.72694, - lon: -85.02472, - }, - KAPF: { - id: 'KAPF', - city: 'Naples, Naples Municipal Airport', - state: 'FL', - lat: 26.15, - lon: -81.76667, - }, - KBCR: { - id: 'KBCR', - city: 'Tri-County Airport', - state: 'FL', - lat: 30.84389, - lon: -85.60175, - }, - KBCT: { - id: 'KBCT', - city: 'Boca Raton, Boca Raton Airport', - state: 'FL', - lat: 26.3786099, - lon: -80.10778, - }, - KBKV: { - id: 'KBKV', - city: 'Brooksville-Tampa Bay Regional Airport', - state: 'FL', - lat: 28.47361, - lon: -82.45444, - }, - KBOW: { - id: 'KBOW', - city: 'Bartow Municipal', - state: 'FL', - lat: 27.95, - lon: -81.78333, - }, - KCEW: { - id: 'KCEW', - city: 'Crestview, Sikes Airport', - state: 'FL', - lat: 30.77222, - lon: -86.52, - }, - KCGC: { - id: 'KCGC', - city: 'Crystal River Airport', - state: 'FL', - lat: 28.8673, - lon: -82.5712999, - }, - KCLW: { - id: 'KCLW', - city: 'Clearwater Air Park', - state: 'FL', - lat: 27.9742, - lon: -82.7563, - }, - KCOF: { - id: 'KCOF', - city: 'Cocoa - Patrick Air Force Base', - state: 'FL', - lat: 28.24219, - lon: -80.60799, - }, - KCOI: { - id: 'KCOI', - city: 'Merritt Island Airport', - state: 'FL', - lat: 28.3422, - lon: -80.68407, - }, - KCRG: { - id: 'KCRG', - city: 'Jacksonville Craig Municipal Airport', - state: 'FL', - lat: 30.33709, - lon: -81.51275, - }, - KCTY: { - id: 'KCTY', - city: 'Cross City Airport', - state: 'FL', - lat: 29.633326, - lon: -83.105458, - }, - KDAB: { - id: 'KDAB', - city: 'Daytona Beach International Airport', - state: 'FL', - lat: 29.17354, - lon: -81.07186, - }, - KDED: { - id: 'KDED', - city: 'DeLand Municipal Airport', - state: 'FL', - lat: 29.067, - lon: -81.2837, - }, - KDTS: { - id: 'KDTS', - city: 'Destin, Destin-Ft. Walton Beach Airport', - state: 'FL', - lat: 30.39333, - lon: -86.4675, - }, - KECP: { - id: 'KECP', - city: 'Panama City - Northwest Florida Beaches International Airport', - state: 'FL', - lat: 30.3582, - lon: -85.7955999, - }, - KEGI: { - id: 'KEGI', - city: 'Duke Field / Eglin Auxiliary', - state: 'FL', - lat: 30.65, - lon: -86.51667, - }, - KEVB: { - id: 'KEVB', - city: 'New Smyrna Beach Municipal Airport', - state: 'FL', - lat: 29.05687, - lon: -80.94909, - }, - KEYW: { - id: 'KEYW', - city: 'Key West International Airport', - state: 'FL', - lat: 24.55707, - lon: -81.75539, - }, - KFHB: { - id: 'KFHB', - city: 'Fernandina Beach Municipal Airport', - state: 'FL', - lat: 30.61183, - lon: -81.46119, - }, - KFIN: { - id: 'KFIN', - city: 'Flagler County Airport', - state: 'FL', - lat: 29.4657, - lon: -81.20872, - }, - KFLL: { - id: 'KFLL', - city: 'Fort Lauderdale/Hollywood International Airport', - state: 'FL', - lat: 26.07874, - lon: -80.1622, - }, - KFMY: { - id: 'KFMY', - city: 'Fort Myers, Page Field', - state: 'FL', - lat: 26.58417, - lon: -81.8625, - }, - KFPR: { - id: 'KFPR', - city: 'Fort Pierce, St. Lucie County International Airport', - state: 'FL', - lat: 27.49806, - lon: -80.37667, - }, - KFPY: { - id: 'KFPY', - city: 'Perry-Foley Airport', - state: 'FL', - lat: 30.07081, - lon: -83.58154, - }, - KFXE: { - id: 'KFXE', - city: 'Fort Lauderdale, Fort Lauderdale Executive Airport', - state: 'FL', - lat: 26.2, - lon: -80.18333, - }, - KGIF: { - id: 'KGIF', - city: 'Winter Havens Gilbert Airport', - state: 'FL', - lat: 28.06138, - lon: -81.75684, - }, - KGNV: { - id: 'KGNV', - city: 'Gainesville, Gainesville Regional Airport', - state: 'FL', - lat: 29.69194, - lon: -82.27556, - }, - KHEG: { - id: 'KHEG', - city: 'Herlong Recreational Airport', - state: 'FL', - lat: 30.27778, - lon: -81.80594, - }, - KHRT: { - id: 'KHRT', - city: 'Hurlburt Field', - state: 'FL', - lat: 30.41667, - lon: -86.68333, - }, - KHST: { - id: 'KHST', - city: 'Homestead Air Reserve Base', - state: 'FL', - lat: 25.4948799, - lon: -80.37324, - }, - KHWO: { - id: 'KHWO', - city: 'Hollywood, North Perry Airport', - state: 'FL', - lat: 25.99889, - lon: -80.24111, - }, - KIMM: { - id: 'KIMM', - city: 'IMMOKALEE', - state: 'FL', - lat: 26.43, - lon: -81.4, - }, - KINF: { - id: 'KINF', - city: 'Inverness Airport', - state: 'FL', - lat: 28.8086, - lon: -82.3165, - }, - KISM: { - id: 'KISM', - city: 'Kissimmee Gateway Airport', - state: 'FL', - lat: 28.29236, - lon: -81.43716, - }, - KJAX: { - id: 'KJAX', - city: 'Jacksonville International Airport', - state: 'FL', - lat: 30.49534, - lon: -81.6937, - }, - KLAL: { - id: 'KLAL', - city: 'Lakeland Linder International Airport', - state: 'FL', - lat: 27.98333, - lon: -82.01667, - }, - KLCQ: { - id: 'KLCQ', - city: 'Lake City Municipal Airport', - state: 'FL', - lat: 30.1821, - lon: -82.5769, - }, - KLEE: { - id: 'KLEE', - city: 'Leesburg International Airport', - state: 'FL', - lat: 28.82142, - lon: -81.80964, - }, - KLNA: { - id: 'KLNA', - city: 'Palm Beach County Park Airport', - state: 'FL', - lat: 26.59305, - lon: -80.08506, - }, - KMAI: { - id: 'KMAI', - city: 'Marianna Municipal Airport', - state: 'FL', - lat: 30.83698, - lon: -85.18347, - }, - KMCF: { - id: 'KMCF', - city: 'Macdill Air Force Base, Fl.', - state: 'FL', - lat: 27.85, - lon: -82.5, - }, - KMCO: { - id: 'KMCO', - city: 'Orlando International Airport', - state: 'FL', - lat: 28.41826, - lon: -81.32413, - }, - KMIA: { - id: 'KMIA', - city: 'Miami, Miami International Airport', - state: 'FL', - lat: 25.79056, - lon: -80.31639, - }, - KMLB: { - id: 'KMLB', - city: 'Melbourne International Airport', - state: 'FL', - lat: 28.09973, - lon: -80.6356, - }, - KMTH: { - id: 'KMTH', - city: 'The Florida Keys - Marathon International Airport', - state: 'FL', - lat: 24.72626, - lon: -81.04765, - }, - KNDZ: { - id: 'KNDZ', - city: 'Milton, Whiting Field South', - state: 'FL', - lat: 30.69722, - lon: -87.02, - }, - KNEN: { - id: 'KNEN', - city: 'WHITEHOUSE NOF', - state: 'FL', - lat: 30.35, - lon: -81.88, - }, - KNIP: { - id: 'KNIP', - city: 'Jacksonville Naval Air Station', - state: 'FL', - lat: 30.23468, - lon: -81.67462, - }, - KNPA: { - id: 'KNPA', - city: 'Pensacola Naval Air Station', - state: 'FL', - lat: 30.35641, - lon: -87.32326, - }, - KNQX: { - id: 'KNQX', - city: 'Key West Naval Air Station', - state: 'FL', - lat: 24.5800899, - lon: -81.68293, - }, - KNRB: { - id: 'KNRB', - city: 'Mayport Naval Station - Adm David L. McDonald Field', - state: 'FL', - lat: 30.39589, - lon: -81.42286, - }, - KNSE: { - id: 'KNSE', - city: 'Milton - Whiting Field Naval Air Station North', - state: 'FL', - lat: 30.72848, - lon: -87.02192, - }, - KOBE: { - id: 'KOBE', - city: 'Okeechobee County Airport', - state: 'FL', - lat: 27.2628, - lon: -80.8498, - }, - KOCF: { - id: 'KOCF', - city: 'Ocala International Airport - Jim Taylor Field', - state: 'FL', - lat: 29.16372, - lon: -82.22097, - }, - KOMN: { - id: 'KOMN', - city: 'Ormond Beach, Ormond Beach Municipal Airport', - state: 'FL', - lat: 29.30111, - lon: -81.11361, - }, - KOPF: { - id: 'KOPF', - city: 'Miami, Opa Locka Airport', - state: 'FL', - lat: 25.91, - lon: -80.28306, - }, - KORL: { - id: 'KORL', - city: 'Orlando Executive Airport', - state: 'FL', - lat: 28.54655, - lon: -81.33543, - }, - KPAM: { - id: 'KPAM', - city: 'Tyndall Air Force Base', - state: 'FL', - lat: 30.06444, - lon: -85.5637, - }, - KPBI: { - id: 'KPBI', - city: 'West Palm Beach - Palm Beach International Airport', - state: 'FL', - lat: 26.6850999, - lon: -80.0991899, - }, - KPCM: { - id: 'KPCM', - city: 'Plant City, Plant City Municipal Airport', - state: 'FL', - lat: 28, - lon: -82.15, - }, - KPGD: { - id: 'KPGD', - city: 'Punta Gorda, Charlotte County Airport', - state: 'FL', - lat: 26.91778, - lon: -81.99361, - }, - KPIE: { - id: 'KPIE', - city: 'St. Petersburg/Clearwater Airport', - state: 'FL', - lat: 27.91259, - lon: -82.68554, - }, - KPMP: { - id: 'KPMP', - city: 'Pompano Beach, Pompano Beach Airpark', - state: 'FL', - lat: 26.24556, - lon: -80.11139, - }, - KPNS: { - id: 'KPNS', - city: 'Pensacola - Pensacola International Airport', - state: 'FL', - lat: 30.47806, - lon: -87.18694, - }, - KRSW: { - id: 'KRSW', - city: 'Fort Myers, Southwest Florida International Airport', - state: 'FL', - lat: 26.52694, - lon: -81.76639, - }, - KSEF: { - id: 'KSEF', - city: 'Sebring Regional Airport', - state: 'FL', - lat: 27.45639, - lon: -81.34239, - }, - KSFB: { - id: 'KSFB', - city: 'Orlando / Sanford Airport', - state: 'FL', - lat: 28.78333, - lon: -81.25, - }, - KSGJ: { - id: 'KSGJ', - city: 'Northeast Florida Regional Airport', - state: 'FL', - lat: 29.95924, - lon: -81.34105, - }, - KSPG: { - id: 'KSPG', - city: 'Albert Whitted Airport', - state: 'FL', - lat: 27.76852, - lon: -82.62564, - }, - KSRQ: { - id: 'KSRQ', - city: 'Sarasota / Bradenton, Sarasota-Bradenton International Airport', - state: 'FL', - lat: 27.40139, - lon: -82.55861, - }, - KSUA: { - id: 'KSUA', - city: 'Witham Field Airport', - state: 'FL', - lat: 27.18157, - lon: -80.22519, - }, - KTDR: { - id: 'KTDR', - city: 'Tyndall Drone Runway', - state: 'FL', - lat: 30.0333, - lon: -85.5333, - }, - KTIX: { - id: 'KTIX', - city: 'Titusville', - state: 'FL', - lat: 28.51667, - lon: -80.8, - }, - KTLH: { - id: 'KTLH', - city: 'Tallahassee International Airport', - state: 'FL', - lat: 30.39675, - lon: -84.35087, - }, - KTMB: { - id: 'KTMB', - city: 'Miami, Kendall-Tamiami Executive Airport', - state: 'FL', - lat: 25.64194, - lon: -80.43472, - }, - KTPA: { - id: 'KTPA', - city: 'Tampa, Tampa International Airport', - state: 'FL', - lat: 27.96139, - lon: -82.54028, - }, - KTPF: { - id: 'KTPF', - city: 'Tampa, Peter O Knight Airport', - state: 'FL', - lat: 27.91556, - lon: -82.44917, - }, - KTTS: { - id: 'KTTS', - city: 'Titusville, NASA Shuttle Landing Facility', - state: 'FL', - lat: 28.61667, - lon: -80.7, - }, - KVDF: { - id: 'KVDF', - city: 'Tampa, Vandenberg Airport', - state: 'FL', - lat: 28.01983, - lon: -82.3415, - }, - KVNC: { - id: 'KVNC', - city: 'Venice Municipal Airport', - state: 'FL', - lat: 27.0716, - lon: -82.44033, - }, - KVPS: { - id: 'KVPS', - city: 'Valparaiso / Eglin Air Force Base', - state: 'FL', - lat: 30.48333, - lon: -86.51667, - }, - KVQQ: { - id: 'KVQQ', - city: 'Cecil Airport', - state: 'FL', - lat: 30.21292, - lon: -81.8707, - }, - KVRB: { - id: 'KVRB', - city: 'Vero Beach, Vero Beach Municipal Airport', - state: 'FL', - lat: 27.65556, - lon: -80.41806, - }, - KXMR: { - id: 'KXMR', - city: 'Cocoa Beach, Cape Canaveral Air Force Station Skid Strip', - state: 'FL', - lat: 28.46667, - lon: -80.56667, - }, - KZPH: { - id: 'KZPH', - city: 'Zephyrhills Airport', - state: 'FL', - lat: 28.2281, - lon: -82.1559, - }, - KABH: { - id: 'KABH', - city: 'ELLICOTT-B AFA', - state: 'CO', - lat: 38.7578, - lon: -104.3013, - }, - KAEJ: { - id: 'KAEJ', - city: 'Central Colorado Regional Airport', - state: 'CO', - lat: 38.81416, - lon: -106.12069, - }, - KAFF: { - id: 'KAFF', - city: 'Air Force Academy', - state: 'CO', - lat: 38.96667, - lon: -104.81667, - }, - KAJZ: { - id: 'KAJZ', - city: 'Delta/Blake Field Airport', - state: 'CO', - lat: 38.7868799, - lon: -108.06584, - }, - KAKO: { - id: 'KAKO', - city: 'Colorado Plains Regional Airport', - state: 'CO', - lat: 40.17428, - lon: -103.21459, - }, - KALS: { - id: 'KALS', - city: 'San Luis Valley Regional Airport', - state: 'CO', - lat: 37.43933, - lon: -105.8618, - }, - KANK: { - id: 'KANK', - city: 'Harriet Alexander Field Airport', - state: 'CO', - lat: 38.53828, - lon: -106.04864, - }, - KAPA: { - id: 'KAPA', - city: 'Denver - Centennial Airport', - state: 'CO', - lat: 39.55991, - lon: -104.84841, - }, - KASE: { - id: 'KASE', - city: 'Aspen-Pitkin County Airport', - state: 'CO', - lat: 39.22992, - lon: -106.87051, - }, - KBDU: { - id: 'KBDU', - city: 'Boulder Municipal Airport', - state: 'CO', - lat: 40.0394297, - lon: -105.2258217, - }, - KBJC: { - id: 'KBJC', - city: 'Rocky Mountain Metro', - state: 'CO', - lat: 39.90085, - lon: -105.10417, - }, - KBKF: { - id: 'KBKF', - city: 'Buckley Space Force Base', - state: 'CO', - lat: 39.71331, - lon: -104.75806, - }, - KCAG: { - id: 'KCAG', - city: 'Craig-Moffat Airport', - state: 'CO', - lat: 40.49297, - lon: -107.52394, - }, - KCCU: { - id: 'KCCU', - city: 'Copper Mountain - Red Cliff Pass', - state: 'CO', - lat: 39.47523, - lon: -106.15228, - }, - KCEZ: { - id: 'KCEZ', - city: 'Cortez-Montezuma County Airport', - state: 'CO', - lat: 37.30706, - lon: -108.62644, - }, - KCFO: { - id: 'KCFO', - city: 'Colorado Air and Space Port Airport', - state: 'CO', - lat: 39.78419, - lon: -104.53764, - }, - KCOS: { - id: 'KCOS', - city: 'City of Colorado Springs Municipal Airport', - state: 'CO', - lat: 38.8094899, - lon: -104.68873, - }, - KCPW: { - id: 'KCPW', - city: 'Pagosa Springs, Wolf Creek Pass', - state: 'CO', - lat: 37.45139, - lon: -106.80028, - }, - KCWN: { - id: 'KCWN', - city: 'Cheyenne Mountain', - state: 'CO', - lat: 38.7434299, - lon: -104.84334, - }, - KDEN: { - id: 'KDEN', - city: 'Denver, Denver International Airport', - state: 'CO', - lat: 39.84658, - lon: -104.65622, - }, - KDRO: { - id: 'KDRO', - city: 'Durango-La Plata County Airport', - state: 'CO', - lat: 37.14312, - lon: -107.76023, - }, - KEEO: { - id: 'KEEO', - city: 'Meeker Airport', - state: 'CO', - lat: 40.0444, - lon: -107.88832, - }, - KEGE: { - id: 'KEGE', - city: 'Eagle County Regional', - state: 'CO', - lat: 39.65, - lon: -106.91667, - }, - KEIK: { - id: 'KEIK', - city: 'Erie Municipal Airport', - state: 'CO', - lat: 40.01169, - lon: -105.05033, - }, - KFCS: { - id: 'KFCS', - city: 'Butts Army Airfield (Fort Carson)', - state: 'CO', - lat: 38.68312, - lon: -104.75977, - }, - KFLY: { - id: 'KFLY', - city: 'Meadow Lake Airport', - state: 'CO', - lat: 38.94391, - lon: -104.5684, - }, - KFMM: { - id: 'KFMM', - city: 'Fort Morgan Municipal Airport', - state: 'CO', - lat: 40.33148, - lon: -103.80704, - }, - KFNL: { - id: 'KFNL', - city: 'Fort Collins/Loveland - Northern Colorado Regional Airport', - state: 'CO', - lat: 40.45, - lon: -105.01667, - }, - KGJT: { - id: 'KGJT', - city: 'Grand Junction Regional Airport', - state: 'CO', - lat: 39.13389, - lon: -108.53861, - }, - KGNB: { - id: 'KGNB', - city: 'Granby-Grand County Airport', - state: 'CO', - lat: 40.09006, - lon: -105.91664, - }, - KGUC: { - id: 'KGUC', - city: 'Gunnison, Gunnison-Crested Butte Regional Airport', - state: 'CO', - lat: 38.53333, - lon: -106.93333, - }, - KGXY: { - id: 'KGXY', - city: 'Greeley, Greeley-Weld County Airport', - state: 'CO', - lat: 40.43333, - lon: -104.63333, - }, - KHEQ: { - id: 'KHEQ', - city: 'Holyoke Airport', - state: 'CO', - lat: 40.57155, - lon: -102.27676, - }, - KITR: { - id: 'KITR', - city: 'Burlington - Carson County Airport', - state: 'CO', - lat: 39.24149, - lon: -102.2818999, - }, - KLAA: { - id: 'KLAA', - city: 'Lamar Municipal Airport', - state: 'CO', - lat: 38.0717799, - lon: -102.68745, - }, - KLHX: { - id: 'KLHX', - city: 'La Junta Municipal Airport', - state: 'CO', - lat: 38.04949, - lon: -103.51334, - }, - KLIC: { - id: 'KLIC', - city: 'Limon Municipal Airport', - state: 'CO', - lat: 39.27334, - lon: -103.66738, - }, - KLMO: { - id: 'KLMO', - city: 'Vance Brand Airport', - state: 'CO', - lat: 40.16115, - lon: -105.16042, - }, - KLXV: { - id: 'KLXV', - city: 'Leadville, Lake County Airport', - state: 'CO', - lat: 39.22806, - lon: -106.31611, - }, - KMNH: { - id: 'KMNH', - city: 'Elbert Mountain - Monument Pass', - state: 'CO', - lat: 39.22317, - lon: -104.6422599, - }, - KMTJ: { - id: 'KMTJ', - city: 'Montrose, Montrose Regional Airport', - state: 'CO', - lat: 38.505, - lon: -107.8975, - }, - KMYP: { - id: 'KMYP', - city: 'Salida - Monarch Pass', - state: 'CO', - lat: 38.4972, - lon: -106.3197, - }, - KPSO: { - id: 'KPSO', - city: 'Stevens Field, Pagosa Springs', - state: 'CO', - lat: 37.2862, - lon: -107.056, - }, - KPUB: { - id: 'KPUB', - city: 'Pueblo Memorial Airport', - state: 'CO', - lat: 38.28869, - lon: -104.5057, - }, - KRCV: { - id: 'KRCV', - city: 'Astronaut Kent Rominger - Del Norte', - state: 'CO', - lat: 37.7138, - lon: -106.352, - }, - KRIL: { - id: 'KRIL', - city: 'Garfield County Regional Airport', - state: 'CO', - lat: 39.52793, - lon: -107.71961, - }, - KSBS: { - id: 'KSBS', - city: 'Steamboat Springs', - state: 'CO', - lat: 40.5153, - lon: -106.86767, - }, - KSHM: { - id: 'KSHM', - city: 'Schriever AFB', - state: 'CO', - lat: 38.8, - lon: -104.5167, - }, - KSPD: { - id: 'KSPD', - city: 'Springfield, Comanche National Grassland', - state: 'CO', - lat: 37.28333, - lon: -102.61667, - }, - KSTK: { - id: 'KSTK', - city: 'Sterling Municipal Airport', - state: 'CO', - lat: 40.61331, - lon: -103.26109, - }, - KTAD: { - id: 'KTAD', - city: 'Perry Stokes Airport', - state: 'CO', - lat: 37.26218, - lon: -104.33184, - }, - KTEX: { - id: 'KTEX', - city: 'Telluride, Telluride Regional Airport', - state: 'CO', - lat: 37.95389, - lon: -107.90861, - }, - KVTP: { - id: 'KVTP', - city: 'La Veta Mountain, La Veta Pass', - state: 'CO', - lat: 37.50111, - lon: -105.16694, - }, - PARW: { - id: 'PARW', - city: 'YAKIMA RIVER NEAR PARKER, WA.', - state: 'WA', - lat: 46.5061111, - lon: -120.4519444, - }, - QSPW: { - id: 'QSPW', - city: 'QUARTZ MTN', - state: 'WA', - lat: 47.0672222, - lon: -121.0788888, - }, - KABI: { - id: 'KABI', - city: 'Abilene, Abilene Regional Airport', - state: 'TX', - lat: 32.41028, - lon: -99.68167, - }, - KACT: { - id: 'KACT', - city: 'Waco, Waco Regional Airport', - state: 'TX', - lat: 31.61722, - lon: -97.22778, - }, - KADS: { - id: 'KADS', - city: 'Dallas / Addison Airport', - state: 'TX', - lat: 32.96667, - lon: -96.83333, - }, - KAFW: { - id: 'KAFW', - city: 'Fort Worth, Fort Worth Alliance Airport', - state: 'TX', - lat: 32.97333, - lon: -97.31806, - }, - KALI: { - id: 'KALI', - city: 'Alice, Alice International Airport', - state: 'TX', - lat: 27.74111, - lon: -98.02694, - }, - KAMA: { - id: 'KAMA', - city: 'Amarillo, Amarillo International Airport', - state: 'TX', - lat: 35.22, - lon: -101.71722, - }, - KAPY: { - id: 'KAPY', - city: 'Zapata, TX', - state: 'TX', - lat: 26.969, - lon: -99.249, - }, - KAQO: { - id: 'KAQO', - city: 'Llano, Llano Municipal Airport', - state: 'TX', - lat: 30.78361, - lon: -98.66194, - }, - KARM: { - id: 'KARM', - city: 'Wharton, Wharton Regional Airport', - state: 'TX', - lat: 29.25417, - lon: -96.1541699, - }, - KASL: { - id: 'KASL', - city: 'Marshall', - state: 'TX', - lat: 32.5205, - lon: -94.3078, - }, - KATT: { - id: 'KATT', - city: 'Austin City, Austin Camp Mabry', - state: 'TX', - lat: 30.31667, - lon: -97.76667, - }, - KAUS: { - id: 'KAUS', - city: 'Austin-Bergstrom International Airport', - state: 'TX', - lat: 30.18304, - lon: -97.6798699, - }, - KAXH: { - id: 'KAXH', - city: 'Houston Southwest Airport', - state: 'TX', - lat: 29.50613, - lon: -95.47692, - }, - KBAZ: { - id: 'KBAZ', - city: 'New Braunfels National Airport', - state: 'TX', - lat: 29.70575, - lon: -98.04322, - }, - KBBD: { - id: 'KBBD', - city: 'Brady, Curtis Field Airport', - state: 'TX', - lat: 31.17917, - lon: -99.32389, - }, - KBEA: { - id: 'KBEA', - city: 'Beeville Municipal Airport', - state: 'TX', - lat: 28.362, - lon: -97.791, - }, - KBGD: { - id: 'KBGD', - city: 'Borger, Hutchinson County Airport', - state: 'TX', - lat: 35.695, - lon: -101.395, - }, - KBIF: { - id: 'KBIF', - city: 'Biggs Army Air Field - Fort Bliss', - state: 'TX', - lat: 31.86119, - lon: -106.3691599, - }, - KBKD: { - id: 'KBKD', - city: 'Stephens County Airport', - state: 'TX', - lat: 32.719, - lon: -98.891, - }, - KBKS: { - id: 'KBKS', - city: 'Falfurrias, Brooks County Airport', - state: 'TX', - lat: 27.20667, - lon: -98.12111, - }, - KBMQ: { - id: 'KBMQ', - city: 'Burnet, Burnet Municipal Craddock Field', - state: 'TX', - lat: 30.74056, - lon: -98.23528, - }, - KBMT: { - id: 'KBMT', - city: 'Beaumont Municipal Airport', - state: 'TX', - lat: 30.0702, - lon: -94.2151, - }, - KBPC: { - id: 'KBPC', - city: 'Mesa Vista Ranch AP', - state: 'TX', - lat: 35.889, - lon: -101.03, - }, - KBPG: { - id: 'KBPG', - city: 'Big Spring, Big Spring McMahon-Wrinkle Airport', - state: 'TX', - lat: 32.2, - lon: -101.51667, - }, - KBPT: { - id: 'KBPT', - city: 'Beaumont/Port Arthur Southeast Texas Regional Airport', - state: 'TX', - lat: 29.9521, - lon: -94.0261, - }, - KBQX: { - id: 'KBQX', - city: 'BRAZOS 451 OIL PLATFORM', - state: 'TX', - lat: 28.5, - lon: -95.72, - }, - KBRO: { - id: 'KBRO', - city: 'Brownsville, Brownsville / South Padre Island International Airport', - state: 'TX', - lat: 25.91417, - lon: -97.42306, - }, - KBWD: { - id: 'KBWD', - city: 'Brownwood, Brownwood Regional Airport', - state: 'TX', - lat: 31.8, - lon: -98.95, - }, - KBYY: { - id: 'KBYY', - city: 'Bay City, Bay City Municipal Airport', - state: 'TX', - lat: 28.97306, - lon: -95.86333, - }, - KCDS: { - id: 'KCDS', - city: 'Childress, Childress Municipal Airport', - state: 'TX', - lat: 34.4275, - lon: -100.28333, - }, - KCFD: { - id: 'KCFD', - city: 'Bryan Coulter Field', - state: 'TX', - lat: 30.7157, - lon: -96.3314, - }, - KCLL: { - id: 'KCLL', - city: 'College Station, Easterwood Field', - state: 'TX', - lat: 30.58222, - lon: -96.36167, - }, - KCNW: { - id: 'KCNW', - city: 'Waco-James Connally Airport', - state: 'TX', - lat: 31.6378, - lon: -97.0741, - }, - KCOM: { - id: 'KCOM', - city: 'COLEMAN', - state: 'TX', - lat: 31.84, - lon: -99.4, - }, - KCOT: { - id: 'KCOT', - city: 'Cotulla, Cotulla-La Salle County Airport', - state: 'TX', - lat: 28.45833, - lon: -99.22028, - }, - KCPT: { - id: 'KCPT', - city: 'Cleburne, Cleburne Municipal Airport', - state: 'TX', - lat: 32.35361, - lon: -97.43361, - }, - KCRP: { - id: 'KCRP', - city: 'Corpus Christi, Corpus Christi International Airport', - state: 'TX', - lat: 27.77306, - lon: -97.51278, - }, - KCRS: { - id: 'KCRS', - city: 'Corsicana, Campbell Field-Corsicana Municipal Airport', - state: 'TX', - lat: 32.03111, - lon: -96.39889, - }, - KCVB: { - id: 'KCVB', - city: 'Castroville Municipal Airport', - state: 'TX', - lat: 29.34192, - lon: -98.8509, - }, - KCWC: { - id: 'KCWC', - city: 'Kickapoo Downtown Airport', - state: 'TX', - lat: 33.8606, - lon: -98.4903999, - }, - KCXO: { - id: 'KCXO', - city: 'Conroe, Montgomery County Airport', - state: 'TX', - lat: 30.35667, - lon: -95.41389, - }, - KCZT: { - id: 'KCZT', - city: 'Carrizo Springs Dimmit County Airport', - state: 'TX', - lat: 28.5222, - lon: -99.8236, - }, - KDAL: { - id: 'KDAL', - city: 'Dallas Love Field', - state: 'TX', - lat: 32.85416, - lon: -96.85506, - }, - KDFW: { - id: 'KDFW', - city: 'Dallas/Fort Worth International Airport', - state: 'TX', - lat: 32.89743, - lon: -97.02196, - }, - KDHT: { - id: 'KDHT', - city: 'Dalhart, Dalhart Municipal Airport', - state: 'TX', - lat: 36.02333, - lon: -102.54722, - }, - KDKR: { - id: 'KDKR', - city: 'Crockett, Houston County Airport', - state: 'TX', - lat: 31.30694, - lon: -95.40361, - }, - KDLF: { - id: 'KDLF', - city: 'Laughlin Air Force Base Auxiliary Airfield', - state: 'TX', - lat: 29.36652, - lon: -100.78469, - }, - KDRT: { - id: 'KDRT', - city: 'Del Rio, Del Rio International Airport', - state: 'TX', - lat: 29.37472, - lon: -100.92361, - }, - KDTO: { - id: 'KDTO', - city: 'Denton Enterprise Airport', - state: 'TX', - lat: 33.20505, - lon: -97.20061, - }, - KDUX: { - id: 'KDUX', - city: 'Dumas, Moore County Airport', - state: 'TX', - lat: 35.85778, - lon: -102.01306, - }, - KDWH: { - id: 'KDWH', - city: 'Houston, Hooks Memorial Airport', - state: 'TX', - lat: 30.0675, - lon: -95.55611, - }, - KDYS: { - id: 'KDYS', - city: 'Abilene, Dyess Air Force Base', - state: 'TX', - lat: 32.42, - lon: -99.85694, - }, - KDZB: { - id: 'KDZB', - city: 'Horseshoe Bay Resort Airpark', - state: 'TX', - lat: 30.5271, - lon: -98.3588, - }, - KEBG: { - id: 'KEBG', - city: 'Edinburg, Edinburg International Airport', - state: 'TX', - lat: 26.44194, - lon: -98.12944, - }, - KECU: { - id: 'KECU', - city: 'Rocksprings, Edwards County Airport', - state: 'TX', - lat: 29.94667, - lon: -100.17361, - }, - KEDC: { - id: 'KEDC', - city: 'Austin Executive Airport', - state: 'TX', - lat: 30.3925, - lon: -97.5621, - }, - KEFD: { - id: 'KEFD', - city: 'Houston / Ellington', - state: 'TX', - lat: 29.6, - lon: -95.16667, - }, - KELA: { - id: 'KELA', - city: 'Eagle Lake', - state: 'TX', - lat: 29.6006, - lon: -96.3219, - }, - KELP: { - id: 'KELP', - city: 'El Paso, El Paso International Airport', - state: 'TX', - lat: 31.81111, - lon: -106.3758299, - }, - KERV: { - id: 'KERV', - city: 'Kerrville, Kerrville Municipal Airport/Louis Schreiner Field', - state: 'TX', - lat: 29.96667, - lon: -99.08333, - }, - KETN: { - id: 'KETN', - city: 'Eastland Municipal Airport', - state: 'TX', - lat: 32.41489, - lon: -98.80969, - }, - KFST: { - id: 'KFST', - city: 'Fort Stockton, Fort Stockton-Pecos County Airport', - state: 'TX', - lat: 30.91194, - lon: -102.91667, - }, - KFTN: { - id: 'KFTN', - city: 'Faith Ranch Airport', - state: 'TX', - lat: 28.2086, - lon: -100.0188, - }, - KFTW: { - id: 'KFTW', - city: 'Fort Worth, Meacham International Airport', - state: 'TX', - lat: 32.82528, - lon: -97.36417, - }, - KFWS: { - id: 'KFWS', - city: 'Fort Worth Spinks Airport', - state: 'TX', - lat: 32.56537, - lon: -97.30837, - }, - KGDJ: { - id: 'KGDJ', - city: 'Granbury, Granbury Municipal Airport', - state: 'TX', - lat: 32.44417, - lon: -97.81667, - }, - KGGG: { - id: 'KGGG', - city: 'Longview - East Texas Regional Airport', - state: 'TX', - lat: 32.39056, - lon: -94.71389, - }, - KGKY: { - id: 'KGKY', - city: 'Arlington Municipal Airport', - state: 'TX', - lat: 32.65829, - lon: -97.09509, - }, - KGLS: { - id: 'KGLS', - city: 'Galveston, Scholes Field', - state: 'TX', - lat: 29.27028, - lon: -94.86417, - }, - KGNC: { - id: 'KGNC', - city: 'Seminole, Gaines County Airport', - state: 'TX', - lat: 32.67528, - lon: -102.6525, - }, - KGOP: { - id: 'KGOP', - city: 'Gatesville, City-County Airport', - state: 'TX', - lat: 31.42111, - lon: -97.79694, - }, - KGPM: { - id: 'KGPM', - city: 'Grand Prairie, Grand Prairie Municipal Airport', - state: 'TX', - lat: 32.69861, - lon: -97.04667, - }, - KGRK: { - id: 'KGRK', - city: 'Fort Hood, Robert Gray AAF Ft Hood', - state: 'TX', - lat: 31.06667, - lon: -97.81667, - }, - KGTU: { - id: 'KGTU', - city: 'Georgetown, Georgetown Municipal Airport', - state: 'TX', - lat: 30.68333, - lon: -97.68333, - }, - KGUL: { - id: 'KGUL', - city: 'GUNNISON OIL PLATFORM', - state: 'TX', - lat: 27.3, - lon: -93.53, - }, - KGVT: { - id: 'KGVT', - city: 'Greenville / Majors', - state: 'TX', - lat: 33.06667, - lon: -96.06667, - }, - KGVW: { - id: 'KGVW', - city: 'Galveston 209A', - state: 'TX', - lat: 29.13, - lon: -94.55, - }, - KGYB: { - id: 'KGYB', - city: 'Giddings, Giddings-Lee County Airport', - state: 'TX', - lat: 30.16917, - lon: -96.98, - }, - KGYI: { - id: 'KGYI', - city: 'Sherman/Denison, Grayson County Airport', - state: 'TX', - lat: 33.71667, - lon: -96.66667, - }, - KGZN: { - id: 'KGZN', - city: 'Gregory M Simmons Memorial Airport', - state: 'TX', - lat: 32.3658, - lon: -99.0237, - }, - KHDO: { - id: 'KHDO', - city: 'Hondo, Hondo Municipal Airport', - state: 'TX', - lat: 29.35944, - lon: -99.17417, - }, - KHHF: { - id: 'KHHF', - city: 'Canadian, Hemphill County Airport', - state: 'TX', - lat: 35.9, - lon: -100.4, - }, - KHHV: { - id: 'KHHV', - city: 'Alaminos Canyon 25/H-D (ExxonMobil)', - state: 'TX', - lat: 26.939, - lon: -94.6889999, - }, - KHLR: { - id: 'KHLR', - city: 'Fort Hood, Hood AAF Ft Hood', - state: 'TX', - lat: 31.13333, - lon: -97.7, - }, - KHOU: { - id: 'KHOU', - city: 'Houston, Houston Hobby Airport', - state: 'TX', - lat: 29.6375, - lon: -95.2825, - }, - KHQZ: { - id: 'KHQZ', - city: 'Mesquite, Mesquite Metro Airport', - state: 'TX', - lat: 32.74694, - lon: -96.53028, - }, - KHRL: { - id: 'KHRL', - city: 'Harlingen, Rio Grande Valley International Airport', - state: 'TX', - lat: 26.22972, - lon: -97.65528, - }, - KHRX: { - id: 'KHRX', - city: 'Hereford Municipal Airport', - state: 'TX', - lat: 34.8578, - lon: -102.3264, - }, - KHYI: { - id: 'KHYI', - city: 'San Marcos, San Marcos Municipal Airport', - state: 'TX', - lat: 29.89361, - lon: -97.86472, - }, - KIAH: { - id: 'KIAH', - city: 'Houston Intercontinental Airport', - state: 'TX', - lat: 29.9844, - lon: -95.36074, - }, - KIKG: { - id: 'KIKG', - city: 'Kleberg County Airport', - state: 'TX', - lat: 27.5509, - lon: -98.0309, - }, - KILE: { - id: 'KILE', - city: 'Killeen, Skylark Field Airport', - state: 'TX', - lat: 31.08333, - lon: -97.68333, - }, - KINJ: { - id: 'KINJ', - city: 'Hillsboro, Hillsboro Municipal Airport', - state: 'TX', - lat: 32.0833299, - lon: -97.0972199, - }, - KINK: { - id: 'KINK', - city: 'Wink, Winkler County Airport', - state: 'TX', - lat: 31.77972, - lon: -103.20139, - }, - KJAS: { - id: 'KJAS', - city: 'Jasper, Jasper County-Bell Field Airport', - state: 'TX', - lat: 30.88556, - lon: -94.0347199, - }, - KJCT: { - id: 'KJCT', - city: 'Junction, Kimble County Airport', - state: 'TX', - lat: 30.51083, - lon: -99.76639, - }, - KJDD: { - id: 'KJDD', - city: 'Mineola/Quitman, Wood County Airport', - state: 'TX', - lat: 32.74194, - lon: -95.49639, - }, - KJSO: { - id: 'KJSO', - city: 'Jacksonville, Cherokee County Airport', - state: 'TX', - lat: 31.86917, - lon: -95.21722, - }, - KJWY: { - id: 'KJWY', - city: 'Midlothian/Waxahachie, Mid-Way Regional Airport', - state: 'TX', - lat: 32.45583, - lon: -96.91222, - }, - KJXI: { - id: 'KJXI', - city: 'Gilmer, Fox Stephens Field - Gilmer Municipal Airport', - state: 'TX', - lat: 32.69889, - lon: -94.94861, - }, - KLBB: { - id: 'KLBB', - city: 'Lubbock, Lubbock International Airport', - state: 'TX', - lat: 33.6674999, - lon: -101.8213899, - }, - KLFK: { - id: 'KLFK', - city: 'Lufkin, Angelina County Airport', - state: 'TX', - lat: 31.23389, - lon: -94.75, - }, - KLHB: { - id: 'KLHB', - city: 'Hearne, Hearne Municipal Airport', - state: 'TX', - lat: 30.87167, - lon: -96.62222, - }, - KLLN: { - id: 'KLLN', - city: 'Levelland Municipal Airport', - state: 'TX', - lat: 33.55253, - lon: -102.37253, - }, - KLNC: { - id: 'KLNC', - city: 'Lancaster Airport', - state: 'TX', - lat: 32.58323, - lon: -96.72091, - }, - KLRD: { - id: 'KLRD', - city: 'Laredo, Laredo International Airport', - state: 'TX', - lat: 27.54361, - lon: -99.46139, - }, - KLUD: { - id: 'KLUD', - city: 'Decatur, Decatur Municipal Airport', - state: 'TX', - lat: 33.25444, - lon: -97.58056, - }, - KLUV: { - id: 'KLUV', - city: 'Lamesa Municipal Airport', - state: 'TX', - lat: 32.75631, - lon: -101.92022, - }, - KLVJ: { - id: 'KLVJ', - city: 'Houston, Pearland Regional Airport', - state: 'TX', - lat: 29.52111, - lon: -95.24194, - }, - KLXY: { - id: 'KLXY', - city: 'Mexia Limestone County Airport', - state: 'TX', - lat: 31.6412, - lon: -96.5145, - }, - KMAF: { - id: 'KMAF', - city: 'Midland, Midland International Airport', - state: 'TX', - lat: 31.94778, - lon: -102.2086099, - }, - KMCJ: { - id: 'KMCJ', - city: 'John Dunn Helistop', - state: 'TX', - lat: 29.714, - lon: -95.395, - }, - KMDD: { - id: 'KMDD', - city: 'Midland, Midland Airpark', - state: 'TX', - lat: 32.03639, - lon: -102.10083, - }, - KMFE: { - id: 'KMFE', - city: 'McAllen, Miller International Airport', - state: 'TX', - lat: 26.17972, - lon: -98.24444, - }, - KMKN: { - id: 'KMKN', - city: 'Comanche, Comanche County-City Airport', - state: 'TX', - lat: 31.91667, - lon: -98.60028, - }, - KMNZ: { - id: 'KMNZ', - city: 'Hamilton Municipal Airport', - state: 'TX', - lat: 31.6659, - lon: -98.1486, - }, - KMWL: { - id: 'KMWL', - city: 'Mineral Wells, Mineral Wells Airport', - state: 'TX', - lat: 32.78167, - lon: -98.06028, - }, - KNFW: { - id: 'KNFW', - city: 'Fort Worth, Naval Air Station', - state: 'TX', - lat: 32.76583, - lon: -97.43333, - }, - KNGP: { - id: 'KNGP', - city: 'Corpus Christi, Corpus Christi Naval Air Station/Truax Field', - state: 'TX', - lat: 27.6925, - lon: -97.29111, - }, - KNOG: { - id: 'KNOG', - city: 'Orange Grove NALF', - state: 'TX', - lat: 27.8947, - lon: -98.0425099, - }, - KNQI: { - id: 'KNQI', - city: 'Kingsville, Naval Air Station', - state: 'TX', - lat: 27.50306, - lon: -97.81167, - }, - KOCH: { - id: 'KOCH', - city: 'Nacogdoches, A L Mangham Jr. Regional Airport', - state: 'TX', - lat: 31.58333, - lon: -94.7166699, - }, - KODO: { - id: 'KODO', - city: 'Odessa, Odessa-Schlemeyer Field', - state: 'TX', - lat: 31.92139, - lon: -102.39167, - }, - KORG: { - id: 'KORG', - city: 'Orange, Orange County Airport', - state: 'TX', - lat: 30.06917, - lon: -93.80361, - }, - KOSA: { - id: 'KOSA', - city: 'Mount Pleasant, Mount Pleasant Regional Airport', - state: 'TX', - lat: 33.09528, - lon: -94.96139, - }, - KOZA: { - id: 'KOZA', - city: 'Ozona Municipal Airport', - state: 'TX', - lat: 30.7353, - lon: -101.203, - }, - KPEZ: { - id: 'KPEZ', - city: 'Pleasanton Municipal Airport', - state: 'TX', - lat: 28.9562, - lon: -98.5184, - }, - KPIL: { - id: 'KPIL', - city: 'Port Isabel, Port Isabel-Cameron County Airport', - state: 'TX', - lat: 26.15917, - lon: -97.3375, - }, - KPKV: { - id: 'KPKV', - city: 'Port Lavaca - Calhoun County Airport', - state: 'TX', - lat: 28.65159, - lon: -96.68196, - }, - KPPA: { - id: 'KPPA', - city: 'Pampa, Perry Lefors Field Airport', - state: 'TX', - lat: 35.61278, - lon: -100.99611, - }, - KPRS: { - id: 'KPRS', - city: 'Presidio Lely International Airport', - state: 'TX', - lat: 29.6341, - lon: -104.3616, - }, - KPRX: { - id: 'KPRX', - city: 'Paris / Cox Field', - state: 'TX', - lat: 33.63333, - lon: -95.45, - }, - KPSN: { - id: 'KPSN', - city: 'Palestine, Palestine Municipal Airport', - state: 'TX', - lat: 31.77944, - lon: -95.70611, - }, - KPVW: { - id: 'KPVW', - city: 'Plainview, Hale County Airport', - state: 'TX', - lat: 34.1680599, - lon: -101.71722, - }, - KPWG: { - id: 'KPWG', - city: 'Waco, Mc Gregor Executive Airport', - state: 'TX', - lat: 31.48333, - lon: -97.31667, - }, - KPYX: { - id: 'KPYX', - city: 'Perryton, Perryton Ochiltree County Airport', - state: 'TX', - lat: 36.4, - lon: -100.73333, - }, - KRAS: { - id: 'KRAS', - city: 'Port Aransas, Mustang Beach Airport', - state: 'TX', - lat: 27.81167, - lon: -97.08861, - }, - KRBD: { - id: 'KRBD', - city: 'Dallas, Redbird Airport', - state: 'TX', - lat: 32.67583, - lon: -96.86389, - }, - KRBO: { - id: 'KRBO', - city: 'Robstown, Nueces County Airport', - state: 'TX', - lat: 27.77833, - lon: -97.69028, - }, - KRFI: { - id: 'KRFI', - city: 'Rusk County Airport', - state: 'TX', - lat: 32.1417, - lon: -94.8516999, - }, - KRKP: { - id: 'KRKP', - city: 'Rockport Aransas County Airport', - state: 'TX', - lat: 28.08371, - lon: -97.04664, - }, - KRND: { - id: 'KRND', - city: 'Randolph Air Force Base', - state: 'TX', - lat: 29.53333, - lon: -98.28333, - }, - KRPH: { - id: 'KRPH', - city: 'Graham, Graham Municipal Airport', - state: 'TX', - lat: 33.11, - lon: -98.55528, - }, - KRWV: { - id: 'KRWV', - city: 'Caldwell, Caldwell Municipal Airport', - state: 'TX', - lat: 30.51528, - lon: -96.70389, - }, - KRYW: { - id: 'KRYW', - city: 'Lago Vista TX, Rusty Allen Airport', - state: 'TX', - lat: 30.4967, - lon: -97.9659, - }, - KSAT: { - id: 'KSAT', - city: 'San Antonio, San Antonio International Airport', - state: 'TX', - lat: 29.53278, - lon: -98.46361, - }, - KSEP: { - id: 'KSEP', - city: 'Stephenville, Clark Field Municipal Airport', - state: 'TX', - lat: 32.21667, - lon: -98.18333, - }, - KSEQ: { - id: 'KSEQ', - city: 'Seguin - Randolph AFB Auxiliary Field', - state: 'TX', - lat: 29.56579, - lon: -97.90834, - }, - KSGR: { - id: 'KSGR', - city: 'Houston, Sugar Land Municipal / Hull Field Airport', - state: 'TX', - lat: 29.62222, - lon: -95.65667, - }, - KSHP: { - id: 'KSHP', - city: 'Sheppard Air Force Base', - state: 'TX', - lat: 33.96667, - lon: -98.48333, - }, - KSJT: { - id: 'KSJT', - city: 'San Angelo, Mathis Field', - state: 'TX', - lat: 31.35139, - lon: -100.4938899, - }, - KSKF: { - id: 'KSKF', - city: 'San Antonio - Kelly Field', - state: 'TX', - lat: 29.38333, - lon: -98.58333, - }, - KSLR: { - id: 'KSLR', - city: 'Sulphur Springs, Sulphur Springs Municipal Airport', - state: 'TX', - lat: 33.16111, - lon: -95.62111, - }, - KSNK: { - id: 'KSNK', - city: 'Snyder, Winston Field Airport', - state: 'TX', - lat: 32.69333, - lon: -100.95028, - }, - KSOA: { - id: 'KSOA', - city: 'Sonora, Sonora Municipal Airport', - state: 'TX', - lat: 30.58556, - lon: -100.64833, - }, - KSPS: { - id: 'KSPS', - city: 'Wichita Falls, Sheppard Air Force Base', - state: 'TX', - lat: 33.97861, - lon: -98.49278, - }, - KSSF: { - id: 'KSSF', - city: 'San Antonio, Stinson Municipal Airport', - state: 'TX', - lat: 29.33889, - lon: -98.47167, - }, - KSWW: { - id: 'KSWW', - city: 'Sweetwater, Avenger Field Airport', - state: 'TX', - lat: 32.46722, - lon: -100.46639, - }, - KTFP: { - id: 'KTFP', - city: 'Mc Campbell', - state: 'TX', - lat: 27.913, - lon: -97.2115, - }, - KTKI: { - id: 'KTKI', - city: 'McKinney - McKinney National Airport', - state: 'TX', - lat: 33.17778, - lon: -96.59028, - }, - KTME: { - id: 'KTME', - city: 'Houston Executive Airport', - state: 'TX', - lat: 29.80717, - lon: -95.89791, - }, - KTPL: { - id: 'KTPL', - city: 'Temple, Draughon-Miller Central Texas Regional Airport', - state: 'TX', - lat: 31.15, - lon: -97.4, - }, - KTRL: { - id: 'KTRL', - city: 'Terrell, Terrell Municipal Airport', - state: 'TX', - lat: 32.71361, - lon: -96.26833, - }, - KTXW: { - id: 'KTXW', - city: 'Mid Valley Airport', - state: 'TX', - lat: 26.17871, - lon: -97.97401, - }, - KTYR: { - id: 'KTYR', - city: 'Tyler, Tyler Pounds Field', - state: 'TX', - lat: 32.35861, - lon: -95.40389, - }, - KUTS: { - id: 'KUTS', - city: 'Huntsville, Huntsville Municipal Airport', - state: 'TX', - lat: 30.74389, - lon: -95.58611, - }, - KUVA: { - id: 'KUVA', - city: 'Uvalde, Garner Field Airport', - state: 'TX', - lat: 29.21111, - lon: -99.74333, - }, - KVAF: { - id: 'KVAF', - city: 'East Breaks 643/Boomvang Spar', - state: 'TX', - lat: 27.354, - lon: -94.625, - }, - KVCT: { - id: 'KVCT', - city: 'Victoria, Victoria Regional Airport', - state: 'TX', - lat: 28.8625, - lon: -96.92972, - }, - KVHN: { - id: 'KVHN', - city: 'Culberson County Airport', - state: 'TX', - lat: 31.05783, - lon: -104.78381, - }, - KXBP: { - id: 'KXBP', - city: 'Bridgeport, Bridgeport Municipal Airport', - state: 'TX', - lat: 33.17528, - lon: -97.8283299, - }, - KAST: { - id: 'KAST', - city: 'Astoria, Astoria Regional Airport', - state: 'OR', - lat: 46.15694, - lon: -123.8825, - }, - KBDN: { - id: 'KBDN', - city: 'Bend Airport AWOS', - state: 'OR', - lat: 44.0948, - lon: -121.2006, - }, - KBKE: { - id: 'KBKE', - city: 'Baker Municipal Airport', - state: 'OR', - lat: 44.84302, - lon: -117.80987, - }, - KBNO: { - id: 'KBNO', - city: 'Burns Municipal Airport', - state: 'OR', - lat: 43.59488, - lon: -118.95791, - }, - KBOK: { - id: 'KBOK', - city: 'Brookings, Brookings Airport', - state: 'OR', - lat: 42.07444, - lon: -124.29, - }, - KCVO: { - id: 'KCVO', - city: 'Corvallis, Corvallis Municipal Airport', - state: 'OR', - lat: 44.5, - lon: -123.28333, - }, - KEUG: { - id: 'KEUG', - city: 'Eugene, Mahlon Sweet Field', - state: 'OR', - lat: 44.13333, - lon: -123.21444, - }, - KGCD: { - id: 'KGCD', - city: 'Grant County Regional Airport', - state: 'OR', - lat: 44.40287, - lon: -118.96715, - }, - KHIO: { - id: 'KHIO', - city: 'Portland-Hillsboro Airport', - state: 'OR', - lat: 45.54765, - lon: -122.95568, - }, - KHRI: { - id: 'KHRI', - city: 'Hermiston, Hermiston Municipal Airport', - state: 'OR', - lat: 45.82583, - lon: -119.26111, - }, - KJSY: { - id: 'KJSY', - city: 'Joseph State Airport AWOS', - state: 'OR', - lat: 45.355889, - lon: -117.254083, - }, - KLGD: { - id: 'KLGD', - city: 'La Grande/Union County Airport', - state: 'OR', - lat: 45.29066, - lon: -118.00884, - }, - KLKV: { - id: 'KLKV', - city: 'Lake County Airport', - state: 'OR', - lat: 42.15664, - lon: -120.39721, - }, - KLMT: { - id: 'KLMT', - city: 'Klamath Falls International Airport', - state: 'OR', - lat: 42.14703, - lon: -121.72548, - }, - KMEH: { - id: 'KMEH', - city: 'Meacham', - state: 'OR', - lat: 45.51176, - lon: -118.42466, - }, - KMFR: { - id: 'KMFR', - city: 'Rogue Valley International Airport', - state: 'OR', - lat: 42.37503, - lon: -122.87696, - }, - KMMV: { - id: 'KMMV', - city: 'McMinnville, McMinnville Municipal Airport', - state: 'OR', - lat: 45.19611, - lon: -123.13222, - }, - KONO: { - id: 'KONO', - city: 'Ontario Municipal Airport', - state: 'OR', - lat: 44.01424, - lon: -117.00808, - }, - KONP: { - id: 'KONP', - city: 'Newport, Newport Municipal Airport', - state: 'OR', - lat: 44.58028, - lon: -124.05806, - }, - KOTH: { - id: 'KOTH', - city: 'Southwest Oregon Regional Airport', - state: 'OR', - lat: 43.41948, - lon: -124.2437, - }, - KPDT: { - id: 'KPDT', - city: 'Eastern Oregon Regional Airport at Pendleton', - state: 'OR', - lat: 45.69757, - lon: -118.83444, - }, - KPDX: { - id: 'KPDX', - city: 'Portland, Portland International Airport', - state: 'OR', - lat: 45.59578, - lon: -122.60917, - }, - KRBG: { - id: 'KRBG', - city: 'Roseburg Regional Airport', - state: 'OR', - lat: 43.23368, - lon: -123.3577, - }, - KRDM: { - id: 'KRDM', - city: 'Redmond Roberts Field', - state: 'OR', - lat: 44.25588, - lon: -121.14059, - }, - KREO: { - id: 'KREO', - city: 'Rome State Airport', - state: 'OR', - lat: 42.57766, - lon: -117.88543, - }, - KSLE: { - id: 'KSLE', - city: 'Salem - McNary Field', - state: 'OR', - lat: 44.90493, - lon: -123.00096, - }, - KSPB: { - id: 'KSPB', - city: 'Scappoose Industrial Airpark', - state: 'OR', - lat: 45.7691, - lon: -122.86365, - }, - KSXT: { - id: 'KSXT', - city: 'Sexton Summit', - state: 'OR', - lat: 42.6, - lon: -123.3656, - }, - KTMK: { - id: 'KTMK', - city: 'Tillamook, Tillamook Airport', - state: 'OR', - lat: 45.4180599, - lon: -123.81444, - }, - KTTD: { - id: 'KTTD', - city: 'Portland, Portland-Troutdale Airport', - state: 'OR', - lat: 45.55111, - lon: -122.40889, - }, - KUAO: { - id: 'KUAO', - city: 'Aurora State Airport', - state: 'OR', - lat: 45.24658, - lon: -122.77095, - }, - KAAT: { - id: 'KAAT', - city: 'Alturas', - state: 'CA', - lat: 41.48362, - lon: -120.5615, - }, - KACV: { - id: 'KACV', - city: 'Arcata / Eureka, Arcata Airport', - state: 'CA', - lat: 40.97806, - lon: -124.10861, - }, - KAJO: { - id: 'KAJO', - city: 'Corona Airport', - state: 'CA', - lat: 33.8977, - lon: -117.6024, - }, - KAPC: { - id: 'KAPC', - city: 'Napa, Napa County Airport', - state: 'CA', - lat: 38.2075, - lon: -122.27944, - }, - KAPV: { - id: 'KAPV', - city: 'APPLEVALLEY', - state: 'CA', - lat: 34.57533, - lon: -117.18619, - }, - KAUN: { - id: 'KAUN', - city: 'Auburn Municipal Airport', - state: 'CA', - lat: 38.95535, - lon: -121.08636, - }, - KAVX: { - id: 'KAVX', - city: 'Avalon Catalina Airport', - state: 'CA', - lat: 33.40421, - lon: -118.41456, - }, - KBAB: { - id: 'KBAB', - city: 'Marysville, Beale Air Force Base', - state: 'CA', - lat: 39.13333, - lon: -121.43333, - }, - KBAN: { - id: 'KBAN', - city: 'MCMWTC BRIDGEPORT', - state: 'CA', - lat: 38.3557, - lon: -119.5188, - }, - KBFL: { - id: 'KBFL', - city: 'Bakersfield, Meadows Field Airport', - state: 'CA', - lat: 35.43361, - lon: -119.05667, - }, - KBIH: { - id: 'KBIH', - city: 'Bishop, Bishop Airport', - state: 'CA', - lat: 37.37111, - lon: -118.35806, - }, - KBLH: { - id: 'KBLH', - city: 'Blythe, Blythe Airport', - state: 'CA', - lat: 33.6191699, - lon: -114.71694, - }, - KBLU: { - id: 'KBLU', - city: 'Emigrant Gap, Blue Canyon Nyack Airport', - state: 'CA', - lat: 39.27611, - lon: -120.70806, - }, - KBUR: { - id: 'KBUR', - city: 'Burbank - Bob Hope Airport', - state: 'CA', - lat: 34.19967, - lon: -118.36538, - }, - KBYS: { - id: 'KBYS', - city: 'Fort Irwin/Barstow, Bicycle Lake Army Airfield', - state: 'CA', - lat: 35.28333, - lon: -116.61667, - }, - KCCB: { - id: 'KCCB', - city: 'Cable Airport', - state: 'CA', - lat: 34.11161, - lon: -117.68739, - }, - KCCR: { - id: 'KCCR', - city: 'Concord, Buchanan Field', - state: 'CA', - lat: 37.99167, - lon: -122.05194, - }, - KCEC: { - id: 'KCEC', - city: 'Crescent City, Jack McNamara Field Airport', - state: 'CA', - lat: 41.78028, - lon: -124.23667, - }, - KCIC: { - id: 'KCIC', - city: 'Chico Municipal Airport', - state: 'CA', - lat: 39.7987899, - lon: -121.85795, - }, - KCMA: { - id: 'KCMA', - city: 'Camarillo, Camarillo Airport', - state: 'CA', - lat: 34.21667, - lon: -119.08333, - }, - KCNO: { - id: 'KCNO', - city: 'Chino, Chino Airport', - state: 'CA', - lat: 33.97556, - lon: -117.62361, - }, - KCPU: { - id: 'KCPU', - city: 'San Andreas Calaveras County Airport', - state: 'CA', - lat: 38.1460999, - lon: -120.6482, - }, - KCRQ: { - id: 'KCRQ', - city: 'Carlsbad, McClellan-Palomar Airport', - state: 'CA', - lat: 33.13, - lon: -117.27583, - }, - KCVH: { - id: 'KCVH', - city: 'Hollister, CA', - state: 'CA', - lat: 36.8933, - lon: -121.4103, - }, - KDAG: { - id: 'KDAG', - city: 'Daggett, Barstow-Daggett Airport', - state: 'CA', - lat: 34.85361, - lon: -116.78667, - }, - KDLO: { - id: 'KDLO', - city: 'Delano Municipal Airport', - state: 'CA', - lat: 35.74556, - lon: -119.2365, - }, - KDVO: { - id: 'KDVO', - city: 'Novato / Gnoss Field', - state: 'CA', - lat: 38.14178, - lon: -122.55463, - }, - KDWA: { - id: 'KDWA', - city: 'Yolo County Airport', - state: 'CA', - lat: 38.5793899, - lon: -121.85694, - }, - KEDU: { - id: 'KEDU', - city: 'University Airport', - state: 'CA', - lat: 38.5315, - lon: -121.7865, - }, - KEDW: { - id: 'KEDW', - city: 'Edwards Air Force Base', - state: 'CA', - lat: 34.918, - lon: -117.879, - }, - KEED: { - id: 'KEED', - city: 'Needles, Needles Airport', - state: 'CA', - lat: 34.76611, - lon: -114.62333, - }, - KEMT: { - id: 'KEMT', - city: 'El Monte', - state: 'CA', - lat: 34.0833299, - lon: -118.03333, - }, - KFAT: { - id: 'KFAT', - city: 'Fresno, Fresno Air Terminal', - state: 'CA', - lat: 36.78, - lon: -119.71944, - }, - KFOT: { - id: 'KFOT', - city: 'Fortuna Rohnerville Airport', - state: 'CA', - lat: 40.55296, - lon: -124.13338, - }, - KFUL: { - id: 'KFUL', - city: 'Fullerton, Fullerton Municipal Airport', - state: 'CA', - lat: 33.87194, - lon: -117.98472, - }, - KGOO: { - id: 'KGOO', - city: 'Nevada County Air Park', - state: 'CA', - lat: 39.2240279, - lon: -121.003083, - }, - KHAF: { - id: 'KHAF', - city: 'Half Moon Bay Airport', - state: 'CA', - lat: 37.5135999, - lon: -122.4996, - }, - KHHR: { - id: 'KHHR', - city: 'Hawthorne, Hawthorne Municipal Airport', - state: 'CA', - lat: 33.9236099, - lon: -118.33194, - }, - KHJO: { - id: 'KHJO', - city: 'Hanford Municipal Airport', - state: 'CA', - lat: 36.31145, - lon: -119.62315, - }, - KHMT: { - id: 'KHMT', - city: 'Hemet-Ryan Airport', - state: 'CA', - lat: 33.73403, - lon: -117.02231, - }, - KHWD: { - id: 'KHWD', - city: 'Hayward, Hayward Air Terminal', - state: 'CA', - lat: 37.66083, - lon: -122.11833, - }, - KIPL: { - id: 'KIPL', - city: 'Imperial, Imperial County Airport', - state: 'CA', - lat: 32.83417, - lon: -115.57861, - }, - KIZA: { - id: 'KIZA', - city: 'Santa Ynez, Santa Ynez Airport', - state: 'CA', - lat: 34.60694, - lon: -120.07556, - }, - KJAQ: { - id: 'KJAQ', - city: 'Westover Field - Amador County Airport', - state: 'CA', - lat: 38.3768, - lon: -120.79391, - }, - KLAX: { - id: 'KLAX', - city: 'Los Angeles, Los Angeles International Airport', - state: 'CA', - lat: 33.93806, - lon: -118.38889, - }, - KLGB: { - id: 'KLGB', - city: 'Long Beach, Long Beach Airport', - state: 'CA', - lat: 33.81167, - lon: -118.14639, - }, - KLHM: { - id: 'KLHM', - city: 'Lincoln Regional Karl Harder Field', - state: 'CA', - lat: 38.9092, - lon: -121.3513, - }, - KLPC: { - id: 'KLPC', - city: 'Lompoc, Lompoc Airport', - state: 'CA', - lat: 34.66667, - lon: -120.46667, - }, - KLVK: { - id: 'KLVK', - city: 'Livermore, Livermore Municipal Airport', - state: 'CA', - lat: 37.69278, - lon: -121.81444, - }, - KMAE: { - id: 'KMAE', - city: 'Madera Municipal Airport', - state: 'CA', - lat: 36.9851, - lon: -120.11064, - }, - KMCC: { - id: 'KMCC', - city: 'Sacramento, McClellan Airfield Airport', - state: 'CA', - lat: 38.66667, - lon: -121.4, - }, - KMCE: { - id: 'KMCE', - city: 'Merced Regional Airport', - state: 'CA', - lat: 37.28306, - lon: -120.50778, - }, - KMHR: { - id: 'KMHR', - city: 'Sacramento Mather Airport', - state: 'CA', - lat: 38.5599599, - lon: -121.28397, - }, - KMHS: { - id: 'KMHS', - city: 'Mount Shasta', - state: 'CA', - lat: 41.31494, - lon: -122.31702, - }, - KMHV: { - id: 'KMHV', - city: 'Mojave', - state: 'CA', - lat: 35.06667, - lon: -118.15, - }, - KMMH: { - id: 'KMMH', - city: 'Mammoth Yosemite Airport', - state: 'CA', - lat: 37.6241, - lon: -118.8423, - }, - KMOD: { - id: 'KMOD', - city: 'Modesto City-County Airport - Harry Sham Field', - state: 'CA', - lat: 37.62549, - lon: -120.9549, - }, - KMRY: { - id: 'KMRY', - city: 'Monterey Regional Airport', - state: 'CA', - lat: 36.59047, - lon: -121.84875, - }, - KMWS: { - id: 'KMWS', - city: 'MOUNT WILSON', - state: 'CA', - lat: 34.22, - lon: -118.07, - }, - KMYF: { - id: 'KMYF', - city: 'San Diego, Montgomery Field', - state: 'CA', - lat: 32.81444, - lon: -117.13639, - }, - KMYV: { - id: 'KMYV', - city: 'Marysville, Yuba County Airport', - state: 'CA', - lat: 39.09778, - lon: -121.56972, - }, - KNFG: { - id: 'KNFG', - city: 'Oceanside, Camp Pendleton, Marine Corps Air Station', - state: 'CA', - lat: 33.30472, - lon: -117.35389, - }, - KNID: { - id: 'KNID', - city: 'China Lake, Naval Air Facility', - state: 'CA', - lat: 35.68639, - lon: -117.69, - }, - KNJK: { - id: 'KNJK', - city: 'El Centro, Naval Air Facility', - state: 'CA', - lat: 32.825, - lon: -115.66056, - }, - KNKX: { - id: 'KNKX', - city: 'San Diego, Miramar MCAS/Mitscher Field Airport', - state: 'CA', - lat: 32.86833, - lon: -117.1425, - }, - KNLC: { - id: 'KNLC', - city: 'Lemoore Naval Air Station - Reeves Field', - state: 'CA', - lat: 36.30244, - lon: -119.93968, - }, - KNRS: { - id: 'KNRS', - city: 'Imperial Beach Naval Outlying Field - Ream Field', - state: 'CA', - lat: 32.56302, - lon: -117.11091, - }, - KNSI: { - id: 'KNSI', - city: 'San Nicolas Island Naval Outlying Field', - state: 'CA', - lat: 33.23379, - lon: -119.45588, - }, - KNTD: { - id: 'KNTD', - city: 'Point Mugu, Naval Air Warfare Center', - state: 'CA', - lat: 34.12389, - lon: -119.12167, - }, - KNUC: { - id: 'KNUC', - city: 'San Clemente Island NALF', - state: 'CA', - lat: 33.0218, - lon: -118.58266, - }, - KNUQ: { - id: 'KNUQ', - city: 'Mountain View, Moffett Field', - state: 'CA', - lat: 37.40583, - lon: -122.04806, - }, - KNXP: { - id: 'KNXP', - city: 'Twentynine Palms SELF Airport', - state: 'CA', - lat: 34.29401, - lon: -116.14717, - }, - KNZY: { - id: 'KNZY', - city: 'San Diego, North Island, Naval Air Station', - state: 'CA', - lat: 32.69083, - lon: -117.20889, - }, - KOAK: { - id: 'KOAK', - city: 'San Francisco Bay Oakland International Airport', - state: 'CA', - lat: 37.72126, - lon: -122.22115, - }, - KOAR: { - id: 'KOAR', - city: 'FORT ORD/FRITZSCHE', - state: 'CA', - lat: 36.68, - lon: -121.77, - }, - KOKB: { - id: 'KOKB', - city: 'Oceanside, Oceanside Municipal Airport', - state: 'CA', - lat: 33.21806, - lon: -117.35139, - }, - KONT: { - id: 'KONT', - city: 'Ontario International Airport', - state: 'CA', - lat: 34.05316, - lon: -117.57685, - }, - KOVE: { - id: 'KOVE', - city: 'Oroville Municipal Airport', - state: 'CA', - lat: 39.49436, - lon: -121.62223, - }, - KOXR: { - id: 'KOXR', - city: 'Oxnard, Oxnard Airport', - state: 'CA', - lat: 34.20056, - lon: -119.20306, - }, - KPAO: { - id: 'KPAO', - city: 'Palo Alto Airport', - state: 'CA', - lat: 37.46667, - lon: -122.11667, - }, - KPMD: { - id: 'KPMD', - city: 'Palmdale, Palmdale Production Flight Plant', - state: 'CA', - lat: 34.62972, - lon: -118.08139, - }, - KPOC: { - id: 'KPOC', - city: 'Brackett Field Airport', - state: 'CA', - lat: 34.09282, - lon: -117.77937, - }, - KPRB: { - id: 'KPRB', - city: 'Paso Robles Municipal Airport', - state: 'CA', - lat: 35.66941, - lon: -120.62912, - }, - KPSP: { - id: 'KPSP', - city: 'Palm Springs Regional Airport', - state: 'CA', - lat: 33.82219, - lon: -116.50431, - }, - KPTV: { - id: 'KPTV', - city: 'Porterville, Porterville Municipal Airport', - state: 'CA', - lat: 36.03333, - lon: -119.06667, - }, - KPVF: { - id: 'KPVF', - city: 'Placerville Airport', - state: 'CA', - lat: 38.7242, - lon: -120.7533, - }, - KRAL: { - id: 'KRAL', - city: 'Riverside Municipal Airport', - state: 'CA', - lat: 33.95189, - lon: -117.44511, - }, - KRBL: { - id: 'KRBL', - city: 'Red Bluff, Red Bluff Municipal Airport', - state: 'CA', - lat: 40.15056, - lon: -122.25222, - }, - KRDD: { - id: 'KRDD', - city: 'Redding Municipal Airport', - state: 'CA', - lat: 40.51461, - lon: -122.2977, - }, - KREI: { - id: 'KREI', - city: 'REDLANDS', - state: 'CA', - lat: 34.08526, - lon: -117.14637, - }, - KRHV: { - id: 'KRHV', - city: 'San Jose / Reid / Hillv', - state: 'CA', - lat: 37.3333299, - lon: -121.81667, - }, - KRIV: { - id: 'KRIV', - city: 'March Air Reserve Base', - state: 'CA', - lat: 33.88194, - lon: -117.25902, - }, - KRNM: { - id: 'KRNM', - city: 'Ramona, Ramona Airport', - state: 'CA', - lat: 33.0375, - lon: -116.91583, - }, - KSAC: { - id: 'KSAC', - city: 'Sacramento Executive Airport', - state: 'CA', - lat: 38.50674, - lon: -121.49597, - }, - KSAN: { - id: 'KSAN', - city: 'San Diego International Airport', - state: 'CA', - lat: 32.73361, - lon: -117.18306, - }, - KSBA: { - id: 'KSBA', - city: 'Santa Barbara, Santa Barbara Municipal Airport', - state: 'CA', - lat: 34.42611, - lon: -119.84361, - }, - KSBD: { - id: 'KSBD', - city: 'San Bernardino Intl. Airport', - state: 'CA', - lat: 34.0902699, - lon: -117.24705, - }, - KSBP: { - id: 'KSBP', - city: 'San Luis Obispo, San Luis Obispo County-Mc Chesney Field', - state: 'CA', - lat: 35.2361099, - lon: -120.63611, - }, - KSCK: { - id: 'KSCK', - city: 'Stockton, Stockton Metropolitan Airport', - state: 'CA', - lat: 37.8897199, - lon: -121.22361, - }, - KSDB: { - id: 'KSDB', - city: 'Sandberg', - state: 'CA', - lat: 34.7436099, - lon: -118.72444, - }, - KSDM: { - id: 'KSDM', - city: 'San Diego, Brown Field Municipal Airport', - state: 'CA', - lat: 32.57528, - lon: -116.99306, - }, - KSEE: { - id: 'KSEE', - city: 'Gillespie Field Airport', - state: 'CA', - lat: 32.82738, - lon: -116.97369, - }, - KSFO: { - id: 'KSFO', - city: 'San Francisco, San Francisco International Airport', - state: 'CA', - lat: 37.61961, - lon: -122.36558, - }, - KSIY: { - id: 'KSIY', - city: 'Montague Siskiyou County Airport', - state: 'CA', - lat: 41.77375, - lon: -122.46817, - }, - KSJC: { - id: 'KSJC', - city: 'San Jose, San Jose International Airport', - state: 'CA', - lat: 37.35917, - lon: -121.92417, - }, - KSLI: { - id: 'KSLI', - city: 'Los Alamitos Army Airfield', - state: 'CA', - lat: 33.79628, - lon: -118.04179, - }, - KSMF: { - id: 'KSMF', - city: 'Sacramento International Airport', - state: 'CA', - lat: 38.70071, - lon: -121.59479, - }, - KSMO: { - id: 'KSMO', - city: 'Santa Monica, Santa Monica Municipal Airport', - state: 'CA', - lat: 34.01583, - lon: -118.45139, - }, - KSMX: { - id: 'KSMX', - city: 'Santa Maria Public Airport/Capt G Allan Hancock Field', - state: 'CA', - lat: 34.89408, - lon: -120.45212, - }, - KSNA: { - id: 'KSNA', - city: 'John Wayne-Orange County Airport', - state: 'CA', - lat: 33.6798, - lon: -117.8674, - }, - KSNS: { - id: 'KSNS', - city: 'Salinas, Salinas Municipal Airport', - state: 'CA', - lat: 36.66361, - lon: -121.60806, - }, - KSQL: { - id: 'KSQL', - city: 'San Carlos Airport', - state: 'CA', - lat: 37.51667, - lon: -122.25, - }, - KSTS: { - id: 'KSTS', - city: 'Santa Rosa, Santa Rosa Sonoma County Airport', - state: 'CA', - lat: 38.5, - lon: -122.81667, - }, - KSUU: { - id: 'KSUU', - city: 'Fairfield / Travis Air Force Base', - state: 'CA', - lat: 38.26667, - lon: -121.95, - }, - KSVE: { - id: 'KSVE', - city: 'Susanville Municipal Airport', - state: 'CA', - lat: 40.37569, - lon: -120.57269, - }, - KTCY: { - id: 'KTCY', - city: 'Tracy Municipal Airport', - state: 'CA', - lat: 37.6888999, - lon: -121.44158, - }, - KTOA: { - id: 'KTOA', - city: 'Torrance, Zamperini Field Airport', - state: 'CA', - lat: 33.8, - lon: -118.33333, - }, - KTQS: { - id: 'KTQS', - city: 'Vandenberg SFB - South', - state: 'CA', - lat: 34.633, - lon: -120.617, - }, - KTRK: { - id: 'KTRK', - city: 'Truckee-Tahoe', - state: 'CA', - lat: 39.31667, - lon: -120.13333, - }, - KTRM: { - id: 'KTRM', - city: 'Palm Springs, Jacqueline Cochran Regional Airport', - state: 'CA', - lat: 33.62667, - lon: -116.15944, - }, - KTSP: { - id: 'KTSP', - city: 'Tehachapi Municipal Airport', - state: 'CA', - lat: 35.135, - lon: -118.4392, - }, - KTVL: { - id: 'KTVL', - city: 'South Lake Tahoe, Lake Tahoe Airport', - state: 'CA', - lat: 38.8983599, - lon: -119.99615, - }, - KUKI: { - id: 'KUKI', - city: 'Ukiah Municipal Airport', - state: 'CA', - lat: 39.12783, - lon: -123.20011, - }, - KVBG: { - id: 'KVBG', - city: 'Vandenberg Space Force Base', - state: 'CA', - lat: 34.7294399, - lon: -120.57667, - }, - KVCB: { - id: 'KVCB', - city: 'Vacaville Nut Tree Airport', - state: 'CA', - lat: 38.37755, - lon: -121.95853, - }, - KVCV: { - id: 'KVCV', - city: 'Victorville, Southern California Logistics Airport', - state: 'CA', - lat: 34.59722, - lon: -117.38278, - }, - KVIS: { - id: 'KVIS', - city: 'Visalia, Visalia Municipal Airport', - state: 'CA', - lat: 36.31667, - lon: -119.4, - }, - KVNY: { - id: 'KVNY', - city: 'Van Nuys, Van Nuys Airport', - state: 'CA', - lat: 34.2125, - lon: -118.49083, - }, - KWHP: { - id: 'KWHP', - city: 'Los Angeles, Whiteman Airport', - state: 'CA', - lat: 34.25, - lon: -118.4, - }, - KWJF: { - id: 'KWJF', - city: 'General Wm J Fox Airfield', - state: 'CA', - lat: 34.74123, - lon: -118.21251, - }, - KWVI: { - id: 'KWVI', - city: 'Watsonville, Watsonville Municipal Airport', - state: 'CA', - lat: 36.93944, - lon: -121.78889, - }, - PARO: { - id: 'PARO', - city: 'PARKDALE', - state: 'OR', - lat: 45.54444, - lon: -121.61667, - }, - PCYO: { - id: 'PCYO', - city: 'PRARIE CITY', - state: 'OR', - lat: 44.44083, - lon: -118.62778, - }, - PDTO: { - id: 'PDTO', - city: 'Umatilla River at Pendleton, OR', - state: 'OR', - lat: 45.6722222, - lon: -118.7916666, - }, - PILO: { - id: 'PILO', - city: 'Pilot Rock 11E, OR', - state: 'OR', - lat: 45.5019444, - lon: -118.6205555, - }, - PNGO: { - id: 'PNGO', - city: 'PINEGROVE', - state: 'OR', - lat: 45.65222, - lon: -121.50917, - }, - POBO: { - id: 'POBO', - city: 'POWELL BUTTE', - state: 'OR', - lat: 44.24833, - lon: -120.94972, - }, - PRHO: { - id: 'PRHO', - city: 'Powder River at Hudspeth Lane near Sumpter, OR', - state: 'OR', - lat: 44.6861111, - lon: -118.1, - }, - PRIO: { - id: 'PRIO', - city: 'Prineville 4NW, OR', - state: 'OR', - lat: 44.3691666, - lon: -120.9377777, - }, - PRVO: { - id: 'PRVO', - city: 'Crooked River near Prineville, OR', - state: 'OR', - lat: 44.1138888, - lon: -120.7944444, - }, - PWDO: { - id: 'PWDO', - city: 'Powder River at Baker, OR', - state: 'OR', - lat: 44.7683333, - lon: -117.8305555, - }, -}; diff --git a/server/scripts/data/travelcities.js b/server/scripts/data/travelcities.js deleted file mode 100644 index d9ada38..0000000 --- a/server/scripts/data/travelcities.js +++ /dev/null @@ -1,243 +0,0 @@ -// eslint-disable-next-line no-unused-vars -const TravelCities = [ - { - Name: 'Atlanta', - Latitude: 33.749, - Longitude: -84.388, - point: { - x: 51, - y: 87, - wfo: 'FFC', - }, - }, - { - Name: 'Boston', - Latitude: 42.3584, - Longitude: -71.0598, - point: { - x: 71, - y: 90, - wfo: 'BOX', - }, - }, - { - Name: 'Chicago', - Latitude: 41.9796, - Longitude: -87.9045, - point: { - x: 66, - y: 77, - wfo: 'LOT', - }, - }, - { - Name: 'Cleveland', - Latitude: 41.4995, - Longitude: -81.6954, - point: { - x: 83, - y: 65, - wfo: 'CLE', - }, - }, - { - Name: 'Dallas', - Latitude: 32.8959, - Longitude: -97.0372, - point: { - x: 80, - y: 109, - wfo: 'FWD', - }, - }, - { - Name: 'Denver', - Latitude: 39.7391, - Longitude: -104.9847, - point: { - x: 63, - y: 61, - wfo: 'BOU', - }, - }, - { - Name: 'Detroit', - Latitude: 42.3314, - Longitude: -83.0457, - point: { - x: 66, - y: 34, - wfo: 'DTX', - }, - }, - { - Name: 'Hartford', - Latitude: 41.7637, - Longitude: -72.6851, - point: { - x: 21, - y: 54, - wfo: 'BOX', - }, - }, - { - Name: 'Houston', - Latitude: 29.7633, - Longitude: -95.3633, - point: { - x: 65, - y: 97, - wfo: 'HGX', - }, - }, - { - Name: 'Indianapolis', - Latitude: 39.7684, - Longitude: -86.158, - point: { - x: 58, - y: 69, - wfo: 'IND', - }, - }, - { - Name: 'Los Angeles', - Latitude: 34.0522, - Longitude: -118.2437, - point: { - x: 155, - y: 45, - wfo: 'LOX', - }, - }, - { - Name: 'Miami', - Latitude: 25.7743, - Longitude: -80.1937, - point: { - x: 110, - y: 51, - wfo: 'MFL', - }, - }, - { - Name: 'Minneapolis', - Latitude: 44.98, - Longitude: -93.2638, - point: { - x: 108, - y: 72, - wfo: 'MPX', - }, - }, - { - Name: 'New York', - Latitude: 40.7142, - Longitude: -74.0059, - point: { - x: 33, - y: 35, - wfo: 'OKX', - }, - }, - { - Name: 'Norfolk', - Latitude: 36.8468, - Longitude: -76.2852, - point: { - x: 90, - y: 52, - wfo: 'AKQ', - }, - }, - { - Name: 'Orlando', - Latitude: 28.5383, - Longitude: -81.3792, - point: { - x: 26, - y: 68, - wfo: 'MLB', - }, - }, - { - Name: 'Philadelphia', - Latitude: 39.9523, - Longitude: -75.1638, - point: { - x: 50, - y: 76, - wfo: 'PHI', - }, - }, - { - Name: 'Pittsburgh', - Latitude: 40.4406, - Longitude: -79.9959, - point: { - x: 78, - y: 66, - wfo: 'PBZ', - }, - }, - { - Name: 'St. Louis', - Latitude: 38.6273, - Longitude: -90.1979, - point: { - x: 95, - y: 74, - wfo: 'LSX', - }, - }, - { - Name: 'San Francisco', - Latitude: 37.7749, - Longitude: -122.4194, - point: { - x: 85, - y: 105, - wfo: 'MTR', - }, - }, - { - Name: 'Seattle', - Latitude: 47.6062, - Longitude: -122.3321, - point: { - x: 125, - y: 68, - wfo: 'SEW', - }, - }, - { - Name: 'Syracuse', - Latitude: 43.0481, - Longitude: -76.1474, - point: { - x: 52, - y: 99, - wfo: 'BGM', - }, - }, - { - Name: 'Tampa', - Latitude: 27.9475, - Longitude: -82.4584, - point: { - x: 71, - y: 97, - wfo: 'TBW', - }, - }, - { - Name: 'Washington DC', - Latitude: 38.8951, - Longitude: -77.0364, - point: { - x: 97, - y: 71, - wfo: 'LWX', - }, - }, -]; diff --git a/server/scripts/index.mjs b/server/scripts/index.mjs index 8878ddc..2ec7fb3 100644 --- a/server/scripts/index.mjs +++ b/server/scripts/index.mjs @@ -1,12 +1,14 @@ import { json } from './modules/utils/fetch.mjs'; import noSleep from './modules/utils/nosleep.mjs'; import { - message as navMessage, isPlaying, resize, resetStatuses, latLonReceived, + message as navMessage, isPlaying, resize, resetStatuses, latLonReceived, isIOS, } from './modules/navigation.mjs'; import { round2 } from './modules/utils/units.mjs'; import { parseQueryString } from './modules/share.mjs'; import settings from './modules/settings.mjs'; import AutoComplete from './modules/autocomplete.mjs'; +import { loadAllData } from './modules/utils/data-loader.mjs'; +import { debugFlag } from './modules/utils/debug.mjs'; document.addEventListener('DOMContentLoaded', () => { init(); @@ -24,11 +26,27 @@ const categories = [ 'Postal', 'Populated Place', ]; const category = categories.join(','); -const TXT_ADDRESS_SELECTOR = '#txtAddress'; +const TXT_ADDRESS_SELECTOR = '#txtLocation'; const TOGGLE_FULL_SCREEN_SELECTOR = '#ToggleFullScreen'; const BNT_GET_GPS_SELECTOR = '#btnGetGps'; -const init = () => { +const init = async () => { + // Load core data first - app cannot function without it + try { + await loadAllData(typeof OVERRIDES !== 'undefined' && OVERRIDES.VERSION ? OVERRIDES.VERSION : ''); + } catch (error) { + console.error('Failed to load core application data:', error); + // Show error message to user and halt initialization + document.body.innerHTML = ` +
+

Unable to load Weather Data

+

The application cannot start because core data failed to load.

+

Please check your connection and try refreshing.

+
+ `; + return; // Stop initialization + } + document.querySelector(TXT_ADDRESS_SELECTOR).addEventListener('focus', (e) => { e.target.select(); }); @@ -39,7 +57,15 @@ const init = () => { document.querySelector('#NavigatePrevious').addEventListener('click', btnNavigatePreviousClick); document.querySelector('#NavigatePlay').addEventListener('click', btnNavigatePlayClick); document.querySelector('#ToggleScanlines').addEventListener('click', btnNavigateToggleScanlines); - document.querySelector(TOGGLE_FULL_SCREEN_SELECTOR).addEventListener('click', btnFullScreenClick); + + // Hide fullscreen button on iOS since it doesn't support true fullscreen + const fullscreenButton = document.querySelector(TOGGLE_FULL_SCREEN_SELECTOR); + if (isIOS()) { + fullscreenButton.style.display = 'none'; + } else { + fullscreenButton.addEventListener('click', btnFullScreenClick); + } + const btnGetGps = document.querySelector(BNT_GET_GPS_SELECTOR); btnGetGps.addEventListener('click', btnGetGpsClick); if (!navigator.geolocation) btnGetGps.style.display = 'none'; @@ -47,9 +73,6 @@ const init = () => { document.querySelector('#divTwc').addEventListener('mousemove', () => { if (document.fullscreenElement) updateFullScreenNavigate(); }); - // local change detection when exiting full screen via ESC key (or other non button click methods) - window.addEventListener('resize', fullScreenResizeCheck); - fullScreenResizeCheck.wasFull = false; document.querySelector('#btnGetLatLng').addEventListener('click', () => autoComplete.directFormSubmit()); @@ -89,6 +112,7 @@ const init = () => { const query = parsedParameters.latLonQuery ?? localStorage.getItem('latLonQuery'); const latLon = parsedParameters.latLon ?? localStorage.getItem('latLon'); const fromGPS = localStorage.getItem('latLonFromGPS') && !loadFromParsed; + if (query && latLon && !fromGPS) { const txtAddress = document.querySelector(TXT_ADDRESS_SELECTOR); txtAddress.value = query; @@ -98,9 +122,21 @@ const init = () => { btnGetGpsClick(); } - // if kiosk mode was set via the query string, also play immediately - settings.kiosk.value = parsedParameters['settings-kiosk-checkbox'] === 'true'; - const play = parsedParameters['settings-kiosk-checkbox'] ?? localStorage.getItem('play'); + // Handle kiosk mode initialization + const urlKioskCheckbox = parsedParameters['settings-kiosk-checkbox']; + + // If kiosk=false is specified, disable kiosk mode and clear any stored value + if (urlKioskCheckbox === 'false') { + settings.kiosk.value = false; + // Clear stored value by using conditional storage with false + settings.kiosk.conditionalStoreToLocalStorage(false, false); + } else if (urlKioskCheckbox === 'true') { + // if kiosk mode was set via the query string, enable it + settings.kiosk.value = true; + } + + // Auto-play logic: also play immediately if kiosk mode is enabled + const play = settings.kiosk.value || urlKioskCheckbox === 'true' ? 'true' : localStorage.getItem('play'); if (play === null || play === 'true') postMessage('navButton', 'play'); document.querySelector('#btnClearQuery').addEventListener('click', () => { @@ -125,6 +161,7 @@ const init = () => { }; const autocompleteOnSelect = async (suggestion) => { + // Note: it's fine that this uses json instead of safeJson since it's infrequent and user-initiated const data = await json('https://geocode.arcgis.com/arcgis/rest/services/World/GeocodeServer/find', { data: { text: suggestion.value, @@ -171,27 +208,42 @@ const btnFullScreenClick = () => { return false; }; -const enterFullScreen = () => { +// This is async because modern browsers return a Promise from requestFullscreen +const enterFullScreen = async () => { const element = document.querySelector('#divTwc'); // Supports most browsers and their versions. - const requestMethod = element.requestFullScreen || element.webkitRequestFullScreen - || element.mozRequestFullScreen || element.msRequestFullscreen; + const requestMethod = element.requestFullscreen || element.webkitRequestFullscreen || element.mozRequestFullscreen || element.msRequestFullscreen; if (requestMethod) { - // Native full screen. - requestMethod.call(element, { navigationUI: 'hide' }); + try { + // Native full screen with options for optimal display + await requestMethod.call(element, { + navigationUI: 'hide', + allowsInlineMediaPlayback: true, + }); + + if (debugFlag('fullscreen')) { + setTimeout(() => { + console.log(`🖥️ Fullscreen engaged. window=${window.innerWidth}x${window.innerHeight} fullscreenElement=${!!document.fullscreenElement}`); + }, 150); + } + } catch (error) { + console.error('❌ Fullscreen request failed:', error); + } } else { // iOS doesn't support FullScreen API. window.scrollTo(0, 0); + resize(true); // Force resize for iOS } - resize(); updateFullScreenNavigate(); // change hover text and image const img = document.querySelector(TOGGLE_FULL_SCREEN_SELECTOR); - img.src = 'images/nav/ic_fullscreen_exit_white_24dp_2x.png'; - img.title = 'Exit fullscreen'; + if (img && img.style.display !== 'none') { + img.src = 'images/nav/ic_fullscreen_exit_white_24dp_2x.png'; + img.title = 'Exit fullscreen'; + } }; const exitFullscreen = () => { @@ -202,20 +254,22 @@ const exitFullscreen = () => { document.exitFullscreen(); } else if (document.webkitExitFullscreen) { document.webkitExitFullscreen(); - } else if (document.mozCancelFullScreen) { - document.mozCancelFullScreen(); + } else if (document.mozCancelFullscreen) { + document.mozCancelFullscreen(); } else if (document.msExitFullscreen) { document.msExitFullscreen(); } - resize(); + // Note: resize will be called by fullscreenchange event listener exitFullScreenVisibilityChanges(); }; const exitFullScreenVisibilityChanges = () => { // change hover text and image const img = document.querySelector(TOGGLE_FULL_SCREEN_SELECTOR); - img.src = 'images/nav/ic_fullscreen_white_24dp_2x.png'; - img.title = 'Enter fullscreen'; + if (img && img.style.display !== 'none') { + img.src = 'images/nav/ic_fullscreen_white_24dp_2x.png'; + img.title = 'Enter fullscreen'; + } document.querySelector('#divTwc').classList.remove('no-cursor'); const divTwcBottom = document.querySelector('#divTwcBottom'); divTwcBottom.classList.remove('hidden'); @@ -295,10 +349,20 @@ const updateFullScreenNavigate = () => { }; const documentKeydown = (e) => { - // don't trigger on ctrl/alt/shift modified key - if (e.altKey || e.ctrlKey || e.shiftKey) return false; const { key } = e; + // Handle Ctrl+K to exit kiosk mode (even when other modifiers would normally be ignored) + if (e.ctrlKey && (key === 'k' || key === 'K')) { + e.preventDefault(); + if (settings.kiosk?.value) { + settings.kiosk.value = false; + } + return false; + } + + // don't trigger on ctrl/alt/shift modified key for other shortcuts + if (e.altKey || e.ctrlKey || e.shiftKey) return false; + if (document.fullscreenElement || document.activeElement === document.body) { switch (key) { case ' ': // Space @@ -397,21 +461,6 @@ const getForecastFromLatLon = (latitude, longitude, fromGps = false) => { }); }; -// check for change in full screen triggered by browser and run local functions -const fullScreenResizeCheck = () => { - if (fullScreenResizeCheck.wasFull && !document.fullscreenElement) { - // leaving full screen - exitFullScreenVisibilityChanges(); - } - if (!fullScreenResizeCheck.wasFull && document.fullscreenElement) { - // entering full screen - // can't do much here because a UI interaction is required to change the full screen div element - } - - // store state of fullscreen element for next change detection - fullScreenResizeCheck.wasFull = !!document.fullscreenElement; -}; - const getCustomCode = async () => { // fetch the custom file and see if it returns a 200 status const response = await fetch('scripts/custom.js', { method: 'HEAD' }); diff --git a/server/scripts/modules/almanac.mjs b/server/scripts/modules/almanac.mjs index 2b75fa9..7d9190f 100644 --- a/server/scripts/modules/almanac.mjs +++ b/server/scripts/modules/almanac.mjs @@ -113,17 +113,28 @@ class Almanac extends WeatherDisplay { async drawCanvas() { super.drawCanvas(); const info = this.data; + + // Generate sun data grid in reading order (left-to-right, top-to-bottom) + + // Set day names const Today = DateTime.local(); const Tomorrow = Today.plus({ days: 1 }); + this.elem.querySelector('.day-1').textContent = Today.toLocaleString({ weekday: 'long' }); + this.elem.querySelector('.day-2').textContent = Tomorrow.toLocaleString({ weekday: 'long' }); - // sun and moon data - this.elem.querySelector('.day-1').innerHTML = Today.toLocaleString({ weekday: 'long' }); - this.elem.querySelector('.day-2').innerHTML = Tomorrow.toLocaleString({ weekday: 'long' }); - this.elem.querySelector('.rise-1').innerHTML = timeFormat(DateTime.fromJSDate(info.sun[0].sunrise)); - this.elem.querySelector('.rise-2').innerHTML = timeFormat(DateTime.fromJSDate(info.sun[1].sunrise)); - this.elem.querySelector('.set-1').innerHTML = timeFormat(DateTime.fromJSDate(info.sun[0].sunset)); - this.elem.querySelector('.set-2').innerHTML = timeFormat(DateTime.fromJSDate(info.sun[1].sunset)); + const todaySunrise = DateTime.fromJSDate(info.sun[0].sunrise); + const todaySunset = DateTime.fromJSDate(info.sun[0].sunset); + const [todaySunriseFormatted, todaySunsetFormatted] = formatTimesForColumn([todaySunrise, todaySunset]); + this.elem.querySelector('.rise-1').textContent = todaySunriseFormatted; + this.elem.querySelector('.set-1').textContent = todaySunsetFormatted; + const tomorrowSunrise = DateTime.fromJSDate(info.sun[1].sunrise); + const tomorrowSunset = DateTime.fromJSDate(info.sun[1].sunset); + const [tomorrowSunriseFormatted, tomorrowSunsetformatted] = formatTimesForColumn([tomorrowSunrise, tomorrowSunset]); + this.elem.querySelector('.rise-2').textContent = tomorrowSunriseFormatted; + this.elem.querySelector('.set-2').textContent = tomorrowSunsetformatted; + + // Moon data const days = info.moon.map((MoonPhase) => { const fill = {}; @@ -168,7 +179,20 @@ const imageName = (type) => { } }; -const timeFormat = (dt) => dt.setZone(timeZone()).toLocaleString(DateTime.TIME_SIMPLE).toLowerCase(); +const formatTimesForColumn = (times) => { + const formatted = times.map((dt) => dt.setZone(timeZone()).toFormat('h:mm a').toUpperCase()); + + // Check if any time has a 2-digit hour (starts with '1') + const hasTwoDigitHour = formatted.some((time) => time.startsWith('1')); + + // If mixed digit lengths, pad single-digit hours with non-breaking space + if (hasTwoDigitHour) { + return formatted.map((time) => (time.startsWith('1') ? time : `\u00A0${time}`)); + } + + // Otherwise, no padding needed + return formatted; +}; // register display const display = new Almanac(9, 'almanac'); diff --git a/server/scripts/modules/autocomplete.mjs b/server/scripts/modules/autocomplete.mjs index 5642ba7..b529e93 100644 --- a/server/scripts/modules/autocomplete.mjs +++ b/server/scripts/modules/autocomplete.mjs @@ -192,7 +192,7 @@ class AutoComplete { let result = this.cachedResponses[search]; if (!result) { - // make the request + // make the request; using json here instead of safeJson is fine because it's infrequent and user-initiated const resultRaw = await json(url); // use the provided parser @@ -296,8 +296,11 @@ class AutoComplete { // if a click is detected on the page, generally we hide the suggestions, unless the click was within the autocomplete elements checkOutsideClick(e) { - if (e.target.id === 'txtAddress') return; - if (e.target?.parentNode?.classList.contains(this.options.containerClass)) return; + if (e.target.id === 'txtLocation') return; + // Fix autocomplete crash on outside click detection + // Add optional chaining to prevent TypeError when checking classList.contains() + // on elements that may not have a classList property. + if (e.target?.parentNode?.classList?.contains(this.options.containerClass)) return; this.hideSuggestions(); } } diff --git a/server/scripts/modules/currentweather.mjs b/server/scripts/modules/currentweather.mjs index 455d699..045cefe 100644 --- a/server/scripts/modules/currentweather.mjs +++ b/server/scripts/modules/currentweather.mjs @@ -1,26 +1,22 @@ // current weather conditions display import STATUS from './status.mjs'; import { preloadImg } from './utils/image.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import { directionToNSEW } from './utils/calc.mjs'; import { locationCleanup } from './utils/string.mjs'; import { getLargeIcon } from './icons.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; +import augmentObservationWithMetar from './utils/metar.mjs'; import { temperature, windSpeed, pressure, distanceMeters, distanceKilometers, } from './utils/units.mjs'; +import { debugFlag } from './utils/debug.mjs'; +import { isDataStale, enhanceObservationWithMapClick } from './utils/mapclick.mjs'; // some stations prefixed do not provide all the necessary data const skipStations = ['U', 'C', 'H', 'W', 'Y', 'T', 'S', 'M', 'O', 'L', 'A', 'F', 'B', 'N', 'V', 'R', 'D', 'E', 'I', 'G', 'J']; -const REQUIRED_VALUES = [ - 'windSpeed', - 'dewpoint', - 'barometricPressure', - 'visibility', - 'relativeHumidity', -]; class CurrentWeather extends WeatherDisplay { constructor(navId, elemId) { super(navId, elemId, 'Current Conditions', true); @@ -44,48 +40,107 @@ class CurrentWeather extends WeatherDisplay { while (!observations && stationNum < filteredStations.length) { // get the station station = filteredStations[stationNum]; + const stationId = station.properties.stationIdentifier; + stationNum += 1; + + let candidateObservation; try { - // station observations // eslint-disable-next-line no-await-in-loop - observations = await json(`${station.id}/observations`, { + candidateObservation = await safeJson(`${station.id}/observations`, { data: { - limit: 2, + limit: 2, // we need the two most recent observations to calculate pressure direction }, retryCount: 3, stillWaiting: () => this.stillWaiting(), }); - - if (observations.features.length === 0) throw new Error(`No features returned for station: ${station.properties.stationIdentifier}, trying next station`); - - // one weather value in the right side column is allowed to be missing. Count them up. - // eslint-disable-next-line no-loop-func - const valuesCount = REQUIRED_VALUES.reduce((prev, cur) => { - const value = observations.features[0].properties?.[cur]?.value; - if (value !== null && value !== undefined) return prev + 1; - // ceiling is a special case :,-( - const ceiling = observations.features[0].properties?.cloudLayers[0]?.base?.value; - if (cur === 'ceiling' && ceiling !== null && ceiling !== undefined) return prev + 1; - return prev; - }, 0); - - // test data quality - if (observations.features[0].properties.temperature.value === null - || observations.features[0].properties.textDescription === null - || observations.features[0].properties.textDescription === '' - || observations.features[0].properties.icon === null - || valuesCount < REQUIRED_VALUES.length - 1) { - observations = undefined; - throw new Error(`Incomplete data set for: ${station.properties.stationIdentifier}, trying next station`); - } } catch (error) { - console.error(error); - observations = undefined; + console.error(`Unexpected error getting Current Conditions for station ${stationId}: ${error.message} (trying next station)`); + candidateObservation = undefined; + } + + // Check if request was successful and has data + if (candidateObservation && candidateObservation.features?.length > 0) { + // Attempt making observation data usable with METAR data + const originalData = { ...candidateObservation.features[0].properties }; + candidateObservation.features[0].properties = augmentObservationWithMetar(candidateObservation.features[0].properties); + const metarFields = [ + { name: 'temperature', check: (orig, metar) => orig.temperature?.value === null && metar.temperature?.value !== null }, + { name: 'windSpeed', check: (orig, metar) => orig.windSpeed?.value === null && metar.windSpeed?.value !== null }, + { name: 'windDirection', check: (orig, metar) => orig.windDirection?.value === null && metar.windDirection?.value !== null }, + { name: 'windGust', check: (orig, metar) => orig.windGust?.value === null && metar.windGust?.value !== null }, + { name: 'dewpoint', check: (orig, metar) => orig.dewpoint?.value === null && metar.dewpoint?.value !== null }, + { name: 'barometricPressure', check: (orig, metar) => orig.barometricPressure?.value === null && metar.barometricPressure?.value !== null }, + { name: 'relativeHumidity', check: (orig, metar) => orig.relativeHumidity?.value === null && metar.relativeHumidity?.value !== null }, + { name: 'visibility', check: (orig, metar) => orig.visibility?.value === null && metar.visibility?.value !== null }, + { name: 'ceiling', check: (orig, metar) => orig.cloudLayers?.[0]?.base?.value === null && metar.cloudLayers?.[0]?.base?.value !== null }, + ]; + const augmentedData = candidateObservation.features[0].properties; + const metarReplacements = metarFields.filter((field) => field.check(originalData, augmentedData)).map((field) => field.name); + if (debugFlag('currentweather') && metarReplacements.length > 0) { + console.log(`Current Conditions for station ${stationId} were augmented with METAR data for ${metarReplacements.join(', ')}`); + } + + // test data quality - check required fields and allow one optional field to be missing + const requiredFields = [ + { name: 'temperature', check: (props) => props.temperature?.value === null, required: true }, + { name: 'textDescription', check: (props) => props.textDescription === null || props.textDescription === '', required: true }, + { name: 'icon', check: (props) => props.icon === null, required: true }, + { name: 'windSpeed', check: (props) => props.windSpeed?.value === null, required: false }, + { name: 'dewpoint', check: (props) => props.dewpoint?.value === null, required: false }, + { name: 'barometricPressure', check: (props) => props.barometricPressure?.value === null, required: false }, + { name: 'visibility', check: (props) => props.visibility?.value === null, required: false }, + { name: 'relativeHumidity', check: (props) => props.relativeHumidity?.value === null, required: false }, + { name: 'ceiling', check: (props) => props.cloudLayers?.[0]?.base?.value === null, required: false }, + ]; + + // Use enhanced observation with MapClick fallback + // eslint-disable-next-line no-await-in-loop + const enhancedResult = await enhanceObservationWithMapClick(augmentedData, { + requiredFields, + maxOptionalMissing: 1, // Allow one optional field to be missing + stationId, + stillWaiting: () => this.stillWaiting(), + debugContext: 'currentweather', + }); + + candidateObservation.features[0].properties = enhancedResult.data; + const { missingFields } = enhancedResult; + const missingRequired = missingFields.filter((fieldName) => { + const field = requiredFields.find((f) => f.name === fieldName && f.required); + return !!field; + }); + const missingOptional = missingFields.filter((fieldName) => { + const field = requiredFields.find((f) => f.name === fieldName && !f.required); + return !!field; + }); + const missingOptionalCount = missingOptional.length; + + // Check final data quality + // Allow one optional field to be missing + if (missingRequired.length === 0 && missingOptionalCount <= 1) { + // Station data is good, use it + observations = candidateObservation; + if (debugFlag('currentweather') && missingOptional.length > 0) { + console.log(`Data for station ${stationId} is missing optional fields: ${missingOptional.join(', ')} (acceptable)`); + } + } else { + const allMissing = [...missingRequired, ...missingOptional]; + if (debugFlag('currentweather')) { + console.log(`Data for station ${stationId} is missing fields: ${allMissing.join(', ')} (${missingRequired.length} required, ${missingOptionalCount} optional) (trying next station)`); + } + } + } else if (debugFlag('verbose-failures')) { + if (!candidateObservation) { + console.log(`Current Conditions for station ${stationId} failed, trying next station`); + } else { + console.log(`No features returned for station ${stationId}, trying next station`); + } } } // test for data received if (!observations) { - console.error('All current weather stations exhausted'); + console.error('Current Conditions failure: all nearby weather stations exhausted!'); if (this.isEnabled) this.setStatus(STATUS.failed); // send failed to subscribers this.getDataCallback(undefined); @@ -99,14 +154,36 @@ class CurrentWeather extends WeatherDisplay { // stop here if we're disabled if (!superResult) return; - // preload the icon - preloadImg(getLargeIcon(observations.features[0].properties.icon)); + // Data is available, ensure we're enabled for display + this.timing.totalScreens = 1; + + // Check final data age + const { isStale, ageInMinutes } = isDataStale(observations.features[0].properties.timestamp, 80); // hourly observation + 20 minute propagation delay + this.isStaleData = isStale; + + if (isStale && debugFlag('currentweather')) { + console.warn(`Current Conditions: Data is ${ageInMinutes.toFixed(0)} minutes old (from ${new Date(observations.features[0].properties.timestamp).toISOString()})`); + } + + // preload the icon if available + if (observations.features[0].properties.icon) { + const iconResult = getLargeIcon(observations.features[0].properties.icon); + if (iconResult) { + preloadImg(iconResult); + } + } this.setStatus(STATUS.loaded); } async drawCanvas() { super.drawCanvas(); + // Update header text based on data staleness + const headerTop = this.elem.querySelector('.header .title .top'); + if (headerTop) { + headerTop.textContent = this.isStaleData ? 'Recent' : 'Current'; + } + let condition = this.data.observations.textDescription; if (condition.length > 15) { condition = shortConditions(condition); @@ -209,17 +286,23 @@ const parseData = (data) => { data.WindGust = windConverter(observations.windGust.value); data.WindUnit = windConverter.units; data.Humidity = Math.round(observations.relativeHumidity.value); - data.Icon = getLargeIcon(observations.icon); + + // Get the large icon, but provide a fallback if it returns false + const iconResult = getLargeIcon(observations.icon); + data.Icon = iconResult || observations.icon; // Use original icon if getLargeIcon returns false + data.PressureDirection = ''; data.TextConditions = observations.textDescription; // set wind speed of 0 as calm if (data.WindSpeed === 0) data.WindSpeed = 'Calm'; - // difference since last measurement (pascals, looking for difference of more than 150) - const pressureDiff = (observations.barometricPressure.value - data.features[1].properties.barometricPressure.value); - if (pressureDiff > 150) data.PressureDirection = 'R'; - if (pressureDiff < -150) data.PressureDirection = 'F'; + // if two measurements are available, use the difference (in pascals) to determine pressure trend + if (data.features.length > 1 && data.features[1].properties.barometricPressure?.value) { + const pressureDiff = (observations.barometricPressure.value - data.features[1].properties.barometricPressure.value); + if (pressureDiff > 150) data.PressureDirection = 'R'; + if (pressureDiff < -150) data.PressureDirection = 'F'; + } return data; }; diff --git a/server/scripts/modules/currentweatherscroll.mjs b/server/scripts/modules/currentweatherscroll.mjs index 4223c60..933b058 100644 --- a/server/scripts/modules/currentweatherscroll.mjs +++ b/server/scripts/modules/currentweatherscroll.mjs @@ -3,11 +3,14 @@ import { elemForEach } from './utils/elem.mjs'; import getCurrentWeather from './currentweather.mjs'; import { currentDisplay } from './navigation.mjs'; import getHazards from './hazards.mjs'; +import settings from './settings.mjs'; // constants const degree = String.fromCharCode(176); -const SCROLL_SPEED = 75; // pixels/second -const DEFAULT_UPDATE = 8; // 0.5s ticks +const SCROLL_SPEED = 100; // pixels/second +const TICK_INTERVAL_MS = 500; // milliseconds per tick +const secondsToTicks = (seconds) => Math.ceil((seconds * 1000) / TICK_INTERVAL_MS); +const DEFAULT_UPDATE = secondsToTicks(4.0); // 4 second default for each current conditions // local variables let interval; @@ -29,7 +32,7 @@ const start = () => { resetFlag = false; // set up the interval if needed if (!interval) { - interval = setInterval(incrementInterval, 500); + interval = setInterval(incrementInterval, TICK_INTERVAL_MS); } // draw the data @@ -71,15 +74,21 @@ const drawScreen = async () => { // get the conditions const data = await getCurrentWeather(); + // create a data object (empty if no valid current weather conditions) + const scrollData = data || {}; + // add the hazards if on screen 0 if (screenIndex === 0) { - data.hazards = await getHazards(() => this.stillWaiting()); + const hazards = await getHazards(); + if (hazards && hazards.length > 0) { + scrollData.hazards = hazards; + } } - // nothing to do if there's no data yet - if (!data) return; + // if we have no current weather and no hazards, there's nothing to display + if (!data && (!scrollData.hazards || scrollData.hazards.length === 0)) return; - const thisScreen = workingScreens[screenIndex](data); + const thisScreen = workingScreens[screenIndex](scrollData); // update classes on the scroll area elemForEach('.weather-display .scroll', (elem) => { @@ -116,7 +125,9 @@ const hazards = (data) => { // test for data if (!data.hazards || data.hazards.length === 0) return false; - const hazard = `${data.hazards[0].properties.event} ${data.hazards[0].properties.description}`; + // since the hazard scroll element has no left/right margins, pad the beginning and end with non-breaking spaces + const padding = ' '.repeat(4); + const hazard = `${padding}${data.hazards[0].properties.event} ${data.hazards[0].properties.description}${padding}`; return { text: hazard, @@ -218,25 +229,35 @@ const drawScrollCondition = (screen) => { // calculate the scroll distance and set a minimum scroll const scrollDistance = Math.max(scrollWidth - clientWidth, 0); - // calculate the scroll time - const scrollTime = scrollDistance / SCROLL_SPEED; - // calculate a new minimum on-screen time +1.0s at start and end - nextUpdate = Math.round(Math.ceil(scrollTime / 0.5) + 4); + // calculate the scroll time (scaled by global speed setting) + const scrollTime = scrollDistance / SCROLL_SPEED * settings.speed.value; + // add 1 second pause at the end of the scroll animation + const endPauseTime = 1.0; + const totalAnimationTime = scrollTime + endPauseTime; + // calculate total on-screen time: animation time + start delay + end pause + const startDelayTime = 1.0; // setTimeout delay below + const totalDisplayTime = totalAnimationTime + startDelayTime; + nextUpdate = secondsToTicks(totalDisplayTime); + + // update the element with initial position and transition + scrollElement.style.transform = 'translateX(0px)'; + scrollElement.style.transition = `transform ${scrollTime.toFixed(1)}s linear`; + scrollElement.style.willChange = 'transform'; // Hint to browser for hardware acceleration + scrollElement.style.backfaceVisibility = 'hidden'; // Force hardware acceleration + scrollElement.style.perspective = '1000px'; // Enable 3D rendering context - // update the element transition and set initial left position - scrollElement.style.left = '0px'; - scrollElement.style.transition = `left linear ${scrollTime.toFixed(1)}s`; elemForEach('.weather-display .scroll .fixed', (elem) => { elem.innerHTML = ''; elem.append(scrollElement.cloneNode(true)); }); - // start the scroll after a short delay + + // start the scroll after the specified delay setTimeout(() => { - // change the left position to trigger the scroll + // change the transform to trigger the scroll elemForEach('.weather-display .scroll .fixed .scroll-area', (elem) => { - elem.style.left = `-${scrollDistance.toFixed(0)}px`; + elem.style.transform = `translateX(-${scrollDistance.toFixed(0)}px)`; }); - }, 1000); + }, startDelayTime * 1000); }; const parseMessage = (event) => { diff --git a/server/scripts/modules/extendedforecast.mjs b/server/scripts/modules/extendedforecast.mjs index f3d02b8..c7fe98a 100644 --- a/server/scripts/modules/extendedforecast.mjs +++ b/server/scripts/modules/extendedforecast.mjs @@ -1,14 +1,16 @@ // display extended forecast graphically -// technically uses the same data as the local forecast, we'll let the browser do the caching of that +// (technically this uses the same data as the local forecast, but we'll let the cache deal with that) import STATUS from './status.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import { DateTime } from '../vendor/auto/luxon.mjs'; import { getLargeIcon } from './icons.mjs'; import { preloadImg } from './utils/image.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; import settings from './settings.mjs'; +import filterExpiredPeriods from './utils/forecast-utils.mjs'; +import { debugFlag } from './utils/debug.mjs'; class ExtendedForecast extends WeatherDisplay { constructor(navId, elemId) { @@ -21,27 +23,30 @@ class ExtendedForecast extends WeatherDisplay { async getData(weatherParameters, refresh) { if (!super.getData(weatherParameters, refresh)) return; - // request us or si units try { - this.data = await json(this.weatherParameters.forecast, { + // request us or si units using centralized safe handling + this.data = await safeJson(this.weatherParameters.forecast, { data: { units: settings.units.value, }, retryCount: 3, stillWaiting: () => this.stillWaiting(), }); - } catch (error) { - console.error('Unable to get extended forecast'); - console.error(error.status, error.responseJSON); - // if there's no previous data, fail + + // if there's no new data and no previous data, fail if (!this.data) { - this.setStatus(STATUS.failed); + // console.warn(`Unable to get extended forecast for ${this.weatherParameters.latitude},${this.weatherParameters.longitude} in ${this.weatherParameters.state}`); + if (this.isEnabled) this.setStatus(STATUS.failed); return; } + + // we only get here if there was data (new or existing) + this.screenIndex = 0; + this.setStatus(STATUS.loaded); + } catch (error) { + console.error(`Unexpected error getting Extended Forecast: ${error.message}`); + if (this.isEnabled) this.setStatus(STATUS.failed); } - // we only get here if there was no error above - this.screenIndex = 0; - this.setStatus(STATUS.loaded); } async drawCanvas() { @@ -49,7 +54,7 @@ class ExtendedForecast extends WeatherDisplay { // determine bounds // grab the first three or second set of three array elements - const forecast = parse(this.data.properties.periods).slice(0 + 3 * this.screenIndex, 3 + this.screenIndex * 3); + const forecast = parse(this.data.properties.periods, this.weatherParameters.forecast).slice(0 + 3 * this.screenIndex, 3 + this.screenIndex * 3); // create each day template const days = forecast.map((Day) => { @@ -78,19 +83,52 @@ class ExtendedForecast extends WeatherDisplay { } // the api provides the forecast in 12 hour increments, flatten to day increments with high and low temperatures -const parse = (fullForecast) => { - // create a list of days starting with today - const Days = [0, 1, 2, 3, 4, 5, 6]; +const parse = (fullForecast, forecastUrl) => { + // filter out expired periods first + const activePeriods = filterExpiredPeriods(fullForecast, forecastUrl); + if (debugFlag('extendedforecast')) { + console.log('ExtendedForecast: First few active periods:'); + activePeriods.slice(0, 4).forEach((period, index) => { + console.log(` [${index}] ${period.name}: ${period.startTime} to ${period.endTime} (isDaytime: ${period.isDaytime})`); + }); + } + + // Skip the first period if it's nighttime (like "Tonight") since extended forecast + // should focus on upcoming full days, not the end of the current day + let startIndex = 0; + let dateOffset = 0; // offset for date labels when we skip periods + + if (activePeriods.length > 0 && !activePeriods[0].isDaytime) { + startIndex = 1; + dateOffset = 1; // start date labels from tomorrow since we're skipping tonight + if (debugFlag('extendedforecast')) { + console.log(`ExtendedForecast: Skipping first period "${activePeriods[0].name}" because it's nighttime`); + } + } else if (activePeriods.length > 0) { + if (debugFlag('extendedforecast')) { + console.log(`ExtendedForecast: Starting with first period "${activePeriods[0].name}" because it's daytime`); + } + } + + // create a list of days starting with the appropriate day + const Days = [0, 1, 2, 3, 4, 5, 6]; const dates = Days.map((shift) => { - const date = DateTime.local().startOf('day').plus({ days: shift }); + const date = DateTime.local().startOf('day').plus({ days: shift + dateOffset }); return date.toLocaleString({ weekday: 'short' }); }); + if (debugFlag('extendedforecast')) { + console.log(`ExtendedForecast: Generated date labels: [${dates.join(', ')}]`); + } + // track the destination forecast index let destIndex = 0; const forecast = []; - fullForecast.forEach((period) => { + + for (let i = startIndex; i < activePeriods.length; i += 1) { + const period = activePeriods[i]; + // create the destination object if necessary if (!forecast[destIndex]) { forecast.push({ @@ -110,12 +148,21 @@ const parse = (fullForecast) => { if (period.isDaytime) { // day time is the high temperature fDay.high = period.temperature; - destIndex += 1; + // Wait for the corresponding night period to increment } else { // low temperature fDay.low = period.temperature; + // Increment after processing night period + destIndex += 1; } - }); + } + + if (debugFlag('extendedforecast')) { + console.log('ExtendedForecast: Final forecast array:'); + forecast.forEach((day, index) => { + console.log(` [${index}] ${day.dayName}: High=${day.high}°, Low=${day.low}°, Text="${day.text}"`); + }); + } return forecast; }; diff --git a/server/scripts/modules/hazards.mjs b/server/scripts/modules/hazards.mjs index 2cd1084..4010fa3 100644 --- a/server/scripts/modules/hazards.mjs +++ b/server/scripts/modules/hazards.mjs @@ -1,9 +1,11 @@ // hourly forecast list import STATUS from './status.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; +import calculateScrollTiming from './utils/scroll-timing.mjs'; +import { debugFlag } from './utils/debug.mjs'; const hazardLevels = { Extreme: 10, @@ -32,6 +34,19 @@ class Hazards extends WeatherDisplay { // take note of the already-shown alert ids this.viewedAlerts = new Set(); this.viewedGetCount = 0; + + // cache for scroll calculations + // This cache is essential because baseCountChange() is called 25 times per second (every 40ms) + // during scrolling. Hazard scrolls can vary greatly in length depending on active alerts, but + // without caching we'd perform hundreds of expensive DOM layout queries during each scroll cycle. + // The cache reduces this to one calculation when content changes, then reuses cached values to try + // and get smoother scrolling. + this.scrollCache = { + displayHeight: 0, + contentHeight: 0, + maxOffset: 0, + hazardLines: null, + }; } async getData(weatherParameters, refresh) { @@ -53,16 +68,24 @@ class Hazards extends WeatherDisplay { } try { - // get the forecast + // get the forecast using centralized safe handling const url = new URL('https://api.weather.gov/alerts/active'); url.searchParams.append('point', `${this.weatherParameters.latitude},${this.weatherParameters.longitude}`); - const alerts = await json(url, { retryCount: 3, stillWaiting: () => this.stillWaiting() }); - const allUnsortedAlerts = alerts.features ?? []; - const unsortedAlerts = allUnsortedAlerts.slice(0, 5); - const hasImmediate = unsortedAlerts.reduce((acc, hazard) => acc || hazard.properties.urgency === 'Immediate', false); - const sortedAlerts = unsortedAlerts.sort((a, b) => (calcSeverity(b.properties.severity, b.properties.event)) - (calcSeverity(a.properties.severity, a.properties.event))); - const filteredAlerts = sortedAlerts.filter((hazard) => hazard.properties.severity !== 'Unknown' && (!hasImmediate || (hazard.properties.urgency === 'Immediate'))); - this.data = filteredAlerts; + const alerts = await safeJson(url, { retryCount: 3, stillWaiting: () => this.stillWaiting() }); + + if (!alerts) { + if (debugFlag('verbose-failures')) { + console.warn('Active Alerts request failed; assuming no active alerts'); + } + this.data = []; + } else { + const allUnsortedAlerts = alerts.features ?? []; + const unsortedAlerts = allUnsortedAlerts.slice(0, 5); + const hasImmediate = unsortedAlerts.reduce((acc, hazard) => acc || hazard.properties.urgency === 'Immediate', false); + const sortedAlerts = unsortedAlerts.sort((a, b) => (calcSeverity(b.properties.severity, b.properties.event)) - (calcSeverity(a.properties.severity, a.properties.event))); + const filteredAlerts = sortedAlerts.filter((hazard) => hazard.properties.severity !== 'Unknown' && (!hasImmediate || (hazard.properties.urgency === 'Immediate'))); + this.data = filteredAlerts; + } // every 10 times through the get process (10 minutes), reset the viewed messages if (this.viewedGetCount >= 10) { @@ -82,8 +105,7 @@ class Hazards extends WeatherDisplay { // draw the canvas to calculate the new timings and activate hazards in the slide deck again this.drawLongCanvas(); } catch (error) { - console.error('Get hazards failed'); - console.error(error.status, error.responseJSON); + console.error(`Unexpected Active Alerts error: ${error.message}`); if (this.isEnabled) this.setStatus(STATUS.failed); // return undefined to other subscribers this.getDataCallback(undefined); @@ -109,8 +131,12 @@ class Hazards extends WeatherDisplay { const lines = unViewed.map((data) => { const fillValues = {}; - // text - fillValues['hazard-text'] = `${data.properties.event}

${data.properties.description.replaceAll('\n\n', '

').replaceAll('\n', ' ')}`; + const description = data.properties.description + .replaceAll('\n\n', '

') + .replaceAll('\n', ' ') + .replace(/(\S)\.\.\.(\S)/g, '$1... $2'); // Add space after ... when surrounded by non-whitespace to improve text-wrappability + + fillValues['hazard-text'] = `${data.properties.event}

${description}



`; // Add some padding to scroll off the bottom a bit return this.fillTemplate('hazard', fillValues); }); @@ -131,16 +157,16 @@ class Hazards extends WeatherDisplay { } setTiming(list) { - // set up the timing - this.timing.baseDelay = 20; - // 24 hours = 6 pages - const pages = Math.max(Math.ceil(list.scrollHeight / 480) - 4); - const timingStep = 480; - this.timing.delay = [150 + timingStep]; - // add additional pages - for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep); - // add the final 3 second delay - this.timing.delay.push(250); + const container = this.elem.querySelector('.main'); + const timingConfig = calculateScrollTiming(list, container, { + finalPause: 2.0, // shorter final pause for hazards + }); + + // Apply the calculated timing + this.timing.baseDelay = timingConfig.baseDelay; + this.timing.delay = timingConfig.delay; + this.scrollTiming = timingConfig.scrollTiming; + this.calcNavTiming(); } @@ -162,25 +188,30 @@ class Hazards extends WeatherDisplay { // base count change callback baseCountChange(count) { + // get the hazard lines element and cache measurements if needed + const hazardLines = this.elem.querySelector('.hazard-lines'); + if (!hazardLines) return; + + // update cache if needed (when content changes or first run) + if (this.scrollCache.hazardLines !== hazardLines || this.scrollCache.displayHeight === 0) { + this.scrollCache.displayHeight = this.elem.querySelector('.main').offsetHeight; + this.scrollCache.contentHeight = hazardLines.offsetHeight; + this.scrollCache.maxOffset = Math.max(0, this.scrollCache.contentHeight - this.scrollCache.displayHeight); + this.scrollCache.hazardLines = hazardLines; + + // Set up hardware acceleration on the hazard lines element + hazardLines.style.willChange = 'transform'; + hazardLines.style.backfaceVisibility = 'hidden'; + } + // calculate scroll offset and don't go past end - let offsetY = Math.min(this.elem.querySelector('.hazard-lines').offsetHeight - 390, (count - 150)); + let offsetY = Math.min(this.scrollCache.maxOffset, (count - this.scrollTiming.initialCounts) * this.scrollTiming.pixelsPerCount); // don't let offset go negative if (offsetY < 0) offsetY = 0; - // move the element - this.elem.querySelector('.main').scrollTo(0, offsetY); - } - - // make data available outside this class - // promise allows for data to be requested before it is available - async getCurrentData(stillWaiting) { - if (stillWaiting) this.stillWaitingCallbacks.push(stillWaiting); - return new Promise((resolve) => { - if (this.data) resolve(this.data); - // data not available, put it into the data callback queue - this.getDataCallbacks.push(() => resolve(this.data)); - }); + // use transform instead of scrollTo for hardware acceleration + hazardLines.style.transform = `translateY(-${Math.round(offsetY)}px)`; } // after we roll through the hazards once, don't display again until the next refresh (10 minutes) diff --git a/server/scripts/modules/hourly-graph.mjs b/server/scripts/modules/hourly-graph.mjs index e110f34..9eed947 100644 --- a/server/scripts/modules/hourly-graph.mjs +++ b/server/scripts/modules/hourly-graph.mjs @@ -31,8 +31,8 @@ class HourlyGraph extends WeatherDisplay { if (!super.getData(undefined, refresh)) return; const data = await getHourlyData(() => this.stillWaiting()); - if (data === undefined) { - this.setStatus(STATUS.failed); + if (!data) { + if (this.isEnabled) this.setStatus(STATUS.failed); return; } diff --git a/server/scripts/modules/hourly.mjs b/server/scripts/modules/hourly.mjs index adba555..faf601e 100644 --- a/server/scripts/modules/hourly.mjs +++ b/server/scripts/modules/hourly.mjs @@ -2,60 +2,70 @@ import STATUS from './status.mjs'; import { DateTime, Interval, Duration } from '../vendor/auto/luxon.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import { temperature as temperatureUnit, distanceKilometers } from './utils/units.mjs'; import { getHourlyIcon } from './icons.mjs'; import { directionToNSEW } from './utils/calc.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay, timeZone } from './navigation.mjs'; import getSun from './almanac.mjs'; +import calculateScrollTiming from './utils/scroll-timing.mjs'; +import { debugFlag } from './utils/debug.mjs'; class Hourly extends WeatherDisplay { constructor(navId, elemId, defaultActive) { // special height and width for scrolling super(navId, elemId, 'Hourly Forecast', defaultActive); - // set up the timing - this.timing.baseDelay = 20; - // 24 hours = 6 pages - const pages = 4; // first page is already displayed, last page doesn't happen - const timingStep = 75 * 4; - this.timing.delay = [150 + timingStep]; - // add additional pages - for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep); - // add the final 3 second delay - this.timing.delay.push(150); + // cache for scroll calculations + // This cache is essential because baseCountChange() is called 25 times per second (every 40ms) + // during scrolling. Without caching, we'd perform hundreds of expensive DOM layout queries during + // the full scroll cycle. The cache reduces this to one calculation when content changes, then + // reuses cached values to try and get smoother scrolling. + this.scrollCache = { + displayHeight: 0, + contentHeight: 0, + maxOffset: 0, + hourlyLines: null, + }; } async getData(weatherParameters, refresh) { // super checks for enabled const superResponse = super.getData(weatherParameters, refresh); - let forecast; + try { - // get the forecast - forecast = await json(this.weatherParameters.forecastGridData, { retryCount: 3, stillWaiting: () => this.stillWaiting() }); - // parse the forecast - this.data = await parseForecast(forecast.properties); - } catch (error) { - console.error('Get hourly forecast failed'); - console.error(error.status, error.responseJSON); - // use old data if available - if (this.data) { - console.log('Using previous hourly forecast'); - // don't return, this.data is usable from the previous update - } else { + const forecast = await safeJson(this.weatherParameters.forecastGridData, { retryCount: 3, stillWaiting: () => this.stillWaiting() }); + + if (forecast) { + try { + // parse the forecast + this.data = await parseForecast(forecast.properties); + } catch (error) { + console.error(`Hourly forecast parsing failed: ${error.message}`); + } + } else if (debugFlag('verbose-failures')) { + console.warn(`Using previous hourly forecast for ${this.weatherParameters.forecastGridData}`); + } + + // use old data if available, fail if no data at all + if (!this.data) { if (this.isEnabled) this.setStatus(STATUS.failed); // return undefined to other subscribers this.getDataCallback(undefined); return; } + + this.getDataCallback(); + if (!superResponse) return; + + this.setStatus(STATUS.loaded); + this.drawLongCanvas(); + } catch (error) { + console.error(`Unexpected error getting hourly forecast: ${error.message}`); + if (this.isEnabled) this.setStatus(STATUS.failed); + this.getDataCallback(undefined); } - - this.getDataCallback(); - if (!superResponse) return; - - this.setStatus(STATUS.loaded); - this.drawLongCanvas(); } async drawLongCanvas() { @@ -102,6 +112,9 @@ class Hourly extends WeatherDisplay { }); list.append(...lines); + + // update timing based on actual content + this.setTiming(list); } drawCanvas() { @@ -122,19 +135,35 @@ class Hourly extends WeatherDisplay { // base count change callback baseCountChange(count) { + // get the hourly lines element and cache measurements if needed + const hourlyLines = this.elem.querySelector('.hourly-lines'); + if (!hourlyLines) return; + + // update cache if needed (when content changes or first run) + if (this.scrollCache.hourlyLines !== hourlyLines || this.scrollCache.displayHeight === 0) { + this.scrollCache.displayHeight = this.elem.querySelector('.main').offsetHeight; + this.scrollCache.contentHeight = hourlyLines.offsetHeight; + this.scrollCache.maxOffset = Math.max(0, this.scrollCache.contentHeight - this.scrollCache.displayHeight); + this.scrollCache.hourlyLines = hourlyLines; + + // Set up hardware acceleration on the hourly lines element + hourlyLines.style.willChange = 'transform'; + hourlyLines.style.backfaceVisibility = 'hidden'; + } + // calculate scroll offset and don't go past end - let offsetY = Math.min(this.elem.querySelector('.hourly-lines').offsetHeight - 289, (count - 150)); + let offsetY = Math.min(this.scrollCache.maxOffset, (count - this.scrollTiming.initialCounts) * this.scrollTiming.pixelsPerCount); // don't let offset go negative if (offsetY < 0) offsetY = 0; - // copy the scrolled portion of the canvas - this.elem.querySelector('.main').scrollTo(0, offsetY); + // use transform instead of scrollTo for hardware acceleration + hourlyLines.style.transform = `translateY(-${Math.round(offsetY)}px)`; } // make data available outside this class // promise allows for data to be requested before it is available - async getCurrentData(stillWaiting) { + async getHourlyData(stillWaiting) { if (stillWaiting) this.stillWaitingCallbacks.push(stillWaiting); // an external caller has requested data, set up auto reload this.setAutoReload(); @@ -144,6 +173,18 @@ class Hourly extends WeatherDisplay { this.getDataCallbacks.push(() => resolve(this.data)); }); } + + setTiming(list) { + const container = this.elem.querySelector('.main'); + const timingConfig = calculateScrollTiming(list, container); + + // Apply the calculated timing + this.timing.baseDelay = timingConfig.baseDelay; + this.timing.delay = timingConfig.delay; + this.scrollTiming = timingConfig.scrollTiming; + + this.calcNavTiming(); + } } // extract specific values from forecast and format as an array @@ -192,7 +233,7 @@ const determineIcon = async (skyCover, weather, iceAccumulation, probabilityOfPr }; // expand a set of values with durations to an hour-by-hour array -const expand = (data) => { +const expand = (data, maxHours = 24) => { const startOfHour = DateTime.utc().startOf('hour').toMillis(); const result = []; // resulting expanded values data.forEach((item) => { @@ -202,12 +243,12 @@ const expand = (data) => { // loop through duration at one hour intervals do { // test for timestamp greater than now - if (startTime >= startOfHour && result.length < 24) { + if (startTime >= startOfHour && result.length < maxHours) { result.push(item.value); // push data array } // timestamp is after now // increment start time by 1 hour startTime += 3_600_000; - } while (startTime < endTime && result.length < 24); + } while (startTime < endTime && result.length < maxHours); }); // for each value return result; @@ -217,4 +258,4 @@ const expand = (data) => { const display = new Hourly(3, 'hourly', false); registerDisplay(display); -export default display.getCurrentData.bind(display); +export default display.getHourlyData.bind(display); diff --git a/server/scripts/modules/icons/icons-large.mjs b/server/scripts/modules/icons/icons-large.mjs index 41ec0dd..be24564 100644 --- a/server/scripts/modules/icons/icons-large.mjs +++ b/server/scripts/modules/icons/icons-large.mjs @@ -1,55 +1,65 @@ /* spell-checker: disable */ -// internal function to add path to returned icon +import parseIconUrl from './icons-parse.mjs'; + const addPath = (icon) => `images/icons/current-conditions/${icon}`; const largeIcon = (link, _isNightTime) => { - if (!link) return false; + let conditionIcon; + let probability; + let isNightTime; - // extract day or night if not provided - const isNightTime = _isNightTime ?? link.indexOf('/night/') >= 0; - - // grab everything after the last slash ending at any of these: ?&, - const afterLastSlash = link.toLowerCase().match(/[^/]+$/)[0]; - let conditionName = afterLastSlash.match(/(.*?)[&,.?]/)[1]; - // using probability as a crude heavy/light indication where possible - const value = +(link.match(/,(\d{2,3})/) ?? [0, 100])[1]; - - // if a 'DualImage' is captured, adjust to just the j parameter - if (conditionName === 'dualimage') { - const match = link.match(/&j=(.*)&/); - [, conditionName] = match; + try { + ({ conditionIcon, probability, isNightTime } = parseIconUrl(link, _isNightTime)); + } catch (error) { + console.warn(`largeIcon: ${error.message}`); + // Return a fallback icon to prevent downstream errors + return addPath(_isNightTime ? 'Clear.gif' : 'Sunny.gif'); } // find the icon - switch (conditionName + (isNightTime ? '-n' : '')) { + switch (conditionIcon + (isNightTime ? '-n' : '')) { case 'skc': case 'hot': - case 'haze': - case 'cold': return addPath('Sunny.gif'); case 'skc-n': - case 'nskc': - case 'nskc-n': + return addPath('Clear.gif'); + + case 'haze': + return addPath('Sunny.gif'); + + case 'haze-n': + return addPath('Clear.gif'); + + case 'cold': + return addPath('Sunny.gif'); + case 'cold-n': return addPath('Clear.gif'); - case 'sct': + case 'dust': + case 'dust-n': + return addPath('Smoke.gif'); + case 'few': + return addPath('Partly-Cloudy.gif'); + + case 'few-n': + return addPath('Mostly-Clear.gif'); + + case 'sct': + return addPath('Partly-Cloudy.gif'); + + case 'sct-n': + return addPath('Mostly-Clear.gif'); + case 'bkn': return addPath('Partly-Cloudy.gif'); case 'bkn-n': - case 'few-n': - case 'nfew-n': - case 'nfew': - case 'sct-n': - case 'nsct': - case 'nsct-n': return addPath('Mostly-Clear.gif'); case 'ovc': - case 'novc': case 'ovc-n': return addPath('Cloudy.gif'); @@ -70,8 +80,10 @@ const largeIcon = (link, _isNightTime) => { return addPath('Smoke.gif'); case 'rain_showers': + case 'rain_showers_hi': case 'rain_showers_high': case 'rain_showers-n': + case 'rain_showers_hi-n': case 'rain_showers_high-n': return addPath('Shower.gif'); @@ -81,10 +93,11 @@ const largeIcon = (link, _isNightTime) => { case 'snow': case 'snow-n': - if (value > 50) return addPath('Heavy-Snow.gif'); + if (probability > 50) return addPath('Heavy-Snow.gif'); return addPath('Light-Snow.gif'); case 'rain_snow': + case 'rain_snow-n': return addPath('Rain-Snow.gif'); case 'snow_fzra': @@ -98,43 +111,66 @@ const largeIcon = (link, _isNightTime) => { return addPath('Freezing-Rain.gif'); case 'snow_sleet': + case 'snow_sleet-n': return addPath('Snow-Sleet.gif'); case 'tsra_sct': - case 'tsra': return addPath('Scattered-Thunderstorms-Day.gif'); case 'tsra_sct-n': + return addPath('Scattered-Thunderstorms-Night.gif'); + + case 'tsra': + return addPath('Scattered-Thunderstorms-Day.gif'); + case 'tsra-n': return addPath('Scattered-Thunderstorms-Night.gif'); case 'tsra_hi': case 'tsra_hi-n': + return addPath('Thunderstorm.gif'); + + case 'tornado': + case 'tornado-n': + return addPath('Thunderstorm.gif'); + case 'hurricane': - case 'tropical_storm': case 'hurricane-n': + case 'tropical_storm': case 'tropical_storm-n': return addPath('Thunderstorm.gif'); - case 'wind_few': - case 'wind_sct': - case 'wind_bkn': - case 'wind_ovc': case 'wind_skc': - case 'wind_few-n': - case 'wind_bkn-n': - case 'wind_ovc-n': + return addPath('Windy.gif'); + case 'wind_skc-n': + return addPath('Windy.gif'); + + case 'wind_few': + case 'wind_few-n': + return addPath('Windy.gif'); + + case 'wind_sct': case 'wind_sct-n': return addPath('Windy.gif'); + case 'wind_bkn': + case 'wind_bkn-n': + return addPath('Windy.gif'); + + case 'wind_ovc': + case 'wind_ovc-n': + return addPath('Windy.gif'); + case 'blizzard': case 'blizzard-n': return addPath('Blowing-Snow.gif'); - default: - console.log(`Unable to locate icon for ${conditionName} ${link} ${isNightTime}`); - return false; + default: { + console.warn(`Unknown weather condition '${conditionIcon}' from ${link}; using fallback icon`); + // Return a reasonable fallback instead of false to prevent downstream errors + return addPath(isNightTime ? 'Clear.gif' : 'Sunny.gif'); + } } }; diff --git a/server/scripts/modules/icons/icons-parse.mjs b/server/scripts/modules/icons/icons-parse.mjs new file mode 100644 index 0000000..87b4a3e --- /dev/null +++ b/server/scripts/modules/icons/icons-parse.mjs @@ -0,0 +1,93 @@ +/** + * Parses weather.gov icon URLs and extracts weather condition information + * Handles both single and dual condition formats according to the weather.gov API spec + * + * NOTE: The 'icon' properties are marked as deprecated in the API documentation. This + * is because it will eventually be replaced with a more generic value that is not a URL. + */ + +import { debugFlag } from '../utils/debug.mjs'; + +/** + * Parses a weather.gov icon URL and extracts condition and timing information + * @param {string} iconUrl - Icon URL from weather.gov API (e.g., "/icons/land/day/skc?size=medium") + * @param {boolean} _isNightTime - Optional override for night time determination + * @returns {Object} Parsed icon data with conditionIcon, probability, and isNightTime + */ +const parseIconUrl = (iconUrl, _isNightTime) => { + if (!iconUrl) { + throw new Error('No icon URL provided'); + } + + // Parse icon URL according to API spec: /icons/{set}/{timeOfDay}/{condition}?{params} + // where {condition} might be single (skc) or dual (tsra_hi,20/rain,50) + // Each period will have an icon, or two if there is changing weather during that period + // see https://github.com/weather-gov/api/discussions/557#discussioncomment-9949521 + // (On the weather.gov site, changing conditions results in a "dualImage" forecast icon) + const iconUrlPattern = /\/icons\/(?\w+)\/(?day|night)\/(?[^?]+)(?:\?(?.*))?$/i; + const match = iconUrl.match(iconUrlPattern); + + if (!match?.groups) { + throw new Error(`Unable to parse icon URL format: ${iconUrl}`); + } + + const { timeOfDay, condition } = match.groups; + + // Determine if it's night time with preference strategy: + // 1. Primary: use _isNightTime parameter if provided (such as from API's isDaytime property) + // 2. Secondary: use timeOfDay parsed from URL + let isNightTime; + if (_isNightTime !== undefined) { + isNightTime = _isNightTime; + } else if (timeOfDay === 'day') { + isNightTime = false; + } else if (timeOfDay === 'night') { + isNightTime = true; + } else { + console.warn(`parseIconUrl: unexpected timeOfDay value: ${timeOfDay}`); + isNightTime = false; + } + + // Dual conditions can have a probability + // Examples: "tsra_hi,30/sct", "rain_showers,30/tsra_hi,50", "hot/tsra_hi,70" + let conditionIcon; + let probability; + if (condition.includes('/')) { // Two conditions + const conditions = condition.split('/'); + const firstCondition = conditions[0] || ''; + const secondCondition = conditions[1] || ''; + + const [firstIcon, firstProb] = firstCondition.split(','); + const [secondIcon, secondProb] = secondCondition.split(','); + + // Default to 100% probability if not specified (high confidence) + const firstProbability = parseInt(firstProb, 10) || 100; + const secondProbability = parseInt(secondProb, 10) || 100; + + if (secondIcon !== firstIcon) { + // When there's more than one condition, use the second condition + // QUESTION: should the condition with the higher probability determine which one to use? + // if (firstProbability >= secondProbability) { ... } + conditionIcon = secondIcon; + probability = secondProbability; + if (debugFlag('icons')) { + console.debug(`2️⃣ Using second condition: '${secondCondition}' instead of first '${firstCondition}'`); + } + } else { + conditionIcon = firstIcon; + probability = firstProbability; + } + } else { // Single condition + const [name, prob] = condition.split(','); + conditionIcon = name; + probability = parseInt(prob, 10) || 100; + } + + return { + conditionIcon, + probability, + isNightTime, + }; +}; + +export default parseIconUrl; diff --git a/server/scripts/modules/icons/icons-small.mjs b/server/scripts/modules/icons/icons-small.mjs index cc30d6f..0709bf0 100644 --- a/server/scripts/modules/icons/icons-small.mjs +++ b/server/scripts/modules/icons/icons-small.mjs @@ -1,52 +1,46 @@ -// internal function to add path to returned icon +import parseIconUrl from './icons-parse.mjs'; + const addPath = (icon) => `images/icons/regional-maps/${icon}`; const smallIcon = (link, _isNightTime) => { - // extract day or night if not provided - const isNightTime = _isNightTime ?? link.indexOf('/night/') >= 0; + let conditionIcon; + let probability; + let isNightTime; - // grab everything after the last slash ending at any of these: ?&, - const afterLastSlash = link.toLowerCase().match(/[^/]+$/)[0]; - let conditionName = afterLastSlash.match(/(.*?)[&,.?]/)[1]; - // using probability as a crude heavy/light indication where possible - const value = +(link.match(/,(\d{2,3})/) ?? [0, 100])[1]; - - // if a 'DualImage' is captured, adjust to just the j parameter - if (conditionName === 'dualimage') { - const match = link.match(/&j=(.*)&/); - [, conditionName] = match; + try { + ({ conditionIcon, probability, isNightTime } = parseIconUrl(link, _isNightTime)); + } catch (error) { + console.warn(`smallIcon: ${error.message}`); + // Return a fallback icon to prevent downstream errors + return addPath(_isNightTime ? 'Clear-1992.gif' : 'Sunny.gif'); } - // find the icon - switch (conditionName + (isNightTime ? '-n' : '')) { + // handle official weather.gov API condition icons + switch (conditionIcon + (isNightTime ? '-n' : '')) { case 'skc': return addPath('Sunny.gif'); case 'skc-n': - case 'nskc': - case 'nskc-n': - case 'cold-n': return addPath('Clear-1992.gif'); + case 'few': + return addPath('Partly-Cloudy.gif'); + + case 'few-n': + return addPath('Partly-Clear-1994.gif'); + + case 'sct': + return addPath('Partly-Cloudy.gif'); + + case 'sct-n': + return addPath('Partly-Cloudy-Night.gif'); + case 'bkn': return addPath('Mostly-Cloudy-1994.gif'); case 'bkn-n': - case 'few-n': - case 'nfew-n': - case 'nfew': return addPath('Partly-Clear-1994.gif'); - case 'sct': - case 'few': - return addPath('Partly-Cloudy.gif'); - - case 'sct-n': - case 'nsct': - case 'nsct-n': - case 'haze-n': - return addPath('Partly-Cloudy-Night.gif'); - case 'ovc': case 'ovc-n': return addPath('Cloudy.gif'); @@ -55,39 +49,33 @@ const smallIcon = (link, _isNightTime) => { case 'fog-n': return addPath('Fog.gif'); - case 'rain_sleet': - return addPath('Rain-Sleet.gif'); - - case 'rain_showers': - case 'rain_showers_high': - return addPath('Scattered-Showers-1994.gif'); - - case 'rain_showers-n': - case 'rain_showers_high-n': - return addPath('Scattered-Showers-Night-1994.gif'); - case 'rain': case 'rain-n': return addPath('Rain-1992.gif'); + case 'rain_showers': + return addPath('Scattered-Showers-1994.gif'); + + case 'rain_showers-n': + return addPath('Scattered-Showers-Night-1994.gif'); + + case 'rain_showers_hi': + return addPath('Scattered-Showers-1994.gif'); + + case 'rain_showers_hi-n': + return addPath('Scattered-Showers-Night-1994.gif'); + case 'snow': case 'snow-n': - if (value > 50) return addPath('Heavy-Snow-1994.gif'); + if (probability > 50) return addPath('Heavy-Snow-1994.gif'); return addPath('Light-Snow.gif'); case 'rain_snow': case 'rain_snow-n': return addPath('Rain-Snow-1992.gif'); - case 'snow_fzra': - case 'snow_fzra-n': - return addPath('Freezing-Rain-Snow-1994.gif'); - - case 'fzra': - case 'fzra-n': - case 'rain_fzra': - case 'rain_fzra-n': - return addPath('Freezing-Rain-1992.gif'); + case 'rain_sleet': + return addPath('Rain-Sleet.gif'); case 'snow_sleet': case 'snow_sleet-n': @@ -97,64 +85,97 @@ const smallIcon = (link, _isNightTime) => { case 'sleet-n': return addPath('Sleet.gif'); - case 'tsra_sct': + case 'fzra': + case 'fzra-n': + return addPath('Freezing-Rain-1992.gif'); + + case 'rain_fzra': + case 'rain_fzra-n': + return addPath('Freezing-Rain-1992.gif'); + + case 'snow_fzra': + case 'snow_fzra-n': + return addPath('Freezing-Rain-Snow-1994.gif'); + case 'tsra': return addPath('Scattered-Tstorms-1994.gif'); - case 'tsra_sct-n': case 'tsra-n': return addPath('Scattered-Tstorms-Night-1994.gif'); + case 'tsra_sct': + return addPath('Scattered-Tstorms-1994.gif'); + + case 'tsra_sct-n': + return addPath('Scattered-Tstorms-Night-1994.gif'); + case 'tsra_hi': case 'tsra_hi-n': - case 'hurricane': - case 'tropical_storm': - case 'hurricane-n': - case 'tropical_storm-n': return addPath('Thunderstorm.gif'); - case 'wind': - case 'wind_': - case 'wind_few': - case 'wind_sct': - case 'wind-n': - case 'wind_-n': - case 'wind_few-n': - return addPath('Wind.gif'); + case 'tornado': + case 'tornado-n': + return addPath('Thunderstorm.gif'); - case 'wind_bkn': - case 'wind_ovc': - case 'wind_bkn-n': - case 'wind_ovc-n': - return addPath('Cloudy-Wind.gif'); + case 'hurricane': + case 'hurricane-n': + return addPath('Thunderstorm.gif'); + + case 'tropical_storm': + case 'tropical_storm-n': + return addPath('Thunderstorm.gif'); case 'wind_skc': return addPath('Sunny-Wind-1994.gif'); case 'wind_skc-n': + return addPath('Clear-Wind-1994.gif'); + + case 'wind_few': + case 'wind_few-n': + return addPath('Wind.gif'); + + case 'wind_sct': + return addPath('Wind.gif'); + case 'wind_sct-n': return addPath('Clear-Wind-1994.gif'); - case 'blizzard': - case 'blizzard-n': - return addPath('Blowing Snow.gif'); + case 'wind_bkn': + case 'wind_bkn-n': + return addPath('Cloudy-Wind.gif'); - case 'cold': - return addPath('Cold.gif'); + case 'wind_ovc': + case 'wind_ovc-n': + return addPath('Cloudy-Wind.gif'); + + case 'dust': + case 'dust-n': + return addPath('Smoke.gif'); case 'smoke': case 'smoke-n': return addPath('Smoke.gif'); + case 'haze': + case 'haze-n': + return addPath('Haze.gif'); + case 'hot': return addPath('Hot.gif'); - case 'haze': - return addPath('Haze.gif'); + case 'cold': + case 'cold-n': + return addPath('Cold.gif'); + + case 'blizzard': + case 'blizzard-n': + return addPath('Blowing Snow.gif'); default: - console.log(`Unable to locate regional icon for ${conditionName} ${link} ${isNightTime}`); - return false; + console.warn(`Unknown weather condition '${conditionIcon}' from ${link}; using fallback icon`); + // Return a reasonable fallback instead of false to prevent downstream errors + return addPath(isNightTime ? 'Clear-1992.gif' : 'Sunny.gif'); } }; diff --git a/server/scripts/modules/latestobservations.mjs b/server/scripts/modules/latestobservations.mjs index 93e0d2e..a7e2446 100644 --- a/server/scripts/modules/latestobservations.mjs +++ b/server/scripts/modules/latestobservations.mjs @@ -1,12 +1,15 @@ // current weather conditions display import { distance as calcDistance, directionToNSEW } from './utils/calc.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson, safePromiseAll } from './utils/fetch.mjs'; import STATUS from './status.mjs'; import { locationCleanup } from './utils/string.mjs'; import { temperature, windSpeed } from './utils/units.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; +import augmentObservationWithMetar from './utils/metar.mjs'; import settings from './settings.mjs'; +import { debugFlag } from './utils/debug.mjs'; +import { enhanceObservationWithMapClick } from './utils/mapclick.mjs'; class LatestObservations extends WeatherDisplay { constructor(navId, elemId) { @@ -32,14 +35,17 @@ class LatestObservations extends WeatherDisplay { // try up to 30 regional stations const regionalStations = sortedStations.slice(0, 30); - // get data for regional stations - // get first 7 stations + // Fetch stations sequentially in batches to avoid unnecessary API calls. + // We start with the 7 closest stations and only fetch more if some fail, + // stopping as soon as we have 7 valid stations with data. const actualConditions = []; let lastStation = Math.min(regionalStations.length, 7); let firstStation = 0; while (actualConditions.length < 7 && (lastStation) <= regionalStations.length) { + // Sequential fetching is intentional here - we want to try closest stations first + // and only fetch additional batches if needed, rather than hitting all 30 stations at once // eslint-disable-next-line no-await-in-loop - const someStations = await getStations(regionalStations.slice(firstStation, lastStation)); + const someStations = await this.getStations(regionalStations.slice(firstStation, lastStation)); actualConditions.push(...someStations); // update counters @@ -58,6 +64,79 @@ class LatestObservations extends WeatherDisplay { this.setStatus(STATUS.loaded); } + // This is a class method because it needs access to the instance's `stillWaiting` method + async getStations(stations) { + // Use centralized safe Promise handling to avoid unhandled AbortError rejections + const stationData = await safePromiseAll(stations.map(async (station) => { + try { + const data = await safeJson(`https://api.weather.gov/stations/${station.id}/observations/latest`, { + retryCount: 1, + stillWaiting: () => this.stillWaiting(), + }); + + if (!data) { + if (debugFlag('verbose-failures')) { + console.log(`Failed to get Latest Observations for station ${station.id}`); + } + return false; + } + + // Enhance observation data with METAR parsing for missing fields + const originalData = { ...data.properties }; + data.properties = augmentObservationWithMetar(data.properties); + const metarFields = [ + { name: 'temperature', check: (orig, metar) => orig.temperature.value === null && metar.temperature.value !== null }, + { name: 'windSpeed', check: (orig, metar) => orig.windSpeed.value === null && metar.windSpeed.value !== null }, + { name: 'windDirection', check: (orig, metar) => orig.windDirection.value === null && metar.windDirection.value !== null }, + ]; + const augmentedData = data.properties; + const metarReplacements = metarFields.filter((field) => field.check(originalData, augmentedData)).map((field) => field.name); + if (debugFlag('latestobservations') && metarReplacements.length > 0) { + console.log(`Latest Observations for station ${station.id} were augmented with METAR data for ${metarReplacements.join(', ')}`); + } + + // test data quality + const requiredFields = [ + { name: 'temperature', check: (props) => props.temperature?.value === null }, + { name: 'windSpeed', check: (props) => props.windSpeed?.value === null }, + { name: 'windDirection', check: (props) => props.windDirection?.value === null }, + { name: 'textDescription', check: (props) => props.textDescription === null || props.textDescription === '' }, + ]; + + // Use enhanced observation with MapClick fallback + const enhancedResult = await enhanceObservationWithMapClick(data.properties, { + requiredFields, + stationId: station.id, + stillWaiting: () => this.stillWaiting(), + debugContext: 'latestobservations', + }); + + data.properties = enhancedResult.data; + const { missingFields } = enhancedResult; + + // Check final data quality + if (missingFields.length > 0) { + if (debugFlag('latestobservations')) { + console.log(`Latest Observations for station ${station.id} is missing fields: ${missingFields.join(', ')}`); + } + return false; + } + + // format the return values + return { + ...data.properties, + StationId: station.id, + city: station.city, + }; + } catch (error) { + console.error(`Unexpected error getting latest observations for station ${station.id}: ${error.message}`); + return false; + } + })); + // filter false (no data or other error) + return stationData.filter((d) => d); + } + async drawCanvas() { super.drawCanvas(); const conditions = this.data; @@ -106,6 +185,7 @@ class LatestObservations extends WeatherDisplay { this.finishDraw(); } } + const shortenCurrentConditions = (_condition) => { let condition = _condition; condition = condition.replace(/Light/, 'L'); @@ -124,28 +204,5 @@ const shortenCurrentConditions = (_condition) => { condition = condition.replace(/ with /, '/'); return condition; }; - -const getStations = async (stations) => { - const stationData = await Promise.all(stations.map(async (station) => { - try { - const data = await json(`https://api.weather.gov/stations/${station.id}/observations/latest`, { retryCount: 1, stillWaiting: () => this.stillWaiting() }); - // test for temperature, weather and wind values present - if (data.properties.temperature.value === null - || data.properties.textDescription === '' - || data.properties.windSpeed.value === null) return false; - // format the return values - return { - ...data.properties, - StationId: station.id, - city: station.city, - }; - } catch { - console.log(`Unable to get latest observations for ${station.id}`); - return false; - } - })); - // filter false (no data or other error) - return stationData.filter((d) => d); -}; // register display registerDisplay(new LatestObservations(2, 'latest-observations')); diff --git a/server/scripts/modules/localforecast.mjs b/server/scripts/modules/localforecast.mjs index da02279..e305714 100644 --- a/server/scripts/modules/localforecast.mjs +++ b/server/scripts/modules/localforecast.mjs @@ -1,17 +1,21 @@ // display text based local forecast import STATUS from './status.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; import settings from './settings.mjs'; +import filterExpiredPeriods from './utils/forecast-utils.mjs'; +import { debugFlag } from './utils/debug.mjs'; class LocalForecast extends WeatherDisplay { + static BASE_FORECAST_DURATION_MS = 5000; // Base duration (in ms) for a standard 3-5 line forecast page + constructor(navId, elemId) { super(navId, elemId, 'Local Forecast', true); // set timings - this.timing.baseDelay = 5000; + this.timing.baseDelay = LocalForecast.BASE_FORECAST_DURATION_MS; } async getData(weatherParameters, refresh) { @@ -22,13 +26,13 @@ class LocalForecast extends WeatherDisplay { // check for data, or if there's old data available if (!rawData && !this.data) { // fail for no old or new data - this.setStatus(STATUS.failed); + if (this.isEnabled) this.setStatus(STATUS.failed); return; } // store the data this.data = rawData || this.data; - // parse raw data - const conditions = parse(this.data); + // parse raw data and filter out expired periods + const conditions = parse(this.data, this.weatherParameters.forecast); // read each text this.screenTexts = conditions.map((condition) => { @@ -46,34 +50,32 @@ class LocalForecast extends WeatherDisplay { forecastsElem.innerHTML = ''; forecastsElem.append(...templates); - // increase each forecast height to a multiple of container height + // Get page height for screen calculations this.pageHeight = forecastsElem.parentNode.offsetHeight; - templates.forEach((forecast) => { - const newHeight = Math.ceil(forecast.scrollHeight / this.pageHeight) * this.pageHeight; - forecast.style.height = `${newHeight}px`; - }); - this.timing.totalScreens = forecastsElem.scrollHeight / this.pageHeight; + this.calculateContentAwareTiming(templates); + this.calcNavTiming(); + this.setStatus(STATUS.loaded); } // get the unformatted data (also used by extended forecast) async getRawData(weatherParameters) { - // request us or si units - try { - return await json(weatherParameters.forecast, { - data: { - units: settings.units.value, - }, - retryCount: 3, - stillWaiting: () => this.stillWaiting(), - }); - } catch (error) { - console.error(`GetWeatherForecast failed: ${weatherParameters.forecast}`); - console.error(error.status, error.responseJSON); + // request us or si units using centralized safe handling + const data = await safeJson(weatherParameters.forecast, { + data: { + units: settings.units.value, + }, + retryCount: 3, + stillWaiting: () => this.stillWaiting(), + }); + + if (!data) { return false; } + + return data; } async drawCanvas() { @@ -84,14 +86,180 @@ class LocalForecast extends WeatherDisplay { this.finishDraw(); } + + // calculate dynamic timing based on height measurement template approach + calculateContentAwareTiming(templates) { + if (!templates || templates.length === 0) { + this.timing.delay = 1; // fallback to single delay if no templates + return; + } + + // Use the original base duration constant for timing calculations + const originalBaseDuration = LocalForecast.BASE_FORECAST_DURATION_MS; + this.timing.baseDelay = 250; // use 250ms per count for precise timing control + + // Get line height from CSS for accurate calculations + const sampleForecast = templates[0]; + const computedStyle = window.getComputedStyle(sampleForecast); + const lineHeight = parseInt(computedStyle.lineHeight, 10); + + // Calculate the actual width that forecast text uses + // Use the forecast container that's already been set up + const forecastContainer = this.elem.querySelector('.local-forecast .container'); + let effectiveWidth; + + if (!forecastContainer) { + console.error('LocalForecast: Could not find forecast container for width calculation, using fallback width'); + effectiveWidth = 492; // "magic number" from manual calculations as fallback + } else { + const containerStyle = window.getComputedStyle(forecastContainer); + const containerWidth = forecastContainer.offsetWidth; + const paddingLeft = parseInt(containerStyle.paddingLeft, 10) || 0; + const paddingRight = parseInt(containerStyle.paddingRight, 10) || 0; + effectiveWidth = containerWidth - paddingLeft - paddingRight; + + if (debugFlag('localforecast')) { + console.log(`LocalForecast: Using measurement width of ${effectiveWidth}px (container=${containerWidth}px, padding=${paddingLeft}+${paddingRight}px)`); + } + } + + // Measure each forecast period to get actual line counts + const forecastLineCounts = []; + templates.forEach((template, index) => { + const currentHeight = template.offsetHeight; + const currentLines = Math.round(currentHeight / lineHeight); + + if (currentLines > 7) { + // Multi-page forecasts measure correctly, so use the measurement directly + forecastLineCounts.push(currentLines); + + if (debugFlag('localforecast')) { + console.log(`LocalForecast: Forecast ${index} measured ${currentLines} lines (${currentHeight}px direct measurement, ${lineHeight}px line-height)`); + } + } else { + // If may be 7 lines or less, we need to pad the content to ensure proper height measurement + // Short forecasts are capped by CSS min-height: 280px (7 lines) + // Add 7
tags to force height beyond the minimum, then subtract the padding + const originalHTML = template.innerHTML; + const paddingBRs = '
'.repeat(7); + template.innerHTML = originalHTML + paddingBRs; + + // Measure the padded height + const paddedHeight = template.offsetHeight; + const paddedLines = Math.round(paddedHeight / lineHeight); + + // Calculate actual content lines by subtracting the 7 BR lines we added + const actualLines = Math.max(1, paddedLines - 7); + + // Restore original content + template.innerHTML = originalHTML; + + forecastLineCounts.push(actualLines); + + if (debugFlag('localforecast')) { + console.log(`LocalForecast: Forecast ${index} measured ${actualLines} lines (${paddedHeight}px with padding - ${7 * lineHeight}px = ${actualLines * lineHeight}px actual, ${lineHeight}px line-height)`); + } + } + }); + + // Apply height padding for proper scrolling display (keep existing system working) + templates.forEach((forecast) => { + const newHeight = Math.ceil(forecast.offsetHeight / this.pageHeight) * this.pageHeight; + forecast.style.height = `${newHeight}px`; + }); + + // Calculate total screens based on padded height (for navigation system) + const forecastsElem = templates[0].parentNode; + const totalHeight = forecastsElem.scrollHeight; + this.timing.totalScreens = Math.round(totalHeight / this.pageHeight); + + // Now calculate timing based on actual measured line counts, ignoring padding + const maxLinesPerScreen = 7; // 280px / 40px line height + const screenTimings = []; forecastLineCounts.forEach((lines, forecastIndex) => { + if (lines <= maxLinesPerScreen) { + // Single screen for this forecast + screenTimings.push({ forecastIndex, lines, type: 'single' }); + } else { + // Multiple screens for this forecast + let remainingLines = lines; + let isFirst = true; + + while (remainingLines > 0) { + const linesThisScreen = Math.min(remainingLines, maxLinesPerScreen); + const type = isFirst ? 'first-of-multi' : 'remainder'; + + screenTimings.push({ forecastIndex, lines: linesThisScreen, type }); + + remainingLines -= linesThisScreen; + isFirst = false; + } + } + }); + + // Create timing array based on measured line counts + const screenDelays = screenTimings.map((screenInfo, screenIndex) => { + const screenLines = screenInfo.lines; + + // Apply timing rules based on actual screen content lines + let timingMultiplier; + if (screenLines === 1) { + timingMultiplier = 0.6; // 1 line = shortest (3.0s at normal speed) + } else if (screenLines === 2) { + timingMultiplier = 0.8; // 2 lines = shorter (4.0s at normal speed) + } else if (screenLines >= 6) { + timingMultiplier = 1.4; // 6+ lines = longer (7.0s at normal speed) + } else { + timingMultiplier = 1.0; // 3-5 lines = normal (5.0s at normal speed) + } + + // Convert to base counts + const desiredDurationMs = timingMultiplier * originalBaseDuration; + const baseCounts = Math.round(desiredDurationMs / this.timing.baseDelay); + + if (debugFlag('localforecast')) { + console.log(`LocalForecast: Screen ${screenIndex}: ${screenLines} lines, ${timingMultiplier.toFixed(2)}x multiplier, ${desiredDurationMs}ms desired, ${baseCounts} counts (forecast ${screenInfo.forecastIndex}, ${screenInfo.type})`); + } + + return baseCounts; + }); + + // Adjust timing array to match actual screen count if needed + while (screenDelays.length < this.timing.totalScreens) { + // Add fallback timing for extra screens + const fallbackCounts = Math.round(originalBaseDuration / this.timing.baseDelay); + screenDelays.push(fallbackCounts); + console.warn(`LocalForecast: using fallback timing for Screen ${screenDelays.length - 1}: 5 lines, 1.00x multiplier, ${fallbackCounts} counts`); + } + + // Truncate if we have too many calculated screens + if (screenDelays.length > this.timing.totalScreens) { + const removed = screenDelays.splice(this.timing.totalScreens); + console.warn(`LocalForecast: Truncated ${removed.length} excess screen timings`); + } + + // Set the timing array based on screen content + this.timing.delay = screenDelays; + + if (debugFlag('localforecast')) { + console.log(`LocalForecast: Final screen count - calculated: ${screenTimings.length}, actual: ${this.timing.totalScreens}, timing array: ${screenDelays.length}`); + const multipliers = screenDelays.map((counts) => counts * this.timing.baseDelay / originalBaseDuration); + console.log('LocalForecast: Screen multipliers:', multipliers); + console.log('LocalForecast: Expected durations (ms):', screenDelays.map((counts) => counts * this.timing.baseDelay)); + } + } } // format the forecast -// only use the first 6 lines -const parse = (forecast) => forecast.properties.periods.slice(0, 6).map((text) => ({ - // format day and text - DayName: text.name.toUpperCase(), - Text: text.detailedForecast, -})); +// filter out expired periods, then use the first 6 forecasts +const parse = (forecast, forecastUrl) => { + const allPeriods = forecast.properties.periods; + const activePeriods = filterExpiredPeriods(allPeriods, forecastUrl); + + return activePeriods.slice(0, 6).map((text) => ({ + // format day and text + DayName: text.name.toUpperCase(), + Text: text.detailedForecast, + })); +}; // register display registerDisplay(new LocalForecast(7, 'local-forecast')); diff --git a/server/scripts/modules/media.mjs b/server/scripts/modules/media.mjs index 353451e..f928958 100644 --- a/server/scripts/modules/media.mjs +++ b/server/scripts/modules/media.mjs @@ -40,21 +40,32 @@ const scanMusicDirectory = async () => { }; const getMedia = async () => { + let playlistSource = ''; + try { const response = await fetch('playlist.json'); if (response.ok) { playlist = await response.json(); - } else if (response.status === 404 - && response.headers.get('X-Weatherstar') === 'true') { - console.warn("Couldn't get playlist.json, falling back to directory scan"); + playlistSource = 'from server'; + } else if (response.status === 404 && response.headers.get('X-Weatherstar') === 'true') { + // Expected behavior in static deployment mode playlist = await scanMusicDirectory(); + playlistSource = 'via directory scan (static deployment)'; } else { - console.warn(`Couldn't get playlist.json: ${response.status} ${response.statusText}`); playlist = { availableFiles: [] }; + playlistSource = `failed (${response.status} ${response.statusText})`; } - } catch (e) { - console.warn("Couldn't get playlist.json, falling back to directory scan"); + } catch (_e) { + // Network error or other fetch failure - fall back to directory scanning playlist = await scanMusicDirectory(); + playlistSource = 'via directory scan (after fetch failed)'; + } + + const fileCount = playlist?.availableFiles?.length || 0; + if (fileCount > 0) { + console.log(`Loaded playlist ${playlistSource} - found ${fileCount} music file${fileCount === 1 ? '' : 's'}`); + } else { + console.log(`No music files found ${playlistSource}`); } enableMediaPlayer(); diff --git a/server/scripts/modules/navigation.mjs b/server/scripts/modules/navigation.mjs index f252b5d..1fe9e9c 100644 --- a/server/scripts/modules/navigation.mjs +++ b/server/scripts/modules/navigation.mjs @@ -2,8 +2,9 @@ import noSleep from './utils/nosleep.mjs'; import STATUS from './status.mjs'; import { wrap } from './utils/calc.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import { getPoint } from './utils/weather.mjs'; +import { debugFlag } from './utils/debug.mjs'; import settings from './settings.mjs'; document.addEventListener('DOMContentLoaded', () => { @@ -16,8 +17,36 @@ let progress; const weatherParameters = {}; const init = async () => { - // set up resize handler - window.addEventListener('resize', resize); + // set up the resize handler with debounce logic to prevent rapid-fire calls + let resizeTimeout; + + // Handle fullscreen change events and trigger an immediate resize calculation + const fullscreenEvents = ['fullscreenchange', 'webkitfullscreenchange', 'mozfullscreenchange', 'MSFullscreenChange']; + fullscreenEvents.forEach((eventName) => { + document.addEventListener(eventName, () => { + if (debugFlag('fullscreen')) { + console.log(`🖥️ ${eventName} event fired. fullscreenElement=${!!document.fullscreenElement}`); + } + resize(true); + }); + }); + + // De-bounced resize handler to prevent rapid-fire resize calls + window.addEventListener('resize', () => { + clearTimeout(resizeTimeout); + resizeTimeout = setTimeout(() => resize(), 100); + }); + + // Handle orientation changes (Mobile Safari doesn't always fire resize events on orientation change) + window.addEventListener('orientationchange', () => { + if (debugFlag('resize')) { + console.log('📱 Orientation change detected, forcing resize after short delay'); + } + clearTimeout(resizeTimeout); + // Use a slightly longer delay for orientation changes to allow the browser to settle + resizeTimeout = setTimeout(() => resize(true), 200); + }); + resize(); generateCheckboxes(); @@ -34,62 +63,87 @@ const getWeather = async (latLon, haveDataCallback) => { // get initial weather data const point = await getPoint(latLon.lat, latLon.lon); + // check if point data was successfully retrieved + if (!point) { + return; + } + if (typeof haveDataCallback === 'function') haveDataCallback(point); - // get stations - const stations = await json(point.properties.observationStations); + try { + // get stations using centralized safe handling + const stations = await safeJson(point.properties.observationStations); - const StationId = stations.features[0].properties.stationIdentifier; + if (!stations) { + console.warn('Failed to get Observation Stations'); + return; + } - let { city } = point.properties.relativeLocation.properties; - const { state } = point.properties.relativeLocation.properties; + // check if stations data is valid + if (!stations || !stations.features || stations.features.length === 0) { + console.warn('No Observation Stations found for this location'); + return; + } - if (StationId in StationInfo) { - city = StationInfo[StationId].city; - [city] = city.split('/'); - city = city.replace(/\s+$/, ''); + const StationId = stations.features[0].properties.stationIdentifier; + + let { city } = point.properties.relativeLocation.properties; + const { state } = point.properties.relativeLocation.properties; + + if (StationId in StationInfo) { + city = StationInfo[StationId].city; + [city] = city.split('/'); + city = city.replace(/\s+$/, ''); + } + + // populate the weather parameters + weatherParameters.latitude = latLon.lat; + weatherParameters.longitude = latLon.lon; + weatherParameters.zoneId = point.properties.forecastZone.substr(-6); + weatherParameters.radarId = point.properties.radarStation.substr(-3); + weatherParameters.stationId = StationId; + weatherParameters.weatherOffice = point.properties.cwa; + weatherParameters.city = city; + weatherParameters.state = state; + weatherParameters.timeZone = point.properties.timeZone; + weatherParameters.forecast = point.properties.forecast; + weatherParameters.forecastGridData = point.properties.forecastGridData; + weatherParameters.stations = stations.features; + + // update the main process for display purposes + populateWeatherParameters(weatherParameters); + + // reset the scroll + postMessage({ type: 'current-weather-scroll', method: 'reload' }); + + // draw the progress canvas and hide others + hideAllCanvases(); + if (!settings?.kiosk?.value) { + // In normal mode, hide loading screen and show progress + // (In kiosk mode, keep the loading screen visible until autoplay starts) + document.querySelector('#loading').style.display = 'none'; + if (progress) { + await progress.drawCanvas(); + progress.showCanvas(); + } + } + + // call for new data on each display + displays.forEach((display) => display.getData(weatherParameters)); + } catch (error) { + console.error(`Failed to get weather data: ${error.message}`); } - - // populate the weather parameters - weatherParameters.latitude = latLon.lat; - weatherParameters.longitude = latLon.lon; - weatherParameters.zoneId = point.properties.forecastZone.substr(-6); - weatherParameters.radarId = point.properties.radarStation.substr(-3); - weatherParameters.stationId = StationId; - weatherParameters.weatherOffice = point.properties.cwa; - weatherParameters.city = city; - weatherParameters.state = state; - weatherParameters.timeZone = point.properties.timeZone; - weatherParameters.forecast = point.properties.forecast; - weatherParameters.forecastGridData = point.properties.forecastGridData; - weatherParameters.stations = stations.features; - - // update the main process for display purposes - populateWeatherParameters(weatherParameters); - - // reset the scroll - postMessage({ type: 'current-weather-scroll', method: 'reload' }); - - // draw the progress canvas and hide others - hideAllCanvases(); - document.querySelector('#loading').style.display = 'none'; - if (progress) { - await progress.drawCanvas(); - progress.showCanvas(); - } - - // call for new data on each display - displays.forEach((display) => display.getData(weatherParameters)); }; // receive a status update from a module {id, value} const updateStatus = (value) => { if (value.id < 0) return; - if (!progress) return; - progress.drawCanvas(displays, countLoadedDisplays()); + if (!progress && !settings?.kiosk?.value) return; + + if (progress) progress.drawCanvas(displays, countLoadedDisplays()); // first display is hazards and it must load before evaluating the first display - if (displays[0].status === STATUS.loading) return; + if (!displays[0] || displays[0].status === STATUS.loading) return; // calculate first enabled display const firstDisplayIndex = displays.findIndex((display) => display?.enabled && display?.timing?.totalScreens > 0); @@ -102,7 +156,7 @@ const updateStatus = (value) => { } // if hazards data arrives after the firstDisplayIndex loads, then we need to hot wire this to the first display - if (value.id === 0 && value.status === STATUS.loaded && displays[0].timing.totalScreens === 0) { + if (value.id === 0 && value.status === STATUS.loaded && displays[0] && displays[0].timing && displays[0].timing.totalScreens === 0) { value.id = firstDisplayIndex; value.status = displays[firstDisplayIndex].status; } @@ -153,19 +207,30 @@ const displayNavMessage = (myMessage) => { const navTo = (direction) => { // test for a current display const current = currentDisplay(); - progress.hideCanvas(); + if (progress) progress.hideCanvas(); if (!current) { // special case for no active displays (typically on progress screen) // find the first ready display let firstDisplay; let displayCount = 0; do { - if (displays[displayCount].status === STATUS.loaded && displays[displayCount].timing.totalScreens > 0) firstDisplay = displays[displayCount]; + // Check if displayCount is within bounds and the display exists + if (displayCount < displays.length && displays[displayCount]) { + const display = displays[displayCount]; + if (display.status === STATUS.loaded && display.timing?.totalScreens > 0) { + firstDisplay = display; + } + } displayCount += 1; } while (!firstDisplay && displayCount < displays.length); if (!firstDisplay) return; + // In kiosk mode, hide the loading screen when we start showing the first display + if (settings?.kiosk?.value) { + document.querySelector('#loading').style.display = 'none'; + } + firstDisplay.navNext(msg.command.firstFrame); firstDisplay.showCanvas(); return; @@ -179,11 +244,32 @@ const loadDisplay = (direction) => { const totalDisplays = displays.length; const curIdx = currentDisplayIndex(); let idx; + let foundSuitableDisplay = false; + for (let i = 0; i < totalDisplays; i += 1) { // convert form simple 0-10 to start at current display index +/-1 and wrap idx = wrap(curIdx + (i + 1) * direction, totalDisplays); - if (displays[idx].status === STATUS.loaded && displays[idx].timing.totalScreens > 0) break; + if (displays[idx].status === STATUS.loaded && displays[idx].timing.totalScreens > 0) { + // Prevent infinite recursion by ensuring we don't select the same display + if (idx !== curIdx) { + foundSuitableDisplay = true; + break; + } + } } + + // If no other suitable display was found, but current display is still suitable (e.g. user only enabled one display), stay on it + if (!foundSuitableDisplay && displays[curIdx] && displays[curIdx].status === STATUS.loaded && displays[curIdx].timing.totalScreens > 0) { + idx = curIdx; + foundSuitableDisplay = true; + } + + // if no suitable display was found at all, do NOT proceed to avoid infinite recursion + if (!foundSuitableDisplay) { + console.warn('No suitable display found for navigation'); + return; + } + const newDisplay = displays[idx]; // hide all displays hideAllCanvases(); @@ -202,17 +288,24 @@ const setPlaying = (newValue) => { localStorage.setItem('play', playing); if (playing) { - noSleep(true); + noSleep(true).catch(() => { + // Wake lock failed, but continue normally + }); playButton.title = 'Pause'; playButton.src = 'images/nav/ic_pause_white_24dp_2x.png'; } else { - noSleep(false); + noSleep(false).catch(() => { + // Wake lock disable failed, but continue normally + }); playButton.title = 'Play'; playButton.src = 'images/nav/ic_play_arrow_white_24dp_2x.png'; } - // if we're playing and on the progress screen jump to the next screen - if (!progress) return; - if (playing && !currentDisplay()) navTo(msg.command.firstFrame); + // if we're playing and on the progress screen (or in kiosk mode), jump to the next screen + if (playing && !currentDisplay()) { + if (progress || settings?.kiosk?.value) { + navTo(msg.command.firstFrame); + } + } }; // handle all navigation buttons @@ -237,7 +330,12 @@ const handleNavButton = (button) => { break; case 'menu': setPlaying(false); - progress.showCanvas(); + if (progress) { + progress.showCanvas(); + } else if (settings?.kiosk?.value) { + // In kiosk mode without progress, show the loading screen + document.querySelector('#loading').style.display = 'flex'; + } hideAllCanvases(); break; default: @@ -248,18 +346,222 @@ const handleNavButton = (button) => { // return the specificed display const getDisplay = (index) => displays[index]; -// resize the container on a page resize -const resize = () => { - const targetWidth = settings.wide.value ? 640 + 107 + 107 : 640; - const widthZoomPercent = (document.querySelector('#divTwcBottom').getBoundingClientRect().width) / targetWidth; - const heightZoomPercent = (window.innerHeight) / 480; +// Helper function to detect iOS (using technique from nosleep.js) +const isIOS = () => { + const { userAgent } = navigator; + const iOSRegex = /CPU.*OS ([0-9_]{1,})[0-9_]{0,}|(CPU like).*AppleWebKit.*Mobile/i; + return iOSRegex.test(userAgent) && !window.MSStream; +}; - const scale = Math.min(widthZoomPercent, heightZoomPercent); - if (scale < 1.0 || document.fullscreenElement || settings.kiosk) { - document.querySelector('#container').style.zoom = scale; - } else { - document.querySelector('#container').style.zoom = 'unset'; +// Track the last applied scale to avoid redundant operations +let lastAppliedScale = null; +let lastAppliedKioskMode = null; + +// resize the container on a page resize +const resize = (force = false) => { + // Ignore resize events caused by pinch-to-zoom on mobile + if (window.visualViewport && Math.abs(window.visualViewport.scale - 1) > 0.01) { + return; } + + const isFullscreen = !!document.fullscreenElement; + const isKioskMode = settings.kiosk?.value || false; + const isMobileSafariKiosk = isIOS() && isKioskMode; // Detect Mobile Safari in kiosk mode (regardless of standalone status) + const targetWidth = settings.wide.value ? 640 + 107 + 107 : 640; + + // Use window width instead of bottom container width to avoid zero-dimension issues + const widthZoomPercent = window.innerWidth / targetWidth; + const heightZoomPercent = window.innerHeight / 480; + + // Standard scaling: fit within both dimensions + const scale = Math.min(widthZoomPercent, heightZoomPercent); + + // For Mobile Safari in kiosk mode, always use centering behavior regardless of scale + // For other platforms, only use fullscreen/centering behavior for actual fullscreen or kiosk mode where content fits naturally + const isKioskLike = isFullscreen || (isKioskMode && scale >= 1.0) || isMobileSafariKiosk; + + if (debugFlag('resize') || debugFlag('fullscreen')) { + console.log(`🖥️ Resize: force=${force} isKioskLike=${isKioskLike} window=${window.innerWidth}x${window.innerHeight} targetWidth=${targetWidth} widthZoom=${widthZoomPercent.toFixed(3)} heightZoom=${heightZoomPercent.toFixed(3)} finalScale=${scale.toFixed(3)} fullscreenElement=${!!document.fullscreenElement} isIOS=${isIOS()} standalone=${window.navigator.standalone} isMobileSafariKiosk=${isMobileSafariKiosk} kioskMode=${settings.kiosk?.value} wideMode=${settings.wide.value}`); + } + + // Prevent zero or negative scale values + if (scale <= 0) { + console.warn('Invalid scale calculated, skipping resize'); + return; + } + + // Skip redundant resize operations if scale and mode haven't changed (unless forced) + const scaleChanged = Math.abs((lastAppliedScale || 0) - scale) > 0.001; + const modeChanged = lastAppliedKioskMode !== isKioskLike; + + if (!force && !scaleChanged && !modeChanged) { + return; // No meaningful change, skip resize operation + } + + // Update tracking variables + lastAppliedScale = scale; + lastAppliedKioskMode = isKioskLike; + window.currentScale = scale; // Make scale available to settings module + + const wrapper = document.querySelector('#divTwc'); + const mainContainer = document.querySelector('#divTwcMain'); + + // BASELINE: content fits naturally, no scaling needed + if (!isKioskLike && scale >= 1.0 && !isKioskMode) { + if (debugFlag('fullscreen')) { + console.log('🖥️ Resetting fullscreen/kiosk styles to normal'); + } + + // Reset wrapper styles (only properties that are actually set in fullscreen/scaling modes) + wrapper.style.removeProperty('width'); + wrapper.style.removeProperty('height'); + wrapper.style.removeProperty('overflow'); + wrapper.style.removeProperty('transform'); + wrapper.style.removeProperty('transform-origin'); + + // Reset container styles that might have been applied during fullscreen + mainContainer.style.removeProperty('transform'); + mainContainer.style.removeProperty('transform-origin'); + mainContainer.style.removeProperty('width'); + mainContainer.style.removeProperty('height'); + mainContainer.style.removeProperty('position'); + mainContainer.style.removeProperty('left'); + mainContainer.style.removeProperty('top'); + mainContainer.style.removeProperty('margin-left'); + mainContainer.style.removeProperty('margin-top'); + + applyScanlineScaling(1.0); + return; + } + + // MOBILE SCALING: Use wrapper scaling for mobile devices (but not Mobile Safari kiosk mode) + if ((scale < 1.0 || (isKioskMode && !isKioskLike)) && !isMobileSafariKiosk) { + /* + * MOBILE SCALING (Wrapper Scaling) + * + * Why scale the wrapper instead of mainContainer? + * - For mobile devices where content is larger than viewport, we need to scale the entire layout + * - The wrapper (#divTwc) contains both the main content AND the bottom navigation bar + * - Scaling the wrapper ensures both elements are scaled together as a unit + * - No centering is applied - content aligns to top-left for typical mobile behavior + * - Uses explicit dimensions to prevent layout issues and eliminate gaps after scaling + */ + wrapper.style.setProperty('transform', `scale(${scale})`); + wrapper.style.setProperty('transform-origin', 'top left'); // Scale from top-left corner + + // Set explicit dimensions to prevent layout issues on mobile + const wrapperWidth = settings.wide.value ? 854 : 640; + // Calculate total height: main content (480px) + bottom navigation bar + const bottomBar = document.querySelector('#divTwcBottom'); + const bottomBarHeight = bottomBar ? bottomBar.offsetHeight : 40; // fallback to ~40px + const totalHeight = 480 + bottomBarHeight; + const scaledHeight = totalHeight * scale; // Height after scaling + + wrapper.style.setProperty('width', `${wrapperWidth}px`); + wrapper.style.setProperty('height', `${scaledHeight}px`); // Use scaled height to eliminate gap + applyScanlineScaling(scale); + return; + } + + // KIOSK/FULLSCREEN SCALING: Two different positioning approaches for different platforms + const wrapperWidth = settings.wide.value ? 854 : 640; + const wrapperHeight = 480; + + // Reset wrapper styles to avoid double scaling (wrapper remains unstyled) + wrapper.style.removeProperty('width'); + wrapper.style.removeProperty('height'); + wrapper.style.removeProperty('transform'); + wrapper.style.removeProperty('transform-origin'); + + // Platform-specific positioning logic + let transformOrigin; + let leftPosition; + let topPosition; + let marginLeft; + let marginTop; + + if (isMobileSafariKiosk) { + /* + * MOBILE SAFARI KIOSK MODE (Manual offset calculation) + * + * Why this approach? + * - Mobile Safari in kiosk mode has unique viewport behaviors that don't work well with standard CSS centering + * - We want orientation-specific centering: vertical in portrait, horizontal in landscape + * - The standard CSS centering method can cause layout issues in Mobile Safari's constrained environment + */ + const scaledWidth = wrapperWidth * scale; + const scaledHeight = wrapperHeight * scale; + + // Determine if we're in portrait or landscape + const isPortrait = window.innerHeight > window.innerWidth; + + let offsetX = 0; + let offsetY = 0; + + if (isPortrait) { + offsetY = (window.innerHeight - scaledHeight) / 2; // center vertically, align to left edge + } else { + offsetX = (window.innerWidth - scaledWidth) / 2; // center horizontally, align to top edge + } + + if (debugFlag('fullscreen')) { + console.log(`📱 Mobile Safari kiosk centering: ${isPortrait ? 'portrait' : 'landscape'} wrapper=${wrapperWidth}x${wrapperHeight} scale=${scale.toFixed(3)} offset=${offsetX.toFixed(1)},${offsetY.toFixed(1)}`); + } + + // Set positioning values for manual offset calculation + transformOrigin = 'top left'; // Scale from top-left corner + leftPosition = `${offsetX}px`; // Exact pixel positioning + topPosition = `${offsetY}px`; // Exact pixel positioning + marginLeft = null; // Clear any previous centering margins + marginTop = null; // Clear any previous centering margins + } else { + /* + * STANDARD FULLSCREEN/KIOSK MODE (CSS-based Centering) + * + * Why this approach? + * - Should work reliably across all other browsers and scenarios (desktop, non-Safari mobile, etc.) + * - Uses standard CSS centering techniques that browsers handle efficiently + * - Always centers both horizontally and vertically + */ + const scaledWidth = wrapperWidth * scale; + const scaledHeight = wrapperHeight * scale; + const offsetX = (window.innerWidth - scaledWidth) / 2; + const offsetY = (window.innerHeight - scaledHeight) / 2; + + if (debugFlag('fullscreen')) { + console.log(`🖥️ Applying fullscreen/kiosk scaling: wrapper=${wrapperWidth}x${wrapperHeight} scale=${scale.toFixed(3)} offset=${offsetX.toFixed(1)},${offsetY.toFixed(1)} transform: scale(${scale}) translate(${offsetX / scale}px, ${offsetY / scale}px)`); + } + + // Set positioning values for CSS-based centering + transformOrigin = 'center center'; // Scale from center point + leftPosition = '50%'; // Position at 50% from left + topPosition = '50%'; // Position at 50% from top + marginLeft = `-${wrapperWidth / 2}px`; // Pull back by half width + marginTop = `-${wrapperHeight / 2}px`; // Pull back by half height + } + + // Apply shared mainContainer properties (same for both kiosk modes) + mainContainer.style.setProperty('transform', `scale(${scale})`, 'important'); + mainContainer.style.setProperty('transform-origin', transformOrigin, 'important'); + mainContainer.style.setProperty('width', `${wrapperWidth}px`, 'important'); + mainContainer.style.setProperty('height', `${wrapperHeight}px`, 'important'); + mainContainer.style.setProperty('position', 'absolute', 'important'); + mainContainer.style.setProperty('left', leftPosition, 'important'); + mainContainer.style.setProperty('top', topPosition, 'important'); + + // Apply or clear margin properties based on positioning method + if (marginLeft !== null) { + mainContainer.style.setProperty('margin-left', marginLeft, 'important'); + } else { + mainContainer.style.removeProperty('margin-left'); + } + if (marginTop !== null) { + mainContainer.style.setProperty('margin-top', marginTop, 'important'); + } else { + mainContainer.style.removeProperty('margin-top'); + } + + applyScanlineScaling(scale); }; // reset all statuses to loading on all displays, used to keep the progress bar accurate during refresh @@ -267,6 +569,164 @@ const resetStatuses = () => { displays.forEach((display) => { display.status = STATUS.loading; }); }; +// Apply scanline scaling to try and prevent banding by avoiding fractional scaling +const applyScanlineScaling = (scale) => { + const container = document.querySelector('#container'); + if (!container || !container.classList.contains('scanlines')) { + return; + } + + const viewportWidth = window.innerWidth; + const viewportHeight = window.innerHeight; + const devicePixelRatio = window.devicePixelRatio || 1; + const currentMode = settings?.scanLineMode?.value || 'auto'; + let cssThickness; + let scanlineDebugInfo = null; + + // Helper function to round CSS values intelligently based on scale and DPR + // At high scales, precise fractional pixels render fine; at low scales, alignment matters more + const roundCSSValue = (value) => { + // On 1x DPI displays, use exact calculated values + if (devicePixelRatio === 1) { + return value; + } + + // At high scales (>2x), the browser scaling dominates and fractional pixels render well + // Prioritize nice fractions for better visual consistency + if (scale > 2.0) { + // Try quarter-pixel boundaries first (0.25, 0.5, 0.75, 1.0, etc.) + const quarterRounded = Math.round(value * 4) / 4; + if (Math.abs(quarterRounded - value) <= 0.125) { // Within 0.125px tolerance + return quarterRounded; + } + // Fall through to half-pixel boundaries for high scale fallback + } + + // At lower scales (and high scale fallback), pixel alignment matters more for crisp rendering + // Round UP to the next half-pixel to ensure scanlines are never thinner than intended + const halfPixelRounded = Math.ceil(value * 2) / 2; + return halfPixelRounded; + }; + + // Manual modes: use smart rounding in scaled scenarios to avoid banding + if (currentMode === 'thin') { + const rawValue = 1 / scale; + const cssValue = scale === 1.0 ? rawValue : roundCSSValue(rawValue); + cssThickness = `${cssValue}px`; + scanlineDebugInfo = { + css: cssValue, + visual: 1, + target: '1px visual thickness', + reason: scale === 1.0 ? 'Thin: 1px visual user override (exact)' : 'Thin: 1px visual user override (rounded)', + isManual: true, + }; + } else if (currentMode === 'medium') { + const rawValue = 2 / scale; + const cssValue = scale === 1.0 ? rawValue : roundCSSValue(rawValue); + cssThickness = `${cssValue}px`; + scanlineDebugInfo = { + css: cssValue, + visual: 2, + target: '2px visual thickness', + reason: scale === 1.0 ? 'Medium: 2px visual user override (exact)' : 'Medium: 2px visual user override (rounded)', + isManual: true, + }; + } else if (currentMode === 'thick') { + const rawValue = 3 / scale; + const cssValue = scale === 1.0 ? rawValue : roundCSSValue(rawValue); + cssThickness = `${cssValue}px`; + scanlineDebugInfo = { + css: cssValue, + visual: 3, + target: '3px visual thickness', + reason: scale === 1.0 ? 'Thick: 3px visual user override (exact)' : 'Thick: 3px visual user override (rounded)', + isManual: true, + }; + } else { + // Auto mode: choose thickness based on scaling behavior + + let visualThickness; + let reason; + + if (scale === 1.0) { + // Unscaled mode: use reasonable thickness based on device characteristics + const isHighDPIMobile = devicePixelRatio >= 2 && viewportWidth <= 768 && viewportHeight <= 768; + const isHighDPITablet = devicePixelRatio >= 2 && viewportWidth <= 1024 && viewportHeight <= 1024; + + if (isHighDPIMobile) { + // High-DPI mobile: use thin scanlines but not too thin + const cssValue = roundCSSValue(1.5 / devicePixelRatio); + cssThickness = `${cssValue}px`; + reason = `Auto: ${cssValue}px unscaled (high-DPI mobile, DPR=${devicePixelRatio})`; + } else if (isHighDPITablet) { + // High-DPI tablets: use slightly thicker scanlines for better visibility + const cssValue = roundCSSValue(1.5 / devicePixelRatio); + cssThickness = `${cssValue}px`; + reason = `Auto: ${cssValue}px unscaled (high-DPI tablet, DPR=${devicePixelRatio})`; + } else if (devicePixelRatio >= 2) { + // High-DPI desktop: use scanlines that look similar to scaled mode + const cssValue = roundCSSValue(1.5 / devicePixelRatio); + cssThickness = `${cssValue}px`; + reason = `Auto: ${cssValue}px unscaled (high-DPI desktop, DPR=${devicePixelRatio})`; + } else { + // Standard DPI desktop: use 2px for better visibility + cssThickness = '2px'; + reason = 'Auto: 2px unscaled (standard DPI desktop)'; + } + } else if (scale < 1.0) { + // Mobile scaling: use thinner scanlines for small displays + visualThickness = 1; + const cssValue = roundCSSValue(visualThickness / scale); + cssThickness = `${cssValue}px`; + reason = `Auto: ${cssValue}px scaled (mobile, scale=${scale})`; + } else if (scale >= 3.0) { + // Very high scale (large displays/high DPI): use thick scanlines for visibility + visualThickness = 3; + const cssValue = roundCSSValue(visualThickness / scale); + cssThickness = `${cssValue}px`; + reason = `Auto: ${cssValue}px scaled (large display/high scale, scale=${scale})`; + } else { + // Medium scale kiosk/fullscreen: use medium scanlines with smart rounding + visualThickness = 2; + const rawValue = visualThickness / scale; + const cssValue = roundCSSValue(rawValue); + cssThickness = `${cssValue}px`; + reason = `Auto: ${cssValue}px scaled (kiosk/fullscreen, scale=${scale})`; + + if (debugFlag('scanlines')) { + console.log(`↕️ Kiosk/fullscreen rounding: raw=${rawValue}, rounded=${cssValue}, DPR=${devicePixelRatio}, scale=${scale}`); + } + } + + // Extract numeric value from cssThickness for debug info + const cssNumericValue = parseFloat(cssThickness); + + scanlineDebugInfo = { + css: cssNumericValue, + visual: scale === 1.0 ? cssNumericValue : visualThickness, // For unscaled mode, visual thickness equals CSS thickness + target: scale === 1.0 ? `${cssNumericValue}px CSS (unscaled)` : `${visualThickness}px visual thickness`, + reason, + isManual: false, + }; + } + + container.style.setProperty('--scanline-thickness', cssThickness); + + // Output debug information if enabled + if (debugFlag('scanlines')) { + const actualRendered = scanlineDebugInfo.css * scale; + const physicalRendered = actualRendered * devicePixelRatio; + const visualThickness = scanlineDebugInfo.visual || actualRendered; // Use visual thickness if available + + console.log(`↕️ Scanline optimization: ${cssThickness} CSS × ${scale.toFixed(3)} scale = ${actualRendered.toFixed(3)}px rendered (${visualThickness}px visual target) × ${devicePixelRatio}x DPI = ${physicalRendered.toFixed(3)}px physical - ${scanlineDebugInfo.reason}`); + console.log(`↕️ Display: ${viewportWidth}×${viewportHeight}, Scale factors: width=${(window.innerWidth / (settings.wide.value ? 854 : 640)).toFixed(3)}, height=${(window.innerHeight / 480).toFixed(3)}, DPR=${devicePixelRatio}`); + console.log(`↕️ Thickness: CSS=${cssThickness}, Visual=${visualThickness.toFixed(1)}px, Rendered=${actualRendered.toFixed(3)}px, Physical=${physicalRendered.toFixed(3)}px`); + } +}; + +// Make applyScanlineScaling available for direct calls from Settings +window.applyScanlineScaling = applyScanlineScaling; + // allow displays to register themselves const registerDisplay = (display) => { if (displays[display.navId]) console.warn(`Display nav ID ${display.navId} already in use`); @@ -321,4 +781,5 @@ export { message, latLonReceived, timeZone, + isIOS, }; diff --git a/server/scripts/modules/radar-utils.mjs b/server/scripts/modules/radar-utils.mjs index 15a15ba..e95a2d2 100644 --- a/server/scripts/modules/radar-utils.mjs +++ b/server/scripts/modules/radar-utils.mjs @@ -33,91 +33,108 @@ const getXYFromLatitudeLongitudeDoppler = (pos, offsetX, offsetY) => { }; const removeDopplerRadarImageNoise = (RadarContext) => { - const RadarImageData = RadarContext.getImageData(0, 0, RadarContext.canvas.width, RadarContext.canvas.height); - - // examine every pixel, - // change any old rgb to the new-rgb - for (let i = 0; i < RadarImageData.data.length; i += 4) { - // i + 0 = red - // i + 1 = green - // i + 2 = blue - // i + 3 = alpha (0 = transparent, 255 = opaque) - let R = RadarImageData.data[i]; - let G = RadarImageData.data[i + 1]; - let B = RadarImageData.data[i + 2]; - let A = RadarImageData.data[i + 3]; - - // is this pixel the old rgb? - if ((R === 0 && G === 0 && B === 0) - || (R === 0 && G === 236 && B === 236) - || (R === 1 && G === 160 && B === 246) - || (R === 0 && G === 0 && B === 246)) { - // change to your new rgb - - // Transparent - R = 0; - G = 0; - B = 0; - A = 0; - } else if ((R === 0 && G === 255 && B === 0)) { - // Light Green 1 - R = 49; - G = 210; - B = 22; - A = 255; - } else if ((R === 0 && G === 200 && B === 0)) { - // Light Green 2 - R = 0; - G = 142; - B = 0; - A = 255; - } else if ((R === 0 && G === 144 && B === 0)) { - // Dark Green 1 - R = 20; - G = 90; - B = 15; - A = 255; - } else if ((R === 255 && G === 255 && B === 0)) { - // Dark Green 2 - R = 10; - G = 40; - B = 10; - A = 255; - } else if ((R === 231 && G === 192 && B === 0)) { - // Yellow - R = 196; - G = 179; - B = 70; - A = 255; - } else if ((R === 255 && G === 144 && B === 0)) { - // Orange - R = 190; - G = 72; - B = 19; - A = 255; - } else if ((R === 214 && G === 0 && B === 0) - || (R === 255 && G === 0 && B === 0)) { - // Red - R = 171; - G = 14; - B = 14; - A = 255; - } else if ((R === 192 && G === 0 && B === 0) - || (R === 255 && G === 0 && B === 255)) { - // Brown - R = 115; - G = 31; - B = 4; - A = 255; - } - - RadarImageData.data[i] = R; - RadarImageData.data[i + 1] = G; - RadarImageData.data[i + 2] = B; - RadarImageData.data[i + 3] = A; + // Validate canvas context and dimensions before calling getImageData + if (!RadarContext || !RadarContext.canvas) { + console.error('Invalid radar context provided to removeDopplerRadarImageNoise'); + return; } - RadarContext.putImageData(RadarImageData, 0, 0); + const { canvas } = RadarContext; + if (canvas.width <= 0 || canvas.height <= 0) { + console.error(`Invalid canvas dimensions in removeDopplerRadarImageNoise: ${canvas.width}x${canvas.height}`); + return; + } + + try { + const RadarImageData = RadarContext.getImageData(0, 0, canvas.width, canvas.height); + + // examine every pixel, + // change any old rgb to the new-rgb + for (let i = 0; i < RadarImageData.data.length; i += 4) { + // i + 0 = red + // i + 1 = green + // i + 2 = blue + // i + 3 = alpha (0 = transparent, 255 = opaque) + let R = RadarImageData.data[i]; + let G = RadarImageData.data[i + 1]; + let B = RadarImageData.data[i + 2]; + let A = RadarImageData.data[i + 3]; + + // is this pixel the old rgb? + if ((R === 0 && G === 0 && B === 0) + || (R === 0 && G === 236 && B === 236) + || (R === 1 && G === 160 && B === 246) + || (R === 0 && G === 0 && B === 246)) { + // change to your new rgb + + // Transparent + R = 0; + G = 0; + B = 0; + A = 0; + } else if ((R === 0 && G === 255 && B === 0)) { + // Light Green 1 + R = 49; + G = 210; + B = 22; + A = 255; + } else if ((R === 0 && G === 200 && B === 0)) { + // Light Green 2 + R = 0; + G = 142; + B = 0; + A = 255; + } else if ((R === 0 && G === 144 && B === 0)) { + // Dark Green 1 + R = 20; + G = 90; + B = 15; + A = 255; + } else if ((R === 255 && G === 255 && B === 0)) { + // Dark Green 2 + R = 10; + G = 40; + B = 10; + A = 255; + } else if ((R === 231 && G === 192 && B === 0)) { + // Yellow + R = 196; + G = 179; + B = 70; + A = 255; + } else if ((R === 255 && G === 144 && B === 0)) { + // Orange + R = 190; + G = 72; + B = 19; + A = 255; + } else if ((R === 214 && G === 0 && B === 0) + || (R === 255 && G === 0 && B === 0)) { + // Red + R = 171; + G = 14; + B = 14; + A = 255; + } else if ((R === 192 && G === 0 && B === 0) + || (R === 255 && G === 0 && B === 255)) { + // Brown + R = 115; + G = 31; + B = 4; + A = 255; + } + + RadarImageData.data[i] = R; + RadarImageData.data[i + 1] = G; + RadarImageData.data[i + 2] = B; + RadarImageData.data[i + 3] = A; + } + + RadarContext.putImageData(RadarImageData, 0, 0); + } catch (error) { + console.error(`Error in removeDopplerRadarImageNoise: ${error.message}. Canvas size: ${canvas.width}x${canvas.height}`); + // Don't re-throw the error, just log it and continue processing + } }; export { diff --git a/server/scripts/modules/radar.mjs b/server/scripts/modules/radar.mjs index 9211297..2ffc03e 100644 --- a/server/scripts/modules/radar.mjs +++ b/server/scripts/modules/radar.mjs @@ -1,7 +1,7 @@ // current weather conditions display import STATUS from './status.mjs'; import { DateTime } from '../vendor/auto/luxon.mjs'; -import { text } from './utils/fetch.mjs'; +import { safeText } from './utils/fetch.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay, timeZone } from './navigation.mjs'; import * as utils from './radar-utils.mjs'; @@ -57,35 +57,60 @@ class Radar extends WeatherDisplay { } const baseUrl = `https://${RADAR_HOST}/archive/data/`; - const baseUrlEnd = '/GIS/uscomp/?F=0&P=n0r*.png'; - const baseUrls = []; - let date = DateTime.utc().minus({ days: 1 }).startOf('day'); + const baseUrlEnd = '/GIS/uscomp/?F=0&P=n0r*.png'; // This URL returns an index of .png files for the given date - // make urls for yesterday and today - while (date <= DateTime.utc().startOf('day')) { - baseUrls.push(`${baseUrl}${date.toFormat('yyyy/LL/dd')}${baseUrlEnd}`); - date = date.plus({ days: 1 }); + // Always get today's data + const today = DateTime.utc().startOf('day'); + const todayStr = today.toFormat('yyyy/LL/dd'); + const yesterday = today.minus({ days: 1 }); + const yesterdayStr = yesterday.toFormat('yyyy/LL/dd'); + const todayUrl = `${baseUrl}${todayStr}${baseUrlEnd}`; + + // Get today's data, then we'll see if we need yesterday's + const todayList = await safeText(todayUrl); + + // Count available images from today + let todayImageCount = 0; + if (todayList) { + const parser = new DOMParser(); + const xmlDoc = parser.parseFromString(todayList, 'text/html'); + const anchors = xmlDoc.querySelectorAll('a'); + todayImageCount = Array.from(anchors).filter((elem) => elem.innerHTML?.match(/n0r_\d{12}\.png/)).length; } - const lists = (await Promise.all(baseUrls.map(async (url) => { - try { - // get a list of available radars - return text(url); - } catch (error) { - console.log('Unable to get list of radars'); - console.error(error); - this.setStatus(STATUS.failed); - return false; - } - }))).filter((d) => d); + // Only fetch yesterday's data if we don't have enough images from today + // or if it's very early in the day when recent images might still be from yesterday + const currentTimeUTC = DateTime.utc(); + const minutesSinceMidnight = currentTimeUTC.hour * 60 + currentTimeUTC.minute; + const requiredTimeWindow = this.dopplerRadarImageMax * 5; // 5 minutes per image + const needYesterday = todayImageCount < this.dopplerRadarImageMax || minutesSinceMidnight < requiredTimeWindow; - // convert to an array of gif urls + // Build the final lists array + const lists = []; + if (needYesterday) { + const yesterdayUrl = `${baseUrl}${yesterdayStr}${baseUrlEnd}`; + const yesterdayList = await safeText(yesterdayUrl); + if (yesterdayList) { + lists.push(yesterdayList); // Add yesterday's data first + } + } + if (todayList) { + lists.push(todayList); // Add today's data + } + + // convert to an array of png urls const pngs = lists.flatMap((html, htmlIdx) => { const parser = new DOMParser(); const xmlDoc = parser.parseFromString(html, 'text/html'); - // add the base url + // add the base url - reconstruct the URL for each list const base = xmlDoc.createElement('base'); - base.href = baseUrls[htmlIdx]; + if (htmlIdx === 0 && needYesterday) { + // First item is yesterday's data when we fetched it + base.href = `${baseUrl}${yesterdayStr}${baseUrlEnd}`; + } else { + // This is today's data (or the only data if yesterday wasn't fetched) + base.href = `${baseUrl}${todayStr}${baseUrlEnd}`; + } xmlDoc.head.append(base); const anchors = xmlDoc.querySelectorAll('a'); const urls = []; @@ -119,69 +144,73 @@ class Radar extends WeatherDisplay { // reset the "used" flag on pre-processed radars // items that were not used during this process are deleted (either expired via time or change of location) processedRadars.forEach((radar) => { radar.used = false; }); - // remove any radars that aren't - // Load the most recent doppler radar images. - const radarInfo = await Promise.all(urls.map(async (url) => { - // store the time - const timeMatch = url.match(/_(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)\./); - const [, year, month, day, hour, minute] = timeMatch; + try { + const radarInfo = await Promise.all(urls.map(async (url) => { + // store the time + const timeMatch = url.match(/_(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)\./); + const [, year, month, day, hour, minute] = timeMatch; - const radarKeyedTimestamp = `${radarKey}:${year}${month}${day}${hour}${minute}`; + const radarKeyedTimestamp = `${radarKey}:${year}${month}${day}${hour}${minute}`; - // check for a pre-processed radar - const preProcessed = processedRadars.find((radar) => radar.key === radarKeyedTimestamp); + // check for a pre-processed radar + const preProcessed = processedRadars.find((radar) => radar.key === radarKeyedTimestamp); - // use the pre-processed radar, or get a new one - const processedRadar = preProcessed?.dataURL ?? await processRadar({ - url, - RADAR_HOST, - OVERRIDES, - radarSourceXY, - }); - - // store the radar - if (!preProcessed) { - processedRadars.push({ - key: radarKeyedTimestamp, - dataURL: processedRadar, - used: true, + // use the pre-processed radar, or get a new one + const processedRadar = preProcessed?.dataURL ?? await processRadar({ + url, + RADAR_HOST, + OVERRIDES, + radarSourceXY, }); - } else { - // set used flag - preProcessed.used = true; - } - const time = DateTime.fromObject({ - year, - month, - day, - hour, - minute, - }, { - zone: 'UTC', - }).setZone(timeZone()); + // store the radar + if (!preProcessed) { + processedRadars.push({ + key: radarKeyedTimestamp, + dataURL: processedRadar, + used: true, + }); + } else { + // set used flag + preProcessed.used = true; + } - const elem = this.fillTemplate('frame', { map: { type: 'img', src: processedRadar } }); - return { - time, - elem, - }; - })); + const time = DateTime.fromObject({ + year, + month, + day, + hour, + minute, + }, { + zone: 'UTC', + }).setZone(timeZone()); - // put the elements in the container - const scrollArea = this.elem.querySelector('.scroll-area'); - scrollArea.innerHTML = ''; - scrollArea.append(...radarInfo.map((r) => r.elem)); + const elem = this.fillTemplate('frame', { map: { type: 'img', src: processedRadar } }); + return { + time, + elem, + }; + })); - // set max length - this.timing.totalScreens = radarInfo.length; + // put the elements in the container + const scrollArea = this.elem.querySelector('.scroll-area'); + scrollArea.innerHTML = ''; + scrollArea.append(...radarInfo.map((r) => r.elem)); - this.times = radarInfo.map((radar) => radar.time); - this.setStatus(STATUS.loaded); + // set max length + this.timing.totalScreens = radarInfo.length; - // clean up any unused stored radars - processedRadars = processedRadars.filter((radar) => radar.used); + this.times = radarInfo.map((radar) => radar.time); + this.setStatus(STATUS.loaded); + + // clean up any unused stored radars + processedRadars = processedRadars.filter((radar) => radar.used); + } catch (_error) { + // Radar fetch failed - skip this display in animation by setting totalScreens = 0 + this.timing.totalScreens = 0; + if (this.isEnabled) this.setStatus(STATUS.failed); + } } async drawCanvas() { diff --git a/server/scripts/modules/regionalforecast-utils.mjs b/server/scripts/modules/regionalforecast-utils.mjs index e5cf702..edd0229 100644 --- a/server/scripts/modules/regionalforecast-utils.mjs +++ b/server/scripts/modules/regionalforecast-utils.mjs @@ -1,7 +1,10 @@ import { getSmallIcon } from './icons.mjs'; import { preloadImg } from './utils/image.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson } from './utils/fetch.mjs'; import { temperature as temperatureUnit } from './utils/units.mjs'; +import augmentObservationWithMetar from './utils/metar.mjs'; +import { debugFlag } from './utils/debug.mjs'; +import { enhanceObservationWithMapClick } from './utils/mapclick.mjs'; const buildForecast = (forecast, city, cityXY) => { // get a unit converter @@ -19,23 +22,66 @@ const buildForecast = (forecast, city, cityXY) => { const getRegionalObservation = async (point, city) => { try { - // get stations - const stations = await json(`https://api.weather.gov/gridpoints/${point.wfo}/${point.x},${point.y}/stations?limit=1`); + // get stations using centralized safe handling + const stations = await safeJson(`https://api.weather.gov/gridpoints/${point.wfo}/${point.x},${point.y}/stations?limit=1`); + + if (!stations || !stations.features || stations.features.length === 0) { + if (debugFlag('verbose-failures')) { + console.warn(`Unable to get regional stations for ${city.city}`); + } + return false; + } // get the first station const station = stations.features[0].id; - // get the observation data - const observation = await json(`${station}/observations/latest`); + const stationId = stations.features[0].properties.stationIdentifier; + // get the observation data using centralized safe handling + const observation = await safeJson(`${station}/observations/latest`); + + if (!observation) { + if (debugFlag('verbose-failures')) { + console.warn(`Unable to get regional observations for station ${stationId}`); + } + return false; + } + + // Enhance observation data with METAR parsing for missing fields + let augmentedObservation = augmentObservationWithMetar(observation.properties); + + // Define required fields for regional observations (more lenient than current weather) + const requiredFields = [ + { name: 'temperature', check: (props) => props.temperature?.value === null }, + { name: 'textDescription', check: (props) => props.textDescription === null || props.textDescription === '' }, + { name: 'icon', check: (props) => props.icon === null }, + ]; + + // Use enhanced observation with MapClick fallback + const enhancedResult = await enhanceObservationWithMapClick(augmentedObservation, { + requiredFields, + stationId, + debugContext: 'regionalforecast', + }); + + augmentedObservation = enhancedResult.data; + const { missingFields } = enhancedResult; + + // Check final data quality + if (missingFields.length > 0) { + if (debugFlag('regionalforecast')) { + console.log(`Regional Observations for station ${stationId} is missing fields: ${missingFields.join(', ')} (skipping)`); + } + return false; + } + // preload the image - if (!observation.properties.icon) return false; - const icon = getSmallIcon(observation.properties.icon, !observation.properties.daytime); + if (!augmentedObservation.icon) return false; + const icon = getSmallIcon(augmentedObservation.icon, !augmentedObservation.daytime); if (!icon) return false; preloadImg(icon); // return the observation - return observation.properties; + return augmentedObservation; } catch (error) { - console.log(`Unable to get regional observations for ${city.Name ?? city.city}`); - console.error(error.status, error.responseJSON); + console.error(`Unexpected error getting Regional Observation for ${city.city}: ${error.message}`); return false; } }; diff --git a/server/scripts/modules/regionalforecast.mjs b/server/scripts/modules/regionalforecast.mjs index 6e440b4..81ac972 100644 --- a/server/scripts/modules/regionalforecast.mjs +++ b/server/scripts/modules/regionalforecast.mjs @@ -3,15 +3,17 @@ import STATUS from './status.mjs'; import { distance as calcDistance } from './utils/calc.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson, safePromiseAll } from './utils/fetch.mjs'; import { temperature as temperatureUnit } from './utils/units.mjs'; import { getSmallIcon } from './icons.mjs'; import { preloadImg } from './utils/image.mjs'; -import { DateTime, Interval } from '../vendor/auto/luxon.mjs'; +import { DateTime } from '../vendor/auto/luxon.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; import * as utils from './regionalforecast-utils.mjs'; import { getPoint } from './utils/weather.mjs'; +import { debugFlag } from './utils/debug.mjs'; +import filterExpiredPeriods from './utils/forecast-utils.mjs'; // map offset const mapOffsetXY = { @@ -77,19 +79,27 @@ class RegionalForecast extends WeatherDisplay { // get a unit converter const temperatureConverter = temperatureUnit(); - // get now as DateTime for calculations below - const now = DateTime.now(); - - // get regional forecasts and observations (the two are intertwined due to the design of api.weather.gov) - const regionalDataAll = await Promise.all(regionalCities.map(async (city) => { + // get regional forecasts and observations using centralized safe Promise handling + const regionalDataAll = await safePromiseAll(regionalCities.map(async (city) => { try { const point = city?.point ?? (await getAndFormatPoint(city.lat, city.lon)); - if (!point) throw new Error('No pre-loaded point'); + if (!point) { + if (debugFlag('verbose-failures')) { + console.warn(`Unable to get Points for '${city.Name ?? city.city}'`); + } + return false; + } // start off the observation task const observationPromise = utils.getRegionalObservation(point, city); - const forecast = await json(`https://api.weather.gov/gridpoints/${point.wfo}/${point.x},${point.y}/forecast`); + const forecast = await safeJson(`https://api.weather.gov/gridpoints/${point.wfo}/${point.x},${point.y}/forecast`); + if (!forecast) { + if (debugFlag('verbose-failures')) { + console.warn(`Regional Forecast request for ${city.Name ?? city.city} failed`); + } + return false; + } // get XY on map for city const cityXY = utils.getXYForCity(city, minMaxLatLon.maxLat, minMaxLatLon.minLon, this.weatherParameters.state); @@ -112,29 +122,23 @@ class RegionalForecast extends WeatherDisplay { // preload the icon preloadImg(getSmallIcon(regionalObservation.icon, !regionalObservation.daytime)); - // return a pared-down forecast - // 0th object should contain the current conditions, but when WFOs go offline or otherwise don't post - // an updated forecast it's possible that the 0th object is in the past. - // so we go on a search for the current time in the start/end times provided in the forecast periods - const { periods } = forecast.properties; - const currentPeriod = periods.reduce((prev, period, index) => { - const start = DateTime.fromISO(period.startTime); - const end = DateTime.fromISO(period.endTime); - const interval = Interval.fromDateTimes(start, end); - if (interval.contains(now)) { - return index; - } - return prev; - }, 0); + // filter out expired periods first, then use the next two periods for forecast + const activePeriods = filterExpiredPeriods(forecast.properties.periods); + + // ensure we have enough periods for forecast + if (activePeriods.length < 3) { + console.warn(`Insufficient active periods for ${city.Name ?? city.city}: only ${activePeriods.length} periods available`); + return false; + } + // group together the current observation and next two periods return [ regionalObservation, - utils.buildForecast(forecast.properties.periods[currentPeriod + 1], city, cityXY), - utils.buildForecast(forecast.properties.periods[currentPeriod + 2], city, cityXY), + utils.buildForecast(activePeriods[1], city, cityXY), + utils.buildForecast(activePeriods[2], city, cityXY), ]; } catch (error) { - console.log(`No regional forecast data for '${city.name ?? city.city}'`); - console.log(error); + console.error(`Unexpected error getting Regional Forecast data for '${city.name ?? city.city}': ${error.message}`); return false; } })); @@ -215,12 +219,19 @@ class RegionalForecast extends WeatherDisplay { } const getAndFormatPoint = async (lat, lon) => { - const point = await getPoint(lat, lon); - return { - x: point.properties.gridX, - y: point.properties.gridY, - wfo: point.properties.gridId, - }; + try { + const point = await getPoint(lat, lon); + if (!point) { + return null; + } + return { + x: point.properties.gridX, + y: point.properties.gridY, + wfo: point.properties.gridId, + }; + } catch (error) { + throw new Error(`Unexpected error getting point for ${lat},${lon}: ${error.message}`); + } }; // register display diff --git a/server/scripts/modules/settings.mjs b/server/scripts/modules/settings.mjs index 0e38d53..4c9795c 100644 --- a/server/scripts/modules/settings.mjs +++ b/server/scripts/modules/settings.mjs @@ -1,12 +1,115 @@ import Setting from './utils/setting.mjs'; -document.addEventListener('DOMContentLoaded', () => { - init(); -}); - -// default speed +// Initialize settings immediately so other modules can access them const settings = { speed: { value: 1.0 } }; +// Track settings that need DOM changes after early initialization +const deferredDomSettings = new Set(); + +// Declare change functions first, before they're referenced in init() to avoid the Temporal Dead Zone (TDZ) +const wideScreenChange = (value) => { + const container = document.querySelector('#divTwc'); + if (!container) { + // DOM not ready; defer enabling if set + if (value) { + deferredDomSettings.add('wide'); + } + return; + } + + if (value) { + container.classList.add('wide'); + } else { + container.classList.remove('wide'); + } + // Trigger resize to recalculate scaling for new width + window.dispatchEvent(new Event('resize')); +}; + +const kioskChange = (value) => { + const body = document.querySelector('body'); + if (!body) { + // DOM not ready; defer enabling if set + if (value) { + deferredDomSettings.add('kiosk'); + } + return; + } + + if (value) { + body.classList.add('kiosk'); + window.dispatchEvent(new Event('resize')); + } else { + body.classList.remove('kiosk'); + window.dispatchEvent(new Event('resize')); + } + + // Conditionally store the kiosk setting based on the "Sticky Kiosk" setting + // (Need to check if the method exists to handle initialization race condition) + if (settings.kiosk?.conditionalStoreToLocalStorage) { + settings.kiosk.conditionalStoreToLocalStorage(value, settings.stickyKiosk?.value); + } +}; + +const scanLineChange = (value) => { + const container = document.getElementById('container'); + const navIcons = document.getElementById('ToggleScanlines'); + + if (!container || !navIcons) { + // DOM not ready; defer enabling if set + if (value) { + deferredDomSettings.add('scanLines'); + } + return; + } + + if (value) { + container.classList.add('scanlines'); + navIcons.classList.add('on'); + } else { + // Remove all scanline classes + container.classList.remove('scanlines', 'scanlines-auto', 'scanlines-fine', 'scanlines-normal', 'scanlines-thick', 'scanlines-classic', 'scanlines-retro'); + navIcons.classList.remove('on'); + } +}; + +const scanLineModeChange = (_value) => { + // Only apply if scanlines are currently enabled + if (settings.scanLines?.value) { + // Call the scanline update function directly with current scale + if (typeof window.applyScanlineScaling === 'function') { + // Get current scale from navigation module or use 1.0 as fallback + const scale = window.currentScale || 1.0; + window.applyScanlineScaling(scale); + } + } +}; + +// Simple global helper to change scanline mode when remote debugging or in kiosk mode +window.changeScanlineMode = (mode) => { + if (typeof settings === 'undefined' || !settings.scanLineMode) { + console.error('Settings system not available'); + return false; + } + + const validModes = ['auto', 'thin', 'medium', 'thick']; + if (!validModes.includes(mode)) { + return false; + } + + settings.scanLineMode.value = mode; + return true; +}; + +const unitChange = () => { + // reload the data at the top level to refresh units + // after the initial load + if (unitChange.firstRunDone) { + window.location.reload(); + } + unitChange.firstRunDone = true; +}; + const init = () => { // create settings see setting.mjs for defaults settings.wide = new Setting('wide', { @@ -20,6 +123,12 @@ const init = () => { defaultValue: false, changeAction: kioskChange, sticky: false, + stickyRead: true, + }); + settings.stickyKiosk = new Setting('stickyKiosk', { + name: 'Sticky Kiosk', + defaultValue: false, + sticky: true, }); settings.speed = new Setting('speed', { name: 'Speed', @@ -39,6 +148,19 @@ const init = () => { changeAction: scanLineChange, sticky: true, }); + settings.scanLineMode = new Setting('scanLineMode', { + name: 'Scan Line Style', + type: 'select', + defaultValue: 'auto', + changeAction: scanLineModeChange, + sticky: true, + values: [ + ['auto', 'Auto (Adaptive)'], + ['thin', 'Thin (1x)'], + ['medium', 'Medium (2x)'], + ['thick', 'Thick (3x)'], + ], + }); settings.units = new Setting('units', { name: 'Units', type: 'select', @@ -62,54 +184,32 @@ const init = () => { ], visible: false, }); +}; - // generate html objects +init(); + +// generate html objects +document.addEventListener('DOMContentLoaded', () => { + // Apply any settings that were deferred due to the DOM not being ready when setting were read + if (deferredDomSettings.size > 0) { + console.log('Applying deferred DOM settings:', Array.from(deferredDomSettings)); + + // Re-apply each pending setting by calling its changeAction with current value + deferredDomSettings.forEach((settingName) => { + const setting = settings[settingName]; + if (setting && setting.changeAction && typeof setting.changeAction === 'function') { + setting.changeAction(setting.value); + } + }); + + deferredDomSettings.clear(); + } + + // Then generate the settings UI const settingHtml = Object.values(settings).map((d) => d.generate()); - - // write to page const settingsSection = document.querySelector('#settings'); settingsSection.innerHTML = ''; settingsSection.append(...settingHtml); -}; - -const wideScreenChange = (value) => { - const container = document.querySelector('#divTwc'); - if (value) { - container.classList.add('wide'); - } else { - container.classList.remove('wide'); - } -}; - -const kioskChange = (value) => { - const body = document.querySelector('body'); - if (value) { - body.classList.add('kiosk'); - window.dispatchEvent(new Event('resize')); - } else { - body.classList.remove('kiosk'); - } -}; - -const scanLineChange = (value) => { - const container = document.getElementById('container'); - const navIcons = document.getElementById('ToggleScanlines'); - if (value) { - container.classList.add('scanlines'); - navIcons.classList.add('on'); - } else { - container.classList.remove('scanlines'); - navIcons.classList.remove('on'); - } -}; - -const unitChange = () => { - // reload the data at the top level to refresh units - // after the initial load - if (unitChange.firstRunDone) { - window.location.reload(); - } - unitChange.firstRunDone = true; -}; +}); export default settings; diff --git a/server/scripts/modules/spc-outlook.mjs b/server/scripts/modules/spc-outlook.mjs index 94ef41b..03f799b 100644 --- a/server/scripts/modules/spc-outlook.mjs +++ b/server/scripts/modules/spc-outlook.mjs @@ -1,11 +1,12 @@ // display spc outlook in a bar graph import STATUS from './status.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson, safePromiseAll } from './utils/fetch.mjs'; import { DateTime } from '../vendor/auto/luxon.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; import testPolygon from './utils/polygon.mjs'; +import { debugFlag } from './utils/debug.mjs'; // list of interesting files ordered [0] = today, [1] = tomorrow... const urlPattern = (day) => `https://www.spc.noaa.gov/products/outlook/day${day}otlk_cat.nolyr.geojson`; @@ -18,8 +19,10 @@ const testAllPoints = (point, data) => { data.forEach((day, index) => { // initialize the result result[index] = false; - // if there's no data (file didn't load), exit early - if (day === undefined) return; + // ensure day exists and has features array + if (!day || !day.features || !Array.isArray(day.features)) { + return; + } // loop through each category day.features.forEach((feature) => { if (!feature.geometry.coordinates) return; @@ -46,7 +49,7 @@ class SpcOutlook extends WeatherDisplay { // don't display on progress/navigation screen this.showOnProgress = false; - // calculate file names + // calculate file names, one for each day this.files = [null, null, null].map((v, i) => urlPattern(i + 1)); // set timings @@ -56,27 +59,43 @@ class SpcOutlook extends WeatherDisplay { async getData(weatherParameters, refresh) { if (!super.getData(weatherParameters, refresh)) return; - // initial data does not need to be reloaded on a location change, only during silent refresh - if (!this.initialData || refresh) { + // SPC outlook data does not need to be reloaded on a location change, only during silent refresh + if (!this.rawOutlookData || refresh) { try { - // get the three categorical files to get started - const filePromises = await Promise.allSettled(this.files.map((file) => json(file))); - // store the data, promise will always be fulfilled - this.initialData = filePromises.map((outlookDay) => outlookDay.value); - } catch (error) { - console.error('Unable to get spc outlook'); - console.error(error.status, error.responseJSON); - // if there's no previous data, fail - if (!this.initialData) { - this.setStatus(STATUS.failed); + // get the data for today, tomorrow, and the day after + const filePromises = this.files.map((file) => safeJson(file, { + retryCount: 1, // Retry one time + timeout: 10000, // 10 second timeout for SPC outlook data + })); + // wait for all the data to be fetched; always returns an array of (potentially null) results + this.rawOutlookData = await safePromiseAll(filePromises); + + // Filter out null results (like failed requests) and ensure the response has GeoJSON-looking data + this.rawOutlookData = this.rawOutlookData.filter((value) => value && value.features); + + if (this.rawOutlookData.length === 0) { + if (debugFlag('verbose-failures')) { + console.warn('SPC Outlook has zero days of data'); + } + if (this.isEnabled) this.setStatus(STATUS.failed); return; } + + if (this.rawOutlookData.length < this.files.length) { + if (debugFlag('verbose-failures')) { + console.warn(`SPC Outlook only loaded ${this.rawOutlookData.length} of ${this.files.length} days successfully`); + } + } + } catch (error) { + console.error(`Unexpected error getting SPC Outlook data: ${error.message}`); + if (this.isEnabled) this.setStatus(STATUS.failed); + return; } } - // do the initial parsing of the data - this.data = testAllPoints([weatherParameters.longitude, weatherParameters.latitude], this.initialData); + // parse the data + this.data = testAllPoints([weatherParameters.longitude, weatherParameters.latitude], this.rawOutlookData); - // if all the data returns false the there's nothing to do, skip this screen + // check if there's a "risk" for any of the three days, otherwise skip the SPC Outlook screen if (this.data.reduce((prev, cur) => prev || !!cur, false)) { this.timing.totalScreens = 1; } else { diff --git a/server/scripts/modules/travelforecast.mjs b/server/scripts/modules/travelforecast.mjs index bf3b9f1..d5b4f02 100644 --- a/server/scripts/modules/travelforecast.mjs +++ b/server/scripts/modules/travelforecast.mjs @@ -1,34 +1,34 @@ // travel forecast display import STATUS from './status.mjs'; -import { json } from './utils/fetch.mjs'; +import { safeJson, safePromiseAll } from './utils/fetch.mjs'; import { getSmallIcon } from './icons.mjs'; import { DateTime } from '../vendor/auto/luxon.mjs'; import WeatherDisplay from './weatherdisplay.mjs'; import { registerDisplay } from './navigation.mjs'; import settings from './settings.mjs'; +import calculateScrollTiming from './utils/scroll-timing.mjs'; +import { debugFlag } from './utils/debug.mjs'; class TravelForecast extends WeatherDisplay { constructor(navId, elemId, defaultActive) { // special height and width for scrolling super(navId, elemId, 'Travel Forecast', defaultActive); - // set up the timing - this.timing.baseDelay = 20; - // page sizes are 4 cities, calculate the number of pages necessary plus overflow - const pagesFloat = TravelCities.length / 4; - const pages = Math.floor(pagesFloat) - 2; // first page is already displayed, last page doesn't happen - const extra = pages % 1; - const timingStep = 75 * 4; - this.timing.delay = [150 + timingStep]; - // add additional pages - for (let i = 0; i < pages; i += 1) this.timing.delay.push(timingStep); - // add the extra (not exactly 4 pages portion) - if (extra !== 0) this.timing.delay.push(Math.round(this.extra * this.cityHeight)); - // add the final 3 second delay - this.timing.delay.push(150); - // add previous data cache this.previousData = []; + + // cache for scroll calculations + // This cache is essential because baseCountChange() is called 25 times per second (every 40ms) + // during scrolling. Travel forecast scroll duration varies based on the number of cities configured. + // Without caching, we'd perform hundreds of expensive DOM layout queries during each scroll cycle. + // The cache reduces this to one calculation when content changes, then reuses cached values to try + // and get smoother scrolling. + this.scrollCache = { + displayHeight: 0, + contentHeight: 0, + maxOffset: 0, + travelLines: null, + }; } async getData(weatherParameters, refresh) { @@ -45,22 +45,27 @@ class TravelForecast extends WeatherDisplay { // get point then forecast if (!city.point) throw new Error('No pre-loaded point'); let forecast; - try { - forecast = await json(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/forecast`, { - data: { - units: settings.units.value, - }, - }); + forecast = await safeJson(`https://api.weather.gov/gridpoints/${city.point.wfo}/${city.point.x},${city.point.y}/forecast`, { + data: { + units: settings.units.value, + }, + }); + + if (forecast) { // store for the next run this.previousData[index] = forecast; - } catch (e) { + } else if (this.previousData?.[index]) { // if there's previous data use it - if (this.previousData?.[index]) { - forecast = this.previousData?.[index]; - } else { - // otherwise re-throw for the standard error handling - throw (e); + if (debugFlag('travelforecast')) { + console.warn(`Using previous forecast data for ${city.Name} travel forecast`); } + forecast = this.previousData?.[index]; + } else { + // no current data and no previous data available + if (debugFlag('verbose-failures')) { + console.warn(`No travel forecast for ${city.Name} available`); + } + return { name: city.Name, error: true }; } // determine today or tomorrow (shift periods by 1 if tomorrow) const todayShift = forecast.properties.periods[0].isDaytime ? 0 : 1; @@ -73,14 +78,13 @@ class TravelForecast extends WeatherDisplay { icon: getSmallIcon(forecast.properties.periods[todayShift].icon), }; } catch (error) { - console.error(`GetTravelWeather for ${city.Name} failed`); - console.error(error.status, error.responseJSON); + console.error(`Unexpected error getting Travel Forecast for ${city.Name}: ${error.message}`); return { name: city.Name, error: true }; } }); - // wait for all forecasts - const forecasts = await Promise.all(forecastPromises); + // wait for all forecasts using centralized safe Promise handling + const forecasts = await safePromiseAll(forecastPromises); this.data = forecasts; // test for some data available in at least one forecast @@ -129,6 +133,9 @@ class TravelForecast extends WeatherDisplay { return this.fillTemplate('travel-row', fillValues); }).filter((d) => d); list.append(...lines); + + // update timing based on actual content + this.setTiming(list); } async drawCanvas() { @@ -157,20 +164,50 @@ class TravelForecast extends WeatherDisplay { // base count change callback baseCountChange(count) { + // get the travel lines element and cache measurements if needed + const travelLines = this.elem.querySelector('.travel-lines'); + if (!travelLines) return; + + // update cache if needed (when content changes or first run) + if (this.scrollCache.travelLines !== travelLines || this.scrollCache.displayHeight === 0) { + this.scrollCache.displayHeight = this.elem.querySelector('.main').offsetHeight; + this.scrollCache.contentHeight = travelLines.offsetHeight; + this.scrollCache.maxOffset = Math.max(0, this.scrollCache.contentHeight - this.scrollCache.displayHeight); + this.scrollCache.travelLines = travelLines; + + // Set up hardware acceleration on the travel lines element + travelLines.style.willChange = 'transform'; + travelLines.style.backfaceVisibility = 'hidden'; + } + // calculate scroll offset and don't go past end - let offsetY = Math.min(this.elem.querySelector('.travel-lines').offsetHeight - 289, (count - 150)); + let offsetY = Math.min(this.scrollCache.maxOffset, (count - this.scrollTiming.initialCounts) * this.scrollTiming.pixelsPerCount); // don't let offset go negative if (offsetY < 0) offsetY = 0; - // copy the scrolled portion of the canvas - this.elem.querySelector('.main').scrollTo(0, offsetY); + // use transform instead of scrollTo for hardware acceleration + travelLines.style.transform = `translateY(-${Math.round(offsetY)}px)`; } // necessary to get the lastest long canvas when scrolling getLongCanvas() { return this.longCanvas; } + + setTiming(list) { + const container = this.elem.querySelector('.main'); + const timingConfig = calculateScrollTiming(list, container, { + staticDisplay: 5.0, // special static display time for travel forecast + }); + + // Apply the calculated timing + this.timing.baseDelay = timingConfig.baseDelay; + this.timing.delay = timingConfig.delay; + this.scrollTiming = timingConfig.scrollTiming; + + this.calcNavTiming(); + } } // effectively returns early on the first found date diff --git a/server/scripts/modules/utils/cache.mjs b/server/scripts/modules/utils/cache.mjs new file mode 100644 index 0000000..d4c3413 --- /dev/null +++ b/server/scripts/modules/utils/cache.mjs @@ -0,0 +1,40 @@ +import { rewriteUrl } from './url-rewrite.mjs'; + +// Clear cache utility for client-side use +const clearCacheEntry = async (url, baseUrl = '') => { + try { + // Rewrite the URL to get the local proxy path + const rewrittenUrl = rewriteUrl(url); + const urlObj = typeof rewrittenUrl === 'string' ? new URL(rewrittenUrl, baseUrl || window.location.origin) : rewrittenUrl; + let cachePath = urlObj.pathname + urlObj.search; + + // Strip the route designator (first path segment) to match actual cache keys + const firstSlashIndex = cachePath.indexOf('/', 1); // Find second slash + if (firstSlashIndex > 0) { + cachePath = cachePath.substring(firstSlashIndex); + } + + // Call the cache clear endpoint + const fetchUrl = baseUrl ? `${baseUrl}/cache${cachePath}` : `/cache${cachePath}`; + const response = await fetch(fetchUrl, { + method: 'DELETE', + }); + + if (response.ok) { + const result = await response.json(); + if (result.cleared) { + console.log(`🗑️ Cleared cache entry: ${cachePath}`); + return true; + } + console.log(`🔍 Cache entry not found: ${cachePath}`); + return false; + } + console.warn(`⚠️ Failed to clear cache entry: ${response.status} ${response.statusText}`); + return false; + } catch (error) { + console.error(`❌ Error clearing cache entry for ${url}:`, error.message); + return false; + } +}; + +export default clearCacheEntry; diff --git a/server/scripts/modules/utils/calc.mjs b/server/scripts/modules/utils/calc.mjs index b4c7469..40d6548 100644 --- a/server/scripts/modules/utils/calc.mjs +++ b/server/scripts/modules/utils/calc.mjs @@ -1,5 +1,9 @@ // wind direction const directionToNSEW = (Direction) => { + // Handle null, undefined, or invalid direction values + if (Direction === null || Direction === undefined || typeof Direction !== 'number' || Number.isNaN(Direction)) { + return 'VAR'; // Variable (or unknown) direction + } const val = Math.floor((Direction / 22.5) + 0.5); const arr = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW']; return arr[(val % 16)]; diff --git a/server/scripts/modules/utils/cors.mjs b/server/scripts/modules/utils/cors.mjs deleted file mode 100644 index 038a4c7..0000000 --- a/server/scripts/modules/utils/cors.mjs +++ /dev/null @@ -1,12 +0,0 @@ -// rewrite some urls for local server -const rewriteUrl = (_url) => { - let url = _url; - url = url.replace('https://api.weather.gov/', `${window.location.protocol}//${window.location.host}/`); - url = url.replace('https://www.cpc.ncep.noaa.gov/', `${window.location.protocol}//${window.location.host}/`); - return url; -}; - -export { - // eslint-disable-next-line import/prefer-default-export - rewriteUrl, -}; diff --git a/server/scripts/modules/utils/data-loader.mjs b/server/scripts/modules/utils/data-loader.mjs new file mode 100644 index 0000000..59cf7b7 --- /dev/null +++ b/server/scripts/modules/utils/data-loader.mjs @@ -0,0 +1,53 @@ +// Data loader utility for fetching JSON data with cache-busting + +let dataCache = {}; + +// Load data with version-based cache busting +const loadData = async (dataType, version = '') => { + if (dataCache[dataType]) { + return dataCache[dataType]; + } + + try { + const url = `/data/${dataType}.json${version ? `?_=${version}` : ''}`; + const response = await fetch(url); + + if (!response.ok) { + throw new Error(`Failed to load ${dataType}: ${response.status}`); + } + + const data = await response.json(); + dataCache[dataType] = data; + return data; + } catch (error) { + console.error(`Error loading ${dataType}:`, error); + throw error; + } +}; + +// Load all data types +const loadAllData = async (version = '') => { + const [travelCities, regionalCities, stationInfo] = await Promise.all([ + loadData('travelcities', version), + loadData('regionalcities', version), + loadData('stations', version), + ]); + + // Set global variables for backward compatibility + window.TravelCities = travelCities; + window.RegionalCities = regionalCities; + window.StationInfo = stationInfo; + + return { travelCities, regionalCities, stationInfo }; +}; + +// Clear cache (useful for development) +const clearDataCache = () => { + dataCache = {}; +}; + +export { + loadData, + loadAllData, + clearDataCache, +}; diff --git a/server/scripts/modules/utils/debug.mjs b/server/scripts/modules/utils/debug.mjs new file mode 100644 index 0000000..0578933 --- /dev/null +++ b/server/scripts/modules/utils/debug.mjs @@ -0,0 +1,148 @@ +// Debug flag management system +// Supports comma-separated debug flags or "all" for everything +// URL parameter takes priority over OVERRIDES.DEBUG + +let debugFlags = null; // memoized parsed flags +let runtimeFlags = null; // runtime modifications via debugEnable/debugDisable/debugSet + +/** + * Parse debug flags from URL parameter or environment variable + * @returns {Set} Set of enabled debug flags + */ +const parseDebugFlags = () => { + if (debugFlags !== null) return debugFlags; + + let debugString = ''; + + // Check URL parameter first + const urlParams = new URLSearchParams(window.location.search); + const urlDebug = urlParams.get('debug'); + + if (urlDebug) { + debugString = urlDebug; + } else { + // Fall back to OVERRIDES.DEBUG + debugString = (typeof OVERRIDES !== 'undefined' ? OVERRIDES?.DEBUG : '') || ''; + } + + // Parse comma-separated values into a Set + if (debugString.trim()) { + debugFlags = new Set( + debugString + .split(',') + .map((flag) => flag.trim().toLowerCase()) + .filter((flag) => flag.length > 0), + ); + } else { + debugFlags = new Set(); + } + + return debugFlags; +}; + +/** + * Get the current active debug flags (including runtime modifications) + * @returns {Set} Set of currently active debug flags + */ +const getActiveFlags = () => { + if (runtimeFlags !== null) { + return runtimeFlags; + } + return parseDebugFlags(); +}; + +/** + * Check if a debug flag is enabled + * @param {string} flag - The debug flag to check + * @returns {boolean} True if the flag is enabled + */ +const debugFlag = (flag) => { + const activeFlags = getActiveFlags(); + + // "all" enables everything + if (activeFlags.has('all')) { + return true; + } + + // Check for specific flag + return activeFlags.has(flag.toLowerCase()); +}; + +/** + * Enable one or more debug flags at runtime + * @param {...string} flags - Debug flags to enable + * @returns {string[]} Array of currently active debug flags after enabling + */ +const debugEnable = (...flags) => { + // Initialize runtime flags from current state if not already done + if (runtimeFlags === null) { + runtimeFlags = new Set(getActiveFlags()); + } + + // Add new flags + flags.forEach((flag) => { + runtimeFlags.add(flag.toLowerCase()); + }); + + return debugList(); +}; + +/** + * Disable one or more debug flags at runtime + * @param {...string} flags - Debug flags to disable + * @returns {string[]} Array of currently active debug flags after disabling + */ +const debugDisable = (...flags) => { + // Initialize runtime flags from current state if not already done + if (runtimeFlags === null) { + runtimeFlags = new Set(getActiveFlags()); + } + + flags.forEach((flag) => { + const lowerFlag = flag.toLowerCase(); + if (lowerFlag === 'all') { + // Special case: disable all flags + runtimeFlags.clear(); + } else { + runtimeFlags.delete(lowerFlag); + } + }); + + return debugList(); +}; + +/** + * Set debug flags at runtime (overwrites existing flags) + * @param {...string} flags - Debug flags to set (replaces all current flags) + * @returns {string[]} Array of currently active debug flags after setting + */ +const debugSet = (...flags) => { + runtimeFlags = new Set( + flags.map((flag) => flag.toLowerCase()), + ); + + return debugList(); +}; + +/** + * Get current debug flags for inspection + * @returns {string[]} Array of currently active debug flags + */ +const debugList = () => Array.from(getActiveFlags()).sort(); + +// Make debug functions globally accessible in development for console use +if (typeof window !== 'undefined') { + window.debugFlag = debugFlag; + window.debugEnable = debugEnable; + window.debugDisable = debugDisable; + window.debugSet = debugSet; + window.debugList = debugList; +} + +export { + debugFlag, + debugEnable, + debugDisable, + debugSet, + debugList, +}; diff --git a/server/scripts/modules/utils/fetch.mjs b/server/scripts/modules/utils/fetch.mjs index 99ce029..2cd2f1c 100644 --- a/server/scripts/modules/utils/fetch.mjs +++ b/server/scripts/modules/utils/fetch.mjs @@ -1,31 +1,111 @@ -import { rewriteUrl } from './cors.mjs'; +import { rewriteUrl } from './url-rewrite.mjs'; + +const DEFAULT_REQUEST_TIMEOUT = 15000; // For example, with 3 retries: 15s+1s+15s+2s+15s+5s+15s = 68s + +// Centralized utilities for handling errors in Promise contexts +const safeJson = async (url, params) => { + try { + const result = await json(url, params); + // Return an object with both data and url if params.returnUrl is true + if (params?.returnUrl) { + return result; + } + // If caller didn't specify returnUrl, result is the raw API response + return result; + } catch (_error) { + // Error already logged in fetchAsync; return null to be "safe" + return null; + } +}; + +const safeText = async (url, params) => { + try { + const result = await text(url, params); + // Return an object with both data and url if params.returnUrl is true + if (params?.returnUrl) { + return result; + } + // If caller didn't specify returnUrl, result is the raw API response + return result; + } catch (_error) { + // Error already logged in fetchAsync; return null to be "safe" + return null; + } +}; + +const safeBlob = async (url, params) => { + try { + const result = await blob(url, params); + // Return an object with both data and url if params.returnUrl is true + if (params?.returnUrl) { + return result; + } + // If caller didn't specify returnUrl, result is the raw API response + return result; + } catch (_error) { + // Error already logged in fetchAsync; return null to be "safe" + return null; + } +}; + +const safePromiseAll = async (promises) => { + try { + const results = await Promise.allSettled(promises); + + return results.map((result, index) => { + if (result.status === 'fulfilled') { + return result.value; + } + // Log rejected promises for debugging (except AbortErrors which are expected) + if (result.reason?.name !== 'AbortError') { + console.warn(`Promise ${index} rejected:`, result.reason?.message || result.reason); + } + return null; + }); + } catch (error) { + console.error('safePromiseAll encountered an unexpected error:', error); + // Return array of nulls matching the input length + return new Array(promises.length).fill(null); + } +}; const json = (url, params) => fetchAsync(url, 'json', params); const text = (url, params) => fetchAsync(url, 'text', params); const blob = (url, params) => fetchAsync(url, 'blob', params); +// Hosts that don't allow custom User-Agent headers due to CORS restrictions +const USER_AGENT_EXCLUDED_HOSTS = [ + 'geocode.arcgis.com', + 'services.arcgis.com', +]; + const fetchAsync = async (_url, responseType, _params = {}) => { - // add user agent header to json request at api.weather.gov const headers = {}; - if (_url.toString().match(/api\.weather\.gov/)) { + + const checkUrl = new URL(_url, window.location.origin); + const shouldExcludeUserAgent = USER_AGENT_EXCLUDED_HOSTS.some((host) => checkUrl.hostname.includes(host)); + + // User-Agent handling: + // - Server mode (with caching proxy): Add User-Agent for all requests except excluded hosts + // - Static mode (direct requests): Only add User-Agent for api.weather.gov, avoiding CORS preflight issues with other services + const shouldAddUserAgent = !shouldExcludeUserAgent && (window.WS4KP_SERVER_AVAILABLE || _url.toString().match(/api\.weather\.gov/)); + if (shouldAddUserAgent) { headers['user-agent'] = 'Weatherstar 4000+; weatherstar@netbymatt.com'; } + // combine default and provided parameters const params = { method: 'GET', mode: 'cors', type: 'GET', - retryCount: 0, + retryCount: 3, // Default to 3 retries for any failed requests (timeout or 5xx server errors) + timeout: DEFAULT_REQUEST_TIMEOUT, ..._params, headers, }; - // store original number of retries - params.originalRetries = params.retryCount; - // build a url, including the rewrite for cors if necessary - let corsUrl = _url; - if (params.cors === true) corsUrl = rewriteUrl(_url); - const url = new URL(corsUrl, `${window.location.origin}/`); + // rewrite URLs for various services to use the backend proxy server for proper caching (and request logging) + const url = rewriteUrl(_url); // match the security protocol when not on localhost // url.protocol = window.location.hostname === 'localhost' ? url.protocol : window.location.protocol; // add parameters if necessary @@ -39,53 +119,174 @@ const fetchAsync = async (_url, responseType, _params = {}) => { } // make the request - const response = await doFetch(url, params); + try { + const response = await doFetch(url, params); - // check for ok response - if (!response.ok) throw new Error(`Fetch error ${response.status} ${response.statusText} while fetching ${response.url}`); - // return the requested response - switch (responseType) { - case 'json': - return response.json(); - case 'text': - return response.text(); - case 'blob': - return response.blob(); - default: - return response; + // check for ok response + if (!response.ok) throw new Error(`Fetch error ${response.status} ${response.statusText} while fetching ${response.url}`); + // process the response based on type + let result; + switch (responseType) { + case 'json': + result = await response.json(); + break; + case 'text': + result = await response.text(); + break; + case 'blob': + result = await response.blob(); + break; + default: + result = response; + } + + // Return both data and URL if requested + if (params.returnUrl) { + return { + data: result, + url: response.url, + }; + } + + return result; + } catch (error) { + // Enhanced error handling for different error types + if (error.name === 'AbortError') { + // AbortError always happens in the browser, regardless of server vs static mode + // Most likely causes include background tab throttling, user navigation, or client timeout + console.log(`🛑 Fetch aborted for ${_url} (background tab throttling?)`); + return null; // Always return null for AbortError instead of throwing + } if (error.name === 'TimeoutError') { + console.warn(`⏱️ Request timeout for ${_url} (${error.message})`); + } else if (error.message.includes('502')) { + console.warn(`🚪 Bad Gateway error for ${_url}`); + } else if (error.message.includes('503')) { + console.warn(`⌛ Temporarily unavailable for ${_url}`); + } else if (error.message.includes('504')) { + console.warn(`⏱️ Gateway Timeout for ${_url}`); + } else if (error.message.includes('500')) { + console.warn(`💥 Internal Server Error for ${_url}`); + } else if (error.message.includes('CORS') || error.message.includes('Access-Control')) { + console.warn(`🔒 CORS or Access Control error for ${_url}`); + } else { + console.warn(`❌ Fetch failed for ${_url} (${error.message})`); + } + + // Add standard error properties that calling code expects + if (!error.status) error.status = 0; + if (!error.responseJSON) error.responseJSON = null; + + throw error; } }; // fetch with retry and back-off -const doFetch = (url, params) => new Promise((resolve, reject) => { - fetch(url, params).then((response) => { - if (params.retryCount > 0) { - // 500 status codes should be retried after a short backoff - if (response.status >= 500 && response.status <= 599 && params.retryCount > 0) { - // call the "still waiting" function - if (typeof params.stillWaiting === 'function' && params.retryCount === params.originalRetries) { - params.stillWaiting(); - } - // decrement and retry - const newParams = { - ...params, - retryCount: params.retryCount - 1, - }; - return resolve(delay(retryDelay(params.originalRetries - newParams.retryCount), doFetch, url, newParams)); - } - // not 500 status - return resolve(response); - } - // out of retries - return resolve(response); - }) - .catch(reject); -}); +const doFetch = (url, params, originalRetryCount = null) => new Promise((resolve, reject) => { + // On the first call, store the retry count for later logging + const initialRetryCount = originalRetryCount ?? params.retryCount; -const delay = (time, func, ...args) => new Promise((resolve) => { - setTimeout(() => { - resolve(func(...args)); - }, time); + // Create AbortController for timeout + const controller = new AbortController(); + const startTime = Date.now(); + const timeoutId = setTimeout(() => { + controller.abort(); + }, params.timeout); + + // Add signal to fetch params + const fetchParams = { + ...params, + signal: controller.signal, + }; + + // Shared retry logic to avoid duplication + const attemptRetry = (reason) => { + // Safety check for params + if (!params || typeof params.retryCount !== 'number') { + console.error(`❌ Invalid params for retry: ${url}`); + return reject(new Error('Invalid retry parameters')); + } + + const retryAttempt = initialRetryCount - params.retryCount + 1; + const remainingRetries = params.retryCount - 1; + const delayMs = retryDelay(retryAttempt); + + console.warn(`🔄 Retry ${retryAttempt}/${initialRetryCount} for ${url} - ${reason} (retrying in ${delayMs}ms, ${remainingRetries} retr${remainingRetries === 1 ? 'y' : 'ies'} left)`); + + // call the "still waiting" function on first retry + if (params && params.stillWaiting && typeof params.stillWaiting === 'function' && retryAttempt === 1) { + try { + params.stillWaiting(); + } catch (callbackError) { + console.warn(`⚠️ stillWaiting callback error for ${url}:`, callbackError.message); + } + } + // decrement and retry with safe parameter copying + const newParams = { + ...params, + retryCount: Math.max(0, params.retryCount - 1), // Ensure retryCount doesn't go negative + }; + // Use setTimeout directly instead of the delay wrapper to avoid Promise resolution issues + setTimeout(() => { + doFetch(url, newParams, initialRetryCount).then(resolve).catch(reject); + }, delayMs); + return undefined; // Explicit return for linter + }; + + fetch(url, fetchParams).then((response) => { + clearTimeout(timeoutId); // Clear timeout on successful response + + // Retry 500 status codes if we have retries left + if (params && params.retryCount > 0 && response.status >= 500 && response.status <= 599) { + let errorType = 'Server error'; + if (response.status === 502) { + errorType = 'Bad Gateway'; + } else if (response.status === 503) { + errorType = 'Service Unavailable'; + } else if (response.status === 504) { + errorType = 'Gateway Timeout'; + } + return attemptRetry(`${errorType} ${response.status} ${response.statusText}`); + } + + // Log when we're out of retries for server errors + // if (response.status >= 500 && response.status <= 599) { + // console.warn(`⚠️ Server error ${response.status} ${response.statusText} for ${url} - no retries remaining`); + // } + + // successful response or out of retries + return resolve(response); + }).catch((error) => { + clearTimeout(timeoutId); // Clear timeout on error + + // Enhance AbortError detection by checking if we're near the timeout duration + if (error.name === 'AbortError') { + const duration = Date.now() - startTime; + const isLikelyTimeout = duration >= (params.timeout - 1000); // Within 1 second of timeout + + // Convert likely timeouts to TimeoutError for better error reporting + if (isLikelyTimeout) { + const reason = `Request timeout after ${Math.round(duration / 1000)}s`; + if (params && params.retryCount > 0) { + return attemptRetry(reason); + } + // Convert to a timeout error for better error reporting + const timeoutError = new Error(`Request timeout after ${Math.round(duration / 1000)}s`); + timeoutError.name = 'TimeoutError'; + reject(timeoutError); + return undefined; + } + } + + // Retry network errors if we have retries left + if (params && params.retryCount > 0 && error.name !== 'AbortError') { + const reason = error.name === 'TimeoutError' ? 'Request timeout' : `Network error: ${error.message}`; + return attemptRetry(reason); + } + + // out of retries or AbortError - reject + reject(error); + return undefined; // Explicit return for linter + }); }); const retryDelay = (retryNumber) => { @@ -102,4 +303,8 @@ export { json, text, blob, + safeJson, + safeText, + safeBlob, + safePromiseAll, }; diff --git a/server/scripts/modules/utils/forecast-utils.mjs b/server/scripts/modules/utils/forecast-utils.mjs new file mode 100644 index 0000000..52970f0 --- /dev/null +++ b/server/scripts/modules/utils/forecast-utils.mjs @@ -0,0 +1,30 @@ +// shared utility functions for forecast processing + +/** + * Filter out expired periods from forecast data + * @param {Array} periods - Array of forecast periods + * @param {string} forecastUrl - URL used for logging (optional) + * @returns {Array} - Array of active (non-expired) periods + */ +const filterExpiredPeriods = (periods, forecastUrl = '') => { + const now = new Date(); + + const { activePeriods, removedPeriods } = periods.reduce((acc, period) => { + const endTime = new Date(period.endTime); + if (endTime > now) { + acc.activePeriods.push(period); + } else { + acc.removedPeriods.push(period); + } + return acc; + }, { activePeriods: [], removedPeriods: [] }); + + if (removedPeriods.length > 0) { + const source = forecastUrl ? ` from ${forecastUrl}` : ''; + console.log(`🚮 Forecast: Removed expired periods${source}: ${removedPeriods.map((p) => `${p.name} (ended ${p.endTime})`).join(', ')}`); + } + + return activePeriods; +}; + +export default filterExpiredPeriods; diff --git a/server/scripts/modules/utils/image.mjs b/server/scripts/modules/utils/image.mjs index ac6c48a..d70271a 100644 --- a/server/scripts/modules/utils/image.mjs +++ b/server/scripts/modules/utils/image.mjs @@ -5,6 +5,11 @@ import { blob } from './fetch.mjs'; // a list of cached icons is used to avoid hitting the cache multiple times const cachedImages = []; const preloadImg = (src) => { + if (!src || typeof src !== 'string') { + console.warn(`preloadImg expects a URL string, received: '${src}' (${typeof src})`); + return false; + } + if (cachedImages.includes(src)) return false; blob(src); cachedImages.push(src); diff --git a/server/scripts/modules/utils/mapclick.mjs b/server/scripts/modules/utils/mapclick.mjs new file mode 100644 index 0000000..532f386 --- /dev/null +++ b/server/scripts/modules/utils/mapclick.mjs @@ -0,0 +1,669 @@ +/** + * MapClick API Fallback Utility + * + * Provides fallback functionality to fetch weather data from forecast.weather.gov's MapClick API + * when the primary api.weather.gov data is stale or incomplete. + * + * MapClick uses the SBN feed which typically has faster METAR (airport) station updates + * but is limited to airport stations only. The primary API uses MADIS which is more + * comprehensive but can have delayed ingestion. + */ + +import { safeJson } from './fetch.mjs'; +import { debugFlag } from './debug.mjs'; + +/** + * Parse MapClick date format to JavaScript Date + * @param {string} dateString - Format: "18 Jun 23:53 pm EDT" + * @returns {Date|null} - Parsed date or null if invalid + */ +export const parseMapClickDate = (dateString) => { + try { + // Extract components using regex + const match = dateString.match(/(\d{1,2})\s+(\w{3})\s+(\d{1,2}):(\d{2})\s+(am|pm)\s+(\w{3})/i); + if (!match) return null; + + const [, day, month, hour, minute, ampm, timezone] = match; + const currentYear = new Date().getFullYear(); + + // Convert to 12-hour format since we have AM/PM + let hour12 = parseInt(hour, 10); + // If it's in 24-hour format but we have AM/PM, convert it + if (hour12 > 12) { + hour12 -= 12; + } + + // Reconstruct in a format that Date.parse understands (12-hour format with AM/PM) + const standardFormat = `${month} ${day}, ${currentYear} ${hour12}:${minute}:00 ${ampm.toUpperCase()} ${timezone}`; + + const parsedDate = new Date(standardFormat); + + // Check if the date is valid + if (Number.isNaN(parsedDate.getTime())) { + console.warn(`MapClick: Invalid date parsed from: ${dateString} -> ${standardFormat}`); + return null; + } + + return parsedDate; + } catch (error) { + console.warn(`MapClick: Failed to parse date: ${dateString}`, error); + return null; + } +}; + +/** + * Normalize icon name to determine if it's night and get base name for mapping + * @param {string} iconName - Icon name without extension + * @returns {Object} - { isNightTime: boolean, baseIconName: string } + */ +const normalizeIconName = (iconName) => { + // Handle special cases where 'n' is not a prefix (hi_nshwrs, hi_ntsra) + const hiNightMatch = iconName.match(/^hi_n(.+)/); + if (hiNightMatch) { + return { + isNightTime: true, + baseIconName: `hi_${hiNightMatch[1]}`, // Reconstruct as hi_[condition] + }; + } + + // Handle the general 'n' prefix rule (including nra, nwind_skc, etc.) + if (iconName.startsWith('n')) { + return { + isNightTime: true, + baseIconName: iconName.substring(1), // Strip the 'n' prefix + }; + } + + // Not a night icon + return { + isNightTime: false, + baseIconName: iconName, + }; +}; + +/** + * Convert MapClick weather image filename to weather.gov API icon format + * @param {string} weatherImage - MapClick weather image filename (e.g., 'bkn.png') + * @returns {string|null} - Weather.gov API icon URL or null if invalid/missing + */ +const convertMapClickIcon = (weatherImage) => { + // Return null for missing, invalid, or NULL values - let caller handle defaults + if (!weatherImage || weatherImage === 'NULL' || weatherImage === 'NA') { + return null; + } + + // Remove .png extension if present + const iconName = weatherImage.replace('.png', ''); + + // Determine if this is a night icon and get the base name for mapping + const { isNightTime, baseIconName } = normalizeIconName(iconName); + const timeOfDay = isNightTime ? 'night' : 'day'; + + // MapClick icon filename to weather.gov API condition mapping + // This maps MapClick specific icon names to standard API icon names + // Night variants are handled by stripping 'n' prefix before lookup + // based on https://www.weather.gov/forecast-icons/ + const iconMapping = { + // Clear/Fair conditions + skc: 'skc', // Clear sky condition + + // Cloud coverage + few: 'few', // A few clouds + sct: 'sct', // Scattered clouds / Partly cloudy + bkn: 'bkn', // Broken clouds / Mostly cloudy + ovc: 'ovc', // Overcast + + // Light Rain + Drizzle + minus_ra: 'rain', // Light rain -> rain + ra: 'rain', // Rain + // Note: nra.png is used for both light rain and rain at night + // but normalizeIconName strips the 'n' to get 'ra' which maps to 'rain' + + // Snow variants + sn: 'snow', // Snow + + // Rain + Snow combinations + ra_sn: 'rain_snow', // Rain snow + rasn: 'rain_snow', // Standard rain snow + + // Ice Pellets/Sleet + raip: 'rain_sleet', // Rain ice pellets -> rain_sleet + ip: 'sleet', // Ice pellets + + // Freezing Rain + ra_fzra: 'rain_fzra', // Rain freezing rain -> rain_fzra + fzra: 'fzra', // Freezing rain + + // Freezing Rain + Snow + fzra_sn: 'snow_fzra', // Freezing rain snow -> snow_fzra + + // Snow + Ice Pellets + snip: 'snow_sleet', // Snow ice pellets -> snow_sleet + + // Showers + hi_shwrs: 'rain_showers_hi', // Isolated showers -> rain_showers_hi + shra: 'rain_showers', // Showers -> rain_showers + + // Thunderstorms + tsra: 'tsra', // Thunderstorm + scttsra: 'tsra_sct', // Scattered thunderstorm -> tsra_sct + hi_tsra: 'tsra_hi', // Isolated thunderstorm -> tsra_hi + + // Fog + fg: 'fog', // Fog + + // Wind conditions + wind_skc: 'wind_skc', // Clear and windy + wind_few: 'wind_few', // Few clouds and windy + wind_sct: 'wind_sct', // Scattered clouds and windy + wind_bkn: 'wind_bkn', // Broken clouds and windy + wind_ovc: 'wind_ovc', // Overcast and windy + + // Extreme weather + blizzard: 'blizzard', // Blizzard + cold: 'cold', // Cold + hot: 'hot', // Hot + du: 'dust', // Dust + fu: 'smoke', // Smoke + hz: 'haze', // Haze + + // Tornadoes + fc: 'tornado', // Funnel cloud + tor: 'tornado', // Tornado + }; + + // Get the mapped condition, return null if not found in the mapping + const condition = iconMapping[baseIconName]; + if (!condition) { + return null; + } + + return `/icons/land/${timeOfDay}/${condition}?size=medium`; +}; + +/** + * Convert MapClick observation data to match the standard API format + * + * This is NOT intended to be a full replacment process, but rather a minimal + * fallback for the data used in WS4KP. + * + * @param {Object} mapClickObs - MapClick observation data + * @returns {Object} - Data formatted to match api.weather.gov structure + */ +export const convertMapClickObservationsToApiFormat = (mapClickObs) => { + // Convert temperature from Fahrenheit to Celsius (only if valid) + const tempF = parseFloat(mapClickObs.Temp); + const tempC = !Number.isNaN(tempF) ? (tempF - 32) * 5 / 9 : null; + + const dewpF = parseFloat(mapClickObs.Dewp); + const dewpC = !Number.isNaN(dewpF) ? (dewpF - 32) * 5 / 9 : null; + + // Convert wind speed from mph to km/h (only if valid) + const windMph = parseFloat(mapClickObs.Winds); + const windKmh = !Number.isNaN(windMph) ? windMph * 1.60934 : null; + + // Convert wind gust from mph to km/h (only if valid and not "NA") + const gustMph = mapClickObs.Gust !== 'NA' ? parseFloat(mapClickObs.Gust) : NaN; + const windGust = !Number.isNaN(gustMph) ? gustMph * 1.60934 : null; + + // Convert wind direction (only if valid) + const windDir = parseFloat(mapClickObs.Windd); + const windDirection = !Number.isNaN(windDir) ? windDir : null; + + // Convert pressure from inHg to Pa (only if valid) + const pressureInHg = parseFloat(mapClickObs.SLP); + const pressurePa = !Number.isNaN(pressureInHg) ? pressureInHg * 3386.39 : null; + + // Convert visibility from miles to meters (only if valid) + const visibilityMiles = parseFloat(mapClickObs.Visibility); + const visibilityMeters = !Number.isNaN(visibilityMiles) ? visibilityMiles * 1609.34 : null; + + // Convert relative humidity (only if valid) + const relh = parseFloat(mapClickObs.Relh); + const relativeHumidity = !Number.isNaN(relh) ? relh : null; + + // Convert wind chill from Fahrenheit to Celsius (only if valid and not "NA") + const windChillF = mapClickObs.WindChill !== 'NA' ? parseFloat(mapClickObs.WindChill) : NaN; + const windChill = !Number.isNaN(windChillF) ? (windChillF - 32) * 5 / 9 : null; + + // Convert MapClick weather image to weather.gov API icon format + const iconUrl = convertMapClickIcon(mapClickObs.Weatherimage); + + return { + features: [ + { + properties: { + timestamp: parseMapClickDate(mapClickObs.Date)?.toISOString() || new Date().toISOString(), + temperature: { value: tempC, unitCode: 'wmoUnit:degC' }, + dewpoint: { value: dewpC, unitCode: 'wmoUnit:degC' }, + windDirection: { value: windDirection, unitCode: 'wmoUnit:degree_(angle)' }, + windSpeed: { value: windKmh, unitCode: 'wmoUnit:km_h-1' }, + windGust: { value: windGust, unitCode: 'wmoUnit:km_h-1' }, + barometricPressure: { value: pressurePa, unitCode: 'wmoUnit:Pa' }, + visibility: { value: visibilityMeters, unitCode: 'wmoUnit:m' }, + relativeHumidity: { value: relativeHumidity, unitCode: 'wmoUnit:percent' }, + textDescription: mapClickObs.Weather || null, + icon: iconUrl, // Can be null if no valid icon available + heatIndex: { value: null }, + windChill: { value: windChill }, + cloudLayers: [], // no cloud layer data available from MapClick + }, + }, + ], + }; +}; + +/** + * Convert MapClick forecast data to weather.gov API forecast format + * @param {Object} mapClickData - Raw MapClick response data + * @returns {Object|null} - Forecast data in API format or null if invalid + */ +export const convertMapClickForecastToApiFormat = (mapClickData) => { + if (!mapClickData?.data || !mapClickData?.time) { + return null; + } + + const { data, time } = mapClickData; + const { + temperature, weather, iconLink, text, pop, + } = data; + + if (!temperature || !weather || !iconLink || !text || !time.startValidTime || !time.startPeriodName) { + return null; + } + + // Convert each forecast period + const periods = temperature.map((temp, index) => { + if (index >= weather.length || index >= iconLink.length || index >= text.length || index >= time.startValidTime.length) { + return null; + } + + // Determine if this is a daytime period based on the period name + const periodName = time.startPeriodName[index] || ''; + const isDaytime = !periodName.toLowerCase().includes('night'); + + // Convert icon from MapClick format to API format + let icon = iconLink[index]; + if (icon) { + let filename = null; + + // Handle DualImage.php URLs: extract from 'i' parameter + if (icon.includes('DualImage.php')) { + const iMatch = icon.match(/[?&]i=([^&]+)/); + if (iMatch) { + [, filename] = iMatch; + } + } else { + // Handle regular image URLs: extract filename from path, removing percentage numbers + const pathMatch = icon.match(/\/([^/]+?)(?:\d+)?(?:\.png)?$/); + if (pathMatch) { + [, filename] = pathMatch; + } + } + + if (filename) { + icon = convertMapClickIcon(filename); + } + } + + return { + number: index + 1, + name: periodName, + startTime: time.startValidTime[index], + endTime: index + 1 < time.startValidTime.length ? time.startValidTime[index + 1] : null, + isDaytime, + temperature: parseInt(temp, 10), + temperatureUnit: 'F', + temperatureTrend: null, + probabilityOfPrecipitation: { + unitCode: 'wmoUnit:percent', + value: pop[index] ? parseInt(pop[index], 10) : null, + }, + dewpoint: { + unitCode: 'wmoUnit:degC', + value: null, // MapClick doesn't provide dewpoint in forecast + }, + relativeHumidity: { + unitCode: 'wmoUnit:percent', + value: null, // MapClick doesn't provide humidity in forecast + }, + windSpeed: null, // MapClick doesn't provide wind speed in forecast + windDirection: null, // MapClick doesn't provide wind direction in forecast + icon, + shortForecast: weather[index], + detailedForecast: text[index], + }; + }).filter((period) => period !== null); + + // Return in API forecast format + return { + type: 'Feature', + geometry: { + type: 'Point', + coordinates: [mapClickData.location?.longitude, mapClickData.location?.latitude], + }, + properties: { + units: 'us', + forecastGenerator: 'MapClick', + generatedAt: new Date().toISOString(), + updateTime: parseMapClickDate(mapClickData.creationDateLocal)?.toISOString() || new Date().toISOString(), + validTimes: `${time.startValidTime[0]}/${time.startValidTime[time.startValidTime.length - 1]}`, + elevation: { + unitCode: 'wmoUnit:m', + value: mapClickData.location?.elevation ? parseFloat(mapClickData.location.elevation) : null, + }, + periods, + }, + }; +}; + +/** + * Check if API data is stale and should trigger a MapClick fallback + * @param {string|Date} timestamp - ISO timestamp string or Date object from API data + * @param {number} maxAgeMinutes - Maximum age in minutes before considering stale (default: 60) + * @returns {Object} - { isStale: boolean, ageInMinutes: number } + */ +export const isDataStale = (timestamp, maxAgeMinutes = 60) => { + // Handle both Date objects and timestamp strings + const observationTime = timestamp instanceof Date ? timestamp : new Date(timestamp); + const now = new Date(); + const ageInMinutes = (now - observationTime) / (1000 * 60); + + return { + isStale: ageInMinutes > maxAgeMinutes, + ageInMinutes, + }; +}; + +/** + * Fetch MapClick data from the MapClick API + * @param {number} latitude - Latitude coordinate + * @param {number} longitude - Longitude coordinate + * @param {Object} options - Optional parameters + * @param {string} stationId - Station identifier (used for URL logging) + * @param {Function} options.stillWaiting - Callback for loading status + * @param {number} options.retryCount - Number of retries (default: 3) + * @returns {Object|null} - MapClick data or null if failed + */ +export const getMapClickData = async (latitude, longitude, stationId, options = {}) => { + const { stillWaiting, retryCount = 3 } = options; + + // Round coordinates to 4 decimal places to match weather.gov API precision + const lat = latitude.toFixed(4); + const lon = longitude.toFixed(4); + + // &unit=0&lg=english are default parameters for MapClick API + const mapClickUrl = `https://forecast.weather.gov/MapClick.php?FcstType=json&lat=${lat}&lon=${lon}&station=${stationId}`; + + try { + const mapClickData = await safeJson(mapClickUrl, { + retryCount, + stillWaiting, + }); + + if (mapClickData) { + return mapClickData; + } + + if (debugFlag('verbose-failures')) { + console.log(`MapClick: No data available for ${lat},${lon}`); + } + return null; + } catch (error) { + console.error(`Unexpected error fetching MapClick data for ${lat},${lon}: ${error.message}`); + return null; + } +}; + +/** + * Get current observation from MapClick API in weather.gov API format + * @param {number} latitude - Latitude coordinate + * @param {number} longitude - Longitude coordinate + * @param {string} stationId - Station identifier (used for URL logging) + * @param {Object} options - Optional parameters + * @param {Function} options.stillWaiting - Callback for loading status + * @param {number} options.retryCount - Number of retries (default: 3) + * @returns {Object|null} - Current observation in API format or null if failed + */ +export const getMapClickCurrentObservation = async (latitude, longitude, stationId, options = {}) => { + const { stillWaiting, retryCount = 3 } = options; + + const mapClickData = await getMapClickData(latitude, longitude, stationId, { stillWaiting, retryCount }); + + if (!mapClickData?.currentobservation) { + return null; + } + + // Convert to API format + return convertMapClickObservationsToApiFormat(mapClickData.currentobservation); +}; + +/** + * Get forecast data from MapClick API in weather.gov API format + * @param {number} latitude - Latitude coordinate + * @param {number} longitude - Longitude coordinate + * @param {string} stationId - Station identifier (used for URL logging) + * @param {Object} options - Optional parameters + * @param {Function} options.stillWaiting - Callback for loading status + * @param {number} options.retryCount - Number of retries (default: 3) + * @returns {Object|null} - Forecast data in API format or null if failed + */ +export const getMapClickForecast = async (latitude, longitude, stationId, options = {}) => { + const { stillWaiting, retryCount = 3 } = options; + + const mapClickData = await getMapClickData(latitude, longitude, stationId, { stillWaiting, retryCount }); + + if (!mapClickData) { + return null; + } + + // Convert to API format + return convertMapClickForecastToApiFormat(mapClickData); +}; + +/** + * Enhanced observation fetcher with MapClick fallback + * Centralized logic for checking data quality and falling back to MapClick when needed + * @param {Object} observationData - Original API observation data + * @param {Object} options - Configuration options + * @param {Array} options.requiredFields - Array of field definitions with { name, check, required? } + * @param {number} options.maxOptionalMissing - Max missing optional fields allowed (default: 0) + * @param {string} options.stationId - Station identifier for looking up coordinates (e.g., 'KORD') + * @param {Function} options.stillWaiting - Loading callback + * @param {string} options.debugContext - Debug logging context name + * @param {number} options.maxAgeMinutes - Max age before considering stale (default: 60) + * @returns {Object} - { data, wasImproved, improvements, missingFields } + */ +export const enhanceObservationWithMapClick = async (observationData, options = {}) => { + const { + requiredFields = [], + maxOptionalMissing = 0, + stationId, + stillWaiting, + debugContext = 'mapclick', + maxAgeMinutes = 80, // hourly observation plus 20 minute ingestion delay + } = options; + + // Helper function to return original data with consistent logging + const returnOriginalData = (reason, missingRequired = [], missingOptional = [], isStale = false, ageInMinutes = 0) => { + if (debugFlag(debugContext)) { + const issues = []; + if (isStale) issues.push(`API data is stale: ${ageInMinutes.toFixed(0)} minutes old`); + if (missingRequired.length > 0) issues.push(`API data missing required: ${missingRequired.join(', ')}`); + if (missingOptional.length > maxOptionalMissing) issues.push(`API data missing optional: ${missingOptional.join(', ')}`); + + if (reason) { + if (issues.length > 0) { + console.log(`🚫 ${debugContext}: Station ${stationId} ${reason} (${issues.join(', ')})`); + } else { + console.log(`🚫 ${debugContext}: Station ${stationId} ${reason}`); + } + } else if (issues.length > 0) { + console.log(`🚫 ${debugContext}: Station ${stationId} ${issues.join('; ')}`); + } + } + return { + data: observationData, + wasImproved: false, + improvements: [], + missingFields: [...missingRequired, ...missingOptional], + }; + }; + + if (!observationData) { + return returnOriginalData('no original observation data'); + } + + // Look up station coordinates from global StationInfo + if (!stationId || typeof window === 'undefined' || !window.StationInfo) { + return returnOriginalData('no station ID'); + } + + const stationLookup = Object.values(window.StationInfo).find((s) => s.id === stationId); + if (!stationLookup) { + let reason = null; + if (stationId.length === 4) { // MapClick only supports 4-letter station IDs, so other failures are "expected" + reason = `station ${stationId} not found in StationInfo`; + } + return returnOriginalData(reason); + } + + // Check data staleness + const observationTime = new Date(observationData.timestamp); + const { isStale, ageInMinutes } = isDataStale(observationTime, maxAgeMinutes); + + // Categorize fields by required/optional + const requiredFieldDefs = requiredFields.filter((field) => field.required !== false); + const optionalFieldDefs = requiredFields.filter((field) => field.required === false); + + // Check current data quality + const missingRequired = requiredFieldDefs.filter((field) => field.check(observationData)).map((field) => field.name); + const missingOptional = optionalFieldDefs.filter((field) => field.check(observationData)).map((field) => field.name); + const missingOptionalCount = missingOptional.length; + + // Determine if we should try MapClick + const shouldTryMapClick = isStale || missingRequired.length > 0 || missingOptionalCount > maxOptionalMissing; + + if (!shouldTryMapClick) { + return returnOriginalData(null, missingRequired, missingOptional, isStale, ageInMinutes); + } + + // Try MapClick API + const mapClickData = await getMapClickCurrentObservation(stationLookup.lat, stationLookup.lon, stationId, { + stillWaiting, + retryCount: 1, + }); + + if (!mapClickData) { + return returnOriginalData('MapClick fetch failed', missingRequired, missingOptional, isStale, ageInMinutes); + } + + // Evaluate MapClick data quality + const mapClickProps = mapClickData.features[0].properties; + const mapClickTimestamp = new Date(mapClickProps.timestamp); + const isFresher = mapClickTimestamp > observationTime; + + const mapClickMissingRequired = requiredFieldDefs.filter((field) => field.check(mapClickProps)).map((field) => field.name); + const mapClickMissingOptional = optionalFieldDefs.filter((field) => field.check(mapClickProps)).map((field) => field.name); + const mapClickMissingOptionalCount = mapClickMissingOptional.length; + + // Determine if MapClick data is better + let hasBetterQuality = false; + if (optionalFieldDefs.length > 0) { + // For modules with optional fields (like currentweather) + hasBetterQuality = (mapClickMissingRequired.length < missingRequired.length) + || (missingOptionalCount > maxOptionalMissing && mapClickMissingOptionalCount <= maxOptionalMissing); + } else { + // For modules with only required fields (like latestobservations, regionalforecast) + hasBetterQuality = mapClickMissingRequired.length < missingRequired.length; + } + + // Only use MapClick if: + // 1. It doesn't make required fields worse AND + // 2. It's either fresher OR has better quality + const doesNotWorsenRequired = mapClickMissingRequired.length <= missingRequired.length; + const shouldUseMapClick = doesNotWorsenRequired && (isFresher || hasBetterQuality); + if (!shouldUseMapClick) { + // Build brief rejection reason only when debugging is enabled + let rejectionReason = 'MapClick data rejected'; + if (debugFlag(debugContext)) { + const rejectionDetails = []; + + if (!doesNotWorsenRequired) { + rejectionDetails.push(`has ${mapClickMissingRequired.length - missingRequired.length} missing fields`); + if (mapClickMissingRequired.length > 0) { + rejectionDetails.push(`required: ${mapClickMissingRequired.join(', ')}`); + } + } else { + // MapClick doesn't worsen required fields, but wasn't good enough + if (!hasBetterQuality) { + if (optionalFieldDefs.length > 0 && mapClickMissingOptional.length > missingOptional.length) { + rejectionDetails.push(`optional: ${mapClickMissingOptional.length} vs ${missingOptional.length}`); + } + } + if (!isFresher) { + const mapClickAgeInMinutes = Math.round((Date.now() - mapClickTimestamp) / (1000 * 60)); + rejectionDetails.push(`older: ${mapClickAgeInMinutes}min`); + } + } + + if (rejectionDetails.length > 0) { + rejectionReason += `: ${rejectionDetails.join('; ')}`; + } + } + + return returnOriginalData(rejectionReason, missingRequired, missingOptional, isStale, ageInMinutes); + } + + // Build improvements list for logging + const improvements = []; + if (isFresher) { + // NOTE: for the forecast version, we'd want to use the `updateTime` property instead of `timestamp` + const mapClickAgeInMinutes = Math.round((Date.now() - mapClickTimestamp) / (1000 * 60)); + improvements.push(`${mapClickAgeInMinutes} minutes old vs. ${ageInMinutes.toFixed(0)} minutes old`); + } + + if (hasBetterQuality) { + const nowPresentRequired = missingRequired.filter((fieldName) => { + const field = requiredFieldDefs.find((f) => f.name === fieldName); + return field && !field.check(mapClickProps); + }); + const nowPresentOptional = missingOptional.filter((fieldName) => { + const field = optionalFieldDefs.find((f) => f.name === fieldName); + return field && !field.check(mapClickProps); + }); + + if (nowPresentRequired.length > 0) { + improvements.push(`provides missing required: ${nowPresentRequired.join(', ')}`); + } + if (nowPresentOptional.length > 0) { + improvements.push(`provides missing optional: ${nowPresentOptional.join(', ')}`); + } + if (nowPresentRequired.length === 0 && nowPresentOptional.length === 0 && mapClickMissingRequired.length < missingRequired.length) { + improvements.push('better data quality'); + } + } + + // Log the improvements + if (debugFlag(debugContext)) { + console.log(`🗺️ ${debugContext}: preferring MapClick data for station ${stationId} (${improvements.join('; ')})`); + } + + return { + data: mapClickProps, + wasImproved: true, + improvements, + missingFields: [...mapClickMissingRequired, ...mapClickMissingOptional], + }; +}; + +export default { + parseMapClickDate, + convertMapClickObservationsToApiFormat, + convertMapClickForecastToApiFormat, + isDataStale, + getMapClickData, + getMapClickCurrentObservation, + getMapClickForecast, + enhanceObservationWithMapClick, +}; diff --git a/server/scripts/modules/utils/metar.mjs b/server/scripts/modules/utils/metar.mjs new file mode 100644 index 0000000..98b371e --- /dev/null +++ b/server/scripts/modules/utils/metar.mjs @@ -0,0 +1,153 @@ +// METAR parsing utilities using metar-taf-parser library +import { parseMetar } from '../../vendor/auto/metar-taf-parser.mjs'; + +/** + * Augment observation data by parsing METAR when API fields are missing + * @param {Object} observation - The observation object from the API + * @returns {Object} - Augmented observation with parsed METAR data filled in + */ +const augmentObservationWithMetar = (observation) => { + if (!observation?.rawMessage) { + return observation; + } + + const metar = { ...observation }; + + try { + const metarData = parseMetar(observation.rawMessage); + + if (observation.windSpeed?.value === null && metarData.wind?.speed !== undefined) { + metar.windSpeed = { + ...observation.windSpeed, + value: metarData.wind.speed * 1.852, // Convert knots to km/h (API uses km/h) + qualityControl: 'M', // M for METAR-derived + }; + } + + if (observation.windDirection?.value === null && metarData.wind?.degrees !== undefined) { + metar.windDirection = { + ...observation.windDirection, + value: metarData.wind.degrees, + qualityControl: 'M', + }; + } + + if (observation.windGust?.value === null && metarData.wind?.gust !== undefined) { + metar.windGust = { + ...observation.windGust, + value: metarData.wind.gust * 1.852, // Convert knots to km/h + qualityControl: 'M', + }; + } + + if (observation.temperature?.value === null && metarData.temperature !== undefined) { + metar.temperature = { + ...observation.temperature, + value: metarData.temperature, + qualityControl: 'M', + }; + } + + if (observation.dewpoint?.value === null && metarData.dewPoint !== undefined) { + metar.dewpoint = { + ...observation.dewpoint, + value: metarData.dewPoint, + qualityControl: 'M', + }; + } + + if (observation.barometricPressure?.value === null && metarData.altimeter !== undefined) { + // Convert inHg to Pascals + const pascals = Math.round(metarData.altimeter * 3386.39); + metar.barometricPressure = { + ...observation.barometricPressure, + value: pascals, + qualityControl: 'M', + }; + } + + // Calculate relative humidity if missing from API but we have temp and dewpoint + if (observation.relativeHumidity?.value === null && metar.temperature?.value !== null && metar.dewpoint?.value !== null) { + const humidity = calculateRelativeHumidity(metar.temperature.value, metar.dewpoint.value); + metar.relativeHumidity = { + ...observation.relativeHumidity, + value: humidity, + qualityControl: 'M', // M for METAR-derived + }; + } + + if (observation.visibility?.value === null && metarData.visibility?.value !== undefined) { + let visibilityKm; + if (metarData.visibility.unit === 'SM') { + // Convert statute miles to kilometers + visibilityKm = metarData.visibility.value * 1.609344; + } else if (metarData.visibility.unit === 'm') { + // Convert meters to kilometers + visibilityKm = metarData.visibility.value / 1000; + } else { + // Assume it's already in the right unit + visibilityKm = metarData.visibility.value; + } + + metar.visibility = { + ...observation.visibility, + value: Math.round(visibilityKm * 10) / 10, // Round to 1 decimal place + qualityControl: 'M', + }; + } + + if (observation.cloudLayers?.[0]?.base?.value === null && metarData.clouds?.length > 0) { + // Find the lowest broken (BKN) or overcast (OVC) layer for ceiling + const ceilingLayer = metarData.clouds + .filter((cloud) => cloud.type === 'BKN' || cloud.type === 'OVC') + .sort((a, b) => a.height - b.height)[0]; + + if (ceilingLayer) { + // Convert feet to meters + const heightMeters = Math.round(ceilingLayer.height * 0.3048); + + // Create cloud layer structure if it doesn't exist + if (!metar.cloudLayers || !metar.cloudLayers[0]) { + metar.cloudLayers = [{ + base: { + value: heightMeters, + qualityControl: 'M', + }, + }]; + } else { + metar.cloudLayers[0].base = { + ...observation.cloudLayers[0].base, + value: heightMeters, + qualityControl: 'M', + }; + } + } + } + } catch (error) { + // If METAR parsing fails, just return the original observation + console.warn(`Failed to parse METAR: ${error.message}`); + return observation; + } + + return metar; +}; + +/** + * Calculate relative humidity from temperature and dewpoint + * @param {number} temperature - Temperature in Celsius + * @param {number} dewpoint - Dewpoint in Celsius + * @returns {number} Relative humidity as a percentage (0-100) + */ +const calculateRelativeHumidity = (temperature, dewpoint) => { + // Using the Magnus formula approximation + const a = 17.625; + const b = 243.04; + + const alpha = Math.log(Math.exp((a * dewpoint) / (b + dewpoint)) / Math.exp((a * temperature) / (b + temperature))); + const relativeHumidity = Math.exp(alpha) * 100; + + // Clamp between 0 and 100 and round to nearest integer + return Math.round(Math.max(0, Math.min(100, relativeHumidity))); +}; + +export default augmentObservationWithMetar; diff --git a/server/scripts/modules/utils/nosleep.mjs b/server/scripts/modules/utils/nosleep.mjs index 53fe5f9..25125bc 100644 --- a/server/scripts/modules/utils/nosleep.mjs +++ b/server/scripts/modules/utils/nosleep.mjs @@ -7,12 +7,19 @@ const noSleep = (enable = false) => { // get a nosleep controller if (!noSleep.controller) noSleep.controller = new NoSleep(); // don't call anything if the states match - if (wakeLock === enable) return false; + if (wakeLock === enable) return Promise.resolve(false); // store the value wakeLock = enable; // call the function - if (enable) return noSleep.controller.enable(); - return noSleep.controller.disable(); + if (enable) { + return noSleep.controller.enable().catch((error) => { + // Handle wake lock request failures gracefully + console.warn('Wake lock request failed:', error.message); + wakeLock = false; + return false; + }); + } + return Promise.resolve(noSleep.controller.disable()); }; export default noSleep; diff --git a/server/scripts/modules/utils/scroll-timing.mjs b/server/scripts/modules/utils/scroll-timing.mjs new file mode 100644 index 0000000..a647a46 --- /dev/null +++ b/server/scripts/modules/utils/scroll-timing.mjs @@ -0,0 +1,66 @@ +// Utility functions for dynamic scroll timing calculations + +/** + * Calculate dynamic scroll timing based on actual content dimensions + * @param {HTMLElement} list - The scrollable content element + * @param {HTMLElement} container - The container element (for measuring display height) + * @param {Object} options - Timing configuration options + * @param {number} options.scrollSpeed - Pixels per second scroll speed (default: 50) + * @param {number} options.initialDelay - Seconds before scrolling starts (default: 3.0) + * @param {number} options.finalPause - Seconds after scrolling ends (default: 3.0) + * @param {number} options.staticDisplay - Seconds for static display when no scrolling needed (default: same as initialDelay + finalPause) + * @param {number} options.baseDelay - Milliseconds per timing count (default: 40) + * @returns {Object} Timing configuration object with delay array, scrollTiming, and baseDelay + */ +const calculateScrollTiming = (list, container, options = {}) => { + const { + scrollSpeed = 50, + initialDelay = 3.0, + finalPause = 3.0, + staticDisplay = initialDelay + finalPause, + baseDelay = 40, + } = options; + + // timing conversion helper + const secondsToTimingCounts = (seconds) => Math.ceil(seconds * 1000 / baseDelay); + + // calculate actual scroll distance needed + const displayHeight = container.offsetHeight; + const contentHeight = list.scrollHeight; + const scrollableHeight = Math.max(0, contentHeight - displayHeight); + + // calculate scroll time based on actual distance and speed + const scrollTimeSeconds = scrollableHeight > 0 ? scrollableHeight / scrollSpeed : 0; + + // convert seconds to timing counts + const initialCounts = secondsToTimingCounts(initialDelay); + const scrollCounts = secondsToTimingCounts(scrollTimeSeconds); + const finalCounts = secondsToTimingCounts(finalPause); + const staticCounts = secondsToTimingCounts(staticDisplay); + + // calculate pixels per count based on our actual scroll distance and time + // This ensures the scroll animation matches our timing perfectly + const pixelsPerCount = scrollCounts > 0 ? scrollableHeight / scrollCounts : 0; + + // Build timing array - simple approach + const delay = []; + + if (scrollableHeight === 0) { + // No scrolling needed - just show static content + delay.push(staticCounts); + } else { + // Initial delay + scroll time + final pause + delay.push(initialCounts + scrollCounts + finalCounts); + } + + return { + baseDelay, + delay, + scrollTiming: { + initialCounts, + pixelsPerCount, + }, + }; +}; + +export default calculateScrollTiming; diff --git a/server/scripts/modules/utils/setting.mjs b/server/scripts/modules/utils/setting.mjs index a4075fc..17e44f3 100644 --- a/server/scripts/modules/utils/setting.mjs +++ b/server/scripts/modules/utils/setting.mjs @@ -9,6 +9,7 @@ const DEFAULTS = { defaultValue: undefined, changeAction: () => { }, sticky: true, + stickyRead: false, values: [], visible: true, placeholder: '', @@ -29,6 +30,7 @@ class Setting { this.myValue = this.defaultValue; this.type = options?.type; this.sticky = options.sticky; + this.stickyRead = options.stickyRead; this.values = options.values; this.visible = options.visible; this.changeAction = options.changeAction; @@ -56,7 +58,7 @@ class Setting { // get existing value if present const storedValue = urlState ?? this.getFromLocalStorage(); - if ((this.sticky || urlValue !== undefined) && storedValue !== null) { + if ((this.sticky || this.stickyRead || urlValue !== undefined) && storedValue !== null) { this.myValue = storedValue; } @@ -199,6 +201,20 @@ class Setting { localStorage?.setItem(SETTINGS_KEY, JSON.stringify(allSettings)); } + // Conditional storage method for stickyRead settings + conditionalStoreToLocalStorage(value, shouldStore) { + if (!this.stickyRead) return; + const allSettingsString = localStorage?.getItem(SETTINGS_KEY) ?? '{}'; + const allSettings = JSON.parse(allSettingsString); + + if (shouldStore) { + allSettings[this.shortName] = value; + } else { + delete allSettings[this.shortName]; + } + localStorage?.setItem(SETTINGS_KEY, JSON.stringify(allSettings)); + } + getFromLocalStorage() { const allSettings = localStorage?.getItem(SETTINGS_KEY); try { @@ -216,8 +232,9 @@ class Setting { } } } - } catch { - return null; + } catch (error) { + console.warn(`Failed to parse settings from localStorage: ${error} - allSettings=${allSettings}`); + localStorage?.removeItem(SETTINGS_KEY); } return null; } diff --git a/server/scripts/modules/utils/url-rewrite.mjs b/server/scripts/modules/utils/url-rewrite.mjs new file mode 100644 index 0000000..2230472 --- /dev/null +++ b/server/scripts/modules/utils/url-rewrite.mjs @@ -0,0 +1,58 @@ +// rewrite URLs to use local proxy server +const rewriteUrl = (_url) => { + if (!_url) { + throw new Error(`rewriteUrl called with invalid argument: '${_url}' (${typeof _url})`); + } + + // Handle relative URLs early: return them as-is since they don't need rewriting + if (typeof _url === 'string' && !_url.startsWith('http')) { + return _url; + } + + if (typeof _url !== 'string' && !(_url instanceof URL)) { + throw new Error(`rewriteUrl expects a URL string or URL object, received: ${typeof _url}`); + } + + // Convert to URL object (for URL objects, creates a copy to avoid mutating the original) + const url = new URL(_url); + + if (!window.WS4KP_SERVER_AVAILABLE) { + // If running standalone in the browser, simply return a URL object without rewriting + return url; + } + + // Rewrite the origin to use local proxy server + if (url.origin === 'https://api.weather.gov') { + url.protocol = window.location.protocol; + url.host = window.location.host; + url.pathname = `/api${url.pathname}`; + } else if (url.origin === 'https://forecast.weather.gov') { + url.protocol = window.location.protocol; + url.host = window.location.host; + url.pathname = `/forecast${url.pathname}`; + } else if (url.origin === 'https://www.spc.noaa.gov') { + url.protocol = window.location.protocol; + url.host = window.location.host; + url.pathname = `/spc${url.pathname}`; + } else if (url.origin === 'https://radar.weather.gov') { + url.protocol = window.location.protocol; + url.host = window.location.host; + url.pathname = `/radar${url.pathname}`; + } else if (url.origin === 'https://mesonet.agron.iastate.edu') { + url.protocol = window.location.protocol; + url.host = window.location.host; + url.pathname = `/mesonet${url.pathname}`; + } else if (typeof OVERRIDES !== 'undefined' && OVERRIDES?.RADAR_HOST && url.origin === `https://${OVERRIDES.RADAR_HOST}`) { + // Handle override radar host + url.protocol = window.location.protocol; + url.host = window.location.host; + url.pathname = `/mesonet${url.pathname}`; + } + + return url; +}; + +export { + // eslint-disable-next-line import/prefer-default-export + rewriteUrl, +}; diff --git a/server/scripts/modules/utils/weather.mjs b/server/scripts/modules/utils/weather.mjs index 0024bc5..b80b1ec 100644 --- a/server/scripts/modules/utils/weather.mjs +++ b/server/scripts/modules/utils/weather.mjs @@ -1,13 +1,15 @@ -import { json } from './fetch.mjs'; +import { safeJson } from './fetch.mjs'; +import { debugFlag } from './debug.mjs'; const getPoint = async (lat, lon) => { - try { - return await json(`https://api.weather.gov/points/${lat.toFixed(4)},${lon.toFixed(4)}`); - } catch (error) { - console.log(`Unable to get point ${lat}, ${lon}`); - console.error(error); + const point = await safeJson(`https://api.weather.gov/points/${lat.toFixed(4)},${lon.toFixed(4)}`); + if (!point) { + if (debugFlag('verbose-failures')) { + console.warn(`Unable to get points for ${lat},${lon}`); + } return false; } + return point; }; export { diff --git a/server/scripts/modules/weatherdisplay.mjs b/server/scripts/modules/weatherdisplay.mjs index cd38ea9..3c0f8fd 100644 --- a/server/scripts/modules/weatherdisplay.mjs +++ b/server/scripts/modules/weatherdisplay.mjs @@ -8,6 +8,7 @@ import { import { parseQueryString } from './share.mjs'; import settings from './settings.mjs'; import { elemForEach } from './utils/elem.mjs'; +import { debugFlag } from './utils/debug.mjs'; class WeatherDisplay { constructor(navId, elemId, name, defaultEnabled) { @@ -28,7 +29,7 @@ class WeatherDisplay { // default navigation timing this.timing = { totalScreens: 1, - baseDelay: 9000, // 5 seconds + baseDelay: 9000, // 9 seconds delay: 1, // 1*1second = 1 second total display time }; this.navBaseCount = 0; @@ -249,6 +250,23 @@ class WeatherDisplay { // increment the base count this.navBaseCount += 1; + if (debugFlag('weatherdisplay')) { + const now = Date.now(); + if (!this.timingDebug) { + this.timingDebug = { startTime: now, lastTransition: now, baseCountLog: [] }; + if (this.navBaseCount !== 1) { + console.log(`⏱️ [${this.constructor.name}] Starting at baseCount ${this.navBaseCount}`); + } + } + const elapsed = now - this.timingDebug.lastTransition; + this.timingDebug.baseCountLog.push({ + baseCount: this.navBaseCount, + timestamp: now, + elapsedMs: elapsed, + screenIndex: this.screenIndex, + }); + } + // call base count change if available for this function if (this.baseCountChange) this.baseCountChange(this.navBaseCount); @@ -270,6 +288,30 @@ class WeatherDisplay { // test for no change and exit early if (nextScreenIndex === this.screenIndex) return; + if (debugFlag('weatherdisplay') && this.timingDebug) { + const now = Date.now(); + const elapsed = now - this.timingDebug.lastTransition; + this.timingDebug.lastTransition = now; + console.log(`⏱️ [${this.constructor.name}] Screen Transition: ${this.screenIndex} → ${nextScreenIndex === -1 ? 0 : nextScreenIndex}, baseCount=${this.navBaseCount}, duration=${elapsed}ms`); + if (this.screenIndex !== -1 && this.timing && this.timing.delay !== undefined) { // Skip expected duration calculation for the first transition (screenIndex -1 → 0) + let expectedMs; + if (Array.isArray(this.timing.delay)) { // Array-based timing (different delay per screen/period) + // Find the timing index for the screen we just LEFT (the one that just finished displaying) + // For transition "X → Y", we want the timing for screen X (which is this.screenIndex before it gets updated) + const timingIndex = this.screenIndex; + if (timingIndex >= 0 && timingIndex < this.timing.delay.length) { // Handle both simple number delays and object delays with time property (radar) + const delayValue = typeof this.timing.delay[timingIndex] === 'object' ? this.timing.delay[timingIndex].time : this.timing.delay[timingIndex]; + expectedMs = this.timing.baseDelay * delayValue * (settings?.speed?.value || 1); + } + } else if (typeof this.timing.delay === 'number') { // Simple number-based timing (same delay for all screens) + expectedMs = this.timing.baseDelay * this.timing.delay * (settings?.speed?.value || 1); + } + if (expectedMs !== undefined) { + console.log(`⏱️ [${this.constructor.name}] Expected duration: ${expectedMs}ms, Actual: ${elapsed}ms, Diff: ${elapsed - expectedMs}ms`); + } + } + } + // test for -1 (no screen displayed yet) this.screenIndex = nextScreenIndex === -1 ? 0 : nextScreenIndex; @@ -369,10 +411,29 @@ class WeatherDisplay { // start and stop base counter startNavCount() { - if (!this.navInterval) this.navInterval = setInterval(() => this.navBaseTime(), this.timing.baseDelay * settings.speed.value); + if (!this.navInterval) { + if (debugFlag('weatherdisplay')) { + console.log(`⏱️ [${this.constructor.name}] Starting navigation:`, { + baseDelay: this.timing.baseDelay, + intervalMs: this.timing.baseDelay * (settings?.speed?.value || 1), + totalScreens: this.timing.totalScreens, + delayArray: this.timing.delay, + fullDelayArray: this.timing.fullDelay, + screenIndexes: this.timing.screenIndexes, + }); + } + this.navInterval = setInterval(() => this.navBaseTime(), this.timing.baseDelay * settings.speed.value); + } } resetNavBaseCount() { + if (debugFlag('weatherdisplay') && this.timingDebug && this.timingDebug.baseCountLog.length > 1) { + const totalDuration = this.timingDebug.baseCountLog[this.timingDebug.baseCountLog.length - 1].timestamp - this.timingDebug.baseCountLog[0].timestamp; + const avgInterval = totalDuration / (this.timingDebug.baseCountLog.length - 1); + console.log(`⏱️ [${this.constructor.name}] Total duration: ${totalDuration}ms, Avg base interval: ${avgInterval.toFixed(1)}ms, Base count range: ${this.timingDebug.baseCountLog[0].baseCount}-${this.timingDebug.baseCountLog[this.timingDebug.baseCountLog.length - 1].baseCount}`); + this.timingDebug = null; + } + this.navBaseCount = 0; this.screenIndex = -1; // reset the timing so we don't short-change the first screen @@ -446,7 +507,7 @@ class WeatherDisplay { setAutoReload() { // refresh time can be forced by the user (for hazards) const refreshTime = this.refreshTime ?? settings.refreshTime.value; - this.autoRefreshHandle = this.autoRefreshHandle ?? setInterval(() => this.getData(false, true), refreshTime); + this.autoRefreshHandle = this.autoRefreshHandle ?? setInterval(() => this.getData(this.weatherParameters, true), refreshTime); } } diff --git a/server/scripts/vendor/auto/locale/en.js b/server/scripts/vendor/auto/locale/en.js new file mode 100644 index 0000000..a772567 --- /dev/null +++ b/server/scripts/vendor/auto/locale/en.js @@ -0,0 +1,398 @@ +var en = { + CloudQuantity: { + BKN: "broken", + FEW: "few", + NSC: "no significant clouds.", + OVC: "overcast", + SCT: "scattered", + SKC: "sky clear", + }, + CloudType: { + AC: "Altocumulus", + AS: "Altostratus", + CB: "Cumulonimbus", + CC: "CirroCumulus", + CI: "Cirrus", + CS: "Cirrostratus", + CU: "Cumulus", + NS: "Nimbostratus", + SC: "Stratocumulus", + ST: "Stratus", + TCU: "Towering cumulus", + }, + Converter: { + D: "decreasing", + E: "East", + ENE: "East North East", + ESE: "East South East", + N: "North", + NE: "North East", + NNE: "North North East", + NNW: "North North West", + NSC: "no significant change", + NW: "North West", + S: "South", + SE: "South East", + SSE: "South South East", + SSW: "South South West", + SW: "South West", + U: "up rising", + VRB: "Variable", + W: "West", + WNW: "West North West", + WSW: "West South West", + }, + DepositBrakingCapacity: { + GOOD: "good", + MEDIUM: "medium", + MEDIUM_GOOD: "medium/good", + MEDIUM_POOR: "poor/medium", + NOT_REPORTED: "not reported", + POOR: "poor", + UNRELIABLE: "figures unreliable", + }, + DepositCoverage: { + FROM_11_TO_25: "from 11% to 25%", + FROM_26_TO_50: "from 26% to 50%", + FROM_51_TO_100: "from 51% to 100%", + LESS_10: "less than 10%", + NOT_REPORTED: "not reported", + }, + DepositThickness: { + CLOSED: "closed", + LESS_1_MM: "less than 1 mm", + NOT_REPORTED: "not reported", + THICKNESS_10: "10 cm", + THICKNESS_15: "15 cm", + THICKNESS_20: "20 cm", + THICKNESS_25: "25 cm", + THICKNESS_30: "30 cm", + THICKNESS_35: "35 cm", + THICKNESS_40: "40 cm or more", + }, + DepositType: { + CLEAR_DRY: "clear and dry", + COMPACTED_SNOW: "compacted or rolled snow", + DAMP: "damp", + DRY_SNOW: "dry snow", + FROZEN_RIDGES: "frozen ruts or ridges", + ICE: "ice", + NOT_REPORTED: "not reported", + RIME_FROST_COVERED: "rime or frost covered", + SLUSH: "slush", + WET_SNOW: "wet snow", + WET_WATER_PATCHES: "wet or water patches", + }, + Descriptive: { + BC: "patches", + BL: "blowing", + DR: "low drifting", + FZ: "freezing", + MI: "shallow", + PR: "partial", + SH: "showers of", + TS: "thunderstorm", + }, + Error: { + prefix: "An error occured. Error code n°", + }, + ErrorCode: { + AirportNotFound: "The airport was not found for this message.", + InvalidMessage: "The entered message is invalid.", + }, + Indicator: { + M: "less than", + P: "greater than", + }, + "intensity-plus": "Heavy", + Intensity: { + "-": "Light", + VC: "In the vicinity", + }, + MetarFacade: { + InvalidIcao: "Icao code is invalid.", + }, + Phenomenon: { + BR: "mist", + DS: "duststorm", + DU: "widespread dust", + DZ: "drizzle", + FC: "funnel cloud", + FG: "fog", + FU: "smoke", + GR: "hail", + GS: "small hail and/or snow pellets", + HZ: "haze", + IC: "ice crystals", + PL: "ice pellets", + PO: "dust or sand whirls", + PY: "spray", + RA: "rain", + SA: "sand", + SG: "snow grains", + SN: "snow", + SQ: "squall", + SS: "sandstorm", + TS: "thunderstorm", + UP: "unknown precipitation", + VA: "volcanic ash", + }, + Remark: { + ALQDS: "all quadrants", + AO1: "automated stations without a precipitation discriminator", + AO2: "automated station with a precipitation discriminator", + BASED: "based", + Barometer: [ + "Increase, then decrease", + "Increase, then steady, or increase then Increase more slowly", + "steady or unsteady increase", + "Decrease or steady, then increase; or increase then increase more rapidly", + "Steady", + "Decrease, then increase", + "Decrease then steady; or decrease then decrease more slowly", + "Steady or unsteady decrease", + "Steady or increase, then decrease; or decrease then decrease more rapidly", + ], + Ceiling: { + Height: "ceiling varying between {0} and {1} feet", + Second: { + Location: "ceiling of {0} feet mesured by a second sensor located at {1}", + }, + }, + DSNT: "distant", + FCST: "forecast", + FUNNELCLOUD: "funnel cloud", + HVY: "heavy", + Hail: { + "0": "largest hailstones with a diameter of {0} inches", + LesserThan: "largest hailstones with a diameter less than {0} inches", + }, + Hourly: { + Maximum: { + Minimum: { + Temperature: "24-hour maximum temperature of {0}°C and 24-hour minimum temperature of {1}°C", + }, + Temperature: "6-hourly maximum temperature of {0}°C", + }, + Minimum: { + Temperature: "6-hourly minimum temperature of {0}°C", + }, + Temperature: { + "0": "hourly temperature of {0}°C", + Dew: { + Point: "hourly temperature of {0}°C and dew point of {1}°C", + }, + }, + }, + Ice: { + Accretion: { + Amount: "{0}/100 of an inch of ice accretion in the past {1} hour(s)", + }, + }, + LGT: "light", + LTG: "lightning", + MOD: "moderate", + NXT: "next", + ON: "on", + Obscuration: "{0} layer at {1} feet composed of {2}", + PRESFR: "pressure falling rapidly", + PRESRR: "pressure rising rapidly", + PeakWind: "peak wind of {1} knots from {0} degrees at {2}:{3}", + Precipitation: { + Amount: { + "24": "{0} inches of precipitation fell in the last 24 hours", + "3": { + "6": "{1} inches of precipitation fell in the last {0} hours", + }, + Hourly: "{0}/100 of an inch of precipitation fell in the last hour", + }, + Beg: { + "0": "{0} {1} beginning at {2}:{3}", + End: "{0} {1} beginning at {2}:{3} ending at {4}:{5}", + }, + End: "{0} {1} ending at {2}:{3}", + }, + Pressure: { + Tendency: "of {0} hectopascals in the past 3 hours", + }, + SLPNO: "sea level pressure not available", + Sea: { + Level: { + Pressure: "sea level pressure of {0} HPa", + }, + }, + Second: { + Location: { + Visibility: "visibility of {0} SM mesured by a second sensor located at {1}", + }, + }, + Sector: { + Visibility: "visibility of {1} SM in the {0} direction", + }, + Snow: { + Depth: "snow depth of {0} inches", + Increasing: { + Rapidly: "snow depth increase of {0} inches in the past hour with a total depth on the ground of {1} inches", + }, + Pellets: "{0} snow pellets", + }, + Sunshine: { + Duration: "{0} minutes of sunshine", + }, + Surface: { + Visibility: "surface visibility of {0} statute miles", + }, + TORNADO: "tornado", + Thunderstorm: { + Location: { + "0": "thunderstorm {0} of the station", + Moving: "thunderstorm {0} of the station moving towards {1}", + }, + }, + Tornadic: { + Activity: { + BegEnd: "{0} beginning at {1}:{2} ending at {3}:{4} {5} SM {6} of the station", + Beginning: "{0} beginning at {1}:{2} {3} SM {4} of the station", + Ending: "{0} ending at {1}:{2} {3} SM {4} of the station", + }, + }, + Tower: { + Visibility: "control tower visibility of {0} statute miles", + }, + VIRGA: "virga", + Variable: { + Prevailing: { + Visibility: "variable prevailing visibility between {0} and {1} SM", + }, + Sky: { + Condition: { + "0": "cloud layer varying between {0} and {1}", + Height: "cloud layer at {0} feet varying between {1} and {2}", + }, + }, + }, + Virga: { + Direction: "virga {0} from the station", + }, + WATERSPOUT: "waterspout", + Water: { + Equivalent: { + Snow: { + Ground: "water equivalent of {0} inches of snow", + }, + }, + }, + WindShift: { + "0": "wind shift at {0}:{1}", + FROPA: "wind shift accompanied by frontal passage at {0}:{1}", + }, + }, + TimeIndicator: { + AT: "at", + FM: "From", + TL: "until", + }, + ToString: { + airport: "airport", + altimeter: "altimeter (hPa)", + amendment: "amendment", + auto: "auto", + cavok: "cavok", + clouds: "clouds", + day: { + hour: "hour of the day", + month: "day of the month", + }, + deposit: { + braking: "braking capacity", + coverage: "coverage", + thickness: "thickness", + type: "type of deposit", + }, + descriptive: "descriptive", + dew: { + point: "dew point", + }, + end: { + day: { + month: "end day of the month", + }, + hour: { + day: "end hour of the day", + }, + }, + height: { + feet: "height (ft)", + meter: "height (m)", + }, + indicator: "indicator", + intensity: "intensity", + message: "original message", + name: "name", + nosig: "nosig", + phenomenons: "phenomenons", + probability: "probability", + quantity: "quantity", + remark: "remarks", + report: { + time: "time of report", + }, + runway: { + info: "runways information", + }, + start: { + day: { + month: "starting day of the month", + }, + hour: { + day: "starting hour of the day", + }, + minute: "starting minute", + }, + temperature: { + "0": "temperature (°C)", + max: "maximum temperature (°C)", + min: "minimum temperature (°C)", + }, + trend: "trend", + trends: "trends", + type: "type", + vertical: { + visibility: "vertical visibility (ft)", + }, + visibility: { + main: "main visibility", + max: "maximum visibility", + min: { + "0": "minimum visibility", + direction: "minimum visibility direction", + }, + }, + weather: { + conditions: "weather conditions", + }, + wind: { + direction: { + "0": "direction", + degrees: "direction (degrees)", + }, + gusts: "gusts", + max: { + variation: "maximal wind variation", + }, + min: { + variation: "minimal wind variation", + }, + speed: "speed", + unit: "unit", + }, + }, + WeatherChangeType: { + BECMG: "Becoming", + FM: "From", + PROB: "Probability", + TEMPO: "Temporary", + }, +}; + +export { en as default }; diff --git a/server/scripts/vendor/auto/metar-taf-parser.mjs b/server/scripts/vendor/auto/metar-taf-parser.mjs new file mode 100644 index 0000000..c6a17aa --- /dev/null +++ b/server/scripts/vendor/auto/metar-taf-parser.mjs @@ -0,0 +1,2840 @@ +import en from './locale/en.js'; + +/****************************************************************************** +Copyright (c) Microsoft Corporation. + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY +AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. +***************************************************************************** */ + +function __classPrivateFieldGet(receiver, state, kind, f) { + if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); + if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); + return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); +} + +class ParseError extends Error { + constructor(message) { + super(message); + this.name = "ParseError"; + Object.setPrototypeOf(this, new.target.prototype); + } +} +class InvalidWeatherStatementError extends ParseError { + constructor(cause) { + super(typeof cause === "string" + ? `Invalid weather string: ${cause}` + : "Invalid weather string"); + this.name = "InvalidWeatherStatementError"; + Object.setPrototypeOf(this, new.target.prototype); + if (typeof cause !== "string") + this.cause = cause; + } +} +/** + * Thrown when command marked as canParse, but couldn't parse when + * executing (for example, an invalid CloudQuantity) + */ +class CommandExecutionError extends ParseError { + constructor(message) { + super(message); + this.name = "CommandExecutionError"; + Object.setPrototypeOf(this, new.target.prototype); + } +} +/** + * Should never occur + */ +class UnexpectedParseError extends ParseError { + constructor(message) { + super(message); + this.name = "UnexpectedParseError"; + Object.setPrototypeOf(this, new.target.prototype); + } +} + +/** + * Split behaving similar to Python's implementation + */ +function pySplit(string, separator, n) { + let split = string.split(separator); + // Note: Python implementation will automatically trim empty values if + // separator is undefined. Since this function is kinda meh, we'll just do it + // for any spaces (pretty close to their implementation, since a space is the + // default character to split on) + // + // https://docs.python.org/3/library/stdtypes.html?highlight=split#str.split + if (separator === " ") + split = split.filter((n) => n); + if (n == null || split.length <= n) + return split; + const out = split.slice(0, n); + out.push(split.slice(n).join(separator)); + return out; +} +/** + * Access nested object properties by string path + * + * https://stackoverflow.com/a/22129960 + */ +function resolve(obj, path, separator = ".") { + const properties = Array.isArray(path) ? path : path.split(separator); + return properties.reduce((prev, curr) => prev?.[curr], obj); +} +/** + * For safely casting input values + * @param input String that is expected to be in the snum + * @param enumExpected The enum to cast the input value to + * @throws RemarkExecutionError when input is not a key of enum + */ +function as(input, enumExpected) { + if (!Object.values(enumExpected).includes(input)) + throw new CommandExecutionError(`${input} not found in ${Object.values(enumExpected)}`); + return input; +} + +function _(path, lang) { + const translation = resolve(lang, path); + if (!translation || typeof translation !== "string") + return undefined; + return translation; +} +function format(message, ...args) { + if (!message) + return; + // All arguments must be defined, otherwise nothing is returned + for (const arg of args) { + if (arg === undefined) + return; + } + return message.replace(/{\d+}/g, (match) => { + const index = +match.slice(1, -1); + return `${args[index]}`; + }); +} + +class Command { + constructor(locale) { + this.locale = locale; + } +} + +var _CeilingHeightCommand_regex; +class CeilingHeightCommand extends Command { + constructor() { + super(...arguments); + _CeilingHeightCommand_regex.set(this, /^CIG (\d{3})V(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _CeilingHeightCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _CeilingHeightCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const min = +matches[1] * 100; + const max = +matches[2] * 100; + const description = format(_("Remark.Ceiling.Height", this.locale), min, max); + remark.push({ + type: RemarkType.CeilingHeight, + description, + raw: matches[0], + min, + max, + }); + return [code.replace(__classPrivateFieldGet(this, _CeilingHeightCommand_regex, "f"), "").trim(), remark]; + } +} +_CeilingHeightCommand_regex = new WeakMap(); + +var _CeilingSecondLocationCommand_regex; +class CeilingSecondLocationCommand extends Command { + constructor() { + super(...arguments); + _CeilingSecondLocationCommand_regex.set(this, /^CIG (\d{3}) (\w+)\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _CeilingSecondLocationCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _CeilingSecondLocationCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const height = +matches[1] * 100; + const location = matches[2]; + const description = format(_("Remark.Ceiling.Second.Location", this.locale), height, location); + remark.push({ + type: RemarkType.CeilingSecondLocation, + description, + raw: matches[0], + height, + location, + }); + return [code.replace(__classPrivateFieldGet(this, _CeilingSecondLocationCommand_regex, "f"), "").trim(), remark]; + } +} +_CeilingSecondLocationCommand_regex = new WeakMap(); + +var CloudQuantity; +(function (CloudQuantity) { + /** + * Sky clear + */ + CloudQuantity["SKC"] = "SKC"; + /** + * Few + */ + CloudQuantity["FEW"] = "FEW"; + /** + * Broken + */ + CloudQuantity["BKN"] = "BKN"; + /** + * Scattered + */ + CloudQuantity["SCT"] = "SCT"; + /** + * Overcast + */ + CloudQuantity["OVC"] = "OVC"; + /** + * No significant cloud + */ + CloudQuantity["NSC"] = "NSC"; +})(CloudQuantity || (CloudQuantity = {})); +var CloudType; +(function (CloudType) { + /** + * Cumulonimbus + */ + CloudType["CB"] = "CB"; + /** + * Towering cumulus, cumulus congestus + */ + CloudType["TCU"] = "TCU"; + /** + * Cirrus + */ + CloudType["CI"] = "CI"; + /** + * Cirrocumulus + */ + CloudType["CC"] = "CC"; + /** + * Cirrostratus + */ + CloudType["CS"] = "CS"; + /** + * Altocumulus + */ + CloudType["AC"] = "AC"; + /** + * Stratus + */ + CloudType["ST"] = "ST"; + /** + * Cumulus + */ + CloudType["CU"] = "CU"; + /** + * Astrostratus + */ + CloudType["AS"] = "AS"; + /** + * Nimbostratus + */ + CloudType["NS"] = "NS"; + /** + * Stratocumulus + */ + CloudType["SC"] = "SC"; +})(CloudType || (CloudType = {})); +/** + * Moderate has no qualifier. + */ +var Intensity; +(function (Intensity) { + Intensity["LIGHT"] = "-"; + /** + * Heavy or well-developed + */ + Intensity["HEAVY"] = "+"; + Intensity["IN_VICINITY"] = "VC"; +})(Intensity || (Intensity = {})); +var Descriptive; +(function (Descriptive) { + Descriptive["SHOWERS"] = "SH"; + Descriptive["SHALLOW"] = "MI"; + Descriptive["PATCHES"] = "BC"; + Descriptive["PARTIAL"] = "PR"; + Descriptive["DRIFTING"] = "DR"; + Descriptive["THUNDERSTORM"] = "TS"; + Descriptive["BLOWING"] = "BL"; + Descriptive["FREEZING"] = "FZ"; +})(Descriptive || (Descriptive = {})); +var Phenomenon; +(function (Phenomenon) { + Phenomenon["RAIN"] = "RA"; + Phenomenon["DRIZZLE"] = "DZ"; + Phenomenon["SNOW"] = "SN"; + Phenomenon["SNOW_GRAINS"] = "SG"; + Phenomenon["ICE_PELLETS"] = "PL"; + Phenomenon["ICE_CRYSTALS"] = "IC"; + Phenomenon["HAIL"] = "GR"; + Phenomenon["SMALL_HAIL"] = "GS"; + Phenomenon["UNKNOW_PRECIPITATION"] = "UP"; + Phenomenon["FOG"] = "FG"; + Phenomenon["VOLCANIC_ASH"] = "VA"; + Phenomenon["MIST"] = "BR"; + Phenomenon["HAZE"] = "HZ"; + Phenomenon["WIDESPREAD_DUST"] = "DU"; + Phenomenon["SMOKE"] = "FU"; + Phenomenon["SAND"] = "SA"; + Phenomenon["SPRAY"] = "PY"; + Phenomenon["SQUALL"] = "SQ"; + Phenomenon["SAND_WHIRLS"] = "PO"; + Phenomenon["THUNDERSTORM"] = "TS"; + Phenomenon["DUSTSTORM"] = "DS"; + Phenomenon["SANDSTORM"] = "SS"; + Phenomenon["FUNNEL_CLOUD"] = "FC"; +})(Phenomenon || (Phenomenon = {})); +var TimeIndicator; +(function (TimeIndicator) { + TimeIndicator["AT"] = "AT"; + TimeIndicator["FM"] = "FM"; + TimeIndicator["TL"] = "TL"; +})(TimeIndicator || (TimeIndicator = {})); +/** + * https://www.aviationweather.gov/taf/decoder + */ +var WeatherChangeType; +(function (WeatherChangeType) { + /** + * FROM Group + * + * ie. `FM1600` + * + * The FM group is used when a rapid change, usually occuring in less than one + * hour, in prevailing conditions is expected. Typically, a rapid change of + * prevailing conditions to more or less a completely new set of prevailing + * conditions is associated with a synoptic feature passing through the + * terminal area (cold or warm frontal passage). Appended to the FM indicator + * is the four-digit hour and minute the change is expected to begin and + * continues until the next change group or until the end of the current + * forecast. + * + * A FM group will mark the beginning of a new line in a TAF report. Each FM + * group contains all the required elements -- wind, visibility, weather, and + * sky condition. Weather will be omitted in FM groups when it is not + * significant to aviation. FM groups will not include the contraction NSW. + * + * Examples: + * + * 1. `FM0100 SKC` - After 0100Z sky clear + * 2. `FM1430 OVC020` - After 1430Z ceiling two thousand overcast + */ + WeatherChangeType["FM"] = "FM"; + /** + * BECOMING Group + * + * ie. `BECMG 2224` + * + * The BECMG group is used when a gradual change in conditions is expected + * over a longer time period, usually two hours. The time period when the + * change is expected is a four-digit group with the beginning hour and ending + * hour of the change period which follows the BECMG indicator. The gradual + * change will occur at an unspecified time within this time period. Only the + * conditions are carried over from the previous time group. + * + * Example: + * + * 1. `OVC012 BECMG 1416 BKN020` - Ceiling one thousand two hundred overcast. + * Then a gradual change to ceiling two thousand broken between 1400Z and + * 1600Z. + */ + WeatherChangeType["BECMG"] = "BECMG"; + /** + * TEMPORARY Group + * + * ie. `TEMPO 1316` + * + * The TEMPO group is used for any conditions in wind, visibility, weather, or + * sky condition which are expected to last for generally less than an hour at + * a time (occasional), and are expected to occur during less than half the + * time period. The TEMPO indicator is followed by a four-digit group giving + * the beginning hour and ending hour of the time period during which the + * temporary conditions are expected. Only the changing forecast + * meteorological conditions are included in TEMPO groups. The omitted + * conditions are carried over from the previous time group. + * + * Examples: + * + * 1. `SCT030 TEMPO 1923 BKN030` - Three thousand scattered with occasional + * ceilings three thousand broken between 1900Z and 2300Z. + * 2. `4SM HZ TEMPO 0006 2SM BR HZ` - Visibility four in haze with occasional + * visibility two in mist and haze between 0000Z and 0600Z. + */ + WeatherChangeType["TEMPO"] = "TEMPO"; + /** + * Probability Forecast + * + * ie. `PROB40 0006` + * + * The probability or chance of thunderstorms or other precipitation events + * occuring, along with associated weather conditions (wind, visibility, and + * sky conditions). + * + * The PROB40 group is used when the occurrence of thunderstorms or + * precipitation is in the 30% to less than 50% range, thus the probability + * value 40 is appended to the PROB contraction. This is followed by a + * four-digit group giving the beginning hour and ending hour of the time + * period during which the thunderstorms or precipitation is expected. + * + * Note: PROB40 will not be shown during the first six hours of a forecast. + * + * Examples: + * + * 1. `PROB40 2102 1/2SM +TSRA` - Chance between 2100Z and 0200Z of + * visibility one-half thunderstorm, heavy rain. + * 2. `PROB40 1014 1SM RASN` - Chance between 1000Z and 1400Z of visibility + * one rain and snow. + * 3. `PROB40 2024 2SM FZRA` - Chance between 2000Z and 0000Z of visibility + * two freezing rain. + + */ + WeatherChangeType["PROB"] = "PROB"; +})(WeatherChangeType || (WeatherChangeType = {})); +var Direction; +(function (Direction) { + Direction["E"] = "E"; + Direction["ENE"] = "ENE"; + Direction["ESE"] = "ESE"; + Direction["N"] = "N"; + Direction["NE"] = "NE"; + Direction["NNE"] = "NNE"; + Direction["NNW"] = "NNW"; + Direction["NW"] = "NW"; + Direction["S"] = "S"; + Direction["SE"] = "SE"; + Direction["SSE"] = "SSE"; + Direction["SSW"] = "SSW"; + Direction["SW"] = "SW"; + Direction["W"] = "W"; + Direction["WNW"] = "WNW"; + Direction["WSW"] = "WSW"; +})(Direction || (Direction = {})); +var DistanceUnit; +(function (DistanceUnit) { + DistanceUnit["Meters"] = "m"; + DistanceUnit["StatuteMiles"] = "SM"; +})(DistanceUnit || (DistanceUnit = {})); +var SpeedUnit; +(function (SpeedUnit) { + SpeedUnit["Knot"] = "KT"; + SpeedUnit["MetersPerSecond"] = "MPS"; + SpeedUnit["KilometersPerHour"] = "KM/H"; +})(SpeedUnit || (SpeedUnit = {})); +/** + * Used to indicate the actual value is greater than or less than the value written + * + * For example, + * + * 1. `P6SM` = visibility greater than 6 statute miles + * 2. `M1/4SM` = visibility less than 1/4 statute mile + */ +var ValueIndicator; +(function (ValueIndicator) { + ValueIndicator["GreaterThan"] = "P"; + ValueIndicator["LessThan"] = "M"; +})(ValueIndicator || (ValueIndicator = {})); +var RunwayInfoTrend; +(function (RunwayInfoTrend) { + RunwayInfoTrend["Uprising"] = "U"; + RunwayInfoTrend["Decreasing"] = "D"; + RunwayInfoTrend["NoSignificantChange"] = "N"; +})(RunwayInfoTrend || (RunwayInfoTrend = {})); +var RunwayInfoUnit; +(function (RunwayInfoUnit) { + RunwayInfoUnit["Feet"] = "FT"; + RunwayInfoUnit["Meters"] = "m"; +})(RunwayInfoUnit || (RunwayInfoUnit = {})); + +function degreesToCardinal(input) { + const degrees = +input; + if (isNaN(degrees)) + return "VRB"; + const dirs = [ + "N", + "NNE", + "NE", + "ENE", + "E", + "ESE", + "SE", + "SSE", + "S", + "SSW", + "SW", + "WSW", + "W", + "WNW", + "NW", + "NNW", + ]; + const ix = Math.floor((degrees + 11.25) / 22.5); + return dirs[ix % 16]; +} +function convertVisibility(input) { + if (input === "9999") + return { + indicator: ValueIndicator.GreaterThan, + value: +input, + unit: DistanceUnit.Meters, + }; + return { + value: +input, + unit: DistanceUnit.Meters, + }; +} +/** + * @param input May start with P or M, and must end with SM + * @returns Distance + */ +function convertNauticalMilesVisibility(input) { + let indicator; + let index = 0; + if (input.startsWith("P")) { + indicator = ValueIndicator.GreaterThan; + index = 1; + } + else if (input.startsWith("M")) { + indicator = ValueIndicator.LessThan; + index = 1; + } + return { + indicator, + value: convertFractionalAmount(input.slice(index, -2)), + unit: DistanceUnit.StatuteMiles, + }; +} +/** + * Converts fractional and/or whole amounts + * + * Example "1/3", "1 1/3" and "1" + */ +function convertFractionalAmount(input) { + const [whole, fraction] = input.split(" "); + if (!fraction) + return parseFraction(whole); + return +whole + parseFraction(fraction); +} +function parseFraction(input) { + const [top, bottom] = input.split("/"); + if (!bottom) + return +top; + return Math.round((+top / +bottom) * 100) / 100; +} +function convertTemperature(input) { + if (input.startsWith("M")) + return -pySplit(input, "M")[1]; + return +input; +} +function convertInchesMercuryToPascal(input) { + return 33.8639 * input; +} +/** + * Converts number `.toFixed(1)` before outputting to match python implementation + */ +function convertTemperatureRemarks(sign, temperature) { + const temp = +temperature / 10; + if (sign === "0") + return temp; + return -temp; +} +function convertPrecipitationAmount(amount) { + return +amount / 100; +} + +var _HailSizeCommand_regex; +class HailSizeCommand extends Command { + constructor() { + super(...arguments); + _HailSizeCommand_regex.set(this, /^GR ((\d\/\d)|((\d) ?(\d\/\d)?))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HailSizeCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HailSizeCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Hail.0", this.locale), matches[1]); + remark.push({ + type: RemarkType.HailSize, + description, + raw: matches[0], + size: convertFractionalAmount(matches[1]), + }); + return [code.replace(__classPrivateFieldGet(this, _HailSizeCommand_regex, "f"), "").trim(), remark]; + } +} +_HailSizeCommand_regex = new WeakMap(); + +var _HourlyMaximumMinimumTemperatureCommand_regex; +class HourlyMaximumMinimumTemperatureCommand extends Command { + constructor() { + super(...arguments); + _HourlyMaximumMinimumTemperatureCommand_regex.set(this, /^4([01])(\d{3})([01])(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HourlyMaximumMinimumTemperatureCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HourlyMaximumMinimumTemperatureCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Hourly.Maximum.Minimum.Temperature", this.locale), convertTemperatureRemarks(matches[1], matches[2]).toFixed(1), convertTemperatureRemarks(matches[3], matches[4]).toFixed(1)); + remark.push({ + type: RemarkType.HourlyMaximumMinimumTemperature, + description: description, + raw: matches[0], + max: convertTemperatureRemarks(matches[1], matches[2]), + min: convertTemperatureRemarks(matches[3], matches[4]), + }); + return [code.replace(__classPrivateFieldGet(this, _HourlyMaximumMinimumTemperatureCommand_regex, "f"), "").trim(), remark]; + } +} +_HourlyMaximumMinimumTemperatureCommand_regex = new WeakMap(); + +var _HourlyMaximumTemperatureCommand_regex; +class HourlyMaximumTemperatureCommand extends Command { + constructor() { + super(...arguments); + _HourlyMaximumTemperatureCommand_regex.set(this, /^1([01])(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HourlyMaximumTemperatureCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HourlyMaximumTemperatureCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Hourly.Maximum.Temperature", this.locale), convertTemperatureRemarks(matches[1], matches[2]).toFixed(1)); + remark.push({ + type: RemarkType.HourlyMaximumTemperature, + description: description, + raw: matches[0], + max: convertTemperatureRemarks(matches[1], matches[2]), + }); + return [code.replace(__classPrivateFieldGet(this, _HourlyMaximumTemperatureCommand_regex, "f"), "").trim(), remark]; + } +} +_HourlyMaximumTemperatureCommand_regex = new WeakMap(); + +var _HourlyMinimumTemperatureCommand_regex; +class HourlyMinimumTemperatureCommand extends Command { + constructor() { + super(...arguments); + _HourlyMinimumTemperatureCommand_regex.set(this, /^2([01])(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HourlyMinimumTemperatureCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HourlyMinimumTemperatureCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Hourly.Minimum.Temperature", this.locale), convertTemperatureRemarks(matches[1], matches[2]).toFixed(1)); + remark.push({ + type: RemarkType.HourlyMinimumTemperature, + description, + raw: matches[0], + min: convertTemperatureRemarks(matches[1], matches[2]), + }); + return [code.replace(__classPrivateFieldGet(this, _HourlyMinimumTemperatureCommand_regex, "f"), "").trim(), remark]; + } +} +_HourlyMinimumTemperatureCommand_regex = new WeakMap(); + +var _HourlyPrecipitationAmountCommand_regex; +class HourlyPrecipitationAmountCommand extends Command { + constructor() { + super(...arguments); + _HourlyPrecipitationAmountCommand_regex.set(this, /^P(\d{4})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HourlyPrecipitationAmountCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HourlyPrecipitationAmountCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const amount = +matches[1]; + const description = format(_("Remark.Precipitation.Amount.Hourly", this.locale), amount); + remark.push({ + type: RemarkType.HourlyPrecipitationAmount, + description, + raw: matches[0], + amount: amount / 100, + }); + return [code.replace(__classPrivateFieldGet(this, _HourlyPrecipitationAmountCommand_regex, "f"), "").trim(), remark]; + } +} +_HourlyPrecipitationAmountCommand_regex = new WeakMap(); + +var _HourlyPressureCommand_regex; +class HourlyPressureCommand extends Command { + constructor() { + super(...arguments); + _HourlyPressureCommand_regex.set(this, /^5(\d)(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HourlyPressureCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HourlyPressureCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const part1 = _(`Remark.Barometer.${+matches[1]}`, this.locale); + const part2 = format(_("Remark.Pressure.Tendency", this.locale), +matches[2] / 10); + const description = part1 != null && part2 != null ? `${part1} ${part2}` : undefined; + remark.push({ + type: RemarkType.HourlyPressure, + description, + raw: matches[0], + code: +matches[1], + pressureChange: +matches[2] / 10, + }); + return [code.replace(__classPrivateFieldGet(this, _HourlyPressureCommand_regex, "f"), "").trim(), remark]; + } +} +_HourlyPressureCommand_regex = new WeakMap(); + +var _HourlyTemperatureDewPointCommand_regex; +class HourlyTemperatureDewPointCommand extends Command { + constructor() { + super(...arguments); + _HourlyTemperatureDewPointCommand_regex.set(this, /^T([01])(\d{3})(([01])(\d{3}))?/); + } + canParse(code) { + return __classPrivateFieldGet(this, _HourlyTemperatureDewPointCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _HourlyTemperatureDewPointCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const temperature = convertTemperatureRemarks(matches[1], matches[2]); + if (!matches[3]) { + const description = format(_("Remark.Hourly.Temperature.0", this.locale), temperature.toFixed(1)); + remark.push({ + type: RemarkType.HourlyTemperatureDewPoint, + description, + raw: matches[0], + temperature, + }); + } + else { + const dewPoint = convertTemperatureRemarks(matches[4], matches[5]); + const description = format(_("Remark.Hourly.Temperature.Dew.Point", this.locale), temperature.toFixed(1), dewPoint.toFixed(1)); + remark.push({ + type: RemarkType.HourlyTemperatureDewPoint, + description, + raw: matches[0], + temperature, + dewPoint, + }); + } + return [code.replace(__classPrivateFieldGet(this, _HourlyTemperatureDewPointCommand_regex, "f"), "").trim(), remark]; + } +} +_HourlyTemperatureDewPointCommand_regex = new WeakMap(); + +var _IceAccretionCommand_regex; +class IceAccretionCommand extends Command { + constructor() { + super(...arguments); + _IceAccretionCommand_regex.set(this, /^l(\d)(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _IceAccretionCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _IceAccretionCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Ice.Accretion.Amount", this.locale), +matches[2], +matches[1]); + remark.push({ + type: RemarkType.IceAccretion, + description, + raw: matches[0], + amount: +matches[2] / 100, + periodInHours: +matches[1], + }); + return [code.replace(__classPrivateFieldGet(this, _IceAccretionCommand_regex, "f"), "").trim(), remark]; + } +} +_IceAccretionCommand_regex = new WeakMap(); + +var _ObscurationCommand_regex; +class ObscurationCommand extends Command { + constructor() { + super(...arguments); + _ObscurationCommand_regex.set(this, /^([A-Z]{2}) ([A-Z]{3})(\d{3})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _ObscurationCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _ObscurationCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const quantity = as(matches[2], CloudQuantity); + const height = 100 * +matches[3]; + const phenomenon = as(matches[1], Phenomenon); + const description = format(_("Remark.Obscuration", this.locale), _(`CloudQuantity.${quantity}`, this.locale), height, _(`Phenomenon.${phenomenon}`, this.locale)); + remark.push({ + type: RemarkType.Obscuration, + description, + raw: matches[0], + quantity, + height, + phenomenon, + }); + return [code.replace(__classPrivateFieldGet(this, _ObscurationCommand_regex, "f"), "").trim(), remark]; + } +} +_ObscurationCommand_regex = new WeakMap(); + +var _PrecipitationAmount24HourCommand_regex; +class PrecipitationAmount24HourCommand extends Command { + constructor() { + super(...arguments); + _PrecipitationAmount24HourCommand_regex.set(this, /^7(\d{4})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _PrecipitationAmount24HourCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _PrecipitationAmount24HourCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const amount = convertPrecipitationAmount(matches[1]); + const description = format(_("Remark.Precipitation.Amount.24", this.locale), amount); + remark.push({ + type: RemarkType.PrecipitationAmount24Hour, + description, + raw: matches[0], + amount, + }); + return [code.replace(__classPrivateFieldGet(this, _PrecipitationAmount24HourCommand_regex, "f"), "").trim(), remark]; + } +} +_PrecipitationAmount24HourCommand_regex = new WeakMap(); + +var _PrecipitationAmount36HourCommand_regex; +class PrecipitationAmount36HourCommand extends Command { + constructor() { + super(...arguments); + _PrecipitationAmount36HourCommand_regex.set(this, /^([36])(\d{4})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _PrecipitationAmount36HourCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _PrecipitationAmount36HourCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const periodInHours = +matches[1]; + const amount = convertPrecipitationAmount(matches[2]); + const description = format(_("Remark.Precipitation.Amount.3.6", this.locale), periodInHours, amount); + remark.push({ + type: RemarkType.PrecipitationAmount36Hour, + description, + raw: matches[0], + periodInHours, + amount, + }); + return [code.replace(__classPrivateFieldGet(this, _PrecipitationAmount36HourCommand_regex, "f"), "").trim(), remark]; + } +} +_PrecipitationAmount36HourCommand_regex = new WeakMap(); + +var _PrecipitationBegEndCommand_regex; +class PrecipitationBegEndCommand extends Command { + constructor() { + super(...arguments); + _PrecipitationBegEndCommand_regex.set(this, /^(([A-Z]{2})?([A-Z]{2})B(\d{2})?(\d{2})E(\d{2})?(\d{2}))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _PrecipitationBegEndCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _PrecipitationBegEndCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const descriptive = matches[2] ? as(matches[2], Descriptive) : undefined; + const phenomenon = as(matches[3], Phenomenon); + const description = format(_("Remark.Precipitation.Beg.End", this.locale), descriptive ? _(`Descriptive.${descriptive}`, this.locale) : "", _(`Phenomenon.${phenomenon}`, this.locale), matches[4] || "", matches[5], matches[6] || "", matches[7]); + remark.push({ + type: RemarkType.PrecipitationBegEnd, + description, + raw: matches[0], + descriptive, + phenomenon, + startHour: matches[4] ? +matches[4] : undefined, + startMin: +matches[5], + endHour: matches[6] ? +matches[6] : undefined, + endMin: +matches[7], + }); + return [code.replace(__classPrivateFieldGet(this, _PrecipitationBegEndCommand_regex, "f"), "").trim(), remark]; + } +} +_PrecipitationBegEndCommand_regex = new WeakMap(); + +var _PrevailingVisibilityCommand_regex; +class PrevailingVisibilityCommand extends Command { + constructor() { + super(...arguments); + _PrevailingVisibilityCommand_regex.set(this, /^VIS ((\d)*( )?(\d?\/?\d))V((\d)*( )?(\d?\/?\d))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const minVisibility = matches[1]; + const maxVisibility = matches[5]; + const description = format(_("Remark.Variable.Prevailing.Visibility", this.locale), minVisibility, maxVisibility); + remark.push({ + type: RemarkType.PrevailingVisibility, + description, + raw: matches[0], + minVisibility: convertFractionalAmount(minVisibility), + maxVisibility: convertFractionalAmount(maxVisibility), + }); + return [code.replace(__classPrivateFieldGet(this, _PrevailingVisibilityCommand_regex, "f"), "").trim(), remark]; + } +} +_PrevailingVisibilityCommand_regex = new WeakMap(); + +var _SeaLevelPressureCommand_regex; +class SeaLevelPressureCommand extends Command { + constructor() { + super(...arguments); + _SeaLevelPressureCommand_regex.set(this, /^SLP(\d{2})(\d)/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SeaLevelPressureCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SeaLevelPressureCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + let pressure = matches[1].startsWith("9") ? "9" : "10"; + pressure += matches[1] + "." + matches[2]; + const description = format(_("Remark.Sea.Level.Pressure", this.locale), pressure); + remark.push({ + type: RemarkType.SeaLevelPressure, + description, + raw: matches[0], + pressure: +pressure, + }); + return [code.replace(__classPrivateFieldGet(this, _SeaLevelPressureCommand_regex, "f"), "").trim(), remark]; + } +} +_SeaLevelPressureCommand_regex = new WeakMap(); + +var _SecondLocationVisibilityCommand_regex; +class SecondLocationVisibilityCommand extends Command { + constructor() { + super(...arguments); + _SecondLocationVisibilityCommand_regex.set(this, /^VIS ((\d)*( )?(\d?\/?\d)) (\w+)/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const distance = matches[1]; + const location = matches[5]; + const description = format(_("Remark.Second.Location.Visibility", this.locale), distance, location); + remark.push({ + type: RemarkType.SecondLocationVisibility, + description, + raw: matches[0], + distance: convertFractionalAmount(distance), + location, + }); + return [code.replace(__classPrivateFieldGet(this, _SecondLocationVisibilityCommand_regex, "f"), "").trim(), remark]; + } +} +_SecondLocationVisibilityCommand_regex = new WeakMap(); + +var _SectorVisibilityCommand_regex; +class SectorVisibilityCommand extends Command { + constructor() { + super(...arguments); + _SectorVisibilityCommand_regex.set(this, /^VIS ([A-Z]{1,2}) ((\d)*( )?(\d?\/?\d))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const direction = as(matches[1], Direction); + const description = format(_("Remark.Sector.Visibility", this.locale), _(`Converter.${direction}`, this.locale), matches[2]); + remark.push({ + type: RemarkType.SectorVisibility, + description, + raw: matches[0], + direction, + distance: convertFractionalAmount(matches[2]), + }); + return [code.replace(__classPrivateFieldGet(this, _SectorVisibilityCommand_regex, "f"), "").trim(), remark]; + } +} +_SectorVisibilityCommand_regex = new WeakMap(); + +var _SmallHailSizeCommand_regex; +class SmallHailSizeCommand extends Command { + constructor() { + super(...arguments); + _SmallHailSizeCommand_regex.set(this, /^GR LESS THAN ((\d )?(\d\/\d)?)/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Hail.LesserThan", this.locale), matches[1]); + remark.push({ + type: RemarkType.SmallHailSize, + description, + raw: matches[0], + size: convertFractionalAmount(matches[1]), + }); + return [code.replace(__classPrivateFieldGet(this, _SmallHailSizeCommand_regex, "f"), "").trim(), remark]; + } +} +_SmallHailSizeCommand_regex = new WeakMap(); + +var _SnowDepthCommand_regex; +class SnowDepthCommand extends Command { + constructor() { + super(...arguments); + _SnowDepthCommand_regex.set(this, /^4\/(\d{3})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SnowDepthCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SnowDepthCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const depth = +matches[1]; + const description = format(_("Remark.Snow.Depth", this.locale), depth); + remark.push({ + type: RemarkType.SnowDepth, + description, + raw: matches[0], + depth, + }); + return [code.replace(__classPrivateFieldGet(this, _SnowDepthCommand_regex, "f"), "").trim(), remark]; + } +} +_SnowDepthCommand_regex = new WeakMap(); + +var _SnowIncreaseCommand_regex; +class SnowIncreaseCommand extends Command { + constructor() { + super(...arguments); + _SnowIncreaseCommand_regex.set(this, /^SNINCR (\d+)\/(\d+)/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SnowIncreaseCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SnowIncreaseCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const inchesLastHour = +matches[1]; + const totalDepth = +matches[2]; + const description = format(_("Remark.Snow.Increasing.Rapidly", this.locale), inchesLastHour, totalDepth); + remark.push({ + type: RemarkType.SnowIncrease, + description, + raw: matches[0], + inchesLastHour, + totalDepth, + }); + return [code.replace(__classPrivateFieldGet(this, _SnowIncreaseCommand_regex, "f"), "").trim(), remark]; + } +} +_SnowIncreaseCommand_regex = new WeakMap(); + +var _SnowPelletsCommand_regex; +class SnowPelletsCommand extends Command { + constructor() { + super(...arguments); + _SnowPelletsCommand_regex.set(this, /^GS (LGT|MOD|HVY)/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SnowPelletsCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SnowPelletsCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.Snow.Pellets", this.locale), _(`Remark.${matches[1]}`, this.locale)); + remark.push({ + type: RemarkType.SnowPellets, + description, + raw: matches[0], + amount: matches[1], + }); + return [code.replace(__classPrivateFieldGet(this, _SnowPelletsCommand_regex, "f"), "").trim(), remark]; + } +} +_SnowPelletsCommand_regex = new WeakMap(); + +var _SunshineDurationCommand_regex; +class SunshineDurationCommand extends Command { + constructor() { + super(...arguments); + _SunshineDurationCommand_regex.set(this, /^98(\d{3})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SunshineDurationCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SunshineDurationCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const duration = +matches[1]; + const description = format(_("Remark.Sunshine.Duration", this.locale), duration); + remark.push({ + type: RemarkType.SunshineDuration, + description, + raw: matches[0], + duration, + }); + return [code.replace(__classPrivateFieldGet(this, _SunshineDurationCommand_regex, "f"), "").trim(), remark]; + } +} +_SunshineDurationCommand_regex = new WeakMap(); + +var _SurfaceVisibilityCommand_regex; +class SurfaceVisibilityCommand extends Command { + constructor() { + super(...arguments); + _SurfaceVisibilityCommand_regex.set(this, /^SFC VIS ((\d)*( )?(\d?\/?\d))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const distance = matches[1]; + const description = format(_("Remark.Surface.Visibility", this.locale), distance); + remark.push({ + type: RemarkType.SurfaceVisibility, + description, + raw: matches[0], + distance: convertFractionalAmount(distance), + }); + return [code.replace(__classPrivateFieldGet(this, _SurfaceVisibilityCommand_regex, "f"), "").trim(), remark]; + } +} +_SurfaceVisibilityCommand_regex = new WeakMap(); + +var _ThunderStormLocationCommand_regex; +class ThunderStormLocationCommand extends Command { + constructor() { + super(...arguments); + _ThunderStormLocationCommand_regex.set(this, /^TS ([A-Z]{2})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _ThunderStormLocationCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _ThunderStormLocationCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const location = as(matches[1], Direction); + const description = format(_("Remark.Thunderstorm.Location.0", this.locale), _(`Converter.${location}`, this.locale)); + remark.push({ + type: RemarkType.ThunderStormLocation, + description, + raw: matches[0], + location, + }); + return [code.replace(__classPrivateFieldGet(this, _ThunderStormLocationCommand_regex, "f"), "").trim(), remark]; + } +} +_ThunderStormLocationCommand_regex = new WeakMap(); + +var _ThunderStormLocationMovingCommand_regex; +class ThunderStormLocationMovingCommand extends Command { + constructor() { + super(...arguments); + _ThunderStormLocationMovingCommand_regex.set(this, /^TS ([A-Z]{2}) MOV ([A-Z]{2})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _ThunderStormLocationMovingCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _ThunderStormLocationMovingCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const location = as(matches[1], Direction); + const moving = as(matches[2], Direction); + const description = format(_("Remark.Thunderstorm.Location.Moving", this.locale), _(`Converter.${location}`, this.locale), _(`Converter.${moving}`, this.locale)); + remark.push({ + type: RemarkType.ThunderStormLocationMoving, + description, + raw: matches[0], + location, + moving, + }); + return [code.replace(__classPrivateFieldGet(this, _ThunderStormLocationMovingCommand_regex, "f"), "").trim(), remark]; + } +} +_ThunderStormLocationMovingCommand_regex = new WeakMap(); + +var _TornadicActivityBegCommand_regex; +class TornadicActivityBegCommand extends Command { + constructor() { + super(...arguments); + _TornadicActivityBegCommand_regex.set(this, /^(TORNADO|FUNNEL CLOUD|WATERSPOUT) (B(\d{2})?(\d{2}))( (\d+)? ([A-Z]{1,2})?)?/); + } + canParse(code) { + return __classPrivateFieldGet(this, _TornadicActivityBegCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _TornadicActivityBegCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const direction = as(matches[7], Direction); + const description = format(_("Remark.Tornadic.Activity.Beginning", this.locale), _(`Remark.${matches[1].replace(" ", "")}`, this.locale), matches[3] || "", matches[4], matches[6], _(`Converter.${direction}`, this.locale)); + remark.push({ + type: RemarkType.TornadicActivityBeg, + description, + raw: matches[0], + tornadicType: matches[1], + startHour: matches[3] ? +matches[3] : undefined, + startMinute: +matches[4], + distance: +matches[6], + direction, + }); + return [code.replace(__classPrivateFieldGet(this, _TornadicActivityBegCommand_regex, "f"), "").trim(), remark]; + } +} +_TornadicActivityBegCommand_regex = new WeakMap(); + +var _TornadicActivityBegEndCommand_regex; +class TornadicActivityBegEndCommand extends Command { + constructor() { + super(...arguments); + _TornadicActivityBegEndCommand_regex.set(this, /^(TORNADO|FUNNEL CLOUD|WATERSPOUT) (B(\d{2})?(\d{2}))(E(\d{2})?(\d{2}))( (\d+)? ([A-Z]{1,2})?)?/); + } + canParse(code) { + return __classPrivateFieldGet(this, _TornadicActivityBegEndCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _TornadicActivityBegEndCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const direction = as(matches[10], Direction); + const description = format(_("Remark.Tornadic.Activity.BegEnd", this.locale), _(`Remark.${matches[1].replace(" ", "")}`, this.locale), matches[3] || "", matches[4], matches[6] || "", matches[7], matches[9], _(`Converter.${direction}`, this.locale)); + remark.push({ + type: RemarkType.TornadicActivityBegEnd, + description, + raw: matches[0], + tornadicType: matches[1], + startHour: matches[3] ? +matches[3] : undefined, + startMinute: +matches[4], + endHour: matches[6] ? +matches[6] : undefined, + endMinute: +matches[7], + distance: +matches[9], + direction, + }); + return [code.replace(__classPrivateFieldGet(this, _TornadicActivityBegEndCommand_regex, "f"), "").trim(), remark]; + } +} +_TornadicActivityBegEndCommand_regex = new WeakMap(); + +var _TornadicActivityEndCommand_regex; +class TornadicActivityEndCommand extends Command { + constructor() { + super(...arguments); + _TornadicActivityEndCommand_regex.set(this, /^(TORNADO|FUNNEL CLOUD|WATERSPOUT) (E(\d{2})?(\d{2}))( (\d+)? ([A-Z]{1,2})?)?/); + } + canParse(code) { + return __classPrivateFieldGet(this, _TornadicActivityEndCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _TornadicActivityEndCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const direction = as(matches[7], Direction); + const description = format(_("Remark.Tornadic.Activity.Ending", this.locale), _(`Remark.${matches[1].replace(" ", "")}`, this.locale), matches[3] || "", matches[4], matches[6], _(`Converter.${direction}`, this.locale)); + remark.push({ + type: RemarkType.TornadicActivityEnd, + description, + raw: matches[0], + tornadicType: matches[1], + endHour: matches[3] ? +matches[3] : undefined, + endMinute: +matches[4], + distance: +matches[6], + direction, + }); + return [code.replace(__classPrivateFieldGet(this, _TornadicActivityEndCommand_regex, "f"), "").trim(), remark]; + } +} +_TornadicActivityEndCommand_regex = new WeakMap(); + +var _TowerVisibilityCommand_regex; +class TowerVisibilityCommand extends Command { + constructor() { + super(...arguments); + _TowerVisibilityCommand_regex.set(this, /^TWR VIS ((\d)*( )?(\d?\/?\d))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const distance = matches[1]; + const description = format(_("Remark.Tower.Visibility", this.locale), distance); + remark.push({ + type: RemarkType.TowerVisibility, + description, + raw: matches[0], + distance: convertFractionalAmount(distance), + }); + return [code.replace(__classPrivateFieldGet(this, _TowerVisibilityCommand_regex, "f"), "").trim(), remark]; + } +} +_TowerVisibilityCommand_regex = new WeakMap(); + +var _VariableSkyCommand_regex; +class VariableSkyCommand extends Command { + constructor() { + super(...arguments); + _VariableSkyCommand_regex.set(this, /^([A-Z]{3}) V ([A-Z]{3})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _VariableSkyCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _VariableSkyCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const firstQuantity = as(matches[1], CloudQuantity); + const secondQuantity = as(matches[2], CloudQuantity); + const description = format(_("Remark.Variable.Sky.Condition.0", this.locale), _(`CloudQuantity.${firstQuantity}`, this.locale), _(`CloudQuantity.${secondQuantity}`, this.locale)); + remark.push({ + type: RemarkType.VariableSky, + description, + raw: matches[0], + cloudQuantityRange: [firstQuantity, secondQuantity], + }); + return [code.replace(__classPrivateFieldGet(this, _VariableSkyCommand_regex, "f"), "").trim(), remark]; + } +} +_VariableSkyCommand_regex = new WeakMap(); + +var _VariableSkyHeightCommand_regex; +class VariableSkyHeightCommand extends Command { + constructor() { + super(...arguments); + _VariableSkyHeightCommand_regex.set(this, /^([A-Z]{3})(\d{3}) V ([A-Z]{3})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _VariableSkyHeightCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _VariableSkyHeightCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const firstQuantity = as(matches[1], CloudQuantity); + const secondQuantity = as(matches[3], CloudQuantity); + const height = 100 * +matches[2]; + const description = format(_("Remark.Variable.Sky.Condition.Height", this.locale), height, _(`CloudQuantity.${firstQuantity}`, this.locale), _(`CloudQuantity.${secondQuantity}`, this.locale)); + remark.push({ + type: RemarkType.VariableSkyHeight, + description, + raw: matches[0], + height, + cloudQuantityRange: [firstQuantity, secondQuantity], + }); + return [code.replace(__classPrivateFieldGet(this, _VariableSkyHeightCommand_regex, "f"), "").trim(), remark]; + } +} +_VariableSkyHeightCommand_regex = new WeakMap(); + +var _VirgaDirectionCommand_regex; +class VirgaDirectionCommand extends Command { + constructor() { + super(...arguments); + _VirgaDirectionCommand_regex.set(this, /^VIRGA ([A-Z]{2})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _VirgaDirectionCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _VirgaDirectionCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const direction = as(matches[1], Direction); + const description = format(_("Remark.Virga.Direction", this.locale), _(`Converter.${direction}`, this.locale)); + remark.push({ + type: RemarkType.VirgaDirection, + description, + raw: matches[0], + direction, + }); + return [code.replace(__classPrivateFieldGet(this, _VirgaDirectionCommand_regex, "f"), "").trim(), remark]; + } +} +_VirgaDirectionCommand_regex = new WeakMap(); + +var _WaterEquivalentSnowCommand_regex; +class WaterEquivalentSnowCommand extends Command { + constructor() { + super(...arguments); + _WaterEquivalentSnowCommand_regex.set(this, /^933(\d{3})\b/); + } + canParse(code) { + return __classPrivateFieldGet(this, _WaterEquivalentSnowCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _WaterEquivalentSnowCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const amount = +matches[1] / 10; + const description = format(_("Remark.Water.Equivalent.Snow.Ground", this.locale), amount); + remark.push({ + type: RemarkType.WaterEquivalentSnow, + description, + raw: matches[0], + amount, + }); + return [code.replace(__classPrivateFieldGet(this, _WaterEquivalentSnowCommand_regex, "f"), "").trim(), remark]; + } +} +_WaterEquivalentSnowCommand_regex = new WeakMap(); + +var _WindPeakCommand_regex; +class WindPeakCommand extends Command { + constructor() { + super(...arguments); + _WindPeakCommand_regex.set(this, /^PK WND (\d{3})(\d{2,3})\/(\d{2})?(\d{2})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _WindPeakCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _WindPeakCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const degrees = +matches[1]; + const speed = +matches[2]; + const description = format(_("Remark.PeakWind", this.locale), degrees, speed, matches[3] || "", matches[4]); + remark.push({ + type: RemarkType.WindPeak, + description, + raw: matches[0], + speed, + degrees, + startHour: matches[3] ? +matches[3] : undefined, + startMinute: +matches[4], + }); + return [code.replace(__classPrivateFieldGet(this, _WindPeakCommand_regex, "f"), "").trim(), remark]; + } +} +_WindPeakCommand_regex = new WeakMap(); + +var _WindShiftCommand_regex; +class WindShiftCommand extends Command { + constructor() { + super(...arguments); + _WindShiftCommand_regex.set(this, /^WSHFT (\d{2})?(\d{2})/); + } + canParse(code) { + return __classPrivateFieldGet(this, _WindShiftCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _WindShiftCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.WindShift.0", this.locale), matches[1] || "", matches[2]); + remark.push({ + type: RemarkType.WindShift, + description, + raw: matches[0], + startHour: matches[1] ? +matches[1] : undefined, + startMinute: +matches[2], + }); + return [code.replace(__classPrivateFieldGet(this, _WindShiftCommand_regex, "f"), "").trim(), remark]; + } +} +_WindShiftCommand_regex = new WeakMap(); + +var _WindShiftFropaCommand_regex; +class WindShiftFropaCommand extends Command { + constructor() { + super(...arguments); + _WindShiftFropaCommand_regex.set(this, /^WSHFT (\d{2})?(\d{2}) FROPA/); + } + canParse(code) { + return __classPrivateFieldGet(this, _WindShiftFropaCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _WindShiftFropaCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const description = format(_("Remark.WindShift.FROPA", this.locale), matches[1] || "", matches[2]); + remark.push({ + type: RemarkType.WindShiftFropa, + description, + raw: matches[0], + startHour: matches[1] ? +matches[1] : undefined, + startMinute: +matches[2], + }); + return [code.replace(__classPrivateFieldGet(this, _WindShiftFropaCommand_regex, "f"), "").trim(), remark]; + } +} +_WindShiftFropaCommand_regex = new WeakMap(); + +class DefaultCommand extends Command { + canParse() { + return true; + } + execute(code, remark) { + const rmkSplit = pySplit(code, " ", 1); + const rem = _(`Remark.${rmkSplit[0]}`, this.locale); + if (RemarkType[rmkSplit[0]]) { + remark.push({ + type: rmkSplit[0], + description: rem, + raw: rmkSplit[0], + }); + } + else { + const lastRemark = remark[remark.length - 1]; + if (lastRemark?.type === RemarkType.Unknown) { + // Merge with last unknown value + lastRemark.raw = `${lastRemark.raw} ${rmkSplit[0]}`; + } + else { + remark.push({ + type: RemarkType.Unknown, + raw: rmkSplit[0], + }); + } + } + return [rmkSplit.length === 1 ? "" : rmkSplit[1], remark]; + } +} + +var _PrecipitationBegCommand_regex; +class PrecipitationBegCommand extends Command { + constructor() { + super(...arguments); + _PrecipitationBegCommand_regex.set(this, /^(([A-Z]{2})?([A-Z]{2})B(\d{2})?(\d{2}))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _PrecipitationBegCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _PrecipitationBegCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const descriptive = matches[2] ? as(matches[2], Descriptive) : undefined; + const phenomenon = as(matches[3], Phenomenon); + const description = format(_("Remark.Precipitation.Beg.0", this.locale), descriptive ? _(`Descriptive.${descriptive}`, this.locale) : "", _(`Phenomenon.${phenomenon}`, this.locale), matches[4] || "", matches[5])?.trim(); + remark.push({ + type: RemarkType.PrecipitationBeg, + description, + raw: matches[0], + descriptive, + phenomenon, + startHour: matches[4] ? +matches[4] : undefined, + startMin: +matches[5], + }); + return [code.replace(__classPrivateFieldGet(this, _PrecipitationBegCommand_regex, "f"), "").trim(), remark]; + } +} +_PrecipitationBegCommand_regex = new WeakMap(); + +var _PrecipitationEndCommand_regex; +class PrecipitationEndCommand extends Command { + constructor() { + super(...arguments); + _PrecipitationEndCommand_regex.set(this, /^(([A-Z]{2})?([A-Z]{2})E(\d{2})?(\d{2}))/); + } + canParse(code) { + return __classPrivateFieldGet(this, _PrecipitationEndCommand_regex, "f").test(code); + } + execute(code, remark) { + const matches = code.match(__classPrivateFieldGet(this, _PrecipitationEndCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const descriptive = matches[2] ? as(matches[2], Descriptive) : undefined; + const phenomenon = as(matches[3], Phenomenon); + const description = format(_("Remark.Precipitation.End", this.locale), descriptive ? _(`Descriptive.${descriptive}`, this.locale) : "", _(`Phenomenon.${phenomenon}`, this.locale), matches[4] || "", matches[5])?.trim(); + remark.push({ + type: RemarkType.PrecipitationEnd, + description, + raw: matches[0], + descriptive, + phenomenon, + endHour: matches[4] ? +matches[4] : undefined, + endMin: +matches[5], + }); + return [code.replace(__classPrivateFieldGet(this, _PrecipitationEndCommand_regex, "f"), "").trim(), remark]; + } +} +_PrecipitationEndCommand_regex = new WeakMap(); + +class RemarkCommandSupplier { + constructor(locale) { + this.locale = locale; + this.defaultCommand = new DefaultCommand(locale); + this.commandList = [ + new WindPeakCommand(locale), + new WindShiftFropaCommand(locale), + new WindShiftCommand(locale), + new TowerVisibilityCommand(locale), + new SurfaceVisibilityCommand(locale), + new PrevailingVisibilityCommand(locale), + new SecondLocationVisibilityCommand(locale), + new SectorVisibilityCommand(locale), + new TornadicActivityBegEndCommand(locale), + new TornadicActivityBegCommand(locale), + new TornadicActivityEndCommand(locale), + new PrecipitationBegEndCommand(locale), + new PrecipitationBegCommand(locale), + new PrecipitationEndCommand(locale), + new ThunderStormLocationMovingCommand(locale), + new ThunderStormLocationCommand(locale), + new SmallHailSizeCommand(locale), + new HailSizeCommand(locale), + new SnowPelletsCommand(locale), + new VirgaDirectionCommand(locale), + new CeilingHeightCommand(locale), + new ObscurationCommand(locale), + new VariableSkyHeightCommand(locale), + new VariableSkyCommand(locale), + new CeilingSecondLocationCommand(locale), + new SeaLevelPressureCommand(locale), + new SnowIncreaseCommand(locale), + new HourlyMaximumMinimumTemperatureCommand(locale), + new HourlyMaximumTemperatureCommand(locale), + new HourlyMinimumTemperatureCommand(locale), + new HourlyPrecipitationAmountCommand(locale), + new HourlyTemperatureDewPointCommand(locale), + new HourlyPressureCommand(locale), + new IceAccretionCommand(locale), + new PrecipitationAmount36HourCommand(locale), + new PrecipitationAmount24HourCommand(locale), + new SnowDepthCommand(locale), + new SunshineDurationCommand(locale), + new WaterEquivalentSnowCommand(locale), + ]; + } + get(code) { + for (const command of this.commandList) { + if (command.canParse(code)) + return command; + } + return this.defaultCommand; + } +} +var RemarkType; +(function (RemarkType) { + // Unknown processed with default command + RemarkType["Unknown"] = "Unknown"; + // Processed with default command + RemarkType["AO1"] = "AO1"; + RemarkType["AO2"] = "AO2"; + RemarkType["PRESFR"] = "PRESFR"; + RemarkType["PRESRR"] = "PRESRR"; + RemarkType["TORNADO"] = "TORNADO"; + RemarkType["FUNNELCLOUD"] = "FUNNELCLOUD"; + RemarkType["WATERSPOUT"] = "WATERSPOUT"; + RemarkType["VIRGA"] = "VIRGA"; + // Regular commands below + RemarkType["WindPeak"] = "WindPeak"; + RemarkType["WindShiftFropa"] = "WindShiftFropa"; + RemarkType["WindShift"] = "WindShift"; + RemarkType["TowerVisibility"] = "TowerVisibility"; + RemarkType["SurfaceVisibility"] = "SurfaceVisibility"; + RemarkType["PrevailingVisibility"] = "PrevailingVisibility"; + RemarkType["SecondLocationVisibility"] = "SecondLocationVisibility"; + RemarkType["SectorVisibility"] = "SectorVisibility"; + RemarkType["TornadicActivityBegEnd"] = "TornadicActivityBegEnd"; + RemarkType["TornadicActivityBeg"] = "TornadicActivityBeg"; + RemarkType["TornadicActivityEnd"] = "TornadicActivityEnd"; + RemarkType["PrecipitationBeg"] = "PrecipitationBeg"; + RemarkType["PrecipitationBegEnd"] = "PrecipitationBegEnd"; + RemarkType["PrecipitationEnd"] = "PrecipitationEnd"; + RemarkType["ThunderStormLocationMoving"] = "ThunderStormLocationMoving"; + RemarkType["ThunderStormLocation"] = "ThunderStormLocation"; + RemarkType["SmallHailSize"] = "SmallHailSize"; + RemarkType["HailSize"] = "HailSize"; + RemarkType["SnowPellets"] = "SnowPellets"; + RemarkType["VirgaDirection"] = "VirgaDirection"; + RemarkType["CeilingHeight"] = "CeilingHeight"; + RemarkType["Obscuration"] = "Obscuration"; + RemarkType["VariableSkyHeight"] = "VariableSkyHeight"; + RemarkType["VariableSky"] = "VariableSky"; + RemarkType["CeilingSecondLocation"] = "CeilingSecondLocation"; + RemarkType["SeaLevelPressure"] = "SeaLevelPressure"; + RemarkType["SnowIncrease"] = "SnowIncrease"; + RemarkType["HourlyMaximumMinimumTemperature"] = "HourlyMaximumMinimumTemperature"; + RemarkType["HourlyMaximumTemperature"] = "HourlyMaximumTemperature"; + RemarkType["HourlyMinimumTemperature"] = "HourlyMinimumTemperature"; + RemarkType["HourlyPrecipitationAmount"] = "HourlyPrecipitationAmount"; + RemarkType["HourlyTemperatureDewPoint"] = "HourlyTemperatureDewPoint"; + RemarkType["HourlyPressure"] = "HourlyPressure"; + RemarkType["IceAccretion"] = "IceAccretion"; + RemarkType["PrecipitationAmount36Hour"] = "PrecipitationAmount36Hour"; + RemarkType["PrecipitationAmount24Hour"] = "PrecipitationAmount24Hour"; + RemarkType["SnowDepth"] = "SnowDepth"; + RemarkType["SunshineDuration"] = "SunshineDuration"; + RemarkType["WaterEquivalentSnow"] = "WaterEquivalentSnow"; +})(RemarkType || (RemarkType = {})); + +function isWeatherConditionValid(weather) { + return (weather.phenomenons.length !== 0 || + weather.descriptive == Descriptive.THUNDERSTORM || + (weather.intensity === Intensity.IN_VICINITY && + weather.descriptive == Descriptive.SHOWERS)); +} + +var _CloudCommand_cloudRegex, _MainVisibilityCommand_regex, _WindCommand_regex, _WindVariationCommand_regex, _WindShearCommand_regex, _VerticalVisibilityCommand_regex, _MinimalVisibilityCommand_regex, _MainVisibilityNauticalMilesCommand_regex, _CommandSupplier_commands$1; +/** + * This function creates a wind element. + * @param wind The wind object + * @param direction The direction in degrees + * @param speed The speed + * @param gust The speed of the gust. + * @param unit The speed unit + */ +function makeWind(direction, speed, gust, unit) { + return { + speed: +speed, + direction: degreesToCardinal(direction), + degrees: direction !== "VRB" ? +direction : undefined, + gust: gust ? +gust : undefined, + unit, + }; +} +class CloudCommand { + constructor() { + _CloudCommand_cloudRegex.set(this, /^([A-Z]{3})(\d{3})?([A-Z]{2,3})?$/); + } + parse(cloudString) { + const m = cloudString.match(__classPrivateFieldGet(this, _CloudCommand_cloudRegex, "f")); + if (!m) + return; + const quantity = CloudQuantity[m[1]]; + const height = 100 * +m[2] || undefined; + const type = CloudType[m[3]]; + if (!quantity) + return; + return { quantity, height, type }; + } + execute(container, cloudString) { + const cloud = this.parse(cloudString); + if (cloud) { + container.clouds.push(cloud); + return true; + } + return false; + } + canParse(cloudString) { + return __classPrivateFieldGet(this, _CloudCommand_cloudRegex, "f").test(cloudString); + } +} +_CloudCommand_cloudRegex = new WeakMap(); +class MainVisibilityCommand { + constructor() { + _MainVisibilityCommand_regex.set(this, /^(\d{4})(|NDV)$/); + } + canParse(visibilityString) { + return __classPrivateFieldGet(this, _MainVisibilityCommand_regex, "f").test(visibilityString); + } + execute(container, visibilityString) { + const matches = visibilityString.match(__classPrivateFieldGet(this, _MainVisibilityCommand_regex, "f")); + if (!matches) + return false; + const distance = convertVisibility(matches[1]); + if (!container.visibility) + container.visibility = distance; + container.visibility = { ...container.visibility, ...distance }; + if (matches[2] === "NDV") + container.visibility.ndv = true; + return true; + } +} +_MainVisibilityCommand_regex = new WeakMap(); +class WindCommand { + constructor() { + _WindCommand_regex.set(this, /^(VRB|\d{3})(\d{2})G?(\d{2})?(KT|MPS|KM\/H)?/); + } + canParse(windString) { + return __classPrivateFieldGet(this, _WindCommand_regex, "f").test(windString); + } + parseWind(windString) { + const matches = windString.match(__classPrivateFieldGet(this, _WindCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Wind should be defined"); + return makeWind(matches[1], matches[2], matches[3], as(matches[4] || "KT", SpeedUnit)); + } + execute(container, windString) { + const wind = this.parseWind(windString); + container.wind = wind; + return true; + } +} +_WindCommand_regex = new WeakMap(); +class WindVariationCommand { + constructor() { + _WindVariationCommand_regex.set(this, /^(\d{3})V(\d{3})/); + } + canParse(windString) { + return __classPrivateFieldGet(this, _WindVariationCommand_regex, "f").test(windString); + } + parseWindVariation(wind, windString) { + const matches = windString.match(__classPrivateFieldGet(this, _WindVariationCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Wind should be defined"); + wind.minVariation = +matches[1]; + wind.maxVariation = +matches[2]; + } + execute(container, windString) { + if (!container.wind) + throw new UnexpectedParseError(); + this.parseWindVariation(container.wind, windString); + return true; + } +} +_WindVariationCommand_regex = new WeakMap(); +class WindShearCommand { + constructor() { + _WindShearCommand_regex.set(this, /^WS(\d{3})\/(\w{3})(\d{2})G?(\d{2})?(KT|MPS|KM\/H)/); + } + canParse(windString) { + return __classPrivateFieldGet(this, _WindShearCommand_regex, "f").test(windString); + } + parseWindShear(windString) { + const matches = windString.match(__classPrivateFieldGet(this, _WindShearCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Wind shear should be defined"); + return { + ...makeWind(matches[2], matches[3], matches[4], as(matches[5], SpeedUnit)), + height: 100 * +matches[1], + }; + } + execute(container, windString) { + container.windShear = this.parseWindShear(windString); + return true; + } +} +_WindShearCommand_regex = new WeakMap(); +class VerticalVisibilityCommand { + constructor() { + _VerticalVisibilityCommand_regex.set(this, /^VV(\d{3})$/); + } + execute(container, visibilityString) { + const matches = visibilityString.match(__classPrivateFieldGet(this, _VerticalVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Vertical visibility should be defined"); + container.verticalVisibility = 100 * +matches[1]; + return true; + } + canParse(windString) { + return __classPrivateFieldGet(this, _VerticalVisibilityCommand_regex, "f").test(windString); + } +} +_VerticalVisibilityCommand_regex = new WeakMap(); +class MinimalVisibilityCommand { + constructor() { + _MinimalVisibilityCommand_regex.set(this, /^(\d{4}[a-zA-Z]{1,2})$/); + } + execute(container, visibilityString) { + const matches = visibilityString.match(__classPrivateFieldGet(this, _MinimalVisibilityCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Vertical visibility should be defined"); + if (!container.visibility) + throw new UnexpectedParseError("container.visibility not instantiated"); + container.visibility.min = { + value: +matches[1].slice(0, 4), + direction: matches[1].slice(4), + }; + return true; + } + canParse(windString) { + return __classPrivateFieldGet(this, _MinimalVisibilityCommand_regex, "f").test(windString); + } +} +_MinimalVisibilityCommand_regex = new WeakMap(); +class MainVisibilityNauticalMilesCommand { + constructor() { + _MainVisibilityNauticalMilesCommand_regex.set(this, /^(P|M)?(\d)*(\s)?((\d\/\d)?SM)$/); + } + execute(container, visibilityString) { + const distance = convertNauticalMilesVisibility(visibilityString); + container.visibility = distance; + return true; + } + canParse(windString) { + return __classPrivateFieldGet(this, _MainVisibilityNauticalMilesCommand_regex, "f").test(windString); + } +} +_MainVisibilityNauticalMilesCommand_regex = new WeakMap(); +class CommandSupplier$1 { + constructor() { + _CommandSupplier_commands$1.set(this, [ + new WindShearCommand(), + new WindCommand(), + new WindVariationCommand(), + new MainVisibilityCommand(), + new MainVisibilityNauticalMilesCommand(), + new MinimalVisibilityCommand(), + new VerticalVisibilityCommand(), + new CloudCommand(), + ]); + } + get(input) { + for (const command of __classPrivateFieldGet(this, _CommandSupplier_commands$1, "f")) { + if (command.canParse(input)) + return command; + } + } +} +_CommandSupplier_commands$1 = new WeakMap(); + +var _AltimeterCommand_regex; +class AltimeterCommand { + constructor() { + _AltimeterCommand_regex.set(this, /^Q(\d{4})$/); + } + canParse(input) { + return __classPrivateFieldGet(this, _AltimeterCommand_regex, "f").test(input); + } + execute(metar, input) { + const matches = input.match(__classPrivateFieldGet(this, _AltimeterCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + metar.altimeter = Math.trunc(+matches[1]); + } +} +_AltimeterCommand_regex = new WeakMap(); + +var _AltimeterMercuryCommand_regex; +class AltimeterMercuryCommand { + constructor() { + _AltimeterMercuryCommand_regex.set(this, /^A(\d{4})$/); + } + canParse(input) { + return __classPrivateFieldGet(this, _AltimeterMercuryCommand_regex, "f").test(input); + } + execute(metar, input) { + const matches = input.match(__classPrivateFieldGet(this, _AltimeterMercuryCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + const mercury = +matches[1] / 100; + metar.altimeter = Math.trunc(convertInchesMercuryToPascal(mercury)); + } +} +_AltimeterMercuryCommand_regex = new WeakMap(); + +var _RunwayCommand_genericRegex, _RunwayCommand_runwayMaxRangeRegex, _RunwayCommand_runwayRegex; +class RunwayCommand { + constructor() { + _RunwayCommand_genericRegex.set(this, /^(R\d{2}\w?\/)/); + _RunwayCommand_runwayMaxRangeRegex.set(this, /^R(\d{2}\w?)\/(\d{4})V(\d{3,4})([UDN])?(FT)?/); + _RunwayCommand_runwayRegex.set(this, /^R(\d{2}\w?)\/([MP])?(\d{4})([UDN])?(FT)?$/); + } + canParse(input) { + return __classPrivateFieldGet(this, _RunwayCommand_genericRegex, "f").test(input); + } + execute(metar, input) { + // TODO idk if this matches super well... + if (__classPrivateFieldGet(this, _RunwayCommand_runwayRegex, "f").test(input)) { + const matches = input.match(__classPrivateFieldGet(this, _RunwayCommand_runwayRegex, "f")); + if (!matches) + throw new UnexpectedParseError("Should be able to parse"); + const indicator = matches[2] ? as(matches[2], ValueIndicator) : undefined; + const trend = matches[4] ? as(matches[4], RunwayInfoTrend) : undefined; + const unit = matches[5] + ? as(matches[5], RunwayInfoUnit) + : RunwayInfoUnit.Meters; + metar.runwaysInfo.push({ + name: matches[1], + indicator, + minRange: +matches[3], + trend, + unit, + }); + } + else if (__classPrivateFieldGet(this, _RunwayCommand_runwayMaxRangeRegex, "f").test(input)) { + const matches = input.match(__classPrivateFieldGet(this, _RunwayCommand_runwayMaxRangeRegex, "f")); + if (!matches) + throw new UnexpectedParseError("Should be able to parse"); + const trend = matches[4] ? as(matches[4], RunwayInfoTrend) : undefined; + const unit = matches[5] + ? as(matches[5], RunwayInfoUnit) + : RunwayInfoUnit.Meters; + metar.runwaysInfo.push({ + name: matches[1], + minRange: +matches[2], + maxRange: +matches[3], + trend, + unit, + }); + } + } +} +_RunwayCommand_genericRegex = new WeakMap(), _RunwayCommand_runwayMaxRangeRegex = new WeakMap(), _RunwayCommand_runwayRegex = new WeakMap(); + +var _TemperatureCommand_regex; +class TemperatureCommand { + constructor() { + _TemperatureCommand_regex.set(this, /^(M?\d{2})\/(M?\d{2})$/); + } + canParse(input) { + return __classPrivateFieldGet(this, _TemperatureCommand_regex, "f").test(input); + } + execute(metar, input) { + const matches = input.match(__classPrivateFieldGet(this, _TemperatureCommand_regex, "f")); + if (!matches) + throw new UnexpectedParseError("Match not found"); + metar.temperature = convertTemperature(matches[1]); + metar.dewPoint = convertTemperature(matches[2]); + } +} +_TemperatureCommand_regex = new WeakMap(); + +var _CommandSupplier_commands; +class CommandSupplier { + constructor() { + _CommandSupplier_commands.set(this, [ + new RunwayCommand(), + new TemperatureCommand(), + new AltimeterCommand(), + new AltimeterMercuryCommand(), + ]); + } + get(input) { + for (const command of __classPrivateFieldGet(this, _CommandSupplier_commands, "f")) { + if (command.canParse(input)) + return command; + } + } +} +_CommandSupplier_commands = new WeakMap(); + +var _AbstractParser_INTENSITY_REGEX, _AbstractParser_CAVOK, _AbstractParser_commonSupplier, _MetarParser_commandSupplier, _TAFParser_validityPattern, _RemarkParser_supplier; +/** + * Parses the delivery time of a METAR/TAF + * @param abstractWeatherCode The TAF or METAR object + * @param timeString The string representing the delivery time + */ +function parseDeliveryTime(timeString) { + const day = +timeString.slice(0, 2); + const hour = +timeString.slice(2, 4); + const minute = +timeString.slice(4, 6); + if (isNaN(day) || isNaN(hour) || isNaN(minute)) + return; + return { + day, + hour, + minute, + }; +} +function parseFlags(abstractWeatherCode, flag) { + const flags = findFlags(flag); + if (flags) + Object.assign(abstractWeatherCode, flags); + return !!flags; +} +var FlagMap; +(function (FlagMap) { + FlagMap["AMD"] = "amendment"; + FlagMap["AUTO"] = "auto"; + FlagMap["CNL"] = "canceled"; + FlagMap["COR"] = "corrected"; + FlagMap["NIL"] = "nil"; +})(FlagMap || (FlagMap = {})); +function findFlags(flag) { + if (flag in FlagMap) + return { [FlagMap[flag]]: true }; +} +/** + * This function parses the array containing the remark and concat the array into a string + * @param container the metar, taf or taf trend to update + * @param line The array containing the current line tokens + * @param index the index starting the remark ie token RMK + */ +function parseRemark(container, line, index, locale) { + const remarks = new RemarkParser(locale).parse(line.slice(index + 1).join(" ")); + container.remarks = remarks; + container.remark = remarks + .map(({ description, raw }) => description || raw) + .join(" "); +} +/** + * Parses the temperature in a TAF + * @param input the string containing the temperature + * @returns TemperatureDated object + */ +function parseTemperature(input) { + const parts = pySplit(input, "/"); + return { + temperature: convertTemperature(parts[0].slice(2)), + day: +parts[1].slice(0, 2), + hour: +parts[1].slice(2, 4), + }; +} +/** + * Parses validity of a TAF or a TAFTrend + * @param input the string containing the validity + * @returns Validity object + */ +function parseValidity(input) { + const parts = pySplit(input, "/"); + return { + startDay: +parts[0].slice(0, 2), + startHour: +parts[0].slice(2), + endDay: +parts[1].slice(0, 2), + endHour: +parts[1].slice(2), + }; +} +/** + * Parses the validity for a FROM taf trend + * @param input the string containing the validity + * @returns a Validity object + */ +function parseFromValidity(input) { + return { + startDay: +input.slice(2, 4), + startHour: +input.slice(4, 6), + startMinutes: +input.slice(6, 8), + }; +} +/** + * Abstract class. + * Base parser. + */ +class AbstractParser { + constructor(locale) { + this.locale = locale; + this.FM = "FM"; + this.TEMPO = "TEMPO"; + this.BECMG = "BECMG"; + this.RMK = "RMK"; + // Safari does not currently support negative lookbehind + // #TOKENIZE_REGEX = /\s((?=\d\/\dSM)(? v); + // Hack for safari below... + const splitRegex = /\s|=/; + const smRegex = /^\d\/\dSM$/; + const digitRegex = /^(P|M)?\d$/; + // return input.split(this.#TOKENIZE_REGEX).filter((v) => v); + const splitted = input.split(splitRegex); + for (let i = 0; i < splitted.length; i++) { + if (digitRegex.test(splitted[i])) { + if (splitted[i + 1] && smRegex.test(splitted[i + 1])) { + splitted.splice(i, 2, `${splitted[i]} ${splitted[i + 1]}`); + } + } + } + return splitted.filter((t) => t); + } + /** + * Common parse method for METAR, TAF and trends object + * @param abstractWeatherCode the object to update + * @param input The token to parse + * @returns True if the token was parsed false otherwise + */ + generalParse(abstractWeatherContainer, input) { + if (input === __classPrivateFieldGet(this, _AbstractParser_CAVOK, "f")) { + abstractWeatherContainer.cavok = true; + abstractWeatherContainer.visibility = { + indicator: ValueIndicator.GreaterThan, + value: 9999, + unit: DistanceUnit.Meters, + }; + return true; + } + const command = __classPrivateFieldGet(this, _AbstractParser_commonSupplier, "f").get(input); + if (command) { + return command.execute(abstractWeatherContainer, input); + } + const weatherCondition = this.parseWeatherCondition(input); + if (isWeatherConditionValid(weatherCondition)) { + abstractWeatherContainer.weatherConditions.push(weatherCondition); + return true; + } + return false; + } +} +_AbstractParser_INTENSITY_REGEX = new WeakMap(), _AbstractParser_CAVOK = new WeakMap(), _AbstractParser_commonSupplier = new WeakMap(); +class MetarParser extends AbstractParser { + constructor() { + super(...arguments); + this.AT = "AT"; + this.TL = "TL"; + _MetarParser_commandSupplier.set(this, new CommandSupplier()); + } + /** + * Parses a trend of a metar + * @param index the index starting the trend in the list + * @param trend The trend to update + * @param trendParts array of tokens + * @returns the last index of the token that was last parsed + */ + parseTrend(index, trend, trendParts) { + let i = index + 1; + while (i < trendParts.length && + trendParts[i] !== this.TEMPO && + trendParts[i] !== this.BECMG) { + if (trendParts[i].startsWith(this.FM) || + trendParts[i].startsWith(this.TL) || + trendParts[i].startsWith(this.AT)) { + const trendTime = { + type: TimeIndicator[trendParts[i].slice(0, 2)], + hour: +trendParts[i].slice(2, 4), + minute: +trendParts[i].slice(4, 6), + }; + trend.times.push(trendTime); + } + else { + this.generalParse(trend, trendParts[i]); + } + i = i + 1; + } + return i - 1; + } + /** + * Parses an message and returns a METAR + * @param input The message to parse + * @returns METAR + */ + parse(input) { + const metarTab = this.tokenize(input); + const metar = { + ...parseDeliveryTime(metarTab[1]), + station: metarTab[0], + message: input, + remarks: [], + clouds: [], + weatherConditions: [], + trends: [], + runwaysInfo: [], + }; + let index = 2; + while (index < metarTab.length) { + if (!super.generalParse(metar, metarTab[index]) && + !parseFlags(metar, metarTab[index])) { + if (metarTab[index] === "NOSIG") { + metar.nosig = true; + } + else if (metarTab[index] === this.TEMPO || + metarTab[index] === this.BECMG) { + const trend = { + type: WeatherChangeType[metarTab[index]], + weatherConditions: [], + clouds: [], + times: [], + remarks: [], + raw: input, + }; + index = this.parseTrend(index, trend, metarTab); + metar.trends.push(trend); + } + else if (metarTab[index] === this.RMK) { + parseRemark(metar, metarTab, index, this.locale); + break; + } + else { + const command = __classPrivateFieldGet(this, _MetarParser_commandSupplier, "f").get(metarTab[index]); + if (command) + command.execute(metar, metarTab[index]); + } + } + index = index + 1; + } + return metar; + } +} +_MetarParser_commandSupplier = new WeakMap(); +/** + * Parser for TAF messages + */ +class TAFParser extends AbstractParser { + constructor() { + super(...arguments); + this.TAF = "TAF"; + this.PROB = "PROB"; + this.TX = "TX"; + this.TN = "TN"; + this.NSW = "NSW"; + _TAFParser_validityPattern.set(this, /^\d{4}\/\d{4}$/); + } + /** + * the message to parse + * @param input + * @returns a TAF object + * @throws ParseError if the message is invalid + */ + parse(input) { + const lines = this.extractLinesTokens(input); + let index = 0; + if (lines[0][0] === this.TAF) + index = 1; + if (lines[0][1] === this.TAF) + index = 2; + const flags = findFlags(lines[0][index]); + if (flags) { + index += 1; + } + const station = lines[0][index]; + index += 1; + const time = parseDeliveryTime(lines[0][index]); + if (time) + index += 1; + const validity = parseValidity(lines[0][index]); + const taf = { + station, + ...flags, + ...time, + validity, + message: input, + trends: [], + remarks: [], + clouds: [], + weatherConditions: [], + initialRaw: lines[0].join(" "), + }; + for (let i = index + 1; i < lines[0].length; i++) { + const token = lines[0][i]; + if (token == this.RMK) { + parseRemark(taf, lines[0], i, this.locale); + break; + } + else { + parseFlags(taf, token); + this.generalParse(taf, token); + } + } + const minMaxTemperatureLines = [ + lines[0].slice(index + 1), // EU countries have min/max in first line + ]; + // US military bases have min/max in last line + if (lines.length > 1) + minMaxTemperatureLines.push(lines[lines.length - 1]); + this.parseMaxMinTemperatures(taf, minMaxTemperatureLines); + // Handle the other lines + for (let i = 1; i < lines.length; i++) { + this.parseLine(taf, lines[i]); + } + return taf; + } + parseMaxMinTemperatures(taf, lines) { + for (const line of lines) { + for (const token of line) { + if (token == this.RMK) + break; + else if (token.startsWith(this.TX)) + taf.maxTemperature = parseTemperature(token); + else if (token.startsWith(this.TN)) + taf.minTemperature = parseTemperature(token); + } + } + } + /** + * Format the message as a multiple line code so each line can be parsed + * @param tafCode The base message + * @returns a list of string representing the lines of the message + */ + extractLinesTokens(tafCode) { + const singleLine = tafCode.replace(/\n/g, " "); + const cleanLine = singleLine.replace(/\s{2,}/g, " "); + const lines = joinProbIfNeeded(cleanLine + .replace(/\s(?=PROB\d{2}\sTEMPO|TEMPO|BECMG|FM|PROB)/g, "\n") + .split(/\n/)); + // TODO cleanup + function joinProbIfNeeded(ls) { + for (let i = 0; i < ls.length; i++) { + if (/^PROB\d{2}$/.test(ls[i]) && /^TEMPO/.test(ls[i + 1])) { + ls.splice(i, 2, `${ls[i]} ${ls[i + 1]}`); + } + } + return ls; + } + const linesToken = lines.map(this.tokenize); + return linesToken; + } + /** + * Parses the tokens of the line and updates the TAF object + * @param taf TAF object to update + * @param lineTokens the array of tokens representing a line + */ + parseLine(taf, lineTokens) { + let index = 1; + let trend; + if (lineTokens[0].startsWith(this.FM)) { + trend = { + ...this.makeEmptyTAFTrend(), + type: WeatherChangeType.FM, + validity: parseFromValidity(lineTokens[0]), + raw: lineTokens.join(" "), + }; + } + else if (lineTokens[0].startsWith(this.PROB)) { + const validity = this.findLineValidity(index, lineTokens); + if (!validity) + return; + trend = { + ...this.makeEmptyTAFTrend(), + type: WeatherChangeType.PROB, + validity, + raw: lineTokens.join(" "), + }; + if (lineTokens.length > 1 && lineTokens[1] === this.TEMPO) { + trend = { + ...this.makeEmptyTAFTrend(), + type: WeatherChangeType[lineTokens[1]], + validity, + raw: lineTokens.join(" "), + }; + index = 2; + } + trend.probability = +lineTokens[0].slice(4); + } + else { + const validity = this.findLineValidity(index, lineTokens); + if (!validity) + return; + trend = { + ...this.makeEmptyTAFTrend(), + type: WeatherChangeType[lineTokens[0]], + validity, + raw: lineTokens.join(" "), + }; + } + this.parseTrend(index, lineTokens, trend); + taf.trends.push(trend); + } + /** + * Finds a non-FM validity in a line + * @param index the index at which the array should be parsed + * @param line The array of string containing the line + * @param trend The trend object to update + */ + findLineValidity(index, line) { + let validity; + for (let i = index; i < line.length; i++) { + if (__classPrivateFieldGet(this, _TAFParser_validityPattern, "f").test(line[i])) + validity = parseValidity(line[i]); + } + return validity; + } + /** + * Parses a trend of the TAF + * @param index the index at which the array should be parsed + * @param line The array of string containing the line + * @param trend The trend object to update + */ + parseTrend(index, line, trend) { + for (let i = index; i < line.length; i++) { + if (line[i] === this.RMK) { + parseRemark(trend, line, i, this.locale); + break; + } + else if (line[i] === this.NSW) + trend.nsw = true; + // already parsed + else if (__classPrivateFieldGet(this, _TAFParser_validityPattern, "f").test(line[i])) + continue; + else + super.generalParse(trend, line[i]); + } + } + makeEmptyTAFTrend() { + return { + remarks: [], + clouds: [], + weatherConditions: [], + }; + } +} +_TAFParser_validityPattern = new WeakMap(); +class RemarkParser { + constructor(locale) { + this.locale = locale; + _RemarkParser_supplier.set(this, new RemarkCommandSupplier(this.locale)); + } + parse(code) { + let rmkStr = code; + let rmkList = []; + while (rmkStr) { + try { + [rmkStr, rmkList] = __classPrivateFieldGet(this, _RemarkParser_supplier, "f").get(rmkStr).execute(rmkStr, rmkList); + } + catch (e) { + if (e instanceof CommandExecutionError) { + [rmkStr, rmkList] = __classPrivateFieldGet(this, _RemarkParser_supplier, "f").defaultCommand.execute(rmkStr, rmkList); + } + else { + throw e; + } + } + } + return rmkList; + } +} +_RemarkParser_supplier = new WeakMap(); + +/** + * + * @param date Ideally the date the report was issued. However, any date within + * ~14 days of the report will work. + * @param day Day of the month (from the report) + * @param hour Hour (from the report) + * @param minute Minute (from the report) + * @returns + */ +function determineReportIssuedDate(date, day, hour, minute) { + // Some TAF reports do not include a delivery time + if (day == null || hour == null) + return date; + const months = [ + setDateComponents(addMonthsUTC(date, -1), day, hour, minute), + setDateComponents(new Date(date), day, hour, minute), + setDateComponents(addMonthsUTC(date, 1), day, hour, minute), + ]; + return months + .map((d) => ({ + date: d, + difference: Math.abs(d.getTime() - date.getTime()), + })) + .sort((a, b) => a.difference - b.difference)[0].date; +} +function getReportDate(issued, day, hour, minute = 0) { + let date = new Date(issued); + if (day < date.getUTCDate()) { + date = addMonthsUTC(date, 1); + } + date.setUTCDate(day); + date.setUTCHours(hour); + if (minute != null) + date.setUTCMinutes(minute); + return date; +} +function setDateComponents(date, day, hour, minute) { + date.setUTCDate(day); + date.setUTCHours(hour); + if (minute != null) + date.setUTCMinutes(minute); + return date; +} +function addMonthsUTC(date, count) { + if (date && count) { + let m, d = (date = new Date(+date)).getUTCDate(); + date.setUTCMonth(date.getUTCMonth() + count, 1); + m = date.getUTCMonth(); + date.setUTCDate(d); + if (date.getUTCMonth() !== m) + date.setUTCDate(0); + } + return date; +} + +function metarDatesHydrator(report, date) { + return { + ...report, + issued: determineReportIssuedDate(date, report.day, report.hour, report.minute), + }; +} + +function tafDatesHydrator(report, date) { + const issued = determineReportIssuedDate(date, report.day, report.hour, report.minute); + return { + ...report, + issued, + validity: { + ...report.validity, + start: getReportDate(issued, report.validity.startDay, report.validity.startHour), + end: getReportDate(issued, report.validity.endDay, report.validity.endHour), + }, + minTemperature: report.minTemperature + ? { + ...report.minTemperature, + date: getReportDate(issued, report.minTemperature.day, report.minTemperature.hour), + } + : undefined, + maxTemperature: report.maxTemperature + ? { + ...report.maxTemperature, + date: getReportDate(issued, report.maxTemperature.day, report.maxTemperature.hour), + } + : undefined, + trends: report.trends.map((trend) => ({ + ...trend, + validity: (() => { + switch (trend.type) { + case WeatherChangeType.FM: + return { + ...trend.validity, + start: getReportDate(issued, trend.validity.startDay, trend.validity.startHour, trend.validity.startMinutes), + }; + default: + return { + ...trend.validity, + start: getReportDate(issued, trend.validity.startDay, trend.validity.startHour), + end: getReportDate(issued, trend.validity.endDay, trend.validity.endHour), + }; + } + })(), + })), + }; +} + +function getForecastFromTAF(taf) { + return { + ...taf, + start: getReportDate(taf.issued, taf.validity.startDay, taf.validity.startHour), + end: getReportDate(taf.issued, taf.validity.endDay, taf.validity.endHour), + forecast: hydrateEndDates([makeInitialForecast(taf), ...taf.trends], taf.validity), + }; +} +/** + * Treat the base of the TAF as a FM + */ +function makeInitialForecast(taf) { + return { + wind: taf.wind, + visibility: taf.visibility, + verticalVisibility: taf.verticalVisibility, + windShear: taf.windShear, + cavok: taf.cavok, + remark: taf.remark, + remarks: taf.remarks, + clouds: taf.clouds, + weatherConditions: taf.weatherConditions, + raw: taf.initialRaw, + validity: { + // End day/hour are for end of the entire TAF + startDay: taf.validity.startDay, + startHour: taf.validity.startHour, + startMinutes: 0, + start: taf.validity.start, + }, + }; +} +function hasImplicitEnd({ type }) { + return (type === WeatherChangeType.FM || + // BECMG are special - the "end" date in the validity isn't actually + // the end date, it's when the change that's "becoming" is expected to + // finish transition. The actual "end" date of the BECMG is determined by + // the next FM/BECMG/end of the report validity, just like a FM + type === WeatherChangeType.BECMG || + // Special case for beginning of report conditions + type === undefined); +} +function hydrateEndDates(trends, reportValidity) { + function findNext(index) { + for (let i = index; i < trends.length; i++) { + if (hasImplicitEnd(trends[i])) + return trends[i]; + } + } + const forecasts = []; + let previouslyHydratedTrend; + for (let i = 0; i < trends.length; i++) { + const currentTrend = trends[i]; + const nextTrend = findNext(i + 1); + if (!hasImplicitEnd(currentTrend)) { + forecasts.push({ + ...currentTrend, + start: currentTrend.validity.start, + // Has a type and not a FM/BECMG/undefined, so always has an end + end: currentTrend.validity.end, + }); + continue; + } + let forecast; + if (nextTrend === undefined) { + forecast = hydrateWithPreviousContextIfNeeded({ + ...currentTrend, + start: currentTrend.validity.start, + end: reportValidity.end, + ...byIfNeeded(currentTrend), + }, previouslyHydratedTrend); + } + else { + forecast = hydrateWithPreviousContextIfNeeded({ + ...currentTrend, + start: currentTrend.validity.start, + end: new Date(nextTrend.validity.start), + ...byIfNeeded(currentTrend), + }, previouslyHydratedTrend); + } + forecasts.push(forecast); + previouslyHydratedTrend = forecast; + } + return forecasts; +} +/** + * BECMG doesn't always have all the context for the period, so + * it needs to be populated + */ +function hydrateWithPreviousContextIfNeeded(forecast, context) { + if (forecast.type !== WeatherChangeType.BECMG || !context) + return forecast; + // Remarks should not be carried over + context = { ...context }; + delete context.remark; + context.remarks = []; + delete context.nsw; + forecast = { + ...context, + ...forecast, + }; + if (!forecast.clouds.length) + forecast.clouds = context.clouds; + // If NSW = true, previous weather conditions have stopped and should + // not be carried over + if (!forecast.weatherConditions.length && !forecast.nsw) + forecast.weatherConditions = context.weatherConditions; + return forecast; +} +class TimestampOutOfBoundsError extends ParseError { + constructor(message) { + super(message); + this.name = "TimestampOutOfBoundsError"; + Object.setPrototypeOf(this, new.target.prototype); + } +} +function getCompositeForecastForDate(date, forecastContainer) { + // Validity bounds check + if (date.getTime() > forecastContainer.end.getTime() || + date.getTime() < forecastContainer.start.getTime()) + throw new TimestampOutOfBoundsError("Provided timestamp is outside the report validity period"); + let base; + let additional = []; + for (const forecast of forecastContainer.forecast) { + if (hasImplicitEnd(forecast) && + forecast.start.getTime() <= date.getTime()) { + // Is FM or initial forecast + base = forecast; + } + if (!hasImplicitEnd(forecast) && + forecast.end && + forecast.end.getTime() - date.getTime() > 0 && + forecast.start.getTime() - date.getTime() <= 0) { + // Is TEMPO, BECMG etc + additional.push(forecast); + } + } + if (!base) + throw new UnexpectedParseError("Unable to find trend for date"); + return { base, additional }; +} +function byIfNeeded(forecast) { + if (forecast.type !== WeatherChangeType.BECMG) + return {}; + return { by: forecast.validity.end }; +} + +function parseMetar(rawMetar, options) { + return parse(rawMetar, options, MetarParser, metarDatesHydrator); +} +function parseTAF(rawTAF, options) { + return parse(rawTAF, options, TAFParser, tafDatesHydrator); +} +function parseTAFAsForecast(rawTAF, options) { + const taf = parseTAF(rawTAF, options); + return getForecastFromTAF(taf); +} +function parse(rawReport, options, parser, datesHydrator) { + const lang = options?.locale || en; + try { + const report = new parser(lang).parse(rawReport); + if (options && "issued" in options) { + return datesHydrator(report, options.issued); + } + return report; + } + catch (e) { + if (e instanceof ParseError) + throw e; + throw new InvalidWeatherStatementError(e); + } +} + +export { CloudQuantity, CloudType, CommandExecutionError, Descriptive, Direction, DistanceUnit, Intensity, InvalidWeatherStatementError, ParseError, Phenomenon, RemarkType, RunwayInfoTrend, RunwayInfoUnit, SpeedUnit, TimeIndicator, TimestampOutOfBoundsError, UnexpectedParseError, ValueIndicator, WeatherChangeType, getCompositeForecastForDate, isWeatherConditionValid, parseMetar, parseTAF, parseTAFAsForecast }; diff --git a/server/styles/main.css b/server/styles/main.css index d083450..6907680 100644 --- a/server/styles/main.css +++ b/server/styles/main.css @@ -1 +1 @@ -@font-face{font-family:"Star4000";src:url("../fonts/Star4000.woff") format("woff");font-display:swap}body{font-family:"Star4000"}@media(prefers-color-scheme: dark){body{background-color:#000;color:#fff}}@media(prefers-color-scheme: dark){body a{color:#add8e6}}body.kiosk{margin:0px;overflow:hidden;width:100vw}#divQuery{max-width:640px}#divQuery .buttons{display:inline-block;width:150px;text-align:right}#divQuery .buttons #imgGetGps{height:13px;vertical-align:middle}#divQuery .buttons button{font-size:16pt;border:1px solid #a9a9a9}@media(prefers-color-scheme: dark){#divQuery .buttons button{background-color:#000;color:#fff}}#divQuery .buttons #btnGetGps img.dark{display:none}@media(prefers-color-scheme: dark){#divQuery .buttons #btnGetGps img.dark{display:inline-block}}@media(prefers-color-scheme: dark){#divQuery .buttons #btnGetGps img.light{display:none}}#divQuery .buttons #btnGetGps.active{background-color:#000}@media(prefers-color-scheme: dark){#divQuery .buttons #btnGetGps.active{background-color:#fff}}#divQuery .buttons #btnGetGps.active img{filter:invert(1)}#divQuery input,#divQuery button{font-family:"Star4000"}#divQuery #txtAddress{width:calc(100% - 170px);max-width:490px;font-size:16pt;min-width:200px;display:inline-block}@media(prefers-color-scheme: dark){#divQuery #txtAddress{background-color:#000;color:#fff;border:1px solid #a9a9a9}}.autocomplete-suggestions{background-color:#fff;border:1px solid #000;position:absolute;z-index:9999}@media(prefers-color-scheme: dark){.autocomplete-suggestions{background-color:#000}}.autocomplete-suggestions div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:16pt}.autocomplete-suggestions div.selected{background-color:blue;color:#fff}#divTwc{display:block;background-color:#000;color:#fff;width:100%;max-width:640px}#divTwc.wide{max-width:854px}.kiosk #divTwc{max-width:unset}#divTwcLeft{display:none;text-align:right;flex-direction:column;vertical-align:middle}#divTwcLeft>div{flex:1;padding-right:12px;display:flex;flex-direction:column;justify-content:center}#divTwcRight{text-align:left;display:none;flex-direction:column;vertical-align:middle}#divTwcRight>div{flex:1;padding-left:12px;display:flex;flex-direction:column;justify-content:center}#divTwcBottom{display:flex;flex-direction:row;background-color:#000;color:#fff;width:100%}@media(prefers-color-scheme: dark){#divTwcBottom{background-color:#303030}}#divTwcBottom>div{padding-left:6px;padding-right:6px}@media(max-width: 550px){#divTwcBottom>div{zoom:.9}}@media(max-width: 500px){#divTwcBottom>div{zoom:.8}}@media(max-width: 450px){#divTwcBottom>div{zoom:.7}}@media(max-width: 400px){#divTwcBottom>div{zoom:.6}}@media(max-width: 350px){#divTwcBottom>div{zoom:.5}}#divTwcBottomLeft{flex:1;text-align:left}#divTwcBottomMiddle{flex:0;text-align:center}#divTwcBottomRight{flex:1;text-align:right}#divTwcNavContainer{display:none}#divTwcNav{width:100%;display:flex;flex-direction:row;background-color:#000;color:#fff;max-width:640px}#divTwcNav>div{padding-left:6px;padding-right:6px}#divTwcNavLeft{flex:1;text-align:left}#divTwcNavMiddle{flex:0;text-align:center}#divTwcNavRight{flex:1;text-align:right}#imgPause1x{visibility:hidden;position:absolute}.HideCursor{cursor:none !important}#txtScrollText{width:475px}@font-face{font-family:"Star4000 Extended";src:url("../fonts/Star4000 Extended.woff") format("woff");font-display:swap}@font-face{font-family:"Star4000 Large";src:url("../fonts/Star4000 Large.woff") format("woff");font-display:swap}@font-face{font-family:"Star4000 Small";src:url("../fonts/Star4000 Small.woff") format("woff");font-display:swap}#display{font-family:"Star4000";margin:0 0 0 0;width:100%}#container{position:relative;width:640px;height:480px;background-image:url(../images/backgrounds/1.png);transform-origin:0 0}.wide #container{padding-left:107px;padding-right:107px;background-repeat:no-repeat;background:url(../images/backgrounds/1-wide.png)}#divTwc:-webkit-full-screen #container{width:unset;height:unset;transform-origin:unset}#divTwc:fullscreen #container,.kiosk #divTwc #container{width:unset;height:unset;transform-origin:unset}#loading{width:640px;height:480px;max-width:100%;text-shadow:4px 4px #000;display:flex;align-items:center;text-align:center;justify-content:center}#loading .title{font-family:Star4000 Large;font-size:36px;color:#ff0;margin-bottom:0px}#loading .version{margin-bottom:35px}#loading .instructions{font-size:18pt}.heading{font-weight:bold;margin-top:15px}#settings{margin-bottom:15px}#enabledDisplays,#settings{margin-bottom:15px}#enabledDisplays .loading,#enabledDisplays .retrying,#settings .loading,#settings .retrying{color:#ff0}#enabledDisplays .press-here,#settings .press-here{color:lime;cursor:pointer}#enabledDisplays .failed,#settings .failed{color:red}#enabledDisplays .no-data,#settings .no-data{color:silver}#enabledDisplays .disabled,#settings .disabled{color:silver}#enabledDisplays .press-here,#settings .press-here{color:#fff}@media(prefers-color-scheme: light){#enabledDisplays .loading,#enabledDisplays .retrying,#settings .loading,#settings .retrying{color:#990}#enabledDisplays .press-here,#settings .press-here{color:#000;cursor:pointer}#enabledDisplays .failed,#settings .failed{color:#900}#enabledDisplays .no-data,#settings .no-data{color:#4d4d4d}#enabledDisplays .disabled,#settings .disabled{color:#4d4d4d}}#enabledDisplays label,#settings label{display:block;max-width:300px}#enabledDisplays label .alert,#settings label .alert{display:none}#enabledDisplays label .alert.show,#settings label .alert.show{display:inline;color:red}#divTwcBottom img{transform:scale(0.75)}#divTwc:-webkit-full-screen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:fullscreen,.kiosk #divTwc{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:-webkit-full-screen.no-cursor{cursor:none}#divTwc:fullscreen.no-cursor,.kiosk #divTwc.no-cursor{cursor:none}#divTwc:-webkit-full-screen #display{position:relative}#divTwc:fullscreen #display,.kiosk #divTwc #display{position:relative}#divTwc:-webkit-full-screen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}#divTwc:fullscreen #divTwcBottom,.kiosk #divTwc #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}.kiosk #divTwc #divTwcBottom>div{display:none}.navButton{cursor:pointer}#ToggleScanlines{display:inline-block}#ToggleScanlines .on{display:none}#ToggleScanlines .off{display:inline-block}#ToggleScanlines.on .on{display:inline-block}#ToggleScanlines.on .off{display:none}.visible{visibility:visible;opacity:1;transition:opacity .1s linear}#divTwc:-webkit-full-screen .hidden{visibility:hidden;opacity:0;-webkit-transition:visibility 0s 1s,opacity 1s linear;transition:visibility 0s 1s,opacity 1s linear}#divTwc:fullscreen .hidden{visibility:hidden;opacity:0;transition:visibility 0s 1s,opacity 1s linear}.github-links{width:610px;max-width:calc(100vw - 30px);display:flex;justify-content:space-evenly;flex-wrap:wrap}.github-links span a{text-decoration:none;outline:0}.github-links span .widget{display:inline-block;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;font-size:0;line-height:0;white-space:nowrap}.github-links span .btn,.github-links span .social-count{position:relative;display:inline-block;display:inline-flex;height:14px;padding:2px 5px;font-size:11px;font-weight:600;line-height:14px;vertical-align:bottom;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-repeat:repeat-x;background-position:-1px -1px;background-size:110% 110%;border:1px solid}.github-links span .btn{border-radius:.25em}.github-links span .btn:not(:last-child){border-radius:.25em 0 0 .25em}.github-links span .social-count{border-left:0;border-radius:0 .25em .25em 0}.github-links span .widget-lg .btn,.github-links span .widget-lg .social-count{height:16px;padding:5px 10px;font-size:12px;line-height:16px}.github-links span .octicon{display:inline-block;vertical-align:text-top;fill:currentColor;overflow:visible}.github-links span .btn:focus-visible,.github-links span .social-count:focus-visible{outline:2px solid #0969da;outline-offset:-2px}.github-links span .btn{color:#24292f;background-color:#ebf0f4;border-color:#ccd1d5;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f6f8fa'/%3e%3cstop offset='90%25' stop-color='%23ebf0f4'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f6f8fa, #ebf0f4 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF6F8FA", endColorstr="#FFEAEFF3")}.github-links span :root .btn{filter:none}.github-links span .btn:hover,.github-links span .btn:focus{background-color:#e9ebef;background-position:0 -0.5em;border-color:#caccd1;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f3f4f6'/%3e%3cstop offset='90%25' stop-color='%23e9ebef'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f3f4f6, #e9ebef 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF3F4F6", endColorstr="#FFE8EAEE")}.github-links span :root .btn:hover,.github-links span :root .btn:focus{filter:none}.github-links span .btn:active{background-color:#e5e9ed;border-color:#c7cbcf;border-color:rgba(27,31,36,.15);box-shadow:inset 0 .15em .3em rgba(27,31,36,.15);background-image:none;filter:none}.github-links span .social-count{color:#24292f;background-color:#fff;border-color:#ddddde;border-color:rgba(27,31,36,.15)}.github-links span .social-count:hover,.github-links span .social-count:focus{color:#0969da}.github-links span .octicon-heart{color:#bf3989}@media(prefers-color-scheme: light){.github-links span .btn:focus-visible,.github-links span .social-count:focus-visible{outline:2px solid #0969da;outline-offset:-2px}.github-links span .btn{color:#24292f;background-color:#ebf0f4;border-color:#ccd1d5;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f6f8fa'/%3e%3cstop offset='90%25' stop-color='%23ebf0f4'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f6f8fa, #ebf0f4 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF6F8FA", endColorstr="#FFEAEFF3")}.github-links span :root .btn{filter:none}.github-links span .btn:hover,.github-links span .btn:focus{background-color:#e9ebef;background-position:0 -0.5em;border-color:#caccd1;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f3f4f6'/%3e%3cstop offset='90%25' stop-color='%23e9ebef'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f3f4f6, #e9ebef 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF3F4F6", endColorstr="#FFE8EAEE")}.github-links span :root .btn:hover,.github-links span :root .btn:focus{filter:none}.github-links span .btn:active{background-color:#e5e9ed;border-color:#c7cbcf;border-color:rgba(27,31,36,.15);box-shadow:inset 0 .15em .3em rgba(27,31,36,.15);background-image:none;filter:none}.github-links span .social-count{color:#24292f;background-color:#fff;border-color:#ddddde;border-color:rgba(27,31,36,.15)}.github-links span .social-count:hover,.github-links span .social-count:focus{color:#0969da}.github-links span .octicon-heart{color:#bf3989}}@media(prefers-color-scheme: dark){.github-links span .btn:focus-visible,.github-links span .social-count:focus-visible{outline:2px solid #58a6ff;outline-offset:-2px}.github-links span .btn{color:#c9d1d9;background-color:#1a1e23;border-color:#2f3439;border-color:rgba(240,246,252,.1);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%2321262d'/%3e%3cstop offset='90%25' stop-color='%231a1e23'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #21262d, #1a1e23 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FF21262D", endColorstr="#FF191D22")}.github-links span :root .btn{filter:none}.github-links span .btn:hover,.github-links span .btn:focus{background-color:#292e33;background-position:0 -0.5em;border-color:#8b949e;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%2330363d'/%3e%3cstop offset='90%25' stop-color='%23292e33'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #30363d, #292e33 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FF30363D", endColorstr="#FF282D32")}.github-links span :root .btn:hover,.github-links span :root .btn:focus{filter:none}.github-links span .btn:active{background-color:#161719;border-color:#8b949e;box-shadow:inset 0 .15em .3em rgba(1,4,9,.15);background-image:none;filter:none}.github-links span .social-count{color:#c9d1d9;background-color:#0d1117;border-color:#24282e;border-color:rgba(240,246,252,.1)}.github-links span .social-count:hover,.github-links span .social-count:focus{color:#58a6ff}.github-links span .octicon-heart{color:#db61a2}}#share-link-copied{color:#990;display:none}#share-link-instructions{display:none}.kiosk #divQuery,.kiosk>.info,.kiosk>.related-links,.kiosk>.heading,.kiosk #enabledDisplays,.kiosk #settings,.kiosk #divInfo{display:none}.weather-display{width:640px;height:480px;overflow:hidden;position:relative;background-image:url(../images/backgrounds/1.png);height:0px}.weather-display.show{height:480px}.weather-display .template{display:none}.weather-display .header{width:640px;height:60px;padding-top:30px}.weather-display .header .title{color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000";font-size:24pt;position:absolute;width:250px}.weather-display .header .title.single{left:170px;top:25px}.weather-display .header .title.dual{left:170px}.weather-display .header .title.dual>div{position:absolute}.weather-display .header .title.dual .top{top:-3px}.weather-display .header .title.dual .bottom{top:26px}.weather-display .header .logo{top:30px;left:50px;position:absolute;z-index:10}.weather-display .header .noaa-logo{position:absolute;top:39px;left:356px}.weather-display .header .title.single{top:40px}.weather-display .header .date-time{white-space:pre;color:#fff;font-family:"Star4000 Small";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;left:415px;width:170px;text-align:right;position:absolute}.weather-display .header .date-time.date{padding-top:22px}.weather-display .main{position:relative}.weather-display .main.has-scroll{width:640px;height:310px;overflow:hidden}.weather-display .main.has-scroll.no-header{height:400px}.weather-display .main.has-box{margin-left:64px;margin-right:64px;width:calc(100% - 128px)}.weather-display .scroll{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;width:640px;height:70px;overflow:hidden;margin-top:3px}.weather-display .scroll.hazard{background-color:#702323}.weather-display .scroll .fixed,.weather-display .scroll .scroll-header{margin-left:55px;margin-right:55px;overflow:hidden}.weather-display .scroll .scroll-header{height:26px;font-family:"Star4000 Small";font-size:20pt;margin-top:-10px}.weather-display .scroll .fixed{font-family:"Star4000";font-size:24pt}.weather-display .scroll .fixed .scroll-area{text-wrap:nowrap;position:relative}.weather-display .main.current-weather.main .col{height:50px;width:255px;display:inline-block;margin-top:10px;padding-top:10px;position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.current-weather.main .col.left{font-family:"Star4000 Extended";font-size:24pt}.weather-display .main.current-weather.main .col.right{right:0px;font-family:"Star4000 Large";font-size:20px;font-weight:bold;line-height:24px}.weather-display .main.current-weather.main .col.right .row{margin-bottom:12px}.weather-display .main.current-weather.main .col.right .row .label,.weather-display .main.current-weather.main .col.right .row .value{display:inline-block}.weather-display .main.current-weather.main .col.right .row .label{margin-left:20px}.weather-display .main.current-weather.main .col.right .row .value{float:right;margin-right:10px}.weather-display .main.current-weather.main .center{text-align:center}.weather-display .main.current-weather.main .temp{font-family:"Star4000 Large";font-size:24pt}.weather-display .main.current-weather.main .icon{height:100px}.weather-display .main.current-weather.main .icon img{max-width:126px}.weather-display .main.current-weather.main .wind-container{margin-bottom:10px}.weather-display .main.current-weather.main .wind-container>div{width:45%;display:inline-block;margin:0px}.weather-display .main.current-weather.main .wind-container .wind-label{margin-left:5px}.weather-display .main.current-weather.main .wind-container .wind{text-align:right}.weather-display .main.current-weather.main .wind-gusts{margin-left:5px}.weather-display .main.current-weather.main .location{color:#ff0;max-height:32px;margin-bottom:10px;padding-top:4px;overflow:hidden;text-wrap:nowrap}#extended-forecast-html.weather-display{background-image:url("../images/backgrounds/2.png")}.weather-display .main.extended-forecast .day-container{margin-top:16px;margin-left:27px}.weather-display .main.extended-forecast .day{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;padding:5px;height:285px;width:155px;display:inline-block;margin:0px 15px;font-family:"Star4000";font-size:24pt}.weather-display .main.extended-forecast .day .date{text-transform:uppercase;text-align:center;color:#ff0}.weather-display .main.extended-forecast .day .condition{text-align:center;height:74px;margin-top:5px}.weather-display .main.extended-forecast .day .icon{text-align:center;height:75px}.weather-display .main.extended-forecast .day .icon img{max-height:75px}.weather-display .main.extended-forecast .day .temperatures{width:100%}.weather-display .main.extended-forecast .day .temperatures .temperature-block{display:inline-block;width:44%;vertical-align:top}.weather-display .main.extended-forecast .day .temperatures .temperature-block>div{text-align:center}.weather-display .main.extended-forecast .day .temperatures .temperature-block .value{font-family:"Star4000 Large";margin-top:4px}.weather-display .main.extended-forecast .day .temperatures .temperature-block.lo .label{color:#8080ff}.weather-display .main.extended-forecast .day .temperatures .temperature-block.hi .label{color:#ff0}.weather-display .main.hourly.main{overflow-y:hidden}.weather-display .main.hourly.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly.main .column-headers{position:sticky;top:0px;z-index:5}.weather-display .main.hourly.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.hourly.main .column-headers .temp{left:355px}.weather-display .main.hourly.main .column-headers .like{left:435px}.weather-display .main.hourly.main .column-headers .wind{left:535px}.weather-display .main.hourly.main .hourly-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.hourly.main .hourly-lines .hourly-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.hourly.main .hourly-lines .hourly-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.hourly.main .hourly-lines .hourly-row .hour{left:25px}.weather-display .main.hourly.main .hourly-lines .hourly-row .icon{left:255px;width:70px;text-align:center;top:unset}.weather-display .main.hourly.main .hourly-lines .hourly-row .temp{left:355px}.weather-display .main.hourly.main .hourly-lines .hourly-row .like{left:425px}.weather-display .main.hourly.main .hourly-lines .hourly-row .like.heat-index{color:#e00}.weather-display .main.hourly.main .hourly-lines .hourly-row .like.wind-chill{color:#8080ff}.weather-display .main.hourly.main .hourly-lines .hourly-row .wind{left:505px;width:100px;text-align:right}#hourly-graph-html{background-image:url(../images/backgrounds/1-chart.png)}#hourly-graph-html .header .right{position:absolute;top:35px;right:60px;width:360px;font-family:"Star4000 Small";font-size:32px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:right}#hourly-graph-html .header .right div{margin-top:-18px}#hourly-graph-html .header .right .temperature{color:red}#hourly-graph-html .header .right .cloud{color:#d3d3d3}#hourly-graph-html .header .right .rain{color:aqua}.weather-display .main.hourly-graph.main>div{position:absolute}.weather-display .main.hourly-graph.main .label{font-family:"Star4000 Small";font-size:24pt;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;margin-top:-15px;position:absolute}.weather-display .main.hourly-graph.main .x-axis{bottom:0px;left:0px;width:640px;height:20px}.weather-display .main.hourly-graph.main .x-axis .label{text-align:center;width:50px}.weather-display .main.hourly-graph.main .x-axis .label.l-1{left:25px}.weather-display .main.hourly-graph.main .x-axis .label.l-2{left:158px}.weather-display .main.hourly-graph.main .x-axis .label.l-3{left:291px}.weather-display .main.hourly-graph.main .x-axis .label.l-4{left:424px}.weather-display .main.hourly-graph.main .x-axis .label.l-5{left:557px}.weather-display .main.hourly-graph.main .chart{top:0px;left:50px}.weather-display .main.hourly-graph.main .chart img{width:532px;height:285px}.weather-display .main.hourly-graph.main .y-axis{top:0px;left:0px;width:50px;height:285px}.weather-display .main.hourly-graph.main .y-axis .label{text-align:right;right:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-1{top:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-2{top:140px}.weather-display .main.hourly-graph.main .y-axis .label.l-3{bottom:0px}.weather-display .main.hourly-graph.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly-graph.main .column-headers{position:sticky;top:0px;z-index:5}.weather-display .main.hourly-graph.main .column-headers .temp{left:355px}.weather-display .main.hourly-graph.main .column-headers .like{left:435px}.weather-display .main.hourly-graph.main .column-headers .wind{left:535px}.weather-display .main.travel.main{overflow-y:hidden}.weather-display .main.travel.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.travel.main .column-headers{position:sticky;top:0px;z-index:5}.weather-display .main.travel.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.travel.main .column-headers .temp{width:50px;text-align:center}.weather-display .main.travel.main .column-headers .temp.low{left:455px}.weather-display .main.travel.main .column-headers .temp.high{left:510px;width:60px}.weather-display .main.travel.main .travel-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.travel.main .travel-lines .travel-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.travel.main .travel-lines .travel-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.travel.main .travel-lines .travel-row .city{left:80px}.weather-display .main.travel.main .travel-lines .travel-row .icon{left:330px;width:70px;text-align:center;top:unset}.weather-display .main.travel.main .travel-lines .travel-row .icon img{max-width:47px}.weather-display .main.travel.main .travel-lines .travel-row .temp{width:50px;text-align:center}.weather-display .main.travel.main .travel-lines .travel-row .temp.low{left:455px}.weather-display .main.travel.main .travel-lines .travel-row .temp.high{left:510px;width:60px}.weather-display .latest-observations.main{overflow-y:hidden}.weather-display .latest-observations.main .column-headers{height:20px;position:absolute;width:100%}.weather-display .latest-observations.main .column-headers{top:0px}.weather-display .latest-observations.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;position:absolute;top:-14px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .latest-observations.main .column-headers .temp{display:none}.weather-display .latest-observations.main .column-headers .temp.show{display:inline-block}.weather-display .latest-observations.main .temp{left:230px}.weather-display .latest-observations.main .weather{left:280px}.weather-display .latest-observations.main .wind{left:430px}.weather-display .latest-observations.main .observation-lines{min-height:338px;padding-top:10px}.weather-display .latest-observations.main .observation-lines .observation-row{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative;height:40px}.weather-display .latest-observations.main .observation-lines .observation-row>div{position:absolute;top:8px}.weather-display .latest-observations.main .observation-lines .observation-row .wind{white-space:pre;text-align:right}.weather-display .local-forecast .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:280px;overflow:hidden}.weather-display .local-forecast .forecasts{position:relative}.weather-display .local-forecast .forecast{font-family:"Star4000";font-size:24pt;text-transform:uppercase;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;min-height:280px;line-height:40px}.weather-display .progress{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000 Extended";font-size:19pt}.weather-display .progress .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:310px;overflow:hidden}.weather-display .progress .container .item{position:relative}.weather-display .progress .container .item .name{white-space:nowrap}.weather-display .progress .container .item .name::after{content:"........................................................................"}.weather-display .progress .container .item .links{position:absolute;text-align:right;right:0px;top:0px}.weather-display .progress .container .item .links>div{background-color:#26235a;display:none;padding-left:4px}.weather-display .progress .container .item .links .loading,.weather-display .progress .container .item .links .retrying{color:#ff0}.weather-display .progress .container .item .links .press-here{color:lime;cursor:pointer}.weather-display .progress .container .item .links .failed{color:red}.weather-display .progress .container .item .links .no-data{color:silver}.weather-display .progress .container .item .links .disabled{color:silver}.weather-display .progress .container .item .links.loading .loading,.weather-display .progress .container .item .links.press-here .press-here,.weather-display .progress .container .item .links.failed .failed,.weather-display .progress .container .item .links.no-data .no-data,.weather-display .progress .container .item .links.disabled .disabled,.weather-display .progress .container .item .links.retrying .retrying{display:block}@keyframes progress-scroll{0%{background-position:-40px 0}100%{background-position:40px 0}}#progress-html.weather-display .scroll .progress-bar-container{border:2px solid #000;background-color:#fff;margin:20px auto;width:524px;position:relative;display:none}#progress-html.weather-display .scroll .progress-bar-container.show{display:block}#progress-html.weather-display .scroll .progress-bar-container .progress-bar{height:20px;margin:2px;width:520px;background:repeating-linear-gradient(90deg, #09246f 0px, #09246f 5px, #364ac0 5px, #364ac0 10px, #4f99f9 10px, #4f99f9 15px, #8ffdfa 15px, #8ffdfa 20px, #4f99f9 20px, #4f99f9 25px, #364ac0 25px, #364ac0 30px, #09246f 30px, #09246f 40px);animation-duration:2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:progress-scroll;animation-timing-function:steps(8, end)}#progress-html.weather-display .scroll .progress-bar-container .cover{position:absolute;top:0px;right:0px;background-color:#fff;width:100%;height:24px;transition:width 1s steps(6)}#radar-html.weather-display{background-image:url("../images/backgrounds/4.png")}#radar-html.weather-display .header{height:83px}#radar-html.weather-display .header .title.dual{color:#fff;font-family:"Arial",sans-serif;font-weight:bold;font-size:28pt;left:155px}#radar-html.weather-display .header .title.dual .top{top:-4px}#radar-html.weather-display .header .title.dual .bottom{top:31px}#radar-html.weather-display .header .right{position:absolute;right:0px;width:360px;margin-top:2px;font-family:"Star4000";font-size:18pt;font-weight:bold;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:center}#radar-html.weather-display .header .right .scale>div{display:inline-block}#radar-html.weather-display .header .right .scale-table{display:table-row;border-collapse:collapse}#radar-html.weather-display .header .right .scale-table .box{display:table-cell;border:2px solid #000;width:17px;height:24px;padding:0}#radar-html.weather-display .header .right .scale-table .box-1{background-color:#31d216}#radar-html.weather-display .header .right .scale-table .box-2{background-color:#1c8a12}#radar-html.weather-display .header .right .scale-table .box-3{background-color:#145a0f}#radar-html.weather-display .header .right .scale-table .box-4{background-color:#0a280a}#radar-html.weather-display .header .right .scale-table .box-5{background-color:#c4b346}#radar-html.weather-display .header .right .scale-table .box-6{background-color:#be4813}#radar-html.weather-display .header .right .scale-table .box-7{background-color:#ab0e0e}#radar-html.weather-display .header .right .scale-table .box-8{background-color:#731f04}#radar-html.weather-display .header .right .scale .text{position:relative;top:-5px}#radar-html.weather-display .header .right .time{position:relative;font-weight:normal;top:-14px;font-family:"Star4000 Small";font-size:24pt}.weather-display .main.radar{overflow:hidden;height:367px}.weather-display .main.radar .container .tiles{position:absolute;width:1400px}.weather-display .main.radar .container .tiles img{vertical-align:middle}.weather-display .main.radar .container .scroll-area{position:relative}.wide.radar #container{background:url(../images/backgrounds/4-wide.png)}#regional-forecast-html.weather-display{background-image:url("../images/backgrounds/5.png")}.weather-display .main.regional-forecast{position:relative}.weather-display .main.regional-forecast .map{position:absolute;transform-origin:0 0}.weather-display .main.regional-forecast .location{position:absolute;width:140px;margin-left:-40px;margin-top:-35px}.weather-display .main.regional-forecast .location>div{position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.regional-forecast .location .icon{top:26px;left:44px}.weather-display .main.regional-forecast .location .icon img{max-height:32px}.weather-display .main.regional-forecast .location .temp{font-family:"Star4000 Large";font-size:28px;padding-top:2px;color:#ff0;top:28px;text-align:right;width:40px}.weather-display .main.regional-forecast .location .city{font-family:Star4000;font-size:20px}#almanac-html.weather-display{background-image:url("../images/backgrounds/3.png")}.weather-display .main.almanac{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.almanac .sun{display:table;margin-left:50px;height:100px}.weather-display .main.almanac .sun>div{display:table-row;position:relative}.weather-display .main.almanac .sun>div>div{display:table-cell}.weather-display .main.almanac .sun .days{color:#ff0;text-align:right;top:-5px}.weather-display .main.almanac .sun .days .day{padding-right:10px}.weather-display .main.almanac .sun .times{text-align:right}.weather-display .main.almanac .sun .times .sun-time{width:200px}.weather-display .main.almanac .sun .times.times-1{top:-10px}.weather-display .main.almanac .sun .times.times-2{top:-15px}.weather-display .main.almanac .moon{position:relative;top:-10px;padding:0px 60px}.weather-display .main.almanac .moon .title{color:#ff0}.weather-display .main.almanac .moon .day{display:inline-block;text-align:center;width:130px}.weather-display .main.almanac .moon .day .icon{padding-left:10px}.weather-display .main.almanac .moon .day .date{position:relative;top:-10px}.weather-display .main.hazards.main{overflow-y:hidden;height:480px}.weather-display .main.hazards.main .hazard-lines{min-height:400px;padding-top:10px;background-color:#702323}.weather-display .main.hazards.main .hazard-lines .hazard{font-family:"Star4000";font-size:24pt;color:#fff;text-shadow:0px 0px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative;text-transform:uppercase;margin-top:10px;margin-left:80px;margin-right:80px;padding-bottom:10px}.media{display:none}#ToggleMedia{display:none}#ToggleMedia.available{display:inline-block}#ToggleMedia.available img.on{display:none}#ToggleMedia.available img.off{display:block}#ToggleMedia.available.playing img.on{display:block}#ToggleMedia.available.playing img.off{display:none}#spc-outlook-html.weather-display{background-image:url("../images/backgrounds/6.png")}.weather-display .spc-outlook .container{position:relative;top:0px;margin:0px 10px;box-sizing:border-box;height:300px;overflow:hidden}.weather-display .spc-outlook .risk-levels{position:absolute;left:206px;font-family:"Star4000 Small";font-size:32px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .spc-outlook .risk-levels .risk-level{position:relative;top:-14px;height:20px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(1){left:100px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(2){left:80px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(3){left:60px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(4){left:40px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(5){left:20px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(6){left:0px}.weather-display .spc-outlook .days{position:absolute;top:120px}.weather-display .spc-outlook .days .day{height:60px}.weather-display .spc-outlook .days .day .day-name{position:absolute;font-family:"Star4000";font-size:24pt;width:200px;text-align:right;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;padding-top:20px}.weather-display .spc-outlook .days .day .risk-bar{position:absolute;width:150px;height:40px;left:210px;margin-top:20px;border:3px outset #b3b3b3;background:linear-gradient(0deg, hsl(0, 0%, 40%) 0%, hsl(0, 0%, 60%) 50%, hsl(0, 0%, 40%) 100%)}.scanlines{position:relative;overflow:hidden}.scanlines:before,.scanlines:after{display:block;pointer-events:none;content:"";position:absolute}.scanlines:before{width:100%;height:1px;z-index:2147483649;background:rgba(0,0,0,.3);opacity:.75;animation:scanline 6s linear infinite}.scanlines:after{top:0;right:0;bottom:0;left:0;z-index:2147483648;background:linear-gradient(to bottom, transparent 50%, rgba(0, 0, 0, 0.3) 51%);background-size:100% 2px;animation:none}@keyframes scanline{0%{transform:translate3d(0, 200000%, 0)}}@keyframes scanlines{0%{background-position:0 50%}}/*# sourceMappingURL=main.css.map */ \ No newline at end of file +@font-face{font-family:"Star4000";src:url("../fonts/Star4000.woff") format("woff");font-display:swap}body{font-family:"Star4000";margin:0}@media(prefers-color-scheme: dark){body{background-color:#000;color:#fff}}@media(prefers-color-scheme: dark){body a{color:#add8e6}}body.kiosk{margin:0px;padding:0px;overflow:hidden;width:100vw;background-color:#000 !important}#divQuery{max-width:640px;padding:8px}#divQuery .buttons{display:inline-block;width:150px;text-align:right}#divQuery .buttons #imgGetGps{height:13px;vertical-align:middle}#divQuery .buttons button{font-size:16pt;border:1px solid #a9a9a9}@media(prefers-color-scheme: dark){#divQuery .buttons button{background-color:#000;color:#fff}}#divQuery .buttons #btnGetGps img.dark{display:none}@media(prefers-color-scheme: dark){#divQuery .buttons #btnGetGps img.dark{display:inline-block}}@media(prefers-color-scheme: dark){#divQuery .buttons #btnGetGps img.light{display:none}}#divQuery .buttons #btnGetGps.active{background-color:#000}@media(prefers-color-scheme: dark){#divQuery .buttons #btnGetGps.active{background-color:#fff}}#divQuery .buttons #btnGetGps.active img{filter:invert(1)}#divQuery input,#divQuery button{font-family:"Star4000"}#divQuery #txtLocation{width:calc(100% - 170px);max-width:490px;font-size:16pt;min-width:200px;display:inline-block;background-color:#fff;color:#000;border:2px inset gray}@media(prefers-color-scheme: dark){#divQuery #txtLocation{background-color:#000;color:#fff;border:2px inset gray}}.autocomplete-suggestions{background-color:#fff;border:1px solid #000;position:absolute;z-index:9999}@media(prefers-color-scheme: dark){.autocomplete-suggestions{background-color:#000}}.autocomplete-suggestions div{white-space:nowrap;overflow:hidden;text-overflow:ellipsis;font-size:16pt}.autocomplete-suggestions div.selected{background-color:blue;color:#fff}#divTwc{display:block;background-color:#000;color:#fff;width:100%;max-width:640px;margin:0}#divTwc.wide{max-width:854px}.content-wrapper{padding:8px}#divTwcMain{width:640px;height:480px}.wide #divTwcMain{width:854px}.kiosk #divTwc{max-width:unset}#divTwcLeft{display:none;text-align:right;flex-direction:column;vertical-align:middle}#divTwcLeft>div{flex:1;padding-right:12px;display:flex;flex-direction:column;justify-content:center}#divTwcRight{text-align:left;display:none;flex-direction:column;vertical-align:middle}#divTwcRight>div{flex:1;padding-left:12px;display:flex;flex-direction:column;justify-content:center}#divTwcBottom{display:flex;flex-direction:row;background-color:#000;color:#fff;width:640px}.wide #divTwcBottom{width:854px}@media(prefers-color-scheme: dark){#divTwcBottom{background-color:#303030}}#divTwcBottom>div{padding-left:6px;padding-right:6px}@media(max-width: 550px){#divTwcBottom>div{font-size:.9em}}@media(max-width: 500px){#divTwcBottom>div{font-size:.8em}}@media(max-width: 450px){#divTwcBottom>div{font-size:.7em}}@media(max-width: 400px){#divTwcBottom>div{font-size:.6em}}@media(max-width: 350px){#divTwcBottom>div{font-size:.5em}}#divTwcBottomLeft{flex:1;text-align:left}#divTwcBottomMiddle{flex:0;text-align:center}#divTwcBottomRight{flex:1;text-align:right}#divTwcNavContainer{display:none}#divTwcNav{width:100%;display:flex;flex-direction:row;background-color:#000;color:#fff;max-width:640px}#divTwcNav>div{padding-left:6px;padding-right:6px}#divTwcNavLeft{flex:1;text-align:left}#divTwcNavMiddle{flex:0;text-align:center}#divTwcNavRight{flex:1;text-align:right}#imgPause1x{visibility:hidden;position:absolute}.HideCursor{cursor:none !important}#txtScrollText{width:475px}@font-face{font-family:"Star4000 Extended";src:url("../fonts/Star4000 Extended.woff") format("woff");font-display:swap}@font-face{font-family:"Star4000 Large";src:url("../fonts/Star4000 Large.woff") format("woff");font-display:swap}@font-face{font-family:"Star4000 Small";src:url("../fonts/Star4000 Small.woff") format("woff");font-display:swap}#display{font-family:"Star4000";margin:0 0 0 0;width:100%}#container{position:relative;width:640px;height:480px;background-image:url(../images/backgrounds/1.png);transform-origin:0 0}.wide #container{padding-left:107px;padding-right:107px;background-repeat:no-repeat;background:url(../images/backgrounds/1-wide.png)}#divTwc:-webkit-full-screen #container{width:unset;height:unset}#divTwc:fullscreen #container,.kiosk #divTwc #container{width:unset;height:unset}#loading{width:640px;height:480px;max-width:100%;text-shadow:4px 4px #000;display:flex;align-items:center;text-align:center;justify-content:center}#loading .title{font-family:Star4000 Large;font-size:36px;color:#ff0;margin-bottom:0px}#loading .version{margin-bottom:35px}#loading .instructions{font-size:18pt}.heading{font-weight:bold;margin-top:15px}#settings{margin-bottom:15px}#enabledDisplays,#settings{margin-bottom:15px}#enabledDisplays .loading,#enabledDisplays .retrying,#settings .loading,#settings .retrying{color:#ff0}#enabledDisplays .press-here,#settings .press-here{color:lime;cursor:pointer}#enabledDisplays .failed,#settings .failed{color:red}#enabledDisplays .no-data,#settings .no-data{color:silver}#enabledDisplays .disabled,#settings .disabled{color:silver}#enabledDisplays .press-here,#settings .press-here{color:#fff}@media(prefers-color-scheme: light){#enabledDisplays .loading,#enabledDisplays .retrying,#settings .loading,#settings .retrying{color:#990}#enabledDisplays .press-here,#settings .press-here{color:#000;cursor:pointer}#enabledDisplays .failed,#settings .failed{color:#900}#enabledDisplays .no-data,#settings .no-data{color:#4d4d4d}#enabledDisplays .disabled,#settings .disabled{color:#4d4d4d}}#enabledDisplays label,#settings label{display:block;max-width:-moz-fit-content;max-width:fit-content;cursor:pointer}#enabledDisplays label .alert,#settings label .alert{display:none}#enabledDisplays label .alert.show,#settings label .alert.show{display:inline;color:red}#divTwcBottom img{transform:scale(0.75)}@media(max-width: 550px){.wide #divTwcBottom img{transform:scale(1)}}#divTwc:-webkit-full-screen{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:fullscreen,.kiosk #divTwc{display:flex;align-items:center;justify-content:center;align-content:center}#divTwc:-webkit-full-screen.no-cursor{cursor:none}#divTwc:fullscreen.no-cursor,.kiosk #divTwc.no-cursor{cursor:none}#divTwc:-webkit-full-screen #display{position:relative}#divTwc:fullscreen #display,.kiosk #divTwc #display{position:relative}#divTwc:-webkit-full-screen #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}#divTwc:fullscreen #divTwcBottom,.kiosk #divTwc #divTwcBottom{display:flex;flex-direction:row;background-color:rgba(0,0,0,.5);color:#fff;width:100%;position:absolute;bottom:0px}.kiosk #divTwc #divTwcBottom{display:none}.navButton{cursor:pointer}#ToggleScanlines{display:inline-block}#ToggleScanlines .on{display:none}#ToggleScanlines .off{display:inline-block}#ToggleScanlines.on .on{display:inline-block}#ToggleScanlines.on .off{display:none}.visible{visibility:visible;opacity:1;transition:opacity .1s linear}#divTwc:-webkit-full-screen .hidden{visibility:hidden;opacity:0;-webkit-transition:visibility 0s 1s,opacity 1s linear;transition:visibility 0s 1s,opacity 1s linear}#divTwc:fullscreen .hidden{visibility:hidden;opacity:0;transition:visibility 0s 1s,opacity 1s linear}.github-links{width:610px;max-width:calc(100vw - 30px);display:flex;justify-content:space-evenly;flex-wrap:wrap}.github-links span a{text-decoration:none;outline:0}.github-links span .widget{display:inline-block;overflow:hidden;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif;font-size:0;line-height:0;white-space:nowrap}.github-links span .btn,.github-links span .social-count{position:relative;display:inline-block;display:inline-flex;height:14px;padding:2px 5px;font-size:11px;font-weight:600;line-height:14px;vertical-align:bottom;cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none;background-repeat:repeat-x;background-position:-1px -1px;background-size:110% 110%;border:1px solid}.github-links span .btn{border-radius:.25em}.github-links span .btn:not(:last-child){border-radius:.25em 0 0 .25em}.github-links span .social-count{border-left:0;border-radius:0 .25em .25em 0}.github-links span .widget-lg .btn,.github-links span .widget-lg .social-count{height:16px;padding:5px 10px;font-size:12px;line-height:16px}.github-links span .octicon{display:inline-block;vertical-align:text-top;fill:currentColor;overflow:visible}.github-links span .btn:focus-visible,.github-links span .social-count:focus-visible{outline:2px solid #0969da;outline-offset:-2px}.github-links span .btn{color:#24292f;background-color:#ebf0f4;border-color:#ccd1d5;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f6f8fa'/%3e%3cstop offset='90%25' stop-color='%23ebf0f4'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f6f8fa, #ebf0f4 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF6F8FA", endColorstr="#FFEAEFF3")}.github-links span :root .btn{filter:none}.github-links span .btn:hover,.github-links span .btn:focus{background-color:#e9ebef;background-position:0 -0.5em;border-color:#caccd1;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f3f4f6'/%3e%3cstop offset='90%25' stop-color='%23e9ebef'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f3f4f6, #e9ebef 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF3F4F6", endColorstr="#FFE8EAEE")}.github-links span :root .btn:hover,.github-links span :root .btn:focus{filter:none}.github-links span .btn:active{background-color:#e5e9ed;border-color:#c7cbcf;border-color:rgba(27,31,36,.15);box-shadow:inset 0 .15em .3em rgba(27,31,36,.15);background-image:none;filter:none}.github-links span .social-count{color:#24292f;background-color:#fff;border-color:#ddddde;border-color:rgba(27,31,36,.15)}.github-links span .social-count:hover,.github-links span .social-count:focus{color:#0969da}.github-links span .octicon-heart{color:#bf3989}@media(prefers-color-scheme: light){.github-links span .btn:focus-visible,.github-links span .social-count:focus-visible{outline:2px solid #0969da;outline-offset:-2px}.github-links span .btn{color:#24292f;background-color:#ebf0f4;border-color:#ccd1d5;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f6f8fa'/%3e%3cstop offset='90%25' stop-color='%23ebf0f4'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f6f8fa, #ebf0f4 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF6F8FA", endColorstr="#FFEAEFF3")}.github-links span :root .btn{filter:none}.github-links span .btn:hover,.github-links span .btn:focus{background-color:#e9ebef;background-position:0 -0.5em;border-color:#caccd1;border-color:rgba(27,31,36,.15);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%23f3f4f6'/%3e%3cstop offset='90%25' stop-color='%23e9ebef'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #f3f4f6, #e9ebef 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FFF3F4F6", endColorstr="#FFE8EAEE")}.github-links span :root .btn:hover,.github-links span :root .btn:focus{filter:none}.github-links span .btn:active{background-color:#e5e9ed;border-color:#c7cbcf;border-color:rgba(27,31,36,.15);box-shadow:inset 0 .15em .3em rgba(27,31,36,.15);background-image:none;filter:none}.github-links span .social-count{color:#24292f;background-color:#fff;border-color:#ddddde;border-color:rgba(27,31,36,.15)}.github-links span .social-count:hover,.github-links span .social-count:focus{color:#0969da}.github-links span .octicon-heart{color:#bf3989}}@media(prefers-color-scheme: dark){.github-links span .btn:focus-visible,.github-links span .social-count:focus-visible{outline:2px solid #58a6ff;outline-offset:-2px}.github-links span .btn{color:#c9d1d9;background-color:#1a1e23;border-color:#2f3439;border-color:rgba(240,246,252,.1);background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%2321262d'/%3e%3cstop offset='90%25' stop-color='%231a1e23'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #21262d, #1a1e23 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FF21262D", endColorstr="#FF191D22")}.github-links span :root .btn{filter:none}.github-links span .btn:hover,.github-links span .btn:focus{background-color:#292e33;background-position:0 -0.5em;border-color:#8b949e;background-image:url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg'%3e%3clinearGradient id='o' x2='0' y2='1'%3e%3cstop stop-color='%2330363d'/%3e%3cstop offset='90%25' stop-color='%23292e33'/%3e%3c/linearGradient%3e%3crect width='100%25' height='100%25' fill='url(%23o)'/%3e%3c/svg%3e");background-image:linear-gradient(180deg, #30363d, #292e33 90%);filter:progid:DXImageTransform.Microsoft.Gradient(startColorstr="#FF30363D", endColorstr="#FF282D32")}.github-links span :root .btn:hover,.github-links span :root .btn:focus{filter:none}.github-links span .btn:active{background-color:#161719;border-color:#8b949e;box-shadow:inset 0 .15em .3em rgba(1,4,9,.15);background-image:none;filter:none}.github-links span .social-count{color:#c9d1d9;background-color:#0d1117;border-color:#24282e;border-color:rgba(240,246,252,.1)}.github-links span .social-count:hover,.github-links span .social-count:focus{color:#58a6ff}.github-links span .octicon-heart{color:#db61a2}}#share-link-copied{color:#990;display:none}#share-link-instructions{display:none}body.kiosk #loading .instructions{display:none !important}.kiosk>*:not(#divTwc){display:none !important}.weather-display{width:640px;height:480px;overflow:hidden;position:relative;background-image:url(../images/backgrounds/1.png);height:0px}.weather-display.show{height:480px}.weather-display .template{display:none}.weather-display .header{width:640px;height:60px;padding-top:30px}.weather-display .header .title{color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000";font-size:24pt;position:absolute;width:250px}.weather-display .header .title.single{left:170px;top:25px}.weather-display .header .title.dual{left:170px}.weather-display .header .title.dual>div{position:absolute}.weather-display .header .title.dual .top{top:-3px}.weather-display .header .title.dual .bottom{top:26px}.weather-display .header .logo{top:30px;left:50px;position:absolute;z-index:10}.weather-display .header .noaa-logo{position:absolute;top:39px;left:356px}.weather-display .header .title.single{top:40px}.weather-display .header .date-time{white-space:pre;color:#fff;font-family:"Star4000 Small";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;left:415px;width:170px;text-align:right;position:absolute}.weather-display .header .date-time.date{padding-top:22px}.weather-display .main{position:relative}.weather-display .main.has-scroll{width:640px;margin-top:0;height:310px;overflow:hidden}.weather-display .main.has-scroll.no-header{height:400px;margin-top:0}.weather-display .main.has-box{margin-left:64px;margin-right:64px;width:calc(100% - 128px)}.weather-display .scroll{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;width:640px;height:70px;overflow:hidden;margin-top:3px}.weather-display .scroll.hazard{background-color:#702323}.weather-display .scroll .fixed,.weather-display .scroll .scroll-header{margin-left:55px;margin-right:55px;overflow:hidden}.weather-display .scroll.hazard .fixed{margin-left:0;margin-right:0}.weather-display .scroll .scroll-header{height:26px;font-family:"Star4000 Small";font-size:20pt;margin-top:-10px}.weather-display .scroll .fixed{font-family:"Star4000";font-size:24pt}.weather-display .scroll .fixed .scroll-area{text-wrap:nowrap;position:relative}.weather-display .main.current-weather.main .col{height:50px;width:255px;display:inline-block;margin-top:10px;padding-top:10px;position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.current-weather.main .col.left{font-family:"Star4000 Extended";font-size:24pt}.weather-display .main.current-weather.main .col.right{right:0px;font-family:"Star4000 Large";font-size:20px;font-weight:bold;line-height:24px}.weather-display .main.current-weather.main .col.right .row{margin-bottom:12px}.weather-display .main.current-weather.main .col.right .row .label,.weather-display .main.current-weather.main .col.right .row .value{display:inline-block}.weather-display .main.current-weather.main .col.right .row .label{margin-left:20px}.weather-display .main.current-weather.main .col.right .row .value{float:right;margin-right:10px}.weather-display .main.current-weather.main .center{text-align:center}.weather-display .main.current-weather.main .temp{font-family:"Star4000 Large";font-size:24pt}.weather-display .main.current-weather.main .icon img{margin:0 auto;display:block}.weather-display .main.current-weather.main .wind-container{margin-left:10px;display:flex}.weather-display .main.current-weather.main .wind-container>div{width:50%}.weather-display .main.current-weather.main .wind-container .wind{text-align:right}.weather-display .main.current-weather.main .wind-gusts{text-align:right;font-size:28px}.weather-display .main.current-weather.main .location{color:#ff0;max-height:32px;margin-bottom:10px;padding-top:4px;overflow:hidden;text-wrap:nowrap}#extended-forecast-html.weather-display{background-image:url("../images/backgrounds/2.png")}.weather-display .main.extended-forecast .day-container{margin-top:16px;margin-left:27px}.weather-display .main.extended-forecast .day{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;padding:5px;height:285px;width:155px;display:inline-block;margin:0px 15px;font-family:"Star4000";font-size:24pt}.weather-display .main.extended-forecast .day .date{text-transform:uppercase;text-align:center;color:#ff0}.weather-display .main.extended-forecast .day .condition{text-align:center;height:74px;margin-top:5px}.weather-display .main.extended-forecast .day .icon{text-align:center;height:75px}.weather-display .main.extended-forecast .day .icon img{max-height:75px}.weather-display .main.extended-forecast .day .temperatures{width:100%}.weather-display .main.extended-forecast .day .temperatures .temperature-block{display:inline-block;width:44%;vertical-align:top}.weather-display .main.extended-forecast .day .temperatures .temperature-block>div{text-align:center}.weather-display .main.extended-forecast .day .temperatures .temperature-block .value{font-family:"Star4000 Large";margin-top:4px}.weather-display .main.extended-forecast .day .temperatures .temperature-block.lo .label{color:#8080ff}.weather-display .main.extended-forecast .day .temperatures .temperature-block.hi .label{color:#ff0}.weather-display .main.hourly.main{overflow-y:hidden}.weather-display .main.hourly.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly.main .column-headers{position:sticky;top:0px;z-index:5}.weather-display .main.hourly.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.hourly.main .column-headers .temp{left:355px}.weather-display .main.hourly.main .column-headers .like{left:435px}.weather-display .main.hourly.main .column-headers .wind{left:535px}.weather-display .main.hourly.main .hourly-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.hourly.main .hourly-lines .hourly-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.hourly.main .hourly-lines .hourly-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.hourly.main .hourly-lines .hourly-row .hour{left:25px}.weather-display .main.hourly.main .hourly-lines .hourly-row .icon{left:255px;width:70px;text-align:center;top:unset}.weather-display .main.hourly.main .hourly-lines .hourly-row .temp{left:355px}.weather-display .main.hourly.main .hourly-lines .hourly-row .like{left:425px}.weather-display .main.hourly.main .hourly-lines .hourly-row .like.heat-index{color:#e00}.weather-display .main.hourly.main .hourly-lines .hourly-row .like.wind-chill{color:#8080ff}.weather-display .main.hourly.main .hourly-lines .hourly-row .wind{left:505px;width:100px;text-align:right}#hourly-graph-html{background-image:url(../images/backgrounds/1-chart.png)}#hourly-graph-html .header .right{position:absolute;top:35px;right:60px;width:360px;font-family:"Star4000 Small";font-size:32px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:right}#hourly-graph-html .header .right div{margin-top:-18px}#hourly-graph-html .header .right .temperature{color:red}#hourly-graph-html .header .right .cloud{color:#d3d3d3}#hourly-graph-html .header .right .rain{color:aqua}.weather-display .main.hourly-graph.main>div{position:absolute}.weather-display .main.hourly-graph.main .label{font-family:"Star4000 Small";font-size:24pt;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;margin-top:-15px;position:absolute}.weather-display .main.hourly-graph.main .x-axis{bottom:0px;left:0px;width:640px;height:20px}.weather-display .main.hourly-graph.main .x-axis .label{text-align:center;width:50px}.weather-display .main.hourly-graph.main .x-axis .label.l-1{left:25px}.weather-display .main.hourly-graph.main .x-axis .label.l-2{left:158px}.weather-display .main.hourly-graph.main .x-axis .label.l-3{left:291px}.weather-display .main.hourly-graph.main .x-axis .label.l-4{left:424px}.weather-display .main.hourly-graph.main .x-axis .label.l-5{left:557px}.weather-display .main.hourly-graph.main .chart{top:0px;left:50px}.weather-display .main.hourly-graph.main .chart img{width:532px;height:285px}.weather-display .main.hourly-graph.main .y-axis{top:0px;left:0px;width:50px;height:285px}.weather-display .main.hourly-graph.main .y-axis .label{text-align:right;right:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-1{top:0px}.weather-display .main.hourly-graph.main .y-axis .label.l-2{top:140px}.weather-display .main.hourly-graph.main .y-axis .label.l-3{bottom:0px}.weather-display .main.hourly-graph.main .column-headers{background-color:#200057;height:20px;position:absolute;width:100%}.weather-display .main.hourly-graph.main .column-headers{position:sticky;top:0px;z-index:5}.weather-display .main.hourly-graph.main .column-headers .temp{left:355px}.weather-display .main.hourly-graph.main .column-headers .like{left:435px}.weather-display .main.hourly-graph.main .column-headers .wind{left:535px}.weather-display .main.travel.main{overflow-y:hidden}.weather-display .main.travel.main .column-headers{background-color:#200057;height:20px;position:sticky;top:0px;width:100%;z-index:5;overflow:hidden}.weather-display .main.travel.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;color:#ff0;position:absolute;top:-14px;z-index:5;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.travel.main .column-headers .temp{width:50px;text-align:center}.weather-display .main.travel.main .column-headers .temp.low{left:455px}.weather-display .main.travel.main .column-headers .temp.high{left:510px;width:60px}.weather-display .main.travel.main .travel-lines{min-height:338px;padding-top:10px;background:repeating-linear-gradient(0deg, #001040 0px, #102080 136px, #102080 202px, #001040 338px)}.weather-display .main.travel.main .travel-lines .travel-row{font-family:"Star4000 Large";font-size:24pt;height:72px;color:#ff0;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative}.weather-display .main.travel.main .travel-lines .travel-row>div{position:absolute;white-space:pre;top:8px}.weather-display .main.travel.main .travel-lines .travel-row .city{left:80px}.weather-display .main.travel.main .travel-lines .travel-row .icon{left:330px;width:70px;text-align:center;top:unset}.weather-display .main.travel.main .travel-lines .travel-row .icon img{max-width:47px}.weather-display .main.travel.main .travel-lines .travel-row .temp{width:50px;text-align:center}.weather-display .main.travel.main .travel-lines .travel-row .temp.low{left:455px}.weather-display .main.travel.main .travel-lines .travel-row .temp.high{left:510px;width:60px}.weather-display .latest-observations.main{overflow-y:hidden}.weather-display .latest-observations.main .column-headers{height:20px;position:absolute;width:100%}.weather-display .latest-observations.main .column-headers{top:0px}.weather-display .latest-observations.main .column-headers div{display:inline-block;font-family:"Star4000 Small";font-size:24pt;position:absolute;top:-14px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .latest-observations.main .column-headers .temp{display:none}.weather-display .latest-observations.main .column-headers .temp.show{display:inline-block}.weather-display .latest-observations.main .temp{left:230px}.weather-display .latest-observations.main .weather{left:280px}.weather-display .latest-observations.main .wind{left:430px}.weather-display .latest-observations.main .observation-lines{min-height:338px;padding-top:10px}.weather-display .latest-observations.main .observation-lines .observation-row{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative;height:40px}.weather-display .latest-observations.main .observation-lines .observation-row>div{position:absolute;top:8px}.weather-display .latest-observations.main .observation-lines .observation-row .wind{white-space:pre;text-align:right}.weather-display .local-forecast .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:280px;overflow:hidden}.weather-display .local-forecast .forecasts{position:relative}.weather-display .local-forecast .forecast{font-family:"Star4000";font-size:24pt;text-transform:uppercase;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;min-height:280px;line-height:40px}.weather-display .progress{text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;font-family:"Star4000 Extended";font-size:19pt}.weather-display .progress .container{position:relative;top:15px;margin:0px 10px;box-sizing:border-box;height:310px;overflow:hidden;line-height:28px}.weather-display .progress .container .item{position:relative}.weather-display .progress .container .item .name{white-space:nowrap}.weather-display .progress .container .item .name::after{content:"........................................................................"}.weather-display .progress .container .item .links{position:absolute;text-align:right;right:0px;top:0px}.weather-display .progress .container .item .links>div{background-color:#26235a;display:none;padding-left:4px}.weather-display .progress .container .item .links .loading,.weather-display .progress .container .item .links .retrying{color:#ff0}.weather-display .progress .container .item .links .press-here{color:lime;cursor:pointer}.weather-display .progress .container .item .links .failed{color:red}.weather-display .progress .container .item .links .no-data{color:silver}.weather-display .progress .container .item .links .disabled{color:silver}.weather-display .progress .container .item .links.loading .loading,.weather-display .progress .container .item .links.press-here .press-here,.weather-display .progress .container .item .links.failed .failed,.weather-display .progress .container .item .links.no-data .no-data,.weather-display .progress .container .item .links.disabled .disabled,.weather-display .progress .container .item .links.retrying .retrying{display:block}@keyframes progress-scroll{0%{background-position:-40px 0}100%{background-position:40px 0}}#progress-html.weather-display .scroll .progress-bar-container{border:2px solid #000;background-color:#fff;margin:20px auto;width:524px;position:relative;display:none}#progress-html.weather-display .scroll .progress-bar-container.show{display:block}#progress-html.weather-display .scroll .progress-bar-container .progress-bar{height:20px;margin:2px;width:520px;background:repeating-linear-gradient(90deg, #09246f 0px, #09246f 5px, #364ac0 5px, #364ac0 10px, #4f99f9 10px, #4f99f9 15px, #8ffdfa 15px, #8ffdfa 20px, #4f99f9 20px, #4f99f9 25px, #364ac0 25px, #364ac0 30px, #09246f 30px, #09246f 40px);animation-duration:2s;animation-fill-mode:forwards;animation-iteration-count:infinite;animation-name:progress-scroll;animation-timing-function:steps(8, end)}#progress-html.weather-display .scroll .progress-bar-container .cover{position:absolute;top:0px;right:0px;background-color:#fff;width:100%;height:24px;transition:width 1s steps(6)}#radar-html.weather-display{background-image:url("../images/backgrounds/4.png")}#radar-html.weather-display .header{height:83px}#radar-html.weather-display .header .title.dual{color:#fff;font-family:"Arial",sans-serif;font-weight:bold;font-size:28pt;left:155px}#radar-html.weather-display .header .title.dual .top{top:-4px}#radar-html.weather-display .header .title.dual .bottom{top:31px}#radar-html.weather-display .header .right{position:absolute;right:0px;width:360px;margin-top:2px;font-family:"Star4000";font-size:18pt;font-weight:bold;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;text-align:center}#radar-html.weather-display .header .right .scale>div{display:inline-block}#radar-html.weather-display .header .right .scale-table{display:table-row;border-collapse:collapse}#radar-html.weather-display .header .right .scale-table .box{display:table-cell;border:2px solid #000;width:17px;height:24px;padding:0}#radar-html.weather-display .header .right .scale-table .box-1{background-color:#31d216}#radar-html.weather-display .header .right .scale-table .box-2{background-color:#1c8a12}#radar-html.weather-display .header .right .scale-table .box-3{background-color:#145a0f}#radar-html.weather-display .header .right .scale-table .box-4{background-color:#0a280a}#radar-html.weather-display .header .right .scale-table .box-5{background-color:#c4b346}#radar-html.weather-display .header .right .scale-table .box-6{background-color:#be4813}#radar-html.weather-display .header .right .scale-table .box-7{background-color:#ab0e0e}#radar-html.weather-display .header .right .scale-table .box-8{background-color:#731f04}#radar-html.weather-display .header .right .scale .text{position:relative;top:-5px}#radar-html.weather-display .header .right .time{position:relative;font-weight:normal;top:-14px;font-family:"Star4000 Small";font-size:24pt}.weather-display .main.radar{overflow:hidden;height:367px}.weather-display .main.radar .container .tiles{position:absolute;width:1400px}.weather-display .main.radar .container .tiles img{vertical-align:middle}.weather-display .main.radar .container .scroll-area{position:relative}.wide.radar #container{background:url(../images/backgrounds/4-wide.png)}#regional-forecast-html.weather-display{background-image:url("../images/backgrounds/5.png")}.weather-display .main.regional-forecast{position:relative}.weather-display .main.regional-forecast .map{position:absolute;transform-origin:0 0}.weather-display .main.regional-forecast .location{position:absolute;width:140px;margin-left:-40px;margin-top:-35px}.weather-display .main.regional-forecast .location>div{position:absolute;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.regional-forecast .location .icon{top:26px;left:44px}.weather-display .main.regional-forecast .location .icon img{max-height:32px}.weather-display .main.regional-forecast .location .temp{font-family:"Star4000 Large";font-size:28px;padding-top:2px;color:#ff0;top:28px;text-align:right;width:40px}.weather-display .main.regional-forecast .location .city{font-family:Star4000;font-size:20px}#almanac-html.weather-display{background-image:url("../images/backgrounds/3.png")}.weather-display .main.almanac{font-family:"Star4000";font-size:24pt;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .main.almanac .sun{display:grid;grid-template-columns:auto auto auto;grid-template-rows:auto auto auto;gap:0px 90px;margin:3px auto 5px auto;width:-moz-fit-content;width:fit-content;line-height:30px}.weather-display .main.almanac .sun .grid-item{width:auto;height:auto;padding:0;margin:0;position:relative}.weather-display .main.almanac .sun .grid-item.header{color:#ff0;text-align:center}.weather-display .main.almanac .sun .grid-item.row-label{text-align:right}.weather-display .main.almanac .sun .grid-item.time{text-align:center}.weather-display .main.almanac .moon{position:relative;padding:7px 50px;line-height:36px}.weather-display .main.almanac .moon .title{color:#ff0;padding-left:13px}.weather-display .main.almanac .moon .day{display:inline-block;text-align:center;width:132px}.weather-display .main.almanac .moon .day .icon{padding-left:10px}.weather-display .main.almanac .moon .day .date{position:relative;top:-10px}.weather-display .main.hazards.main{overflow-y:hidden;height:480px;background-color:#702323}.weather-display .main.hazards.main .hazard-lines{min-height:400px;padding-top:10px}.weather-display .main.hazards.main .hazard-lines .hazard{font-family:"Star4000";font-size:24pt;color:#fff;text-shadow:0px 0px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;position:relative;text-transform:uppercase;margin-top:10px;margin-left:80px;margin-right:80px;padding-bottom:10px}.media{display:none}#ToggleMedia{display:none}#ToggleMedia.available{display:inline-block}#ToggleMedia.available img.on{display:none}#ToggleMedia.available img.off{display:block}#ToggleMedia.available.playing img.on{display:block}#ToggleMedia.available.playing img.off{display:none}#spc-outlook-html.weather-display{background-image:url("../images/backgrounds/6.png")}.weather-display .spc-outlook .container{position:relative;top:0px;margin:0px 10px;box-sizing:border-box;height:300px;overflow:hidden}.weather-display .spc-outlook .risk-levels{position:absolute;left:206px;font-family:"Star4000 Small";font-size:32px;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000}.weather-display .spc-outlook .risk-levels .risk-level{position:relative;top:-14px;height:20px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(1){left:100px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(2){left:80px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(3){left:60px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(4){left:40px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(5){left:20px}.weather-display .spc-outlook .risk-levels .risk-level:nth-child(6){left:0px}.weather-display .spc-outlook .days{position:absolute;top:120px}.weather-display .spc-outlook .days .day{height:60px}.weather-display .spc-outlook .days .day .day-name{position:absolute;font-family:"Star4000";font-size:24pt;width:200px;text-align:right;text-shadow:3px 3px 0 #000,-1.5px -1.5px 0 #000,0 -1.5px 0 #000,1.5px -1.5px 0 #000,1.5px 0 0 #000,1.5px 1.5px 0 #000,0 1.5px 0 #000,-1.5px 1.5px 0 #000,-1.5px 0 0 #000;padding-top:20px}.weather-display .spc-outlook .days .day .risk-bar{position:absolute;width:150px;height:40px;left:210px;margin-top:20px;border:3px outset #b3b3b3;background:linear-gradient(0deg, hsl(0, 0%, 40%) 0%, hsl(0, 0%, 60%) 50%, hsl(0, 0%, 40%) 100%)}.scanlines{position:relative;overflow:hidden}.scanlines:before,.scanlines:after{display:block;pointer-events:none;content:"";position:absolute}.scanlines:before{width:100%;height:1px;z-index:2147483649;background:rgba(0,0,0,.3);opacity:.75;animation:scanline 6s linear infinite}.scanlines:after{top:0;right:0;bottom:0;left:0;z-index:2147483648;background:repeating-linear-gradient(to bottom, transparent 0, transparent 1px, rgba(0, 0, 0, 0.3) 1px, rgba(0, 0, 0, 0.3) 2px);animation:none;image-rendering:crisp-edges;image-rendering:pixelated}.scanlines:before{height:var(--scanline-thickness, 1px)}.scanlines:after{background:repeating-linear-gradient(to bottom, transparent 0, transparent var(--scanline-thickness, 1px), rgba(0, 0, 0, 0.3) var(--scanline-thickness, 1px), rgba(0, 0, 0, 0.3) calc(var(--scanline-thickness, 1px) * 2))}@keyframes scanline{0%{transform:translate3d(0, 200000%, 0)}}@keyframes scanlines{0%{background-position:0 50%}}/*# sourceMappingURL=main.css.map */ \ No newline at end of file diff --git a/server/styles/main.css.map b/server/styles/main.css.map index b23e224..4e5e0c4 100644 --- a/server/styles/main.css.map +++ b/server/styles/main.css.map @@ -1 +1 @@ -{"version":3,"sources":["scss/_page.scss","scss/shared/_utils.scss","scss/_weather-display.scss","scss/shared/_colors.scss","scss/_current-weather.scss","scss/_extended-forecast.scss","scss/_hourly.scss","scss/_hourly-graph.scss","scss/_travel.scss","scss/_latest-observations.scss","scss/_local-forecast.scss","scss/_progress.scss","scss/_radar.scss","scss/_regional-forecast.scss","scss/_almanac.scss","scss/_hazards.scss","scss/_media.scss","scss/_spc-outlook.scss","scss/shared/_scanlines.scss"],"names":[],"mappings":"AAGA,WACC,sBAAA,CACA,gDAAA,CACA,iBAAA,CAGD,KACC,sBAAA,CAEA,mCAHD,KAIE,qBAAA,CACA,UAAA,CAAA,CAIA,mCADD,OAEE,aAAA,CAAA,CAIF,WACC,UAAA,CACA,eAAA,CACA,WAAA,CAIF,UACC,eAAA,CAEA,mBACC,oBAAA,CACA,WAAA,CACA,gBAAA,CAEA,8BACC,WAAA,CACA,qBAAA,CAGD,0BACC,cAAA,CACA,wBAAA,CAEA,mCAJD,0BAKE,qBAAA,CACA,UAAA,CAAA,CAQA,uCACC,YAAA,CAEA,mCAHD,uCAIE,oBAAA,CAAA,CAKD,mCADD,wCAEE,YAAA,CAAA,CAKH,qCACC,qBAAA,CAEA,mCAHD,qCAIE,qBAAA,CAAA,CAGD,yCACC,gBAAA,CAMJ,iCAEC,sBAAA,CAGD,sBACC,wBAAA,CACA,eAAA,CACA,cAAA,CACA,eAAA,CACA,oBAAA,CAEA,mCAPD,sBAQE,qBAAA,CACA,UAAA,CACA,wBAAA,CAAA,CAOH,0BACC,qBAAA,CACA,qBAAA,CACA,iBAAA,CACA,YAAA,CAEA,mCAND,0BAOE,qBAAA,CAAA,CAGD,8BAEC,kBAAA,CACA,eAAA,CACA,sBAAA,CACA,cAAA,CAEA,uCACC,qBAAA,CACA,UAAA,CAMH,QACC,aAAA,CACA,qBAAA,CACA,UAAA,CACA,UAAA,CACA,eAAA,CAEA,aACC,eAAA,CAIF,eACC,eAAA,CAGD,YACC,YAAA,CACA,gBAAA,CACA,qBAAA,CACA,qBAAA,CAGD,gBACC,MAAA,CACA,kBAAA,CACA,YAAA,CACA,qBAAA,CACA,sBAAA,CAGD,aACC,eAAA,CACA,YAAA,CACA,qBAAA,CACA,qBAAA,CAGD,iBACC,MAAA,CACA,iBAAA,CACA,YAAA,CACA,qBAAA,CACA,sBAAA,CAGD,cAEC,YAAA,CACA,kBAAA,CACA,qBAAA,CAEA,UAAA,CACA,UAAA,CAEA,mCATD,cAUE,wBAAA,CAAA,CAKF,kBACC,gBAAA,CACA,iBAAA,CAGA,yBALD,kBAME,OAAA,CAAA,CAGD,yBATD,kBAUE,OAAA,CAAA,CAGD,yBAbD,kBAcE,OAAA,CAAA,CAGD,yBAjBD,kBAkBE,OAAA,CAAA,CAGD,yBArBD,kBAsBE,OAAA,CAAA,CAIF,kBACC,MAAA,CACA,eAAA,CAID,oBACC,MAAA,CACA,iBAAA,CAGD,mBACC,MAAA,CACA,gBAAA,CAGD,oBACC,YAAA,CAGD,WACC,UAAA,CACA,YAAA,CACA,kBAAA,CACA,qBAAA,CACA,UAAA,CACA,eAAA,CAGD,eACC,gBAAA,CACA,iBAAA,CAGD,eACC,MAAA,CACA,eAAA,CAGD,iBACC,MAAA,CACA,iBAAA,CAGD,gBACC,MAAA,CACA,gBAAA,CAGD,YACC,iBAAA,CACA,iBAAA,CAGD,YACC,sBAAA,CAGD,eACC,WAAA,CAGD,WACC,+BAAA,CACA,yDAAA,CACA,iBAAA,CAGD,WACC,4BAAA,CACA,sDAAA,CACA,iBAAA,CAGD,WACC,4BAAA,CACA,sDAAA,CACA,iBAAA,CAGD,SACC,sBAAA,CACA,cAAA,CACA,UAAA,CAGD,WACC,iBAAA,CACA,WAAA,CACA,YAAA,CAEA,iDAAA,CACA,oBAAA,CAGD,iBACC,kBAAA,CACA,mBAAA,CACA,2BAAA,CACA,gDAAA,CAGD,uCAGC,WAAA,CACA,YAAA,CACA,sBAAA,CALD,wDAGC,WAAA,CACA,YAAA,CACA,sBAAA,CAGD,SACC,WAAA,CACA,YAAA,CACA,cAAA,CACA,wBAAA,CACA,YAAA,CACA,kBAAA,CACA,iBAAA,CACA,sBAAA,CAEA,gBACC,0BAAA,CACA,cAAA,CACA,UAAA,CACA,iBAAA,CAGD,kBACC,kBAAA,CAGD,uBACC,cAAA,CAIF,SACC,gBAAA,CACA,eAAA,CAGD,UACC,kBAAA,CAGD,2BAEC,kBAAA,CC3VA,4FAEC,UAAA,CAGD,mDACC,UAAA,CACA,cAAA,CAGD,2CACC,SAAA,CAGD,6CACC,YAAA,CAGD,+CACC,YAAA,CD2UD,mDACC,UAAA,CAGD,oCAEC,4FAEC,UAAA,CAGD,mDACC,UAAA,CACA,cAAA,CAGD,2CACC,UAAA,CAGD,6CACC,aAAA,CAGD,+CACC,aAAA,CAAA,CAIF,uCACC,aAAA,CACA,eAAA,CAEA,qDACC,YAAA,CAEA,+DACC,cAAA,CACA,SAAA,CAMJ,kBACC,qBAAA,CAGD,4BAEC,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,oBAAA,CALD,kCAEC,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,oBAAA,CAEA,sCACC,WAAA,CADD,sDACC,WAAA,CAIF,qCAEC,iBAAA,CAFD,oDAEC,iBAAA,CAGD,0CAEC,YAAA,CACA,kBAAA,CACA,+BAAA,CACA,UAAA,CACA,UAAA,CACA,iBAAA,CACA,UAAA,CARD,8DAEC,YAAA,CACA,kBAAA,CACA,+BAAA,CACA,UAAA,CACA,UAAA,CACA,iBAAA,CACA,UAAA,CAKC,iCACC,YAAA,CAKH,WACC,cAAA,CAGD,iBACC,oBAAA,CAEA,qBACC,YAAA,CAGD,sBACC,oBAAA,CAKA,wBACC,oBAAA,CAGD,yBACC,YAAA,CAMH,SACC,kBAAA,CACA,SAAA,CACA,6BAAA,CAGD,oCACC,iBAAA,CACA,SAAA,CACA,qDAAA,CAAA,6CAAA,CAHD,2BACC,iBAAA,CACA,SAAA,CACA,6CAAA,CAGD,cACC,WAAA,CACA,4BAAA,CACA,YAAA,CACA,4BAAA,CACA,cAAA,CAGC,qBACC,oBAAA,CACA,SAAA,CAGD,2BACC,oBAAA,CACA,eAAA,CACA,gFAAA,CACA,WAAA,CACA,aAAA,CACA,kBAAA,CAGD,yDAEC,iBAAA,CACA,oBAAA,CACA,mBAAA,CACA,WAAA,CACA,eAAA,CACA,cAAA,CACA,eAAA,CACA,gBAAA,CACA,qBAAA,CACA,cAAA,CACA,wBAAA,CACA,qBAAA,CAEA,gBAAA,CACA,0BAAA,CACA,6BAAA,CACA,yBAAA,CACA,gBAAA,CAGD,wBACC,mBAAA,CAGD,yCACC,6BAAA,CAGD,iCACC,aAAA,CACA,6BAAA,CAGD,+EAEC,WAAA,CACA,gBAAA,CACA,cAAA,CACA,gBAAA,CAGD,4BACC,oBAAA,CACA,uBAAA,CACA,iBAAA,CACA,gBAAA,CAGD,qFAEC,yBAAA,CACA,mBAAA,CAGD,wBACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,8BACC,WAAA,CAGD,4DAEC,wBAAA,CACA,4BAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,wEAEC,WAAA,CAGD,+BACC,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,gDAAA,CACA,qBAAA,CACA,WAAA,CAGD,iCACC,aAAA,CACA,qBAAA,CACA,oBAAA,CACA,+BAAA,CAGD,8EAEC,aAAA,CAGD,kCACC,aAAA,CAGD,oCAEC,qFAEC,yBAAA,CACA,mBAAA,CAGD,wBACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,8BACC,WAAA,CAGD,4DAEC,wBAAA,CACA,4BAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,wEAEC,WAAA,CAGD,+BACC,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,gDAAA,CACA,qBAAA,CACA,WAAA,CAGD,iCACC,aAAA,CACA,qBAAA,CACA,oBAAA,CACA,+BAAA,CAGD,8EAEC,aAAA,CAGD,kCACC,aAAA,CAAA,CAIF,mCAEC,qFAEC,yBAAA,CACA,mBAAA,CAGD,wBACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,iCAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,8BACC,WAAA,CAGD,4DAEC,wBAAA,CACA,4BAAA,CACA,oBAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,wEAEC,WAAA,CAGD,+BACC,wBAAA,CACA,oBAAA,CACA,6CAAA,CACA,qBAAA,CACA,WAAA,CAGD,iCACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,iCAAA,CAGD,8EAEC,aAAA,CAGD,kCACC,aAAA,CAAA,CAMJ,mBACC,UAAA,CACA,YAAA,CAGD,yBACC,YAAA,CAKA,6HAOC,YAAA,CExwBF,iBACC,WAAA,CACA,YAAA,CACA,eAAA,CACA,iBAAA,CACA,iDAAA,CAGA,UAAA,CAEA,sBACC,YAAA,CAGD,2BACC,YAAA,CAGD,yBACC,WAAA,CACA,WAAA,CACA,gBAAA,CAEA,gCACC,UC3BW,CFMb,wKACC,CCsBC,sBAAA,CACA,cAAA,CACA,iBAAA,CACA,WAAA,CAEA,uCACC,UAAA,CACA,QAAA,CAGD,qCACC,UAAA,CAEA,yCACC,iBAAA,CAGD,0CACC,QAAA,CAGD,6CACC,QAAA,CAMH,+BACC,QAAA,CACA,SAAA,CACA,iBAAA,CACA,UAAA,CAGD,oCACC,iBAAA,CACA,QAAA,CACA,UAAA,CAGD,uCACC,QAAA,CAGD,oCACC,eAAA,CACA,UC3ES,CD4ET,4BAAA,CACA,cAAA,CDxEF,wKACC,CCyEC,UAAA,CACA,WAAA,CACA,gBAAA,CACA,iBAAA,CAEA,yCACC,gBAAA,CAKH,uBACC,iBAAA,CAEA,kCACC,WAAA,CACA,YAAA,CACA,eAAA,CAEA,4CACC,YAAA,CAIF,+BACC,gBAAA,CACA,iBAAA,CACA,wBAAA,CAMF,yBD3GA,wKACC,CC4GA,WAAA,CACA,WAAA,CACA,eAAA,CACA,cAAA,CAEA,gCACC,wBAAA,CAGD,wEAEC,gBAAA,CACA,iBAAA,CACA,eAAA,CAGD,wCACC,WAAA,CACA,4BAAA,CACA,cAAA,CACA,gBAAA,CAGD,gCACC,sBAAA,CACA,cAAA,CAEA,6CACC,gBAAA,CACA,iBAAA,CE1IF,iDACC,WAAA,CACA,WAAA,CACA,oBAAA,CACA,eAAA,CACA,gBAAA,CACA,iBAAA,CHNF,wKACC,CGSC,sDACC,+BAAA,CACA,cAAA,CAID,uDACC,SAAA,CACA,4BAAA,CACA,cAAA,CACA,gBAAA,CACA,gBAAA,CAEA,4DACC,kBAAA,CAEA,sIAEC,oBAAA,CAGD,mEACC,gBAAA,CAGD,mEACC,WAAA,CACA,iBAAA,CAQJ,oDACC,iBAAA,CAGD,kDACC,4BAAA,CACA,cAAA,CAKD,kDACC,YAAA,CAEA,sDACC,eAAA,CAIF,4DACC,kBAAA,CAEA,gEACC,SAAA,CACA,oBAAA,CACA,UAAA,CAGD,wEACC,eAAA,CAGD,kEACC,gBAAA,CAIF,wDACC,eAAA,CAGD,sDACC,UD7FW,CC8FX,eAAA,CACA,kBAAA,CACA,eAAA,CACA,eAAA,CACA,gBAAA,CC/FH,wCACC,mDAAA,CAIA,wDACC,eAAA,CACA,gBAAA,CAGD,8CJPA,wKACC,CIQA,WAAA,CACA,YAAA,CACA,WAAA,CACA,oBAAA,CACA,eAAA,CACA,sBAAA,CACA,cAAA,CAEA,oDACC,wBAAA,CACA,iBAAA,CACA,UF1BW,CE6BZ,yDACC,iBAAA,CACA,WAAA,CACA,cAAA,CAGD,oDACC,iBAAA,CACA,WAAA,CAEA,wDACC,eAAA,CAIF,4DACC,UAAA,CAEA,+EACC,oBAAA,CACA,SAAA,CACA,kBAAA,CAEA,mFACC,iBAAA,CAGD,sFACC,4BAAA,CACA,cAAA,CAGD,yFACC,aFhDU,CEmDX,yFACC,UFlES,CGIb,mCACC,iBAAA,CAEA,mDACC,wBHJa,CGKb,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,mDACC,eAAA,CACA,OAAA,CACA,SAAA,CAEA,uDACC,oBAAA,CACA,4BAAA,CACA,cAAA,CACA,UHpBiB,CGqBjB,iBAAA,CACA,SAAA,CACA,SAAA,CLpBH,wKACC,CKuBC,yDACC,UAAA,CAGD,yDACC,UAAA,CAGD,yDACC,UAAA,CAIF,iDACC,gBAAA,CACA,gBAAA,CAEA,oGAAA,CAMA,6DACC,4BAAA,CACA,cAAA,CACA,WAAA,CACA,UHzDU,CFMb,wKACC,CKoDE,iBAAA,CAEA,iEACC,iBAAA,CACA,eAAA,CACA,OAAA,CAGD,mEACC,SAAA,CAGD,mEACC,UAAA,CACA,UAAA,CACA,iBAAA,CACA,SAAA,CAGD,mEACC,UAAA,CAGD,mEACC,UAAA,CAEA,8EACC,UAAA,CAGD,8EACC,aH5ES,CGgFX,mEACC,UAAA,CACA,WAAA,CACA,gBAAA,CC9FL,mBACC,uDAAA,CAGC,kCACC,iBAAA,CACA,QAAA,CACA,UAAA,CACA,WAAA,CACA,4BAAA,CACA,cAAA,CNPF,wKACC,CMQC,gBAAA,CAEA,sCACC,gBAAA,CAGD,+CACC,SAAA,CAGD,yCACC,aAAA,CAGD,wCACC,UAAA,CASF,6CACC,iBAAA,CAGD,gDACC,4BAAA,CACA,cAAA,CACA,UJ3CkB,CFGpB,wKACC,CMyCC,gBAAA,CACA,iBAAA,CAGD,iDACC,UAAA,CACA,QAAA,CACA,WAAA,CACA,WAAA,CAEA,wDACC,iBAAA,CACA,UAAA,CAEA,4DACC,SAAA,CAGD,4DACC,UAAA,CAGD,4DACC,UAAA,CAGD,4DACC,UAAA,CAGD,4DACC,UAAA,CAQH,gDACC,OAAA,CACA,SAAA,CAEA,oDACC,WAAA,CACA,YAAA,CAIF,iDACC,OAAA,CACA,QAAA,CACA,UAAA,CACA,YAAA,CAEA,wDACC,gBAAA,CACA,SAAA,CAEA,4DACC,OAAA,CAGD,4DACC,SAAA,CAGD,4DACC,UAAA,CAKH,yDACC,wBJtHa,CIuHb,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,yDACC,eAAA,CACA,OAAA,CACA,SAAA,CAGA,+DACC,UAAA,CAGD,+DACC,UAAA,CAGD,+DACC,UAAA,CC3IH,mCACC,iBAAA,CAEA,mDACC,wBLJa,CKKb,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,mDACC,eAAA,CACA,OAAA,CACA,SAAA,CAEA,uDACC,oBAAA,CACA,4BAAA,CACA,cAAA,CACA,ULpBiB,CKqBjB,iBAAA,CACA,SAAA,CACA,SAAA,CPpBH,wKACC,COuBC,yDACC,UAAA,CACA,iBAAA,CAEA,6DACC,UAAA,CAID,8DACC,UAAA,CACA,UAAA,CAKH,iDACC,gBAAA,CACA,gBAAA,CAEA,oGAAA,CAMA,6DACC,4BAAA,CACA,cAAA,CACA,WAAA,CACA,UL5DU,CFMb,wKACC,COuDE,iBAAA,CAEA,iEACC,iBAAA,CACA,eAAA,CACA,OAAA,CAGD,mEACC,SAAA,CAGD,mEACC,UAAA,CACA,UAAA,CACA,iBAAA,CACA,SAAA,CAEA,uEACC,cAAA,CAIF,mEACC,UAAA,CACA,iBAAA,CAEA,uEACC,UAAA,CAGD,wEACC,UAAA,CACA,UAAA,CC1FL,2CACC,iBAAA,CAEA,2DACC,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,2DACC,OAAA,CAEA,+DACC,oBAAA,CACA,4BAAA,CACA,cAAA,CACA,iBAAA,CACA,SAAA,CRhBH,wKACC,CQmBC,iEAEC,YAAA,CAEA,sEACC,oBAAA,CAKH,iDACC,UAAA,CAGD,oDACC,UAAA,CAGD,iDACC,UAAA,CAGD,8DACC,gBAAA,CACA,gBAAA,CAEA,+EACC,sBAAA,CACA,cAAA,CRhDH,wKACC,CQiDE,iBAAA,CACA,WAAA,CAEA,mFACC,iBAAA,CACA,OAAA,CAGD,qFACC,eAAA,CACA,gBAAA,CC9DJ,4CACC,iBAAA,CACA,QAAA,CACA,eAAA,CACA,qBAAA,CACA,YAAA,CACA,eAAA,CAGD,4CACC,iBAAA,CAGD,2CACC,sBAAA,CACA,cAAA,CACA,wBAAA,CTdD,wKACC,CSeA,gBAAA,CACA,gBAAA,CCpBF,2BVGC,wKACC,CUFD,+BAAA,CACA,cAAA,CAEA,sCACC,iBAAA,CACA,QAAA,CACA,eAAA,CACA,qBAAA,CACA,YAAA,CACA,eAAA,CAEA,4CACC,iBAAA,CAEA,kDACC,kBAAA,CAEA,yDACC,kFAAA,CAIF,mDACC,iBAAA,CACA,gBAAA,CACA,SAAA,CACA,OAAA,CAEA,uDACC,wBRlBM,CQmBN,YAAA,CACA,gBAAA,CVhBJ,yHAEC,UAAA,CAGD,+DACC,UAAA,CACA,cAAA,CAGD,2DACC,SAAA,CAGD,4DACC,YAAA,CAGD,6DACC,YAAA,CUEE,gaAMC,aAAA,CAYJ,2BACC,GACC,2BAAA,CAGD,KACC,0BAAA,CAAA,CAIF,+DACC,qBAAA,CACA,qBAAA,CACA,gBAAA,CACA,WAAA,CACA,iBAAA,CACA,YAAA,CAEA,oEACC,aAAA,CAGD,6EACC,WAAA,CACA,UAAA,CACA,WAAA,CACA,4OAAA,CAiBA,qBAAA,CACA,4BAAA,CACA,kCAAA,CACA,8BAAA,CACA,uCAAA,CAGD,sEACC,iBAAA,CACA,OAAA,CACA,SAAA,CACA,qBAAA,CACA,UAAA,CACA,WAAA,CACA,4BAAA,CCjHH,4BACC,mDAAA,CAEA,oCACC,WAAA,CAEA,gDACC,UAAA,CACA,8BAAA,CACA,gBAAA,CACA,cAAA,CACA,UAAA,CAEA,qDACC,QAAA,CAGD,wDACC,QAAA,CAIF,2CACC,iBAAA,CACA,SAAA,CACA,WAAA,CACA,cAAA,CACA,sBAAA,CACA,cAAA,CACA,gBAAA,CX1BF,wKACC,CW2BC,iBAAA,CAEA,sDACC,oBAAA,CAGD,wDACC,iBAAA,CACA,wBAAA,CAEA,6DACC,kBAAA,CACA,qBAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAKD,wDACC,iBAAA,CACA,QAAA,CAIF,iDACC,iBAAA,CACA,kBAAA,CACA,SAAA,CACA,4BAAA,CACA,cAAA,CAMJ,6BACC,eAAA,CACA,YAAA,CAIC,+CACC,iBAAA,CACA,YAAA,CAEA,mDACC,qBAAA,CAIF,qDACC,iBAAA,CAKH,uBACC,gDAAA,CC1HD,wCACC,mDAAA,CAGD,yCAGC,iBAAA,CAEA,8CACC,iBAAA,CACA,oBAAA,CAGD,mDACC,iBAAA,CACA,WAAA,CACA,iBAAA,CACA,gBAAA,CAEA,uDACC,iBAAA,CZlBF,wKACC,CYqBA,yDACC,QAAA,CACA,SAAA,CAEA,6DACC,eAAA,CAIF,yDACC,4BAAA,CACA,cAAA,CACA,eAAA,CACA,UVzCW,CU0CX,QAAA,CACA,gBAAA,CACA,UAAA,CAGD,yDACC,oBAAA,CACA,cAAA,CC9CH,8BACC,mDAAA,CAGD,+BACC,sBAAA,CACA,cAAA,CbHA,wKACC,CaKD,oCACC,aAAA,CACA,gBAAA,CACA,YAAA,CAGA,wCACC,iBAAA,CACA,iBAAA,CAEA,4CACC,kBAAA,CAIF,0CACC,UXzBkB,CW0BlB,gBAAA,CACA,QAAA,CAEA,+CACC,kBAAA,CAKF,2CACC,gBAAA,CAEA,qDACC,WAAA,CAGD,mDACC,SAAA,CAGD,mDACC,SAAA,CAKH,qCACC,iBAAA,CACA,SAAA,CAEA,gBAAA,CAEA,4CACC,UX3DkB,CW8DnB,0CACC,oBAAA,CACA,iBAAA,CACA,WAAA,CAEA,gDAEC,iBAAA,CAGD,gDACC,iBAAA,CACA,SAAA,CCzEH,oCACC,iBAAA,CACA,YAAA,CAEA,kDACC,gBAAA,CACA,gBAAA,CAEA,wBAAA,CAEA,0DACC,sBAAA,CACA,cAAA,CACA,UAAA,CdXH,wKACC,CcYE,iBAAA,CACA,wBAAA,CACA,eAAA,CACA,gBAAA,CACA,iBAAA,CACA,mBAAA,CCxBJ,OACC,YAAA,CAGD,aACC,YAAA,CAEA,uBACC,oBAAA,CAEA,8BACC,YAAA,CAGD,+BACC,aAAA,CAKA,sCACC,aAAA,CAGD,uCACC,YAAA,CCtBJ,kCACC,mDAAA,CAKA,yCACC,iBAAA,CACA,OAAA,CACA,eAAA,CACA,qBAAA,CACA,YAAA,CACA,eAAA,CAGD,2CACC,iBAAA,CACA,UAAA,CACA,4BAAA,CACA,cAAA,ChBhBD,wKACC,CgBmBA,uDACC,iBAAA,CACA,SAAA,CACA,WAAA,CAEA,oEACC,UAAA,CAGD,oEACC,SAAA,CAGD,oEACC,SAAA,CAGD,oEACC,SAAA,CAGD,oEACC,SAAA,CAGD,oEACC,QAAA,CAKH,oCACC,iBAAA,CACA,SAAA,CAEA,yCACC,WAAA,CAEA,mDACC,iBAAA,CACA,sBAAA,CACA,cAAA,CACA,WAAA,CACA,gBAAA,ChB/DH,wKACC,CgBgEE,gBAAA,CAGD,mDACC,iBAAA,CACA,WAAA,CACA,WAAA,CACA,UAAA,CACA,eAAA,CACA,yBAAA,CACA,+FAAA,CC7BJ,WACC,iBAAA,CACA,eAAA,CAEA,mCAEC,aAAA,CACA,mBAAA,CACA,UAAA,CACA,iBAAA,CAID,kBAGC,UAAA,CACA,UAAA,CACA,kBAAA,CACA,yBA3DW,CA4DX,WAhDa,CAkBb,qCAAA,CAoCD,iBACC,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,kBAnEa,CAoEb,8EAAA,CAGA,wBAAA,CApDA,cAAA,CA0DF,oBACC,GACC,oCAAA,CAAA,CAKF,qBACC,GACC,yBAAA,CAAA","file":"main.css"} \ No newline at end of file +{"version":3,"sources":["scss/_page.scss","scss/shared/_utils.scss","scss/_weather-display.scss","scss/shared/_colors.scss","scss/_current-weather.scss","scss/_extended-forecast.scss","scss/_hourly.scss","scss/_hourly-graph.scss","scss/_travel.scss","scss/_latest-observations.scss","scss/_local-forecast.scss","scss/_progress.scss","scss/_radar.scss","scss/_regional-forecast.scss","scss/_almanac.scss","scss/_hazards.scss","scss/_media.scss","scss/_spc-outlook.scss","scss/shared/_scanlines.scss"],"names":[],"mappings":"AAGA,WACC,sBAAA,CACA,gDAAA,CACA,iBAAA,CAGD,KACC,sBAAA,CACA,QAAA,CAEA,mCAJD,KAKE,qBAAA,CACA,UAAA,CAAA,CAIA,mCADD,OAEE,aAAA,CAAA,CAIF,WACC,UAAA,CACA,WAAA,CACA,eAAA,CACA,WAAA,CAEA,gCAAA,CAIF,UACC,eAAA,CACA,WAAA,CAEA,mBACC,oBAAA,CACA,WAAA,CACA,gBAAA,CAEA,8BACC,WAAA,CACA,qBAAA,CAGD,0BACC,cAAA,CACA,wBAAA,CAEA,mCAJD,0BAKE,qBAAA,CACA,UAAA,CAAA,CAQA,uCACC,YAAA,CAEA,mCAHD,uCAIE,oBAAA,CAAA,CAKD,mCADD,wCAEE,YAAA,CAAA,CAKH,qCACC,qBAAA,CAEA,mCAHD,qCAIE,qBAAA,CAAA,CAGD,yCACC,gBAAA,CAMJ,iCAEC,sBAAA,CAGD,uBACC,wBAAA,CACA,eAAA,CACA,cAAA,CACA,eAAA,CACA,oBAAA,CAGA,qBAAA,CACA,UAAA,CACA,qBAAA,CAEA,mCAZD,uBAaE,qBAAA,CACA,UAAA,CACA,qBAAA,CAAA,CAOH,0BACC,qBAAA,CACA,qBAAA,CACA,iBAAA,CACA,YAAA,CAEA,mCAND,0BAOE,qBAAA,CAAA,CAGD,8BAEC,kBAAA,CACA,eAAA,CACA,sBAAA,CACA,cAAA,CAEA,uCACC,qBAAA,CACA,UAAA,CAMH,QACC,aAAA,CACA,qBAAA,CACA,UAAA,CACA,UAAA,CACA,eAAA,CACA,QAAA,CAEA,aACC,eAAA,CAIF,iBACC,WAAA,CAGD,YACC,WAAA,CACA,YAAA,CAEA,kBACC,WAAA,CAIF,eACC,eAAA,CAGD,YACC,YAAA,CACA,gBAAA,CACA,qBAAA,CACA,qBAAA,CAGD,gBACC,MAAA,CACA,kBAAA,CACA,YAAA,CACA,qBAAA,CACA,sBAAA,CAGD,aACC,eAAA,CACA,YAAA,CACA,qBAAA,CACA,qBAAA,CAGD,iBACC,MAAA,CACA,iBAAA,CACA,YAAA,CACA,qBAAA,CACA,sBAAA,CAGD,cAEC,YAAA,CACA,kBAAA,CACA,qBAAA,CAEA,UAAA,CACA,WAAA,CAEA,oBACC,WAAA,CAGD,mCAbD,cAcE,wBAAA,CAAA,CAKF,kBACC,gBAAA,CACA,iBAAA,CAIA,yBAND,kBAOE,cAAA,CAAA,CAGD,yBAVD,kBAWE,cAAA,CAAA,CAGD,yBAdD,kBAeE,cAAA,CAAA,CAGD,yBAlBD,kBAmBE,cAAA,CAAA,CAGD,yBAtBD,kBAuBE,cAAA,CAAA,CAIF,kBACC,MAAA,CACA,eAAA,CAID,oBACC,MAAA,CACA,iBAAA,CAGD,mBACC,MAAA,CACA,gBAAA,CAGD,oBACC,YAAA,CAGD,WACC,UAAA,CACA,YAAA,CACA,kBAAA,CACA,qBAAA,CACA,UAAA,CACA,eAAA,CAGD,eACC,gBAAA,CACA,iBAAA,CAGD,eACC,MAAA,CACA,eAAA,CAGD,iBACC,MAAA,CACA,iBAAA,CAGD,gBACC,MAAA,CACA,gBAAA,CAGD,YACC,iBAAA,CACA,iBAAA,CAGD,YACC,sBAAA,CAGD,eACC,WAAA,CAGD,WACC,+BAAA,CACA,yDAAA,CACA,iBAAA,CAGD,WACC,4BAAA,CACA,sDAAA,CACA,iBAAA,CAGD,WACC,4BAAA,CACA,sDAAA,CACA,iBAAA,CAGD,SACC,sBAAA,CACA,cAAA,CACA,UAAA,CAGD,WACC,iBAAA,CACA,WAAA,CACA,YAAA,CAEA,iDAAA,CACA,oBAAA,CAGD,iBACC,kBAAA,CACA,mBAAA,CACA,2BAAA,CACA,gDAAA,CAGD,uCAGC,WAAA,CACA,YAAA,CAJD,wDAGC,WAAA,CACA,YAAA,CAGD,SACC,WAAA,CACA,YAAA,CACA,cAAA,CACA,wBAAA,CACA,YAAA,CACA,kBAAA,CACA,iBAAA,CACA,sBAAA,CAEA,gBACC,0BAAA,CACA,cAAA,CACA,UAAA,CACA,iBAAA,CAGD,kBACC,kBAAA,CAGD,uBACC,cAAA,CAIF,SACC,gBAAA,CACA,eAAA,CAGD,UACC,kBAAA,CAGD,2BAEC,kBAAA,CCvXA,4FAEC,UAAA,CAGD,mDACC,UAAA,CACA,cAAA,CAGD,2CACC,SAAA,CAGD,6CACC,YAAA,CAGD,+CACC,YAAA,CDuWD,mDACC,UAAA,CAGD,oCAEC,4FAEC,UAAA,CAGD,mDACC,UAAA,CACA,cAAA,CAGD,2CACC,UAAA,CAGD,6CACC,aAAA,CAGD,+CACC,aAAA,CAAA,CAIF,uCACC,aAAA,CACA,0BAAA,CAAA,qBAAA,CACA,cAAA,CAEA,qDACC,YAAA,CAEA,+DACC,cAAA,CACA,SAAA,CAMJ,kBACC,qBAAA,CAGA,yBACC,wBACC,kBAAA,CAAA,CAKH,4BAEC,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,oBAAA,CALD,kCAEC,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,oBAAA,CAEA,sCACC,WAAA,CADD,sDACC,WAAA,CAIF,qCAEC,iBAAA,CAFD,oDAEC,iBAAA,CAGD,0CAEC,YAAA,CACA,kBAAA,CACA,+BAAA,CACA,UAAA,CACA,UAAA,CACA,iBAAA,CACA,UAAA,CARD,8DAEC,YAAA,CACA,kBAAA,CACA,+BAAA,CACA,UAAA,CACA,UAAA,CACA,iBAAA,CACA,UAAA,CAIA,6BACC,YAAA,CAIF,WACC,cAAA,CAGD,iBACC,oBAAA,CAEA,qBACC,YAAA,CAGD,sBACC,oBAAA,CAKA,wBACC,oBAAA,CAGD,yBACC,YAAA,CAMH,SACC,kBAAA,CACA,SAAA,CACA,6BAAA,CAGD,oCACC,iBAAA,CACA,SAAA,CACA,qDAAA,CAAA,6CAAA,CAHD,2BACC,iBAAA,CACA,SAAA,CACA,6CAAA,CAGD,cACC,WAAA,CACA,4BAAA,CACA,YAAA,CACA,4BAAA,CACA,cAAA,CAGC,qBACC,oBAAA,CACA,SAAA,CAGD,2BACC,oBAAA,CACA,eAAA,CACA,gFAAA,CACA,WAAA,CACA,aAAA,CACA,kBAAA,CAGD,yDAEC,iBAAA,CACA,oBAAA,CACA,mBAAA,CACA,WAAA,CACA,eAAA,CACA,cAAA,CACA,eAAA,CACA,gBAAA,CACA,qBAAA,CACA,cAAA,CACA,wBAAA,CACA,qBAAA,CAEA,gBAAA,CACA,0BAAA,CACA,6BAAA,CACA,yBAAA,CACA,gBAAA,CAGD,wBACC,mBAAA,CAGD,yCACC,6BAAA,CAGD,iCACC,aAAA,CACA,6BAAA,CAGD,+EAEC,WAAA,CACA,gBAAA,CACA,cAAA,CACA,gBAAA,CAGD,4BACC,oBAAA,CACA,uBAAA,CACA,iBAAA,CACA,gBAAA,CAGD,qFAEC,yBAAA,CACA,mBAAA,CAGD,wBACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,8BACC,WAAA,CAGD,4DAEC,wBAAA,CACA,4BAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,wEAEC,WAAA,CAGD,+BACC,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,gDAAA,CACA,qBAAA,CACA,WAAA,CAGD,iCACC,aAAA,CACA,qBAAA,CACA,oBAAA,CACA,+BAAA,CAGD,8EAEC,aAAA,CAGD,kCACC,aAAA,CAGD,oCAEC,qFAEC,yBAAA,CACA,mBAAA,CAGD,wBACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,8BACC,WAAA,CAGD,4DAEC,wBAAA,CACA,4BAAA,CACA,oBAAA,CACA,+BAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,wEAEC,WAAA,CAGD,+BACC,wBAAA,CACA,oBAAA,CACA,+BAAA,CACA,gDAAA,CACA,qBAAA,CACA,WAAA,CAGD,iCACC,aAAA,CACA,qBAAA,CACA,oBAAA,CACA,+BAAA,CAGD,8EAEC,aAAA,CAGD,kCACC,aAAA,CAAA,CAIF,mCAEC,qFAEC,yBAAA,CACA,mBAAA,CAGD,wBACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,iCAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,8BACC,WAAA,CAGD,4DAEC,wBAAA,CACA,4BAAA,CACA,oBAAA,CACA,6SAAA,CAEA,8DAAA,CACA,qGAAA,CAGD,wEAEC,WAAA,CAGD,+BACC,wBAAA,CACA,oBAAA,CACA,6CAAA,CACA,qBAAA,CACA,WAAA,CAGD,iCACC,aAAA,CACA,wBAAA,CACA,oBAAA,CACA,iCAAA,CAGD,8EAEC,aAAA,CAGD,kCACC,aAAA,CAAA,CAMJ,mBACC,UAAA,CACA,YAAA,CAGD,yBACC,YAAA,CAID,kCACC,uBAAA,CAMA,sBACC,uBAAA,CE1yBF,iBACC,WAAA,CACA,YAAA,CACA,eAAA,CACA,iBAAA,CACA,iDAAA,CAGA,UAAA,CAEA,sBACC,YAAA,CAGD,2BACC,YAAA,CAGD,yBACC,WAAA,CACA,WAAA,CACA,gBAAA,CAEA,gCACC,UC3BW,CFMb,wKACC,CCsBC,sBAAA,CACA,cAAA,CACA,iBAAA,CACA,WAAA,CAEA,uCACC,UAAA,CACA,QAAA,CAGD,qCACC,UAAA,CAEA,yCACC,iBAAA,CAGD,0CACC,QAAA,CAGD,6CACC,QAAA,CAMH,+BACC,QAAA,CACA,SAAA,CACA,iBAAA,CACA,UAAA,CAGD,oCACC,iBAAA,CACA,QAAA,CACA,UAAA,CAGD,uCACC,QAAA,CAGD,oCACC,eAAA,CACA,UC3ES,CD4ET,4BAAA,CACA,cAAA,CDxEF,wKACC,CCyEC,UAAA,CACA,WAAA,CACA,gBAAA,CACA,iBAAA,CAEA,yCACC,gBAAA,CAKH,uBACC,iBAAA,CAEA,kCACC,WAAA,CACA,YAAA,CACA,YAAA,CACA,eAAA,CAEA,4CACC,YAAA,CACA,YAAA,CAIF,+BACC,gBAAA,CACA,iBAAA,CACA,wBAAA,CAMF,yBD7GA,wKACC,CC8GA,WAAA,CACA,WAAA,CACA,eAAA,CACA,cAAA,CAEA,gCACC,wBAAA,CAGD,wEAEC,gBAAA,CACA,iBAAA,CACA,eAAA,CAID,uCACC,aAAA,CACA,cAAA,CAGD,wCACC,WAAA,CACA,4BAAA,CACA,cAAA,CACA,gBAAA,CAGD,gCACC,sBAAA,CACA,cAAA,CAEA,6CACC,gBAAA,CACA,iBAAA,CElJF,iDACC,WAAA,CACA,WAAA,CACA,oBAAA,CACA,eAAA,CACA,gBAAA,CACA,iBAAA,CHNF,wKACC,CGSC,sDACC,+BAAA,CACA,cAAA,CAID,uDACC,SAAA,CACA,4BAAA,CACA,cAAA,CACA,gBAAA,CACA,gBAAA,CAEA,4DACC,kBAAA,CAEA,sIAEC,oBAAA,CAGD,mEACC,gBAAA,CAGD,mEACC,WAAA,CACA,iBAAA,CAQJ,oDACC,iBAAA,CAGD,kDACC,4BAAA,CACA,cAAA,CAIA,sDACC,aAAA,CACA,aAAA,CAIF,4DACC,gBAAA,CACA,YAAA,CAEA,gEACC,SAAA,CAGD,kEACC,gBAAA,CAIF,wDACC,gBAAA,CACA,cAAA,CAGD,sDACC,UDtFW,CCuFX,eAAA,CACA,kBAAA,CACA,eAAA,CACA,eAAA,CACA,gBAAA,CCxFH,wCACC,mDAAA,CAIA,wDACC,eAAA,CACA,gBAAA,CAGD,8CJPA,wKACC,CIQA,WAAA,CACA,YAAA,CACA,WAAA,CACA,oBAAA,CACA,eAAA,CACA,sBAAA,CACA,cAAA,CAEA,oDACC,wBAAA,CACA,iBAAA,CACA,UF1BW,CE6BZ,yDACC,iBAAA,CACA,WAAA,CACA,cAAA,CAGD,oDACC,iBAAA,CACA,WAAA,CAEA,wDACC,eAAA,CAIF,4DACC,UAAA,CAEA,+EACC,oBAAA,CACA,SAAA,CACA,kBAAA,CAEA,mFACC,iBAAA,CAGD,sFACC,4BAAA,CACA,cAAA,CAGD,yFACC,aFhDU,CEmDX,yFACC,UFlES,CGIb,mCACC,iBAAA,CAEA,mDACC,wBHJa,CGKb,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,mDACC,eAAA,CACA,OAAA,CACA,SAAA,CAEA,uDACC,oBAAA,CACA,4BAAA,CACA,cAAA,CACA,UHpBiB,CGqBjB,iBAAA,CACA,SAAA,CACA,SAAA,CLpBH,wKACC,CKuBC,yDACC,UAAA,CAGD,yDACC,UAAA,CAGD,yDACC,UAAA,CAIF,iDACC,gBAAA,CACA,gBAAA,CAEA,oGAAA,CAMA,6DACC,4BAAA,CACA,cAAA,CACA,WAAA,CACA,UHzDU,CFMb,wKACC,CKoDE,iBAAA,CAEA,iEACC,iBAAA,CACA,eAAA,CACA,OAAA,CAGD,mEACC,SAAA,CAGD,mEACC,UAAA,CACA,UAAA,CACA,iBAAA,CACA,SAAA,CAGD,mEACC,UAAA,CAGD,mEACC,UAAA,CAEA,8EACC,UAAA,CAGD,8EACC,aH5ES,CGgFX,mEACC,UAAA,CACA,WAAA,CACA,gBAAA,CC9FL,mBACC,uDAAA,CAGC,kCACC,iBAAA,CACA,QAAA,CACA,UAAA,CACA,WAAA,CACA,4BAAA,CACA,cAAA,CNPF,wKACC,CMQC,gBAAA,CAEA,sCACC,gBAAA,CAGD,+CACC,SAAA,CAGD,yCACC,aAAA,CAGD,wCACC,UAAA,CASF,6CACC,iBAAA,CAGD,gDACC,4BAAA,CACA,cAAA,CACA,UJ3CkB,CFGpB,wKACC,CMyCC,gBAAA,CACA,iBAAA,CAGD,iDACC,UAAA,CACA,QAAA,CACA,WAAA,CACA,WAAA,CAEA,wDACC,iBAAA,CACA,UAAA,CAEA,4DACC,SAAA,CAGD,4DACC,UAAA,CAGD,4DACC,UAAA,CAGD,4DACC,UAAA,CAGD,4DACC,UAAA,CAQH,gDACC,OAAA,CACA,SAAA,CAEA,oDACC,WAAA,CACA,YAAA,CAIF,iDACC,OAAA,CACA,QAAA,CACA,UAAA,CACA,YAAA,CAEA,wDACC,gBAAA,CACA,SAAA,CAEA,4DACC,OAAA,CAGD,4DACC,SAAA,CAGD,4DACC,UAAA,CAKH,yDACC,wBJtHa,CIuHb,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,yDACC,eAAA,CACA,OAAA,CACA,SAAA,CAGA,+DACC,UAAA,CAGD,+DACC,UAAA,CAGD,+DACC,UAAA,CC3IH,mCACC,iBAAA,CAEA,mDACC,wBLJa,CKKb,WAAA,CACA,eAAA,CACA,OAAA,CACA,UAAA,CACA,SAAA,CACA,eAAA,CAEA,uDACC,oBAAA,CACA,4BAAA,CACA,cAAA,CACA,ULjBiB,CKkBjB,iBAAA,CACA,SAAA,CACA,SAAA,CPjBH,wKACC,COoBC,yDACC,UAAA,CACA,iBAAA,CAEA,6DACC,UAAA,CAID,8DACC,UAAA,CACA,UAAA,CAKH,iDACC,gBAAA,CACA,gBAAA,CAEA,oGAAA,CAMA,6DACC,4BAAA,CACA,cAAA,CACA,WAAA,CACA,ULzDU,CFMb,wKACC,COoDE,iBAAA,CAEA,iEACC,iBAAA,CACA,eAAA,CACA,OAAA,CAGD,mEACC,SAAA,CAGD,mEACC,UAAA,CACA,UAAA,CACA,iBAAA,CACA,SAAA,CAEA,uEACC,cAAA,CAIF,mEACC,UAAA,CACA,iBAAA,CAEA,uEACC,UAAA,CAGD,wEACC,UAAA,CACA,UAAA,CCvFL,2CACC,iBAAA,CAEA,2DACC,WAAA,CACA,iBAAA,CACA,UAAA,CAGD,2DACC,OAAA,CAEA,+DACC,oBAAA,CACA,4BAAA,CACA,cAAA,CACA,iBAAA,CACA,SAAA,CRhBH,wKACC,CQmBC,iEAEC,YAAA,CAEA,sEACC,oBAAA,CAKH,iDACC,UAAA,CAGD,oDACC,UAAA,CAGD,iDACC,UAAA,CAGD,8DACC,gBAAA,CACA,gBAAA,CAEA,+EACC,sBAAA,CACA,cAAA,CRhDH,wKACC,CQiDE,iBAAA,CACA,WAAA,CAEA,mFACC,iBAAA,CACA,OAAA,CAGD,qFACC,eAAA,CACA,gBAAA,CC9DJ,4CACC,iBAAA,CACA,QAAA,CACA,eAAA,CACA,qBAAA,CACA,YAAA,CACA,eAAA,CAGD,4CACC,iBAAA,CAGD,2CACC,sBAAA,CACA,cAAA,CACA,wBAAA,CTdD,wKACC,CSeA,gBAAA,CACA,gBAAA,CCpBF,2BVGC,wKACC,CUFD,+BAAA,CACA,cAAA,CAEA,sCACC,iBAAA,CACA,QAAA,CACA,eAAA,CACA,qBAAA,CACA,YAAA,CACA,eAAA,CACA,gBAAA,CAEA,4CACC,iBAAA,CAEA,kDACC,kBAAA,CAEA,yDACC,kFAAA,CAIF,mDACC,iBAAA,CACA,gBAAA,CACA,SAAA,CACA,OAAA,CAEA,uDACC,wBRnBM,CQoBN,YAAA,CACA,gBAAA,CVjBJ,yHAEC,UAAA,CAGD,+DACC,UAAA,CACA,cAAA,CAGD,2DACC,SAAA,CAGD,4DACC,YAAA,CAGD,6DACC,YAAA,CUGE,gaAMC,aAAA,CAYJ,2BACC,GACC,2BAAA,CAGD,KACC,0BAAA,CAAA,CAIF,+DACC,qBAAA,CACA,qBAAA,CACA,gBAAA,CACA,WAAA,CACA,iBAAA,CACA,YAAA,CAEA,oEACC,aAAA,CAGD,6EACC,WAAA,CACA,UAAA,CACA,WAAA,CACA,4OAAA,CAiBA,qBAAA,CACA,4BAAA,CACA,kCAAA,CACA,8BAAA,CACA,uCAAA,CAGD,sEACC,iBAAA,CACA,OAAA,CACA,SAAA,CACA,qBAAA,CACA,UAAA,CACA,WAAA,CACA,4BAAA,CClHH,4BACC,mDAAA,CAEA,oCACC,WAAA,CAEA,gDACC,UAAA,CACA,8BAAA,CACA,gBAAA,CACA,cAAA,CACA,UAAA,CAEA,qDACC,QAAA,CAGD,wDACC,QAAA,CAIF,2CACC,iBAAA,CACA,SAAA,CACA,WAAA,CACA,cAAA,CACA,sBAAA,CACA,cAAA,CACA,gBAAA,CX1BF,wKACC,CW2BC,iBAAA,CAEA,sDACC,oBAAA,CAGD,wDACC,iBAAA,CACA,wBAAA,CAEA,6DACC,kBAAA,CACA,qBAAA,CACA,UAAA,CACA,WAAA,CACA,SAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAGD,+DACC,wBAAA,CAKD,wDACC,iBAAA,CACA,QAAA,CAIF,iDACC,iBAAA,CACA,kBAAA,CACA,SAAA,CACA,4BAAA,CACA,cAAA,CAMJ,6BACC,eAAA,CACA,YAAA,CAIC,+CACC,iBAAA,CACA,YAAA,CAEA,mDACC,qBAAA,CAIF,qDACC,iBAAA,CAKH,uBACC,gDAAA,CC1HD,wCACC,mDAAA,CAGD,yCAGC,iBAAA,CAEA,8CACC,iBAAA,CACA,oBAAA,CAGD,mDACC,iBAAA,CACA,WAAA,CACA,iBAAA,CACA,gBAAA,CAEA,uDACC,iBAAA,CZlBF,wKACC,CYqBA,yDACC,QAAA,CACA,SAAA,CAEA,6DACC,eAAA,CAIF,yDACC,4BAAA,CACA,cAAA,CACA,eAAA,CACA,UVzCW,CU0CX,QAAA,CACA,gBAAA,CACA,UAAA,CAGD,yDACC,oBAAA,CACA,cAAA,CC9CH,8BACC,mDAAA,CAGD,+BACC,sBAAA,CACA,cAAA,CbHA,wKACC,CaKD,oCAGC,YAAA,CACA,oCAAA,CACA,iCAAA,CACA,YAAA,CACA,wBAAA,CACA,sBAAA,CAAA,iBAAA,CACA,gBAAA,CAEA,+CAEC,UAAA,CACA,WAAA,CACA,SAAA,CACA,QAAA,CACA,iBAAA,CAGA,sDACC,UX9BiB,CW+BjB,iBAAA,CAID,yDAEC,gBAAA,CAID,oDACC,iBAAA,CAKH,qCACC,iBAAA,CACA,gBAAA,CACA,gBAAA,CAEA,4CACC,UXrDkB,CWsDlB,iBAAA,CAGD,0CACC,oBAAA,CACA,iBAAA,CACA,WAAA,CAEA,gDAEC,iBAAA,CAGD,gDACC,iBAAA,CACA,SAAA,CCpEH,oCACC,iBAAA,CACA,YAAA,CACA,wBAAA,CAEA,kDACC,gBAAA,CACA,gBAAA,CAEA,0DACC,sBAAA,CACA,cAAA,CACA,UAAA,CdVH,wKACC,CcWE,iBAAA,CACA,wBAAA,CACA,eAAA,CACA,gBAAA,CACA,iBAAA,CACA,mBAAA,CCvBJ,OACC,YAAA,CAGD,aACC,YAAA,CAEA,uBACC,oBAAA,CAEA,8BACC,YAAA,CAGD,+BACC,aAAA,CAKA,sCACC,aAAA,CAGD,uCACC,YAAA,CCtBJ,kCACC,mDAAA,CAKA,yCACC,iBAAA,CACA,OAAA,CACA,eAAA,CACA,qBAAA,CACA,YAAA,CACA,eAAA,CAGD,2CACC,iBAAA,CACA,UAAA,CACA,4BAAA,CACA,cAAA,ChBhBD,wKACC,CgBmBA,uDACC,iBAAA,CACA,SAAA,CACA,WAAA,CAEA,oEACC,UAAA,CAGD,oEACC,SAAA,CAGD,oEACC,SAAA,CAGD,oEACC,SAAA,CAGD,oEACC,SAAA,CAGD,oEACC,QAAA,CAKH,oCACC,iBAAA,CACA,SAAA,CAEA,yCACC,WAAA,CAEA,mDACC,iBAAA,CACA,sBAAA,CACA,cAAA,CACA,WAAA,CACA,gBAAA,ChB/DH,wKACC,CgBgEE,gBAAA,CAGD,mDACC,iBAAA,CACA,WAAA,CACA,WAAA,CACA,UAAA,CACA,eAAA,CACA,yBAAA,CACA,+FAAA,CC5BJ,WACC,iBAAA,CACA,eAAA,CAEA,mCAEC,aAAA,CACA,mBAAA,CACA,UAAA,CACA,iBAAA,CAID,kBAGC,UAAA,CACA,UAAA,CACA,kBAAA,CACA,yBA3DW,CA4DX,WAhDa,CAkBb,qCAAA,CAoCD,iBACC,KAAA,CACA,OAAA,CACA,QAAA,CACA,MAAA,CACA,kBAnEa,CAqEb,+HAAA,CAlDA,cAAA,CA0DA,2BAAA,CACA,yBAAA,CAQD,kBACC,qCAAA,CAGD,iBACC,0NAAA,CASF,oBACC,GACC,oCAAA,CAAA,CAKF,qBACC,GACC,yBAAA,CAAA","file":"main.css"} \ No newline at end of file diff --git a/server/styles/scss/_almanac.scss b/server/styles/scss/_almanac.scss index 54356b1..ffe943d 100644 --- a/server/styles/scss/_almanac.scss +++ b/server/styles/scss/_almanac.scss @@ -1,5 +1,5 @@ -@use 'shared/_colors'as c; -@use 'shared/_utils'as u; +@use 'shared/_colors' as c; +@use 'shared/_utils' as u; #almanac-html.weather-display { background-image: url('../images/backgrounds/3.png'); @@ -11,62 +11,57 @@ @include u.text-shadow(); .sun { - display: table; - margin-left: 50px; - height: 100px; + // Use CSS Grid for cross-browser consistency + // Grid is populated in reading order (left-to-right, top-to-bottom): + display: grid; + grid-template-columns: auto auto auto; + grid-template-rows: auto auto auto; + gap: 0px 90px; + margin: 3px auto 5px auto; // align the bottom of the div with the background + width: fit-content; + line-height: 30px; - - &>div { - display: table-row; + .grid-item { + // Reset inherited styles that interfere with grid layout + width: auto; + height: auto; + padding: 0; + margin: 0; position: relative; - &>div { - display: table-cell; - } - } - - .days { - color: c.$column-header-text; - text-align: right; - top: -5px; - - .day { - padding-right: 10px; + // Column headers (day names) + &.header { + color: c.$column-header-text; + text-align: center; } - } - - .times { - text-align: right; - - .sun-time { - width: 200px; + // Row labels (Sunrise:, Sunset:) + &.row-label { + // color: c.$column-header-text; // screenshots show labels were white + text-align: right; } - &.times-1 { - top: -10px; - } - - &.times-2 { - top: -15px; + // Time values (sunrise/sunset) + &.time { + text-align: center; } } } .moon { position: relative; - top: -10px; - - padding: 0px 60px; + padding: 7px 50px; + line-height: 36px; .title { color: c.$column-header-text; + padding-left: 13px; } .day { display: inline-block; text-align: center; - width: 130px; + width: 132px; .icon { // shadow in image make it look off center @@ -82,4 +77,4 @@ -} \ No newline at end of file +} diff --git a/server/styles/scss/_current-weather.scss b/server/styles/scss/_current-weather.scss index eca3954..4606de3 100644 --- a/server/styles/scss/_current-weather.scss +++ b/server/styles/scss/_current-weather.scss @@ -1,5 +1,5 @@ -@use 'shared/_colors'as c; -@use 'shared/_utils'as u; +@use 'shared/_colors' as c; +@use 'shared/_utils' as u; .weather-display .main.current-weather { &.main { @@ -58,27 +58,19 @@ font-size: 24pt; } - .condition {} - .icon { - height: 100px; - img { - max-width: 126px; + margin: 0 auto; + display: block; } } .wind-container { - margin-bottom: 10px; + margin-left: 10px; + display: flex; &>div { - width: 45%; - display: inline-block; - margin: 0px; - } - - .wind-label { - margin-left: 5px; + width: 50%; } .wind { @@ -87,7 +79,8 @@ } .wind-gusts { - margin-left: 5px; + text-align: right; + font-size: 28px; } .location { @@ -99,4 +92,4 @@ text-wrap: nowrap; } } -} \ No newline at end of file +} diff --git a/server/styles/scss/_hazards.scss b/server/styles/scss/_hazards.scss index b2473be..8e94316 100644 --- a/server/styles/scss/_hazards.scss +++ b/server/styles/scss/_hazards.scss @@ -1,17 +1,16 @@ -@use 'shared/_colors'as c; -@use 'shared/_utils'as u; +@use 'shared/_colors' as c; +@use 'shared/_utils' as u; .weather-display .main.hazards { &.main { overflow-y: hidden; height: 480px; + background-color: rgb(112, 35, 35); .hazard-lines { min-height: 400px; padding-top: 10px; - background-color: rgb(112, 35, 35); - .hazard { font-family: 'Star4000'; font-size: 24pt; @@ -26,4 +25,4 @@ } } } -} \ No newline at end of file +} diff --git a/server/styles/scss/_page.scss b/server/styles/scss/_page.scss index f6bf8af..3f7ade2 100644 --- a/server/styles/scss/_page.scss +++ b/server/styles/scss/_page.scss @@ -1,5 +1,5 @@ -@use 'shared/_utils'as u; -@use 'shared/_colors'as c; +@use 'shared/_utils' as u; +@use 'shared/_colors' as c; @font-face { font-family: "Star4000"; @@ -9,6 +9,7 @@ body { font-family: "Star4000"; + margin: 0; @media (prefers-color-scheme: dark) { background-color: #000000; @@ -23,13 +24,17 @@ body { &.kiosk { margin: 0px; + padding: 0px; overflow: hidden; width: 100vw; + // Always use black background in kiosk mode, regardless of light/dark preference + background-color: #000000 !important; } } #divQuery { max-width: 640px; + padding: 8px; .buttons { display: inline-block; @@ -89,17 +94,22 @@ body { font-family: "Star4000"; } - #txtAddress { + #txtLocation { width: calc(100% - 170px); max-width: 490px; font-size: 16pt; min-width: 200px; display: inline-block; + // Ensure consistent styling across light and dark modes + background-color: white; + color: black; + border: 2px inset #808080; + @media (prefers-color-scheme: dark) { background-color: #000000; color: white; - border: 1px solid darkgray; + border: 2px inset #808080; } } @@ -137,12 +147,26 @@ body { color: #ffffff; width: 100%; max-width: 640px; + margin: 0; // Ensure edge-to-edge display &.wide { max-width: 854px; } } +.content-wrapper { + padding: 8px; +} + +#divTwcMain { + width: 640px; + height: 480px; + + .wide & { + width: 854px; + } +} + .kiosk #divTwc { max-width: unset; } @@ -184,7 +208,11 @@ body { background-color: #000000; color: #ffffff; - width: 100%; + width: 640px; + + .wide & { + width: 854px; + } @media (prefers-color-scheme: dark) { background-color: rgb(48, 48, 48); @@ -196,25 +224,26 @@ body { padding-left: 6px; padding-right: 6px; - // scale down the buttons on narrower screens + // Use font-size scaling instead of zoom/transform to avoid layout gaps and preserve icon tap targets. + // While not semantically ideal, it works well for our fixed-layout design. @media (max-width: 550px) { - zoom: 0.90; + font-size: 0.90em; } @media (max-width: 500px) { - zoom: 0.80; + font-size: 0.80em; } @media (max-width: 450px) { - zoom: 0.70; + font-size: 0.70em; } @media (max-width: 400px) { - zoom: 0.60; + font-size: 0.60em; } @media (max-width: 350px) { - zoom: 0.50; + font-size: 0.50em; } } @@ -325,7 +354,6 @@ body { // background-image: none; width: unset; height: unset; - transform-origin: unset; } #loading { @@ -399,7 +427,8 @@ body { label { display: block; - max-width: 300px; + max-width: fit-content; + cursor: pointer; .alert { display: none; @@ -414,6 +443,13 @@ body { #divTwcBottom img { transform: scale(0.75); + + // Make icons larger in widescreen mode on mobile + @media (max-width: 550px) { + .wide & { + transform: scale(1.0); // Larger icons in widescreen + } + } } #divTwc:fullscreen, @@ -446,9 +482,7 @@ body { .kiosk { #divTwc #divTwcBottom { - >div { - display: none; - } + display: none; } } @@ -768,15 +802,15 @@ body { display: none; } +// Hide instructions in kiosk mode (higher specificity than the show rule) +body.kiosk #loading .instructions { + display: none !important; +} + .kiosk { - #divQuery, - >.info, - >.related-links, - >.heading, - #enabledDisplays, - #settings, - #divInfo { - display: none; + // In kiosk mode, hide everything except the main weather display + >*:not(#divTwc) { + display: none !important; } -} \ No newline at end of file +} diff --git a/server/styles/scss/_progress.scss b/server/styles/scss/_progress.scss index 2bfcea0..98a3c6c 100644 --- a/server/styles/scss/_progress.scss +++ b/server/styles/scss/_progress.scss @@ -1,5 +1,5 @@ -@use 'shared/_colors'as c; -@use 'shared/_utils'as u; +@use 'shared/_colors' as c; +@use 'shared/_utils' as u; .weather-display .progress { @include u.text-shadow(); @@ -13,6 +13,7 @@ box-sizing: border-box; height: 310px; overflow: hidden; + line-height: 28px; .item { position: relative; @@ -117,4 +118,4 @@ transition: width 1s steps(6); } } -} \ No newline at end of file +} diff --git a/server/styles/scss/_travel.scss b/server/styles/scss/_travel.scss index 08f8f0e..add8642 100644 --- a/server/styles/scss/_travel.scss +++ b/server/styles/scss/_travel.scss @@ -1,5 +1,5 @@ -@use 'shared/_colors'as c; -@use 'shared/_utils'as u; +@use 'shared/_colors' as c; +@use 'shared/_utils' as u; .weather-display .main.travel { &.main { @@ -8,14 +8,11 @@ .column-headers { background-color: c.$column-header; height: 20px; - position: absolute; - width: 100%; - } - - .column-headers { position: sticky; top: 0px; + width: 100%; z-index: 5; + overflow: hidden; // prevent thin gaps between header and content div { display: inline-block; @@ -100,4 +97,4 @@ } } } -} \ No newline at end of file +} diff --git a/server/styles/scss/_weather-display.scss b/server/styles/scss/_weather-display.scss index 24d1c24..fd7ed22 100644 --- a/server/styles/scss/_weather-display.scss +++ b/server/styles/scss/_weather-display.scss @@ -1,5 +1,5 @@ -@use 'shared/_colors'as c; -@use 'shared/_utils'as u; +@use 'shared/_colors' as c; +@use 'shared/_utils' as u; .weather-display { width: 640px; @@ -94,11 +94,13 @@ &.has-scroll { width: 640px; + margin-top: 0; height: 310px; overflow: hidden; &.no-header { height: 400px; + margin-top: 0; // Reset for no-header case since the gap issue is header-related } } @@ -129,6 +131,12 @@ overflow: hidden; } + // Remove margins for hazard scrolls to maximize text space + &.hazard .fixed { + margin-left: 0; + margin-right: 0; + } + .scroll-header { height: 26px; font-family: "Star4000 Small"; @@ -150,4 +158,4 @@ } } -} \ No newline at end of file +} diff --git a/server/styles/scss/shared/_scanlines.scss b/server/styles/scss/shared/_scanlines.scss index 70c664a..66636f1 100644 --- a/server/styles/scss/shared/_scanlines.scss +++ b/server/styles/scss/shared/_scanlines.scss @@ -1,7 +1,8 @@ /* REGULAR SCANLINES SETTINGS */ -// width of 1 scanline (min.: 1px) +// width of 1 scanline (responsive units to prevent banding) $scan-width: 1px; +$scan-width-scaled: 0.15vh; // viewport-relative unit for better scaling // emulates a damage-your-eyes bad pre-2000 CRT screen ♥ (true, false) $scan-crt: false; @@ -75,18 +76,41 @@ $scan-opacity: .75; @include scan-moving($scan-moving-line); } - // the scanlines, so! + // the scanlines, so! - with responsive scaling for low-res displays &:after { top: 0; right: 0; bottom: 0; left: 0; z-index: $scan-z-index; - background: linear-gradient(to bottom, - transparent 50%, - $scan-color 51%); - background-size: 100% $scan-width*2; + // repeating-linear-gradient is more efficient than linear-gradient+background-size because it doesn't require the browser to calculate tiling + background: repeating-linear-gradient(to bottom, + transparent 0, + transparent $scan-width, + $scan-color $scan-width, + $scan-color calc($scan-width * 2)); @include scan-crt($scan-crt); + + // Prevent sub-pixel aliasing on scaled displays + image-rendering: crisp-edges; + image-rendering: pixelated; + } + + // Scanlines use dynamic thickness calculated by JavaScript + // JavaScript calculates optimal thickness to prevent banding at any scale factor + // The --scanline-thickness custom property is set by applyScanlineScaling() + // The modes (hairline, thin, medium, thick) force the base thickness selection + // Some modes may appear the same (e.g. hairline and thin) depending on the display + &:before { + height: var(--scanline-thickness, $scan-width); + } + + &:after { + background: repeating-linear-gradient(to bottom, + transparent 0, + transparent var(--scanline-thickness, $scan-width), + $scan-color var(--scanline-thickness, $scan-width), + $scan-color calc(var(--scanline-thickness, $scan-width) * 2)); } } @@ -103,4 +127,4 @@ $scan-opacity: .75; background-position: 0 50%; // bottom: 0%; // to have a continuous scanline move, use this line (here in 0% step) instead of transform and write, in &:before, { position: absolute; bottom: 100%; } } -} \ No newline at end of file +} diff --git a/tests/index.mjs b/tests/index.mjs index e1d9ac4..198dc8e 100644 --- a/tests/index.mjs +++ b/tests/index.mjs @@ -21,7 +21,7 @@ page.on('console', messageFormatter); const tester = async (location, testPage) => { // Set the address - await testPage.type('#txtAddress', location); + await testPage.type('#txtLocation', location); await setTimeout(500); // get the page await testPage.click('#btnGetLatLng'); diff --git a/views/index.ejs b/views/index.ejs index 005ec3e..bb66069 100644 --- a/views/index.ejs +++ b/views/index.ejs @@ -14,26 +14,34 @@ - - - - - - - - + + + + + + + + + <% if (typeof serverAvailable !== 'undefined' && serverAvailable) { %> + + <% } %> <% if (production) { %> - - + <% } else { %> - - - + + + @@ -53,82 +61,78 @@ - - - - - - - + + + <% } %> - +class="kiosk" <% }%>> +
+ +
+ + + +
+
+ -
- -
- - - -
-
- - -
-
-
-
-
WeatherStar 4000+
-
v<%- version %>
-
Enter your location above to continue
+
+
+
+
+
+
WeatherStar 4000+
+
v<%- version %>
+
Enter your location above to continue
+
+
+
+ <%- include('partials/progress.ejs') %> +
+
+ <%- include('partials/hourly.ejs') %> +
+
+ <%- include('partials/hourly-graph.ejs') %> +
+
+ <%- include('partials/travel.ejs') %> +
+
+ <%- include('partials/current-weather.ejs') %> +
+
+ <%- include('partials/local-forecast.ejs') %> +
+
+ <%- include('partials/latest-observations.ejs') %> +
+
+ <%- include('partials/regional-forecast.ejs') %> +
+
+ <%- include('partials/almanac.ejs') %> +
+
+ <%- include('partials/spc-outlook.ejs') %> +
+
+ <%- include('partials/extended-forecast.ejs') %> +
+
+ <%- include('partials/radar.ejs') %> +
+
+ <%- include('partials/hazards.ejs') %>
-
-
- <%- include('partials/progress.ejs') %> -
-
- <%- include('partials/hourly.ejs') %> -
-
- <%- include('partials/hourly-graph.ejs') %> -
-
- <%- include('partials/travel.ejs') %> -
-
- <%- include('partials/current-weather.ejs') %> -
-
- <%- include('partials/local-forecast.ejs') %> -
-
- <%- include('partials/latest-observations.ejs') %> -
-
- <%- include('partials/regional-forecast.ejs') %> -
-
- <%- include('partials/almanac.ejs') %> -
-
- <%- include('partials/spc-outlook.ejs') %> -
-
- <%- include('partials/extended-forecast.ejs') %> -
-
- <%- include('partials/radar.ejs') %> -
-
- <%- include('partials/hazards.ejs') %>
@@ -142,55 +146,56 @@
-
- - -
-
- - -
+
+ + +
+
+ + +
-
+
+
-
- More information + +
+ +
Selected displays
+
+ +
+ +
Settings
+
+
+ +
Sharing
+
+ Copy Permalink Link copied to clipboard! + +
+ +
Forecast Information
+
+ Location:
+ Station Id:
+ Radar Id:
+ Zone Id:
+ Music: Not playing
+ Ws4kp Version: <%- version %> +
-
- -
Selected displays
-
- -
- -
Settings
-
-
- -
Sharing
-
- Copy Permalink Link copied to clipboard! - -
-
- -
Forecast Information
-
- Location:
- Station Id:
- Radar Id:
- Zone Id:
- Music: Not playing
- Ws4kp Version: <%- version %> -
- \ No newline at end of file + diff --git a/views/partials/almanac.ejs b/views/partials/almanac.ejs index fa8f81a..6bf0a09 100644 --- a/views/partials/almanac.ejs +++ b/views/partials/almanac.ejs @@ -1,21 +1,15 @@ <%- include('header.ejs', {title:'Almanac', hasTime: true}) %>
-
-
-
Monday
-
Tuesday
-
-
-
Sunrise:
-
6:24 am
-
6:25 am
-
-
-
Sunset:
-
6:24 am
-
6:25 am
-
+
+
+
+
Sunrise:
+
+
+
Sunset:
+
+
Moon Data:
@@ -28,4 +22,4 @@
-<%- include('scroll.ejs') %> \ No newline at end of file +<%- include('scroll.ejs') %> diff --git a/ws4kp.code-workspace b/ws4kp.code-workspace index fbbdf04..67581ec 100644 --- a/ws4kp.code-workspace +++ b/ws4kp.code-workspace @@ -1,72 +1,85 @@ -{ - "folders": [ - { - "path": "." - } - ], - "settings": { - "search.exclude": { - "**/*.code-search": true, - "**/*.css": true, - "**/*.min.js": true, - "**/bower_components": true, - "**/node_modules": true, - "**/vendor": true, - "dist/**": true - }, - "cSpell.enabledFileTypes": { - "markdown": true, - "JavaScript": true - }, - "cSpell.enabled": true, - "cSpell.ignoreWords": [ - "'storm", - "arcgis", - "Battaglia", - "devbridge", - "gifs", - "ltrim", - "mbar", - "Noaa", - "nosleep", - "Pngs", - "PRECIP", - "rtrim", - "sonarjs", - "T", - "T'storm", - "uscomp", - "Visib", - "Waukegan", - "WSQS", - "Tucsan", - "Malek", - "mwood", - "unmuted", - "dumpio", - "mesonet" - ], - "cSpell.ignorePaths": [ - "**/package-lock.json", - "**/node_modules/**", - "**/vscode-extension/**", - "**/.git/objects/**", - ".vscode", - ".vscode-insiders", - "**/vendor/auto/**", - ], - "editor.tabSize": 2, - "emmet.includeLanguages": { - "ejs": "html", - }, - "[html]": { - "editor.defaultFormatter": "j69.ejs-beautify" - }, - "files.exclude": {}, - "files.eol": "\n", - "editor.formatOnSave": true, - "editor.codeActionsOnSave": { - "source.fixAll.eslint": "explicit" - }, - }, -} \ No newline at end of file +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "search.exclude": { + "**/*.code-search": true, + "**/*.css": true, + "**/*.min.js": true, + "**/bower_components": true, + "**/node_modules": true, + "**/vendor": true, + "dist/**": true + }, + "cSpell.enabledFileTypes": { + "markdown": true, + "JavaScript": true + }, + "cSpell.enabled": true, + "cSpell.ignoreWords": [ + "'storm", + "arcgis", + "Battaglia", + "devbridge", + "gifs", + "ltrim", + "mbar", + "Noaa", + "nosleep", + "Pngs", + "PRECIP", + "rtrim", + "sonarjs", + "T", + "T'storm", + "uscomp", + "Visib", + "Waukegan", + "WSQS", + "Tucsan", + "Malek", + "mwood", + "unmuted", + "dumpio", + "mesonet" + ], + "cSpell.ignorePaths": [ + "**/package-lock.json", + "**/node_modules/**", + "**/vscode-extension/**", + "**/.git/objects/**", + ".vscode", + ".vscode-insiders", + "**/vendor/auto/**", + ], + "editor.tabSize": 2, + "editor.insertSpaces": false, // .eslintrc wants tabs instead of spaces + "emmet.includeLanguages": { + "ejs": "html", + }, + "[ejs]": { + "editor.occurrencesHighlight": "off", + "editor.defaultFormatter": "j69.ejs-beautify" + }, + "files.exclude": {}, + "files.eol": "\n", + "files.associations": { + "*.ejs": "ejs" + }, + "editor.formatOnSave": true, + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } + }, + "extensions": { + "recommendations": [ + "digitalbrainstem.javascript-ejs-support", // EJS (Embedded JavaScript) template language support + "dbaeumer.vscode-eslint", // ESLint JavaScript linting integration + "streetsidesoftware.code-spell-checker", + "j69.ejs-beautify", + ] + } +}