diff --git a/package-lock.json b/package-lock.json
index 3202b3a..7ab1ce7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -13,7 +13,7 @@
"devDependencies": {
"@eslint/compat": "^2.0.2",
"@eslint/js": "^9.39.2",
- "@owlboard/owlboard-ts": "^3.0.0-dev.20260325T1023",
+ "@owlboard/owlboard-ts": "^3.0.0-dev.202603302258",
"@playwright/test": "^1.58.1",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.50.2",
@@ -780,20 +780,21 @@
}
},
"node_modules/@owlboard/api-schema-types": {
- "version": "3.0.2-alpha2",
- "resolved": "https://git.fjla.uk/api/packages/OwlBoard/npm/%40owlboard%2Fapi-schema-types/-/3.0.2-alpha2/api-schema-types-3.0.2-alpha2.tgz",
- "integrity": "sha512-KyX4QcOCzVqYpiXY+WfhM1soXduMt2ldG6JSBK2WBxXWokS+keZshOHWHGTZvPLoZEWsuPznMAdzytI03/D3Ag==",
+ "version": "3.0.2-alpha3",
+ "resolved": "https://git.fjla.uk/api/packages/OwlBoard/npm/%40owlboard%2Fapi-schema-types/-/3.0.2-alpha3/api-schema-types-3.0.2-alpha3.tgz",
+ "integrity": "sha512-3NFP21QdSfjziwlGQixlNnUWC55HlKZGyWANIOimWu0FZejWQWExJiaAVfb6m3Sbv+zvQMu3B8mzcMCcGadZCQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@owlboard/owlboard-ts": {
- "version": "3.0.0-dev.20260325T1023",
- "resolved": "https://git.fjla.uk/api/packages/OwlBoard/npm/%40owlboard%2Fowlboard-ts/-/3.0.0-dev.20260325T1023/owlboard-ts-3.0.0-dev.20260325t1023.tgz",
- "integrity": "sha512-h5jAO9MYmYUToXvw3gCohUbG3oVl7h+PKrZ94I1NahXOLEd+CaQzXbXk5+KCsnojgkqf0I1FavaBbADgb2ZKkQ==",
+ "version": "3.0.0-dev.202603302258",
+ "resolved": "https://git.fjla.uk/api/packages/OwlBoard/npm/%40owlboard%2Fowlboard-ts/-/3.0.0-dev.202603302258/owlboard-ts-3.0.0-dev.202603302258.tgz",
+ "integrity": "sha512-uJRoahtqnkmkPg8QsIWhtxhAibWY8xG25fhjzzdDFNE/2+uCj1ev5iD+t0O1dkE7ic3yTcMZqDitEspW216bjw==",
"dev": true,
"license": "GPL-3.0",
"dependencies": {
- "@owlboard/api-schema-types": "^3.0.2-alpha2"
+ "@owlboard/api-schema-types": "^3.0.2-alpha3",
+ "latlon-geohash": "^2.0.0"
}
},
"node_modules/@playwright/test": {
@@ -1558,9 +1559,9 @@
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
- "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.3.tgz",
+ "integrity": "sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1881,9 +1882,9 @@
"license": "MIT"
},
"node_modules/brace-expansion": {
- "version": "1.1.12",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
- "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
+ "version": "1.1.13",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.13.tgz",
+ "integrity": "sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -2664,6 +2665,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/latlon-geohash": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/latlon-geohash/-/latlon-geohash-2.0.0.tgz",
+ "integrity": "sha512-OKBswTwrvTdtenV+9C9euBmvgGuqyjJNAzpQCarRz1m8/pYD2nz9fKkXmLs2S3jeXaLi3Ry76twQplKKUlgS/g==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/levn": {
"version": "0.4.1",
"resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz",
@@ -2901,9 +2909,9 @@
"license": "ISC"
},
"node_modules/picomatch": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
- "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz",
+ "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
"engines": {
@@ -3028,9 +3036,9 @@
}
},
"node_modules/postcss-load-config/node_modules/yaml": {
- "version": "1.10.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
- "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
+ "version": "1.10.3",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz",
+ "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==",
"dev": true,
"license": "ISC",
"engines": {
@@ -3843,9 +3851,9 @@
}
},
"node_modules/yaml": {
- "version": "2.8.2",
- "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.2.tgz",
- "integrity": "sha512-mplynKqc1C2hTVYxd0PU2xQAc22TI1vShAYGksCCfxbn/dFwnHTNi1bvYsBTkhdUNtGIf5xNOg938rrSSYvS9A==",
+ "version": "2.8.3",
+ "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.3.tgz",
+ "integrity": "sha512-AvbaCLOO2Otw/lW5bmh9d/WEdcDFdQp2Z2ZUH3pX9U2ihyUY0nvLv7J6TrWowklRGPYbB/IuIMfYgxaCPg5Bpg==",
"dev": true,
"license": "ISC",
"optional": true,
diff --git a/package.json b/package.json
index c6bda83..b1612b0 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
"devDependencies": {
"@eslint/compat": "^2.0.2",
"@eslint/js": "^9.39.2",
- "@owlboard/owlboard-ts": "^3.0.0-dev.20260325T1023",
+ "@owlboard/owlboard-ts": "^3.0.0-dev.202603302258",
"@playwright/test": "^1.58.1",
"@sveltejs/adapter-static": "^3.0.10",
"@sveltejs/kit": "^2.50.2",
diff --git a/src/lib/components/ui/LocationSearchBox.svelte b/src/lib/components/ui/LocationSearchBox.svelte
index f997ce7..31ca9e5 100644
--- a/src/lib/components/ui/LocationSearchBox.svelte
+++ b/src/lib/components/ui/LocationSearchBox.svelte
@@ -27,7 +27,6 @@
return LOCATIONS.data
.filter((r) => tokens.every((t) => r.s.includes(t)))
.sort((a, b) => {
-
// Priority One - Exact CRS Match
const aExactCrs = a.c?.toLowerCase() === lowerQuery;
const bExactCrs = b.c?.toLowerCase() === lowerQuery;
@@ -36,7 +35,7 @@
// Priority Two - 'Stations' with CRS
if (!!a.c && !b.c) return -1;
- if (!a.c & !! b.c) return 1;
+ if (!a.c & !!b.c) return 1;
// Alphabetical Sort
return a.n.localeCompare(b.n);
diff --git a/src/lib/components/ui/TocStyle.svelte b/src/lib/components/ui/TocStyle.svelte
index 3349838..1b4c7df 100644
--- a/src/lib/components/ui/TocStyle.svelte
+++ b/src/lib/components/ui/TocStyle.svelte
@@ -1,53 +1,56 @@
- {code}
+ {code}
\ No newline at end of file
+ .XC {
+ /* CrossCountry */
+ background-color: #660000;
+ color: #e4d5b1;
+ }
+
diff --git a/src/lib/components/ui/cards/NearbyStationsCard.svelte b/src/lib/components/ui/cards/NearbyStationsCard.svelte
new file mode 100644
index 0000000..602bde0
--- /dev/null
+++ b/src/lib/components/ui/cards/NearbyStationsCard.svelte
@@ -0,0 +1,69 @@
+
+
+
+
+ {#if nearestStationsState.error && nearestStationsState.list.length === 0}
+
{nearestStationsState.error}
+ {:else if nearestStationsState.loading && nearestStationsState.list.length === 0}
+
Locating stations...
+ {:else}
+
+ {#each nearestStationsState.list as station (station.c)}
+
+
+
+ {/each}
+
+ {/if}
+
+
+
+
diff --git a/src/lib/components/ui/cards/pis/PisCode.svelte b/src/lib/components/ui/cards/pis/PisCode.svelte
index 968a103..cde44c6 100644
--- a/src/lib/components/ui/cards/pis/PisCode.svelte
+++ b/src/lib/components/ui/cards/pis/PisCode.svelte
@@ -1,28 +1,34 @@
-
-
-
-
-
+
+
+
+
+
@@ -34,21 +40,21 @@ function resetValues(): void {
padding: 10px 0 10px 0;
}
- .textbox-container {
- display: flex;
- width: 100%;
- justify-content: center;
- gap: 4rem;
- }
+ .textbox-container {
+ display: flex;
+ width: 100%;
+ justify-content: center;
+ gap: 4rem;
+ }
- .textbox-item-wrapper {
- width: 30%;
- }
+ .textbox-item-wrapper {
+ width: 30%;
+ }
- .button-wrapper {
- display: flex;
- justify-content: center;
- gap: 1rem;
- margin-top: 15px;
- }
-
\ No newline at end of file
+ .button-wrapper {
+ display: flex;
+ justify-content: center;
+ gap: 1rem;
+ margin-top: 15px;
+ }
+
diff --git a/src/lib/components/ui/cards/pis/PisStartEndCard.svelte b/src/lib/components/ui/cards/pis/PisStartEndCard.svelte
index 49dad3e..ddf347a 100644
--- a/src/lib/components/ui/cards/pis/PisStartEndCard.svelte
+++ b/src/lib/components/ui/cards/pis/PisStartEndCard.svelte
@@ -1,34 +1,33 @@
-
-
-
-
-
+
+
+
+
+
@@ -40,21 +39,21 @@ function resetValues(): void {
padding: 10px 0 10px 0;
}
- .textbox-container {
- display: flex;
- width: 100%;
- justify-content: center;
- gap: 4rem;
- }
+ .textbox-container {
+ display: flex;
+ width: 100%;
+ justify-content: center;
+ gap: 4rem;
+ }
- .textbox-item-wrapper {
- width: 30%;
- }
+ .textbox-item-wrapper {
+ width: 30%;
+ }
- .button-wrapper {
- display: flex;
- justify-content: center;
- gap: 1rem;
- margin-top: 15px;
- }
-
\ No newline at end of file
+ .button-wrapper {
+ display: flex;
+ justify-content: center;
+ gap: 1rem;
+ margin-top: 15px;
+ }
+
diff --git a/src/lib/geohash.svelte.ts b/src/lib/geohash.svelte.ts
new file mode 100644
index 0000000..8c6f575
--- /dev/null
+++ b/src/lib/geohash.svelte.ts
@@ -0,0 +1,90 @@
+import { OwlClient, ValidationError, ApiError } from './owlClient';
+import type { ApiStationsNearestStations } from '@owlboard/owlboard-ts';
+
+class NearestStationsState {
+ list = $state([]);
+ currentHash = $state('');
+ loading = $state(true);
+ error = $state(null);
+
+ private geoConfig: PositionOptions = {
+ enableHighAccuracy: false,
+ timeout: 30000,
+ maximumAge: 120000
+ };
+
+ constructor() {
+ if (typeof window !== 'undefined' && 'geolocation' in navigator) {
+ this.jumpstart();
+ this.initWatcher();
+ }
+ }
+
+ private jumpstart() {
+ navigator.geolocation.getCurrentPosition(
+ (pos) => this.handleUpdate(pos.coords.latitude, pos.coords.longitude),
+ (err) => this.handleError(err),
+ this.geoConfig
+ );
+ }
+
+ private initWatcher() {
+ navigator.geolocation.watchPosition(
+ (pos) => this.handleUpdate(pos.coords.latitude, pos.coords.longitude),
+ (err) => this.handleError(err),
+ this.geoConfig
+ );
+ }
+
+ private async handleUpdate(lat: number, lon: number) {
+ const newHash = OwlClient.stationData.generateGeohash(lat, lon);
+ if (newHash !== this.currentHash) {
+ this.loading = true;
+
+ try {
+ const result = await OwlClient.stationData.getNearestStations(newHash);
+ this.list = result.data;
+ this.error = null;
+ this.currentHash = newHash;
+ } catch (e) {
+ this.handleApiError(e);
+ } finally {
+ this.loading = false;
+ }
+ }
+ }
+
+ private handleError(err: GeolocationPositionError) {
+ if (err.code === 1) {
+ this.error = 'Location access denied by device';
+ } else {
+ this.error = 'Waiting for GPS signal...';
+ }
+ }
+
+ private handleApiError(e: unknown) {
+ if (e instanceof ValidationError) {
+ this.error = `Request Error: ${e.reason} (Field: ${e.field})`;
+ } else if (e instanceof ApiError) {
+ switch (e.status) {
+ case 404:
+ this.error = 'No stations found nearby';
+ break;
+ case 429:
+ this.error = 'Too many requests, will retry';
+ break;
+ case 500:
+ this.error = 'Server Error, will retry';
+ break;
+ default:
+ this.error = `Service error: ${e.code}`;
+ }
+ } else {
+ this.error = 'Connection lost, waiting for signal';
+ }
+
+ console.error('OwlBoard API Error:', e);
+ }
+}
+
+export const nearestStationsState = new NearestStationsState();
diff --git a/src/lib/locations-object.svelte.ts b/src/lib/locations-object.svelte.ts
index e804181..520229f 100644
--- a/src/lib/locations-object.svelte.ts
+++ b/src/lib/locations-object.svelte.ts
@@ -1,5 +1,5 @@
-import { OwlClient } from "./owlClient";
-import type { ApiLocationFilter } from '@owlboard/owlboard-ts'
+import { OwlClient } from './owlClient';
+import type { ApiLocationFilter } from '@owlboard/owlboard-ts';
class LocationStore {
data = $state([]);
@@ -9,7 +9,7 @@ class LocationStore {
if (this.loaded) return;
try {
- const fetch = await OwlClient.locationFilter.getLocationFilterData()
+ const fetch = await OwlClient.locationFilter.getLocationFilterData();
this.data = fetch.data;
this.loaded = true;
} catch (err) {
diff --git a/src/lib/owlClient.ts b/src/lib/owlClient.ts
index b6eab3f..bff817d 100644
--- a/src/lib/owlClient.ts
+++ b/src/lib/owlClient.ts
@@ -1,21 +1,21 @@
-import { OwlBoardClient, ValidationError, ApiError } from "@owlboard/owlboard-ts";
-import { browser, dev } from "$app/environment";
+import { OwlBoardClient, ValidationError, ApiError } from '@owlboard/owlboard-ts';
+import { browser, dev } from '$app/environment';
// Import the runes containing the API Key config Here...
const baseUrl: string = browser ? window.location.origin : '';
const getBaseUrl = () => {
- if (!browser) return '';
+ if (!browser) return '';
- if (dev) return 'https://test.owlboard.info';
+ if (dev) return 'https://test.owlboard.info';
- return window.location.origin;
-}
+ return window.location.origin;
+};
export const OwlClient = new OwlBoardClient(
- getBaseUrl(),
- // API Key Here when ready!!!
-)
+ getBaseUrl()
+ // API Key Here when ready!!!
+);
-export { ValidationError, ApiError };
\ No newline at end of file
+export { ValidationError, ApiError };
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte
index 79fc665..79d6f94 100644
--- a/src/routes/+layout.svelte
+++ b/src/routes/+layout.svelte
@@ -4,6 +4,7 @@
import { onMount } from 'svelte';
import { LOCATIONS } from '$lib/locations-object.svelte';
+ import { nearestStationsState } from '$lib/geohash.svelte';
import '$lib/global.css';
diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte
index 6ec1a92..c18f801 100644
--- a/src/routes/+page.svelte
+++ b/src/routes/+page.svelte
@@ -1,9 +1,11 @@
+
\ No newline at end of file
+ .reset-button-container {
+ padding: 20px 0 3px 0;
+ }
+
diff --git a/src/routes/pis/+page.ts b/src/routes/pis/+page.ts
index 2d33b8a..798c608 100644
--- a/src/routes/pis/+page.ts
+++ b/src/routes/pis/+page.ts
@@ -2,4 +2,4 @@ export const load = () => {
return {
title: 'PIS Codes'
};
-};
\ No newline at end of file
+};
diff --git a/static/api/tiplocs b/static/api/tiplocs
deleted file mode 100644
index afa6f60..0000000
--- a/static/api/tiplocs
+++ /dev/null
@@ -1,106 +0,0 @@
-[
- {"n":"Manchester Piccadilly","t":"MANPICD","c":"MAN","s":"manchester piccadilly man manpicd"},
- {"n":"Manchester Victoria","t":"MCV","c":"MCV","s":"manchester victoria mcv"},
- {"n":"Manchester Oxford Road","t":"MCOR","c":"MCO","s":"manchester oxford road mco mcor"},
- {"n":"Manchester Airport","t":"MANAPTL","c":"MIA","s":"manchester airport mia manaptl"},
- {"n":"London Euston","t":"EUSTON","c":"EUS","s":"london euston eus euston"},
- {"n":"London Kings Cross","t":"KGX","c":"KGX","s":"london kings cross kgx kingscross"},
- {"n":"London St Pancras International","t":"STPANCR","c":"STP","s":"london st pancras international stp stpancr"},
- {"n":"London Paddington","t":"PADTON","c":"PAD","s":"london paddington pad padton"},
- {"n":"London Victoria","t":"VIC","c":"VIC","s":"london victoria vic"},
- {"n":"London Liverpool Street","t":"LIVST","c":"LST","s":"london liverpool street lst livst"},
- {"n":"London Bridge","t":"LONGBR","c":"LBG","s":"london bridge lbg longbr"},
- {"n":"Birmingham New Street","t":"BHMNEWST","c":"BHM","s":"birmingham new street bhm bhmnewst bham"},
- {"n":"Birmingham Moor Street","t":"BHMMRS","c":"BMO","s":"birmingham moor street bmo bhmmrs"},
- {"n":"Birmingham Snow Hill","t":"BHMSH","c":"BSW","s":"birmingham snow hill bsw bhmsh"},
- {"n":"Leeds","t":"LEEDS","c":"LDS","s":"leeds lds"},
- {"n":"York","t":"YORK","c":"YRK","s":"york yrk"},
- {"n":"Liverpool Lime Street","t":"LIVLST","c":"LIV","s":"liverpool lime street liv livlst"},
- {"n":"Liverpool Central","t":"LIVCEN","c":"LVC","s":"liverpool central lvc livcen"},
- {"n":"Sheffield","t":"SHEFFLD","c":"SHF","s":"sheffield shf sheffld"},
- {"n":"Nottingham","t":"NOTTM","c":"NOT","s":"nottingham not nottm"},
- {"n":"Derby","t":"DERBY","c":"DBY","s":"derby dby"},
- {"n":"Leicester","t":"LEICEST","c":"LEI","s":"leicester lei leicest"},
- {"n":"Bristol Temple Meads","t":"BRSTLTM","c":"BRI","s":"bristol temple meads bri brstltm"},
- {"n":"Cardiff Central","t":"CDFCEN","c":"CDF","s":"cardiff central cdf cdfcen"},
- {"n":"Newcastle","t":"NEWCAST","c":"NCL","s":"newcastle ncl newcast"},
- {"n":"Edinburgh Waverley","t":"EDINBUR","c":"EDB","s":"edinburgh waverley edb edinbur"},
- {"n":"Glasgow Central","t":"GLASCEN","c":"GLC","s":"glasgow central glc glascen"},
- {"n":"Glasgow Queen Street","t":"GLAQS","c":"GLQ","s":"glasgow queen street glq glaqs"},
- {"n":"Reading","t":"READING","c":"RDG","s":"reading rdg"},
- {"n":"Oxford","t":"OXFORD","c":"OXF","s":"oxford oxf"},
- {"n":"Cambridge","t":"CAMBRDG","c":"CBG","s":"cambridge cbg cambrdg"},
- {"n":"Peterborough","t":"PBOUGH","c":"PBO","s":"peterborough pbo pbough"},
- {"n":"Doncaster","t":"DONCAST","c":"DON","s":"doncaster don doncast"},
- {"n":"Crewe","t":"CREWE","c":"CRE","s":"crewe cre"},
- {"n":"Preston","t":"PRESTON","c":"PRE","s":"preston pre"},
- {"n":"Blackpool North","t":"BPLNOR","c":"BPN","s":"blackpool north bpn bplnor"},
- {"n":"Bolton","t":"BOLTON","c":"BON","s":"bolton bon"},
- {"n":"Huddersfield","t":"HUDDSFD","c":"HUD","s":"huddersfield hud huddsfd"},
- {"n":"Stockport","t":"STOCKPT","c":"SPT","s":"stockport spt stockpt"},
- {"n":"Wigan North Western","t":"WIGNW","c":"WGN","s":"wigan north western wgn wignw"},
- {"n":"Bath Spa","t":"BATHSPA","c":"BTH","s":"bath spa bth bathspa"},
- {"n":"Exeter St Davids","t":"EXD","c":"EXD","s":"exeter st davids exd"},
- {"n":"Plymouth","t":"PLYMTH","c":"PLY","s":"plymouth ply plymth"},
- {"n":"Truro","t":"TRURO","c":"TRU","s":"truro tru"},
- {"n":"Aberdeen","t":"ABERDN","c":"ABD","s":"aberdeen abd aberdn"},
- {"n":"Inverness","t":"INVNESS","c":"INV","s":"inverness inv invness"},
- {"n":"Perth","t":"PERTH","c":"PTH","s":"perth pth"},
- {"n":"Dundee","t":"DUNDEE","c":"DEE","s":"dundee dee"},
- {"n":"Stirling","t":"STIRLNG","c":"STG","s":"stirling stg stirlng"},
- {"n":"Falkirk Grahamston","t":"FLKGRA","c":"FKG","s":"falkirk grahamston fkg flkgra"},
- {"n":"Motherwell","t":"MOTHRWL","c":"MTH","s":"motherwell mth mothrwl"},
- {"n":"Paisley Gilmour Street","t":"PAISGL","c":"PYG","s":"paisley gilmour street pyg paisgl"},
- {"n":"Greenock Central","t":"GRNOCK","c":"GKC","s":"greenock central gkc grnock"},
- {"n":"Ayr","t":"AYR","c":"AYR","s":"ayr"},
- {"n":"Carlisle","t":"CARLISL","c":"CAR","s":"carlisle car carlisl"},
- {"n":"Penrith North Lakes","t":"PNRITH","c":"PNR","s":"penrith north lakes pnr pnrith"},
- {"n":"Kendal","t":"KENDAL","c":"KEN","s":"kendal ken"},
- {"n":"Windermere","t":"WNDRMRE","c":"WDM","s":"windermere wdm wndrme"},
- {"n":"Lancaster","t":"LANCAST","c":"LAN","s":"lancaster lan lancast"},
- {"n":"Chester","t":"CHESTER","c":"CTR","s":"chester ctr"},
- {"n":"Warrington Bank Quay","t":"WRRGBQ","c":"WBQ","s":"warrington bank quay wbq wrrgbq"},
- {"n":"Warrington Central","t":"WRRGCN","c":"WAC","s":"warrington central wac wrrgcn"},
- {"n":"Runcorn","t":"RUNCORN","c":"RUN","s":"runcorn run"},
- {"n":"Widnes","t":"WIDNES","c":"WID","s":"widnes wid"},
- {"n":"Southport","t":"STHPORT","c":"SOP","s":"southport sop sthport"},
- {"n":"Ormskirk","t":"ORMSKRK","c":"OMS","s":"ormskirk oms ormskrk"},
- {"n":"Blackburn","t":"BLKBRN","c":"BBN","s":"blackburn bbn blkbrn"},
- {"n":"Burnley Manchester Road","t":"BURNMR","c":"BYM","s":"burnley manchester road bym burnmr"},
- {"n":"Rochdale","t":"ROCHDAL","c":"RCD","s":"rochdale rcd rochdal"},
- {"n":"Oldham Mumps","t":"OLDMUM","c":"OMM","s":"oldham mumps omm oldmum"},
- {"n":"Ashton-under-Lyne","t":"ASHTON","c":"AHN","s":"ashton under lyne ahn ashton"},
- {"n":"Stalybridge","t":"STALYBG","c":"SYB","s":"stalybridge syb stalybg"},
- {"n":"Macclesfield","t":"MACCLFD","c":"MAC","s":"macclesfield mac macclfd"},
- {"n":"Congleton","t":"CONGLTN","c":"CNG","s":"congleton cng conglt"},
- {"n":"Stoke-on-Trent","t":"STOKETR","c":"SOT","s":"stoke on trent sot stoketr"},
- {"n":"Stafford","t":"STAFFRD","c":"STA","s":"stafford sta staffrd"},
- {"n":"Tamworth","t":"TAMWTH","c":"TAM","s":"tamworth tam tamwth"},
- {"n":"Nuneaton","t":"NUNEATN","c":"NUN","s":"nuneaton nun nuneatn"},
- {"n":"Coventry","t":"COVNTRY","c":"COV","s":"coventry cov covntry"},
- {"n":"Rugby","t":"RUGBY","c":"RUG","s":"rugby rug"},
- {"n":"Milton Keynes Central","t":"MKCEN","c":"MKC","s":"milton keynes central mkc mkcen"},
- {"n":"Birmingham Washwood Heath Junction","t":"BWHJCT","c":"","s":"birmingham washwood heath junction bwhjct"},
- {"n":"Manchester Trafford Park Yard","t":"MTRYD","c":"","s":"manchester trafford park yard mtryd"},
- {"n":"London Willesden Junction","t":"WLSDJCT","c":"","s":"london willesden junction wlsdjct"},
- {"n":"Leeds Neville Hill Depot","t":"NVHLDP","c":"","s":"leeds neville hill depot nvhldp"},
- {"n":"York Holgate Junction","t":"YHGJCT","c":"","s":"york holgate junction yhgjct"},
- {"n":"Crewe Basford Hall Junction","t":"CBHJCT","c":"","s":"crewe basford hall junction cbhjct"},
- {"n":"Doncaster Decoy Sidings","t":"DCDSID","c":"","s":"doncaster decoy sidings dcdsid"},
- {"n":"Liverpool Edge Hill Yard","t":"LEHYD","c":"","s":"liverpool edge hill yard lehyd"},
- {"n":"Bristol East Junction","t":"BREJCT","c":"","s":"bristol east junction brejct"},
- {"n":"Glasgow Polmadie Depot","t":"GLPDEP","c":"","s":"glasgow polmadie depot glpdep"},
- {"n":"Newcastle Manors Junction","t":"NCMJCT","c":"","s":"newcastle manors junction ncmjct"},
- {"n":"Edinburgh Haymarket Sidings","t":"EHSID","c":"","s":"edinburgh haymarket sidings ehsid"},
- {"n":"Reading South Junction","t":"RDSJCT","c":"","s":"reading south junction rdsjct"},
- {"n":"Oxford Rewley Road Depot","t":"OXRDEP","c":"","s":"oxford rewley road depot oxrdep"},
- {"n":"Cambridge Coldham Lane Junction","t":"CCLJCT","c":"","s":"cambridge coldham lane junction ccljct"},
- {"n":"Watford North Junction","t":"WFNJCT","c":"","s":"watford north junction wfnjct"},
- {"n":"Luton Airport Sidings","t":"LUTSID","c":"","s":"luton airport sidings lutsid"},
- {"n":"Stevenage Hitchin Junction","t":"STHJC","c":"","s":"stevenage hitchin junction sthjc"},
- {"n":"Chelmsford New Hall Junction","t":"CHNJCT","c":"","s":"chelmsford new hall junction chnjct"},
- {"n":"","t":"BPWY532","c":"","s":"bpwy532"},
- {"n":"Ipswich Derby Road Depot","t":"IPDRDP","c":"","s":"ipswich derby road depot ipdrdp"},
- {"n":"Rhoose Cardiff International Airport","c":"RIA","t":"RHOOSE","s":"rhoose cardiff international airport ria"},
- {"n":"Southampton Airport Parkway","c":"SOA","t":"SOTAPT","s":"southampton airport parkway soa sotapt"}
-]
\ No newline at end of file