commit 279f408a26e2b2353be9b855859349324b559c92 Author: Martin Donnelly Date: Fri Mar 29 11:36:36 2024 +0000 init diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4fc30a3 --- /dev/null +++ b/.gitignore @@ -0,0 +1,201 @@ +### GoLand+all template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# AWS User-specific +.idea/**/aws.xml + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# SonarLint plugin +.idea/sonarlint/ + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +### Go template +# If you prefer the allow list template instead of the deny list, see community template: +# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore +# +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Dependency directories (remove the comment below to include it) +# vendor/ + +# Go workspace file +go.work + +### GoLand+iml template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +### GoLand template +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio, WebStorm and Rider +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff + +# AWS User-specific + +# Generated files + +# Sensitive or high-churn files + +# Gradle + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake + +# Mongo Explorer plugin + +# File-based project format + +# IntelliJ + +# mpeltonen/sbt-idea plugin + +# JIRA plugin + +# Cursive Clojure plugin + +# SonarLint plugin + +# Crashlytics plugin (for Android Studio and IntelliJ) + +# Editor-based Rest Client + +# Android studio 3.1+ serialized cache file + +/menuserver diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6424ce0 --- /dev/null +++ b/Makefile @@ -0,0 +1,40 @@ +PROJECT = traintimes + +VERSION=`git describe --tags` +BUILD=`date +%FT%T%z` + + +ECR_REPO = git.caliban.io/martin + +APP_IMAGE = $(ECR_REPO)/$(PROJECT):$(VERSION) + +NO_CACHE = true + +LDFLAGS=-ldflags "-w -s -X main.Version=${VERSION} -X main.Build=${BUILD}" + + +.PHONY: build +build: + #CC=/usr/local/musl/bin/musl-gcc go build --ldflags '-linkmode external -extldflags "-static"' server.go + # GCO_ENABLED=0 GOOS=linux go build ${LDFLAGS} -o ${PROJECT} server.go + go build ${LDFLAGS} -o ${PROJECT} server.go + +# docker build ./docker/. -t $(APP_IMAGE) --build-arg VERSION=$(VERSION) --no-cache=$(NO_CACHE) --compress=true + docker build --platform linux/amd64 --no-cache -force-rm --tag ${APP_IMAGE} --file ./docker/Dockerfile . + + +#push docker image to registry +.PHONY: push +push: build + docker push $(APP_IMAGE) + + +#push docker image to registry +.PHONY: run +run: build + docker run $(APP_IMAGE) + +ver: + @echo '$(VERSION)' + #echo $ERSION +.PHONY: ver \ No newline at end of file diff --git a/dist/browserconfig.xml b/dist/browserconfig.xml new file mode 100644 index 0000000..9e68e5d --- /dev/null +++ b/dist/browserconfig.xml @@ -0,0 +1,9 @@ + + + + + + #2b5797 + + + diff --git a/dist/build/bundle.css b/dist/build/bundle.css new file mode 100644 index 0000000..797405f --- /dev/null +++ b/dist/build/bundle.css @@ -0,0 +1,12 @@ +@import url("https://fonts.googleapis.com/css?family=Roboto+Condensed");@import url(./fonts/fujicons.css);*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}body{height:100%;overflow-x:hidden;font-family:'Roboto Condensed', sans-serif;font-size:1rem;line-height:1.6}a{color:#5e81ac;text-decoration:none}a:hover{color:#666}a.active{color:#b48ead}ul{list-style:none}img{width:100%}.container{max-width:1100px;margin:auto;overflow-y:scroll;padding:0 2rem}hr{margin-top:2.2rem;margin-bottom:2rem;border-width:0;border-top:1px solid #2e3440}.flex{display:flex}.pad{padding:0.5rem}.pad--1{padding:1rem}.pad--2{padding:2rem}.pad--3{padding:3rem}.pady{padding:0.5rem 0}.pady--top{padding-top:0.5rem}.pady--bottom{padding-bottom:0.5rem}.pady--1{padding:1rem 0}.pady--2{padding:2rem 0}.pady--3{padding:3rem 0}.padx{padding:0 0.5rem}.padx--right{padding-right:0.5rem}.padx--left{padding-left:0.5rem}.padx--1{padding:0 1rem}.padx--2{padding:0 2rem}.padx--3{padding:0 3rem}.grid{display:flex;display:-ms-flexbox;flex-wrap:wrap}.grid--1{display:grid;grid-template-columns:repeat(1, 1fr);grid-gap:1rem}.grid--2{display:grid;grid-template-columns:repeat(2, 1fr);grid-gap:1rem}.grid--3{display:grid;grid-template-columns:repeat(3, 1fr);grid-gap:1px}.grid--4{display:grid;grid-template-columns:repeat(4, 1fr);grid-gap:1rem}.row{margin-left:3px;margin-right:3px}.row:before,.row:after{content:" ";display:table}.row:after{clear:both}.column,.columns{margin-left:4%}.column:first-child,.columns:first-child{margin-left:0}.col-1{width:8.33333%}.col-2{width:16.66667%}.col-3{width:25%}.col-4{width:33.33333%}.col-5{width:41.66667%}.col-6{width:50%}.col-7{width:58.33333%}.col-8{width:66.66667%}.col-9{width:75%}.col-10{width:83.33333%}.col-11{width:91.66667%}.col-12{width:100%;margin-left:0}.col-1-3rd{width:32.666667%}.col-2-3rd{width:65.3333333333%}.col-half{width:48%}.offset-1-col{margin-left:8.66666666667%}.offset-2-col{margin-left:17.3333333333%}.offset-3-col{margin-left:26%}.offset-4-col{margin-left:34.6666666667%}.offset-5-col{margin-left:43.3333333333%}.offset-6-col{margin-left:52%}.offset-7-col{margin-left:60.6666666667%}.offset-8-col{margin-left:69.3333333333%}.offset-9-col{margin-left:78.0%}.offset-10-col{margin-left:86.6666666667%}.offset-11-col{margin-left:95.3333333333%}.offset-1-3rd-col{margin-left:34.6666666667%}.offset-2-3rd-col{margin-left:69.3333333333%}.offset-half-col{margin-left:52%}.x-large{font-size:4rem;line-height:1.2;margin-bottom:1rem}.large{font-size:3rem;line-height:1.2;margin-bottom:1rem}.lead{font-size:1.5rem;margin-bottom:1rem}.text-primary{color:#5e81ac}.text-dark{color:#2e3440}.text-light{color:#2e3440}.text-success{color:#a3be8c}.text-danger{color:#bf616a}.text-highlight{color:#b48ead}.text-highlight2{color:#ebcb8b}.text-center{text-align:center}.text-right{text-align:right}.text-left{text-align:left}.text-lowercase{text-transform:lowercase}.text-uppercase{text-transform:uppercase}.text-capitalize{text-transform:capitalize}.text-display1,h1{font-weight:400;font-size:34px;line-height:40px}.text-title,h3{font-weight:400;font-size:20px;line-height:28px}.text-subhead,h4{font-weight:400;font-size:16px;line-height:24px}.text-body2,h5{font-weight:500;font-size:14px;line-height:24px}.text-body1{font-weight:400;font-size:14px;line-height:20px}.text-caption{font-weight:400;font-size:12px;line-height:16px}.align-middle{vertical-align:middle !important}.all-center{display:flex;flex-direction:column;width:100%;margin:auto;justify-content:center;align-items:center;text-align:center}.text-justify{text-align:justify !important}.text-nowrap{white-space:nowrap !important}.align-baseline{vertical-align:baseline !important}.align-top{vertical-align:top !important}.align-bottom{vertical-align:bottom !important}.btn,.btn--slim{display:inline-block;background:#e5e9f0;color:#333;padding:0.4rem 1.3rem;font-size:1rem;border:none;cursor:pointer;margin-right:0.5rem;transition:opacity 0.2s ease-in;outline:none}.btn:disabled,.btn--slim:disabled{cursor:not-allowed;pointer-events:none;opacity:0.60;box-shadow:none}.btn:enabled:hover,.btn--slim:enabled:hover{opacity:0.8}.btn--slim{padding:0.4rem}.btn-link{background:none;padding:0;margin:0}.btn-block{display:block;width:100%}.btn-sm,.btn-sm--slim{font-size:0.8rem;padding:0.3rem 1rem;margin-right:0.2rem}.btn-sm--slim{padding:0.3rem}.badge{display:inline-block;font-size:0.6rem;padding:0.1rem 0.4rem;text-align:center;margin:0.3rem;background:#e5e9f0;color:#333;border-radius:3px}.alert{padding:0.7rem;margin:1rem 0;opacity:0.9;background:#e5e9f0;color:#333}.btn-primary,.bg-primary,.badge-primary,.alert-primary{background:#5e81ac;color:#fff}.btn-light,.bg-light,.badge-light,.alert-light{background:#e5e9f0;color:#333}.btn-dark,.bg-dark,.badge-dark,.alert-dark{background:#2e3440;color:#fff}.btn-danger,.bg-danger,.badge-danger,.alert-danger{background:#bf616a;color:#fff}.btn-success,.bg-success,.badge-success,.alert-success{background:#a3be8c;color:#fff}.btn-white,.bg-white,.badge-white,.alert-white{background:#fff;color:#333;border:#ccc solid 1px}.bg-light,.badge-light{border:#ccc solid 1px}.table-responsive{display:block;overflow-x:auto;width:100%}table{max-width:100%;width:100%;border:0;margin-bottom:1rem;border-collapse:collapse}tr{border-top:1px solid #ccc}tbody tr:nth-of-type(odd){background-color:rgba(0, 0, 0, 0.04)}tbody td{border-top:1px solid #e1e1e1}.navbar{position:fixed;display:flex;justify-content:space-between;align-items:center;z-index:2;width:100%;opacity:0.9;margin-bottom:1rem;min-height:56px}.navbar ul{display:flex}.navbar a{color:#fff;padding:0.45rem;margin:0 0.25rem}.navbar a:hover{color:#e5e9f0}.navbar .welcome span{margin-right:0.6rem}.navbar .navbar-section{align-items:center;display:flex;display:-ms-flexbox;flex:1 0 0;-ms-flex-align:center}.navbar .navbar-section:not(:first-child):last-child{justify-content:flex-end}.navbar .navbar-brand{font-size:200%;font-weight:bold}header+div.container{position:relative;top:56px;overflow:auto;height:calc(100vh - 56px);max-height:calc(100vh - 56px)}.m{margin:0.5rem}.m--1{margin:1rem}.m--2{margin:2rem}.m--3{margin:3rem}.mb{margin-bottom:.1rem !important}.mb--1{margin-bottom:.2rem !important}.mb--2{margin-bottom:.4rem !important}.ml{margin-left:.1rem !important}.ml--1{margin-left:.2rem !important}.ml--2{margin-left:.4rem !important}.mr{margin-right:.1rem !important}.mr--1{margin-right:.2rem !important}.mr .mr-2{margin-right:.4rem !important}.mt{margin-top:.1rem !important}.mt--1{margin-top:.2rem !important}.mt--2{margin-top:.4rem !important}.mx{margin-left:0.5rem !important;margin-right:0.5rem !important}.mx--1{margin-left:1rem !important;margin-right:1rem !important}.mx--2{margin-left:2rem !important;margin-right:2rem !important}.my{margin:0.5rem 0}.my--1{margin:1rem 0}.my--2{margin:2rem 0}.my--3{margin:3rem 0}.card,.card--slim{padding:1rem;border:#ccc 1px dotted;margin:0.7rem 0}.card--slim{padding:5px}.cardTitle{border-bottom-color:#eee;border-bottom-width:1px;border-bottom-style:solid;margin-bottom:15px}.cardV2{border-radius:4px;background-color:#fff;box-shadow:0 0 4px 0 rgba(0, 0, 0, 0.14), 0 3px 4px 0 rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2);min-width:0}.seemore{font-size:14px;font-weight:500}.cardLink{color:#2196F3;margin-top:10px}@media(max-width: 480px){.container{max-width:98vw;padding:0 0;overflow-y:scroll}}@media(max-height: 480px){.navbar{min-height:36px}header+div.container{position:relative;top:36px;max-height:calc(100vh - 36px)}.navbar .navbar-brand{font-size:125%;font-weight:bold}}@media(min-height: 900px){body{font-size:x-large}}.nrccAlert a{color:#00ffa2}.betterInput{background-color:deeppink;padding-bottom:6px !important;padding-top:6px !important}.up,.ontime,.trendUp{color:#4CAF50 !important}.down,.delayed,.trendDown{color:#F44336 !important} +.mui-dropdown.svelte-1up86vp.svelte-1up86vp.svelte-1up86vp{display:inline-block;position:relative}.mui-dropdown__menu.svelte-1up86vp.svelte-1up86vp.svelte-1up86vp{box-shadow:0 1px 3px rgba(21, 21, 21, 0.12), 0 1px 2px rgba(21, 21, 21, 0.24);position:absolute;display:none;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;font-size:1rem;text-align:left;background-color:#fff;border-radius:0.1;z-index:100;background-clip:padding-box}@media all and (-ms-high-contrast: none), (-ms-high-contrast: active){.mui-dropdown__menu.svelte-1up86vp.svelte-1up86vp.svelte-1up86vp{border-top:1px solid rgba(21, 21, 21, 0.12);border-left:1px solid rgba(21, 21, 21, 0.12)}}@supports (-ms-ime-align: auto){.mui-dropdown__menu.svelte-1up86vp.svelte-1up86vp.svelte-1up86vp{border-top:1px solid rgba(21, 21, 21, 0.12);border-left:1px solid rgba(21, 21, 21, 0.12)}}.mui-dropdown__menu.mui--is-open.svelte-1up86vp.svelte-1up86vp.svelte-1up86vp{display:block}.mui-dropdown__menu.svelte-1up86vp>li.svelte-1up86vp>a.svelte-1up86vp{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:1.6;color:#294c5d;text-decoration:none;white-space:nowrap}.mui-dropdown__menu.svelte-1up86vp>li.svelte-1up86vp>a.svelte-1up86vp:hover,.mui-dropdown__menu.svelte-1up86vp>li.svelte-1up86vp>a.svelte-1up86vp:focus{text-decoration:none;color:#294c5d;background-color:#dcc894}.mui-dropdown--right.svelte-1up86vp.svelte-1up86vp>.mui-dropdown__menu.svelte-1up86vp.svelte-1up86vp{margin:0 0 0 2px}input.svelte-1up86vp.svelte-1up86vp.svelte-1up86vp{background-color:deeppink;padding-bottom:6px !important;padding-top:6px !important} +.grid-3.svelte-ojjucl{display:grid;grid-template-columns:repeat(3, 1fr);grid-gap:1rem} +.TRcard.svelte-10t8pfm.svelte-10t8pfm{display:flex;justify-content:space-between;align-items:center;padding:0.7rem 0rem;z-index:1;width:98%;opacity:0.9;margin-bottom:0.4rem;border-bottom-color:#666666;box-shadow:0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), + 0 1px 5px 0 rgba(0, 0, 0, 0.12)}.TRcard.svelte-10t8pfm .entry.svelte-10t8pfm{align-items:left;display:flex;display:-ms-flexbox;-ms-flex-align:center;flex-direction:column}.TRcard.svelte-10t8pfm .entry.svelte-10t8pfm:not(:first-child):last-child{justify-content:flex-end;align-items:right}.entryOld.svelte-10t8pfm.svelte-10t8pfm{height:36px;margin:6px 0;vertical-align:middle}.TRcardOld.svelte-10t8pfm.svelte-10t8pfm{position:relative;background-color:#fff;min-height:48px;margin:0.5rem 8px;border-bottom-color:#666666;box-shadow:0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.2), + 0 1px 5px 0 rgba(0, 0, 0, 0.12);vertical-align:middle;padding:0.5rem 0;border-radius:0.1rem} +.avatar.svelte-1y2z4hv{max-width:48px;max-height:48px;-o-object-fit:scale-down;object-fit:scale-down;border-radius:0.1rem} +label.svelte-1wws4hx{font-weight:normal} +.svelte-apetsu{background:#f55a4e;padding:3px} +.svelte-apetsu{background:#f55a4e;padding:3px} + +/*# sourceMappingURL=bundle.css.map */ \ No newline at end of file diff --git a/dist/build/bundle.js b/dist/build/bundle.js new file mode 100644 index 0000000..7bf47fc --- /dev/null +++ b/dist/build/bundle.js @@ -0,0 +1,8 @@ +var app=function(){"use strict";function e(){}const t=e=>e;function n(e){return e()}function r(){return Object.create(null)}function o(e){e.forEach(n)}function a(e){return"function"==typeof e}function i(e,t){return e!=e?t==t:e!==t||e&&"object"==typeof e||"function"==typeof e}function l(t,...n){if(null==t)return e;const r=t.subscribe(...n);return r.unsubscribe?()=>r.unsubscribe():r}function s(e){let t;return l(e,e=>t=e)(),t}const c="undefined"!=typeof window;let u=c?()=>window.performance.now():()=>Date.now(),d=c?e=>requestAnimationFrame(e):e;const h=new Set;function f(e){h.forEach(t=>{t.c(e)||(h.delete(t),t.f())}),0!==h.size&&d(f)}function S(e){let t;return 0===h.size&&d(f),{promise:new Promise(n=>{h.add(t={c:e,f:n})}),abort(){h.delete(t)}}}function m(e,t){e.appendChild(t)}function g(e,t,n){e.insertBefore(t,n||null)}function y(e){e.parentNode.removeChild(e)}function B(e,t){for(let n=0;ne.removeEventListener(t,n,r)}function H(e,t,n){null==n?e.removeAttribute(t):e.getAttribute(t)!==n&&e.setAttribute(t,n)}function W(e,t){t=""+t,e.wholeText!==t&&(e.data=t)}function v(e,t){e.value=null==t?"":t}function T(e,t){const n=document.createEvent("CustomEvent");return n.initCustomEvent(e,!1,!1,t),n}const N=new Set;let R,M=0;function P(e,t,n,r,o,a,i,l=0){const s=16.666/r;let c="{\n";for(let e=0;e<=1;e+=s){const r=t+(n-t)*a(e);c+=100*e+`%{${i(r,1-r)}}\n`}const u=c+`100% {${i(n,1-n)}}\n}`,d=`__svelte_${function(e){let t=5381,n=e.length;for(;n--;)t=(t<<5)-t^e.charCodeAt(n);return t>>>0}(u)}_${l}`,h=e.ownerDocument;N.add(h);const f=h.__svelte_stylesheet||(h.__svelte_stylesheet=h.head.appendChild(p("style")).sheet),S=h.__svelte_rules||(h.__svelte_rules={});S[d]||(S[d]=!0,f.insertRule(`@keyframes ${d} ${u}`,f.cssRules.length));const m=e.style.animation||"";return e.style.animation=`${m?m+", ":""}${d} ${r}ms linear ${o}ms 1 both`,M+=1,d}function A(e,t){const n=(e.style.animation||"").split(", "),r=n.filter(t?e=>e.indexOf(t)<0:e=>-1===e.indexOf("__svelte")),o=n.length-r.length;o&&(e.style.animation=r.join(", "),M-=o,M||d(()=>{M||(N.forEach(e=>{const t=e.__svelte_stylesheet;let n=t.cssRules.length;for(;n--;)t.deleteRule(n);e.__svelte_rules={}}),N.clear())}))}function D(e){R=e}function E(){if(!R)throw new Error("Function called outside component initialization");return R}function k(e){E().$$.on_mount.push(e)}function G(e){E().$$.on_destroy.push(e)}function F(e,t){const n=e.$$.callbacks[t.type];n&&n.slice().forEach(e=>e(t))}const I=[],O=[],K=[],x=[],$=Promise.resolve();let Y=!1;function _(){Y||(Y=!0,$.then(Q))}function U(){return _(),$}function V(e){K.push(e)}function J(e){x.push(e)}let j=!1;const X=new Set;function Q(){if(!j){j=!0;do{for(let e=0;e{Z=null})),Z}function ee(e,t,n){e.dispatchEvent(T(`${t?"intro":"outro"}${n}`))}const te=new Set;let ne;function re(){ne={r:0,c:[],p:ne}}function oe(){ne.r||o(ne.c),ne=ne.p}function ae(e,t){e&&e.i&&(te.delete(e),e.i(t))}function ie(e,t,n,r){if(e&&e.o){if(te.has(e))return;te.add(e),ne.c.push(()=>{te.delete(e),r&&(n&&e.d(1),r())}),e.o(t)}}const le={duration:0};function se(n,r,i,l){let s=r(n,i),c=l?0:1,d=null,h=null,f=null;function m(){f&&A(n,f)}function g(e,t){const n=e.b-c;return t*=Math.abs(n),{a:c,b:e.b,d:n,duration:t,start:e.start,end:e.start+t,group:e.group}}function y(r){const{delay:a=0,duration:i=300,easing:l=t,tick:y=e,css:B}=s||le,p={start:u()+a,b:r};r||(p.group=ne,ne.r+=1),d?h=p:(B&&(m(),f=P(n,c,r,i,a,l,B)),r&&y(0,1),d=g(p,i),V(()=>ee(n,r,"start")),S(e=>{if(h&&e>h.start&&(d=g(h,i),h=null,ee(n,d.b,"start"),B&&(m(),f=P(n,c,d.b,d.duration,0,l,s.css))),d)if(e>=d.end)y(c=d.b,1-c),ee(n,d.b,"end"),h||(d.b?m():--d.group.r||o(d.group.c)),d=null;else if(e>=d.start){const t=e-d.start;c=d.a+d.d*l(t/d.duration),y(c,1-c)}return!(!d&&!h)}))}return{run(e){a(s)?q().then(()=>{s=s(),y(e)}):y(e)},end(){m(),d=h=null}}}function ce(e,t){ie(e,1,1,()=>{t.delete(e.key)})}function ue(e,t,n,r,o,a,i,l,s,c,u,d){let h=e.length,f=a.length,S=h;const m={};for(;S--;)m[e[S].key]=S;const g=[],y=new Map,B=new Map;for(S=f;S--;){const e=d(o,a,S),l=n(e);let s=i.get(l);s?r&&s.p(e,t):(s=c(l,e),s.c()),y.set(l,g[S]=s),l in m&&B.set(l,Math.abs(S-m[l]))}const p=new Set,C=new Set;function L(e){ae(e,1),e.m(l,u),i.set(e.key,e),u=e.first,f--}for(;h&&f;){const t=g[f-1],n=e[h-1],r=t.key,o=n.key;t===n?(u=t.first,h--,f--):y.has(o)?!i.has(r)||p.has(r)?L(t):C.has(o)?h--:B.get(r)>B.get(o)?(C.add(r),L(t)):(p.add(o),h--):(s(n,i),h--)}for(;h--;){const t=e[h];y.has(t.key)||s(t,i)}for(;f;)L(g[f-1]);return g}function de(e,t,n){const r=e.$$.props[t];void 0!==r&&(e.$$.bound[r]=n,n(e.$$.ctx[r]))}function he(e){e&&e.c()}function fe(e,t,r){const{fragment:i,on_mount:l,on_destroy:s,after_update:c}=e.$$;i&&i.m(t,r),V(()=>{const t=l.map(n).filter(a);s?s.push(...t):o(t),e.$$.on_mount=[]}),c.forEach(V)}function Se(e,t){const n=e.$$;null!==n.fragment&&(o(n.on_destroy),n.fragment&&n.fragment.d(t),n.on_destroy=n.fragment=null,n.ctx=[])}function me(t,n,a,i,l,s,c=[-1]){const u=R;D(t);const d=n.props||{},h=t.$$={fragment:null,ctx:null,props:s,update:e,not_equal:l,bound:r(),on_mount:[],on_destroy:[],before_update:[],after_update:[],context:new Map(u?u.$$.context:[]),callbacks:r(),dirty:c,skip_bound:!1};let f=!1;if(h.ctx=a?a(t,d,(e,n,...r)=>{const o=r.length?r[0]:n;return h.ctx&&l(h.ctx[e],h.ctx[e]=o)&&(!h.skip_bound&&h.bound[e]&&h.bound[e](o),f&&function(e,t){-1===e.$$.dirty[0]&&(I.push(e),_(),e.$$.dirty.fill(0)),e.$$.dirty[t/31|0]|=1<{const e=n.indexOf(t);-1!==e&&n.splice(e,1)}}$set(e){var t;this.$$set&&(t=e,0!==Object.keys(t).length)&&(this.$$.skip_bound=!0,this.$$set(e),this.$$.skip_bound=!1)}}const ye=[];function Be(e,t){return{subscribe:pe(e,t).subscribe}}function pe(t,n=e){let r;const o=[];function a(e){if(i(t,e)&&(t=e,r)){const e=!ye.length;for(let e=0;e{const e=o.indexOf(s);-1!==e&&o.splice(e,1),0===o.length&&(r(),r=null)}}}}function Ce(t,n,r){const i=!Array.isArray(t),s=i?[t]:t,c=n.length<2;return Be(r,t=>{let r=!1;const u=[];let d=0,h=e;const f=()=>{if(d)return;h();const r=n(i?u[0]:u,t);c?t(r):h=a(r)?r:e},S=s.map((e,t)=>l(e,e=>{u[t]=e,d&=~(1<{d|=1<{Se(e,1)}),oe()}o?(t=new o({}),t.$on("routeEvent",e[5]),he(t.$$.fragment),ae(t.$$.fragment,1),fe(t,n.parentNode,n)):t=null}},i(e){r||(t&&ae(t.$$.fragment,e),r=!0)},o(e){t&&ie(t.$$.fragment,e),r=!1},d(e){e&&y(n),t&&Se(t,e)}}}function we(e){let t,n,r;var o=e[0];function a(e){return{props:{params:e[1]}}}return o&&(t=new o(a(e)),t.$on("routeEvent",e[4])),{c(){t&&he(t.$$.fragment),n=w()},m(e,o){t&&fe(t,e,o),g(e,n,o),r=!0},p(e,r){const i={};if(2&r&&(i.params=e[1]),o!==(o=e[0])){if(t){re();const e=t;ie(e.$$.fragment,1,0,()=>{Se(e,1)}),oe()}o?(t=new o(a(e)),t.$on("routeEvent",e[4]),he(t.$$.fragment),ae(t.$$.fragment,1),fe(t,n.parentNode,n)):t=null}else o&&t.$set(i)},i(e){r||(t&&ae(t.$$.fragment,e),r=!0)},o(e){t&&ie(t.$$.fragment,e),r=!1},d(e){e&&y(n),t&&Se(t,e)}}}function be(e){let t,n,r,o;const a=[we,Le],i=[];function l(e,t){return e[1]?0:1}return t=l(e),n=i[t]=a[t](e),{c(){n.c(),r=w()},m(e,n){i[t].m(e,n),g(e,r,n),o=!0},p(e,[o]){let s=t;t=l(e),t===s?i[t].p(e,o):(re(),ie(i[s],1,1,()=>{i[s]=null}),oe(),n=i[t],n||(n=i[t]=a[t](e),n.c()),ae(n,1),n.m(r.parentNode,r))},i(e){o||(ae(n),o=!0)},o(e){ie(n),o=!1},d(e){i[t].d(e),e&&y(r)}}}function He(){const e=window.location.href.indexOf("#/");let t=e>-1?window.location.href.substr(e+1):"/";const n=t.indexOf("?");let r="";return n>-1&&(r=t.substr(n+1),t=t.substr(0,n)),{location:t,querystring:r}}const We=Be(null,(function(e){e(He());const t=()=>{e(He())};return window.addEventListener("hashchange",t,!1),function(){window.removeEventListener("hashchange",t,!1)}}));Ce(We,e=>e.location),Ce(We,e=>e.querystring);function ve(e){if(!e||e.length<1||"/"!=e.charAt(0)&&0!==e.indexOf("#/"))throw Error("Invalid parameter location");return U().then(()=>{window.location.hash=("#"==e.charAt(0)?"":"#")+e})}function Te(t,n,r){let o,a=e;!function(e,t,n){e.$$.on_destroy.push(l(t,n))}(t,We,e=>r(6,o=e)),t.$$.on_destroy.push(()=>a());let{routes:i={}}=n,{prefix:s=""}=n;class c{constructor(e,t){if(!t||"function"!=typeof t&&("object"!=typeof t||!0!==t._sveltesparouter))throw Error("Invalid component object");if(!e||"string"==typeof e&&(e.length<1||"/"!=e.charAt(0)&&"*"!=e.charAt(0))||"object"==typeof e&&!(e instanceof RegExp))throw Error('Invalid value for "path" argument');const{pattern:n,keys:r}=function(e,t){if(e instanceof RegExp)return{keys:!1,pattern:e};var n,r,o,a,i=[],l="",s=e.split("/");for(s[0]||s.shift();o=s.shift();)"*"===(n=o[0])?(i.push("wild"),l+="/(.*)"):":"===n?(r=o.indexOf("?",1),a=o.indexOf(".",1),i.push(o.substring(1,~r?r:~a?a:o.length)),l+=~r&&!~a?"(?:/([^/]+?))?":"/([^/]+?)",~a&&(l+=(~r?"?":"")+"\\"+o.substring(a))):l+="/"+o;return{keys:i,pattern:new RegExp("^"+l+(t?"(?=$|/)":"/?$"),"i")}}(e);this.path=e,"object"==typeof t&&!0===t._sveltesparouter?(this.component=t.route,this.conditions=t.conditions||[],this.userData=t.userData):(this.component=t,this.conditions=[],this.userData=void 0),this._pattern=n,this._keys=r}match(e){s&&e.startsWith(s)&&(e=e.substr(s.length)||"/");const t=this._pattern.exec(e);if(null===t)return null;if(!1===this._keys)return t;const n={};let r=0;for(;r{u.push(new c(t,e))}):Object.keys(i).forEach(e=>{u.push(new c(e,i[e]))});let d=null,h=null;const f=function(){const e=E();return(t,n)=>{const r=e.$$.callbacks[t];if(r){const o=T(t,n);r.slice().forEach(t=>{t.call(e,o)})}}}(),S=(e,t)=>{U().then(()=>{f(e,t)})};return t.$$set=e=>{"routes"in e&&r(2,i=e.routes),"prefix"in e&&r(3,s=e.prefix)},t.$$.update=()=>{if(65&t.$$.dirty){r(0,d=null);let e=0;for(;!d&&e{t&&(e.node.classList.remove(t),e.pattern.test(Me)&&e.node.classList.add(t))})}function Ae(e){const t=e-1;return t*t*t+1}function De(e,{delay:n=0,duration:r=400,easing:o=t}){const a=+getComputedStyle(e).opacity;return{delay:n,duration:r,easing:o,css:e=>"opacity: "+e*a}}function Ee(e,{delay:t=0,duration:n=400,easing:r=Ae}){const o=getComputedStyle(e),a=+o.opacity,i=parseFloat(o.height),l=parseFloat(o.paddingTop),s=parseFloat(o.paddingBottom),c=parseFloat(o.marginTop),u=parseFloat(o.marginBottom),d=parseFloat(o.borderTopWidth),h=parseFloat(o.borderBottomWidth);return{delay:t,duration:n,easing:r,css:e=>`overflow: hidden;opacity: ${Math.min(20*e,1)*a};height: ${e*i}px;padding-top: ${e*l}px;padding-bottom: ${e*s}px;margin-top: ${e*c}px;margin-bottom: ${e*u}px;border-top-width: ${e*d}px;border-bottom-width: ${e*h}px;`}}We.subscribe(e=>{Me=e.location+(e.querystring?"?"+e.querystring:""),Re.map(Pe)});const ke=new Map([["ZNJ","Northampton North Junction"],["ZPS","Plaistow L.T."],["MSC","Marseille St Charles"],["ZAE","Aldgate East"],["ZEP","East Putney"],["GBG","Gorebridge"],["ZHR","Holloway Road"],["ZPN","Paddington (Bakerloo Line)"],["NMC","New Mills Central"],["HBB","Hubberts Bridge"],["ADC","Adlington (Cheshire)"],["WHI","Whitstable"],["FEG","Fellgate (T & W Metro)"],["HRH","Horsham"],["LNW","Llanwrtyd"],["RYP","Ryde Pier Head"],["PRU","Prudhoe"],["TLH","Tilehurst"],["SBM","South Bermondsey"],["TAM","Tamworth"],["CFD","Castleford"],["NMN","New Mills Newtown"],["HFS","Hatfield & Stainforth"],["WFN","Watford North"],["GWN","Gowerton"],["WMW","Walthamstow Queens Road"],["INP","Inverkip"],["WRW","Warwick"],["WHG","Westhoughton"],["WIM","Wimbledon"],["CLM","Collingham"],["DRF","Driffield"],["NWT","Newtown (Powys)"],["SOE","Southend East"],["PNF","Penyffordd"],["WYE","Wye"],["BAR","Bare Lane"],["YRM","Yarm"],["NTH","Neath"],["ERH","Erith"],["CFO","Chalfont & Latimer"],["FGW","Fishguard & Goodwick"],["BAY","Bayford"],["BER","Bearley"],["SIT","Sittingbourne"],["WHL","White Hart Lane"],["DRN","Duirinish"],["SWK","Southwick"],["MTM","Martin Mill"],["NWR","Newtonmore"],["ADW","Addiewell"],["ALV","Alvechurch"],["SQE","Surrey Quays"],["HIG","Highbridge & Burnham"],["RMC","Rotherham Central"],["NTN","Newton"],["CBN","Camborne"],["RIA","Rhoose Cardiff Intl Airport"],["BXW","Boxhill & Westhumble"],["TNN","Thorne North"],["FTN","Fratton"],["RUA","Ruabon"],["LAY","Layton"],["LLV","Llandovery"],["MAS","Manors"],["CLG","Claygate"],["CTT","Church Stretton"],["GGV","Gargrave"],["TNS","Thorne South"],["CRE","Crewe"],["WXC","Wrexham Central"],["CAD","Cadoxton"],["HYB","Honeybourne"],["WGT","Wigton"],["WRX","Wrexham General"],["RHO","Rhosneigr"],["KWL","Kidwelly"],["RYD","Ryde Esplanade"],["PTL","Priesthill & Darnley"],["NWN","Newton for Hyde"],["SBP","Stonebridge Park"],["PEV","Pevensey & Westham"],["ACL","Acle"],["GDH","Gordon Hill"],["LSY","Lower Sydenham"],["SEB","Seaburn (T & W Metro)"],["AYW","Aberystwyth"],["LNZ","Lenzie"],["MDS","Morden South"],["ADD","Adderley Park"],["EFL","East Farleigh"],["SPU","Staplehurst"],["UHL","Upper Holloway"],["WLP","Welshpool"],["CAS","Castleton"],["HAM","Hamworthy"],["BGN","Bridgend"],["BRN","Bearsden"],["APG","Aspley Guise"],["DEW","Dewsbury"],["BPS","Blackpool South"],["KSL","Kearsley"],["PYJ","Paisley St James"],["NBA","New Barnet"],["WHR","West Horndon"],["HLD","Hellifield"],["RDR","Radyr"],["VAL","Valley"],["BSD","Bearsted"],["FIT","Filton Abbey Wood"],["NAY","Newton Aycliffe"],["BWK","Berwick-upon-Tweed"],["BIF","Barrow-in-Furness"],["DMY","Drumry"],["CKH","Corkerhill"],["LBK","Long Buckby"],["BEA","Bridge of Allan"],["PEB","Pevensey Bay"],["CRL","Chorley"],["ECS","Eccles Road"],["FSG","Fishersgate"],["YSR","Ystrad Rhondda"],["UNV","University (T & W Metro)"],["WCL","West Calder"],["GNW","Greenwich"],["SAB","Smallbrook Junction"],["BDA","Brundall"],["LNG","Longcross"],["PSW","Polesworth"],["SPP","Shippea Hill"],["FIL","Filey"],["HRR","Harrington"],["MGM","Metheringham"],["RAV","Ravenglass for Eskdale"],["OLT","Olton"],["CRD","Chester Road"],["SAH","Salhouse"],["GIL","Gillingham (Dorset)"],["GNT","Gunton"],["FEN","Fenny Stratford"],["CBB","Carbis Bay"],["BLW","Bulwell"],["FMR","Falmer"],["WNY","White Notley"],["SFD","Salford Central"],["BGI","Bargeddie"],["WLY","Woodley"],["BYC","Betws-y-Coed"],["WYT","Wythall"],["KID","Kidderminster"],["SMO","South Merton"],["ULC","Ulceby"],["AWK","Adwick"],["CRR","Corrour"],["OVR","Overton"],["RET","Retford"],["STQ","Southampton Town Quay (Bus)"],["BBS","Bordesley"],["GOS","Grange-over-Sands"],["MAY","Maybole"],["YET","Yetminster"],["LIH","Leigh (Kent)"],["SMC","Sampford Courtenay"],["SLO","Slough"],["LHE","Loch Eil Outward Bound"],["WBP","West Brompton"],["NBT","Norbiton"],["KVP","Kiveton Park"],["PNL","Pannal"],["MEO","Meols"],["SRG","Seer Green"],["CTO","Carlton"],["GLY","Glynde"],["MSW","Mansfield Woodhouse"],["IBM","IBM"],["BRL","Barrhill"],["TRD","Troed-y-rhiw"],["MEC","Meols Cop"],["POL","Polsloe Bridge"],["TPN","Ton Pentre"],["BCK","Buckley"],["CHC","Charing Cross (Glasgow)"],["SRA","Stratford (London)"],["WWO","West Worthing"],["RSH","Rose Hill Marple"],["SMT","St Margarets (Hertfordshire)"],["WIH","Winchmore Hill"],["CRS","Carstairs"],["KGX","London Kings Cross"],["LHS","Limehouse"],["THB","Thornliebank"],["DRT","Darton"],["LLD","Llandudno"],["NRN","Nairn"],["KGE","Kingsknowe"],["TNA","Thornton Abbey"],["LRD","London Road (Guildford)"],["BAL","Balham"],["FRH","Calais Frethun"],["WAC","Warrington Central"],["GMV","Great Malvern"],["MNC","Markinch"],["WRT","Worstead"],["EBB","Ebbw Vale Town"],["MEL","Meldreth"],["BYB","Blythe Bridge"],["LOT","Lostock"],["CNM","Cheltenham Spa"],["FZH","Frizinghall"],["LLJ","Llandudno Junction"],["UPM","Upminster"],["DBC","Dumbarton Central"],["STT","Stewarton"],["DBE","Dumbarton East"],["TYS","Tyseley"],["DNS","Dinas Powys"],["DEE","Dundee"],["LDY","Ladybank"],["PBY","Pembrey & Burry Port"],["GMD","Grimsby Docks"],["KEI","Keighley"],["BIP","Bishopstone"],["SFO","Stanford-le-Hope"],["BYF","Broughty Ferry"],["MYH","Maryhill"],["DRM","Drem"],["NBE","Newbridge"],["WSF","Winsford"],["THD","Thames Ditton"],["HMM","Hammerton"],["HOR","Horley"],["BLY","Bletchley"],["ARU","Arundel"],["FNB","Farnborough (Main)"],["CGW","Caergwrle"],["MAO","Martins Heron"],["OXT","Oxted"],["PAT","Patricroft"],["GMB","Grimsby Town"],["TUR","Turkey Street"],["TAF","Taffs Well"],["LTN","Luton Airport Parkway"],["CHM","Chelmsford"],["FLW","Fulwell"],["HTW","Hartwood"],["PNZ","Penzance"],["WDE","Wood End"],["GCW","Glan Conwy"],["HOV","Hove"],["TRH","Trehafod"],["WTE","Whitlocks End"],["DLJ","Dalston Junction"],["VIR","Virginia Water"],["ASP","Aspatria"],["LPT","Longport"],["LWS","Lewes"],["EWD","Earlswood (West Midlands)"],["WAN","Wanborough"],["BTO","Betchworth"],["FLN","Flint"],["BUK","Bucknell"],["LLM","Llangammarch"],["CNG","Congleton"],["WMN","Warminster"],["MTL","Mortlake"],["BWT","Bridgwater"],["BRT","Barlaston"],["MNP","Manor Park"],["ESL","Eastleigh"],["SHO","Sholing"],["EGT","Egton"],["HDH","Hampstead Heath"],["WCP","Worcester Park"],["ISP","Islip"],["TPB","Thorpe Bay"],["CRH","Crouch Hill"],["TBW","Tunbridge Wells"],["GLE","Gleneagles"],["KSW","Kirkby Stephen"],["ALW","Allens West"],["DMG","Dinas Rhondda"],["BSR","Broadstairs"],["WEM","Wem"],["CSN","Chessington North"],["HRD","Harling Road"],["AUI","Ardlui"],["ERI","Eridge"],["APD","Appledore (Kent)"],["DHN","Deighton"],["GLG","Glengarnock"],["MLH","Mill Hill (Lancashire)"],["WRP","Warwick Parkway"],["GOF","Golf Street"],["CHY","Chertsey"],["WOK","Woking"],["LLE","Llanelli"],["MYB","London Marylebone"],["WIL","Willington"],["WIJ","Willesden Junction"],["BME","Broome"],["CAM","Camberley"],["SRT","Shortlands"],["SOP","Southport"],["TYB","Tan-y-Bwlch (Bus)"],["ENC","Enfield Chase"],["RYP","Ryde Pier Head"],["BEB","Bebington"],["LGW","Langwathby"],["WSE","Winchelsea"],["BFR","London Blackfriars"],["SCT","Scotscalder"],["RUG","Rugby"],["SRS","Selhurst"],["MLF","Milford (Surrey)"],["PNA","Penally"],["STU","Sturry"],["TWB","Tweedbank"],["YSM","Ystrad Mynach"],["JEQ","Jewellery Quarter"],["PTW","Prestwick Town"],["EBK","Eastbrook"],["PER","Penrhiwceiber"],["CWM","Cwmbran"],["ING","Invergowrie"],["RBS","British Steel Redcar"],["HLG","Hall Green"],["LSN","Livingston North"],["RML","Romiley"],["BUU","Burnham-on-Crouch"],["ZBC","Barons Court Underground"],["CPN","Chapleton"],["ROG","Rogart"],["LVG","Livingston South"],["HTC","Heaton Chapel"],["KGN","Kings Nympton"],["LCC","Lochluichart"],["DCG","Duncraig"],["TOD","Todmorden"],["WEA","West Ealing"],["SOK","South Kenton"],["SLA","Slateford"],["HLC","Helensburgh Central"],["LGJ","Loughborough Junction"],["HED","Halewood"],["ATH","Atherstone"],["EYN","Eynsford"],["SOT","Stoke-on-Trent"],["CAC","Caldercruix"],["SRC","Streatham Common"],["MSO","Moston"],["BEU","Beaulieu Road"],["ZBK","Barking Underground"],["BNR","Brockley Whins (T & W Metro)"],["LOH","Lostock Hall"],["MIL","Mill Hill Broadway"],["OHL","Old Hill"],["BDW","Bedwyn"],["PMA","Portsmouth Arms"],["WHC","Walthamstow Central"],["KDY","Kirkcaldy"],["FAZ","Fazakerley"],["GLC","Glasgow Central"],["HLU","Helensburgh Upper"],["LTG","Lostock Gralam"],["DLK","Dalston Kingsland"],["MTN","Moreton (Dorset)"],["EBL","East Boldon (T & W Metro)"],["CYN","Cynghordy"],["CHT","Chathill"],["HPT","Hopton Heath"],["ALO","Alloa"],["PMS","Portsmouth & Southsea"],["CON","Connel Ferry"],["WNC","Windsor & Eton Central"],["BET","Bethnal Green"],["SST","Stansted Mountfitchet"],["ESH","Esher"],["WSE","Winchelsea"],["CSS","Chessington South"],["CSL","Codsall"],["CPA","Corpach"],["HGF","Hag Fold"],["SRD","Stapleton Road"],["UPM","Upminster"],["BSJ","Bedford St Johns"],["RYB","Roy Bridge"],["DMP","Dumpton Park"],["LYT","Lymington Town"],["WHE","Whalley"],["HKC","Hackney Central"],["HYC","Hyde Central"],["PEW","Pewsey"],["AHN","Ashton-under-Lyne"],["PRW","Perranwell"],["CKL","Corkickle"],["DOD","Dodworth"],["WTA","Wester Hailes"],["PAW","Pelaw (T & W Metro)"],["AYP","Albany Park"],["NEW","Newcraighall"],["ORE","Ore"],["HAS","Halesworth"],["KWG","Kew Gardens"],["EXG","Exhibition Centre"],["HIL","Hillside"],["MPL","Marple"],["SDA","Snodland"],["BKA","Bookham"],["BNT","Brinnington"],["HKW","Hackney Wick"],["ACR","Accrington"],["QRP","Queens Road Peckham"],["MDG","Midgham"],["BAW","Blackwater"],["MEX","Mexborough"],["ADK","Ardwick"],["DNY","Danby"],["HIN","Hindley"],["PYG","Paisley Gilmour Street"],["PRA","Prestwick Intl Airport"],["DDP","Dudley Port"],["NMK","Newmarket"],["KGL","Kings Langley"],["MLN","Milngavie"],["FML","Frimley"],["NTR","Northallerton"],["SDW","Sandwich"],["BBW","Berry Brow"],["DID","Didcot Parkway"],["SOG","Stonegate"],["HAI","Halling"],["PWL","Pwllheli"],["WCF","Westcliff"],["HGG","Haggerston"],["CMR","Cromer"],["ALX","Alexandria"],["COO","Cookham"],["MRS","Monks Risborough"],["YRT","Yorton"],["BEN","Bentham"],["GOB","Gobowen"],["HAL","Hale"],["CAY","Carntyne"],["BUI","Burnside"],["SEL","Sellafield"],["WIM","Wimbledon"],["YRD","Yardley Wood"],["CHN","Cheshunt"],["HFX","Halifax"],["ELD","Earlswood (Surrey)"],["TOK","Three Oaks"],["PBN","Paris Nord"],["TED","Teddington"],["HKM","Hykeham"],["GRS","Garscadden"],["DSL","Disley"],["HDE","Hedge End"],["BNP","Barnstaple"],["KNS","Kennishead"],["LAK","Lakenheath"],["TUH","Tulse Hill"],["BSY","Brondesbury"],["FOX","Foxfield"],["SHR","Shrewsbury"],["WMG","Welham Green"],["HLF","Hillfoot"],["PMR","Peckham Rye"],["SGR","Slade Green"],["FRE","Freshfield"],["SDG","Sandling"],["DMR","Dalmuir"],["TRF","Trefforest"],["LZB","Lazonby & Kirkoswald"],["KCK","Knockholt"],["LLW","Llwyngwril"],["DCT","Danescourt"],["HRM","Harrietsham"],["WCM","Wickham Market"],["FEA","Featherstone"],["HNH","Herne Hill"],["MCO","Manchester Oxford Road"],["LER","Leytonstone High Road"],["RAU","Rauceby"],["HMW","Hampton Wick"],["SJS","St James Street"],["TEA","Tees-side Airport"],["LNR","Llanwrda"],["BEE","Beeston"],["MTV","Mount Vernon"],["BSV","Buckshaw Parkway"],["DAL","Dalmally"],["KTN","Kentish Town"],["TRA","Trafford Park"],["AMB","Ambergate"],["GOX","Goxhill"],["PLT","Pontlottyn"],["ATT","Attadale"],["POK","Pokesdown"],["STI","Stadium of Light (T & W Metro)"],["HOO","Hooton"],["KGS","Kings Sutton"],["KTW","Kentish Town West"],["ZPC","Piccadilly Circus Underground"],["UTT","Uttoxeter"],["BLH","Bellshill"],["BGA","Brundall Gardens"],["PRT","Prestatyn"],["CPT","Clapton"],["LET","Letchworth Garden City"],["PSN","Parson Street"],["PNE","Penge East"],["NFD","Northfield"],["LTV","Lichfield Trent Valley"],["CBG","Cambridge"],["NPD","New Pudsey"],["ETL","East Tilbury"],["LTV","Lichfield Trent Valley"],["SNI","Snaith"],["AVN","Avonmouth"],["TEN","Tenby"],["PTG","Port Glasgow"],["SPF","Springfield"],["TBD","Three Bridges"],["SLD","Salford Crescent"],["GOE","Goldthorpe"],["SMY","St Mary Cray"],["DBY","Derby"],["HXX","Heathrow Airport T123"],["THO","Thornford"],["PRE","Preston"],["KWN","Kilwinning"],["PRE","Preston"],["HWH","Haltwhistle"],["CNN","Canonbury"],["BOH","Bosham"],["OPK","Orrell Park"],["BDB","Broadbottom"],["LCK","Lockwood"],["NFL","Northfleet"],["TNP","Tonypandy"],["FOC","Falls of Cruachan"],["HYM","Haymarket"],["HIT","Hitchin"],["CLE","Cleethorpes"],["PAL","Palmers Green"],["ARD","Ardgay"],["BUS","Busby"],["LGE","Long Eaton"],["TUL","Tulloch"],["ABD","Aberdeen"],["BRO","Bridge of Orchy"],["GCT","Great Coates"],["INE","Ince & Elton"],["WTT","Witton"],["TRS","Thurston"],["FNC","Farncombe"],["EBD","Ebbsfleet International"],["DUR","Durrington-on-Sea"],["CSA","Cosham"],["PEG","Pegswood"],["CEA","Cleland"],["GCR","Gloucester"],["TAC","Tackley"],["MFH","Milford Haven"],["PRY","Perry Barr"],["RHL","Rhyl"],["THW","The Hawthorns"],["WTH","Whitehaven"],["KNG","Kingston"],["MIK","Micklefield"],["LRG","Lairg"],["EPS","Epsom"],["WBQ","Warrington Bank Quay"],["CUW","Clunderwen"],["DTG","Dinting"],["ACT","Ascot"],["BID","Bidston"],["BWG","Bowling"],["BMP","Brampton (Cumbria)"],["CLT","Clacton-on-Sea"],["BCH","Birchington-on-Sea"],["BEF","Benfleet"],["HMS","Helmsdale"],["KEY","Keyham"],["MOS","Moss Side"],["PTK","Partick"],["SGN","South Greenford"],["SOR","Sole Street"],["DBD","Denby Dale"],["BSP","Brondesbury Park"],["SEE","Southease"],["CNR","Crianlarich"],["CRT","Chartham"],["SUG","Sugar Loaf"],["HGM","Higham"],["WNG","Waun-gron Park"],["DUM","Dumbreck"],["PMR","Peckham Rye"],["CRB","Corbridge"],["NFA","North Fambridge"],["AGV","Abergavenny"],["HAG","Hagley"],["CEL","Chelford"],["HGD","Hungerford"],["BWN","Bloxwich North"],["KVD","Kelvindale"],["RUS","Ruswarp"],["CLV","Claverdon"],["RNH","Rainhill"],["EWW","Ewell West"],["HHY","Highbury & Islington"],["APP","Appleby"],["HKN","Hucknall"],["MSN","Marsden"],["TPC","Thorpe Culvert"],["EWE","Ewell East"],["GTN","Grangetown"],["LEO","Leominster"],["DOL","Dolau"],["CUH","Curriehill"],["KBK","Kents Bank"],["DPS","Dublin Port (Stena)"],["PAI","Pallion (T & W Metro)"],["MCB","Moulsecoomb"],["NMT","Needham Market"],["WFI","Westerfield"],["SCG","Stone Crossing"],["STR","Stranraer"],["ZWA","Waterloo Underground"],["PIL","Pilning"],["SWD","Swinderby"],["MSK","Marske"],["TRN","Troon"],["WID","Widnes"],["KMS","Kemsing"],["STZ","St Peters (T & W Metro)"],["ANF","Ashurst New Forest"],["WTN","Whitton"],["ANL","Anniesland"],["SCS","Starcross"],["FRB","Fairbourne"],["STK","Stockton"],["BEV","Beverley"],["KKM","Kirkham & Wesham"],["PDW","Paddock Wood"],["CAN","Carnoustie"],["STC","Strathcarron"],["CUF","Cuffley"],["MTP","Montpelier"],["SWM","Swanscombe"],["CBE","Canterbury East"],["DMF","Dumfries"],["HNT","Huntly"],["LLT","Llanbister Road"],["WAT","London Waterloo"],["MEW","Maesteg (Ewenny Road)"],["SUT","Sutton Coldfield"],["LDS","Leeds"],["BNM","Burnham"],["BEL","Beauly"],["HXM","Hoveton & Wroxham"],["HDL","Headstone Lane"],["LEY","Leyland"],["PRE","Preston"],["SNY","Sunnymeads"],["RNF","Rainford"],["EGN","Eastrington"],["KGH","Kinghorn"],["MAT","Matlock"],["NCK","New Cumnock"],["NWP","Newport (South Wales)"],["QPW","Queens Park (London)"],["MSD","Moorside"],["WLM","Williamwood"],["DWD","Dolwyddelan"],["WTL","Whitland"],["MPK","Mosspark"],["MAU","Mauldeth Road"],["HEX","Hexham"],["CLI","Clifton"],["SYD","Sydenham"],["LAD","Ladywell"],["CTM","Chatham"],["SWY","Sway"],["TRU","Truro"],["DLY","Dalry"],["PRP","Preston Park"],["BPB","Blackpool Pleasure Beach"],["LHO","Langho"],["SPS","Stepps"],["TOP","Topsham"],["BIA","Bishop Auckland"],["HTH","Handforth"],["MRT","Moreton (Merseyside)"],["MCH","March"],["TDU","Tondu"],["BCS","Bicester North"],["NMP","Northampton"],["ALP","Althorpe"],["BSE","Bury St Edmunds"],["PTR","Petersfield"],["BUC","Buckenham"],["KLY","Kenley"],["ELW","Eltham"],["WHA","Westenhanger"],["WWL","Whitwell"],["EDW","East Dulwich"],["NRD","North Road"],["BTE","Bitterne"],["IMW","Imperial Wharf"],["ANN","Annan"],["BDN","Brading"],["CES","Cressing"],["KBW","Knebworth"],["DAR","Darlington"],["HWD","Hawarden"],["TAD","Tadworth"],["BAG","Bagshot"],["ZHS","Kensington High St Underground"],["SMD","Stamford"],["BUD","Burneside"],["DOT","Dunston"],["ELS","Elstree & Borehamwood"],["CHF","Church Fenton"],["HAZ","Hazel Grove"],["KMH","Kempston Hardwick"],["SOF","South Woodham Ferrers"],["NRW","Norwich"],["AHS","Ashurst"],["FZW","Fitzwilliam"],["MIN","Milliken Park"],["RUN","Runcorn"],["WSL","Walsall"],["OKM","Oakham"],["WAT","London Waterloo"],["AYP","Albany Park"],["MST","Maesteg"],["KNU","Knucklas"],["LEI","Leicester"],["WAT","London Waterloo"],["WCR","Whitecraigs"],["MRP","Moorthorpe"],["SNH","St Helens Central"],["CAO","Cannock"],["RAI","Rainham (Kent)"],["RKT","Ruskington"],["YOK","Yoker"],["BDT","Bridlington"],["LDN","Llandanwg"],["SHJ","St Helens Junction"],["CHH","Christs Hospital"],["CMF","Cromford"],["HYR","Haydons Road"],["LGN","Longton"],["BXH","Bexleyheath"],["CPM","Chippenham"],["DFR","Drumfrochar"],["NCO","Newcourt"],["WET","Weeton"],["EMD","East Midlands Parkway"],["POP","Poppleton"],["AYH","Aylesham"],["ZUM","Upminster Underground"],["CHD","Chesterfield"],["HEZ","Heworth (T & W Metro)"],["PRB","Prestbury"],["GTR","Goostrey"],["ACK","Acklington"],["KNL","Kensal Green"],["SAN","Sandown"],["THL","Tile Hill"],["SIP","Shipton"],["SFA","Stratford International"],["UPW","Upwey"],["GIP","Gipsy Hill"],["RUT","Rutherglen"],["SES","South Elmsall"],["TGM","Teignmouth"],["ADS","Ardrossan Harbour"],["BCG","Birchgrove"],["RFD","Rochford"],["PES","Pensarn"],["BAI","Blairhill"],["TLB","Talybont"],["SVG","Stevenage"],["WPE","Wapping"],["BDG","Bridgeton"],["THH","Thatto Heath"],["ATB","Attenborough"],["MTH","Motherwell"],["WKM","Wokingham"],["GMT","Grosmont"],["ARL","Arlesey"],["BGD","Bargoed"],["REE","Reedham (Norfolk)"],["HPA","Honor Oak Park"],["NUN","Nuneaton"],["TRM","Trimley"],["WTY","Witley"],["SWO","Snowdown"],["MDB","Maidstone Barracks"],["ENL","Enfield Lock"],["MIJ","Mitcham Junction"],["MDE","Maidstone East"],["GOD","Godalming"],["HGR","Hither Green"],["SPO","Spondon"],["WNT","Wandsworth Town"],["ECR","East Croydon"],["CLS","Chester-le-Street"],["QYD","Quakers Yard"],["WBC","Waterbeach"],["NES","Neston"],["PCN","Paisley Canal"],["WSA","West Allerton"],["SFI","Shawfair"],["SLH","Sleights"],["HTN","Hatton"],["KIV","Kiveton Bridge"],["RIS","Rishton"],["DMS","Dormans"],["LCN","Lincoln Central"],["AYP","Albany Park"],["ERI","Eridge"],["WLC","Waltham Cross"],["MPT","Morpeth"],["MDW","Maidstone West"],["WEL","Wellingborough"],["HRY","Harringay Green Lanes"],["MOB","Mobberley"],["SWL","Swale"],["ECC","Eccles"],["HEW","Heworth"],["LLH","Llangennech"],["BKO","Brookwood"],["GSY","Guiseley"],["SBY","Selby"],["WSB","Westbury"],["ETC","Etchingham"],["BLT","Blantyre"],["SSD","Stansted Airport"],["DOR","Dore"],["NVR","Navigation Road"],["CFF","Croftfoot"],["CKN","Crewkerne"],["GLT","Glenrothes with Thornton"],["WTG","Watlington"],["BAN","Banbury"],["HYS","Hayes (Kent)"],["BHR","Builth Road"],["KND","Kingswood"],["KNN","Kings Norton"],["WOL","Wolverton"],["WTO","Water Orton"],["ADR","Airdrie"],["LLC","Llandecwyn"],["PKS","Parkstone (Dorset)"],["GOM","Gomshall"],["TYL","Tyndrum Lower"],["BOP","Bowes Park"],["HRY","Harringay Green Lanes"],["HER","Hersham"],["WRH","Worthing"],["BON","Bolton"],["BOA","Bradford-on-Avon"],["CFH","Chafford Hundred"],["UTY","Upper Tyndrum"],["NAR","Narberth"],["BDL","Birkdale"],["HMT","Ham Street"],["MKM","Melksham"],["AUW","Ascott-under-Wychwood"],["EAL","Ealing Broadway"],["EAL","Ealing Broadway"],["WTB","Whitby"],["CST","London Cannon Street"],["DWN","Darwen"],["BLE","Bramley (West Yorkshire)"],["AAP","Alexandra Palace"],["NUF","Nutfield"],["STG","Stirling"],["HON","Honiton"],["BPW","Bristol Parkway"],["KIT","Kintbury"],["RAD","Radley"],["MCE","Metro Centre"],["SNT","Stanlow & Thornton"],["BYD","Barry Docks"],["DAM","Dalmeny"],["FIN","Finstock"],["BMT","Bedminster"],["HSL","Haslemere"],["CET","Colchester Town"],["HDG","Heald Green"],["PNR","Penrith"],["MHM","Merstham"],["HSC","Hoscar"],["SNO","St Neots"],["BGM","Bellingham"],["NTL","Netley"],["HYH","Hythe"],["RDC","Redditch"],["LTK","Little Kimble"],["FOD","Ford"],["CLJ","Clapham Junction"],["HON","Honiton"],["CLJ","Clapham Junction"],["PNW","Penge West"],["WFJ","Watford Junction"],["HCH","Holmes Chapel"],["LVN","Littlehaven"],["BTL","Batley"],["ZET","Earl's Court Underground"],["WDL","Woodhall"],["BLX","Bloxwich"],["HLS","Hilsea"],["MKT","Marks Tey"],["OKE","Okehampton"],["HWY","High Wycombe"],["SYT","Somerleyton"],["MRY","Maryport"],["SDY","Sandy"],["CLJ","Clapham Junction"],["CEF","Chapel-en-le-Frith"],["LTP","Littleport"],["KPT","Kilpatrick"],["WDD","Widdrington"],["WHM","Whimple"],["CIT","Chislehurst"],["PFR","Pontefract Baghill"],["BKC","Birkenhead Central"],["HOY","Honley"],["INC","Ince"],["CLJ","Clapham Junction"],["GRC","Great Chesterford"],["IPS","Ipswich"],["WCB","Westcombe Park"],["CLJ","Clapham Junction"],["LYP","Lymington Pier"],["CTF","Catford"],["CTE","Chatelherault"],["FWY","Five Ways"],["NDL","North Dulwich"],["BWO","Bricket Wood"],["BKN","Birkenhead North"],["SOW","Sowerby Bridge"],["BTY","Bentley (Hampshire)"],["KLD","Kildale"],["NQY","Newquay"],["SCA","Scarborough"],["BEG","Beltring"],["BKP","Birkenhead Park"],["CLJ","Clapham Junction"],["GLO","Glossop"],["GRH","Gartcosh"],["TUT","Tutbury & Hatton"],["BCE","Bracknell"],["NNT","Nunthorpe"],["ZNP","Newbury Park Underground"],["SND","Sandhurst"],["FSB","Fishbourne (West Sussex)"],["SLW","Salwick"],["DIG","Digby & Sowton"],["EDG","Edge Hill"],["INH","Invershin"],["BTB","Barnetby"],["SJN","St James (T & W Metro)"],["SUY","Sudbury"],["AIG","Aigburth"],["ELR","Elsecar"],["SGB","Smethwick Galton Bridge"],["HYL","Hayle"],["KEM","Kemble"],["WIM","Wimbledon"],["SAS","St Annes-on-the-Sea"],["SHM","Sheringham"],["WRL","Wetheral"],["SUP","Sundridge Park"],["AWM","Ashwell & Morden"],["BUY","Burley Park"],["ABA","Aberdare"],["CRO","Croy"],["DAT","Datchet"],["LGS","Langside"],["WDM","Windermere"],["GMY","Goodmayes"],["BDQ","Bradford Forster Square"],["SOH","South Hampstead"],["GPK","Grange Park"],["EDP","Edinburgh Park"],["NWB","North Wembley"],["NWE","Newport (Essex)"],["CYT","Cherry Tree"],["HUY","Huyton"],["SFN","Shifnal"],["TOM","Tottenham Hale"],["CDI","Crediton"],["HUT","Hutton Cranswick"],["ABW","Abbey Wood"],["GDL","Godley"],["RHD","Ribblehead"],["TYP","Tynemouth (T & W Metro)"],["CSO","Croston"],["PHR","Penshurst"],["LAC","Lancing"],["SWS","South Wigston"],["BUX","Buxton"],["MLD","Mouldsworth"],["FLE","Fleet"],["MKR","Market Rasen"],["LEG","Lea Green"],["CMH","Cwmbach"],["TMC","Templecombe"],["TWI","Twickenham"],["WEE","Weeley"],["HID","Hall I' Th' Wood"],["TTF","Thetford"],["DLH","Doleham"],["BTF","Bottesford"],["JOR","Jordanhill"],["TIL","Tilbury Town"],["BMR","Bromborough Rake"],["DPD","Dorking Deepdene"],["BUT","Burton-on-Trent"],["LEO","Leominster"],["FRN","Fearn"],["SPK","Sutton Parkway"],["STL","Southall"],["VXH","Vauxhall"],["ALM","Alnmouth"],["HMN","Homerton"],["PNS","Penistone"],["DFP","Dublin Ferryport"],["SED","Shelford"],["MLB","Millbrook (Bedfordshire)"],["WWR","Wandsworth Road"],["WBR","Whaley Bridge"],["CNS","Conisbrough"],["JHN","Johnstone"],["LND","Longniddry"],["STF","Stromeferry"],["BCN","Branchton"],["PET","Petts Wood"],["RSG","Rose Grove"],["SAM","Saltmarshe"],["BNS","Barnes"],["PKG","Penkridge"],["SGB","Smethwick Galton Bridge"],["MUF","Manchester United FC"],["RHY","Rhymney"],["AMR","Amersham"],["KDB","Kidbrooke"],["PLC","Pluckley"],["CSM","Castleton Moor"],["HWF","Heathrow Airport T4 (Bus)"],["TAD","Tadworth"],["GTY","Gatley"],["HWX","Heathrow Airport T5 (Bus)"],["BLK","Blackrod"],["SLK","Silkstone Common"],["BSB","Bleasby"],["AGS","Argyle Street"],["MUI","Muirend"],["SMG","St Margarets (London)"],["MAN","Manchester Piccadilly"],["SEG","Selling"],["PLN","Portlethen"],["BSM","Branksome"],["NLN","New Lane"],["HTO","Hightown"],["BYI","Barry Island"],["HOL","Holton Heath"],["SFL","Seaforth & Litherland"],["SBR","Spean Bridge"],["KGS","Kings Sutton"],["LRB","London Road (Brighton)"],["GSC","Gilshochill"],["MCM","Morecambe"],["STP","London St Pancras (Intl)"],["FGT","Faygate"],["ALD","Alderley Edge"],["COH","Crowborough"],["ANF","Ashurst New Forest"],["OCK","Ockendon"],["ASN","Addlestone"],["CLL","Collington"],["MOT","Motspur Park"],["SDL","Sandhills"],["KKB","Kirkby in Ashfield"],["PAD","London Paddington"],["WOB","Woburn Sands"],["BNI","Barnes Bridge"],["QPW","Queens Park (London)"],["BNY","Barnsley"],["BPN","Blackpool North"],["KWD","Kirkwood"],["SCH","Scotstounhill"],["KNT","Kenton"],["LHD","Leatherhead"],["DRO","Dronfield"],["MRD","Morchard Road"],["CHU","Cheadle Hulme"],["LIC","Lichfield City"],["DSM","Darsham"],["ENF","Enfield Town"],["SSE","Shoreham-by-Sea"],["LGF","Longfield"],["LIP","Liphook"],["ACC","Acton Central"],["NHE","New Hythe"],["GCH","Garelochhead"],["GSN","Garston (Hertfordshire)"],["WRY","Wraysbury"],["RID","Ridgmont"],["KNF","Knutsford"],["STN","Stonehaven"],["WHP","West Hampstead Thameslink"],["DIS","Diss"],["MLG","Mallaig"],["REI","Reigate"],["DNG","Dunton Green"],["LUX","Luxulyan"],["GFD","Greenford"],["GNR","Green Road"],["STH","Shepreth"],["BXW","Boxhill & Westhumble"],["DUD","Duddeston"],["FER","Fernhill"],["CHI","Chingford"],["BKQ","Hamilton Square"],["MUB","Musselburgh"],["ULL","Ulleskelf"],["CLP","Clapham High Street"],["COW","Cowdenbeath"],["GLH","Glasshoughton"],["ATL","Attleborough"],["BIN","Bingham"],["LGO","Llangynllo"],["LRB","London Road (Brighton)"],["WKD","Walkden"],["HRW","Harrow & Wealdstone"],["URM","Urmston"],["CUA","Culrain"],["NBW","North Berwick"],["DMC","Drumchapel"],["EMP","Emerson Park"],["HLE","Hillington East"],["MGN","Marston Green"],["UWL","Upper Warlingham"],["LWM","Llantwit Major"],["ZDE","Dagenham East Underground"],["HIB","High Brooms"],["TQY","Torquay"],["LEU","Leuchars"],["LST","London Liverpool Street"],["ZTG","Turnham Green Underground"],["CDY","Cartsdyke"],["MTC","Mitcham Eastfields"],["HVF","Haverfordwest"],["CSW","Chestfield & Swalecliffe"],["TIR","Tir-phil"],["ERL","Earlestown"],["BGL","Bugle"],["HWM","Harlow Mill"],["SYB","Stalybridge"],["NOA","Newton-on-Ayr"],["FRT","Frant"],["GUI","Guide Bridge"],["HLW","Hillington West"],["MYT","Mytholmroyd"],["BKM","Berkhamsted"],["NEL","Nelson"],["NLT","Northolt Park"],["BES","Bescar Lane"],["BNA","Burnage"],["SRY","Shoeburyness"],["MSR","Minster"],["BNH","Barnehurst"],["DUN","Dunbar"],["LLG","Llangadog"],["PIN","Pinhoe"],["POR","Porth"],["CTR","Chester"],["MCK","Marne La Vallee"],["BUO","Bursledon"],["MDL","Middlewood"],["RHM","Reedham (Surrey)"],["WHD","West Hampstead"],["BDH","Bedhampton"],["ROB","Roby"],["KBF","Kirkby-in-Furness"],["RTR","Rochester"],["STV","Stevenston"],["TIP","Tipton"],["ASB","Ardrossan South Beach"],["DBR","Derby Road"],["LMS","Leamington Spa"],["FSK","Fiskerton"],["HWI","Horwich Parkway"],["WLI","Welling"],["WGC","Welwyn Garden City"],["SOU","Southampton Central"],["RUE","Runcorn East"],["FNH","Farnham"],["SRI","Spring Road"],["TAU","Taunton"],["ALT","Altrincham"],["WDS","Woodlesford"],["LEL","Lelant"],["MNR","Manor Road"],["PPL","Pontypool & New Inn"],["RDG","Reading"],["WNR","Windsor & Eton Riverside"],["SWT","Slaithwaite"],["RCD","Rochdale"],["CYP","Crystal Palace"],["DDG","Dorridge"],["KBX","Kirby Cross"],["SBJ","Stourbridge Junction"],["CRI","Cricklewood"],["WDU","West Dulwich"],["SNN","Swinton (Manchester)"],["BRP","Brampton (Suffolk)"],["COV","Coventry"],["DGL","Dingle Road"],["PYC","Pontyclun"],["LNY","Langley"],["GRP","Grove Park"],["HOU","Hounslow"],["SAE","Saltaire"],["BEH","Bedworth"],["SCY","South Croydon"],["BCY","Brockley"],["AVI","Avignon"],["VIC","London Victoria"],["BWD","Birchwood"],["HWN","Harlow Town"],["VIC","London Victoria"],["FRO","Frome"],["VIC","London Victoria"],["AWT","Armathwaite"],["CAT","Caterham"],["COB","Cooden Beach"],["WVH","Wolverhampton"],["HME","Hamble"],["AUG","Aughton Park"],["BEX","Bexhill"],["ACY","Abercynon"],["CML","Carmyle"],["PBR","Potters Bar"],["TOL","Tolworth"],["APN","Newcastle Airport"],["ADN","Ardrossan Town"],["GDP","Gidea Park"],["SBJ","Stourbridge Junction"],["WIJ","Willesden Junction"],["SDM","Shieldmuir"],["SEV","Sevenoaks"],["FRM","Fareham"],["HNA","Hinton Admiral"],["MRN","Marden"],["MIA","Manchester Airport"],["SBT","Stourbridge Town"],["MAI","Maidenhead"],["BKH","Blackheath"],["BYS","Braystones"],["HGT","Harrogate"],["BIL","Billingham"],["STM","St Michaels"],["BVD","Belvedere"],["LTS","Lelant Saltings"],["LHA","Loch Awe"],["BAD","Banstead"],["INT","Ingatestone"],["MKC","Milton Keynes Central"],["EDR","Edmonton Green"],["BNV","Banavie"],["BTP","Braintree Freeport"],["ROC","Roche"],["CHP","Chipstead"],["FNW","Farnworth"],["TAI","Tain"],["GAL","Galashiels"],["CHG","Charing"],["RMD","Richmond"],["MTN","Moreton (Dorset)"],["COR","Corby"],["SOI","Stow"],["BLG","Bellgrove"],["CNF","Carnforth"],["PST","Prestonpans"],["PKT","Park Street"],["SKS","Stocksfield"],["NRC","Newbury Racecourse"],["PNY","Pen-y-bont"],["EKL","East Kilbride"],["SRU","South Ruislip"],["CDU","Cam & Dursley"],["BRV","Bournville"],["WMS","Wemyss Bay"],["UDD","Uddingston"],["BHD","Brithdir"],["MOR","Mortimer"],["CUM","Culham"],["SDH","Sudbury Hill Harrow"],["STA","Stafford"],["PRL","Prittlewell"],["RDT","Radlett"],["SHP","Shepperton"],["CNP","Conway Park"],["TLK","The Lakes"],["BRX","Brixton"],["MTB","Matlock Bath"],["CLN","Chapeltown"],["KYN","Keynsham"],["NWA","North Walsham"],["BYA","Berney Arms"],["REC","Rectory Road"],["RRB","Ryder Brow"],["SUD","Sudbury & Harrow Road"],["SMN","Southminster"],["YAT","Yatton"],["KSN","Kearsney"],["PTF","Pantyffynnon"],["SWN","Swinton (South Yorkshire)"],["SRN","Strines"],["SWA","Swansea"],["TRR","Torre"],["SSC","Seascale"],["HOT","Henley-on-Thames"],["MVL","Malvern Link"],["ARR","Arram"],["SLT","Saltcoats"],["ANZ","Anerley"],["FPK","Finsbury Park"],["LAN","Lancaster"],["THA","Thatcham"],["BSC","Bescot Stadium"],["MTO","Marton"],["EGG","Eggesford"],["KEH","Keith"],["WCY","West Croydon"],["BOD","Bodmin Parkway"],["HOP","Hope (Derbyshire)"],["HRW","Harrow & Wealdstone"],["WTC","Whitchurch (Shropshire)"],["CHX","London Charing Cross"],["KIR","Kirkby"],["WGA","Westgate-on-Sea"],["WSM","Weston-super-Mare"],["BKS","Bekesbourne"],["AHT","Aldershot"],["DFI","Duffield"],["GIR","Girvan"],["ZBB","Barbican Underground"],["HPE","Hope (Flintshire)"],["CLW","Chorleywood"],["HHL","Heath High Level"],["KKS","Kirk Sandall"],["RDD","Riddlesdown"],["RFY","Rock Ferry"],["ABE","Aber"],["HSK","Hassocks"],["SHT","Shotton"],["LVC","Liverpool Central"],["AIN","Aintree"],["HNG","Hengoed"],["LIS","Liss"],["ARM","Armadale"],["FFA","Ffairfach"],["HCB","Hackbridge"],["LVC","Liverpool Central"],["ELP","Ellesmere Port"],["DYF","Dyffryn Ardudwy"],["TYW","Tywyn"],["CWN","Cowden"],["EGH","Egham"],["RET","Retford"],["HAY","Hayes & Harlington"],["SAT","South Acton"],["PMT","Polmont"],["HPQ","Harwich International"],["WED","Wedgwood"],["BIO","Baillieston"],["WCH","Whitchurch (Hampshire)"],["MNE","Manea"],["SNF","Shenfield"],["ROM","Romsey"],["CHL","Chilworth"],["CDN","Coulsdon Town"],["TLS","Thorpe-le-Soken"],["WRS","Wressle"],["BDY","Bredbury"],["THI","Thirsk"],["WES","Westerton"],["CPU","Capenhurst"],["LRH","Larkhall"],["OLD","Old Street"],["DGT","Deansgate"],["SEM","Seamer"],["SVB","Severn Beach"],["BMC","Bromley Cross"],["SEC","Seaton Carew"],["ZLW","Whitechapel"],["SEE","Southease"],["SOA","Southampton Airpt Parkway"],["WDO","Waddon"],["WTS","Whatstandwell"],["LPY","Liverpool South Parkway"],["HFN","Hertford North"],["KGM","Kingham"],["WFL","Wainfleet"],["SKN","St Keyne Wishing Well Halt"],["DPT","Devonport"],["SOW","Sowerby Bridge"],["WDU","West Dulwich"],["BCB","Burscough Bridge"],["HST","High Street"],["LEM","Leyton Midland Road"],["PYL","Pyle"],["WRU","West Ruislip"],["WYB","Weybridge"],["TAB","Tame Bridge Parkway"],["TRE","Trefforest Estate"],["WYB","Weybridge"],["HND","Hanborough"],["WLW","Welwyn North"],["BMO","Birmingham Moor Street"],["BCJ","Burscough Junction"],["DCW","Dorchester West"],["LVJ","James Street"],["RDF","Radcliffe (Nottinghamshire)"],["CPY","Clapham (North Yorkshire)"],["RMF","Romford"],["SAV","Stratford-upon-Avon"],["LHW","Lochwinnoch"],["NOT","Nottingham"],["CUD","Cuddington"],["LLA","Llanaber"],["SNE","Stone"],["SHL","Shawlands"],["FFD","Freshford"],["SHF","Sheffield"],["YRK","York"],["CSD","Cobham & Stoke d'Abernon"],["ENT","Entwistle"],["PRN","Parton"],["ROL","Rolleston"],["BRH","Borth"],["BCV","Bruce Grove"],["SMR","Smethwick Rolfe Street"],["ACN","Achnasheen"],["KWB","Kew Bridge"],["SAR","St Andrews Road"],["ASF","Ashfield"],["FLM","Flimby"],["LBT","Larbert"],["WOR","Worle"],["CWL","Colwall"],["EXC","Exeter Central"],["NTB","Norton Bridge"],["TWY","Twyford"],["ROR","Rogerstone"],["BDI","Bradford Interchange"],["WNL","Whinhill"],["BLA","Blair Atholl"],["KML","Kemsley"],["SDR","Saunderton"],["GRK","Gourock"],["VXH","Vauxhall"],["FTW","Fort William"],["LIT","Littlehampton"],["SIV","St Ives"],["BLD","Baildon"],["GLM","Gillingham (Kent)"],["SHS","Shotts"],["UCK","Uckfield"],["BTG","Barnt Green"],["BOM","Bromborough"],["ACH","Achnashellach"],["UHA","Uphall"],["VXH","Vauxhall"],["DIN","Dingwall"],["HDW","Hadley Wood"],["SOB","Southbourne"],["LEE","Lee"],["QBR","Queenborough"],["LOC","Lockerbie"],["SMA","Small Heath"],["WDB","Woodbridge"],["HIR","Horton-in-Ribblesdale"],["PON","Ponders End"],["FRI","Frinton-on-Sea"],["SAL","Salisbury"],["SRH","Streatham Hill"],["CRK","Chirk"],["EXR","Essex Road"],["HOK","Hook"],["SML","Sea Mills"],["HLY","Holytown"],["NWD","Norwood Junction"],["ASY","Ashley"],["ESW","Elmswell"],["HOH","Harrow-on-the-Hill"],["AGR","Angel Road"],["NSD","Newstead"],["HUL","Hull"],["HLL","Heath Low Level"],["PBL","Parbold"],["JOH","Johnston"],["SMB","Smithy Bridge"],["NSH","North Sheen"],["UPL","Upholland"],["BGE","Broad Green"],["CBY","Charlbury"],["WME","Woodmansterne"],["LAR","Largs"],["MMO","Melton Mowbray"],["LIN","Linlithgow"],["WDT","West Drayton"],["HFE","Hertford East"],["KET","Kettering"],["PUL","Pulborough"],["QRB","Queenstown Road Battersea"],["WMB","Wembley Central"],["BRG","Borough Green & Wrotham"],["GEA","Gretna Green"],["KPA","Kensington Olympia"],["CIM","Cilmeri"],["SWR","Stewartby"],["CMO","Camelon"],["GLQ","Glasgow Queen Street"],["BSU","Brunstane"],["IFI","Ifield"],["ARN","Arnside"],["FRW","Fairwater"],["LKE","Lake"],["CTL","Cattal"],["DMH","Dilton Marsh"],["WWD","Woolwich Dockyard"],["BTS","Burntisland"],["HSW","Heswall"],["KEL","Kelvedon"],["DBL","Dunblane"],["NLR","North Llanrwst"],["HUB","Hunmanby"],["SAF","Salfords"],["WNE","Wilnecote"],["QPK","Queens Park (Glasgow)"],["WTM","Witham"],["AVP","Aylesbury Vale Parkway"],["PTD","Pontarddulais"],["RDG","Reading"],["EXM","Exmouth"],["SNW","Swanwick"],["FCN","Falconwood"],["GOO","Goole"],["LBO","Loughborough"],["HSB","Helsby"],["SHD","Shildon"],["TAY","Taynuilt"],["SNS","Staines"],["CBW","Canterbury West"],["EGF","East Garforth"],["AUR","Aberdour"],["DKG","Dorking"],["GAR","Garrowhill"],["HUN","Huntingdon"],["LLY","Llwynypia"],["SAY","Swanley"],["TTH","Thornton Heath"],["LSK","Liskeard"],["LSW","Leasowe"],["PMP","Plumpton"],["WKK","Wakefield Kirkgate"],["RFY","Rock Ferry"],["DDK","Dagenham Dock"],["HPN","Hapton"],["LNB","Llanbradach"],["BAD","Banstead"],["BIT","Bicester Village"],["MBR","Middlesbrough"],["AAT","Achanalt"],["HIP","Highams Park"],["SIN","Singer"],["TYG","Tygwyn"],["CUP","Cupar"],["FKC","Folkestone Central"],["SIL","Sileby"],["ESM","Elsenham"],["EPD","Epsom Downs"],["HBP","Hornbeam Park"],["HOZ","Howwood"],["RFY","Rock Ferry"],["MEP","Meopham"],["SWG","Swaythling"],["AVM","Aviemore"],["BHK","Bush Hill Park"],["PEA","Peartree"],["WNN","Wennington"],["AYL","Aylesford"],["PIT","Pitlochry"],["OVE","Overpool"],["ZCO","Croxley Underground"],["GYM","Great Yarmouth"],["CPK","Carpenders Park"],["GLC","Glasgow Central"],["LAS","Llansamlet"],["SPN","Spooner Row"],["FKW","Folkestone West"],["KBC","Kinbrace"],["AND","Anderston"],["ZCW","Canada Water"],["DON","Doncaster"],["EAR","Earley"],["CTN","Charlton"],["ZFD","Farringdon Underground"],["SBF","St Budeaux Ferry Road"],["PCD","Pencoed"],["LBG","London Bridge"],["MZH","Maze Hill"],["WTI","Winnersh Triangle"],["HPD","Harpenden"],["SHT","Shotton"],["LBG","London Bridge"],["NRT","Nethertown"],["LBG","London Bridge"],["HMY","Hairmyres"],["HHB","Heysham Port"],["PSH","Pershore"],["PAN","Pangbourne"],["CLU","Carluke"],["SOC","Southend Central"],["MFF","Minffordd"],["BRF","Brierfield"],["COT","Cottingley"],["PTB","Pentre-bach"],["SKG","Skegness"],["INS","Insch"],["EXN","Exton"],["LOO","Looe"],["WWA","Woolwich Arsenal"],["CLK","Clock House"],["BPT","Bishopton"],["BAS","Bere Alston"],["LCS","Locheilside"],["MEV","Merthyr Vale"],["BDH","Bedhampton"],["SDE","Shadwell"],["STP","London St Pancras (Intl)"],["WEH","West Ham"],["HUP","Humphrey Park"],["BTO","Betchworth"],["EVE","Evesham"],["SEF","Seaford"],["ALR","Alresford"],["HNL","Henley-in-Arden"],["SRL","Shirley"],["BFF","Blaenau Ffestiniog"],["FNN","Farnborough North"],["NLW","Newton-le-Willows"],["YAL","Yalding"],["BMH","Bournemouth"],["LHM","Lealholm"],["TVP","Tiverton Parkway"],["BIW","Biggleswade"],["WLS","Woolston"],["BIP","Bishopstone"],["EBV","Ebbw Vale Parkway"],["NNG","Newark North Gate"],["PHG","Penhelig"],["MNG","Manningtree"],["TAT","Tattenham Corner"],["MEN","Menheniot"],["FSB","Fishbourne (West Sussex)"],["CNN","Canonbury"],["HRO","Harold Wood"],["BKJ","Beckenham Junction"],["NFN","Nafferton"],["BNO","Benton (T & W Metro)"],["GRV","Gravesend"],["NBY","Newbury"],["SDC","Shoreditch High Street"],["AXP","Alexandra Parade"],["FXN","Foxton"],["MTS","Montrose"],["BTN","Brighton"],["RDG","Reading"],["CIR","Caledonian Rd & Barnsbury"],["TAL","Talsarnau"],["CWN","Cowden"],["NLS","Nailsea & Backwell"],["WNH","Warnham"],["HWB","Hawarden Bridge"],["LLN","Llandaf"],["NRB","Norbury"],["CSY","Coseley"],["LLL","Llandeilo"],["RIC","Rickmansworth"],["WMB","Wembley Central"],["ADV","Andover"],["PFL","Purfleet"],["SWE","Swineshead"],["SHB","Shirebrook"],["DFD","Dartford"],["HAN","Hanwell"],["NUT","Nutbourne"],["MLW","Marlow"],["WBL","Warblington"],["RHI","Rhiwbina"],["DEP","Deptford"],["CUB","Cumbernauld"],["HCN","Headcorn"],["LAW","Landywood"],["THC","Thurnscoe"],["CNO","Chetnole"],["COI","Crosshill"],["SHW","Shawford"],["BAJ","Baglan"],["SUR","Surbiton"],["AUK","Auchinleck"],["KTL","Kirton Lindsey"],["LID","Lidlington"],["CDR","Cardross"],["SYL","Syon Lane"],["HYT","Hyde North"],["LAI","Laindon"],["HOX","Hoxton"],["LEW","Lewisham"],["BSK","Basingstoke"],["CRW","Crawley"],["GBS","Goring-by-Sea"],["WHS","Whyteleafe South"],["MHR","Market Harborough"],["ERD","Erdington"],["GST","Gathurst"],["LGG","Langley Green"],["OVR","Overton"],["NEH","New Eltham"],["SDN","St Denys"],["MTG","Mottingham"],["WTR","Wateringbury"],["CDB","Cardiff Bay"],["FNT","Feniton"],["BLP","Belper"],["HSG","Hathersage"],["HVH","Hoek Van Holland"],["DVN","Davenport"],["LWH","Lawrence Hill"],["WCK","Wick"],["BMB","Bamber Bridge"],["DRI","Drigg"],["TWN","Town Green"],["CHE","Cheam"],["SAX","Saxmundham"],["MAG","Maghull"],["SBE","Starbeck"],["MCN","Machynlleth"],["CBC","Coatbridge Central"],["BYL","Barry Links"],["BEM","Bempton"],["SFR","Shalford"],["BIC","Billericay"],["BTR","Braintree"],["ISL","Isleworth"],["HLN","Harlington"],["SSM","Stocksmoor"],["GMN","Great Missenden"],["KNE","Kennett"],["POO","Poole"],["RNR","Roughton Road"],["ILK","Ilkley"],["PMH","Portsmouth Harbour"],["RDA","Redland"],["FRS","Forsinard"],["HRN","Hornsey"],["SLY","Selly Oak"],["OXT","Oxted"],["CBS","Coatbridge Sunnyside"],["WMD","Wymondham"],["TEY","Teynham"],["BAV","Barrow Haven"],["BYE","Bynea"],["WKB","West Kilbride"],["BCU","Brockenhurst"],["AMT","Aldermaston"],["LGB","Langbank"],["MRF","Moorfields"],["PMH","Portsmouth Harbour"],["ROO","Roose"],["KIL","Kildonan"],["BHC","Balloch"],["WIV","Wivenhoe"],["BTT","Battersby"],["CCT","Cathcart"],["HRL","Harlech"],["RGW","Ramsgreave & Wilpshire"],["WVF","Wivelsfield"],["SAJ","St Johns"],["WDH","Woodhouse"],["FOG","Forest Gate"],["HTF","Hartford"],["WNW","West Norwood"],["CSG","Cressington"],["SHU","Stonehouse"],["WDN","Walsden"],["SAC","St Albans"],["WFF","Whifflet"],["HOW","Howden"],["MLY","Morley"],["ASG","Alsager"],["LOB","Longbridge"],["WOM","Wombwell"],["MSH","Mossley Hill"],["ECP","Energlyn & Churchill Park"],["EPH","Elephant & Castle"],["RDW","Reading West"],["EKB","Eskbank"],["BRU","Bruton"],["CME","Combe"],["MIH","Mills Hill"],["PPD","Pontypridd"],["SAD","Sandwell & Dudley"],["KGT","Kilgetty"],["BRI","Bristol Temple Meads"],["HOC","Hockley"],["LBR","Llanbedr"],["NSG","New Southgate"],["DGC","Denham Golf Club"],["PNM","Penmere"],["MHS","Meadowhall"],["PSL","Port Sunlight"],["DWW","Dawlish Warren"],["RTN","Renton"],["BUJ","Burton Joyce"],["HUR","Hurst Green"],["BDK","Baldock"],["LNY","Langley"],["BSH","Bushey"],["DOW","Downham Market"],["KIN","Kingussie"],["BLO","Blaydon"],["DVY","Dovey Junction"],["BWS","Barrow Upon Soar"],["SGL","South Gyle"],["WHT","Whitchurch (Glamorgan)"],["ACB","Acton Bridge"],["ZHA","Hammersmith Underground"],["WRB","Wrabness"],["NQU","North Queensferry"],["TYC","Ty Croes"],["ANC","Ancaster"],["NBN","New Brighton"],["HEC","Heckington"],["QUI","Quintrell Downs"],["WCX","Wembley Stadium"],["LWT","Lowestoft"],["RAN","Rannoch"],["THU","Thurgarton"],["CSK","Calstock"],["MER","Merthyr Tydfil"],["NEI","Neilston"],["CBD","Conon Bridge"],["DNO","Dunrobin Castle"],["HUD","Huddersfield"],["SKW","Stoke Newington"],["ARG","Arisaig"],["CNW","Conwy"],["MNN","Menston"],["PLE","Pollokshields East"],["LLO","Llandrindod"],["LAU","Laurencekirk"],["MSL","Mossley"],["SIE","Sherburn-in-Elmet"],["CBH","Cambridge Heath"],["KBN","Kilburn High Road"],["SID","Sidcup"],["FEL","Feltham"],["CCC","Criccieth"],["STO","South Tottenham"],["WOO","Wool"],["GRK","Gourock"],["LLI","Llandybie"],["AXM","Axminster"],["WGV","Wargrave"],["HSD","Hamstead"],["PLW","Pollokshields West"],["BRK","Berwick (Sussex)"],["CTW","Church & Oswaldtwistle"],["XIB","Bourg St Maurice"],["SKI","Skipton"],["BDM","Bedford"],["PLM","Plumley"],["YVJ","Yeovil Junction"],["DEN","Dean"],["DAM","Dalmeny"],["WGN","Wigan North Western"],["WRE","Wrenbury"],["RYN","Roydon"],["YVJ","Yeovil Junction"],["ABH","Abererch"],["UNI","University"],["AMY","Amberley"],["CSB","Carshalton Beeches"],["EFF","Effingham Junction"],["SVK","Seven Kings"],["DEA","Deal"],["WNP","Wanstead Park"],["ALK","Aslockton"],["ULV","Ulverston"],["LIV","Liverpool Lime Street"],["ABC","Altnabreac"],["LAP","Lapford"],["NIT","Nitshill"],["RAM","Ramsgate"],["KNO","Knottingley"],["LIV","Liverpool Lime Street"],["CSH","Carshalton"],["BFE","Bere Ferrers"],["AVY","Aberdovey"],["CBK","Cranbrook (Devon)"],["WLN","Wellington (Shropshire)"],["CGN","Cogan"],["ASC","Ashchurch for Tewkesbury"],["AVF","Avoncliff"],["CBP","Castle Bar Park"],["GSL","Gunnislake"],["HMC","Hampton Court"],["PLY","Plymouth"],["CLA","Clandon"],["CNE","Colne"],["NXG","New Cross Gate"],["CIL","Chilham"],["FLI","Flixton"],["NWX","New Cross"],["BMY","Bramley (Hampshire)"],["CWS","Caersws"],["BHO","Blackhorse Road"],["CFT","Crofton Park"],["GLS","Glaisdale"],["WMI","Wildmill"],["AST","Aston"],["CDT","Caldicot"],["ESD","Elmstead Woods"],["KLN","Kings Lynn"],["SLQ","St Leonards Warrior Square"],["PNC","Penychain"],["BUB","Burnley Barracks"],["BNC","Burnley Central"],["AXM","Axminster"],["AXM","Axminster"],["BGS","Bogston"],["BAC","Bache"],["HWW","How Wood"],["BNG","Bangor (Gwynedd)"],["BRM","Barmouth"],["DNL","Dunlop"],["EML","East Malling"],["CMO","Camelon"],["EDY","East Didsbury"],["SPR","Springburn"],["ELE","Elmers End"],["WKI","West Kirby"],["LBZ","Leighton Buzzard"],["WES","Westerton"],["LYD","Lydney"],["PYT","Poynton"],["RCC","Redcar Central"],["CWE","Crowle"],["KNA","Knaresborough"],["RCE","Redcar East"],["BUH","Brough"],["DAN","Darnall"],["WNF","Winchfield"],["WKF","Wakefield Westgate"],["PWY","Patchway"],["DZY","Danzey"],["FLD","Fauldhouse"],["WPL","Worplesdon"],["BSL","Beasdale"],["KKD","Kirkdale"],["EAG","Eaglescliffe"],["CRM","Cramlington"],["SIH","St Helier"],["HBY","Hartlebury"],["COA","Coatdyke"],["CHW","Chalkwell"],["RYS","Royston"],["DVH","Dove Holes"],["HEV","Hever"],["SPA","Spalding"],["BOG","Bognor Regis"],["EUS","London Euston"],["FRL","Fairlie"],["EDB","Edinburgh"],["MRR","Morar"],["WSH","Wishaw"],["CPW","Chepstow"],["SUU","Sunbury"],["HAP","Hatfield Peverel"],["OUN","Oulton Broad North"],["MIC","Micheldever"],["WOF","Worcester Foregate Street"],["WRX","Wrexham General"],["OUS","Oulton Broad South"],["CAK","Cark"],["FRY","Ferriby"],["FOH","Forest Hill"],["STY","Stratford Parkway"],["OLF","Oldfield Park"],["WAL","Walton-on-Thames"],["PTT","Patterton"],["GLQ","Glasgow Queen Street"],["EBA","Euxton Balshaw Lane"],["HLM","Holmwood"],["FAV","Faversham"],["GOL","Golspie"],["KKH","Kirkhill"],["WSR","Woodsmoor"],["CNL","Canley"],["SPT","Stockport"],["WBD","Whitley Bridge"],["HIA","Hampton-in-Arden"],["BLV","Belle Vue"],["DMK","Denmark Hill"],["DWL","Dawlish"],["FLF","Flowery Field"],["DGY","Deganwy"],["SYS","Syston"],["KKN","Kirknewton"],["WBO","Wimbledon Chase"],["ALB","Albrighton"],["BEP","Bermuda Park (Nuneaton)"],["BFN","Byfleet & New Haw"],["SKM","Stoke Mandeville"],["NEM","New Malden"],["SER","St Erth"],["GNL","Green Lane"],["HEI","Heighington"],["OMS","Ormskirk"],["HBN","Hollingbourne"],["COL","Colchester"],["MES","Melton"],["AHV","Ash Vale"],["KRK","Kirkconnel"],["BYN","Bryn"],["CWC","Chappel & Wakes Colne"],["BIK","Birkbeck"],["SWM","Swanscombe"],["AUD","Audley End"],["BRE","Brentwood"],["YOK","Yoker"],["AHS","Ashurst"],["GSW","Garswood"],["SHU","Stonehouse"],["SNR","Sanderstead"],["BRC","Breich"],["HDM","Haddenham & Thame Parkway"],["BAH","Bank Hall"],["PRR","Princes Risborough"],["SYA","Styal"],["GPO","Gospel Oak"],["SLV","Silver Street"],["FZP","Furze Platt"],["MFA","Morfa Mawddach"],["DLG","Dolgarrog"],["CWB","Colwyn Bay"],["HVN","Havenhouse"],["LUT","Luton"],["GIG","Giggleswick"],["KGP","Kings Park"],["RYH","Rye House"],["GOR","Goring & Streatley"],["HFD","Hereford"],["BIG","Billingshurst"],["STJ","Severn Tunnel Junction"],["SAU","St Austell"],["WHS","Whyteleafe South"],["WST","Wood Street"],["LED","Ledbury"],["MRF","Moorfields"],["OLF","Oldfield Park"],["ATN","Atherton"],["BRS","Berrylands"],["WSB","Westbury"],["CYS","Cathays"],["CWD","Creswell"],["LOS","Lostwithiel"],["BHS","Brockholes"],["THT","Thorntonhall"],["DRG","Drayton Green"],["ANS","Ainsdale"],["DYP","Drayton Park"],["KLY","Kenley"],["LEH","Lea Hall"],["LPR","Long Preston"],["SVS","Seven Sisters"],["WWW","Wootton Wawen"],["SHI","Shiplake"],["WML","Wilmslow"],["EDL","Edale"],["FLX","Felixstowe"],["NBR","Narborough"],["PFY","Poulton-le-Fylde"],["PRP","Preston Park"],["COE","Coombe Junction Halt"],["SST","Stansted Mountfitchet"],["WLD","West St Leonards"],["PMW","Penmaenmawr"],["YEO","Yeoford"],["YVP","Yeovil Pen Mill"],["GRF","Garforth"],["MON","Monifieth"],["NOR","Normanton"],["COM","Commondale"],["ZFD","Farringdon Underground"],["ORR","Orrell"],["LOW","Lowdham"],["YVP","Yeovil Pen Mill"],["HWF","Heathrow Airport T4 (Bus)"],["LPG","Llanfairpwll"],["LWR","Llanrwst"],["CRN","Crowthorne"],["JCH","James Cook"],["LLS","Llanishen"],["NCE","New Clee"],["RAY","Raynes Park"],["SAW","Sawbridgeworth"],["WLO","Waterloo (Merseyside)"],["ROE","Rotherhithe"],["HNB","Herne Bay"],["SHY","Shipley"],["MTA","Mountain Ash"],["SJP","St James' Park"],["LYC","Lympstone Commando"],["NWM","New Milton"],["WIJ","Willesden Junction"],["FLT","Flitwick"],["BRA","Brora"],["HYN","Hyndland"],["RUF","Rufford"],["PTA","Port Talbot Parkway"],["SMH","Stamford Hill"],["GVE","Garve"],["HTE","Hatch End"],["WSE","Winchelsea"],["DLT","Dalton"],["SPY","Shepley"],["CFL","Crossflatts"],["LIH","Leigh (Kent)"],["LYM","Lympstone Village"],["SOL","Solihull"],["CTH","Chadwell Heath"],["FOK","Four Oaks"],["TRI","Tring"],["BLB","Battlesbridge"],["FAL","Falmouth Docks"],["HPL","Hartlepool"],["OXN","Oxenholme Lake District"],["OTF","Otford"],["OUT","Outwood"],["WLE","Whittlesea"],["SBV","St Budeaux Victoria Road"],["HHY","Highbury & Islington"],["CKS","Clarkston"],["EDN","Eden Park"],["SDP","Sandplace"],["AFK","Ashford International"],["DLM","Delamere"],["HHY","Highbury & Islington"],["INK","Inverkeithing"],["SAA","St Albans Abbey"],["HLB","Hildenborough"],["KTH","Kent House"],["BUL","Butlers Lane"],["AML","Acton Main Line"],["FMT","Falmouth Town"],["BAM","Bamford"],["FFD","Freshford"],["WAT","London Waterloo"],["SHN","Shanklin"],["CKT","Crookston"],["BKL","Bickley"],["DND","Dinsdale"],["NCL","Newcastle"],["WLV","Wallasey Village"],["THS","Thurso"],["ZBS","Baker Street Underground"],["WAE","London Waterloo East"],["TIS","Tisbury"],["BXS","Brussels Midi"],["LEA","Leagrave"],["BAB","Balcombe"],["NCZ","Newcastle Central Metro"],["ASH","Ash"],["RDB","Redbridge"],["BBK","Bilbrook"],["BUW","Burley-in-Wharfedale"],["GBD","Gilberdyke"],["NSB","Normans Bay"],["RGT","Rugeley Town"],["SEH","Shoreham (Kent)"],["BSH","Bushey"],["ELG","Elgin"],["FTN","Fratton"],["EBN","Eastbourne"],["FTM","Fort Matilda"],["MBK","Millbrook (Hampshire)"],["POT","Pontefract Tanshelf"],["WGW","Wigan Wallgate"],["SUO","Sutton (Surrey)"],["AYS","Aylesbury"],["LVM","Levenshulme"],["WAD","Wadhurst"],["PGN","Paignton"],["BOC","Bootle"],["BUG","Burgess Hill"],["AHD","Ashtead"],["OKL","Oakleigh Park"],["LTT","Little Sutton"],["BAU","Barton-on-Humber"],["GWE","Gwersyllt"],["PMH","Portsmouth Harbour"],["SBU","Southbury"],["CDF","Cardiff Central"],["DTW","Droitwich Spa"],["FST","London Fenchurch Street"],["CEY","Cononley"],["HML","Hemel Hempstead"],["OKN","Oakengates"],["CGD","Craigendoran"],["PEM","Pemberton"],["NHL","New Holland"],["SNP","Stanhope"],["EST","Easterhouse"],["GRA","Grantham"],["TAP","Taplow"],["SUC","Sutton Common"],["GNH","Greenhithe for Bluewater"],["NCT","Newark Castle"],["BTD","Bolton-on-Dearne"],["HNC","Hamilton Central"],["ECL","Eccleston Park"],["OLY","Ockley"],["PLD","Portslade"],["BBG","Bishopbriggs"],["COP","Copplestone"],["SDB","Sandbach"],["COV","Coventry"],["EXD","Exeter St Davids"],["LTH","Llanhilleth"],["SQH","Sanquhar"],["ERA","Eastham Rake"],["BSK","Basingstoke"],["MIR","Mirfield"],["PFM","Pontefract Monkhill"],["GUN","Gunnersbury"],["WLG","Wallasey Grove Road"],["PBO","Peterborough"],["PLU","Plumstead"],["CDQ","Cardiff Queen Street"],["BXB","Broxbourne"],["HNW","Hamilton West"],["EXT","Exeter St Thomas"],["WLT","Wallington"],["HNX","Hunts Cross"],["HMP","Hampton"],["ALF","Alfreton"],["BAA","Barnham"],["SEA","Seaham"],["WBY","West Byfleet"],["BGL","Bugle"],["WRK","Worksop"],["WWI","West Wickham"],["FGT","Faygate"],["STW","Strawberry Hill"],["NFL","Northfleet"],["BUE","Bures"],["NMP","Northampton"],["CBL","Cambuslang"],["GFN","Giffnock"],["INV","Inverness"],["WGR","Woodgrange Park"],["STS","Saltash"],["STP","London St Pancras (Intl)"],["SUN","Sunderland"],["SDF","Saundersfoot"],["FNV","Furness Vale"],["YAE","Yate"],["MCV","Manchester Victoria"],["RED","Redruth"],["SNG","Sunningdale"],["PDG","Padgate"],["HTR","Heathrow Central Bus Stn"],["BHI","Birmingham International"],["CWH","Crews Hill"],["NTA","Newton Abbot"],["SFA","Stratford International"],["WOH","Woldingham"],["SXY","Saxilby"],["GKC","Greenock Central"],["PTC","Portchester"],["GLD","Guildford"],["BNF","Briton Ferry"],["DAG","Dalgety Bay"],["SOO","Strood"],["DLS","Dalston"],["LFD","Lingfield"],["BBN","Blackburn"],["CGM","Cottingham"],["RVB","Ravensbourne"],["AIR","Airbles"],["BRR","Barrhead"],["CLH","Clitheroe"],["MRM","Manors (T & W Metro)"],["GMT","Grosmont"],["DHM","Durham"],["PAR","Par"],["IVY","Ivybridge"],["LVN","Littlehaven"],["GKW","Greenock West"],["HNK","Hinckley"],["KMK","Kilmarnock"],["RMD","Richmond"],["SIC","Silecroft"],["HAD","Haddiscoe"],["DNM","Denham"],["OXS","Oxshott"],["SLB","Saltburn"],["DNT","Dent"],["WHY","Whyteleafe"],["CRG","Cross Gates"],["LCG","Lochgelly"],["BHG","Bathgate"],["TNF","Tonfanau"],["MAL","Malden Manor"],["NUT","Nutbourne"],["NWX","New Cross"],["TON","Tonbridge"],["TRO","Trowbridge"],["WKG","Workington"],["BSI","Balmossie"],["SMK","Stowmarket"],["LGD","Lingwood"],["FBY","Formby"],["NNP","Ninian Park"],["ADM","Adisham"],["GRL","Greenfaulds"],["RLN","Rowlands Castle"],["AMF","Ammanford"],["KMP","Kempton Park"],["SNL","Stoneleigh"],["BWB","Bow Brickhill"],["ABY","Ashburys"],["BRY","Barry"],["MYL","Maryland"],["BBL","Bat & Ball"],["PUT","Putney"],["CAA","Coventry Arena"],["HMD","Hampden Park"],["GYP","Gypsy Lane"],["CMY","Crossmyloof"],["DUL","Dullingham"],["WNM","Weston Milton"],["AFV","Ansdell & Fairhaven"],["SYH","Sydenham Hill"],["GTW","Gatwick Airport"],["HYK","Hoylake"],["MIS","Mistley"],["PPK","Possilpark & Parkhouse"],["WYM","Wylam"],["MLM","Millom"],["WAV","Wavertree Tech Park"],["LAM","Lamphey"],["CCH","Chichester"],["MLT","Malton"],["SGM","St Germans"],["WND","Wendover"],["HAF","Heathrow Airport T4"],["THE","Theale"],["ADL","Adlington (Lancashire)"],["HWV","Heathrow Airport T5"],["PLK","Plockton"],["HWC","Harwich Town"],["CWU","Crowhurst"],["CHK","Chiswick"],["HEN","Hendon"],["DRU","Drumgelloch"],["HAB","Habrough"],["LVT","Lisvane & Thornhill"],["TOK","Three Oaks"],["SVR","Silverdale"],["HEL","Hensall"],["SON","Steeton & Silsden"],["WIC","Wickford"],["NAN","Nantwich"],["LUD","Ludlow"],["AFS","Ashford (Surrey)"],["SGH","South Gosforth (T & W Metro)"],["WYL","Wylde Green"],["RDH","Redhill"],["RNM","Rainham (Essex)"],["MIF","Millfield (T & W Metro)"],["WIN","Winchester"],["LLR","Llanharan"],["NET","Netherfield"],["BSN","Boston"],["GRN","Grindleford"],["APB","Appley Bridge"],["PYN","Penryn"],["SRR","Sarn"],["BND","Brandon"],["DLW","Dalwhinnie"],["BIB","Bishops Lydeard"],["CUX","Cuxton"],["PRS","Prees"],["CLC","Castle Cary"],["SCF","Stechford"],["CLD","Chelsfield"],["RIL","Rice Lane"],["TBY","Thornaby"],["LPY","Liverpool South Parkway"],["CRV","Craven Arms"],["WMA","West Malling"],["DTN","Denton"],["DOC","Dockyard"],["DCH","Dorchester South"],["NXG","New Cross Gate"],["CDS","Coulsdon South"],["LLF","Llanfairfechan"],["SLL","Stallingborough"],["CDO","Cardonald"],["HAT","Hatfield"],["RDN","Reddish North"],["WOS","Worcester Shrub Hill"],["HAV","Havant"],["SNA","Sandal & Agbrigg"],["MIM","Moreton-in-Marsh"],["ART","Arrochar & Tarbet"],["OBN","Oban"],["RDS","Reddish South"],["TOO","Tooting"],["WMC","Wilmcote"],["SIA","Southend Airport"],["EBT","Edenbridge Town"],["PLG","Polegate"],["BSW","Birmingham Snow Hill"],["GRB","Great Bentley"],["HHB","Heysham Port"],["SNK","Sankey for Penketh"],["BXD","Buxted"],["ASK","Askam"],["CFB","Catford Bridge"],["GMG","Garth (Mid Glamorgan)"],["NCM","North Camp"],["APF","Appleford"],["EWR","East Worthing"],["WON","Walton-on-the-Naze"],["ROW","Rowley Regis"],["WSU","West Sutton"],["BGG","Brigg"],["EBD","Ebbsfleet International"],["ZEL","Elephant & Castle Underground"],["PHR","Penshurst"],["MRB","Manorbier"],["SPH","Shepherds Well"],["STD","Stroud"],["TGS","Ty Glas"],["BCF","Beaconsfield"],["HDF","Hadfield"],["CDD","Cardenden"],["LTL","Littleborough"],["CHR","Christchurch"],["MFT","Mansfield"],["PWE","Pollokshaws East"],["LPW","Lapworth"],["BNE","Bourne End"],["CRA","Cradley Heath"],["CHO","Cholsey"],["WRM","Wareham"],["CSR","Chassen Road"],["SEN","Shenstone"],["BOE","Botley"],["ANG","Angmering"],["DVC","Dovercourt"],["PMG","Porthmadog Harbour (Bus)"],["ORN","Old Roan"],["NGT","Newington"],["KNI","Knighton"],["GVH","Gravelly Hill"],["OXF","Oxford"],["CKY","Crosskeys"],["BLL","Bardon Mill"],["FGH","Fishguard Harbour"],["LYE","Lye"],["CLR","Clarbeston Road"],["HBD","Hebden Bridge"],["IGD","Invergordon"],["YNW","Ynyswen"],["PWW","Pollokshaws West"],["RMB","Roman Bridge"],["GRT","Grateley"],["AGT","Aldrington"],["CED","Cheddington"],["RVN","Ravensthorpe"],["KEN","Kendal"],["MAR","Margate"],["PSE","Pitsea"],["CTK","City Thameslink"],["BAT","Battle"],["HEV","Hever"],["WAS","Watton-at-Stone"],["CLY","Chinley"],["HES","Hessle"],["UPH","Upper Halliford"],["WNS","Winnersh"],["AON","Alton"],["LGK","Longbeck"],["SHC","Streethouse"],["EMS","Emsworth"],["SYH","Sydenham Hill"],["BAK","Battersea Park"],["GLQ","Glasgow Queen Street"],["BKJ","Beckenham Junction"],["UMB","Umberleigh"],["CMN","Carmarthen"],["SHH","Shirehampton"],["MAX","Maxwell Park"],["HGY","Harringay"],["AVF","Avoncliff"],["BYK","Bentley (South Yorkshire)"],["GER","Gerrards Cross"],["HLR","Hall Road"],["HNF","Hednesford"],["FRD","Frodsham"],["KNR","Kensal Rise"],["BCC","Beccles"],["HGN","Hough Green"],["BKW","Berkswell"],["EBR","Edenbridge"],["BKT","Blake Street"],["CEH","Coleshill Parkway"],["LEN","Lenham"],["BEC","Beckenham Hill"],["FNY","Finchley Road & Frognal"],["LTM","Lytham"],["BKJ","Beckenham Junction"],["KDG","Kidsgrove"],["IGD","Invergordon"],["CPH","Caerphilly"],["APS","Apsley"],["HTY","Hattersley"],["SAL","Salisbury"],["BNW","Bootle New Strand"],["SOB","Southbourne"],["BTH","Bath Spa"],["DFE","Dunfermline Town"],["SLS","Shettleston"],["ELY","Ely"],["BMF","Broomfleet"],["NVH","Newhaven Harbour"],["LCL","Lochailort"],["PMD","Pembroke Dock"],["WAR","Ware"],["BFD","Brentford"],["GLZ","Glazebrook"],["HSY","Horsley"],["SPI","Spital"],["SHZ","South Hylton (T & W Metro)"],["MOO","Muir of Ord"],["NHD","Nunhead"],["BKR","Blackridge"],["IRL","Irlam"],["NVN","Newhaven Town"],["WRN","West Runton"],["HDB","Haydon Bridge"],["EAD","Earlsfield"],["RDM","Riding Mill"],["WMR","Widney Manor"],["BPK","Brookmans Park"],["WLF","Whittlesford Parkway"],["GDN","Godstone"],["TFC","Telford Central"],["SHE","Sherborne"],["GNB","Gainsborough Central"],["BOT","Bootle Oriel Road"],["EGR","East Grinstead"],["LNK","Lanark"],["NEG","Newtongrange"],["SAL","Salisbury"],["CFR","Chandlers Ford"],["LGM","Langley Mill"],["GSD","Garsdale"],["LAG","Langwith-Whaley Thorns"],["BNL","Barnhill"],["IVR","Iver"],["CNY","Cantley"],["HGS","Hastings"],["BEY","Ben Rhydding"],["BMD","Brimsdown"],["ARB","Arbroath"],["BLN","Blundellsands & Crosby"],["MSS","Moses Gate"],["DST","Duke Street"],["HYW","Hinchley Wood"],["AYR","Ayr"],["SRO","Shireoaks"],["CAR","Carlisle"],["DSY","Daisy Hill"],["RGL","Rugeley Trent Valley"],["GFF","Gilfach Fargoed"],["WAF","Wallyford"],["INR","Inverurie"],["SBK","South Bank"],["ELO","Elton & Orston"],["SPB","Shepherds Bush"],["STE","Streatham"],["CYB","Cefn-y-Bedd"],["HDY","Headingley"],["HCT","Huncoat"],["DYC","Dyce"],["HYD","Heyford"],["PRH","Penrhyndeudraeth"],["SET","Settle"],["WFH","Watford High Street"],["DLR","Dalreoch"],["BKD","Blakedown"],["PTM","Porthmadog"],["ORP","Orpington"],["GBL","Gainsborough Lea Road"],["SCU","Scunthorpe"],["PTH","Perth"],["TAM","Tamworth"],["TRB","Treherbert"],["BXY","Bexley"],["TRY","Treorchy"],["HRS","Horsforth"],["SHV","Southsea Hoverport (Bus)"],["SUM","Summerston"],["WFJ","Watford Junction"],["FYS","Ferryside"],["NUM","Northumberland Park"],["SVL","Staveley"],["CYK","Clydebank"],["HDN","Harlesden"],["PLS","Pleasington"],["TLC","Tal-y-Cafn"],["WAM","Walmer"],["BMG","Barming"],["IFD","Ilford"],["GTA","Great Ayton"],["NBC","New Beckenham"],["LUD","Ludlow"],["FNR","Farningham Road"],["CFN","Clifton Down"],["HAC","Hackney Downs"],["PGM","Pengam"],["RLG","Rayleigh"],["BKG","Barking"],["BLM","Belmont"],["NTC","Newton St Cyres"],["RYE","Rye"],["DBG","Mottisfont & Dunbridge"],["NWI","Northwich"],["PSC","Prescot"],["DKD","Dunkeld & Birnam"],["AGL","Abergele & Pensarn"],["CRF","Carfin"],["SOM","South Milford"],["CRY","Crayford"],["LIU","Lille Europe"],["GLF","Glenfinnan"],["SWI","Swindon"],["SCR","St Columb Road"],["TEO","Theobalds Grove"],["BHM","Birmingham New Street"],["BML","Bramhall"],["WIJ","Willesden Junction"],["COS","Cosford"],["ACG","Acocks Green"],["DVP","Dover Priory"],["MOG","Moorgate"],["ROS","Rosyth"],["WAO","Walton (Merseyside)"],["GNH","Greenhithe for Bluewater"],["RWC","Rawcliffe"],["LES","Leigh-on-Sea"],["HLI","Healing"],["WEY","Weymouth"],["AFK","Ashford International"],["HON","Honiton"],["RCA","Risca & Pontymister"],["BIY","Bingley"],["FOR","Forres"],["KLM","Kilmaurs"],["BOR","Bodorgan"],["BSS","Barassie"],["PUR","Purley"],["MAC","Macclesfield"],["RBR","Robertsbridge"],["HHE","Haywards Heath"],["ALN","Althorne"],["GBK","Greenbank"],["BMV","Bromsgrove"],["GTO","Gorton"],["PMB","Pembroke"],["SKE","Skewen"],["CAU","Causeland"],["PEN","Penarth"],["UPT","Upton"],["BMN","Bromley North"],["ZTH","Tower Hill Underground"],["KYL","Kyle of Lochalsh"],["TTN","Totton"],["HWF","Heathrow Airport T4 (Bus)"],["BMS","Bromley South"],["ASS","Alness"],["SSS","Sheerness-on-Sea"],["CAG","Carrbridge"],["GTH","Garth (Powys)"],["LOF","London Fields"],["BIS","Bishops Stortford"],["BRW","Brunswick"],["CHH","Christs Hospital"],["HHD","Holyhead"],["MFL","Mount Florida"],["DAK","Dalmarnock"],["WSW","Wandsworth Common"],["MDN","Maiden Newton"],["DFL","Dunfermline Queen Margaret"],["IRV","Irvine"],["WHN","Whiston"],["SBS","St Bees"],["PKG","Penkridge"],["SOU","Southampton Central"],["COY","Coryton"],["GGJ","Georgemas Junction"],["SLR","Sleaford"],["DKT","Dorking West"],["SQU","Squires Gate"],["CMD","Camden Road"],["BSO","Basildon"],["CBR","Cooksbridge"],["BYM","Burnley Manchester Road"],["MLF","Milford (Surrey)"],["RYR","Ryde St Johns Road"],["TEY","Teynham"],["TOT","Totnes"],["FRF","Fairfield"],["PUO","Purley Oaks"],["GNF","Greenfield"],["GRY","Grays"],["BGH","Brighouse"],["FKG","Falkirk Grahamston"],["HKH","Hawkhead"],["PYP","Pont-y-Pant"],["FKK","Falkirk High"],["SOV","Southend Victoria"],["MEY","Merryton"]]);var Ge={findStation:function(e){const t=e.toUpperCase(),n=ke.get(t);return console.log(n),n},searchStation:function(e){const t=[],n=e.length<=3,r=e.length>=3,o=new RegExp(`(${e})`,"gi");return ke.forEach((e,a)=>{let i;n&&o.test(a)&&(i=[a,e]),void 0===i&&r&&o.test(e)&&(i=[a,e]),"object"==typeof i&&t.push(i)}),t.slice(0,5)}};let Fe={};Fe=function(){try{return!!localStorage}catch(e){return!1}}()?{save:function(e,t){localStorage[e]=t},load:function(e){return localStorage[e]},exists:function(e){return!(void 0===localStorage[e])}}:{save:function(e,t){document.cookie=`${e}=${encodeURIComponent(t)}`},load:function(e){var t=`; ${document.cookie};`,n=t.indexOf(`; ${e}=`);if(n<0)return"";n=n+e.length+3;var r=t.indexOf(";",n+1);return decodeURIComponent(t.substring(n,r))}};var Ie={partOfDay:function(e,t){console.log(new Date),null==e&&(e=(new Date).getHours().toString()),void 0===t&&(t=!1);const n=e.substring(0,2);let r="";return console.log("Hours",n),r=n>=0&&n<4?"Late Night":n>=4&&n<7?"Early Morning":n>=7&&n<12?"Morning":n>=12&&n<17?"Afternoon":n<21?"Evening":"Night",t&&(r="night"===r?"tonight":"this "+r),console.log("partOfDay",r),r},toHour:function(e=0){return 36e5-(new Date).getTime()%36e5+e},hourFloor:function(){const e=new Date;return parseInt(36e5*~~(e.getTime()/36e5),10).toString(32)},distance:function(e,t,n,r){const o=.017453292519943295,a=Math.cos,i=.5-a((n-e)*o)/2+a(e*o)*a(n*o)*(1-a((r-t)*o))/2;return 12742*Math.asin(Math.sqrt(i))},maybePluralize:(e,t,n="s")=>`${e} ${t}${1!==e?n:""}`,minuteFloor:function(){const e=new Date;return parseInt(6e4*~~(e.getTime()/6e4),10).toString(32)},debounce:function(e,t){let n;return function(...r){clearTimeout(n),n=setTimeout(()=>e.apply(this,r),t)}},throttle:function(e,t){var n=!1;return function(){n||(e.apply(null,arguments),n=!0,setTimeout((function(){n=!1}),t))}},once:function(e){var t,n=!1;return function(){return n||(t=e.apply(this,arguments),n=!0),t}},isEmpty:function(e){for(const t in e)if(e.hasOwnProperty(t))return!1;return!0},LocalStorage:Fe},Oe=function e(t){function n(e,t,r){var o,a={};if(Array.isArray(e))return e.concat(t);for(o in e)a[r?o.toLowerCase():o]=e[o];for(o in t){var i=r?o.toLowerCase():o,l=t[o];a[i]=i in a&&"object"==typeof l?n(a[i],l,"headers"===i):l}return a}function r(e,r,o,a){"string"!=typeof e&&(e=(r=e).url);var i={config:r},l=n(t,r),s={},c=a||l.data;(l.transformRequest||[]).map((function(e){c=e(c,l.headers)||c})),c&&"object"==typeof c&&"function"!=typeof c.append&&(c=JSON.stringify(c),s["content-type"]="application/json");var u=document.cookie.match(RegExp("(^|; )"+l.xsrfCookieName+"=([^;]*)"));if(u&&(s[l.xsrfHeaderName]=u[2]),l.auth&&(s.authorization=l.auth),l.baseURL&&(e=new URL(e,l.baseURL)+""),l.params){var d=~e.indexOf("?")?"&":"?";e+=d+(l.paramsSerializer?l.paramsSerializer(l.params):new URLSearchParams(l.params))}return(l.fetch||fetch)(e,{method:o||l.method,body:c,headers:n(l.headers,s,!0),credentials:l.withCredentials?"include":void 0}).then((function(e){for(var t in e)"function"!=typeof e[t]&&(i[t]=e[t]);return(l.validateStatus?l.validateStatus(e.status):e.ok)?"stream"==l.responseType?(i.data=e.body,i):e[l.responseType||"text"]().then((function(e){i.data=e,i.data=JSON.parse(e)})).catch(Object).then((function(){return i})):Promise.reject(i)}))}return t=t||{},r.request=r,r.get=function(e,t){return r(e,t,"get")},r.delete=function(e,t){return r(e,t,"delete")},r.options=function(e,t){return r(e,t,"options")},r.post=function(e,t,n){return r(e,n,"post",t)},r.put=function(e,t,n){return r(e,n,"put",t)},r.patch=function(e,t,n){return r(e,n,"patch",t)},r.all=Promise.all,r.spread=function(e){return function(t){return e.apply(this,t)}},r.CancelToken="function"==typeof AbortController?AbortController:Object,r.defaults=t,r.create=e,r}(),Ke="undefined"!=typeof globalThis?globalThis:"undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:{};function xe(){throw new Error("Dynamic requires are not currently supported by @rollup/plugin-commonjs")}var $e,Ye,_e=(function(e,t){ +/*! + localForage -- Offline Storage, Improved + Version 1.9.0 + https://localforage.github.io/localForage + (c) 2013-2017 Mozilla, Apache License 2.0 + */ +e.exports=function e(t,n,r){function o(i,l){if(!n[i]){if(!t[i]){if(!l&&xe)return xe();if(a)return a(i,!0);var s=new Error("Cannot find module '"+i+"'");throw s.code="MODULE_NOT_FOUND",s}var c=n[i]={exports:{}};t[i][0].call(c.exports,(function(e){var n=t[i][1][e];return o(n||e)}),c,c.exports,e,t,n,r)}return n[i].exports}for(var a=xe,i=0;i=43)}})).catch((function(){return!1}))}function w(e){return"boolean"==typeof m?c.resolve(m):L(e).then((function(e){return m=e}))}function b(e){var t=g[e.name],n={};n.promise=new c((function(e,t){n.resolve=e,n.reject=t})),t.deferredOperations.push(n),t.dbReady?t.dbReady=t.dbReady.then((function(){return n.promise})):t.dbReady=n.promise}function H(e){var t=g[e.name].deferredOperations.pop();if(t)return t.resolve(),t.promise}function W(e,t){var n=g[e.name].deferredOperations.pop();if(n)return n.reject(t),n.promise}function v(e,t){return new c((function(n,r){if(g[e.name]=g[e.name]||G(),e.db){if(!t)return n(e.db);b(e),e.db.close()}var o=[e.name];t&&o.push(e.version);var a=i.open.apply(i,o);t&&(a.onupgradeneeded=function(t){var n=a.result;try{n.createObjectStore(e.storeName),t.oldVersion<=1&&n.createObjectStore(S)}catch(n){if("ConstraintError"!==n.name)throw n;console.warn('The database "'+e.name+'" has been upgraded from version '+t.oldVersion+" to version "+t.newVersion+', but the storage "'+e.storeName+'" already exists.')}}),a.onerror=function(e){e.preventDefault(),r(a.error)},a.onsuccess=function(){n(a.result),H(e)}}))}function T(e){return v(e,!1)}function N(e){return v(e,!0)}function R(e,t){if(!e.db)return!0;var n=!e.db.objectStoreNames.contains(e.storeName),r=e.versione.db.version;if(r&&(e.version!==t&&console.warn('The database "'+e.name+"\" can't be downgraded from version "+e.db.version+" to version "+e.version+"."),e.version=e.db.version),o||n){if(n){var a=e.db.version+1;a>e.version&&(e.version=a)}return!0}return!1}function M(e){return new c((function(t,n){var r=new FileReader;r.onerror=n,r.onloadend=function(n){var r=btoa(n.target.result||"");t({__local_forage_encoded_blob:!0,data:r,type:e.type})},r.readAsBinaryString(e)}))}function P(e){return s([C(atob(e.data))],{type:e.type})}function A(e){return e&&e.__local_forage_encoded_blob}function D(e){var t=this,n=t._initReady().then((function(){var e=g[t._dbInfo.name];if(e&&e.dbReady)return e.dbReady}));return d(n,e,e),n}function E(e){b(e);for(var t=g[e.name],n=t.forages,r=0;r0&&(!e.db||"InvalidStateError"===o.name||"NotFoundError"===o.name))return c.resolve().then((function(){if(!e.db||"NotFoundError"===o.name&&!e.db.objectStoreNames.contains(e.storeName)&&e.version<=e.db.version)return e.db&&(e.version=e.db.version+1),N(e)})).then((function(){return E(e).then((function(){k(e,t,n,r-1)}))})).catch(n);n(o)}}function G(){return{forages:[],db:null,dbReady:null,deferredOperations:[]}}function F(e){var t=this,n={db:null};if(e)for(var r in e)n[r]=e[r];var o=g[n.name];o||(o=G(),g[n.name]=o),o.forages.push(t),t._initReady||(t._initReady=t.ready,t.ready=D);var a=[];function i(){return c.resolve()}for(var l=0;l>4,u[s++]=(15&r)<<4|o>>2,u[s++]=(3&o)<<6|63&a;return c}function Se(e){var t,n=new Uint8Array(e),r="";for(t=0;t>2],r+=X[(3&n[t])<<4|n[t+1]>>4],r+=X[(15&n[t+1])<<2|n[t+2]>>6],r+=X[63&n[t+2]];return n.length%3==2?r=r.substring(0,r.length-1)+"=":n.length%3==1&&(r=r.substring(0,r.length-2)+"=="),r}function me(e,t){var n="";if(e&&(n=he.call(e)),e&&("[object ArrayBuffer]"===n||e.buffer&&"[object ArrayBuffer]"===he.call(e.buffer))){var r,o=Z;e instanceof ArrayBuffer?(r=e,o+=ee):(r=e.buffer,"[object Int8Array]"===n?o+=ne:"[object Uint8Array]"===n?o+=re:"[object Uint8ClampedArray]"===n?o+=oe:"[object Int16Array]"===n?o+=ae:"[object Uint16Array]"===n?o+=le:"[object Int32Array]"===n?o+=ie:"[object Uint32Array]"===n?o+=se:"[object Float32Array]"===n?o+=ce:"[object Float64Array]"===n?o+=ue:t(new Error("Failed to get type for BinaryArray"))),t(o+Se(r))}else if("[object Blob]"===n){var a=new FileReader;a.onload=function(){var n=Q+e.type+"~"+Se(this.result);t(Z+te+n)},a.readAsArrayBuffer(e)}else try{t(JSON.stringify(e))}catch(n){console.error("Couldn't convert value into a JSON string: ",e),t(null,n)}}function ge(e){if(e.substring(0,q)!==Z)return JSON.parse(e);var t,n=e.substring(de),r=e.substring(q,de);if(r===te&&z.test(n)){var o=n.match(z);t=o[1],n=n.substring(o[0].length)}var a=fe(n);switch(r){case ee:return a;case te:return s([a],{type:t});case ne:return new Int8Array(a);case re:return new Uint8Array(a);case oe:return new Uint8ClampedArray(a);case ae:return new Int16Array(a);case le:return new Uint16Array(a);case ie:return new Int32Array(a);case se:return new Uint32Array(a);case ce:return new Float32Array(a);case ue:return new Float64Array(a);default:throw new Error("Unkown type: "+r)}}var ye={serialize:me,deserialize:ge,stringToBuffer:fe,bufferToString:Se};function Be(e,t,n,r){e.executeSql("CREATE TABLE IF NOT EXISTS "+t.storeName+" (id INTEGER PRIMARY KEY, key unique, value)",[],n,r)}function pe(e){var t=this,n={db:null};if(e)for(var r in e)n[r]="string"!=typeof e[r]?e[r].toString():e[r];var o=new c((function(e,r){try{n.db=openDatabase(n.name,String(n.version),n.description,n.size)}catch(e){return r(e)}n.db.transaction((function(o){Be(o,n,(function(){t._dbInfo=n,e()}),(function(e,t){r(t)}))}),r)}));return n.serializer=ye,o}function Ce(e,t,n,r,o,a){e.executeSql(n,r,o,(function(e,i){i.code===i.SYNTAX_ERR?e.executeSql("SELECT name FROM sqlite_master WHERE type='table' AND name = ?",[t.storeName],(function(e,l){l.rows.length?a(e,i):Be(e,t,(function(){e.executeSql(n,r,o,a)}),a)}),a):a(e,i)}),a)}function Le(e,t){var n=this;e=h(e);var r=new c((function(t,r){n.ready().then((function(){var o=n._dbInfo;o.db.transaction((function(n){Ce(n,o,"SELECT * FROM "+o.storeName+" WHERE key = ? LIMIT 1",[e],(function(e,n){var r=n.rows.length?n.rows.item(0).value:null;r&&(r=o.serializer.deserialize(r)),t(r)}),(function(e,t){r(t)}))}))})).catch(r)}));return u(r,t),r}function we(e,t){var n=this,r=new c((function(t,r){n.ready().then((function(){var o=n._dbInfo;o.db.transaction((function(n){Ce(n,o,"SELECT * FROM "+o.storeName,[],(function(n,r){for(var a=r.rows,i=a.length,l=0;l0)return void a(be.apply(o,[e,l,n,r-1]));i(t)}}))}))})).catch(i)}));return u(a,n),a}function He(e,t,n){return be.apply(this,[e,t,n,1])}function We(e,t){var n=this;e=h(e);var r=new c((function(t,r){n.ready().then((function(){var o=n._dbInfo;o.db.transaction((function(n){Ce(n,o,"DELETE FROM "+o.storeName+" WHERE key = ?",[e],(function(){t()}),(function(e,t){r(t)}))}))})).catch(r)}));return u(r,t),r}function ve(e){var t=this,n=new c((function(e,n){t.ready().then((function(){var r=t._dbInfo;r.db.transaction((function(t){Ce(t,r,"DELETE FROM "+r.storeName,[],(function(){e()}),(function(e,t){n(t)}))}))})).catch(n)}));return u(n,e),n}function Te(e){var t=this,n=new c((function(e,n){t.ready().then((function(){var r=t._dbInfo;r.db.transaction((function(t){Ce(t,r,"SELECT COUNT(key) as c FROM "+r.storeName,[],(function(t,n){var r=n.rows.item(0).c;e(r)}),(function(e,t){n(t)}))}))})).catch(n)}));return u(n,e),n}function Ne(e,t){var n=this,r=new c((function(t,r){n.ready().then((function(){var o=n._dbInfo;o.db.transaction((function(n){Ce(n,o,"SELECT key FROM "+o.storeName+" WHERE id = ? LIMIT 1",[e+1],(function(e,n){var r=n.rows.length?n.rows.item(0).key:null;t(r)}),(function(e,t){r(t)}))}))})).catch(r)}));return u(r,t),r}function Re(e){var t=this,n=new c((function(e,n){t.ready().then((function(){var r=t._dbInfo;r.db.transaction((function(t){Ce(t,r,"SELECT key FROM "+r.storeName,[],(function(t,n){for(var r=[],o=0;o '__WebKitDatabaseInfoTable__'",[],(function(n,r){for(var o=[],a=0;a0}function Fe(e){var t=this,n={};if(e)for(var r in e)n[r]=e[r];return n.keyPrefix=Ee(e,t._defaultConfig),Ge()?(t._dbInfo=n,n.serializer=ye,c.resolve()):c.reject()}function Ie(e){var t=this,n=t.ready().then((function(){for(var e=t._dbInfo.keyPrefix,n=localStorage.length-1;n>=0;n--){var r=localStorage.key(n);0===r.indexOf(e)&&localStorage.removeItem(r)}}));return u(n,e),n}function Oe(e,t){var n=this;e=h(e);var r=n.ready().then((function(){var t=n._dbInfo,r=localStorage.getItem(t.keyPrefix+e);return r&&(r=t.serializer.deserialize(r)),r}));return u(r,t),r}function Ke(e,t){var n=this,r=n.ready().then((function(){for(var t=n._dbInfo,r=t.keyPrefix,o=r.length,a=localStorage.length,i=1,l=0;l=0;t--){var n=localStorage.key(t);0===n.indexOf(e)&&localStorage.removeItem(n)}})):c.reject("Invalid arguments"),t),r}var Je={_driver:"localStorageWrapper",_initStorage:Fe,_support:De(),iterate:Ke,getItem:Oe,setItem:Ue,removeItem:_e,clear:Ie,length:Ye,key:xe,keys:$e,dropInstance:Ve},je=function(e,t){return e===t||"number"==typeof e&&"number"==typeof t&&isNaN(e)&&isNaN(t)},Xe=function(e,t){for(var n=e.length,r=0;r> wsUrl",t),this.socket=null,this.timer=0,this.clock=null,this.connected=!1,this.connectBuffer=[],this.startWebSocket=function(){const e=""===n?t:`${t}:${n}`;console.log("Starting socket",e);const r=window.MozWebSocket?MozWebSocket:WebSocket;this.socket=new r(e,"stream"),this.socket.onopen=this.handleWebsocketOnOpen.bind(this),this.socket.onmessage=this.handleWebsocketMessage.bind(this),this.socket.onclose=this.handleWebsocketClose.bind(this),this.socket.onerror=function(e){console.error(e)}},this.subscribe=function(e){console.log("Subscribe::",e);const t={request:"SUBSCRIBE",message:"",channel:e};this.connected?this.socket.send(JSON.stringify(t)):this.connectBuffer.push(JSON.stringify(t))},this.send=function(e){console.log("Sending",e),this.socket.send(e)},this.handleData=function(t){e.trigger("message",t)},this.handleBuffer=function(){for(console.log("*** handleBuffer");this.connectBuffer.length>0;){const e=this.connectBuffer.shift();this.socket.send(e)}},this.handleWebsocketOnOpen=function(){this.retry=0,console.log("**** Websocket Connected ****"),this.clock=new Date,this.connected=!0,setTimeout(()=>{this.handleBuffer()},1500)},this.handleWebsocketMessage=function(e){let t;try{console.log("handleWebsocketMessage::raw",e),t=JSON.parse(e.data),console.log("handleWebsocketMessage::command",t)}catch(e){}t&&this.handleData.call(this,t)},this.handleWebsocketClose=function(){console.error("WebSocket Connection Closed.");console.log("Socket alive for",.001);const e=this;console.log("Waiting ",15e3),this.timer=setTimeout((function(){e.startWebSocket()}),15e3)},this.startWebSocket()},Ve=[{follow:!1,name:"nationalrailenq",id:33546465},{follow:!1,name:"networkrail",id:365344176},{follow:!1,name:"NetworkRailSCOT",id:402687948},{follow:!1,name:"AvantiWestCoast",id:0xfdebe737417a000},{follow:!1,name:"CalSleeper",id:2870293725},{follow:!1,name:"CrossCountryUK",id:153368708},{follow:!1,name:"Eurostar",id:98412169},{follow:!1,name:"EurostarUK",id:59742254},{follow:!1,name:"GatwickExpress",id:163816182},{follow:!1,name:"GlasgowSubway",id:224607925},{follow:!1,name:"GWRHelp",id:15589815},{follow:!1,name:"HeathrowExpress",id:20240678},{follow:!1,name:"LNER",id:313306238},{follow:!1,name:"LNRailway",id:0xca2b366c356b000},{follow:!1,name:"northernassist",id:194512268},{follow:!1,name:"ScotRail",id:61569136},{follow:!1,name:"Stansted_Exp",id:257511611},{follow:!1,name:"TfL",id:47319664},{follow:!1,name:"WestMidRailway",id:0xcb4b3f097575000},{follow:!1,name:"NetworkRailBHM",id:583910976},{follow:!1,name:"NetworkRailEDB",id:586614081},{follow:!1,name:"NetworkRailEUS",id:581807264},{follow:!1,name:"NetworkRailGLC",id:421061171},{follow:!1,name:"NetworkRailKGX",id:459192871},{follow:!1,name:"NetworkRailLST",id:581826097},{follow:!1,name:"NetworkRailMAN",id:583895871},{follow:!1,name:"NetworkRailVIC",id:587354752},{follow:!1,name:"BTP",id:266094415},{follow:!1,name:"BTPAvonSomerset",id:0xa40431bb2d69000},{follow:!1,name:"BTPBhm",id:952003488},{follow:!1,name:"BTPBlackCountry",id:0xaa76997f5562000},{follow:!1,name:"BTPCambs",id:2574726074},{follow:!1,name:"BTPCardiff_NWP",id:951714852},{follow:!1,name:"BTPEAnglia",id:4479942923},{follow:!1,name:"BTPEssex",id:2949032015},{follow:!1,name:"BTPGtrMcr",id:1670204977},{follow:!1,name:"BTPLeics",id:0xa9023573bd76000},{follow:!1,name:"BTPLiverpoolSt",id:951912242},{follow:!1,name:"BTPLondon",id:957226980},{follow:!1,name:"BTPLondonBridge",id:3346645594},{follow:!1,name:"BTPMersey",id:951748434},{follow:!1,name:"BTPNorthScot",id:2238888007},{follow:!1,name:"BTPNorthWales",id:951487338},{follow:!1,name:"BTPOxon",id:0xa495f93bb965000},{follow:!1,name:"BTPPontypridd",id:1672678292},{follow:!1,name:"BTPScotland",id:957256160},{follow:!1,name:"BTPSouthYorks",id:3384315676},{follow:!1,name:"BTPTeesValley",id:0xb21ed0d43964000},{follow:!1,name:"BTPUnderground",id:0xdafd09816950000},{follow:!1,name:"BTPWales",id:1430734374},{follow:!1,name:"BTPWaterloo",id:951997044},{follow:!1,name:"BTPWestScot",id:951757261}];let Je=location.port?":"+location.port:"",je=`${location.protocol}//${location.hostname}${Je}`,Xe=!1;const Qe={},ze={newTweets:pe([]),twitterFollowing:pe({}),twitterFollowingList:pe([]),tweetList:pe([]),tweets:pe([]),favourites:pe([]),routes:pe([]),routeIndex:pe(0),incrementRouteIndex(){this.routeIndex.update(e=>e+1)},async saveRoute(e){const t={...e};t.id=s(this.routeIndex),this.routes.update(e=>[...e,t]),this.incrementRouteIndex()},deleteRoute(e){const t=s(this.routes).slice(0,e),n=s(this.routes).slice(e+1);this.routes.set([...t,...n])},async getTweets(){const e=s(ze.twitterFollowingList).map(e=>e[1].id),t=je.concat("/twitter");Oe({method:"post",url:t,data:{list:e}}).then(e=>{const t=e.data;this.newTweets.set(t)}).catch(e=>{console.error("Store:getTweets",e)})},getTweetByID(e){return s(this.tweets).get(e)},getTwitterFollowing(){return s(this.twitterFollowing)},saveTwitterFollowing(e){this.twitterFollowing.set(e)},getBaseUrl:()=>je,updateTweetList(e){this.tweetList.update(t=>[e,...t])},updateTwitter(e){this.tweets.update(t=>t.set(e.id,e))},updateNewTweets(e){this.newTweets.update(t=>{let n=[...t];return n.unshift(e),n=n.slice(0,49),n})},trigger(e,t){if(console.log("trigger",t),t.hasOwnProperty("message")){const e=t.message;this.updateNewTweets(e)}}},Ze=new Ue(ze);function qe(t){let n,r,o,a,i,l,s,c,u,d,h,f,S,B;return{c(){n=p("div"),r=p("div"),o=p("div"),a=C(t[0]),i=L(),l=p("div"),s=C(t[1]),c=L(),u=p("div"),d=p("span"),h=C(t[2]),H(r,"class","entry col-8 ml--1 svelte-10t8pfm"),H(d,"class",f="btn "+t[3]+" svelte-10t8pfm"),H(u,"class","entry col-4 text-center svelte-10t8pfm"),H(n,"class","row TRcard svelte-10t8pfm")},m(e,f){g(e,n,f),m(n,r),m(r,o),m(o,a),m(r,i),m(r,l),m(l,s),m(n,c),m(n,u),m(u,d),m(d,h),S||(B=b(d,"click",t[4]),S=!0)},p(e,[t]){1&t&&W(a,e[0]),2&t&&W(s,e[1]),4&t&&W(h,e[2]),8&t&&f!==(f="btn "+e[3]+" svelte-10t8pfm")&&H(d,"class",f)},i:e,o:e,d(e){e&&y(n),S=!1,B()}}}function et(e,t,n){let r,o,a,i,l,s,{destStation:c}=t,{startStation:u}=t,d=ze.getBaseUrl(),h={eta:"OFF",sta:"OFF"},f=0,S=0;async function m(){console.log(`Update: ${u} / ${c}`);const e=new Date,t=e.getHours()<6?36e5:95e3,r=t-e.getTime()%t;S=e.getTime()+r,await async function(){const e=Ie.minuteFloor(),t=a.concat("&mh="+e);Oe.get(t).then(e=>{n(8,h={...e.data}),console.dir(h)}).catch(e=>{console.error("TrainRoute:getTrain",e)})}(),clearTimeout(f),f=0,f=setTimeout(m,r+10)}return k(async()=>{if(Ie.LocalStorage.exists(`${u}${c}`)){const e=JSON.parse(Ie.LocalStorage.load(`${u}${c}`));n(8,h={...h,...e.trainData}),S=e.due,n(0,r=e.startStationName),n(1,o=e.destStationName),a=e.url}else n(0,r=Ge.findStation(u)),n(1,o=Ge.findStation(c)),a=`${d}/getnexttraintimes?from=${u}&to=${c}`;const e=(new Date).getTime();e>S?m():(f=0,f=setTimeout(m,S-e))}),G(async()=>{clearInterval(f);const e={due:S,trainData:h,startStationName:r,destStationName:o,url:a};Ie.LocalStorage.save(`${u}${c}`,JSON.stringify(e))}),e.$$set=e=>{"destStation"in e&&n(5,c=e.destStation),"startStation"in e&&n(6,u=e.startStation)},e.$$.update=()=>{352&e.$$.dirty&&(n(3,l="On time"===h.eta?"ontime":"delayed"),n(2,i="On time"===h.eta?h.sta:h.eta),s=`#/timetable/${u}/${c}`)},[r,o,i,l,function(){ve(s)},c,u]}_e.getItem("twitterFollowing").then(e=>{console.log("localForage::twitterFollowing",e),null!==e?ze.twitterFollowing.set(e):(Ve.forEach(e=>{Qe[e.name]={id:e.id,follow:!1}}),ze.twitterFollowing.set(Qe),_e.setItem("twitterFollowing",Qe).catch(e=>{console.error(e)}))}).catch(e=>{console.error(e)}),_e.getItem("favourites").then(e=>{null!==e&&ze.favourites.set(e)}).catch(e=>{console.error(e)}),_e.getItem("routes").then(e=>{null!==e&&ze.routes.set(e)}).catch(e=>{console.error(e)}),_e.getItem("routeIndex").then(e=>{null!==e&&ze.routeIndex.set(e)}).catch(e=>{console.error(e)}),ze.favourites.subscribe(e=>{console.log(">> Store.state.favourites",e)}),ze.routes.subscribe(e=>{Xe&&_e.setItem("routes",e).catch(e=>{console.error(e)})}),ze.routeIndex.subscribe(e=>{Xe&&_e.setItem("routeIndex",e).catch(e=>{console.error(e)})}),ze.twitterFollowing.subscribe(e=>{Xe&&_e.setItem("twitterFollowing",e).catch(e=>{console.error(e)});const t=Object.entries(s(ze.twitterFollowing)).filter(e=>{if(e[1].follow)return e});ze.twitterFollowingList.set(t)}),ze.twitterFollowingList.subscribe(e=>{0!==e.length&&(console.log("twitterFollowingList",e.length),e.forEach(e=>{const t=e[1].id;Ze.subscribe("t-"+t)}))}),ze.newTweets.subscribe(e=>{if(0===e.length)return;console.log(">> newTweets",e.length);const t=e.sort((e,t)=>t.ts-e.ts).map(e=>e.id),n=e.map(e=>[e.id,e]);ze.tweetList.set(t),ze.tweets.set(new Map(n))}),setTimeout(()=>{Xe=!0},250);class tt extends ge{constructor(e){super(),me(this,e,et,qe,i,{destStation:5,startStation:6})}}function nt(e,t,n){const r=e.slice();return r[1]=t[n],r}function rt(e){let t,n;return t=new tt({props:{destStation:e[1].destStation.id,startStation:e[1].startStation.id}}),{c(){he(t.$$.fragment)},m(e,r){fe(t,e,r),n=!0},p(e,n){const r={};1&n&&(r.destStation=e[1].destStation.id),1&n&&(r.startStation=e[1].startStation.id),t.$set(r)},i(e){n||(ae(t.$$.fragment,e),n=!0)},o(e){ie(t.$$.fragment,e),n=!1},d(e){Se(t,e)}}}function ot(e){let t,n,r=e[0],o=[];for(let t=0;tie(o[e],1,1,()=>{o[e]=null});return{c(){t=p("div");for(let e=0;e{n(0,r=e)}),[r]}var it={reduceOtherDetails(e){const t=[];let n=0;const r=/<\s*[aA].*?href\s*=\s*(?:"|')(.*?)(?:"|')[^>]*>(.*?)<\s*?\/\s*?[aA]\s*?>/;if("object"==typeof e.nrccMessages&&null!==e.nrccMessages)for(const o of e.nrccMessages){const e={index:0,msg:"",link:null,linkText:""};let a=o.value.replace(' ">','">').replace("","").replace("/gi,"");const i=r.exec(o.value);a=a.replace(r,""),e.index=n,e.msg=a,null!==i&&(e.link=i[1],e.linkText=i[2]),t.push(e),n++}return{nrMessages:t,nrMessagesExist:t.length>0}},reduceTrainTimetable(e){const t=[];let n="";const r=["💠","🚉"];if("object"==typeof e&&null!==e){if(console.log(">> reduceTrainService"),"object"==typeof e.trainServices&&null!==e.trainServices)for(const o of e.trainServices){const e=o.destination[0],a=null!==e.via?e.via:"",i=null!==o.platform?o.platform:""+r[0],l=null!==o.sta?o.sta:"D "+o.std,s=null===o.sta,c=null!==o.eta?o.eta:o.etd,u=o.length,d=u>0?` (${u} 🚃) `:"",h="on time"===c.toLowerCase()?"ontime":"delayed",f=null!==o.delayReason?o.delayReason:"",S=null!==o.cancelReason?o.cancelReason:"No reason given 🤷",m=o.serviceIdUrlSafe;t.push({location:e.locationName,time:l,status:c,platform:i,cancel:S,type:"train",delay:f,carriageCount:d,via:a,statusMode:h,isCancelled:o.isCancelled,isDeparture:s,serviceIdUrlSafe:m}),n=o.isCancelled?`${n}${e.locationName} ${a}${l}\n ❌ ${S}`:`${n}${e.locationName}${d}${a}\n ${l}\n ${c}\n ${i}\n ${f}`}if("object"==typeof e.busServices&&null!==e.busServices)for(const n of e.busServices){const e=n.destination[0],r=null!==e.via?e.via:"",o=null!==n.platform?n.platform:"",a=null!==n.sta?n.sta:"D "+n.std,i=null!==n.eta?n.eta:n.etd;t.push({location:e.locationName,time:a,status:i,platform:o,cancel:n.cancelReason,type:"bus",via:r})}}return console.log(t),t},reduceTrainService(e){let t=[];const n=e.sta||e.std,r=e.eta||e.etd,o={locationName:e.locationName,crs:e.crs,st:e.sta,et:e.eta,at:e.ata,isCancelled:e.isCancelled,length:e.length,detachFront:e.detachFront,adhocAlerts:e.adhocAlerts};return null!==e.previousCallingPoints&&(t=t.concat(e.previousCallingPoints[0].callingPoint)),t.push(o),null!==e.subsequentCallingPoints&&(t=t.concat(e.subsequentCallingPoints[0].callingPoint)),t=t.map(e=>(e.et=null===e.et?"":e.et,e.at=null===e.at?"":e.at,e.etMode="on time"===e.et.toLowerCase()?"ontime":"delayed",e.atMode="on time"===e.at.toLowerCase()?"ontime":"delayed",e.delayReason=null!==e.delayReason?e.delayReason:"",e.cancelReason=null!==e.cancelReason?e.cancelReason:"No reason given 🤷",e.classCancel=e.isCancelled?"cancelledRow":"",null!==e.st||null!==e.et&&""!==e.et||(e.st="D "+n,e.et=r),e)),t}};function lt(e,t,n){const r=e.slice();return r[5]=t[n],r}function st(e){let t,n=e[0],r=[];for(let t=0;t0&&st(t);return{c(){n=p("section"),r=p("div"),r.innerHTML='
Station
\n
Due
\n
Estimated
\n
Arrived
',o=L(),a&&a.c(),H(r,"class","grid card text-subhead")},m(e,t){g(e,n,t),m(n,r),m(n,o),a&&a.m(n,null)},p(e,[t]){e[0].length>0?a?a.p(e,t):(a=st(e),a.c(),a.m(n,null)):a&&(a.d(1),a=null)},i:e,o:e,d(e){e&&y(n),a&&a.d()}}}function dt(e,t,n){let r,{serviceId:o}=t,a=[],i=ze.getBaseUrl();async function l(){{const e="/getservice?serviceid="+o,t=i.concat(e);await Oe.get(t).then(e=>{const t=JSON.parse(e.data);n(0,a=it.reduceTrainService(t))})}}return k(async()=>{await l(),r=setInterval(async()=>{console.log("Service update"),await l()},12e4)}),G(async()=>{clearInterval(r)}),e.$$set=e=>{"serviceId"in e&&n(1,o=e.serviceId)},[a,o]}class ht extends ge{constructor(e){super(),me(this,e,dt,ut,i,{serviceId:1})}}function ft(t){let n,r,o;return r=new ht({props:{serviceId:t[0]}}),{c(){n=p("div"),he(r.$$.fragment),H(n,"class","container")},m(e,t){g(e,n,t),fe(r,n,null),o=!0},p:e,i(e){o||(ae(r.$$.fragment,e),o=!0)},o(e){ie(r.$$.fragment,e),o=!1},d(e){e&&y(n),Se(r)}}}function St(e,t,n){let{params:r={}}=t,o=r.serviceId;return e.$$set=e=>{"params"in e&&n(1,r=e.params)},[o,r]}function mt(e,t,n){const r=e.slice();return r[8]=t[n],r[10]=n,r}function gt(e,t,n){const r=e.slice();return r[8]=t[n],r}function yt(e){let t,n,r=e[1].nrMessages,o=[];for(let t=0;te[8].serviceIdUrlSafe;for(let t=0;t{v||(v=se(n,De,{},!0)),v.run(1)}),T=!0)},o(e){e&&(v||(v=se(n,De,{},!1)),v.run(0)),T=!1},d(e){e&&y(n),D&&D.d(),G.d(),e&&v&&v.end(),N=!1,R()}}}function Wt(e){let t,n,r,o,a=!0===e[1].nrMessagesExist&&yt(e),i=e[0].length>0&&Ct(e);return{c(){t=p("div"),n=p("section"),a&&a.c(),r=L(),i&&i.c()},m(e,l){g(e,t,l),m(t,n),a&&a.m(n,null),m(n,r),i&&i.m(n,null),o=!0},p(e,[t]){!0===e[1].nrMessagesExist?a?a.p(e,t):(a=yt(e),a.c(),a.m(n,r)):a&&(a.d(1),a=null),e[0].length>0?i?(i.p(e,t),1&t&&ae(i,1)):(i=Ct(e),i.c(),ae(i,1),i.m(n,null)):i&&(re(),ie(i,1,1,()=>{i=null}),oe())},i(e){o||(ae(i),o=!0)},o(e){ie(i),o=!1},d(e){e&&y(t),a&&a.d(),i&&i.d()}}}function vt(e,t,n){let r,{fromStation:o}=t,{destStation:a}=t,i=[],l={},s=ze.getBaseUrl();async function c(){{const e=`/gettrains?from=${o}&to=${a}`,t=s.concat(e);await Oe.get(t).then(e=>{const t={...e.data};n(0,i=it.reduceTrainTimetable(t)),n(1,l=it.reduceOtherDetails(t))})}}return k(async()=>{await c(),r=setInterval(async()=>{console.log("Timetable update"),await c()},12e4)}),G(async()=>{clearInterval(r)}),e.$$set=e=>{"fromStation"in e&&n(3,o=e.fromStation),"destStation"in e&&n(4,a=e.destStation)},[i,l,function(e){ve("/service/"+e)},o,a]}class Tt extends ge{constructor(e){super(),me(this,e,vt,Wt,i,{fromStation:3,destStation:4})}}function Nt(e){let t,n,r,o,a,i,l,s,c;return s=new Tt({props:{fromStation:e[2],destStation:e[3]}}),{c(){t=p("div"),n=p("div"),r=p("div"),o=C(e[0]),a=C(" TO "),i=C(e[1]),l=L(),he(s.$$.fragment),H(r,"class","text-center text-dark text-subhead"),H(t,"class","container")},m(e,u){g(e,t,u),m(t,n),m(n,r),m(r,o),m(r,a),m(r,i),m(n,l),fe(s,n,null),c=!0},p(e,[t]){(!c||1&t)&&W(o,e[0]),(!c||2&t)&&W(i,e[1])},i(e){c||(ae(s.$$.fragment,e),c=!0)},o(e){ie(s.$$.fragment,e),c=!1},d(e){e&&y(t),Se(s)}}}function Rt(e,t,n){let r,o,{params:a={}}=t,i=a.fromStation,l=a.destStation;return k(async()=>{n(0,r=Ge.findStation(i)),n(1,o=Ge.findStation(l))}),e.$$set=e=>{"params"in e&&n(4,a=e.params)},[r,o,i,l,a]}function Mt(e,t,n){const r=e.slice();return r[9]=t[n],r[11]=n,r}function Pt(e){let t,n=e[4],r=[];for(let t=0;t0&&Pt(t);return{c(){n=p("span"),r=p("label"),i=C(t[1]),l=L(),s=p("input"),c=L(),h&&h.c(),H(r,"for",t[0]),H(s,"class","betterInput svelte-1up86vp"),H(s,"autocomplete","off"),H(s,"name",t[0]),H(n,"class","mui-dropdown mui-dropdown--right svelte-1up86vp")},m(e,o){g(e,n,o),m(n,r),m(r,i),m(n,l),m(n,s),v(s,t[2]),m(n,c),h&&h.m(n,null),u||(d=[b(s,"keyup",(function(){a(t[3])&&t[3].apply(this,arguments)})),b(s,"input",t[7])],u=!0)},p(e,[o]){t=e,2&o&&W(i,t[1]),1&o&&H(r,"for",t[0]),1&o&&H(s,"name",t[0]),4&o&&s.value!==t[2]&&v(s,t[2]),t[4].length>0?h?h.p(t,o):(h=Pt(t),h.c(),h.m(n,null)):h&&(h.d(1),h=null)},i:e,o:e,d(e){e&&y(n),h&&h.d(),u=!1,o(d)}}}function Et(e,t,n){let r,{returnValue:o=""}=t,a="",{name:i}=t,{label:l}=t,s=[];function c(){n(6,o=""),a.length>=2?n(4,s=Ge.searchStation(a)):n(4,s=[])}return k(async()=>{n(3,r=Ie.debounce(c,750))}),e.$$set=e=>{"returnValue"in e&&n(6,o=e.returnValue),"name"in e&&n(0,i=e.name),"label"in e&&n(1,l=e.label)},e.$$.update=()=>{64&e.$$.dirty&&""===o&&n(2,a="")},[i,l,a,r,s,function(e){let[t,r]=e.target.dataset.content.split(",");n(6,o={id:t,name:r}),n(2,a=r),n(4,s=[])},o,function(){a=this.value,n(2,a),n(6,o)}]}class kt extends ge{constructor(e){super(),me(this,e,Et,Dt,i,{returnValue:6,name:0,label:1})}}function Gt(t){let n,r,o,a;return{c(){n=p("div"),r=p("button"),r.textContent="Add a new route",H(r,"class","btn btn-primary"),H(r,"id","new"),H(r,"type","button")},m(e,i){g(e,n,i),m(n,r),o||(a=b(r,"click",t[6]),o=!0)},p:e,i:e,o:e,d(e){e&&y(n),o=!1,a()}}}function Ft(e){let t,n,r,a,i,l,s,c,u,d,h,f,S,B,w,W,v,T,N,R,M,P,A,D;function E(t){e[7].call(null,t)}let k={label:"Departure Station",name:"startStation"};function G(t){e[8].call(null,t)}void 0!==e[1]&&(k.returnValue=e[1]),s=new kt({props:k}),O.push(()=>de(s,"returnValue",E));let F={label:"Destination Station",name:"destStation"};return void 0!==e[2]&&(F.returnValue=e[2]),S=new kt({props:F}),O.push(()=>de(S,"returnValue",G)),{c(){t=p("div"),n=p("div"),r=p("div"),r.textContent="New Route",a=L(),i=p("div"),l=p("div"),he(s.$$.fragment),u=L(),d=p("div"),d.innerHTML='',h=L(),f=p("div"),he(S.$$.fragment),w=L(),W=p("div"),v=p("button"),v.textContent="Close",T=L(),N=p("button"),R=C("Save"),H(r,"class","text-subhead"),H(l,"class",""),H(d,"class","text-center"),H(f,"class",""),H(i,"class","grid-3"),H(v,"class","btn btn-sm"),H(v,"type","button"),H(N,"class","btn btn-primary btn-sm"),H(N,"id","save"),H(N,"type","button"),N.disabled=M=!e[3],H(W,"class","my text-right"),H(n,"class","mui-row card"),H(t,"class","container ")},m(o,c){g(o,t,c),m(t,n),m(n,r),m(n,a),m(n,i),m(i,l),fe(s,l,null),m(i,u),m(i,d),m(i,h),m(i,f),fe(S,f,null),m(n,w),m(n,W),m(W,v),m(W,T),m(W,N),m(N,R),P=!0,A||(D=[b(v,"click",e[4]),b(N,"click",e[5])],A=!0)},p(e,t){const n={};!c&&2&t&&(c=!0,n.returnValue=e[1],J(()=>c=!1)),s.$set(n);const r={};!B&&4&t&&(B=!0,r.returnValue=e[2],J(()=>B=!1)),S.$set(r),(!P||8&t&&M!==(M=!e[3]))&&(N.disabled=M)},i(e){P||(ae(s.$$.fragment,e),ae(S.$$.fragment,e),P=!0)},o(e){ie(s.$$.fragment,e),ie(S.$$.fragment,e),P=!1},d(e){e&&y(t),Se(s),Se(S),A=!1,o(D)}}}function It(e){let t,n,r,o;const a=[Ft,Gt],i=[];function l(e,t){return e[0]?0:1}return t=l(e),n=i[t]=a[t](e),{c(){n.c(),r=w()},m(e,n){i[t].m(e,n),g(e,r,n),o=!0},p(e,[o]){let s=t;t=l(e),t===s?i[t].p(e,o):(re(),ie(i[s],1,1,()=>{i[s]=null}),oe(),n=i[t],n||(n=i[t]=a[t](e),n.c()),ae(n,1),n.m(r.parentNode,r))},i(e){o||(ae(n),o=!0)},o(e){ie(n),o=!1},d(e){i[t].d(e),e&&y(r)}}}function Ot(e,t,n){let r,o,a,i=!1;function l(){n(1,r=""),n(2,o=""),n(0,i=!1)}return e.$$.update=()=>{6&e.$$.dirty&&(console.log("typeof startStation",typeof r),n(3,a="object"==typeof r&&"object"==typeof o))},[i,r,o,a,l,async function(){await ze.saveRoute({startStation:r,destStation:o}),l()},function(){n(0,i=!0)},function(e){r=e,n(1,r)},function(e){o=e,n(2,o)}]}class Kt extends ge{constructor(e){super(),me(this,e,Ot,It,i,{})}}function xt(t){let n,r,a,i,l,s,c,u,d,h;return{c(){n=p("div"),r=p("button"),r.textContent="Delete",a=L(),i=p("button"),i.textContent="Edit",l=L(),s=p("button"),s.textContent="Close",H(r,"class","btn btn-danger btn-sm"),H(r,"id","delete"),H(r,"type","button"),H(i,"class","btn btn-primary btn-sm"),H(i,"id","save"),H(i,"type","button"),H(s,"class","btn btn-sm"),H(s,"type","button"),H(n,"class","my grid-3 svelte-ojjucl")},m(e,o){g(e,n,o),m(n,r),m(n,a),m(n,i),m(n,l),m(n,s),u=!0,d||(h=[b(r,"click",t[2]),b(i,"click",Yt),b(s,"click",t[3])],d=!0)},p:e,i(e){u||(V(()=>{c||(c=se(n,Ee,{},!0)),c.run(1)}),u=!0)},o(e){c||(c=se(n,Ee,{},!1)),c.run(0),u=!1},d(e){e&&y(n),e&&c&&c.end(),d=!1,o(h)}}}function $t(n){let r,i,l,s,c,d,h,f,B,w,v,T,N,R,M,D,E,k=n[0].startStation.name+"",G=n[0].destStation.name+"",F=n[1]&&xt(n);return{c(){r=p("div"),i=p("div"),l=p("div"),s=C(k),c=L(),d=p("div"),d.innerHTML='',h=L(),f=p("div"),B=C(G),w=L(),v=p("div"),T=p("button"),T.innerHTML='',N=L(),F&&F.c(),H(l,"class","col-5"),H(d,"class","col-1"),H(f,"class","col-5"),H(T,"class","btn btn-sm--slim"),H(v,"class","col-1"),H(i,"class","grid card ")},m(e,t){g(e,r,t),m(r,i),m(i,l),m(l,s),m(i,c),m(i,d),m(i,h),m(i,f),m(f,B),m(i,w),m(i,v),m(v,T),m(r,N),F&&F.m(r,null),M=!0,D||(E=b(T,"click",n[5]),D=!0)},p(e,[t]){(!M||1&t)&&k!==(k=e[0].startStation.name+"")&&W(s,k),(!M||1&t)&&G!==(G=e[0].destStation.name+"")&&W(B,G),e[1]?F?(F.p(e,t),2&t&&ae(F,1)):(F=xt(e),F.c(),ae(F,1),F.m(r,null)):F&&(re(),ie(F,1,1,()=>{F=null}),oe())},i(e){M||(ae(F),R&&R.end(1),M=!0)},o(n){ie(F),n&&(R=function(n,r,i){let l,s=r(n,i),c=!0;const d=ne;function h(){const{delay:r=0,duration:a=300,easing:i=t,tick:h=e,css:f}=s||le;f&&(l=P(n,1,0,a,r,i,f));const m=u()+r,g=m+a;V(()=>ee(n,!1,"start")),S(e=>{if(c){if(e>=g)return h(0,1),ee(n,!1,"end"),--d.r||o(d.c),!1;if(e>=m){const t=i((e-m)/a);h(1-t,t)}}return c})}return d.r+=1,a(s)?q().then(()=>{s=s(),h()}):h(),{end(e){e&&s.tick&&s.tick(1,0),c&&(l&&A(n,l),c=!1)}}}(r,Ee,{})),M=!1},d(e){e&&y(r),F&&F.d(),e&&R&&R.end(),D=!1,E()}}}function Yt(){}function _t(e,t,n){let{item:r}=t,{id:o}=t,a=!1;return e.$$set=e=>{"item"in e&&n(0,r=e.item),"id"in e&&n(4,o=e.id)},[r,a,function(){console.log("delete: "+o),n(1,a=!1),ze.deleteRoute(o)},function(){n(1,a=!1)},o,()=>n(1,a=!a)]}class Ut extends ge{constructor(e){super(),me(this,e,_t,$t,i,{item:0,id:4})}}function Vt(e,t,n){const r=e.slice();return r[1]=t[n],r[3]=n,r}function Jt(e,t){let n,r,o;return r=new Ut({props:{item:t[1],id:t[3]}}),{key:e,first:null,c(){n=w(),he(r.$$.fragment),this.first=n},m(e,t){g(e,n,t),fe(r,e,t),o=!0},p(e,t){const n={};1&t&&(n.item=e[1]),1&t&&(n.id=e[3]),r.$set(n)},i(e){o||(ae(r.$$.fragment,e),o=!0)},o(e){ie(r.$$.fragment,e),o=!1},d(e){e&&y(n),Se(r,e)}}}function jt(e){let t,n,r=[],o=new Map,a=e[0];const i=e=>e[1].id;for(let t=0;t{n(0,r=e)}),[r]}class Qt extends ge{constructor(e){super(),me(this,e,Xt,jt,i,{})}}function zt(e,t,n){const r=e.slice();return r[4]=t[n],r[5]=t,r[6]=n,r}function Zt(e){let t,n=Ve,r=[];for(let t=0;t{n(0,r=ze.getTwitterFollowing()),n(1,o=Object.keys(r).length>0)});const a=ze.twitterFollowing.subscribe(async e=>{n(0,r=e),n(1,o=Object.keys(r).length>0),console.log("_following",r)});return G(async()=>{ze.saveTwitterFollowing(r),a()}),[r,o,function(e){r[e.name].follow=this.checked,n(0,r)}]}class nn extends ge{constructor(e){super(),me(this,e,tn,en,i,{})}}function rn(t){let n,r,o,a,i,l,s,c,u,d,h;return a=new Kt({}),l=new Qt({}),d=new nn({}),{c(){n=p("div"),r=p("div"),r.textContent="Settings",o=L(),he(a.$$.fragment),i=L(),he(l.$$.fragment),s=L(),c=p("hr"),u=L(),he(d.$$.fragment),H(r,"class","text-dark text-subhead"),H(n,"class","container")},m(e,t){g(e,n,t),m(n,r),m(n,o),fe(a,n,null),m(n,i),fe(l,n,null),m(n,s),m(n,c),m(n,u),fe(d,n,null),h=!0},p:e,i(e){h||(ae(a.$$.fragment,e),ae(l.$$.fragment,e),ae(d.$$.fragment,e),h=!0)},o(e){ie(a.$$.fragment,e),ie(l.$$.fragment,e),ie(d.$$.fragment,e),h=!1},d(e){e&&y(n),Se(a),Se(l),Se(d)}}}function on(t){let n;return{c(){n=p("div"),n.innerHTML='

Favourites

\n\n
a
\n
b
\n
c
\n
d
',H(n,"class","container svelte-apetsu")},m(e,t){g(e,n,t)},p:e,i:e,o:e,d(e){e&&y(n)}}}function an(e){let t,n,r,o,a,i,l,s,c,u,d,h,f,S,B,w,b,v,T,N,R,M,P=e[0].user.name+"",A=e[0].user.screen_name+"",D=e[0].created_at+"",E=e[1]&&ln(e);return{c(){t=p("div"),n=p("div"),r=p("div"),o=p("img"),l=L(),s=p("div"),c=p("div"),u=C(P),d=L(),h=p("div"),f=C("@"),S=C(A),B=L(),E&&E.c(),w=L(),b=p("div"),v=C(e[2]),T=L(),N=p("div"),R=p("small"),M=C(D),H(o,"class","avatar col-2 svelte-1y2z4hv"),o.src!==(a=cn(e[0].user.profile_image_url_https))&&H(o,"src",a),H(o,"alt",i="@"+e[0].user.screen_name),H(c,"class","text-subhead text-dark"),H(h,"class","badge"),H(s,"class","col-10 ml-2"),H(r,"class","grid"),H(n,"class","tweet-header"),H(b,"class","tweetBody"),H(R,"class","text-highlight2"),H(t,"class","card--slim")},m(e,a){g(e,t,a),m(t,n),m(n,r),m(r,o),m(r,l),m(r,s),m(s,c),m(c,u),m(s,d),m(s,h),m(h,f),m(h,S),m(t,B),E&&E.m(t,null),m(t,w),m(t,b),m(b,v),m(t,T),m(t,N),m(N,R),m(R,M)},p(e,n){1&n&&o.src!==(a=cn(e[0].user.profile_image_url_https))&&H(o,"src",a),1&n&&i!==(i="@"+e[0].user.screen_name)&&H(o,"alt",i),1&n&&P!==(P=e[0].user.name+"")&&W(u,P),1&n&&A!==(A=e[0].user.screen_name+"")&&W(S,A),e[1]?E?E.p(e,n):(E=ln(e),E.c(),E.m(t,w)):E&&(E.d(1),E=null),4&n&&W(v,e[2]),1&n&&D!==(D=e[0].created_at+"")&&W(M,D)},d(e){e&&y(t),E&&E.d()}}}function ln(e){let t,n,r,o=e[0].in_reply_to_screen_name+"";return{c(){t=p("div"),n=C("Replying to @"),r=C(o),H(t,"class","text-primary")},m(e,o){g(e,t,o),m(t,n),m(t,r)},p(e,t){1&t&&o!==(o=e[0].in_reply_to_screen_name+"")&&W(r,o)},d(e){e&&y(t)}}}function sn(t){let n,r=t[0]&&an(t);return{c(){r&&r.c(),n=w()},m(e,t){r&&r.m(e,t),g(e,n,t)},p(e,[t]){e[0]?r?r.p(e,t):(r=an(e),r.c(),r.m(n.parentNode,n)):r&&(r.d(1),r=null)},i:e,o:e,d(e){r&&r.d(e),e&&y(n)}}}function cn(e){return"https://image.silvrtree.co.uk/48,fit,q80/"+e}function un(e,t,n){let r,o,{id:a}=t,i=!1,l="";return k(async()=>{r=ze.getTweetByID(a),n(0,o=JSON.parse(r.tweet))}),e.$$set=e=>{"id"in e&&n(3,a=e.id)},e.$$.update=()=>{1&e.$$.dirty&&o&&(n(1,i=o&&null!==o.in_reply_to_status_id),n(2,l=o&&o.truncated?o.extended_tweet.full_text:o.text))},[o,i,l,a]}class dn extends ge{constructor(e){super(),me(this,e,un,sn,i,{id:3})}}function hn(e,t,n){const r=e.slice();return r[3]=t[n],r[5]=n,r}function fn(e,t){let n,r,o;return r=new dn({props:{id:t[3]}}),{key:e,first:null,c(){n=w(),he(r.$$.fragment),this.first=n},m(e,t){g(e,n,t),fe(r,e,t),o=!0},p(e,t){const n={};1&t&&(n.id=e[3]),r.$set(n)},i(e){o||(ae(r.$$.fragment,e),o=!0)},o(e){ie(r.$$.fragment,e),o=!1},d(e){e&&y(n),Se(r,e)}}}function Sn(e){let t,n,r,o,a=[],i=new Map,l=e[0];const s=e=>e[3];for(let t=0;t{await ze.getTweets()});const o=ze.tweetList.subscribe(async e=>{n(0,r=e)});return G(async()=>{o(),clearInterval(undefined)}),[r]}function gn(t){let n,r,o;return{c(){n=p("h2"),n.textContent="NotFound",r=L(),o=p("p"),o.textContent="Oops, this route doesn't exist!",H(n,"class","routetitle svelte-apetsu"),H(o,"class","svelte-apetsu")},m(e,t){g(e,n,t),g(e,r,t),g(e,o,t)},p:e,i:e,o:e,d(e){e&&y(n),e&&y(r),e&&y(o)}}}const yn=new Map;function Bn(t){let n,r,o;return{c(){n=p("span"),n.innerHTML='',H(n,"class","")},m(e,a){g(e,n,a),r||(o=b(n,"click",t[1]),r=!0)},p:e,d(e){e&&y(n),r=!1,o()}}}function pn(t){let n,r,o,a,i,l,s,c,u,d,h=1===t[0]&&Bn(t);return{c(){n=p("header"),r=p("section"),h&&h.c(),o=L(),a=p("span"),a.textContent=""+Cn,i=L(),l=p("section"),s=p("a"),s.innerHTML='',c=L(),u=p("a"),u.innerHTML='',d=L(),H(a,"class","text-bold navbar-brand mx-1 text-uppercase"),H(r,"class","navbar-section"),H(s,"title","Tweets"),H(s,"href","/#/tweets"),H(s,"class","btn--slim bg-primary"),H(u,"title","Settings"),H(u,"href","/#/settings"),H(u,"class","btn bg-primary "),H(l,"class","navbar-section text-right"),H(n,"class","navbar bg-primary")},m(e,t){g(e,n,t),m(n,r),h&&h.m(r,null),m(r,o),m(r,a),m(n,i),m(n,l),m(l,s),m(l,c),m(l,u),m(l,d)},p(e,[t]){1===e[0]?h?h.p(e,t):(h=Bn(e),h.c(),h.m(r,o)):h&&(h.d(1),h=null)},i:e,o:e,d(e){e&&y(n),h&&h.d()}}}yn.set("/",class extends ge{constructor(e){super(),me(this,e,at,ot,i,{})}}),yn.set("/timetable/:fromStation/:destStation",class extends ge{constructor(e){super(),me(this,e,Rt,Nt,i,{params:4})}}),yn.set("/service/:serviceId",class extends ge{constructor(e){super(),me(this,e,St,ft,i,{params:1})}}),yn.set("/settings",class extends ge{constructor(e){super(),me(this,e,null,rn,i,{})}}),yn.set("/favourites",class extends ge{constructor(e){super(),me(this,e,null,on,i,{})}}),yn.set("/tweets",class extends ge{constructor(e){super(),me(this,e,mn,Sn,i,{})}}),yn.set("*",class extends ge{constructor(e){super(),me(this,e,null,gn,i,{})}});let Cn="Traintimes";function Ln(e,t,n){let r,{page:o}=t;return e.$$set=e=>{"page"in e&&n(2,o=e.page)},e.$$.update=()=>{4&e.$$.dirty&&n(0,r="Home"===o?0:1)},[r,function(){U().then(()=>{window.history.back()})},o]}class wn extends ge{constructor(e){super(),me(this,e,Ln,pn,i,{page:2})}}function bn(e){let t,n,r,o;return t=new wn({props:{page:e[0]}}),r=new Ne({props:{routes:yn}}),r.$on("conditionsFailed",Hn),r.$on("routeLoaded",e[1]),r.$on("routeEvent",Wn),{c(){he(t.$$.fragment),n=L(),he(r.$$.fragment)},m(e,a){fe(t,e,a),g(e,n,a),fe(r,e,a),o=!0},p(e,[n]){const r={};1&n&&(r.page=e[0]),t.$set(r)},i(e){o||(ae(t.$$.fragment,e),ae(r.$$.fragment,e),o=!0)},o(e){ie(t.$$.fragment,e),ie(r.$$.fragment,e),o=!1},d(e){Se(t,e),e&&y(n),Se(r,e)}}}function Hn(e){console.error("Caught event conditionsFailed",e.detail)}function Wn(e){console.info("Caught event routeEvent",e.detail)}function vn(e,t,n){let r;return[r,function(e){console.info("Caught event routeLoaded",e.detail),n(0,r=e.detail.name),console.log("currentPage",r)}]}const Tn=new class extends ge{constructor(e){super(),me(this,e,vn,bn,i,{})}}({target:document.body,props:{}});return"serviceWorker"in navigator&&(navigator.serviceWorker.ready.then((function(e){console.warn("Ready??",e)})),window.addEventListener("load",(function(){navigator.serviceWorker.register("./service-worker.js").then(e=>{console.warn("Service Worker Registered",e.scope)}).catch(e=>{console.error("Registration failed with "+e)})}))),Tn}(); diff --git a/dist/build/fonts/GothamSSm-Black.otf b/dist/build/fonts/GothamSSm-Black.otf new file mode 100755 index 0000000..95aa773 Binary files /dev/null and b/dist/build/fonts/GothamSSm-Black.otf differ diff --git a/dist/build/fonts/GothamSSm-Bold.otf b/dist/build/fonts/GothamSSm-Bold.otf new file mode 100755 index 0000000..3d624a6 Binary files /dev/null and b/dist/build/fonts/GothamSSm-Bold.otf differ diff --git a/dist/build/fonts/GothamSSm-Book.otf b/dist/build/fonts/GothamSSm-Book.otf new file mode 100755 index 0000000..497df6e Binary files /dev/null and b/dist/build/fonts/GothamSSm-Book.otf differ diff --git a/dist/build/fonts/GothamSSm-Light.otf b/dist/build/fonts/GothamSSm-Light.otf new file mode 100755 index 0000000..3430a31 Binary files /dev/null and b/dist/build/fonts/GothamSSm-Light.otf differ diff --git a/dist/build/fonts/GothamSSm-Medium.otf b/dist/build/fonts/GothamSSm-Medium.otf new file mode 100755 index 0000000..8f4e1c2 Binary files /dev/null and b/dist/build/fonts/GothamSSm-Medium.otf differ diff --git a/dist/build/fonts/Roboto-normal-400.woff b/dist/build/fonts/Roboto-normal-400.woff new file mode 100644 index 0000000..92dfacc Binary files /dev/null and b/dist/build/fonts/Roboto-normal-400.woff differ diff --git a/dist/build/fonts/Roboto_Condensed-normal-400.woff b/dist/build/fonts/Roboto_Condensed-normal-400.woff new file mode 100644 index 0000000..613f5de Binary files /dev/null and b/dist/build/fonts/Roboto_Condensed-normal-400.woff differ diff --git a/dist/build/fonts/Roboto_Mono-normal-400.woff b/dist/build/fonts/Roboto_Mono-normal-400.woff new file mode 100644 index 0000000..c41382c Binary files /dev/null and b/dist/build/fonts/Roboto_Mono-normal-400.woff differ diff --git a/dist/build/fonts/Roboto_Slab-normal-400.woff b/dist/build/fonts/Roboto_Slab-normal-400.woff new file mode 100644 index 0000000..3374dc1 Binary files /dev/null and b/dist/build/fonts/Roboto_Slab-normal-400.woff differ diff --git a/dist/build/fonts/fonts.css b/dist/build/fonts/fonts.css new file mode 100644 index 0000000..8c53312 --- /dev/null +++ b/dist/build/fonts/fonts.css @@ -0,0 +1,32 @@ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: url(Roboto-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Roboto Condensed'; + font-style: normal; + font-weight: 400; + src: url(Roboto_Condensed-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + src: url(Roboto_Mono-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: 400; + src: url(Roboto_Slab-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + diff --git a/dist/build/fonts/fujicons.css b/dist/build/fonts/fujicons.css new file mode 100644 index 0000000..ff6f266 --- /dev/null +++ b/dist/build/fonts/fujicons.css @@ -0,0 +1,321 @@ +@font-face { + font-family: 'Fujicons'; + font-style: normal; + font-weight: 400; + src: url(fujicons.ttf) format('truetype'); + unicode-range: U+0-10FFFF; +} + + +.fa { + display: inline-block; + font: normal normal normal 14px/1 Fujicons; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} + + +.fa-back:before { + content: ""; +} + +.fa-back-chevron:before { + content: "\E91F" +} + +.fa-forward:before { + content: ""; +} + +.fa-globe:before { + content: "\EA12" +} + +.fa-up:before { + content: "\E925" +} + +.fa-down:before { + content: "\E922" +} + +.fa-work:before { + content: "\E998" +} + +.fa-home:before { + content: "\EA1E" +} + +.fa-refresh:before { + content: "\EA88" +} + +.fa-menu:before { + content: "\EA68" +} + +.fa-star:before { + content: "\EAB3" +} + +.fa-star-filled:before { + content: "\EAB2" +} + +.fa-thick-arrow:before { + content: "\EA08" +} + +.fa-tick:before { + content: "\E9A4" +} + +.fa-cross:before { + content: "\E951" +} + +.fa-cross-circle:before { + content: "\E9D2" +} + +.fa-cross-circle-filled:before { + content: "\E9D1" +} + +.fa-alert:before { + content: "\E9ED" +} + +.fa-alert-filled:before { + content: "\E9EC" +} + +.fa-info:before { + content: "\E9EF" +} + +.fa-info-filled:before { + content: "\E9EE" +} + +.fa-bookmark:before { + content: "\E951" +} + +.fa-bookmark-filled:before { + content: "\E950" +} + +.fa-clockface:before { + content: "\E9AB" +} + +.fa-clockface-filled:before { + content: "\E9AA" +} + +.fa-twitter:before { + content: "\EAE5" +} + +.fa-cog:before { + content: "\EA9E" +} + +.fa-cog-solid:before { + content: "\EA11" +} + +.fa-foursquare:before { + content: "\EA0B" +} + + + + + + + + + + +/*full list*/ + +.fa-binoculars-solid:before { + content: "\E900" +} + +.fa-binoculars:before { + content: "\E901" +} + +.fa-check-circle-solid:before { + content: "\E902" +} + +.fa-check-circle:before { + content: "\E903" +} + diff --git a/dist/build/fonts/fujicons.ttf b/dist/build/fonts/fujicons.ttf new file mode 100755 index 0000000..a323b19 Binary files /dev/null and b/dist/build/fonts/fujicons.ttf differ diff --git a/dist/build/fonts/fujicons.woff b/dist/build/fonts/fujicons.woff new file mode 100644 index 0000000..c41206c Binary files /dev/null and b/dist/build/fonts/fujicons.woff differ diff --git a/dist/build/fonts/fujicons.woff2 b/dist/build/fonts/fujicons.woff2 new file mode 100644 index 0000000..6331bfa Binary files /dev/null and b/dist/build/fonts/fujicons.woff2 differ diff --git a/dist/build/fonts/gotham.css b/dist/build/fonts/gotham.css new file mode 100644 index 0000000..ce9f10b --- /dev/null +++ b/dist/build/fonts/gotham.css @@ -0,0 +1,39 @@ +@font-face { + font-family: 'Gotham'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Book.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Light'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Light.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Medium'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Medium.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Bold'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Bold.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Black'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Black.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} diff --git a/dist/build/tmp/build-errors.log b/dist/build/tmp/build-errors.log new file mode 100644 index 0000000..4660a1c --- /dev/null +++ b/dist/build/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 1exit status 1 \ No newline at end of file diff --git a/dist/favicon.png b/dist/favicon.png new file mode 100644 index 0000000..669014f Binary files /dev/null and b/dist/favicon.png differ diff --git a/dist/fonts/GothamSSm-Black.otf b/dist/fonts/GothamSSm-Black.otf new file mode 100755 index 0000000..95aa773 Binary files /dev/null and b/dist/fonts/GothamSSm-Black.otf differ diff --git a/dist/fonts/GothamSSm-Bold.otf b/dist/fonts/GothamSSm-Bold.otf new file mode 100755 index 0000000..3d624a6 Binary files /dev/null and b/dist/fonts/GothamSSm-Bold.otf differ diff --git a/dist/fonts/GothamSSm-Book.otf b/dist/fonts/GothamSSm-Book.otf new file mode 100755 index 0000000..497df6e Binary files /dev/null and b/dist/fonts/GothamSSm-Book.otf differ diff --git a/dist/fonts/GothamSSm-Light.otf b/dist/fonts/GothamSSm-Light.otf new file mode 100755 index 0000000..3430a31 Binary files /dev/null and b/dist/fonts/GothamSSm-Light.otf differ diff --git a/dist/fonts/GothamSSm-Medium.otf b/dist/fonts/GothamSSm-Medium.otf new file mode 100755 index 0000000..8f4e1c2 Binary files /dev/null and b/dist/fonts/GothamSSm-Medium.otf differ diff --git a/dist/fonts/Roboto-normal-400.woff b/dist/fonts/Roboto-normal-400.woff new file mode 100644 index 0000000..92dfacc Binary files /dev/null and b/dist/fonts/Roboto-normal-400.woff differ diff --git a/dist/fonts/Roboto_Condensed-normal-400.woff b/dist/fonts/Roboto_Condensed-normal-400.woff new file mode 100644 index 0000000..613f5de Binary files /dev/null and b/dist/fonts/Roboto_Condensed-normal-400.woff differ diff --git a/dist/fonts/Roboto_Mono-normal-400.woff b/dist/fonts/Roboto_Mono-normal-400.woff new file mode 100644 index 0000000..c41382c Binary files /dev/null and b/dist/fonts/Roboto_Mono-normal-400.woff differ diff --git a/dist/fonts/Roboto_Slab-normal-400.woff b/dist/fonts/Roboto_Slab-normal-400.woff new file mode 100644 index 0000000..3374dc1 Binary files /dev/null and b/dist/fonts/Roboto_Slab-normal-400.woff differ diff --git a/dist/fonts/fonts.css b/dist/fonts/fonts.css new file mode 100644 index 0000000..8c53312 --- /dev/null +++ b/dist/fonts/fonts.css @@ -0,0 +1,32 @@ +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: url(Roboto-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Roboto Condensed'; + font-style: normal; + font-weight: 400; + src: url(Roboto_Condensed-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Roboto Mono'; + font-style: normal; + font-weight: 400; + src: url(Roboto_Mono-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Roboto Slab'; + font-style: normal; + font-weight: 400; + src: url(Roboto_Slab-normal-400.woff) format('woff'); + unicode-range: U+0-10FFFF; +} + diff --git a/dist/fonts/fujicons.css b/dist/fonts/fujicons.css new file mode 100644 index 0000000..287f484 --- /dev/null +++ b/dist/fonts/fujicons.css @@ -0,0 +1,209 @@ +@font-face { + font-family: 'Fujicons'; + font-style: normal; + font-weight: 400; + src: url(fujicons.ttf) format('truetype'); + unicode-range: U+0-10FFFF; +} + + +.fa { + display: inline-block; + font: normal normal normal 14px/1 Fujicons; + font-size: inherit; + text-rendering: auto; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +/* makes the font 33% larger relative to the icon container */ +.fa-lg { + font-size: 1.33333333em; + line-height: 0.75em; + vertical-align: -15%; +} +.fa-2x { + font-size: 2em; +} +.fa-3x { + font-size: 3em; +} +.fa-4x { + font-size: 4em; +} +.fa-5x { + font-size: 5em; +} +.fa-fw { + width: 1.28571429em; + text-align: center; +} +.fa-ul { + padding-left: 0; + margin-left: 2.14285714em; + list-style-type: none; +} +.fa-ul > li { + position: relative; +} +.fa-li { + position: absolute; + left: -2.14285714em; + width: 2.14285714em; + top: 0.14285714em; + text-align: center; +} +.fa-li.fa-lg { + left: -1.85714286em; +} +.fa-border { + padding: .2em .25em .15em; + border: solid 0.08em #eeeeee; + border-radius: .1em; +} +.fa-pull-left { + float: left; +} +.fa-pull-right { + float: right; +} +.fa.fa-pull-left { + margin-right: .3em; +} +.fa.fa-pull-right { + margin-left: .3em; +} +/* Deprecated as of 4.4.0 */ +.pull-right { + float: right; +} +.pull-left { + float: left; +} +.fa.pull-left { + margin-right: .3em; +} +.fa.pull-right { + margin-left: .3em; +} +.fa-spin { + -webkit-animation: fa-spin 2s infinite linear; + animation: fa-spin 2s infinite linear; +} +.fa-pulse { + -webkit-animation: fa-spin 1s infinite steps(8); + animation: fa-spin 1s infinite steps(8); +} +@-webkit-keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +@keyframes fa-spin { + 0% { + -webkit-transform: rotate(0deg); + transform: rotate(0deg); + } + 100% { + -webkit-transform: rotate(359deg); + transform: rotate(359deg); + } +} +.fa-rotate-90 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=1)"; + -webkit-transform: rotate(90deg); + -ms-transform: rotate(90deg); + transform: rotate(90deg); +} +.fa-rotate-180 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2)"; + -webkit-transform: rotate(180deg); + -ms-transform: rotate(180deg); + transform: rotate(180deg); +} +.fa-rotate-270 { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=3)"; + -webkit-transform: rotate(270deg); + -ms-transform: rotate(270deg); + transform: rotate(270deg); +} +.fa-flip-horizontal { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)"; + -webkit-transform: scale(-1, 1); + -ms-transform: scale(-1, 1); + transform: scale(-1, 1); +} +.fa-flip-vertical { + -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"; + -webkit-transform: scale(1, -1); + -ms-transform: scale(1, -1); + transform: scale(1, -1); +} +:root .fa-rotate-90, +:root .fa-rotate-180, +:root .fa-rotate-270, +:root .fa-flip-horizontal, +:root .fa-flip-vertical { + filter: none; +} +.fa-stack { + position: relative; + display: inline-block; + width: 2em; + height: 2em; + line-height: 2em; + vertical-align: middle; +} +.fa-stack-1x, +.fa-stack-2x { + position: absolute; + left: 0; + width: 100%; + text-align: center; +} +.fa-stack-1x { + line-height: inherit; +} +.fa-stack-2x { + font-size: 2em; +} +.fa-inverse { + color: #ffffff; +} + + +.fa-back:before { + content: ""; +} + +.fa-forward:before { + content: ""; +} + +.fa-globe:before { + content: "\EA12" +} + +.fa-up:before { + content: "\E925" +} + +.fa-down:before { + content: "\E922" +} + +.fa-work:before { + content: "\E998" +} + +.fa-home:before { + content: "\EA1E" +} + +.fa-refresh:before { + content: "\EA88" +} diff --git a/dist/fonts/fujicons.ttf b/dist/fonts/fujicons.ttf new file mode 100755 index 0000000..a323b19 Binary files /dev/null and b/dist/fonts/fujicons.ttf differ diff --git a/dist/fonts/gotham.css b/dist/fonts/gotham.css new file mode 100644 index 0000000..ce9f10b --- /dev/null +++ b/dist/fonts/gotham.css @@ -0,0 +1,39 @@ +@font-face { + font-family: 'Gotham'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Book.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Light'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Light.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Medium'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Medium.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Bold'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Bold.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} + +@font-face { + font-family: 'Gotham Black'; + font-style: normal; + font-weight: 400; + src: url(GothamSSm-Black.otf) format('opentype'); + unicode-range: U+0-10FFFF; +} diff --git a/dist/global.css b/dist/global.css new file mode 100644 index 0000000..e69de29 diff --git a/dist/img/Icon-144.png b/dist/img/Icon-144.png new file mode 100644 index 0000000..45e0459 Binary files /dev/null and b/dist/img/Icon-144.png differ diff --git a/dist/img/Icon-192.png b/dist/img/Icon-192.png new file mode 100644 index 0000000..daf222c Binary files /dev/null and b/dist/img/Icon-192.png differ diff --git a/dist/img/Icon-36.png b/dist/img/Icon-36.png new file mode 100644 index 0000000..b1ad90e Binary files /dev/null and b/dist/img/Icon-36.png differ diff --git a/dist/img/Icon-48.png b/dist/img/Icon-48.png new file mode 100644 index 0000000..15d29c1 Binary files /dev/null and b/dist/img/Icon-48.png differ diff --git a/dist/img/Icon-512.png b/dist/img/Icon-512.png new file mode 100644 index 0000000..fa3720b Binary files /dev/null and b/dist/img/Icon-512.png differ diff --git a/dist/img/Icon-72.png b/dist/img/Icon-72.png new file mode 100644 index 0000000..649b07c Binary files /dev/null and b/dist/img/Icon-72.png differ diff --git a/dist/img/Icon-96.png b/dist/img/Icon-96.png new file mode 100644 index 0000000..eace2dd Binary files /dev/null and b/dist/img/Icon-96.png differ diff --git a/dist/img/android-chrome-192x192.png b/dist/img/android-chrome-192x192.png new file mode 100644 index 0000000..3aa557d Binary files /dev/null and b/dist/img/android-chrome-192x192.png differ diff --git a/dist/img/apple-touch-icon.png b/dist/img/apple-touch-icon.png new file mode 100644 index 0000000..8387a2e Binary files /dev/null and b/dist/img/apple-touch-icon.png differ diff --git a/dist/img/favicon-16x16.png b/dist/img/favicon-16x16.png new file mode 100644 index 0000000..0e695c5 Binary files /dev/null and b/dist/img/favicon-16x16.png differ diff --git a/dist/img/favicon-32x32.png b/dist/img/favicon-32x32.png new file mode 100644 index 0000000..b4bc5c5 Binary files /dev/null and b/dist/img/favicon-32x32.png differ diff --git a/dist/img/favicon.ico b/dist/img/favicon.ico new file mode 100644 index 0000000..aa96bef Binary files /dev/null and b/dist/img/favicon.ico differ diff --git a/dist/img/mstile-150x150.png b/dist/img/mstile-150x150.png new file mode 100644 index 0000000..f580457 Binary files /dev/null and b/dist/img/mstile-150x150.png differ diff --git a/dist/img/photothumb.db b/dist/img/photothumb.db new file mode 100644 index 0000000..fa58b80 Binary files /dev/null and b/dist/img/photothumb.db differ diff --git a/dist/img/safari-pinned-tab.svg b/dist/img/safari-pinned-tab.svg new file mode 100644 index 0000000..bd9b59f --- /dev/null +++ b/dist/img/safari-pinned-tab.svg @@ -0,0 +1,33 @@ + + + + +Created by potrace 1.11, written by Peter Selinger 2001-2013 + + + + + + + + + diff --git a/dist/index.html b/dist/index.html new file mode 100644 index 0000000..d0c9f03 --- /dev/null +++ b/dist/index.html @@ -0,0 +1,30 @@ + + + + + + + Traintimes + + + + + + + + + + + + + + + + + + + + + + diff --git a/dist/manifest.json b/dist/manifest.json new file mode 100644 index 0000000..30f8da3 --- /dev/null +++ b/dist/manifest.json @@ -0,0 +1,46 @@ +{ + "name": "Train Times", + "short_name": "Train Times", + "icons": [ + { + "src": "/img/Icon-36.png", + "sizes": "36x36", + "type": "image/png" + }, + { + "src": "/img/Icon-48.png", + "sizes": "48x48", + "type": "image/png" + }, + { + "src": "/img/Icon-72.png", + "sizes": "72x72", + "type": "image/png" + }, + { + "src": "/img/Icon-96.png", + "sizes": "96x96", + "type": "image/png" + }, + { + "src": "/img/Icon-144.png", + "sizes": "144x144", + "type": "image/png" + }, + { + "src": "/img/Icon-192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/img/Icon-512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#ffffff", + "background_color": "#ffffff", + "start_url": ".", + "imgdisplay": "standalone", + "display": "standalone" +} diff --git a/dist/service-worker.js b/dist/service-worker.js new file mode 100644 index 0000000..31f8064 --- /dev/null +++ b/dist/service-worker.js @@ -0,0 +1,110 @@ +// Copyright 2016 Google Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +const CACHE_VERSION = 8; +const dataCacheName = `traintimesData-v${CACHE_VERSION}`; +const cacheName = `traintimePWA-final-${CACHE_VERSION}`; +const filesToCache = [ + '/', + '/index.html', + '/service-worker.js', + '/manifest.json', + '/favicon.png', + '/browserconfig.xml', + '/build/bundle.css', + '/build/bundle.js', + '/build/fonts/fujicons.css', + '/build/fonts/fujicons.woff', + '/img/Icon-36.png', + '/img/Icon-48.png', + '/img/Icon-72.png', + '/img/Icon-96.png', + '/img/Icon-144.png', + '/img/Icon-192.png', + '/img/Icon-512.png' +]; + +self.addEventListener('install', function(e) { + console.log('[ServiceWorker] Install'); + e.waitUntil( + caches.open(cacheName).then(function(cache) { + console.log('[ServiceWorker] Caching app shell'); + + return cache.addAll(filesToCache); + }) + ); +}); + +self.addEventListener('activate', function(e) { + console.log('[ServiceWorker] Activate'); + e.waitUntil( + caches.keys().then(function(keyList) { + return Promise.all(keyList.map(function(key) { + if (key !== cacheName && key !== dataCacheName) { + console.log('[ServiceWorker] Removing old cache', key); + + return caches.delete(key); + } + })); + }) + ); + + /* + * Fixes a corner case in which the app wasn't returning the latest data. + * You can reproduce the corner case by commenting out the line below and + * then doing the following steps: 1) load app for first time so that the + * initial New York City data is shown 2) press the refresh button on the + * app 3) go offline 4) reload the app. You expect to see the newer NYC + * data, but you actually see the initial data. This happens because the + * service worker is not yet activated. The code below essentially lets + * you activate the service worker faster. + */ + return self.clients.claim(); +}); + +self.addEventListener('fetch', function(e) { + console.warn('[Service Worker] Fetch', e.request.url); + const dataUrl = '/getnexttraintimes?'; + if (e.request.url.indexOf(dataUrl) > -1) { + console.log('!'); + + /* + * When the request URL contains dataUrl, the app is asking for fresh + * weather data. In this case, the service worker always goes to the + * network and then caches the response. This is called the "Cache then + * network" strategy: + * https://jakearchibald.com/2014/offline-cookbook/#cache-then-network + */ + e.respondWith( + caches.open(dataCacheName).then(function(cache) { + return fetch(e.request).then(function(response) { + cache.put(e.request.url, response.clone()); + + return response; + }); + }) + ); + } + else + + /* + * The app is asking for app shell files. In this scenario the app uses the + * "Cache, falling back to the network" offline strategy: + * https://jakearchibald.com/2014/offline-cookbook/#cache-falling-back-to-network + */ + e.respondWith( + caches.match(e.request).then(function(response) { + return response || fetch(e.request); + }) + ); +}); diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..53af49a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,18 @@ +version: '3.5' + +services: + menuserver: + container_name: menuserver + image: git.caliban.io/martin/menuserver:3.0.0 + restart: always + ports: + - "3000:3000" + volumes: + - ./db:/app/db + environment: + - EMAIL_FROM=Aida + - EMAIL_LOGIN=aida@caliban.io + - EMAIL_RECIPIENTS=Martin ,Jessica + - EMAIL_HOSTNAME=mail.caliban.io + - EMAIL_PASSWORD=Ultra+Topaz+6XQ + - SITE_URL=http://menu.lan \ No newline at end of file diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..241e1da --- /dev/null +++ b/go.mod @@ -0,0 +1,26 @@ +module traintimes + +go 1.22.0 + +require ( + github.com/gofiber/fiber v1.14.6 + github.com/gofiber/fiber/v2 v2.52.2 + github.com/gofiber/template/html/v2 v2.1.1 +) + +require ( + github.com/andybalholm/brotli v1.1.0 // indirect + github.com/gofiber/template v1.8.3 // indirect + github.com/gofiber/utils v1.1.0 // indirect + github.com/google/uuid v1.5.0 // indirect + github.com/gorilla/schema v1.2.1 // indirect + github.com/klauspost/compress v1.17.7 // indirect + github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-isatty v0.0.20 // indirect + github.com/mattn/go-runewidth v0.0.15 // indirect + github.com/rivo/uniseg v0.2.0 // indirect + github.com/valyala/bytebufferpool v1.0.0 // indirect + github.com/valyala/fasthttp v1.52.0 // indirect + github.com/valyala/tcplisten v1.0.0 // indirect + golang.org/x/sys v0.18.0 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d20138f --- /dev/null +++ b/go.sum @@ -0,0 +1,61 @@ +github.com/andybalholm/brotli v1.0.0/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y= +github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= +github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gofiber/fiber v1.14.6 h1:QRUPvPmr8ijQuGo1MgupHBn8E+wW0IKqiOvIZPtV70o= +github.com/gofiber/fiber v1.14.6/go.mod h1:Yw2ekF1YDPreO9V6TMYjynu94xRxZBdaa8X5HhHsjCM= +github.com/gofiber/fiber/v2 v2.52.2 h1:b0rYH6b06Df+4NyrbdptQL8ifuxw/Tf2DgfkZkDaxEo= +github.com/gofiber/fiber/v2 v2.52.2/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ= +github.com/gofiber/template v1.8.3 h1:hzHdvMwMo/T2kouz2pPCA0zGiLCeMnoGsQZBTSYgZxc= +github.com/gofiber/template v1.8.3/go.mod h1:bs/2n0pSNPOkRa5VJ8zTIvedcI/lEYxzV3+YPXdBvq8= +github.com/gofiber/template/html/v2 v2.1.1 h1:QEy3O3EBkvwDthy5bXVGUseOyO6ldJoiDxlF4+MJiV8= +github.com/gofiber/template/html/v2 v2.1.1/go.mod h1:2G0GHHOUx70C1LDncoBpe4T6maQbNa4x1CVNFW0wju0= +github.com/gofiber/utils v0.0.10/go.mod h1:9J5aHFUIjq0XfknT4+hdSMG6/jzfaAgCu4HEbWDeBlo= +github.com/gofiber/utils v1.1.0 h1:vdEBpn7AzIUJRhe+CiTOJdUcTg4Q9RK+pEa0KPbLdrM= +github.com/gofiber/utils v1.1.0/go.mod h1:poZpsnhBykfnY1Mc0KeEa6mSHrS3dV0+oBWyeQmb2e0= +github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= +github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/schema v1.1.0/go.mod h1:kgLaKoK1FELgZqMAVxx/5cbj0kT+57qxUrAlIO2eleU= +github.com/gorilla/schema v1.2.1 h1:tjDxcmdb+siIqkTNoV+qRH2mjYdr2hHe5MKXbp61ziM= +github.com/gorilla/schema v1.2.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= +github.com/klauspost/compress v1.10.7/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= +github.com/klauspost/compress v1.17.7 h1:ehO88t2UGzQK66LMdE8tibEd1ErmzZjNEqWkjLAKQQg= +github.com/klauspost/compress v1.17.7/go.mod h1:Di0epgTjJY877eYKx5yC51cX2A2Vl2ibi7bDH9ttBbw= +github.com/mattn/go-colorable v0.1.7/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= +github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U= +github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= +github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasthttp v1.16.0/go.mod h1:YOKImeEosDdBPnxc0gy7INqi3m1zK6A+xl6TwOBhHCA= +github.com/valyala/fasthttp v1.52.0 h1:wqBQpxH71XW0e2g+Og4dzQM8pk34aFYlA1Ga8db7gU0= +github.com/valyala/fasthttp v1.52.0/go.mod h1:hf5C4QnVMkNXMspnsUlfM3WitlgYflyhHYoKol/szxQ= +github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio= +github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8= +github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20200602114024-627f9648deb9/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200602225109-6fdc65e7d980/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/server-structs.go b/server-structs.go new file mode 100644 index 0000000..f1d42bd --- /dev/null +++ b/server-structs.go @@ -0,0 +1,141 @@ +package main + +import "time" + +type AllServices struct { + AreServicesAvailable bool `json:"areServicesAvailable"` + BusServices interface{} `json:"busServices"` + Crs string `json:"crs"` + FerryServices interface{} `json:"ferryServices"` + Filtercrs string `json:"filtercrs"` + FilterLocationName string `json:"filterLocationName"` + FilterType int `json:"filterType"` + GeneratedAt time.Time `json:"generatedAt"` + LocationName string `json:"locationName"` + NrccMessages []struct { + Value string `json:"value"` + } `json:"nrccMessages"` + PlatformAvailable bool `json:"platformAvailable"` + TrainServices []struct { + AdhocAlerts interface{} `json:"adhocAlerts"` + CancelReason string `json:"cancelReason"` + CurrentDestinations interface{} `json:"currentDestinations"` + CurrentOrigins interface{} `json:"currentOrigins"` + DelayReason interface{} `json:"delayReason"` + Destination []struct { + AssocIsCancelled bool `json:"assocIsCancelled"` + Crs string `json:"crs"` + FutureChangeTo interface{} `json:"futureChangeTo"` + LocationName string `json:"locationName"` + Via interface{} `json:"via"` + } `json:"destination"` + DetachFront bool `json:"detachFront"` + Eta interface{} `json:"eta"` + Etd string `json:"etd"` + FilterLocationCancelled bool `json:"filterLocationCancelled"` + Formation interface{} `json:"formation"` + IsCancelled bool `json:"isCancelled"` + IsCircularRoute bool `json:"isCircularRoute"` + IsReverseFormation bool `json:"isReverseFormation"` + Length int `json:"length"` + Operator string `json:"operator"` + OperatorCode string `json:"operatorCode"` + Origin []struct { + AssocIsCancelled bool `json:"assocIsCancelled"` + Crs string `json:"crs"` + FutureChangeTo interface{} `json:"futureChangeTo"` + LocationName string `json:"locationName"` + Via interface{} `json:"via"` + } `json:"origin"` + Platform interface{} `json:"platform"` + PreviousCallingPoints interface{} `json:"previousCallingPoints"` + Rsid interface{} `json:"rsid"` + ServiceID string `json:"serviceID"` + ServiceIDGUID string `json:"serviceIdGuid"` + ServiceIDPercentEncoded string `json:"serviceIdPercentEncoded"` + ServiceIDURLSafe string `json:"serviceIdUrlSafe"` + ServiceType int `json:"serviceType"` + Sta string `json:"sta"` + Std string `json:"std"` + SubsequentCallingPoints []struct { + AssocIsCancelled bool `json:"assocIsCancelled"` + CallingPoint []struct { + AdhocAlerts interface{} `json:"adhocAlerts"` + At interface{} `json:"at"` + Crs string `json:"crs"` + DetachFront bool `json:"detachFront"` + Et string `json:"et"` + Formation interface{} `json:"formation"` + IsCancelled bool `json:"isCancelled"` + Length int `json:"length"` + LocationName string `json:"locationName"` + St string `json:"st"` + } `json:"callingPoint"` + ServiceChangeRequired bool `json:"serviceChangeRequired"` + ServiceType int `json:"serviceType"` + } `json:"subsequentCallingPoints"` + } `json:"trainServices"` +} + +type AllDepartures struct { + Departures []struct { + Service struct { + Formation interface{} `json:"formation"` + Origin []struct { + LocationName string `json:"locationName"` + Crs string `json:"crs"` + Via interface{} `json:"via"` + FutureChangeTo interface{} `json:"futureChangeTo"` + AssocIsCancelled bool `json:"assocIsCancelled"` + } `json:"origin"` + Destination []struct { + LocationName string `json:"locationName"` + Crs string `json:"crs"` + Via interface{} `json:"via"` + FutureChangeTo interface{} `json:"futureChangeTo"` + AssocIsCancelled bool `json:"assocIsCancelled"` + } `json:"destination"` + CurrentOrigins interface{} `json:"currentOrigins"` + CurrentDestinations interface{} `json:"currentDestinations"` + Rsid interface{} `json:"rsid"` + ServiceIDPercentEncoded string `json:"serviceIdPercentEncoded"` + ServiceIDGUID string `json:"serviceIdGuid"` + ServiceIDURLSafe string `json:"serviceIdUrlSafe"` + Sta string `json:"sta"` + Eta string `json:"eta"` + Std string `json:"std"` + Etd string `json:"etd"` + Platform string `json:"platform"` + Operator string `json:"operator"` + OperatorCode string `json:"operatorCode"` + IsCircularRoute bool `json:"isCircularRoute"` + IsCancelled bool `json:"isCancelled"` + FilterLocationCancelled bool `json:"filterLocationCancelled"` + ServiceType int `json:"serviceType"` + Length int `json:"length"` + DetachFront bool `json:"detachFront"` + IsReverseFormation bool `json:"isReverseFormation"` + CancelReason interface{} `json:"cancelReason"` + DelayReason interface{} `json:"delayReason"` + ServiceID string `json:"serviceID"` + AdhocAlerts interface{} `json:"adhocAlerts"` + } `json:"service"` + Crs string `json:"crs"` + } `json:"departures"` + GeneratedAt time.Time `json:"generatedAt"` + LocationName string `json:"locationName"` + Crs string `json:"crs"` + FilterLocationName interface{} `json:"filterLocationName"` + Filtercrs interface{} `json:"filtercrs"` + FilterType int `json:"filterType"` + NrccMessages []struct { + Value string `json:"value"` + } `json:"nrccMessages"` + PlatformAvailable bool `json:"platformAvailable"` + AreServicesAvailable bool `json:"areServicesAvailable"` +} + +type NextTrain struct { + Sta string `json:"sta"` + Eta string `json:"eta"` +} diff --git a/server.go b/server.go new file mode 100644 index 0000000..b4d5b68 --- /dev/null +++ b/server.go @@ -0,0 +1,245 @@ +package main + +import ( + "encoding/json" + "fmt" + "github.com/gofiber/fiber/v2" + "github.com/gofiber/template/html/v2" + "io" + "log" + "net/http" + "os" + "time" +) + +type DummyRecord struct { + Ts string `json:"ts"` +} + +const host = "https://huxley2.azurewebsites.net" + +func main() { + + log.Println("Traintimeserver") + + engine := html.New("./dist", ".html") + + app := fiber.New(fiber.Config{ + Views: engine, + }) + + app.Get("/", indexHandler) + + port := os.Getenv("PORT") + if port == "" { + port = "8100" + } + + app.Static("/", "./dist") + + app.Get("/gettrains", func(c *fiber.Ctx) error { + return getTrains(c) + }) + + app.Get("/getnexttraintimes", func(c *fiber.Ctx) error { + return GetNextTrainTimes(c) + }) + + app.Get("/getroute", func(c *fiber.Ctx) error { + return NotImplemented(c, "getroute") + }) + + app.Get("/getnews", func(c *fiber.Ctx) error { + return NotImplemented(c, "getnews") + }) + + app.Get("/getservice", func(c *fiber.Ctx) error { + return NotImplemented(c, "getservice") + }) + + log.Fatalln(app.Listen(fmt.Sprintf(":%v", port))) +} + +func indexHandler(c *fiber.Ctx) error { + + return c.Render("index", nil) +} + +func NotImplemented(c *fiber.Ctx, from string) error { + + params := c.Queries() + + fmt.Printf("NotImplemented from: %s\n", from) + fmt.Printf("-- %+v\n", params) + + return c.SendString("{}") + +} + +func getTrains(c *fiber.Ctx) error { + + params := c.Queries() + + log.Println("$$:getTrains") + log.Printf("-- %+v\n", params) + + From := c.Query("from", "") + To := c.Query("to", "") + + ts := time.Now().String() + log.Printf("-- %+v\n", ts) + + log.Printf("-- From: %+v\n", From) + log.Printf("-- To: %+v\n", To) + + dummy := DummyRecord{Ts: ts} + + jsonStr, _ := json.Marshal(dummy) + + // const url = `/all/${ request.query['from'] }/to/${ request.query['to'] }/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8`; + + if From != "" && To != "" { + log.Println("-- Got something to search for") + + // `/all/${ req.query.from }/to/${ req.query.to }/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8`; + url := "/all/" + From + "/to/" + To + "/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8" + + log.Printf("-- url: %+v\n", url) + + tr := &http.Transport{ + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + DisableCompression: true, + } + client := &http.Client{Transport: tr} + + log.Printf("-- full url: %+v\n", host+url) + resp, err := client.Get(host + url) + + if err != nil { + // handle error + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + + if err != nil { + log.Fatal(err) + } + + // log.Printf("-- body: %+v\n", string(body)) + + return c.SendString(string(body)) + } + + return c.SendString(string(jsonStr)) +} + +func GetNextTrainTimes(c *fiber.Ctx) error { + + params := c.Queries() + + log.Println("$$:GetNextTrainTimes") + log.Printf("-- %+v\n", params) + + From := c.Query("from", "") + To := c.Query("to", "") + + ts := time.Now().String() + log.Printf("-- %+v\n", ts) + + log.Printf("-- From: %+v\n", From) + log.Printf("-- To: %+v\n", To) + + dummy := DummyRecord{Ts: ts} + + jsonStr, _ := json.Marshal(dummy) + + if From != "" && To != "" { + log.Println("-- Got something to search for") + + // `/all/${ req.query.from }/to/${ req.query.to }/10?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8`; + url := "/next/" + From + "/to/" + To + "?accessToken=215b99fe-b237-4a01-aadc-cf315d6756d8" + + log.Printf("-- url: %+v\n", url) + + tr := &http.Transport{ + MaxIdleConns: 10, + IdleConnTimeout: 30 * time.Second, + DisableCompression: true, + } + client := &http.Client{Transport: tr} + + log.Printf("-- full url: %+v\n", host+url) + resp, err := client.Get(host + url) + + if err != nil { + // handle error + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + + if err != nil { + log.Fatal(err) + } + + var services AllDepartures + unerr := json.Unmarshal(body, &services) + + if unerr != nil { + + log.Println("Failed to Unmarshal json") + panic(unerr) + + } + + departure := reduceNextTrainTimes(services) + + departJson, derr := json.Marshal(departure) + + if derr != nil { + + log.Println("Failed to marshal json") + panic(derr) + + } + + // log.Println("-- body: %+v\n", string(body)) + c.Set(fiber.HeaderContentType, fiber.MIMEApplicationJSON) + + return c.SendString(string(departJson)) + // return c.Send(body) + } + + return c.SendString(string(jsonStr)) +} + +func reduceNextTrainTimes(departData AllDepartures) NextTrain { + + // log.Printf("-- obj?: %+v\n", departData) + + depart := departData.Departures[0].Service + // log.Printf("-- depart: %+v\n", depart) + var output NextTrain + + if depart.Origin != nil { + if depart.Sta != "" { + output.Sta = depart.Sta + } else { + output.Sta = depart.Std + } + + if depart.Eta != "" { + output.Eta = depart.Eta + } else { + output.Eta = depart.Etd + } + + } else { + output.Eta = "No Service" + output.Sta = "No Service" + } + + // log.Printf("-- output: %+v\n", depart) + + return output +} diff --git a/tmp/build-errors.log b/tmp/build-errors.log new file mode 100644 index 0000000..6c6d080 --- /dev/null +++ b/tmp/build-errors.log @@ -0,0 +1 @@ +exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1 \ No newline at end of file diff --git a/tmp/main b/tmp/main new file mode 100755 index 0000000..3a25520 Binary files /dev/null and b/tmp/main differ diff --git a/traintimes b/traintimes new file mode 100755 index 0000000..3a25520 Binary files /dev/null and b/traintimes differ