ctucx.git: trainsearch

web based trip-planner, fork of https://cyberchaos.dev/yuka/trainsearch

commit 1630cdbe8e2139cbacea53c0e72fb4288d389c73
Author: Yureka <yuka@yuka.dev>
Date: Sat, 14 Aug 2021 12:03:53 +0200

initial commit
36 files changed, 5365 insertions(+), 0 deletions(-)
A
client/.gitignore
|
2
++
A
client/package-lock.json
|
635
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/package.json
|
22
++++++++++++++++++++++
A
client/resources/favicon-512x512.png
|
0
A
client/resources/favicon-64x64.png
|
0
A
client/resources/img/apple-touch-icon.png
|
0
A
client/resources/img/favicon-16x16.png
|
0
A
client/resources/img/favicon-32x32.png
|
0
A
client/resources/img/favicon-512x512.png
|
0
A
client/resources/img/favicon-64x64.png
|
0
A
client/resources/img/travelynx.svg
|
23
+++++++++++++++++++++++
A
client/resources/index.html
|
65
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/resources/manifest.json
|
21
+++++++++++++++++++++
A
client/resources/service-worker.js
|
91
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/resources/style.css
|
993
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/resources/varela-regular-webfont.woff2
|
0
A
client/rollup.config.js
|
31
+++++++++++++++++++++++++++++++
A
client/src/api.js
|
49
+++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/app_functions.js
|
139
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/canvas.js
|
336
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/dataStorage.js
|
84
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/ds100.js
|
2
++
A
client/src/helpers.js
|
97
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/journeyView.js
|
220
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/journeysView.js
|
166
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/languages.js
|
115
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/main.js
|
30
++++++++++++++++++++++++++++++
A
client/src/map.js
|
72
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/overlays.js
|
54
++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/router.js
|
23
+++++++++++++++++++++++
A
client/src/searchView.js
|
461
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
client/src/settingsView.js
|
60
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
server/.gitignore
|
2
++
A
server/index.js
|
124
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
server/package-lock.json
|
1431
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
A
server/package.json
|
17
+++++++++++++++++
diff --git a/client/.gitignore b/client/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+out
diff --git a/client/package-lock.json b/client/package-lock.json
@@ -0,0 +1,635 @@
+{
+  "name": "trainsearch-client",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "@babel/code-frame": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz",
+      "integrity": "sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw==",
+      "dev": true,
+      "requires": {
+        "@babel/highlight": "^7.14.5"
+      }
+    },
+    "@babel/helper-validator-identifier": {
+      "version": "7.14.9",
+      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.14.9.tgz",
+      "integrity": "sha512-pQYxPY0UP6IHISRitNe8bsijHex4TWZXi2HwKVsjPiltzlhse2znVcm9Ace510VT1kxIHjGJCZZQBX2gJDbo0g==",
+      "dev": true
+    },
+    "@babel/highlight": {
+      "version": "7.14.5",
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz",
+      "integrity": "sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg==",
+      "dev": true,
+      "requires": {
+        "@babel/helper-validator-identifier": "^7.14.5",
+        "chalk": "^2.0.0",
+        "js-tokens": "^4.0.0"
+      }
+    },
+    "@mapbox/jsonlint-lines-primitives": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/@mapbox/jsonlint-lines-primitives/-/jsonlint-lines-primitives-2.0.2.tgz",
+      "integrity": "sha1-zlblOfg1UrWNENZy6k1vya3HsjQ="
+    },
+    "@mapbox/mapbox-gl-style-spec": {
+      "version": "13.21.0",
+      "resolved": "https://registry.npmjs.org/@mapbox/mapbox-gl-style-spec/-/mapbox-gl-style-spec-13.21.0.tgz",
+      "integrity": "sha512-qGRAZEHQfhjknjd9eCsNmKclXG5zK62DRdbgUiqAnrdkjjXrFNbs0KFaeyY8RzbdXzKRkwge6nqeKJfjYoD3vw==",
+      "requires": {
+        "@mapbox/jsonlint-lines-primitives": "~2.0.2",
+        "@mapbox/point-geometry": "^0.1.0",
+        "@mapbox/unitbezier": "^0.0.0",
+        "csscolorparser": "~1.0.2",
+        "json-stringify-pretty-compact": "^2.0.0",
+        "minimist": "^1.2.5",
+        "rw": "^1.3.3",
+        "sort-object": "^0.3.2"
+      }
+    },
+    "@mapbox/point-geometry": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz",
+      "integrity": "sha1-ioP5M1x4YO/6Lu7KJUMyqgru2PI="
+    },
+    "@mapbox/unitbezier": {
+      "version": "0.0.0",
+      "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.0.tgz",
+      "integrity": "sha1-FWUb1VOme4WB+zmIEMmK2Go0Uk4="
+    },
+    "@rollup/plugin-commonjs": {
+      "version": "20.0.0",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-20.0.0.tgz",
+      "integrity": "sha512-5K0g5W2Ol8hAcTHqcTBHiA7M58tfmYi1o9KxeJuuRNpGaTa5iLjcyemBitCBcKXaHamOBBEH2dGom6v6Unmqjg==",
+      "dev": true,
+      "requires": {
+        "@rollup/pluginutils": "^3.1.0",
+        "commondir": "^1.0.1",
+        "estree-walker": "^2.0.1",
+        "glob": "^7.1.6",
+        "is-reference": "^1.2.1",
+        "magic-string": "^0.25.7",
+        "resolve": "^1.17.0"
+      }
+    },
+    "@rollup/plugin-node-resolve": {
+      "version": "13.0.4",
+      "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-13.0.4.tgz",
+      "integrity": "sha512-eYq4TFy40O8hjeDs+sIxEH/jc9lyuI2k9DM557WN6rO5OpnC2qXMBNj4IKH1oHrnAazL49C5p0tgP0/VpqJ+/w==",
+      "dev": true,
+      "requires": {
+        "@rollup/pluginutils": "^3.1.0",
+        "@types/resolve": "1.17.1",
+        "builtin-modules": "^3.1.0",
+        "deepmerge": "^4.2.2",
+        "is-module": "^1.0.0",
+        "resolve": "^1.19.0"
+      }
+    },
+    "@rollup/pluginutils": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-3.1.0.tgz",
+      "integrity": "sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "0.0.39",
+        "estree-walker": "^1.0.1",
+        "picomatch": "^2.2.2"
+      },
+      "dependencies": {
+        "estree-walker": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-1.0.1.tgz",
+          "integrity": "sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==",
+          "dev": true
+        }
+      }
+    },
+    "@types/estree": {
+      "version": "0.0.39",
+      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz",
+      "integrity": "sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==",
+      "dev": true
+    },
+    "@types/node": {
+      "version": "16.6.1",
+      "resolved": "https://registry.npmjs.org/@types/node/-/node-16.6.1.tgz",
+      "integrity": "sha512-Sr7BhXEAer9xyGuCN3Ek9eg9xPviCF2gfu9kTfuU2HkTVAMYSDeX40fvpmo72n5nansg3nsBjuQBrsS28r+NUw==",
+      "dev": true
+    },
+    "@types/resolve": {
+      "version": "1.17.1",
+      "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.17.1.tgz",
+      "integrity": "sha512-yy7HuzQhj0dhGpD8RLXSZWEkLsV9ibvxvi6EiJ3bkqLAO1RGo0WbkWQiwpRlSFymTJRz0d3k5LM3kkx8ArDbLw==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*"
+      }
+    },
+    "ansi-styles": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
+      "dev": true,
+      "requires": {
+        "color-convert": "^1.9.0"
+      }
+    },
+    "balanced-match": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+      "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+      "dev": true
+    },
+    "brace-expansion": {
+      "version": "1.1.11",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+      "dev": true,
+      "requires": {
+        "balanced-match": "^1.0.0",
+        "concat-map": "0.0.1"
+      }
+    },
+    "buffer-from": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
+      "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
+      "dev": true
+    },
+    "builtin-modules": {
+      "version": "3.2.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.2.0.tgz",
+      "integrity": "sha512-lGzLKcioL90C7wMczpkY0n/oART3MbBa8R9OFGE1rJxoVI86u4WAGfEk8Wjv10eKSyTHVGkSo3bvBylCEtk7LA==",
+      "dev": true
+    },
+    "chalk": {
+      "version": "2.4.2",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
+      "dev": true,
+      "requires": {
+        "ansi-styles": "^3.2.1",
+        "escape-string-regexp": "^1.0.5",
+        "supports-color": "^5.3.0"
+      }
+    },
+    "color-convert": {
+      "version": "1.9.3",
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
+      "dev": true,
+      "requires": {
+        "color-name": "1.1.3"
+      }
+    },
+    "color-name": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
+      "dev": true
+    },
+    "commander": {
+      "version": "2.20.3",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
+      "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
+      "dev": true
+    },
+    "commondir": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
+      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
+      "dev": true
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
+      "dev": true
+    },
+    "csscolorparser": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/csscolorparser/-/csscolorparser-1.0.3.tgz",
+      "integrity": "sha1-s085HupNqPPpgjHizNjfnAQfFxs="
+    },
+    "deepmerge": {
+      "version": "4.2.2",
+      "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz",
+      "integrity": "sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg==",
+      "dev": true
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
+      "dev": true
+    },
+    "estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "dev": true
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
+      "dev": true
+    },
+    "fsevents": {
+      "version": "2.3.2",
+      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz",
+      "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==",
+      "dev": true,
+      "optional": true
+    },
+    "function-bind": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
+      "dev": true
+    },
+    "glob": {
+      "version": "7.1.7",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz",
+      "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==",
+      "dev": true,
+      "requires": {
+        "fs.realpath": "^1.0.0",
+        "inflight": "^1.0.4",
+        "inherits": "2",
+        "minimatch": "^3.0.4",
+        "once": "^1.3.0",
+        "path-is-absolute": "^1.0.0"
+      }
+    },
+    "has": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+      "dev": true,
+      "requires": {
+        "function-bind": "^1.1.1"
+      }
+    },
+    "has-flag": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
+      "dev": true
+    },
+    "idb": {
+      "version": "6.1.2",
+      "resolved": "https://registry.npmjs.org/idb/-/idb-6.1.2.tgz",
+      "integrity": "sha512-1DNDVu3yDhAZkFDlJf0t7r+GLZ248F5pTAtA7V0oVG3yjmV125qZOx3g0XpAEkGZVYQiFDAsSOnGet2bhugc3w=="
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
+      "dev": true,
+      "requires": {
+        "once": "^1.3.0",
+        "wrappy": "1"
+      }
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+      "dev": true
+    },
+    "is-core-module": {
+      "version": "2.5.0",
+      "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.5.0.tgz",
+      "integrity": "sha512-TXCMSDsEHMEEZ6eCA8rwRDbLu55MRGmrctljsBX/2v1d9/GzqHOxW5c5oPSgrUt2vBFXebu9rGqckXGPWOlYpg==",
+      "dev": true,
+      "requires": {
+        "has": "^1.0.3"
+      }
+    },
+    "is-module": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz",
+      "integrity": "sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE=",
+      "dev": true
+    },
+    "is-reference": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz",
+      "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==",
+      "dev": true,
+      "requires": {
+        "@types/estree": "*"
+      }
+    },
+    "jest-worker": {
+      "version": "26.6.2",
+      "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz",
+      "integrity": "sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ==",
+      "dev": true,
+      "requires": {
+        "@types/node": "*",
+        "merge-stream": "^2.0.0",
+        "supports-color": "^7.0.0"
+      },
+      "dependencies": {
+        "has-flag": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+          "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "7.2.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+          "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+          "dev": true,
+          "requires": {
+            "has-flag": "^4.0.0"
+          }
+        }
+      }
+    },
+    "js-tokens": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
+      "dev": true
+    },
+    "json-stringify-pretty-compact": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-2.0.0.tgz",
+      "integrity": "sha512-WRitRfs6BGq4q8gTgOy4ek7iPFXjbra0H3PmDLKm2xnZ+Gh1HUhiKGgCZkSPNULlP7mvfu6FV/mOLhCarspADQ=="
+    },
+    "lit-html": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/lit-html/-/lit-html-1.4.1.tgz",
+      "integrity": "sha512-B9btcSgPYb1q4oSOb/PrOT6Z/H+r6xuNzfH4lFli/AWhYwdtrgQkQWBbIc6mdnf6E2IL3gDXdkkqNktpU0OZQA=="
+    },
+    "magic-string": {
+      "version": "0.25.7",
+      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.7.tgz",
+      "integrity": "sha512-4CrMT5DOHTDk4HYDlzmwu4FVCcIYI8gauveasrdCu2IKIFOJ3f0v/8MDGJCDL9oD2ppz/Av1b0Nj345H9M+XIA==",
+      "dev": true,
+      "requires": {
+        "sourcemap-codec": "^1.4.4"
+      }
+    },
+    "mapbox-to-css-font": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/mapbox-to-css-font/-/mapbox-to-css-font-2.4.0.tgz",
+      "integrity": "sha512-v674D0WtpxCXlA6E+sBlG1QJWdUkz/s9qAD91bJSXBGuBL5lL4tJXpoJEftecphCh2SVQCjWMS2vhylc3AIQTg=="
+    },
+    "merge-stream": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
+      "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==",
+      "dev": true
+    },
+    "minimatch": {
+      "version": "3.0.4",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
+      "dev": true,
+      "requires": {
+        "brace-expansion": "^1.1.7"
+      }
+    },
+    "minimist": {
+      "version": "1.2.5",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
+      "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
+    },
+    "ol": {
+      "version": "6.6.1",
+      "resolved": "https://registry.npmjs.org/ol/-/ol-6.6.1.tgz",
+      "integrity": "sha512-QHNth7ty7UAPi5oEL5N5rJB/cgdFGAAzigYEM8LTUKCq/StTOTWDf2fFrom3wQVmsr1etf6i6hTBowtY/LiGgg==",
+      "requires": {
+        "ol-mapbox-style": "^6.4.1",
+        "pbf": "3.2.1",
+        "rbush": "^3.0.1"
+      }
+    },
+    "ol-mapbox-style": {
+      "version": "6.4.1",
+      "resolved": "https://registry.npmjs.org/ol-mapbox-style/-/ol-mapbox-style-6.4.1.tgz",
+      "integrity": "sha512-qeHgB5lEaCjvpaR6oK8bPWqPTUAYzM2CTSfYJzujIU3egYLPCvJfVagIfTEMRDUG3CXTtIYHOI2Pg58ihhWJYA==",
+      "requires": {
+        "@mapbox/mapbox-gl-style-spec": "^13.20.1",
+        "mapbox-to-css-font": "^2.4.0",
+        "webfont-matcher": "^1.1.0"
+      }
+    },
+    "once": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
+      "dev": true,
+      "requires": {
+        "wrappy": "1"
+      }
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
+      "dev": true
+    },
+    "path-parse": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+      "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+      "dev": true
+    },
+    "pbf": {
+      "version": "3.2.1",
+      "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz",
+      "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==",
+      "requires": {
+        "ieee754": "^1.1.12",
+        "resolve-protobuf-schema": "^2.1.0"
+      }
+    },
+    "picomatch": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
+      "integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
+      "dev": true
+    },
+    "protocol-buffers-schema": {
+      "version": "3.5.2",
+      "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.5.2.tgz",
+      "integrity": "sha512-LPzSaBYp/TcbuSlpGwqT5jR9kvJ3Zp5ic2N5c2ybx6XB/lSfEHq2D7ja8AgoxHoMD91wXFALJoXsvshKPuXyew=="
+    },
+    "quickselect": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-2.0.0.tgz",
+      "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw=="
+    },
+    "randombytes": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
+      "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
+      "dev": true,
+      "requires": {
+        "safe-buffer": "^5.1.0"
+      }
+    },
+    "rbush": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/rbush/-/rbush-3.0.1.tgz",
+      "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==",
+      "requires": {
+        "quickselect": "^2.0.0"
+      }
+    },
+    "resolve": {
+      "version": "1.20.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
+      "integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
+      "dev": true,
+      "requires": {
+        "is-core-module": "^2.2.0",
+        "path-parse": "^1.0.6"
+      }
+    },
+    "resolve-protobuf-schema": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
+      "integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
+      "requires": {
+        "protocol-buffers-schema": "^3.3.1"
+      }
+    },
+    "rollup": {
+      "version": "2.56.2",
+      "resolved": "https://registry.npmjs.org/rollup/-/rollup-2.56.2.tgz",
+      "integrity": "sha512-s8H00ZsRi29M2/lGdm1u8DJpJ9ML8SUOpVVBd33XNeEeL3NVaTiUcSBHzBdF3eAyR0l7VSpsuoVUGrRHq7aPwQ==",
+      "dev": true,
+      "requires": {
+        "fsevents": "~2.3.2"
+      }
+    },
+    "rollup-plugin-terser": {
+      "version": "7.0.2",
+      "resolved": "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz",
+      "integrity": "sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ==",
+      "dev": true,
+      "requires": {
+        "@babel/code-frame": "^7.10.4",
+        "jest-worker": "^26.2.1",
+        "serialize-javascript": "^4.0.0",
+        "terser": "^5.0.0"
+      }
+    },
+    "rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+      "dev": true
+    },
+    "serialize-javascript": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-4.0.0.tgz",
+      "integrity": "sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw==",
+      "dev": true,
+      "requires": {
+        "randombytes": "^2.1.0"
+      }
+    },
+    "sort-asc": {
+      "version": "0.1.0",
+      "resolved": "https://registry.npmjs.org/sort-asc/-/sort-asc-0.1.0.tgz",
+      "integrity": "sha1-q3md9h/HPqCVbHnEtTHtHp53J+k="
+    },
+    "sort-desc": {
+      "version": "0.1.1",
+      "resolved": "https://registry.npmjs.org/sort-desc/-/sort-desc-0.1.1.tgz",
+      "integrity": "sha1-GYuMDN6wlcRjNBhh45JdTuNZqe4="
+    },
+    "sort-object": {
+      "version": "0.3.2",
+      "resolved": "https://registry.npmjs.org/sort-object/-/sort-object-0.3.2.tgz",
+      "integrity": "sha1-mODRme3kDgfGGoRAPGHWw7KQ+eI=",
+      "requires": {
+        "sort-asc": "^0.1.0",
+        "sort-desc": "^0.1.1"
+      }
+    },
+    "source-map": {
+      "version": "0.7.3",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz",
+      "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==",
+      "dev": true
+    },
+    "source-map-support": {
+      "version": "0.5.19",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.19.tgz",
+      "integrity": "sha512-Wonm7zOCIJzBGQdB+thsPar0kYuCIzYvxZwlBa87yi/Mdjv7Tip2cyVbLj5o0cFPN4EVkuTwb3GDDyUx2DGnGw==",
+      "dev": true,
+      "requires": {
+        "buffer-from": "^1.0.0",
+        "source-map": "^0.6.0"
+      },
+      "dependencies": {
+        "source-map": {
+          "version": "0.6.1",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+          "dev": true
+        }
+      }
+    },
+    "sourcemap-codec": {
+      "version": "1.4.8",
+      "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz",
+      "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==",
+      "dev": true
+    },
+    "supports-color": {
+      "version": "5.5.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+      "dev": true,
+      "requires": {
+        "has-flag": "^3.0.0"
+      }
+    },
+    "terser": {
+      "version": "5.7.1",
+      "resolved": "https://registry.npmjs.org/terser/-/terser-5.7.1.tgz",
+      "integrity": "sha512-b3e+d5JbHAe/JSjwsC3Zn55wsBIM7AsHLjKxT31kGCldgbpFePaFo+PiddtO6uwRZWRw7sPXmAN8dTW61xmnSg==",
+      "dev": true,
+      "requires": {
+        "commander": "^2.20.0",
+        "source-map": "~0.7.2",
+        "source-map-support": "~0.5.19"
+      }
+    },
+    "webfont-matcher": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/webfont-matcher/-/webfont-matcher-1.1.0.tgz",
+      "integrity": "sha1-mM6VCXsp4x++czBT4Q5XFkLRxsc="
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
+      "dev": true
+    }
+  }
+}
diff --git a/client/package.json b/client/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "trainsearch-client",
+  "version": "1.0.0",
+  "description": "",
+  "main": "service-worker.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "AGPL-3.0",
+  "dependencies": {
+    "idb": "^6.1.2",
+    "lit-html": "^1.4.1",
+    "ol": "^6.6.1"
+  },
+  "devDependencies": {
+    "@rollup/plugin-commonjs": "^20.0.0",
+    "@rollup/plugin-node-resolve": "^13.0.4",
+    "rollup": "^2.56.2",
+    "rollup-plugin-terser": "^7.0.2"
+  }
+}
diff --git a/client/resources/favicon-512x512.png b/client/resources/favicon-512x512.png  Binary files differ.
diff --git a/client/resources/favicon-64x64.png b/client/resources/favicon-64x64.png  Binary files differ.
diff --git a/client/resources/img/apple-touch-icon.png b/client/resources/img/apple-touch-icon.png  Binary files differ.
diff --git a/client/resources/img/favicon-16x16.png b/client/resources/img/favicon-16x16.png  Binary files differ.
diff --git a/client/resources/img/favicon-32x32.png b/client/resources/img/favicon-32x32.png  Binary files differ.
diff --git a/client/resources/img/favicon-512x512.png b/client/resources/img/favicon-512x512.png  Binary files differ.
diff --git a/client/resources/img/favicon-64x64.png b/client/resources/img/favicon-64x64.png  Binary files differ.
diff --git a/client/resources/img/travelynx.svg b/client/resources/img/travelynx.svg
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="24" height="24" viewBox="0 0 24 24" version="1.1" id="svg6" sodipodi:docname="travelynx.svg" inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
+  <metadata id="metadata12">
+    <rdf:RDF>
+      <cc:Work rdf:about="">
+        <dc:format>image/svg+xml</dc:format>
+        <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+        <dc:title/>
+      </cc:Work>
+    </rdf:RDF>
+  </metadata>
+  <defs id="defs10"/>
+  <sodipodi:namedview pagecolor="#ffffff" bordercolor="#666666" borderopacity="1" objecttolerance="10" gridtolerance="10" guidetolerance="10" inkscape:pageopacity="0" inkscape:pageshadow="2" inkscape:window-width="1918" inkscape:window-height="2131" id="namedview8" showgrid="false" inkscape:zoom="19.666667" inkscape:cx="0.25717638" inkscape:cy="10.252251" inkscape:window-x="0" inkscape:window-y="0" inkscape:window-maximized="0" inkscape:current-layer="g4573"/>
+  <g id="g4573">
+    <rect y="3.40678" x="3.1271186" height="9.5338984" width="10.550848" id="rect4564" style="fill:#ffffff;fill-opacity:1;stroke-width:1.44797695"/>
+    <g id="g4562">
+      <path d="m 8.4266298,1.3049637 c -3.0613961,0 -6.1227924,0.3826745 -6.1227924,3.0613962 v 7.2708161 c 0,1.477124 1.2015981,2.678722 2.6787217,2.678722 l -1.1480235,1.148023 v 0.382675 H 5.5412639 L 7.071962,14.315898 h 2.8853658 l 1.5306982,1.530698 h 1.530698 V 15.463921 L 11.8707,14.315898 c 1.477124,0 2.678722,-1.201598 2.678722,-2.678722 V 4.3663599 c 0,-2.6787217 -2.73995,-3.0613962 -6.1227922,-3.0613962 z M 4.9825591,12.7852 c -0.6352397,0 -1.1480235,-0.512784 -1.1480235,-1.148024 0,-0.63524 0.5127838,-1.148024 1.1480235,-1.148024 0.6352397,0 1.1480236,0.512784 1.1480236,1.148024 0,0.63524 -0.5127839,1.148024 -1.1480236,1.148024 z M 7.6612808,7.427756 H 3.8345356 V 4.3663599 h 3.8267452 z m 1.5306982,0 V 4.3663599 h 3.826745 V 7.427756 Z M 11.8707,12.7852 c -0.635239,0 -1.148023,-0.512784 -1.148023,-1.148024 0,-0.63524 0.512784,-1.148024 1.148023,-1.148024 0.63524,0 1.148024,0.512784 1.148024,1.148024 0,0.63524 -0.512784,1.148024 -1.148024,1.148024 z" id="path14" inkscape:connector-curvature="0" style="stroke-width:0.76534903"/>
+      <path style="fill:none" inkscape:connector-curvature="0" d="M 0,0 H 24 V 24 H 0 Z" id="path16"/>
+      <path inkscape:connector-curvature="0" d="M 13.208696,20.997167 9.6183022,17.406774 8.3956743,18.620792 13.208696,23.433813 23.540763,13.101746 22.326745,11.887728 Z" id="path16-3" style="stroke-width:0.8610056"/>
+    </g>
+  </g>
+</svg>+
\ No newline at end of file
diff --git a/client/resources/index.html b/client/resources/index.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html lang="de">
+	<head>
+		<title>TrainSearch</title>
+		<meta charset="UTF-8">
+
+		<meta name="viewport" content="width=device-width, initial-scale=1.0">
+		<meta name="theme-color" content="#ffffff">
+		<meta name="description" content="Plan your public transport journeys">
+
+		<link rel="icon" type="image/png" sizes="64x64" href="/favicon-64x64.png">
+		<link rel="manifest" href="/manifest.json">
+		<link rel="stylesheet" type="text/css" href="style.css">
+
+		<link rel="modulepreload" href="main.js">
+		<link rel="manifest" href="manifest.json">
+		<style>
+body {
+	background-color: #333;
+	min-height: 100vh;
+	overflow-x: hidden;
+	overflow-y: visible;
+}
+
+#overlay {
+	position: fixed;
+	top: 0;
+	left: 0;
+	height: 100vh;
+	width: 100vw;
+	background-color: rgba(0, 0, 0, .7);
+	overflow: hidden;
+	display: flex;
+}
+
+#overlay>* {
+	margin: auto;
+}
+
+#logo {
+	background-color: #7171e5;
+	border-radius: 15%;
+	width: 50vmin;
+	height: 50vmin;
+}
+
+#logo>svg {
+	width: 75%;
+	height: 75%;
+	margin: 12.5%;
+	fill: white;
+}
+		</style>
+	</head>
+	<body>
+		<div id="content"></div>
+		<div id="overlay">
+			<noscript>JavaScript is required to use TrainSearch</noscript>
+			<div id="logo">
+				<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm3.5-7H6V6h5v4zm2 0V6h5v4h-5zm3.5 7c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/><path fill="none" d="M0 0h24v24H0V0z"/></svg>
+			</div>
+		</div>
+		<script type="module" src="main.js"></script>
+	</body>
+</html>
diff --git a/client/resources/manifest.json b/client/resources/manifest.json
@@ -0,0 +1,21 @@
+{
+	"name": "TrainSearch",
+	"short_name": "TrainSearch",
+	"start_url": ".",
+	"icons": [
+		{
+			"src": "/favicon-64x64.png",
+			"sizes": "64x64",
+			"type": "image/png"
+		},
+		{
+			"src": "/favicon-512x512.png",
+			"sizes": "512x512",
+			"type": "image/png"
+		}
+	],
+	"theme_color": "#ffffff",
+	"background_color": "#ffffff",
+	"display": "standalone"
+}
+
diff --git a/client/resources/service-worker.js b/client/resources/service-worker.js
@@ -0,0 +1,91 @@
+'use strict';
+
+const CACHE = 'cache-v34';
+
+let preCache = [
+	'./img/product_bus_grey.svg',
+	'./img/product_cablecar_color.svg',
+	'./img/product_cablecar_grey.svg',
+	'./img/product_call_color.svg',
+	'./img/product_call_grey.svg',
+	'./img/product_ferry_color.svg',
+	'./img/product_ferry_grey.svg',
+	'./img/product_highspeed_color.svg',
+	'./img/product_highspeed_grey.svg',
+	'./img/product_suburban_color.svg',
+	'./img/product_suburban_grey.svg',
+	'./img/product_subway_color.svg',
+	'./img/product_subway_grey.svg',
+	'./img/product_train_color.svg',
+	'./img/product_train_grey.svg',
+	'./img/product_bus_color.svg',
+	'./img/product_tram_grey.svg',
+	'./img/product_tram_color.svg',
+	'./img/back.svg',
+	'./img/baseline-beenhere-24px.svg',
+	'./img/baseline-departure_board-24px.svg',
+	'./img/baseline-directions-24px.svg',
+	'./img/baseline-directions-24px_white.svg',
+	'./img/baseline-directions_walk-24px.svg',
+	'./img/baseline-expand_more-24px.svg',
+	'./img/baseline-import_export-24px.svg',
+	'./img/baseline-navigation-24px.svg',
+	'./img/baseline-place-24px.svg',
+	'./img/baseline-settings-20px.svg',
+	'./ing/baseline-swap_vert-24px.svg',
+	'./img/baseline-refresh-24px.svg',
+	'./img/ba8064fd767ceaa170589aa3dd11e58e.jpg',
+	'./img/favicon-16x16.png',
+	'./img/favicon-32x32.png',
+	'./img/favicon-64x64.png',
+	'./img/favicon-512x512.png',
+	'./img/apple-touch-icon.png',
+	'./js/api.js',
+	'./js/canvas.js',
+	'./js/journeysView.js',
+	'./js/journeyView.js',
+	'./js/searchView.js',
+	'./js/settingsView.js',
+	'./js/app_functions.js',
+	'./js/helpers.js',
+	'./js/app.js',
+	'./js/router.js',
+	'./js/overlays.js',
+	'./css/product_selector.css',
+	'./css/style.css',
+	'./manifest.json',
+	'./index.html',
+	'./'
+];
+
+self.addEventListener('install', function (evt) {
+	self.skipWaiting();
+	evt.waitUntil(caches.open(CACHE).then(function (cache) {
+		cache.addAll(preCache);
+	}));
+});
+
+self.addEventListener('fetch', function (evt) {
+	evt.respondWith(fromCache(evt.request).then(function (match) {
+		if (match) {
+			return match;
+		} else {
+			return fetch(evt.request);
+		}
+	}));
+});
+
+self.addEventListener('activate', function (event) {
+	event.waitUntil(clients.claim());
+	event.waitUntil(clients.claim().then(function () {
+		return caches.keys().then(function (cacheNames) {
+			return Promise.all(cacheNames.filter(c => c !== CACHE).map(c => caches.delete(c)));
+		});
+	}));
+});
+
+function fromCache (request) {
+	return caches.open(CACHE).then(function (cache) {
+		return cache.match(request);
+	});
+}
diff --git a/client/resources/style.css b/client/resources/style.css
@@ -0,0 +1,993 @@
+font-face {
+	font-family: 'varelaregular';
+	src: url('./varela-regular-webfont.woff2') format('woff2');
+	font-weight: normal;
+	font-style: normal;
+}
+
+* {
+	font-family: Varela, sans-serif;
+	box-sizing: border-box;
+	border-collapse: collapse;
+}
+
+html, body {
+	margin: 0;
+	min-height: 100vh;
+	overflow-x: hidden;
+	overflow-y: visible;
+}
+ 
+a {
+	color: inherit;
+}
+
+header {
+	position: relative;
+	color: white;
+	background-color: #222;
+	bottom-border: 1px solid rgba(255, 255, 255, .3);
+	display: flex;
+	flex-direction: row;
+	justify-content: center;
+}
+
+.header-content {
+	max-width: 1000px;
+	width: 80vw;
+	display: flex;
+	flex-direction: row;
+	flex-wrap: wrap;
+}
+.header-content>div {
+	display: flex;
+	flex-direction: row;
+	flex-grow: 1;
+	flex-wrap: wrap;
+}
+
+.row {
+	display: flex;
+	flex-direction: row;
+}
+
+.cancelled {
+	text-decoration-line: line-through;
+}
+.cancelled-text {
+	font-weight: bold;
+	color: red;
+}
+
+.pointer {
+	cursor: pointer;
+}
+
+.back.invisible {
+	visibility: hidden;
+}
+.back,
+.reload {
+	cursor: pointer;
+	width: 32px;
+	height: 32px;
+	margin: 12px;
+	user-select: none;
+}
+
+.spinner {
+	margin: calc(50vh - 60px) auto;
+	border: 5px solid rgba(255, 255, 255, .4);
+	border-top: 5px solid #fff;
+	border-radius: 50%;
+	width: 120px;
+	height: 120px;
+	animation: spin 2s linear infinite;
+}
+.spinning {
+	animation: spin 2s linear infinite;
+}
+
+@keyframes spin {
+	0% { transform: rotate(0deg); }
+	100% { transform: rotate(360deg); }
+}
+
+.loadMore {
+	cursor: pointer;
+	height: 72px;
+	width: 72px;
+	margin: 0 auto;
+	transition: transform 150ms;
+	user-select: none;
+	filter: invert();
+}
+
+.loadMore.flipped {
+	transform: rotate(180deg);
+	margin-top: 45px;
+}
+
+:checked ~ label[for=btn-history] {
+	transform: rotateX(180deg);
+}
+
+table {
+	border-bottom: 1px solid rgba(0, 0, 0, 0.3);
+	width: 100%;
+	background-color: #fff;
+	min-width: 390px;
+	max-width: 1000px;
+}
+div.card {
+	overflow-x: auto;
+}
+tbody tr {
+	border-top: 1px solid #ccc;
+}
+tr {
+	background-color: #fff;
+	margin: 0 0 15px 0;
+}
+
+td, th {
+	text-align: center;
+	overflow: hidden;
+}
+
+th {
+	padding: 5px 3px;
+}
+
+
+thead tr:not(:last-child) {
+	background-color: #eee;
+}
+
+
+tbody tr:hover {
+	background-color: #ddd;
+}
+
+tbody tr:hover td {
+	background-color: transparent;
+}
+
+@supports (display: flex) {
+	.btn.go,
+	input[type="date"],
+	input[type="time"],
+	input[type="text"],
+	.switch {
+		cursor: pointer;
+		box-sizing: border-box;
+		width: 100%;
+		padding: .3em .5em;
+		font-size: 1.5em;
+		padding: 7px;
+		border: none;
+		outline: none;
+		background-color: white;
+		color: black;
+		margin-top: 8px;
+		border-radius: 0;
+	}
+	input[type="time"] {
+		flex-grow: 1;
+	}
+	input[type="text"] {
+		border: 1px solid transparent;
+	}
+	input[type="text"]:focus {
+		border-bottom: 1px solid rgba(0, 0, 0, .2);
+	}
+
+	.btn.go,
+	.btn,
+	.selector label {
+		cursor: pointer;
+		background-color: white;
+		width: 32px;
+		padding: 3px;
+		height: 32px;
+		display: inline-block;
+		user-select: none;
+	}
+	.selector div:not(:last-child),
+	.selector label:not(:last-child) {
+		border-right: 1px solid rgba(0, 0, 0, .2);
+	}
+
+	.selector {
+		margin-top: 8px;
+		margin-bottom: 8px;
+		margin-right: auto;
+		display: flex;
+		overflow: hidden;
+	}
+
+	.selector > label {
+		width: 32px;
+		height: 32px;
+		user-select: none;
+	}
+
+	.selector > input {
+		display: none;
+	}
+
+	.selector input + label {
+		background: #d3d3d3;
+	}
+
+	.selector input:checked + label {
+		background: #fff;
+	}
+
+	.switch {
+		position: relative;
+		display: inline-block;
+		width: 84px;
+		padding: 0 !important;
+		overflow: hidden;
+		flex-shrink: 0;
+	}
+
+	.switch input {
+		opacity: 0;
+		width: 0;
+		height: 0;
+	}
+
+	.slider {
+		position: absolute;
+		cursor: pointer;
+		top: 0;
+		left: 0;
+		right: 0;
+		bottom: 0;
+		background-color: #bbb;
+		height: 100%;
+	}
+
+	.slider:before {
+		position: absolute;
+		font-size: 13px;
+		padding-top: calc(25% - 7px);
+		line-height: 100%;
+		text-align: center;
+		height: 100%;
+		width: 42px;
+		background-color: white;
+		transition: .2s;
+	}
+
+	.switch input:checked + .slider:before {
+		transform: translateX(42px);
+	}
+
+	.slider.de:before {
+		content: "AB";
+	}
+
+	.switch input:checked + .slider.de:before {
+		content: "AN";
+	}
+
+	.slider.en:before {
+		content: "DEP";
+	}
+
+	.switch input:checked + .slider.en:before {
+		content: "ARR";
+	}
+}
+
+@media (min-width: 576px) {
+
+}
+@media (max-width: 575px) {
+	.selector:nth-child(2) {
+		flex-basis: 100%;
+	}
+}
+
+.journey,
+.journeys {
+	display: flex;
+	flex-direction: column;
+	min-height: 100vh;
+}
+
+.search {
+	color: white;
+	display: flex;
+	flex-direction: column;
+	margin-bottom: 5em;
+}
+
+.search table {
+	width: 100%;
+	color: black;
+}
+
+.search #date {
+	flex-grow: 1;
+	margin-left: 8px;
+}
+
+.search>.title {
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+
+.search>.title>h1 {
+	font-weight: normal;
+	margin-left: .5em;
+	margin: .7em .3em .5em .3em;
+}
+.search>.title>h1:hover {
+	-webkit-text-fill-color: transparent;
+	-webkit-background-clip: text !important;
+	background: linear-gradient(90deg, #b4dcff 20%, pink 20%, pink 40%, white 40%, white 60%, pink 60%, pink 80%, #b4dcff 80%, #b4dcff 100%);
+}
+
+.search>.title>.logo {
+	background-color: #7171e5;
+	border-radius: 15%;
+	width: 50px;
+	height: 50px;
+	margin: 0;
+	padding: 5px 5px 2px 6px;
+}
+
+.search .btn.go {
+	display: flex;
+	justify-content: center;
+	width: 110px;
+	font-size: 20px;
+}
+
+.search .btn.go label {
+	cursor: pointer;
+}
+
+.search .btn.go svg {
+	margin-left: 5px;
+	fill: #5050ff;
+}
+
+
+
+.journeys {
+	min-height: 100vh;
+}
+
+.journeys table a,
+.journey table span {
+	padding: 5px 3px;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	width: 100%;
+	text-decoration: none;
+	color: black;
+}
+
+.journey table a {
+	padding: 5px 3px;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+	text-decoration: none;
+	color: black;
+}
+
+.journeys a.details-button {
+	height: 30px;
+	padding: 0;
+}
+
+.journey tbody td:nth-child(3) {
+	text-align: left;
+}
+
+.journey tbody:not(:last-child) {
+	border-bottom: 1px solid rgba(0, 0, 0, .2);
+}
+
+.journey p {
+	color: white;
+	width: 100%;
+}
+
+.journey p::before {
+	filter: drop-shadow( 0 0 5px rgba(0, 0, 0, .6) );
+	margin-right: 4px;
+	vertical-align: sub;
+}
+
+.journey p.change,
+.journey p.walk,
+.journey p.transfer {
+	text-shadow: 0 0 15px rgba(0, 0, 0, .6);
+	text-align: center;
+}
+
+.journey p.change::before {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path style="fill: white;" d="M9 3L5 6.99h3V14h2V6.99h3L9 3zm7 14.01V10h-2v7.01h-3L15 21l4-3.99h-3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
+}
+
+.journey p.walk::before {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0z"/><path style="fill: white;" d="M13.5 5.5c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zM9.8 8.9L7 23h2.1l1.8-8 2.1 2v6h2v-7.5l-2.1-2 .6-3C14.8 12 16.8 13 19 13v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1L6 8.3V13h2V9.6l1.8-.7"/></svg>');
+}
+
+.journey p.transfer::before {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path style="fill: white;" d="M21.71 11.29l-9-9c-.39-.39-1.02-.39-1.41 0l-9 9c-.39.39-.39 1.02 0 1.41l9 9c.39.39 1.02.39 1.41 0l9-9c.39-.38.39-1.01 0-1.41zM14 14.5V12h-4v3H8v-4c0-.55.45-1 1-1h5V7.5l3.5 3.5-3.5 3.5z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
+}
+
+
+.suggestionsbox {
+	border-radius: 3px;
+	width: 100%;
+}
+
+.suggestionsbox p:first-child {
+	border-top: 0px;
+}
+
+.suggestionsbox p {
+	font-size: 1.2em;
+	background-color: white;
+	color: black;
+	margin: 0;
+	border-top: 1px solid rgba(0, 0, 0, .2);
+	padding: .3em .6em;
+	cursor: pointer;
+}
+
+.suggestions {
+	position: relative;
+	display: none;
+	overflow: visible;
+	z-index: 999;
+	height: 0;
+}
+
+.suggestions.typing,
+.suggestions.mouseover {
+	display: block;
+}
+
+
+
+@media (max-width: 799px) {
+	.back.invisible {
+		display: none;
+	}
+	.header-content {
+		flex-grow: 1;
+	}
+	.search {
+		padding: 10px;
+	}
+
+	.back {
+		left: 10px;
+	}
+
+	.row {
+		flex-wrap: wrap;
+	}
+
+	.search #date {
+		width: initial;
+	}
+
+	.search #time {
+		width: 100%;
+		flex-shrink: 0;
+	}
+	.loadMore.flipped {
+		margin-top: 15px;
+	}
+	.loadMore {
+		width: 48px;
+	}
+}
+
+@media (min-width: 800px) {
+	.journeys table {
+		margin: 15px auto;
+	}
+
+	#content {
+		justify-content: center;
+	}
+	.center {
+		display: flex;
+		justify-content: center;
+		align-items: center;
+	}
+
+	.search {
+		width: 80vw;
+		max-width: 700px;
+		color: white;
+	}
+
+	.search #date {
+		margin-right: 8px;
+	}
+
+	.search #time {
+		width: 40%;
+	}
+
+	td p {
+		display: inline;
+		margin-right: 5px;
+	}
+
+	th {
+		padding: 10px 5px;
+	}
+	.journeys table a {
+		padding: 10px 5px;
+	}
+
+	table {
+		overflow: hidden;
+		border: none;
+		margin: 50px auto;
+		width: 80vw;
+	}
+}
+
+.hidden {
+	display: none !important;
+}
+
+label[for=from], label[for=via], label[for=to], label[for=isarr], label[for="date"], label[for=time] {
+	display: none;
+}
+
+#settingsView {
+	margin: 1em;
+	overflow: auto;
+}
+
+#overlay {
+	position: fixed;
+	z-index: 1;
+	left: 0;
+	top: 0;
+	width: 100%;
+	height: 100%;
+	overflow: auto;
+	background-color: rgba(0,0,0,0.4);
+	backdrop-filter: blur(10px);
+}
+
+
+.modal {
+	display: flex;
+	position: fixed;
+	top: 0;
+	right: 0;
+	bottom: 0;
+	left: 0;
+	z-index: 1050;
+	overflow: hidden;
+	-webkit-overflow-scrolling: touch;
+	outline: 0;
+}
+
+.modal-alert {
+	margin: auto;
+	border-radius: 4px;
+	background-color: white;
+	width: max-content;
+	padding: 15px;
+}
+
+.button:not(:first-child) {
+	margin-left: .2em;
+}
+.button:not(:last-child) {
+	margin-right: .2em;
+}
+.button {
+	border-radius: 4px;
+	background-color: rgba(20, 30, 255, .7);
+	color: white;
+	width: max-content;
+	padding: 8px 20px;
+	margin-left: auto;
+	margin-top: 10px;
+	transition: background-color 300ms;
+	border: none;
+}
+
+.button:hover {
+	background-color: rgba(70, 100, 255, .8);
+	cursor: pointer;
+}
+
+.modal-header {
+	background-color: #5a5a5a;
+	color: white;
+	min-height: 16.4;
+	padding: 15px;
+	border-bottom: 1px solid #e5e5e5;
+}
+
+.modal-header .close {
+	margin-top: -2px;
+}
+
+.modal-header .modal-close {
+	width:53px;
+	float:right;
+	margin:-15px;
+	margin-left:0px;
+	height:53px;
+	border-left: 1px solid #00000040;
+	background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAABO0lEQVR42u3bURKDIAwEUNiLoyfXC3Ss4mYTh81Xv4R90wqEad+2ra1caIuXAQxgAAMYwAAGMIABDGAAA0zVGOMYYxzqibPGxdtJ/PqsCM8aF4xJKBHY40IxwcrPngbY970rJ3r1zKu5hH4DVAhR4Sk/gWiEyPC0d0AUQnR46kuQjaAIT18FWAiq8CHL4FsEZfiws8Asgjp86GHoKUJG+PDT4F2ErPCttdYVd4OzS2F0eFk/YCaIIry0IfIkkCq8FOBuMGV4OUDFkgK83Qh9GoC1Ff4kAPsw9CmAf5scdWdJCnB3h5eJgOzw2QioED4TAVXCZyGgUvgMBFQLr0ZAxfBKBFQNr0JA5fAKBFQPH40gbYtXfDb1dljRzGCPS7sdVnZymON2/2Nk8TKAAQxgAAMYwAAGMIABDLBmnWRS+u5G6HkFAAAAAElFTkSuQmCC') center no-repeat;
+	background-size:30px;
+	cursor:pointer;
+}
+
+.modal-header .modal-close:hover {
+	background: rgba(0, 0, 0, .4) url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAACXBIWXMAAAsTAAALEwEAmpwYAAABO0lEQVR42u3bURKDIAwEUNiLoyfXC3Ss4mYTh81Xv4R90wqEad+2ra1caIuXAQxgAAMYwAAGMIABDGAAA0zVGOMYYxzqibPGxdtJ/PqsCM8aF4xJKBHY40IxwcrPngbY970rJ3r1zKu5hH4DVAhR4Sk/gWiEyPC0d0AUQnR46kuQjaAIT18FWAiq8CHL4FsEZfiws8Asgjp86GHoKUJG+PDT4F2ErPCttdYVd4OzS2F0eFk/YCaIIry0IfIkkCq8FOBuMGV4OUDFkgK83Qh9GoC1Ff4kAPsw9CmAf5scdWdJCnB3h5eJgOzw2QioED4TAVXCZyGgUvgMBFQLr0ZAxfBKBFQNr0JA5fAKBFQPH40gbYtXfDb1dljRzGCPS7sdVnZymON2/2Nk8TKAAQxgAAMYwAAGMIABDLBmnWRS+u5G6HkFAAAAAElFTkSuQmCC') center no-repeat;
+	background-size:30px;
+}
+
+.modal-title {
+	margin: 0;
+	line-height: 1.4;
+}
+
+.modal-dialog {
+	position: relative;
+	width: auto;
+	margin: 10px;
+}
+
+.modal-content {
+	position: relative;
+	background-color: #fff;
+	background-clip: padding-box;
+	border: 1px solid #999;
+	border: 1px solid rgba(0, 0, 0, .2);
+	outline: 0;
+}
+
+.modal-body {
+	position: relative;
+}
+
+@media (min-width: 768px) {
+	.modal-dialog {
+		width: 600px;
+		margin: 30px auto;
+	}
+
+	.modal-content {
+	}
+}
+
+.row.history:first-child {
+	border-top: 0px;
+}
+
+form>div.history {
+	margin-top: 8px;
+	overflow: hidden;
+	display: none;
+	margin-bottom: 1em;
+	user-select: none;
+}
+:checked ~ .history {
+	display: block;
+}
+.row.history {
+	font-size: 1.2em;
+	background-color: white;
+	color: black;
+	margin: 0;
+	border-top: 1px solid rgba(0, 0, 0, .2);
+	padding: .3em .6em .3em .3em;
+	cursor: pointer;
+
+	display: flex;
+	justify-content: space-between;
+}
+
+.history.via {
+	font-weight: 200;
+}
+.history.from,
+.history.to {
+	width: 40%;
+}
+.history.to {
+	text-align: right;
+}
+
+.history.arrow {
+	width: 25px;
+}
+
+.station-column {
+	width: 60%;
+}
+
+.modal {
+	display: flex;
+}
+
+.box {
+	margin: auto;
+	background-color: white;
+	width: max-content;
+	padding: 15px;
+}
+
+.select a {
+	display: block;
+	text-decoration: none;
+	background-color: rgba(20, 30, 255, .7);
+	color: white;
+	width: 100%;
+	padding: 8px 20px;
+	margin-left: auto;
+	margin-top: 10px;
+	text-align: center;
+	transition: background-color 300ms;
+}
+
+.select a:first-child {
+	margin-top: 0px;
+}
+
+.select a:hover {
+	background-color: rgba(70, 100, 255, .8);
+	cursor: pointer;
+}
+
+.journey .link {
+	vertical-align: bottom;
+	cursor: pointer;
+	max-inline-size: 22px;
+	margin: 0 .3em;
+}
+
+.remark {
+	vertical-align: middle;
+}
+
+.remarks td {
+	margin: 0 10px;
+	text-align: left;
+	display: block;
+}
+
+.remarks {
+	/*background: #000000d0;*/
+	border: 1px solid #ddd;
+	padding: 0;
+	width: 100%;
+	margin: 0;
+}
+
+.icon-back {
+	content: url('data:image/svg+xml;utf8,<svg height="100%" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><g color="white"><path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z" fill="currentColor"></path></g></svg>');
+}
+
+.icon-reload {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path style="fill: white;" d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
+}
+
+.icon-hint {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"/></svg>');
+}
+
+.icon-status {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"/></svg>');
+}
+
+.icon-other {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 17h-2v-2h2v2zm2.07-7.75l-.9.92C13.45 12.9 13 13.5 13 15h-2v-.5c0-1.1.45-2.1 1.17-2.83l1.24-1.26c.37-.36.59-.86.59-1.41 0-1.1-.9-2-2-2s-2 .9-2 2H8c0-2.21 1.79-4 4-4s4 1.79 4 4c0 .88-.36 1.68-.93 2.25z"/></svg>');
+}
+
+.icon-arrow1 {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/><path d="M0 0h24v24 H0z" fill="none"/></svg>');
+}
+
+.icon-arrow2 {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
+}
+
+.icon-arrow3 {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/><path d="M0 0h24v24 H0z" fill="none"/></svg>');
+}
+
+.icon-swap {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M16 17.01V10h-2v7.01h-3L15 21l4-3.99h-3zM9 3L5 6.99h3V14h2V6.99h3L9 3z"/><path d="M0 0h24v24H0z" fill="none"/></svg>');
+}
+
+.icon-settings {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" enable-background="new 0 0 24 24" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><g><path d="M0,0h24v24H0V0z" fill="none"/><path d="M19.14,12.94c0.04-0.3,0.06-0.61,0.06-0.94c0-0.32-0.02-0.64-0.07-0.94l2.03-1.58c0.18-0.14,0.23-0.41,0.12-0.61 l-1.92-3.32c-0.12-0.22-0.37-0.29-0.59-0.22l-2.39,0.96c-0.5-0.38-1.03-0.7-1.62-0.94L14.4,2.81c-0.04-0.24-0.24-0.41-0.48-0.41 h-3.84c-0.24,0-0.43,0.17-0.47,0.41L9.25,5.35C8.66,5.59,8.12,5.92,7.63,6.29L5.24,5.33c-0.22-0.08-0.47,0-0.59,0.22L2.74,8.87 C2.62,9.08,2.66,9.34,2.86,9.48l2.03,1.58C4.84,11.36,4.8,11.69,4.8,12s0.02,0.64,0.07,0.94l-2.03,1.58 c-0.18,0.14-0.23,0.41-0.12,0.61l1.92,3.32c0.12,0.22,0.37,0.29,0.59,0.22l2.39-0.96c0.5,0.38,1.03,0.7,1.62,0.94l0.36,2.54 c0.05,0.24,0.24,0.41,0.48,0.41h3.84c0.24,0,0.44-0.17,0.47-0.41l0.36-2.54c0.59-0.24,1.13-0.56,1.62-0.94l2.39,0.96 c0.22,0.08,0.47,0,0.59-0.22l1.92-3.32c0.12-0.22,0.07-0.47-0.12-0.61L19.14,12.94z M12,15.6c-1.98,0-3.6-1.62-3.6-3.6 s1.62-3.6,3.6-3.6s3.6,1.62,3.6,3.6S13.98,15.6,12,15.6z"/></g></svg>');
+}
+
+.icon-walk-fast {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M13.49 5.48c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm-3.6 13.9l1-4.4 2.1 2v6h2v-7.5l-2.1-2 .6-3c1.3 1.5 3.3 2.5 5.5 2.5v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1l-5.2 2.2v4.7h2v-3.4l1.8-.7-1.6 8.1-4.9-1-.4 2 7 1.4z"/></svg>');
+}
+
+.icon-walk {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><path d="M13.5 5.5c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zM9.8 8.9L7 23h2.1l1.8-8 2.1 2v6h2v-7.5l-2.1-2 .6-3C14.8 12 16.8 13 19 13v-2c-1.9 0-3.5-1-4.3-2.4l-1-1.6c-.4-.6-1-1-1.7-1-.3 0-.5.1-.8.1L6 8.3V13h2V9.6l1.8-.7"/></svg>');
+}
+
+.icon-weelchair {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="black" width="18px" height="18px"><path d="M0 0h24v24H0z" fill="none"/><circle cx="12" cy="4" r="2"/><path d="M19 13v-2c-1.54.02-3.09-.75-4.07-1.83l-1.29-1.43c-.17-.19-.38-.34-.61-.45-.01 0-.01-.01-.02-.01H13c-.35-.2-.75-.3-1.19-.26C10.76 7.11 10 8.04 10 9.09V15c0 1.1.9 2 2 2h5v5h2v-5.5c0-1.1-.9-2-2-2h-3v-3.45c1.29 1.07 3.25 1.94 5 1.95zm-6.17 5c-.41 1.16-1.52 2-2.83 2-1.66 0-3-1.34-3-3 0-1.31.84-2.41 2-2.83V12.1c-2.28.46-4 2.48-4 4.9 0 2.76 2.24 5 5 5 2.42 0 4.44-1.72 4.9-4h-2.07z"/></svg>');
+}
+
+.icon-logo {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path style="fill: white;" d="M12 2c-4 0-8 .5-8 4v9.5C4 17.43 5.57 19 7.5 19L6 20.5v.5h2.23l2-2H14l2 2h2v-.5L16.5 19c1.93 0 3.5-1.57 3.5-3.5V6c0-3.5-3.58-4-8-4zM7.5 17c-.83 0-1.5-.67-1.5-1.5S6.67 14 7.5 14s1.5.67 1.5 1.5S8.33 17 7.5 17zm3.5-7H6V6h5v4zm2 0V6h5v4h-5zm3.5 7c-.83 0-1.5-.67-1.5-1.5s.67-1.5 1.5-1.5 1.5.67 1.5 1.5-.67 1.5-1.5 1.5z"/><path fill="none" d="M0 0h24v24H0V0z"/></svg>')
+}
+
+
+.icon-travelynx {
+	content: url('./img/travelynx.svg');
+}
+
+.selector label {
+	font-weight: bold;
+	font-size: 0;
+	display: flex;
+	justify-content: center;
+	align-items: center;
+}
+.selector label:after {
+	font-size: .9rem;
+	color: black;
+	text-align: center;
+	line-height: .9rem;
+}
+
+.selector label.icon-ice,
+.selector label.icon-ic,
+.selector label.icon-icice,
+.selector label.icon-dzug,
+.selector label.icon-regional {
+	font-style: italic;
+}
+
+.selector label.icon-tram:after,
+.selector label.icon-bus:after,
+.selector label.icon-ferry:after,
+.selector label.icon-taxi:after {
+	font-size: 0.6rem;
+}
+
+.icon-ice:after {
+	content: 'ICE';
+}
+
+.icon-ic:after {
+	content: 'IC';
+}
+
+.icon-icice:after {
+	content: 'IC ICE';
+}
+
+.icon-dzug:after {
+	content: 'D';
+}
+
+.icon-regional:after {
+	content: 'NV';
+}
+
+.icon-suburban:after {
+	content: 'S';
+}
+
+.icon-subway:after {
+	content: 'U';
+}
+
+.icon-tram:after {
+	content: 'Tram';
+}
+
+.icon-bus:after {
+	content: 'Bus';
+}
+
+.icon-ferry:after {
+	content: 'Ferry';
+}
+
+.icon-taxi:after {
+	content: 'Taxi';
+}
+
+#selected {
+	background-color: #bfbfbf !important;
+}
+
+#content {
+	display: flex;
+	flex-direction: column;
+	min-height: 100vh;
+
+}
+
+/* table */
+.icon-table {
+        content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M3 9h14V7H3v2zm0 4h14v-2H3v2zm0 4h14v-2H3v2zm16 0h2v-2h-2v2zm0-10v2h2V7h-2zm0 6h2v-2h-2v2z"/></svg>');
+	filter: invert();
+}
+/* canvas */
+.icon-canvas {
+	transform: rotate(90deg);
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24"><path d="M0 0h24v24H0z" fill="none"/><path d="M5 13h14v-2H5v2zm-2 4h14v-2H3v2zM7 7v2h14V7H7z"/></svg>');
+	filter: invert();
+}
+/*.icon-map {
+	content: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 0 24 24" width="24px" fill="#000000"><path d="M0 0h24v24H0z" fill="none"/><path d="M20.5 3l-.16.03L15 5.1 9 3 3.36 4.9c-.21.07-.36.25-.36.48V20.5c0 .28.22.5.5.5l.16-.03L9 18.9l6 2.1 5.64-1.9c.21-.07.36-.25.36-.48V3.5c0-.28-.22-.5-.5-.5zM15 19l-6-2.11V5l6 2.11V19z"/></svg>');
+	filter: invert();
+}*/
+
+.mode-changers {
+	display: flex;
+	margin-left: auto;
+}
+.mode-changers a.active {
+	border-bottom: 3px solid white;
+}
+.mode-changers a {
+	border-bottom: 3px solid transparent;
+	align-items: center;
+	display: flex;
+	padding: 0 1em;
+	cursor: pointer;
+}
+.mode-changers a span {
+	font-weight: bold;
+	margin: 1em .4em;
+}
+
+header h3 {
+	margin-right: 1.5em;
+}
+
+.train-details {
+	display: flex;
+	justify-content: center;
+}
+
+.journey thead>tr:nth-child(2) {
+	border-bottom: 2px solid #ccc;
+}
+
+.train-detail {
+	margin: .4em 2em;
+}
+
+#journeysMap {
+	flex-grow: 1;
+	display: flex;
+}
+.ol-viewport {
+	flex-grow: 1;
+	height: initial !important;
+}
+#searchView {
+	background-color: #222;
+	flex-grow: 1;
+}
diff --git a/client/resources/varela-regular-webfont.woff2 b/client/resources/varela-regular-webfont.woff2  Binary files differ.
diff --git a/client/rollup.config.js b/client/rollup.config.js
@@ -0,0 +1,31 @@
+import resolve from '@rollup/plugin-node-resolve';
+import cjs from '@rollup/plugin-commonjs';
+import {terser} from 'rollup-plugin-terser';
+
+const terserConfig = {
+	format: {
+		comments: false,
+	},
+};
+
+export default {
+	input: 'src/main.js',
+	output: [
+		{
+			dir: 'out/debug',
+			format: 'es',
+		},
+		{
+			dir: 'out',
+			format: 'es',
+			plugins: [
+				terser(terserConfig),
+			],
+		},
+	],
+	plugins: [
+		resolve(),
+		cjs(),
+	]
+};
+
diff --git a/client/src/api.js b/client/src/api.js
@@ -0,0 +1,49 @@
+
+
+import { showDiv, hideDiv } from './helpers.js';
+import { ConsoleLog } from './app_functions.js';
+import { showAlertModal, showLoader, hideOverlay } from './overlays.js';
+
+const api_base = 'http://127.0.0.1:1234/';
+
+export const request = async (endpoint, params, method, noLoader) => {
+	if (!noLoader) showLoader();
+	let data;
+	const urlparams = [];
+	const addParams = (thing, prefix) => {
+		if (typeof thing === "object") {
+			for (let [key, val] of Object.entries(thing))
+				addParams(val, prefix.concat([encodeURIComponent(key)]));
+		} else {
+			urlparams.push(`${prefix.join(".")}=${encodeURIComponent(thing)}`);
+		}
+	};
+	addParams(params, []);
+
+	const url = `${api_base}${endpoint}?${urlparams.join("&")}`;
+	try {
+		data = await fetch(url, {method})
+			.then(resp => resp.json());
+	} catch(e) {
+		data = {
+			error: true,
+			msg: "Failed to fetch. Please check your network connection.",
+		};
+	}
+	if (!noLoader) hideOverlay();
+
+	if (data.error) {
+		showAlertModal(data.msg);
+		throw new Error(data.msg);
+	} else {
+		return data;
+	}
+};
+
+export const get = (endpoint, params, noLoader) => {
+	return request(endpoint, params, "GET", noLoader);
+};
+
+export const post = async (endpoint, params, noLoader) => {
+	return request(endpoint, params, "POST", noLoader);
+};
diff --git a/client/src/app_functions.js b/client/src/app_functions.js
@@ -0,0 +1,139 @@
+import { dbReady, getSettings, addHistoryEntry, getJourneysHistory } from './dataStorage.js';
+import { get } from './api.js';
+import { showModal } from './overlays.js';
+import { languages } from './languages.js';
+import { html } from 'lit-html';
+import { formatDateTime, getFrom, getTo } from './helpers.js';
+
+let ds100 = {};
+// we don't want to pass these around all the time
+let settings;
+
+export const applySettings = async newSettings => {
+	settings = newSettings;
+	if (settings.showRIL100Names) await loadDS100();
+};
+
+export const addJourneys = async data => {
+	if (!data) return false;
+
+	const db = await dbReady;
+	await db.put('journeys', data);
+
+	//const lastHistoryEntry = (await getJourneysHistory()).slice(-1);
+	//if (lastHistoryEntry[0]
+	//	&& JSON.stringify(lastHistoryEntry[0].fromPoint) === JSON.stringify(getFrom(data.journeys))
+	//	&& JSON.stringify(lastHistoryEntry[0].toPoint) === JSON.stringify(getTo(data.journeys))) {
+	//	dataStorage.journeysHistory[dataStorage.journeysHistory.length-1].slug = data.slug;										
+	//	dataStorage.journeysHistory[dataStorage.journeysHistory.length-1].journeyId = '';
+	//} else {
+		await addHistoryEntry({
+			fromPoint: getFrom(data.journeys),
+			//viaPoint: data.params.via,
+			toPoint: getTo(data.journeys),
+			slug: data.slug,
+			journeyId: ''
+		});
+	//}
+};
+
+export const getJourneys = async slug => {
+	if (!slug) return;
+
+	const db = await dbReady;
+	let data = await db.get('journeys', slug);
+	if (!data) {
+		data = await get("savedJourneys/" + slug, {
+			stopovers: true,
+			polylines: settings.showMap || false,
+			tickets: settings.showPrices || false,
+		});
+		await addJourneys(data);
+	}
+
+	for (let journey of data.journeys) {
+		for (let leg of journey.legs) {
+			if (leg.plannedDeparture) leg.plannedDeparture = new Date(leg.plannedDeparture);
+			if (leg.plannedArrival) leg.plannedArrival = new Date(leg.plannedArrival);
+			if (leg.departure) leg.departure = new Date(leg.departure);
+			if (leg.arrival) leg.arrival = new Date(leg.arrival);
+			for (let stopover of (leg.stopovers || [])) {
+				if (stopover.plannedDeparture) stopover.plannedDeparture = new Date(stopover.plannedDeparture);
+				if (stopover.plannedArrival) stopover.plannedArrival = new Date(stopover.plannedArrival);
+				if (stopover.departure) stopover.departure = new Date(stopover.departure);
+				if (stopover.arrival) stopover.arrival = new Date(stopover.arrival);
+			}
+		}
+	}
+	return data;
+};
+
+export const refreshJourneys = async (reqId, hideLoader) => {
+	const data = await get("savedJourneys/"+reqId, {
+		stopovers: true,
+		polylines: settings.showMap || false,
+		tickets: settings.showPrices || false,
+	}, hideLoader);
+	await addJourneys(data);
+	return data;
+};
+
+export const t = (key, ...params) => {
+	let translation = languages[settings.language][key];
+	if (!translation) return key;
+
+	while (params.length >= 1)
+		translation = translation.replace("{}", params.shift());
+
+	return translation;
+}
+
+export const parseName = (point) => {
+	let nameHTML = '';
+
+	if (point.type == "stop") {
+		nameHTML += point.name+ds100Names(point.id);
+	} else if (point.type == "location") {
+		if (point.name) {
+			nameHTML += point.name;
+		} else if (point.address) {
+			nameHTML += point.address;
+		}
+	} else {
+		return "";
+	}
+
+	return nameHTML;
+};
+
+export const ds100Names = (id) => {
+	if (!settings.showRIL100Names) return '';
+	if (!ds100[Number(id)]) return '';
+	return '('+ds100[Number(id)]+')';
+}
+
+export const ConsoleLog  = (data) => {
+	if (settings.writeDebugLog) {
+		console.log(data);
+	}
+};
+
+export const loadDS100 = async () => {
+	const module = await import('./ds100.js');
+	ds100 = module.ds100;
+};
+
+export const timeTemplate = (data, mode) => {
+	let delay = 0;
+
+	if (!data[mode]) return "-";
+
+	return html`
+		${data[mode+"Delay"] > 0 ? html`
+			${formatDateTime(data[mode])} <b>(+${Math.round(data[mode+"Delay"] / 60)})</b>
+		` : html`
+			${formatDateTime(data[mode])}
+		`}
+	`;
+};
+
diff --git a/client/src/canvas.js b/client/src/canvas.js
@@ -0,0 +1,336 @@
+import { moreJourneys } from './journeysView.js';
+import { go } from './router.js';
+
+const padZeroes = (str) => ('00' + str).slice(-2);
+
+const formatTime = (date) => {
+	return `${padZeroes(date.getHours())}:${padZeroes(date.getMinutes())}`
+};
+
+const textFor = (leg) => leg.line && leg.line.name || "";
+const typeTextFor = (leg) => {
+	let res = "(" + leg.line.trainType + ")";
+	while (res.length < 12) {
+		res = " " + res + " ";
+	}
+	return res;
+};
+const colorFor = (leg, type) => {
+	let product = leg.line && leg.line.product || "walk";
+	return colors[type][product] || colors[type].default;
+};
+
+const flatten = (arr) => [].concat(...arr);
+
+const colors = {
+	fill: {
+		'tram': '#cc5555',
+		'subway': '#5555cc',
+		'suburban': '#55aa55',
+		'nationalExpress': '#fff',
+		'national': '#fff',
+		'regionalExpress': '#888',
+		'regional': '#888',
+		'bus': '#aa55aa',
+		default: '#888'
+	},
+	text: {
+		'nationalExpress': '#ee3333',
+		'national': '#ee3333',
+		default: '#fff'
+	},
+	icon: {
+		'walk': 'directions_walk',
+		'transfer': 'directions_transfer',
+		'subway': 'directions_subway',
+		'bus': 'directions_bus',
+		'tram': 'tram',
+		default: 'train'
+	}
+};
+
+let rectWidth, padding, rectWidthWithPadding, canvas, ctx;
+let dpr = window.devicePixelRatio || 1;
+
+const canvasState = {
+	journeys: [],
+	offsetX: 0,
+};
+
+const textCache = {};
+let textCacheWidth;
+let textCacheDpr;
+
+export const setupCanvas = (data, isUpdate) => {
+	if (!isUpdate) canvasState.offsetX = (window.innerWidth / dpr) > 600 ? 140 : 80;
+	canvas = document.getElementById('canvas');
+	ctx = canvas.getContext('2d');
+	canvasState.indexOffset = data.indexOffset;
+	canvasState.journeys = Object.keys(data.journeys).sort((a, b) => Number(a) - Number(b)).map(k => data.journeys[k]);
+	canvasState.slug = data.slug;
+
+	canvas.addEventListener('mousedown', mouseDownHandler, {passive: true});
+	canvas.addEventListener('touchstart', mouseDownHandler, {passive: true});
+	updateTextCache();
+	resizeHandler();
+};
+
+const addTextToCache = (text, color, fixedHeight) => {
+	const canvas = document.createElement('canvas');
+	const ctx = canvas.getContext('2d');
+	ctx.shadowColor = '#00000080';
+
+	let height, width
+	if (fixedHeight) {
+		height = 15;
+		ctx.font = `${height}px sans-serif`;
+		width = ctx.measureText(text).width;
+	} else {
+		const measureAccuracy = 50;
+		ctx.font = `${measureAccuracy}px sans-serif`;
+		width = rectWidth - 10;
+		height = Math.abs(measureAccuracy * (width / (1 - ctx.measureText(text).width)));
+	}
+
+	canvas.width = width * dpr;
+	canvas.height = Math.ceil(height * 1.5) * dpr;
+	ctx.scale(dpr, dpr);
+
+	ctx.font = `${height}px sans-serif`;
+	ctx.fillStyle = color;
+	if (height > 10) {
+		ctx.fillText(text, 0, height);
+		textCache[text] = canvas;
+	}
+};
+
+const updateTextCache = () => {
+	textCache.length = 0;
+	textCacheWidth = rectWidth;
+	textCacheDpr = dpr;
+	for (let journey of canvasState.journeys) {
+		for (let leg of journey.legs) {
+			addTextToCache(textFor(leg), colorFor(leg, "text"));
+			if (leg.line && leg.line.trainType) addTextToCache(typeTextFor(leg), "#555");
+
+			let times = [];
+
+			if (journey.legs.indexOf(leg) == journey.legs.length - 1) times.push(leg.arrival);
+			if (journey.legs.indexOf(leg) == 0) times.push(leg.departure);
+			for (let time of times) {
+				addTextToCache(formatTime(time), "#fff", 15);
+			}
+		}
+	}
+};
+
+const renderJourneys = () => {
+	ctx.clearRect(0, 0, canvas.width / dpr, canvas.height / dpr);
+	let x = canvasState.offsetX - canvasState.indexOffset * rectWidthWithPadding, y;
+
+	let firstVisibleJourney = Math.max(0, Math.floor((-x + padding) / rectWidthWithPadding));
+	let numVisibleJourneys = Math.ceil(canvas.width / dpr / rectWidthWithPadding);
+	let visibleJourneys = canvasState.journeys.slice(firstVisibleJourney, firstVisibleJourney + numVisibleJourneys);
+
+	if (!visibleJourneys.length) return;
+
+	let firstDeparture = visibleJourneys[0].legs[0].plannedDeparture;
+	let lastArrival = Math.max.apply(Math,
+		visibleJourneys.map(journey => journey.legs[journey.legs.length-1].plannedArrival)
+		.concat(visibleJourneys.map(journey => journey.legs[journey.legs.length-1].arrival)
+	));
+
+	let scaleFactor = 1/(lastArrival - firstDeparture) * (canvas.height - 64 * dpr) / dpr;
+
+	let time = canvasState.journeys[0].legs[0].plannedDeparture;
+
+	ctx.font = `${(window.innerWidth / dpr) > 600 ? 20 : 15}px sans-serif`;
+	ctx.fillStyle = '#aaa';
+	while (time < lastArrival) {
+		let y = (time - firstDeparture) * scaleFactor + 32;
+		ctx.fillText(formatTime(time), (window.innerWidth / dpr) > 600 ? 30 : 10, y);
+		ctx.fillRect(0, y, canvas.width / dpr, 1);
+		time = new Date(Number(time) + Math.floor(120/scaleFactor));
+	}
+	ctx.fillStyle = '#fa5';
+	y = (new Date() / 1000 - firstDeparture) * scaleFactor + 32;
+	ctx.fillRect(0, y-2, canvas.width / dpr, 5);
+
+	const p = new Path2D('M16.59 8.59L12 13.17 7.41 8.59 6 10l6 6 6-6z');
+	ctx.fillStyle = '#fff';
+	ctx.shadowColor = '#00000080';
+	ctx.save();
+	ctx.scale(3, 3);
+	ctx.translate(x / 3 - 15, canvas.height / dpr / 6 - 24);
+	ctx.rotate(-Math.PI*1.5);
+	ctx.fill(p);
+	ctx.restore();
+	ctx.beginPath();
+	ctx.arc(x - 80,canvas.height / dpr / 2 - 35,50,0,2*Math.PI);
+	ctx.fillStyle = '#ffffff40';
+	ctx.fill();
+	ctx.strokeStyle = '#00000020';
+	ctx.stroke();
+
+	for (let journey of canvasState.journeys) {
+		journey.legs.reverse();
+		for (let leg of journey.legs) {
+			if (Math.abs(leg.departureDelay) > 60 || Math.abs(leg.arrivalDelay) > 60) {
+				const duration = (leg.plannedArrival - leg.plannedDeparture) * scaleFactor;
+
+				y = (leg.plannedDeparture - firstDeparture) * scaleFactor + 32;
+
+				ctx.fillStyle = '#44444480';
+				ctx.strokeStyle = '#ffffff80';
+				ctx.fillRect(x-padding, y, rectWidth, duration);
+				ctx.strokeRect(x-padding, y, rectWidth, duration);
+			}
+		}
+		x += rectWidthWithPadding;
+	}
+
+	x = canvasState.offsetX - canvasState.indexOffset * rectWidthWithPadding;
+
+	for (let journey of canvasState.journeys) {
+		for (let leg of journey.legs) {
+			const duration = (leg.arrival - leg.departure) * scaleFactor;
+
+			y = (leg.departure - firstDeparture) * scaleFactor + 32;
+
+			ctx.shadowColor = '#00000060';
+			ctx.shadowBlur = 5;
+
+			if (leg.walking || leg.transfer) {
+				ctx.fillStyle = '#777';
+				ctx.fillRect(x + rectWidth / 2 - rectWidth / 10, y, rectWidth / 5, duration);
+			} else {
+				ctx.fillStyle = colorFor(leg, "fill");
+				ctx.fillRect(x, y, rectWidth, duration);
+			}
+			ctx.shadowBlur = 0;
+
+			let preRenderedText = textCache[textFor(leg)];
+			if ((preRenderedText.height / dpr) < duration - 5) {
+				ctx.scale(1 / dpr, 1 / dpr);
+				ctx.drawImage(preRenderedText, dpr * (x + 5), Math.floor(dpr * (y + duration / 2) - preRenderedText.height / 2.3));
+				ctx.scale(dpr, dpr);
+			}
+			if (leg.line && leg.line.trainType) {
+				let preRenderedTypeText = textCache[typeTextFor(leg)];
+				if ((preRenderedTypeText.height / dpr + preRenderedText.height / dpr) < duration - 5) {
+					ctx.scale(1 / dpr, 1 / dpr);
+					ctx.drawImage(preRenderedTypeText, dpr * (x + 5), Math.floor(dpr * (y + duration / 2 + preRenderedText.height / 2 + 10) - preRenderedTypeText.height / 2.3));
+					ctx.scale(dpr, dpr);
+				}
+			}
+
+			if (leg.cancelled) {
+				ctx.strokeStyle = '#cc4444ff';
+				ctx.lineWidth = 5;
+				ctx.beginPath();
+				ctx.moveTo(x, y);
+				ctx.lineTo(x + rectWidth, y + duration);
+				ctx.stroke();
+				ctx.lineWidth = 1;
+			}
+
+			/* draw journey start and end time */
+			let time;
+			// note: leg order is reversed at this point in time
+			let times = [];
+			if (journey.legs.indexOf(leg) == journey.legs.length - 1) times.push([leg.departure, y - 9.5]);
+			if (journey.legs.indexOf(leg) == 0) times.push([leg.arrival, y + duration + 7.5]);
+			for (let [time, y] of times) {
+				preRenderedText = textCache[formatTime(time)];
+				ctx.scale(1 / dpr, 1 / dpr);
+				ctx.drawImage(preRenderedText, Math.ceil(dpr * (x + ((rectWidth - preRenderedText.width/dpr)) / 2)), dpr * (y - 7.5));
+				ctx.scale(dpr, dpr);
+			}
+		}
+
+		journey.legs.reverse();
+
+		x += rectWidthWithPadding;
+	}
+	ctx.fillStyle = '#fff';
+	ctx.shadowColor = '#00000080';
+	ctx.save();
+	ctx.scale(3, 3);
+	ctx.translate(x / 3 + 5, canvas.height / dpr / 6);
+	ctx.rotate(Math.PI*1.5);
+	ctx.fill(p);
+	ctx.restore();
+	ctx.beginPath();
+	ctx.arc(x + 50,canvas.height / dpr / 2 - 35,50,0,2*Math.PI);
+	ctx.fillStyle = '#ffffff40';
+	ctx.fill();
+	ctx.strokeStyle = '#00000020';
+	ctx.stroke();
+};
+
+const resizeHandler = () => {
+	dpr = window.devicePixelRatio || 1;
+	if (!document.getElementById('canvas')) return;
+
+	rectWidth = (window.innerWidth / dpr) > 600 ? 100 : 80;
+	padding = (window.innerWidth / dpr) > 600 ? 20 : 5;
+	rectWidthWithPadding = rectWidth + 2 * padding;
+
+	if (rectWidth !== textCacheWidth || dpr !== textCacheDpr) updateTextCache();
+
+	const rect = document.getElementById('header').getBoundingClientRect();
+	canvas.width = window.innerWidth * dpr;
+	canvas.height = (window.innerHeight - rect.height) * dpr;
+	canvas.style.width = `${window.innerWidth}px`;
+	canvas.style.height = `${window.innerHeight - rect.height - 4}px`;
+
+	ctx.restore();
+	ctx.save();
+	ctx.scale(dpr, dpr);
+
+	renderJourneys();
+};
+
+const mouseUpHandler = (evt) => {
+	let x = evt.x || evt.changedTouches[0].pageX;
+	if (canvasState.dragging && canvasState.isClick) {
+		let num = Math.floor((x - canvasState.offsetX + 2 * padding) / rectWidthWithPadding);
+		if (num >= 0) {
+			if (num < canvasState.journeys.length) {
+				go(`/${canvasState.slug}/${num - canvasState.indexOffset}`);
+			} else {
+				moreJourneys(canvasState.slug, "later");
+			}
+		} else {
+			moreJourneys(canvasState.slug, "earlier");
+		}
+	}
+
+	canvasState.dragging = false;
+};
+
+const mouseDownHandler = (evt) => {
+	let x = evt.x || evt.changedTouches[0].pageX;
+	canvasState.dragStartMouse = x;
+	canvasState.dragStartOffset = canvasState.offsetX;
+	canvasState.dragging = true;
+	canvasState.isClick = true;
+};
+
+const mouseMoveHandler = (evt) => {
+	if (canvasState.dragging) {
+		evt.preventDefault();
+		let x = evt.x || evt.changedTouches[0].pageX;
+		canvasState.offsetX = canvasState.dragStartOffset - (canvasState.dragStartMouse - x);
+		if (Math.abs(canvasState.dragStartMouse - x) < 20) canvasState.isClick = false;
+		renderJourneys();
+		return true;
+	}
+};
+
+window.addEventListener('mouseup', mouseUpHandler);
+window.addEventListener('touchend', mouseUpHandler);
+window.addEventListener('mousemove', mouseMoveHandler);
+window.addEventListener('touchmove', mouseMoveHandler);
+window.addEventListener('resize', resizeHandler);
+window.addEventListener('zoom', resizeHandler);
diff --git a/client/src/dataStorage.js b/client/src/dataStorage.js
@@ -0,0 +1,84 @@
+import { openDB, deleteDB } from 'idb';
+
+export const devMode = false;
+const dbName = devMode ? 'trainsearch_dev' : 'trainsearch';
+
+const getDefaultLanguage = () => {
+	const userLang = navigator.language || navigator.userLanguage;
+	if (['en', 'de'].includes(userLang)) return userLang;
+	return 'en';
+};
+
+const defaultSettings = {
+	provider: 'DB',
+	products: {
+		"nationalExpress": true,
+		"national": true,
+		"regionalExp": true,
+		"regional": true,
+		"suburban": true,
+		"bus": true,
+		"ferry": true,
+		"subway": true,
+		"tram": true,
+		"taxi": true
+	},
+	accessibility: 'none',
+	advancedSelection: false,
+	showRIL100Names: false,
+	writeDebugLog: false,
+	language: getDefaultLanguage(),
+	travelynx: false,
+	journeysViewMode: 'canvas',
+	showMap: false,
+	showPrices: false,
+};
+
+export const dbReady = openDB(dbName, 1, {
+	upgrade: (db, oldVersion, newVersion, transaction) => {
+		console.log(`upgrading database from ${oldVersion} to ${newVersion}`);
+		switch (oldVersion) {
+			case 0:
+				if (!db.objectStoreNames.contains('journeys'))
+					db.createObjectStore('journeys', {keyPath: 'slug'});
+				if (!db.objectStoreNames.contains('journeysHistory'))
+					db.createObjectStore('journeysHistory', {autoIncrement: true});
+				if (!db.objectStoreNames.contains('settings'))
+					db.createObjectStore('settings');
+			case 1:
+				//... add migrations for 1->2 here
+		}
+	},
+	blocking: async () => {
+		const db = await dbReady;
+		db.close();
+		location.reload();
+	},
+});
+
+export const getSettings = async () => {
+	const db = await dbReady;
+	return (await db.get('settings', 'settings')) || defaultSettings;
+};
+
+export const setSettings = async newSettings => {
+	const db = await dbReady;
+	await db.put('settings', newSettings, 'settings');
+};
+
+export const modifySettings = async callback => {
+	const db = await dbReady;
+	const tx = db.transaction('settings', 'readwrite');
+	const settings = (await tx.store.get('settings')) || defaultSettings;
+	const newSettings = callback(settings);
+	await tx.store.put(newSettings, 'settings');
+	await tx.done;
+};
+
+export const getJourneysHistory = () => dbReady.then(db => db.getAll('journeysHistory'));
+
+export const addHistoryEntry = newEntry => dbReady.then(db => db.put('journeysHistory', newEntry));
+
+export const clearDataStorage = () => {
+	deleteDB(dbName);
+};
diff --git a/client/src/ds100.js b/client/src/ds100.js
@@ -0,0 +1 @@
+export const ds100 = {"8000001":"KA","8000002":"TA","8000004":"HA","8000007":"FALZ","8000009":"NAN","8000010":"NAH","8000011":"AAG","8000012":"KAU","8000013":"MA","8000014":"TAU","8000015":"FBA","8000016":"TB","8000017":"TBF","8000019":"HBHA","8000020":"FBHF","8000021":"SBKN","8000022":"HNDF","8000023":"AO","8000025":"NBA","8000027":"NSCH","8000028":"NBY","8000029":"FB","8000030":"KBE","8000031":"FBH","8000032":"NS","8000033":"KSWE","8000034":"EBZ","8000036":"EBIL, EBILP","8000037":"ESRT","8000038":"TBM","8000039":"FBGK","8000040":"EBCH","8000041":"EBO","8000042":"RSE","8000043":"HSSN","8000044":"KB","8000045":"KBOP","8000046":"ESIE","8000047":"EBTH, EBTHP","8000048":"EBWE","8000049":"HBS","8000050":"HB","8000051":"HBH","8000053":"RBT","8000054":"EBRW","8000055":"RBR","8000056":"ABLZ","8000057":"MBU","8000058":"ABCH","8000059":"HBDE","8000060":"KSIH","8000061":"FBNG","8000062":"EBFT","8000063":"TCW","8000064":"HC","8000065":"FCOE","8000066":"ECMF","8000067":"TC","8000068":"FD","8000069":"TSIG","8000070":"HD","8000071":"HDBG","8000073":"RSI","8000074":"FDIL","8000075":"SDL","8000076":"ESOT","8000077":"RDO","8000078":"MDT","8000080":"EDO","8000081":"EDDP, EDDPH, EDDPT","8000082":"KDF, KDFF, KDFFH","8000083":"EDUL, EDULH","8000084":"KDN, KDN P","8000085":"KD","8000086":"EDG","8000087":"KSO","8000088":"HSO","8000089":"AST","8000090":"HEBG","8000091":"NSTN","8000092":"AEL","8000093":"HELZ","8000094":"KENR","8000095":"NST","8000098":"EE","8000099":"EEST","8000100":"KEU","8000101":"TET","8000102":"EFP","8000103":"AF","8000105":"FF, FFT","8000106":"FHOE","8000107":"RF","8000108":"MFL","8000110":"TFS","8000111":"FFG","8000112":"TF","8000113":"EFOE","8000114":"NF","8000115":"FFU","8000116":"MTS","8000117":"FGEL","8000118":"EG","8000119":"MGE","8000120":"NGM","8000121":"FGHO","8000122":"MTL","8000123":"SGR","8000124":"FG","8000125":"EGBW","8000126":"FGE","8000127":"TGO","8000128":"HG","8000129":"FTS","8000130":"HGS","8000131":"RGN","8000133":"KGRB","8000134":"STR","8000135":"KT","8000136":"FGER","8000137":"RGR","8000138":"KGUA, KGUI","8000139":"MGZB","8000140":"FGTH","8000141":"TT","8000142":"EHG","8000143":"RWGA","8000144":"MTHB","8000145":"EHLT","8000146":"RWPF","8000147":"AHAR, AHRS","8000148":"HHM","8000149":"EHM","8000150":"FH, FH  N, FH  S","8000152":"HH","8000154":"STM","8000155":"AHI","8000156":"RH","8000157":"TH","8000158":"FHWD, FHWR","8000159":"HHLM","8000160":"THT","8000161":"FHRB","8000162":"EHFD","8000163":"TTU","8000164":"EHER","8000165":"EHDT","8000166":"HHB","8000167":"HHES","8000168":"HU","8000169":"HHI","8000170":"TU","8000171":"EUN","8000172":"FHT","8000173":"NHOB","8000174":"KV","8000175":"SVL","8000176":"SHO","8000177":"THB","8000178":"KHR","8000180":"TWN","8000181":"AHM","8000182":"RIM","8000183":"MIH","8000185":"HGI","8000186":"EIL","8000189":"SKL","8000190":"KKAK","8000191":"RK","8000192":"EWAN","8000193":"FK","8000194":"MKFB","8000195":"MKFG","8000196":"HWAR","8000197":"MKP","8000198":"EKG","8000199":"AK","8000201":"NKL","8000203":"TKG","8000204":"NWDO","8000205":"KKLV","8000206":"KKO","8000207":"KK","8000208":"KKER, KKERP","8000209":"KKM","8000211":"KKR","8000212":"KKRO","8000213":"HK","8000214":"EKT","8000215":"ELAG","8000216":"RLA","8000217":"MLA","8000218":"FWG","8000220":"MWH","8000221":"TL","8000222":"FLAU","8000225":"HLEE","8000226":"HLER, HLERA","8000227":"ELE","8000228":"NLF","8000229":"FL","8000230":"MLI","8000233":"HL","8000234":"FLOL","8000235":"TLU","8000236":"RL, RL  T","8000237":"AL","8000238":"ALBG, ALBGW","8000239":"ELUE","8000240":"FMZ","8000241":"FMB, FMB P","8000242":"EWES","8000243":"FMFH","8000244":"RM","8000245":"FWBG","8000247":"NMR","8000248":"KMYO","8000249":"MM","8000250":"FW","8000251":"EWIT","8000252":"HM","8000253":"KM","8000254":"RWRT","8000255":"HWOH, HWOL","8000256":"MRBI","8000257":"FWOR","8000259":"EMLR","8000260":"NWH","8000261":"MH, MH  N, MH  S, MHT","8000262":"MOP","8000263":"EMST, EMSTP","8000264":"RNZ","8000265":"RNM","8000266":"KW","8000267":"NNE","8000268":"HWUN","8000269":"NNS","8000271":"AN","8000272":"SNK","8000273":"DMBH","8000274":"KN, KN  O, KN  W","8000275":"RN","8000276":"KNE","8000277":"FND","8000278":"KNL","8000279":"HNBG","8000280":"MNL","8000282":"HNOS","8000283":"HN","8000284":"NN","8000285":"FORD","8000286":"EOB","8000287":"NOKP","8000288":"FWB","8000290":"RO","8000291":"HOLD","8000294":"HO, HO  O, HO  U","8000295":"TO","8000297":"EPD","8000298":"NPA","8000299":"TPH","8000301":"NPL","8000302":"TP","8000304":"HQ","8000306":"RRA","8000307":"ERE","8000309":"NRH","8000310":"KRE","8000311":"KRL","8000312":"AR","8000313":"TRX","8000314":"TRE","8000315":"ERDW","8000316":"HR","8000317":"KRH","8000318":"KRY, KRY P","8000319":"SRO","8000320":"MRO","8000321":"AROG","8000322":"TR","8000323":"SSH","8000324":"KBPS","8000325":"HSRI","8000326":"RSD","8000328":"NSAW","8000329":"TSG","8000330":"TSHT","8000331":"KAND","8000332":"RFT","8000333":"RHA","8000334":"AJ","8000335":"HLST","8000336":"TLK","8000337":"FMBG","8000338":"MMH","8000339":"TM","8000342":"HWEZ","8000343":"DSCF","8000344":"HWTT","8000346":"EBK","8000347":"FSTM","8000348":"KST, KST P","8000349":"FO","8000350":"FAFD","8000351":"KAK","8000352":"HBGM","8000353":"TBG","8000354":"HBAS","8000355":"KBEE","8000356":"RVLE","8000357":"SBI","8000358":"EBLA, EBP","8000359":"FBOD","8000360":"FBUE","8000362":"FDI","8000363":"KDI","8000364":"HVBG","8000365":"NDB","8000366":"RVL","8000367":"EDME","8000368":"FWAB","8000369":"REA","8000370":"SEG","8000371":"SEI","8000372":"SENK","8000374":"RFHM","8000375":"FGAL","8000376":"RGE","8000377":"RWE","8000378":"SWR, SWRR","8000379":"SWIH","8000380":"TGL","8000382":"EGRN","8000383":"FWR","8000384":"FWH","8000385":"NGUN","8000386":"FHG","8000387":"MHGZ","8000388":"KHI","8000389":"THF","8000390":"KHOK","8000391":"HHZM","8000392":"EHZW","8000393":"RVLH","8000400":"FHUG","8000402":"SKU","8000404":"KAW, KAW P","8000406":"KARE, KAREP","8000409":"KKEM","8000410":"MABG","8000412":"RAH","8000413":"HACH","8000414":"HAMR","8000416":"AACW","8000418":"HADB","8000419":"MAD","8000420":"NADM","8000423":"RADN","8000424":"TAD","8000427":"EKIR","8000431":"TAF","8000433":"MAGD","8000434":"AABG","8000435":"FKIH","8000436":"RA","8000437":"EAHS","8000440":"HSCG","8000441":"EAHL, EAHLH","8000442":"HAHO","8000443":"HALT","8000445":"HSDK","8000446":"AAHR","8000448":"KAH","8000449":"KAHM","8000452":"MAI","8000453":"RFMU","8000454":"TAI","8000456":"TTUN","8000459":"MAIN","8000462":"EABT","8000463":"RAL","8000464":"AAL","8000466":"RAR","8000468":"FAG","8000471":"FALS","8000473":"TAE","8000474":"TALO","8000475":"TALT","8000477":"KALK","8000479":"NKN","8000480":"AAHG","8000481":"TALD","8000482":"MALH","8000483":"HALF","8000488":"HALG","8000489":"HALI","8000491":"SALG","8000492":"FADD","8000495":"KALI","8000496":"RAB","8000498":"NALB","8000499":"TALL","8000500":"KALP","8000501":"RALP","8000503":"FBL","8000504":"NADW","8000505":"SAZ","8000506":"FAHM","8000508":"TACH","8000509":"NAD","8000511":"NAVE","8000512":"AAW","8000513":"EALN","8000514":"KALT","8000515":"MALT","8000517":"SAB","8000518":"EABG","8000520":"FABL","8000522":"HHUD","8000524":"MANE","8000525":"FATF","8000526":"AAT","8000532":"EA","8000534":"NMS","8000537":"EASE","8000538":"FAST","8000539":"MASI","8000540":"NALW","8000544":"RAT","8000545":"MAHB","8000546":"FAT","8000547":"SLKG","8000553":"FAMO","8000556":"MAMT","8000558":"FAZS","8000559":"TAT","8000561":"MATS","8000562":"TATN","8000563":"SLCH","8000566":"NAM","8000569":"EAML","8000571":"ELPP","8000576":"MAPF","8000577":"TAM, TAM S","8000578":"HAMI","8000579":"KANM","8000580":"FANG","8000582":"RAN","8000584":"KANR","8000585":"SLN","8000586":"HLGW","8000588":"NAWN","8000589":"FAZ","8000595":"EAPH","8000596":"RAP, RAPP","8000597":"EARE","8000599":"FAF","8000601":"KARL","8000602":"FARM","8000603":"MANB","8000605":"EARB","8000606":"NARG","8000611":"KARS","8000613":"NAZ","8000615":"FMK","8000618":"NAHF","8000619":"NASU","8000621":"MASC","8000623":"EASB","8000624":"HASD","8000625":"RASH","8000627":"AASN","8000630":"TAX","8000631":"RMF","8000632":"FAS","8000633":"FAL","8000634":"MAG","8000635":"FAH","8000638":"EAT","8000644":"KMO","8000647":"EAWN","8000649":"RACH","8000651":"SAM","8000653":"MAFE","8000655":"TAUF","8000657":"RAUG","8000658":"MAHA","8000659":"MAGM","8000660":"MAMS","8000661":"MAHZ, MAHZF, MAHZH","8000662":"MAOB","8000663":"FMSH","8000664":"HAUG","8000667":"FMT, FMTN","8000668":"FAUM","8000669":"AAH, AAMS","8000671":"FAM","8000672":"NAUR","8000674":"SAUW","8000675":"MAY","8000677":"KBA","8000678":"MBAE","8000681":"RBST","8000683":"FBCH","8000685":"MBCN","8000686":"RBH","8000687":"EMRY","8000688":"MNFR","8000689":"NBAB","8000690":"MBAI","8000691":"RBZB","8000694":"KBRE","8000696":"MBAK","8000697":"HBDG","8000698":"RBDH","8000701":"FEMS","8000702":"FEMW","8000704":"TBK","8000706":"TBWT","8000707":"RBGR","8000708":"RBDT","8000711":"KHGB","8000712":"FHO","8000713":"KHBD","8000714":"NBKI","8000715":"FKI","8000716":"MBKG","8000717":"MBKK","8000718":"RBKR","8000721":"TBLI","8000725":"HMDD","8000726":"SBMS","8000727":"KMUE","8000728":"FBNA","8000729":"KNEB","8000730":"NBNE","8000731":"TBN","8000732":"HOY","8000733":"HBOE","8000734":"RBPL","8000735":"HPRT","8000736":"RBRA","8000737":"MBRL","8000738":"MBRK","8000739":"HSCH","8000740":"HBSA","8000741":"FBSH","8000742":"KSAL","8000743":"FSF","8000744":"EBSU","8000745":"EBSA","8000746":"TBSC","8000749":"ASCH","8000750":"TBSB","8000751":"ASB","8000752":"FBSO","8000753":"FBSD","8000754":"APSD","8000755":"APO","8000756":"NBST","8000757":"TBT","8000758":"MBT","8000759":"HBSK","8000760":"FVL","8000761":"FVLS","8000763":"TBWA","8000765":"RBWF","8000766":"RBWH","8000767":"NBWI","8000768":"MBWH","8000770":"HZWI","8000771":"RHEB","8000772":"HBAD","8000773":"HBDV","8000774":"RBB","8000775":"RBBL","8000777":"RBPK","8000778":"MBHM","8000779":"AALH","8000780":"ABAF","8000781":"MBAB","8000783":"NBD","8000784":"NBAF","8000785":"MBDH","8000786":"FBAD","8000787":"TBLH","8000788":"TBGS","8000792":"SBAL","8000793":"EBAV","8000794":"RBAM","8000796":"HBAN","8000797":"HBTF","8000800":"HNN","8000801":"ABAD, ABAW","8000802":"RBRT","8000804":"ABAE","8000805":"ABAP","8000807":"HBNF","8000808":"HBNT","8000810":"HBAR","8000812":"HBGH","8000815":"AHEM","8000818":"NOF","8000821":"RBZE","8000822":"NBH","8000826":"NBAU","8000827":"ABF","8000830":"NBEI","8000831":"MBGM","8000832":"KBAY","8000834":"MBZ","8000840":"SBE","8000842":"KBH","8000846":"EBEE","8000850":"NBEH","8000851":"FBEI","8000853":"KOPL, KOPLM","8000858":"TBS","8000859":"FBEF","8000860":"ABE","8000861":"RBLN","8000862":"MBNB","8000863":"RBLH","8000864":"RBEL","8000865":"TBEM","8000869":"MBEN","8000870":"SBG","8000871":"HBML","8000872":"HBEN","8000873":"TBEN","8000875":"SOTW","8000876":"SPSN","8000877":"FBAU","8000879":"HBTH","8000880":"RRZ","8000882":"NBE","8000885":"MBG","8000887":"ERES","8000888":"MBE","8000889":"TBER","8000890":"RBRG","8000891":"FSUE","8000892":"EBGA","8000894":"RBGP","8000899":"KBGG","8000902":"NBHM","8000904":"EBRH","8000905":"ABGS","8000907":"EBLB","8000908":"ABTSB, ABTSL","8000909":"RBAH","8000911":"MBN","8000913":"HBER","8000918":"MBER","8000919":"HBBR","8000921":"FBEZ","8000923":"SBS","8000925":"TBE","8000926":"SBES","8000927":"EBWG","8000928":"NBMS","8000932":"RBEU","8000933":"TBEU","8000934":"TBTB","8000935":"ABVS","8000941":"SBX","8000942":"RBI","8000943":"TBI","8000944":"TBIB","8000945":"MBIC","8000948":"FBI","8000951":"FBBM","8000953":"EBIO","8000955":"ABIL","8000956":"EBIS","8000957":"HROE","8000959":"TBIE","8000961":"EDH","8000962":"MBIH, MBIHH","8000963":"RBIE","8000965":"RBGN","8000966":"EBIG","8000967":"SBDS","8000969":"MBIN","8000970":"EBB","8000971":"ABWM","8000973":"RBIN","8000974":"NBI","8000975":"FBGG","8000976":"FBGN","8000977":"EHGV","8000978":"EBIN","8000983":"EBKB","8000984":"RBRK","8000989":"SBRB","8000996":"FBMR","8000997":"MBI","8000999":"TBIS","8001000":"HBSS","8001002":"TBIT","8001003":"NBLA","8001004":"MBLH","8001005":"TBIF","8001006":"KBLB","8001007":"AB","8001008":"KBLH","8001009":"RBAN","8001013":"TBL","8001015":"TBLS","8001017":"RBLB","8001018":"FBLH","8001027":"SBKL","8001028":"MBLM","8001030":"EBKP","8001032":"RBOB","8001033":"MBOB","8001034":"FBST","8001035":"EBGZ","8001038":"EBDA","8001039":"EBOE","8001043":"RBOK","8001045":"EBCK","8001046":"MBOD","8001047":"TBOD","8001048":"HBBU","8001049":"KBOD","8001050":"HBOF","8001051":"NBMA","8001052":"HBOD","8001054":"NBOE","8001055":"TBO","8001057":"RBOE","8001058":"NBHF","8001059":"RBER","8001061":"EBEO","8001063":"HBSM","8001065":"EBSL","8001066":"EBSP","8001069":"NBO","8001071":"HBOM","8001072":"KBOI","8001080":"TBD","8001081":"KBHH","8001082":"KBBG","8001083":"KBB","8001084":"KBD","8001085":"KBM","8001086":"KBO","8001088":"KBEC","8001089":"HBHB","8001090":"TBP","8001091":"KBUN","8001092":"ABRD","8001093":"EBOR","8001095":"EBHS","8001096":"EBGO","8001097":"EBOK","8001098":"FBOK","8001104":"FBO","8001106":"FBOS","8001107":"EBTB","8001108":"EBTV","8001110":"SBO","8001111":"TBOX","8001112":"EBRB","8001113":"KBRC","8001118":"EBRA, EBRAH","8001120":"HBKE","8001121":"HBKH, HBKL","8001122":"HBRM","8001123":"HBRA","8001129":"MBB","8001130":"KBRB","8001131":"RBTI","8001132":"FBFS","8001134":"HGLI","8001135":"SBA","8001136":"ABRB","8001137":"EBDL","8001138":"RBTN","8001139":"ABST","8001143":"RBRS","8001147":"MBRN","8001149":"NBG","8001153":"KBRS","8001155":"HBN","8001156":"HBB","8001157":"HBHM","8001159":"HBL","8001160":"HBM","8001161":"HBON","8001162":"HBOS","8001163":"HBSC","8001164":"HBHS, HBSB","8001165":"HBMG","8001166":"HBV","8001167":"HBWA","8001168":"HBHL","8001170":"HBWU","8001174":"RBN","8001176":"HBRT","8001177":"SBRH","8001178":"TBZ","8001179":"MKRS","8001180":"KBRY","8001182":"EBRS","8001183":"EBRO","8001185":"HBRO","8001186":"KBRO","8001188":"HBST","8001190":"ABRS","8001191":"RBRM","8001196":"FBB","8001198":"RBRH","8001199":"FBK","8001200":"SBUM","8001201":"HBUE","8001203":"MBR","8001205":"TBRU","8001207":"MBRM","8001209":"KBRU","8001212":"RBRP","8001213":"EBRU","8001214":"RBMT","8001215":"KBR, KBR P","8001221":"SBB","8001223":"NBTH","8001225":"NBM","8001229":"MBAU","8001231":"MBHA","8001234":"RBU","8001235":"KBZ","8001236":"FBUS, FBUSS","8001237":"FBUD","8001238":"SBN","8001242":"NBUE","8001244":"FBDH","8001245":"HBKB","8001248":"FBHM","8001249":"FBDW","8001250":"FBDG","8001252":"RBUE","8001256":"FBRG","8001258":"ABUS","8001259":"ABSM","8001261":"KBUT","8001262":"RBGG","8001264":"KBUH","8001266":"EBUD","8001267":"SBY","8001268":"EBUR","8001271":"FBUN","8001273":"ABR","8001276":"MBGU","8001277":"NBUM","8001278":"NBUW","8001279":"HBGD","8001283":"FBUH","8001285":"MBGH","8001287":"FBGH","8001289":"NBK","8001290":"NBUR","8001293":"NBN","8001296":"TBU","8001297":"NBUT","8001298":"NBWH, NROS","8001301":"HBUR","8001302":"SSHI","8001308":"KDEM","8001310":"NBT","8001312":"FBZ","8001315":"ABX","8001316":"ACD","8001317":"NCA","8001318":"HCAL","8001322":"FCA","8001323":"ECP","8001327":"ECA","8001328":"ECAS, ECASP","8001329":"ECME","8001330":"NCH","8001331":"NCHA","8001334":"NCN","8001335":"ECOH","8001337":"HCLP","8001338":"NC","8001339":"NCNS","8001340":"SCOC","8001341":"SCN","8001342":"HCOP","8001343":"ECFS","8001347":"NCR","8001348":"NCRE","8001352":"ACV","8001354":"MDA","8001355":"MDAS","8001357":"EDHL","8001358":"EDAB","8001359":"KDAM","8001360":"ADL","8001362":"EDAK","8001365":"KDAL","8001366":"RDL","8001372":"ADB","8001373":"MDAR","8001375":"FDN","8001376":"FDO","8001377":"FDS","8001378":"FDA","8001379":"FDE","8001380":"FDK","8001382":"MDAG","8001384":"KDAT","8001386":"FDAL","8001387":"ADH","8001388":"SDF","8001389":"FDSU","8001390":"EDVB","8001392":"HDEH","8001393":"HDED","8001394":"EDED","8001397":"NDG","8001399":"RDM","8001400":"NDE","8001404":"MDS","8001405":"TDLM","8001406":"SDE","8001407":"SDEO","8001414":"SDBO","8001415":"RDZ","8001416":"KDEK","8001417":"KDEA","8001418":"KDEB","8001420":"EDTM","8001421":"NDEB","8001427":"FDET","8001428":"TDT","8001429":"HDEM","8001430":"NDN","8001432":"EDEU","8001435":"NDIE","8001438":"ADT","8001439":"MDID","8001443":"HDIP","8001447":"MDIN","8001450":"NDT","8001454":"MDRD","8001455":"FDZM","8001456":"FDZ","8001457":"FDIZ","8001458":"FDIO","8001459":"FDZS","8001460":"FDBT","8001463":"MDIL","8001465":"EDGD","8001466":"MDIF","8001468":"MDKS","8001469":"EDIN","8001470":"SDIR","8001471":"HDBR","8001476":"TDI","8001479":"RDOA","8001480":"RDGN","8001482":"RDOF","8001483":"RDOG","8001484":"NDOE","8001485":"RDOM","8001486":"HDOP, HDPH","8001489":"HDVD","8001491":"RDRN","8001492":"HDOG","8001493":"ADR","8001495":"MDO","8001499":"MDFN","8001502":"HDMK","8001504":"FDH","8001505":"EDOH","8001506":"KDO","8001507":"KDBW, KDBWN","8001511":"FDOH","8001512":"TDS","8001514":"FDW","8001515":"EDSH","8001516":"EDLS","8001517":"EDKK","8001518":"EDMB","8001519":"EDOO","8001520":"EDST","8001521":"EDTP","8001522":"EDWH","8001523":"EDAP","8001524":"EDAU","8001525":"EDOF","8001526":"EDAM","8001527":"EDBA","8001528":"EDBH","8001529":"EDBK","8001530":"EDD","8001531":"EDOL","8001532":"EDHU","8001533":"EDKD","8001534":"EDKH","8001535":"EDKO","8001536":"EDKR","8001537":"EDKU","8001538":"EDLH","8001539":"EDLN","8001540":"EDGM","8001541":"EDMR","8001542":"EDMS","8001543":"EDMG","8001544":"EDRA","8001545":"EDSO","8001546":"EDWI","8001547":"ADO","8001548":"NDM","8001549":"EDSM","8001554":"FDCH","8001558":"EDRS","8001561":"HDRY","8001566":"KDUK","8001567":"FDU","8001570":"SDUW","8001571":"KDUL","8001578":"MDHR","8001579":"KDFS","8001581":"KDV","8001582":"KDW","8001583":"KDZ","8001584":"KDBE","8001585":"KDBH, KDBI","8001586":"KDD, KDDH","8001587":"KDE","8001588":"KDES","8001589":"KDGA","8001590":"KDGE","8001591":"KDOB","8001592":"KDR","8001593":"KDRM","8001594":"KDRE, KDRH","8001595":"KDU","8001596":"EDSL","8001597":"KDHA","8001598":"KDFL","8001599":"EDBI","8001600":"EDBU","8001602":"EDGR","8001603":"KDVS","8001605":"EDHD, EDHP","8001607":"EDMO","8001608":"EDOM","8001609":"EDRM","8001611":"EDRU","8001612":"EDWD, EDWDP","8001614":"MDUH","8001616":"RDRM","8001617":"TDU","8001618":"FDTH","8001619":"NEE","8001620":"NEBH","8001621":"MEBS","8001622":"MEBH","8001623":"NED","8001627":"NEBM","8001628":"MEBM","8001629":"NEB, NEBN","8001632":"TEC","8001634":"MEG","8001636":"NEC","8001638":"RET","8001640":"NEG","8001643":"REBR","8001645":"HEBS","8001646":"AECH","8001647":"MEC","8001648":"FEZL","8001650":"TETD","8001651":"TEI","8001654":"AEC","8001655":"NEMN","8001659":"FED","8001663":"REK, REKH","8001665":"REH","8001666":"SEE","8001668":"FEDI","8001670":"FEF","8001671":"REF","8001672":"FEGB","8001674":"NEGE","8001675":"HEGT","8001679":"MEGM","8001680":"NEO","8001682":"MEGL","8001683":"MELG","8001684":"TEH","8001686":"EELB","8001687":"HELH","8001688":"SEGO","8001689":"TEHN","8001690":"KEHR","8001692":"EERI","8001693":"FEHH","8001694":"FEHR","8001700":"EEHS","8001701":"FECH","8001702":"MEIC","8001704":"FEIZ","8001706":"EEHG","8001707":"REM","8001708":"MEB","8001709":"MEST","8001712":"KEIL","8001713":"HEIV","8001715":"REI","8001718":"AEF","8001720":"SEF","8001727":"SEMA","8001728":"REIS, REISO, REISW","8001729":"EEFD","8001731":"TEF","8001732":"REIW","8001734":"MEI","8001736":"KEIT","8001739":"AEGS","8001741":"HELV","8001742":"NELF","8001745":"KML","8001746":"TBME","8001747":"TELL","8001749":"NEL","8001751":"TEL","8001752":"MELZ","8001760":"HELS","8001762":"NEF","8001763":"FELT","8001764":"FELZ","8001765":"FELS","8001766":"RELZ","8001768":"HE","8001770":"KEMM","8001771":"REMM","8001773":"EEM","8001775":"HEMK","8001777":"HEMT","8001780":"EEMP","8001781":"HEMP","8001782":"EEDT","8001783":"NEK","8001785":"TEN","8001787":"MBEF","8001789":"KENL","8001790":"RENG","8001794":"TENG","8001795":"EENP","8001799":"SEN","8001801":"FENS","8001803":"TEZ","8001806":"MENW","8001808":"EEPE","8001811":"FERN","8001812":"SEP","8001813":"FEPP","8001814":"FER","8001815":"FEP","8001816":"FEPB","8001817":"FERO","8001818":"FERB","8001819":"FERW","8001820":"TER","8001825":"MER","8001826":"FEKW","8001827":"TERD","8001828":"SED","8001829":"MEWG","8001833":"TEG","8001835":"MERB","8001836":"EERG","8001838":"TEK","8001839":"KERZ","8001840":"NERK","8001841":"KER","8001844":"NER","8001845":"NERB, NERH","8001846":"NERS","8001851":"EEK","8001853":"MERG, MERN","8001858":"KERP","8001860":"RERO","8001864":"FEZ, FEZS","8001865":"RERZ","8001867":"HESH","8001870":"FES","8001871":"FESS","8001872":"HESD","8001874":"TESU","8001875":"NESU","8001877":"NESB","8001880":"MECH","8001883":"FEN","8001886":"KE","8001890":"HESO","8001894":"HEKP","8001896":"EESA","8001897":"EESD","8001898":"EENW","8001899":"HESN","8001900":"EEAL","8001901":"EEBE","8001902":"EEBB","8001903":"EEDL","8001904":"EEDO","8001905":"EEIB","8001906":"EEFO","8001907":"EEGE","8001908":"EEHU","8001909":"EEKB","8001910":"EEKN","8001911":"EEKS","8001912":"EEKU","8001913":"EESO","8001914":"EEUE","8001915":"EEWD","8001919":"NEN","8001920":"TE","8001921":"TEME","8001922":"MESH","8001924":"HETL","8001925":"NET","8001926":"RETL","8001928":"EEZB","8001929":"NEW","8001932":"NEZ","8001933":"TEU","8001935":"NEU","8001941":"AEU","8001942":"TEB","8001943":"EGVA","8001946":"TEY","8001949":"HETR","8001950":"FFAN","8001953":"AFK","8001954":"RFN","8001957":"HF","8001958":"HFAL","8001961":"MFCH","8001963":"MFP","8001965":"TFAU","8001967":"TFV","8001969":"NFZ","8001970":"MFA","8001971":"RFB","8001972":"EFEL","8001973":"MFK","8001974":"TFE","8001976":"EFER","8001977":"AFEB","8001978":"NFT","8001982":"TFI","8001983":"FFI","8001984":"TFIL","8001985":"MFNS","8001988":"NFTO","8001989":"NFI, NFIH","8001990":"SFC","8001991":"SFWB","8001992":"MFBU","8001995":"MFN","8001996":"MESG","8001998":"MFIN","8002004":"KFLH","8002010":"FFD","8002011":"AFT","8002012":"MFLI","8002013":"FFH","8002014":"RFLO","8002018":"SFOE","8002019":"NFOE","8002020":"NFDF","8002023":"RFM","8002024":"NFO","8002025":"RFTS","8002026":"TFB","8002027":"KFOS","8002029":"NFH","8002030":"TFOS","8002034":"FMUL","8002036":"RFST","8002038":"FLBF","8002039":"FFO","8002040":"FSP","8002041":"FFS","8002042":"FFW, FFW S","8002043":"FFBK","8002044":"FFBS","8002045":"FFES","8002046":"FGM","8002047":"FLS, FLSS","8002048":"FFMK","8002049":"FFND","8002050":"FNI, FNI S","8002051":"FFAW","8002052":"FRH","8002053":"FSIN, FSINO","8002054":"FSO","8002055":"FFZH","8002057":"NFU","8002058":"FOST","8002059":"FSTL","8002063":"HFRE","8002065":"TFG","8002066":"RFW","8002067":"RFHE","8002068":"RFLT","8002069":"RFSG","8002070":"RFWI","8002071":"RFZ","8002073":"EFRE","8002074":"MFHD","8002075":"NFR","8002076":"NFRE","8002077":"RFK","8002078":"MFR","8002080":"HFST","8002083":"SFF","8002085":"MFLH","8002086":"AFN","8002092":"EFBU","8002095":"FFRN","8002096":"TFD","8002099":"MFDB","8002100":"FFN","8002102":"HFRI","8002103":"FFL","8002104":"KFWH","8002105":"FGS","8002106":"AFBG","8002108":"FFRI","8002109":"EFFD","8002110":"TFH","8002111":"TFF","8002113":"AFRD","8002114":"KFGN","8002115":"AFD","8002116":"RFTL","8002117":"SFI","8002120":"TFFL","8002122":"TFLA","8002123":"RFH","8002127":"KFRI","8002130":"EFRM","8002132":"SFIM","8002133":"TFR","8002134":"FFRL","8002137":"FFUR","8002141":"MFB","8002149":"NFWS","8002150":"RFUE","8002152":"NFBB","8002153":"NFDB","8002154":"NFUB","8002155":"NFUF","8002156":"MFSN","8002159":"NFW","8002161":"MFU","8002162":"MGAL","8002165":"TGT","8002166":"TGFD","8002168":"TGAW","8002171":"MGH","8002173":"MGAI","8002175":"SGSZ","8002179":"HGKE","8002180":"EGAR","8002182":"FGA","8002185":"AGD","8002187":"MGP","8002191":"FGBM","8002195":"TGRN","8002198":"MGT","8002203":"HGEE","8002205":"NGET","8002206":"KGEK","8002207":"KGEH","8002209":"MGLG","8002210":"MGIB","8002212":"FGSM","8002214":"RGSN","8002217":"TGW","8002218":"TG","8002220":"MGEU","8002222":"KGE","8002223":"EGZO","8002224":"EGBN, EGBU","8002225":"EGBS","8002226":"EGHS","8002227":"EGRO","8002233":"MGKG","8002235":"RGB","8002236":"FGEF","8002237":"NGE","8002238":"SGN","8002239":"RGEH, RGEM","8002240":"TGES","8002241":"RGES","8002242":"TGEH","8002243":"TGLH","8002244":"MGLH","8002247":"MGLD","8002249":"FGHM","8002251":"TGN","8002254":"FGFD","8002256":"MGHF","8002259":"FGTB","8002262":"EGK","8002263":"MGHN","8002265":"FGGB","8002266":"AGF","8002267":"EGVH","8002268":"KGVW","8002269":"FGOG","8002272":"TGB","8002274":"HGIS","8002275":"MGCH","8002278":"TGI","8002280":"FGIR","8002281":"HGT","8002283":"EGBO","8002284":"EZK","8002286":"SGM","8002288":"FGBG","8002290":"KGL","8002293":"AGST","8002296":"KGO","8002299":"HGOH","8002300":"RGOR","8002301":"FGOE","8002304":"AGH","8002315":"FGOZ","8002319":"AGK","8002320":"HGOL","8002321":"FGDH","8002329":"NGG","8002333":"NGOD","8002334":"RGH","8002335":"NGZ","8002337":"RG","8002339":"MGFL","8002340":"NGFG","8002341":"NG","8002342":"FGRK","8002343":"MGRA","8002344":"NGFU","8002345":"RGNN","8002346":"MGRL","8002347":"MGB","8002348":"MGRS","8002349":"NGFA","8002351":"MGF","8002358":"FGSN","8002365":"RGRZ","8002369":"EGRV","8002370":"EGVB","8002373":"RGSS","8002374":"FGRF","8002377":"MGRZ","8002378":"MGNB","8002380":"RGM","8002382":"FGRN","8002383":"MGDF","8002386":"FDG","8002388":"FGKA","8002389":"KFKO","8002391":"FGRO","8002393":"FGRU","8002399":"NGRS","8002400":"FGAU","8002402":"KGBU","8002403":"HGBW","8002405":"HGDN","8002409":"FGRB","8002410":"FGL","8002411":"AGRO","8002412":"HGRK","8002413":"FGLR","8002416":"NGRG","8002420":"MGHD","8002422":"MGOI","8002424":"MGK","8002425":"FGK","8002430":"RGCH","8002432":"NGRW","8002434":"NGUF","8002435":"MGRB","8002436":"NGRU","8002439":"FGRG","8002441":"EGNO","8002442":"EGNH","8002444":"RGRN","8002445":"TGRW","8002447":"TGRS","8002448":"TGC","8002452":"SGD","8002454":"SGS","8002457":"MGKF","8002458":"MGNZ","8002461":"EGLO","8002462":"KGU","8002465":"RGDN","8002466":"MGUF","8002467":"NGD","8002468":"NGU","8002470":"RGUN","8002473":"FGUH","8002474":"FGUB","8002477":"KGUS","8002478":"RGTA","8002480":"RGTF","8002484":"FGX","8002489":"RHAG","8002490":"KHAN","8002491":"MHR","8002494":"KHAC","8002495":"FHAD","8002496":"AHNU","8002498":"FHAE","8002499":"HHAE","8002501":"FHHF","8002504":"AHAF","8002506":"NHA","8002507":"HHAG, HHGH","8002509":"KGVK","8002512":"EHGI","8002514":"EHGO","8002515":"RHGB","8002517":"NHBH, NHBU","8002520":"NFTM","8002523":"NHAG","8002524":"FHGO","8002526":"FHME","8002528":"FHHN","8002531":"FHDT","8002532":"FHAI","8002533":"RHAM","8002534":"MHMO","8002536":"EHAD","8002537":"HHAL","8002539":"EHAL","8002542":"NHAL","8002545":"AHKS","8002546":"RHL","8002547":"AAI","8002548":"ADF, ADST","8002549":"AH, AHS","8002550":"AHST","8002551":"AELB","8002554":"ABG, ABG S","8002555":"AEST","8002556":"AFIB","8002557":"ANR, ANRS","8002558":"ARAL","8002559":"ASTS","8002560":"AWN","8002561":"AWFS","8002565":"AHAM","8002567":"NHG","8002568":"NHGO","8002570":"MHAU","8002571":"EHK","8002572":"FHN","8002573":"FHW","8002574":"FHWB","8002575":"AHAN","8002578":"NHAP","8002580":"HHBI","8002581":"HHBO","8002584":"HKL","8002585":"HLEI","8002586":"HLI R","8002588":"SHN","8002589":"HLGF","8002592":"AHA","8002593":"MHRG, MHRH","8002594":"HHRD","8002596":"NHHF","8002598":"HHAR","8002605":"NH","8002607":"HHRS","8002609":"NHAR","8002610":"MHHS","8002612":"NHS","8002615":"HHSB","8002621":"RHS","8002623":"MHMR","8002625":"SHSS","8002628":"AHSB, AHSF","8002630":"NHT","8002632":"RHLO","8002633":"RHAS","8002634":"HHAS","8002635":"FHAT","8002637":"FHAS","8002638":"KHAT","8002639":"EHAT","8002640":"EHTM","8002641":"HHTF","8002643":"SHZ","8002648":"SHAM","8002649":"SHAU","8002651":"MHPH","8002655":"SHPT","8002656":"THAT","8002664":"MHNS","8002666":"RHSN","8002667":"MHHM","8002670":"EHBK","8002673":"THCH","8002674":"AHEN","8002677":"FHED","8002678":"NHED","8002680":"EHE, EHE P","8002681":"RHBF","8002682":"EHEG","8002683":"RHGN","8002684":"RHBO","8002685":"RHKA","8002686":"RHKM","8002687":"RHBP, RHBW","8002689":"THD","8002690":"THDM","8002691":"THDS","8002692":"FHEI","8002694":"HHEI","8002695":"HHDM","8002696":"NHEI","8002699":"THST","8002700":"TTPS","8002704":"RHN","8002705":"NHE","8002707":"SHB","8002710":"MHMK","8002711":"KHEH","8002715":"MHEM","8002716":"FHEB","8002724":"SHZH","8002727":"RHE","8002733":"NHB","8002737":"EHEP","8002745":"EHMD","8002746":"SHEM","8002748":"RHCH","8002751":"NHD","8002753":"KHEN","8002754":"EHNE","8002757":"FHP","8002760":"THTO","8002761":"MHEH","8002763":"RHZ","8002764":"THZ","8002766":"THC","8002768":"KHEC","8002769":"EHCK","8002770":"EHF","8002773":"FHER","8002775":"KHES","8002776":"THMA","8002779":"EHBO","8002782":"NHER","8002783":"NHEN","8002784":"KHER","8002785":"THE, THE Z","8002789":"THL","8002792":"MHI","8002793":"NHL","8002794":"NHR","8002797":"RHRT","8002798":"RHXB","8002800":"HHBS","8002801":"EHEZ","8002806":"KHEZ","8002810":"EHLN","8002812":"HHSO","8002813":"FHET","8002814":"FHH","8002815":"FHZ","8002817":"SHR","8002820":"MHEU","8002821":"MHFM","8002822":"FHEU","8002824":"HHIS","8002826":"EHIB","8002827":"NHGN","8002828":"KHIS","8002830":"HHIO","8002835":"EHIL","8002838":"NHP","8002841":"EHIT","8002843":"AHPF","8002844":"RHIM","8002845":"NHIS","8002847":"SHWP","8002848":"RHIZ","8002850":"MHRS","8002852":"THI","8002853":"NHI","8002856":"MHFN","8002857":"RHO","8002858":"SHIH","8002861":"KHIR","8002864":"AHIF","8002865":"AHZ","8002868":"KHO","8002869":"KHOM","8002872":"FHM","8002873":"AHPS","8002875":"SHY","8002877":"FHD","8002878":"NHM","8002879":"SHST","8002880":"SHS","8002881":"MHWG","8002883":"RHK","8002884":"HHOD","8002886":"FHTN","8002888":"MHDT","8002892":"THFG","8002894":"MHSB","8002895":"SHMB","8002898":"NHTL","8002899":"MHRK","8002903":"FHNB","8002912":"MHLK","8002915":"HHTL","8002916":"EHOM","8002918":"NHOE","8002919":"EHOS","8002920":"EHOV","8002921":"EHVR","8002923":"HHXR","8002924":"NHO","8002927":"NHON","8002929":"SHFD","8002930":"THOF","8002931":"RHFF","8002932":"KHOF","8002933":"FHFG","8002934":"FHOR","8002935":"FHF","8002939":"KHOG","8002940":"MHOB","8002941":"KHB","8002943":"SKLH","8002944":"HHEG, HHEP","8002946":"AHCH","8002953":"EHOG","8002954":"MHPG","8002955":"MHSL","8002956":"NHOH","8002958":"FHSU","8002959":"AHWT","8002962":"HHDF","8002967":"AHES","8002969":"HHOL","8002972":"EHW","8002976":"EHOZ","8002978":"HHZH","8002979":"KHOZ","8002980":"MHO","8002988":"KHOR","8002992":"EHOP","8002994":"MHOP","8002995":"SHPS","8002998":"THBH, THHF","8003000":"EHBM","8003001":"RHBG","8003002":"AHOG","8003003":"AHOT","8003008":"HHOY","8003010":"RHAR","8003014":"RHFM","8003015":"FHMM","8003016":"FHUE","8003018":"EHTG","8003020":"ESW","8003021":"SHT","8003022":"THUB","8003024":"MHUG","8003025":"RHU","8003030":"HHUL","8003032":"AY","8003033":"RHTT","8003035":"RIB","8003036":"HI","8003038":"MIHN","8003039":"MIC","8003040":"SIDO","8003041":"FIST","8003042":"SIG, SIGW","8003044":"NIDF","8003052":"RIR","8003053":"FIH","8003057":"MILT","8003058":"NILL","8003059":"SILG","8003060":"TIL","8003061":"RIMM","8003062":"FIM","8003063":"NIM","8003064":"HIMS","8003065":"MIMS","8003066":"RIMZ","8003070":"SIM","8003072":"MIDR","8003073":"KING","8003075":"FIL","8003076":"MIN","8003078":"AAU","8003079":"MINI","8003080":"RIN","8003081":"NI","8003083":"NIP","8003086":"NIR","8003088":"AIS","8003090":"EILH","8003091":"HIHG","8003092":"MIS","8003096":"EIAV","8003098":"RIT","8003100":"NIL","8003101":"RITL","8003102":"AIZ","8003103":"TIT","8003104":"KIV","8003108":"SJF","8003111":"TJZ","8003115":"AJHH","8003123":"MJET","8003124":"HJ","8003125":"RJO","8003129":"NJS","8003130":"KJUC","8003131":"FJUE","8003135":"KJU","8003137":"AJUS","8003143":"FKLM","8003144":"FKAI","8003146":"MKAI","8003148":"SKAI","8003150":"SKLP","8003151":"SKLW","8003154":"NKAL","8003158":"KKAL","8003160":"KKAS","8003165":"HKAW","8003166":"EKAL","8003168":"EKAM","8003169":"EKME","8003170":"FKMP","8003172":"RKD","8003173":"SKAZ","8003174":"KKAW","8003175":"RKPD","8003179":"STK","8003181":"RKF","8003182":"HKRF","8003183":"RKW","8003184":"RKDU","8003185":"RKHA","8003186":"RKIN","8003187":"RKMG","8003189":"NKA","8003196":"FKH","8003197":"FKJK","8003198":"FKKD","8003199":"FKOZ","8003200":"FKW","8003207":"AKAD","8003208":"AKTO","8003209":"HKAT","8003211":"SKTS","8003212":"EKV","8003213":"FKFT","8003214":"NKG","8003215":"SKW","8003216":"FKAU","8003218":"RKL","8003220":"TKEH","8003222":"AKI","8003227":"MKMZ","8003228":"FKCH","8003229":"NKNN","8003230":"MKPO","8003232":"SKEN","8003233":"RKN","8003235":"FKB","8003238":"NKCH","8003241":"FKES","8003245":"EKGS","8003247":"KKEV","8003248":"TKBI","8003249":"MKI","8003252":"KKIE","8003253":"AKRU","8003255":"FKIL","8003256":"MKIG","8003257":"SKIB","8003262":"FKGS","8003266":"TKIM","8003267":"HKDF","8003268":"NKIR","8003270":"NKO","8003272":"TKI","8003276":"HKHW","8003278":"TKM","8003280":"TKT","8003282":"TKTO","8003283":"TKTS","8003284":"TKU","8003285":"RKH","8003286":"HKHN","8003287":"EKHU","8003288":"HKLG","8003290":"MKO, MKO H","8003292":"HKI","8003293":"RKZ","8003294":"SKI","8003295":"SKR","8003298":"SKRS","8003299":"MKIS","8003302":"MKLA","8003303":"AKX","8003309":"AKC","8003310":"KKSH","8003311":"FKAH","8003312":"AFB","8003313":"FKGE","8003314":"FKO","8003315":"FKLU","8003316":"FKWO","8003317":"MKHN","8003318":"SKB","8003320":"KKTR","8003321":"KKLE","8003323":"HKSI","8003325":"RKES","8003326":"MKKZ","8003329":"NKGM","8003330":"KFKB","8003332":"TKNK","8003336":"RKLN","8003338":"NKNB","8003339":"RMBK","8003340":"KKLM","8003341":"KKSM","8003342":"MKLF","8003344":"SKT","8003345":"TKLU","8003348":"HKNE","8003349":"RKG","8003350":"SKG","8003351":"KKOE","8003352":"KKOL","8003354":"SKOW","8003355":"MKCH","8003356":"NKI","8003357":"NKOE","8003358":"KKFS","8003360":"KKP","8003361":"KKS","8003362":"KKV","8003363":"KKW","8003364":"KKBH","8003365":"KKC","8003366":"KKCN","8003367":"KKDB","8003368":"KKDT, KKDZ, KKDZB","8003369":"KKH","8003370":"KBP","8003371":"KKL","8003372":"KKN, KKN P","8003373":"KKWO","8003374":"RKOE","8003375":"KKMT","8003378":"TKS","8003379":"KSTP","8003381":"TKF","8003382":"HKOL","8003383":"KKWW","8003385":"EKSO","8003386":"KKOW","8003388":"FKRL, FKRLS","8003392":"KKHR","8003393":"NKZ","8003394":"SKV","8003395":"KKOS","8003397":"MKMR","8003398":"RKLR","8003399":"RKNA","8003400":"RKO","8003401":"RKOP","8003402":"SKZ","8003403":"SKU W, SKZM","8003404":"RKOF","8003407":"SKDL","8003408":"RKOR","8003409":"TKO","8003410":"AKWS","8003411":"TKH","8003412":"KKOI","8003413":"NKMG","8003414":"KKOF","8003415":"KKOH","8003416":"RKOW","8003420":"EKRG","8003424":"EKRD","8003426":"KKRL, KKRLF","8003427":"KKRU, KKRX","8003429":"SKRB","8003430":"AKM","8003431":"AKHD","8003432":"TKN","8003434":"SKK","8003436":"KKRZ","8003438":"MKZ","8003440":"KKRW","8003442":"FKRI","8003446":"NK","8003447":"FKRO","8003452":"SKRO","8003455":"KKRF","8003457":"MKRB","8003460":"AKRS","8003461":"TKUC","8003462":"KKUH","8003469":"EKUE","8003470":"EKNT","8003472":"NKUE","8003474":"AKH","8003476":"NKU","8003477":"AKE","8003478":"AKUP","8003479":"AKRH","8003481":"SKUS","8003483":"MKUN","8003484":"SKY","8003485":"NLB","8003487":"HHML","8003488":"MLBW","8003489":"RLD","8003490":"MLLF","8003491":"HLGG","8003494":"RLSW","8003497":"RLBP","8003498":"RLSH","8003503":"FLP","8003504":"SLAO","8003506":"MLDI","8003507":"RLAD","8003508":"RLW","8003512":"MLL","8003515":"SLD","8003516":"SLWR","8003518":"ALAS","8003519":"ALAN","8003520":"FLGS","8003521":"NLG","8003522":"HLNG","8003523":"FLG","8003524":"TLR","8003525":"TLL","8003526":"FLGF","8003528":"MLB","8003529":"ELBG","8003533":"RBS","8003539":"KLAB","8003540":"KLA","8003541":"ALST","8003542":"HLGH","8003543":"FLAH","8003544":"ALG","8003545":"HLGM","8003548":"NLP","8003550":"FSLB","8003551":"MLNW","8003552":"NLZ","8003553":"KLAW","8003554":"NLGU","8003558":"FLF","8003559":"FLAS","8003560":"MLAW","8003562":"RLAC","8003563":"HLAT","8003567":"NLDF","8003568":"SLAU","8003569":"TLH","8003571":"RLCH","8003576":"ALUB","8003577":"ALAU","8003578":"HLFO","8003580":"NLL","8003581":"NLR","8003582":"NLA","8003585":"RLFG","8003586":"RLBO","8003587":"NLLW","8003588":"TLN","8003589":"MLIG","8003591":"TLM","8003592":"TLW","8003593":"FLBG","8003594":"RLBA","8003605":"FLW","8003608":"ELGD","8003609":"RLT","8003611":"SLE","8003612":"FLEH","8003616":"KLEL","8003617":"HLFG","8003622":"TLF","8003627":"MLEH","8003628":"ALE","8003630":"ELBK","8003632":"HLMF","8003635":"HLEM","8003638":"ELSN","8003639":"MLWG","8003640":"ELEN","8003641":"FLE","8003643":"MLG","8003644":"HLGL","8003649":"ALS","8003652":"TLE","8003655":"ELEO","8003656":"HLED","8003657":"ELED","8003658":"ELET","8003659":"HLT","8003660":"KLEU","8003663":"MLSH","8003664":"NLWI","8003665":"KLET","8003668":"KLK, KLKH","8003669":"KLS","8003671":"KEST","8003672":"KLRD, KLRH","8003673":"FLI","8003674":"FLST","8003676":"NLH","8003680":"FLIS","8003681":"FLIE","8003684":"SLB","8003687":"RLI","8003690":"RLID","8003692":"MLIA","8003696":"FLHH, FLHN","8003697":"KLD","8003698":"FLIN","8003699":"HLH","8003700":"HLWL","8003701":"HLIG","8003702":"RLF","8003705":"HLBU","8003708":"KLI","8003711":"FLIH","8003713":"KLIS","8003715":"ELIS","8003716":"ELTF","8003720":"MLCH","8003721":"RLOE","8003722":"HLOD","8003723":"SLF","8003724":"RLGN","8003726":"FLOE","8003729":"RLR","8003730":"RLST","8003731":"RLFB","8003732":"KLO, KLOV","8003733":"TLOE","8003734":"NLOR","8003735":"MLH","8003736":"RLRD","8003737":"RLRS","8003738":"HLON","8003739":"SLOH","8003740":"NLO","8003743":"RLRW","8003748":"TLON","8003749":"MLOH","8003751":"FLOR","8003752":"TLO","8003753":"FLON","8003754":"FLB","8003755":"FLO","8003758":"RLOS","8003759":"RLSM","8003760":"HLOX","8003762":"NLHM","8003763":"NLS","8003764":"RLU","8003765":"RLUM","8003766":"RLO","8003767":"RLUR","8003768":"NLUD","8003770":"NLUS","8003771":"NLT","8003772":"HLBB","8003773":"HLBR","8003774":"ALSJ","8003776":"ALKN, ALKR","8003777":"ALTH","8003778":"ALTS","8003780":"HLN","8003781":"ALB","8003782":"ELS","8003783":"ELDH","8003784":"HLUE","8003785":"ALHS","8003786":"ALD, ALD A","8003788":"ELRN","8003790":"FLUE","8003791":"ELUZ","8003792":"RLUE","8003794":"NLU","8003795":"NLW","8003796":"SLU","8003798":"ALU","8003799":"HLUN","8003800":"HLTT","8003804":"ELUT","8003807":"TMAG","8003808":"TMAI","8003809":"RMKI","8003810":"FMAS","8003813":"NML","8003814":"NMRH","8003815":"FMN","8003816":"FMS","8003817":"FMGO","8003818":"FMG","8003819":"FML","8003820":"FMMB","8003821":"FMM","8003824":"MMA","8003828":"MMAG","8003829":"AMAG","8003830":"MMD","8003831":"TMAL","8003832":"RMS","8003833":"RMSU","8003834":"TMIN","8003839":"NMDF","8003841":"RMR A, RMSM","8003842":"RMFS","8003843":"RMKL","8003844":"RMN","8003845":"RMA","8003847":"RMSE","8003848":"RMW","8003850":"TMAN","8003853":"TMB","8003854":"RMBW","8003855":"EMHD","8003856":"FMBS","8003857":"RMBO","8003859":"MMRN","8003860":"EMV","8003866":"HMAR","8003871":"RMAD","8003872":"RMAR","8003876":"NMB","8003877":"MMOS","8003878":"NMER","8003879":"MSB","8003881":"NMT","8003884":"NMH","8003885":"MMO","8003887":"NMSG","8003888":"EMAM","8003890":"EMHM","8003891":"EMSI","8003896":"EMAR","8003897":"TMAR","8003898":"NMLZ","8003899":"SMSO, SMSW","8003901":"MMSZ","8003903":"NMX","8003905":"MMZG","8003906":"AMA","8003909":"EMAN","8003911":"RMAI","8003913":"TMAU","8003915":"RMAU","8003916":"EDWK","8003920":"RMLG","8003921":"NMSM","8003922":"NMXH","8003924":"KMYW","8003925":"EUNW","8003926":"KMAY","8003927":"KMCH","8003929":"AMD, AMDH","8003930":"TMK","8003931":"KMCK","8003932":"RMK","8003936":"EDWW","8003937":"KMCP","8003938":"NMEE","8003939":"EMEG","8003943":"EMHO","8003946":"EDW","8003947":"HMEI","8003949":"HMRS","8003950":"EMZH","8003952":"MMEI","8003953":"FMLB","8003954":"AMF","8003956":"HMEL","8003957":"HMDF","8003959":"NME","8003960":"AME","8003961":"FMLS","8003965":"EMEU","8003966":"KMD","8003967":"EMED","8003969":"TMG","8003971":"FMBB","8003978":"HMEP","8003979":"MMEG","8003980":"SMER","8003982":"MMR","8003986":"EMES","8003987":"KMES","8003988":"RME","8003989":"MMTG","8003990":"KMEZ","8003991":"SMZM","8003992":"SMZG","8003993":"EMSD","8003996":"FMES","8003998":"EMSN","8004000":"HMSU","8004001":"EMTE","8004003":"FMET","8004004":"SMT","8004008":"MSAF","8004009":"TME","8004011":"NMI","8004013":"NMIK","8004017":"FMI","8004019":"MMIB","8004020":"KMIE","8004023":"KMIL","8004024":"EMIL","8004026":"NMLT","8004028":"NMIM","8004029":"RSLM","8004030":"MMAH","8004032":"RBSK","8004037":"FMGD","8004040":"NMSN","8004043":"MMW","8004048":"AML","8004049":"TMO","8004050":"TML","8004053":"TMOE","8004057":"AMLN","8004060":"FMHF","8004061":"KMGE","8004063":"KMR","8004064":"NMOE","8004065":"FMF","8004066":"RMOE","8004067":"TMHR","8004068":"TMHB","8004070":"TMS","8004071":"MMTN","8004077":"TMON","8004078":"SML","8004080":"SMON","8004084":"MMB","8004090":"NMOU","8004093":"AMM","8004094":"RMO","8004095":"RMOW","8004096":"SMK","8004099":"EMUD","8004100":"FMCK","8004101":"SMD","8004103":"TMRO","8004104":"TMUE","8004105":"HMLN","8004107":"RMH","8004111":"TMUL","8004112":"FMH","8004115":"NMST","8004122":"EMRW","8004124":"RML","8004125":"FMGR","8004126":"NMBG","8004127":"HMHZ","8004128":"MMDN","8004129":"MHAB","8004130":"MHAR","8004131":"MIT","8004132":"MKA","8004133":"MLEF","8004134":"MLEU","8004135":"MMP","8004136":"MRP","8004137":"MSW","8004138":"MMAR","8004139":"MAUG","8004140":"MMAL","8004141":"MMAU","8004142":"MBAL","8004143":"MDFG","8004144":"MEGS","8004145":"MFAS","8004146":"MFG","8004147":"MFE","8004148":"MGI","8004149":"MJK","8004150":"MKF, MKFS","8004151":"ML","8004152":"MLW","8004153":"MLO","8004154":"MMT","8004155":"MMCH","8004156":"MNA","8004157":"MOZ","8004158":"MP, MP  S","8004159":"MPER","8004160":"MRI, MRI P","8004161":"MSN","8004162":"MTR","8004163":"MWKR","8004165":"MMST","8004166":"SMR","8004167":"MFHB","8004168":"MFHM, MFHT","8004169":"NMUE","8004171":"FMTR","8004172":"SMSA","8004173":"ENHF","8004174":"SMLB","8004177":"AMUE","8004178":"RMU","8004179":"MMHG","8004181":"MFH, MFHH","8004182":"TMU","8004183":"HMS","8004184":"RMRG","8004185":"MMU","8004186":"MUO","8004188":"TMT","8004189":"RMCH","8004190":"EMSR","8004191":"NNAB","8004192":"RMU B","8004193":"FNAC","8004195":"TNAS","8004196":"TNA","8004198":"NNIL","8004199":"SNAB","8004200":"KNAM, KNAMN","8004201":"TNA M","8004202":"TNAI","8004204":"MMAM","8004206":"FNAS","8004207":"MNBN","8004208":"HNAH","8004210":"FNU","8004215":"RNB","8004216":"RNA","8004217":"RNMA","8004218":"RNH","8004219":"RNT","8004220":"TN","8004222":"RNEZ","8004223":"SNF","8004227":"ANEZ","8004228":"ENHH","8004229":"TNEH","8004230":"EDDS","8004232":"TN  M","8004233":"TNL","8004235":"TNED","8004236":"SNE","8004238":"TNSN","8004239":"MNSG","8004240":"MNEW","8004241":"ANTB","8004242":"KNEH","8004246":"FNIS, FNIU","8004247":"ANWF","8004249":"MNGH","8004250":"NNAE","8004251":"ENBM, ENBMP","8004252":"MNB","8004253":"SNBR","8004254":"MNBD","8004256":"MNBK","8004257":"RNBU","8004258":"TND","8004260":"HNPL","8004266":"AHAB","8004267":"AHRF","8004268":"NNDU","8004269":"EDK","8004271":"HNKO","8004273":"ENRA","8004276":"TNN","8004279":"MNF","8004280":"TRNF","8004284":"NNP","8004288":"EDOP","8004295":"FNF","8004297":"FNK","8004302":"ANL","8004304":"RNL","8004305":"NNT","8004306":"RND","8004310":"NNKS","8004312":"SNKW","8004313":"ENK","8004316":"KNRC","8004317":"KNSD","8004318":"MNES","8004319":"NNEU","8004320":"KNAK","8004321":"NNSG","8004322":"HNRU","8004323":"NNA","8004325":"NNU","8004326":"MND","8004327":"ANT","8004328":"FNSM","8004331":"RNSS","8004332":"NNW","8004333":"TNHO","8004335":"KNAL","8004336":"NNAM","8004338":"TNW","8004340":"ENV","8004343":"ANB","8004344":"SNID","8004345":"FNFD","8004348":"FNO","8004349":"FNOL","8004350":"FNR","8004351":"FNRO","8004352":"FSLH","8004353":"FNRW","8004357":"TSNU","8004363":"TNB","8004364":"FNCH","8004366":"KND","8004367":"FNIE","8004369":"ENID","8004373":"FNIB","8004376":"FNHD","8004379":"FNDH","8004380":"FNH","8004381":"ENDV","8004382":"FNJ","8004391":"MNLH","8004392":"SNDL","8004393":"KNME","8004395":"FNMI","8004396":"SNDM","8004400":"FNSD","8004401":"MNRU","8004402":"FROD","8004404":"MNRO","8004405":"FNDS","8004406":"ENDN","8004407":"ENDO","8004409":"FNS","8004413":"TNS","8004415":"FNV","8004417":"FNL","8004418":"FNWF","8004419":"EDUV","8004420":"FNDW","8004423":"RNID","8004424":"FNIZ","8004425":"TNF","8004426":"ENBE","8004429":"FKON","8004430":"ENIR","8004432":"FNIR","8004433":"KNIK","8004434":"KNIV","8004435":"FNIV","8004438":"SNI","8004440":"EHWB","8004441":"HNTH","8004442":"NDHF","8004444":"SNON","8004446":"MNHN","8004448":"ENOB","8004449":"HND","8004451":"MNOD","8004452":"HNO","8004453":"NOBW","8004456":"ANH","8004458":"TNO","8004460":"ANZ","8004461":"ENOW","8004462":"KNO","8004463":"SNOR","8004464":"RNO","8004466":"ANF","8004469":"NNRO","8004470":"NNOS","8004471":"NNO","8004473":"NNRS","8004474":"EBW","8004476":"NDTH, NND","8004477":"NNEI, NNES","8004478":"NNER","8004480":"NNLH","8004481":"NNMO","8004483":"NNRE, NNRF","8004484":"NNSR","8004485":"NNSW","8004486":"NNST","8004487":"NNSE, NNSN","8004488":"TNU","8004489":"RNBO","8004490":"TNUF","8004491":"NNRH","8004493":"NSTD","8004496":"TOAI","8004497":"FORA","8004499":"FOW","8004503":"MOA","8004504":"NOA","8004506":"MOU","8004507":"MOD","8004513":"SOH","8004514":"SOG","8004515":"FOBA","8004517":"TOBB","8004518":"FOB","8004521":"NON","8004523":"FOBD","8004525":"TOLC","8004527":"KOE","8004528":"TOES","8004529":"NOB","8004531":"MOGS","8004532":"MOGB","8004533":"NOH","8004538":"FOHS","8004540":"EOHT","8004541":"EOS, EOS P","8004542":"EOSD","8004545":"ROB","8004546":"ROBK","8004549":"TON","8004550":"KOL","8004552":"RLAU","8004553":"TOL","8004554":"MOLH","8004555":"SOW","8004557":"SOBM","8004563":"TOB","8004567":"FOBH","8004571":"MOMN","8004577":"ROSC","8004580":"MOSM","8004583":"NOBS","8004584":"MOSF","8004585":"MOF","8004589":"FOBS","8004592":"NOT","8004593":"FOTS","8004595":"RUDM","8004596":"FOU","8004597":"FOV","8004601":"FOBW","8004603":"ROD","8004604":"KOWI","8004605":"TOBZ","8004609":"NOK","8004610":"HOCH","8004613":"EOP","8004614":"FOCK","8004616":"KODE","8004620":"TCP","8004623":"TOE","8004624":"TOEW","8004626":"EOEL","8004629":"NOER","8004630":"EOER","8004632":"TOED","8004633":"NRTL","8004635":"FOE","8004636":"ROH","8004637":"TOET","8004639":"ROKS","8004640":"FOWH","8004642":"EOVP","8004643":"ROU","8004645":"FOO","8004647":"FOBI","8004652":"HOFN","8004653":"FOFF","8004654":"MOFF","8004658":"ROFH","8004661":"AOP, AOPS","8004662":"MOH","8004664":"FOK","8004665":"HOK","8004667":"MOL","8004668":"HOLB","8004669":"AOL","8004670":"HOLW","8004674":"EOLP","8004676":"EOLS","8004677":"SOU","8004679":"ROP","8004680":"FOPP","8004681":"TOP","8004683":"RORW","8004689":"HOHT","8004694":"KMBO","8004700":"NOS","8004701":"MOSH","8004702":"HOSS","8004703":"MOM","8004704":"HOTM","8004705":"HOTL","8004706":"KOSS","8004707":"AODT","8004709":"HOTW","8004712":"FOM","8004713":"FOS","8004714":"FOHF","8004719":"AOH","8004720":"HOTT","8004723":"MONH","8004724":"NOBE","8004725":"NOTS","8004726":"MOTF","8004727":"AOF","8004728":"AOBG","8004731":"MOTW","8004733":"MOBR","8004735":"HOTZ","8004739":"KOV","8004740":"TOW","8004741":"AOS","8004742":"MOYM","8004744":"EPDK","8004745":"EPDN","8004746":"KPFF","8004747":"MPD","8004748":"SPZ","8004749":"NPK","8004750":"APF","8004751":"HPAP","8004753":"MPP","8004755":"NPB","8004756":"NPAR","8004758":"NPE","8004759":"NPZ","8004760":"HP","8004761":"MPEI","8004762":"MPBG","8004763":"MPBN","8004764":"MPTN","8004765":"MPTO","8004767":"MPZ","8004770":"MPRM","8004771":"SPE","8004774":"NPET","8004775":"MPE","8004777":"HLAD","8004780":"MPFH","8004781":"MPF","8004784":"SPF","8004788":"FPD","8004796":"TPF","8004797":"NPEN","8004801":"TPW","8004803":"NPD","8004806":"MPFD","8004807":"MPFS","8004809":"MPFW","8004813":"RPB","8004814":"SPI","8004815":"MPI","8004816":"FPU","8004819":"AP, APS","8004820":"NPI","8004822":"SPS","8004826":"KPL","8004827":"MPL","8004835":"NPLF","8004838":"EPLT","8004841":"APLN","8004842":"TPL","8004847":"NPG","8004848":"APN","8004849":"NPOE","8004851":"HPOG","8004853":"NPOI","8004854":"MPO","8004858":"NPMH, NPOM","8004859":"SPOM","8004862":"APB","8004865":"NPOP","8004868":"HPTA, HPTH","8004869":"KPR, KPRH","8004873":"KPW","8004874":"MPH","8004875":"NPOH","8004878":"EPRA","8004879":"APZ","8004880":"NPS","8004881":"NPR","8004882":"NPRE","8004883":"EPRN","8004885":"MPR","8004888":"APD","8004893":"MPM","8004898":"KPUL","8004899":"MPUL","8004900":"MPU","8004901":"NPU","8004903":"APU","8004905":"EQLK","8004907":"KQ","8004908":"EQL, EQL O, EQL W","8004909":"SQS","8004910":"SQI","8004913":"ARH","8004914":"MRDD","8004917":"NRA","8004919":"HRAH","8004920":"KDHL","8004922":"MRN","8004923":"NRAF","8004924":"ARS","8004925":"MRAG","8004926":"NRAH","8004927":"MRAM","8004929":"SRCH","8004930":"TRM","8004931":"RRBI","8004932":"RRBH","8004933":"NRAB","8004935":"RRN","8004936":"NRSL","8004938":"SRAS","8004942":"FRAN","8004945":"HRST","8004948":"KRAO","8004952":"ARF","8004955":"MRA","8004960":"ERMA","8004962":"FRA","8004965":"TRB","8004966":"MRH","8004967":"KREC","8004970":"HRFD","8004971":"NRDF","8004972":"ERFE","8004975":"SRWH","8004978":"NRCH","8004979":"NRZ","8004981":"NREG","8004983":"NRPF, NRPH","8004987":"NRGF","8004988":"NRU","8004993":"SRW","8004994":"NREK","8004995":"FRHM","8004997":"RRU","8004999":"TRF","8005001":"TRXS","8005002":"TRCB","8005003":"FRSA","8005005":"NREI","8005007":"MRCH","8005008":"MRS","8005013":"RRIN","8005014":"SREI","8005015":"RRHM","8005016":"ARBK","8005019":"ARD","8005020":"FREI","8005023":"ARE","8005026":"RRSH","8005027":"FRSK","8005030":"EREK","8005031":"EEBS","8005033":"KR","8005034":"KRG","8005035":"KRLU","8005037":"RR","8005039":"FREH","8005044":"SRE","8005045":"NREN","8005047":"HRTN","8005049":"NREZ","8005050":"NRT","8005052":"TREW","8005053":"TREB","8005054":"TRES","8005055":"ERHA","8005057":"KRBL","8005058":"KRBA","8005059":"KRBE","8005062":"KRBR","8005064":"RRH","8005065":"KRHO","8005067":"RRHH","8005068":"RRW","8005069":"RRZA","8005070":"KRHE","8005071":"RRZM","8005072":"RRZU","8005073":"KRYO","8005074":"KRHD","8005077":"RRIH","8005080":"ARL","8005083":"FRID","8005086":"MRDU","8005087":"TRI","8005089":"FRIE","8005090":"RRL","8005092":"NRCK","8005094":"SRI","8005095":"ARY","8005096":"HRIE","8005097":"TRH","8005098":"RRIM","8005101":"RRI","8005102":"ERIK","8005103":"RRIT","8005104":"HRIN","8005106":"ARI","8005107":"HRTH","8005111":"SRC","8005112":"NRC","8005113":"SROA","8005116":"FRB","8005119":"HRDK","8005120":"FRO","8005121":"NROD","8005122":"NRTM","8005125":"FRFH, FRFHW","8005127":"MRM, MRMS","8005131":"FROH","8005133":"NROE","8005134":"KROE","8005136":"RROE","8005137":"HROT","8005138":"MRTA","8005139":"NRTH","8005140":"NRP","8005141":"NRPG","8005142":"NRPE","8005143":"KRST","8005146":"RRST","8005149":"MRFD","8005151":"TRO","8005152":"KROI","8005153":"KROL","8005154":"NRON","8005156":"FROL","8005157":"TROM","8005159":"KROM","8005160":"HRBG","8005161":"FRON","8005163":"FROS","8005164":"KROS","8005166":"NRNU","8005168":"TRBG","8005172":"SROB","8005177":"NRL","8005178":"NRW","8005181":"RRM","8005182":"FROF","8005184":"FRTN","8005185":"NRO","8005189":"NRBG","8005190":"NROT","8005191":"AROP","8005195":"TRR","8005197":"TRT","8005198":"NRTD","8005199":"NRHN","8005200":"TRG","8005201":"TGOL","8005202":"TRSA","8005205":"ERUD","8005207":"ARP","8005208":"FRS","8005209":"NRUE","8005213":"FRDH","8005214":"RRZD","8005217":"RRZH","8005218":"KRUN","8005219":"NRLB","8005220":"FRUE","8005221":"FRUO","8005225":"KRUM","8005227":"EROL","8005229":"FRUK","8005231":"NRST","8005236":"TRUT","8005238":"NSL","8005241":"SSO","8005243":"SSB","8005245":"SSAB","8005246":"SSLB","8005247":"SSLS","8005249":"FSAA","8005250":"NSA","8005253":"TSA","8005255":"RSAE","8005256":"ASAG","8005257":"RANS","8005258":"TSAL","8005259":"MSAL","8005260":"SSMT","8005261":"FBSS","8005262":"HSAL","8005264":"HEB","8005265":"HSB","8005269":"HSI","8005270":"HSL","8005272":"EDEF","8005274":"HST","8005275":"HSW","8005276":"ESZK","8005279":"NSND","8005282":"HSAN","8005283":"ESDB","8005285":"HSAB","8005287":"HSAK","8005288":"ASDW","8005289":"ESCI","8005292":"HSRD","8005293":"ESAS","8005298":"KSA","8005299":"MSR","8005301":"TSL","8005302":"MSGB","8005304":"NGLH","8005306":"SSU","8005311":"MSFL","8005316":"ESMU","8005317":"RSAL","8005320":"HSDL","8005321":"ASAZ","8005322":"ESMD","8005324":"HBLB","8005329":"TSEP","8005330":"ASL","8005332":"SSD","8005333":"TSK","8005334":"TSX","8005335":"RSZL","8005336":"HSCD","8005338":"ESCF","8005339":"KSEV","8005340":"HSCI","8005342":"SUZD","8005343":"HSCB","8005345":"RSDS","8005346":"SSWL","8005347":"RSCM","8005350":"RSCL","8005352":"NSG","8005355":"HSCL","8005356":"KSLA","8005362":"ASW","8005364":"RSG","8005365":"FSBA","8005366":"RSR","8005367":"MSCS","8005369":"ESHO","8005370":"ESNS","8005371":"RSLU","8005374":"FSMU","8005378":"KSMI","8005379":"TSHM","8005381":"MSCN","8005383":"NSMA","8005388":"NSNE","8005389":"MLLS","8005390":"ASDN","8005391":"NSY","8005392":"SSOF","8005393":"FSCH","8005400":"NSGN","8005405":"HSWO","8005406":"MSNG","8005412":"NSOE","8005413":"HSPP","8005415":"ESHM","8005417":"MSDF","8005418":"MSGU","8005419":"MHP, MHPW","8005420":"RSCH","8005421":"TSPF","8005423":"SSCP","8005424":"TSF","8005425":"RSCW","8005426":"RSCS","8005431":"TSCH","8005432":"MSHN","8005435":"ASC","8005436":"HSTT","8005439":"NSC","8005440":"NSCL","8005442":"MSHH","8005444":"MSMN","8005445":"TSWA","8005449":"TSHL","8005451":"NSAI","8005454":"TSWK","8005455":"FSTS","8005456":"FSLN","8005457":"HSWS","8005465":"NSW","8005466":"NSBS","8005468":"ASWA","8005469":"NSDO","8005476":"SSWE","8005479":"NSMT","8005481":"NSST","8005485":"NSWF","8005488":"KSWW","8005489":"MSWN","8005490":"RSCV","8005494":"RSZ","8005495":"MSDG","8005497":"RSST","8005498":"FSN","8005499":"KSEC","8005502":"RSEE","8005504":"MSH","8005505":"MSEG","8005506":"MSEB","8005507":"HS","8005508":"MSE","8005510":"SSE","8005511":"HSEN","8005516":"NSN","8005517":"NSS","8005518":"NSP","8005520":"NSLZ","8005522":"FSEL","8005523":"NSLI","8005525":"ESEM","8005526":"ESEB","8005532":"MSED","8005534":"ESEL","8005535":"ESES","8005536":"TSE","8005539":"SSER","8005540":"TSER","8005543":"NSF","8005544":"FSG","8005545":"NSE","8005547":"NSYB","8005551":"RSIB","8005555":"ESIH","8005556":"KSIB","8005557":"NSDF","8005560":"RSIS","8005561":"ASID","8005562":"SSBG","8005566":"TSY","8005568":"TSIH","8005569":"ESIL","8005572":"NSHU","8005574":"TSI","8005575":"KSID, KSIU","8005576":"FSL","8005577":"FSI","8005578":"RSM","8005580":"KSIZ","8005581":"NSIH, NSIN","8005582":"RSIN","8005583":"SSOB","8005586":"ASOE","8005587":"RSZM","8005588":"RSZN","8005590":"KSS","8005592":"FSOL","8005593":"MSO","8005594":"ASON","8005597":"KSGR","8005598":"KSM","8005600":"ESON","8005602":"RSOH","8005607":"MSHM","8005608":"TSON","8005609":"MSF","8005610":"FSON","8005613":"AS","8005616":"TSP","8005617":"TSPM","8005622":"KSPA","8005623":"FSPE","8005624":"SSPE","8005625":"NSKN","8005626":"RSPN","8005628":"RSP","8005629":"KSPI","8005630":"NSPU","8005635":"ESPR","8005636":"FSPO","8005637":"FSPR, FSPRN, FSPRS","8005638":"HSPR","8005639":"MSAB","8005640":"ASP","8005644":"RSGO","8005645":"FSGO","8005646":"FSGH","8005648":"RSIG","8005649":"SSI","8005652":"MKL","8005653":"MMG","8005655":"ASD","8005656":"MOTN","8005658":"SSTO","8005659":"SSWD","8005661":"FSTA","8005662":"HSHG","8005663":"ASHS","8005665":"HSDF","8005668":"FST","8005670":"NSFN","8005672":"MSTA","8005673":"SSTB","8005674":"NSM","8005675":"MSNO","8005676":"MST","8005678":"SSTH","8005682":"HSTF","8005686":"NSWH","8005688":"RSNA","8005689":"SSTA","8005690":"FSA","8005692":"NSD","8005699":"MSA","8005700":"FSFZ","8005701":"RSTN","8005702":"ESBS","8005703":"HSFD","8005704":"ESTG","8005706":"FSHM","8005708":"HSTM","8005712":"EGRK","8005713":"RSTE","8005714":"RSS","8005715":"SSTW","8005717":"ASTE","8005720":"FSTZ","8005723":"TSTD","8005725":"MSTS","8005726":"TSTE","8005731":"ESKA","8005734":"NSOK","8005735":"MSD","8005736":"FSTH","8005737":"NSTH","8005739":"FSTK","8005740":"FSTR","8005746":"KSOM","8005747":"TSGZ","8005748":"KSTZ","8005749":"MSMS","8005750":"TSTR","8005752":"NSK","8005760":"NSU","8005761":"ESTU","8005763":"HSUB","8005766":"TSEB","8005767":"TSN","8005768":"TFL","8005769":"TSC","8005770":"TSFE, TSZ F","8005771":"TSM","8005772":"TSOM","8005773":"TSRO","8005774":"TSSM","8005775":"TSU, TSU P, TSUH","8005776":"TSV","8005777":"TSZA, TSZAH","8005778":"TSZ","8005779":"TSOS","8005780":"HSUD","8005781":"ASU","8005782":"ASUE","8005783":"ASDD","8005785":"ASDF","8005786":"TSUE","8005787":"NSUE","8005788":"ASUP","8005790":"TSD","8005791":"TSUL","8005792":"TSUS","8005795":"TSBM","8005796":"SSZ","8005797":"SSZA","8005798":"FSZ","8005799":"FSZN","8005800":"NSR","8005801":"NSRH","8005802":"MSUG","8005809":"HSYK","8005810":"ESYL","8005811":"ESYH","8005812":"STB","8005820":"TTM","8005823":"TTA","8005824":"MTPF","8005825":"ATP","8005826":"ATAT","8005828":"MTA","8005831":"MTU","8005833":"MTO","8005834":"ETEL","8005835":"STS","8005836":"RTMU","8005843":"STWF","8005845":"TTL","8005852":"MTMA","8005855":"NTAS","8005857":"STN","8005858":"ATHS","8005864":"NTHM","8005865":"KTH","8005867":"ATB","8005870":"ATK","8005871":"RTI","8005874":"ATIM","8005876":"RTIT","8005885":"ATG","8005887":"ATM","8005888":"ATST","8005889":"STT","8005890":"NTB","8005891":"FTH","8005895":"NTG","8005896":"FTRE","8005901":"HTRI","8005902":"RTR","8005903":"NTRI","8005905":"STRS","8005907":"NTF","8005908":"TTO","8005910":"KTR","8005911":"TTR","8005917":"TTD","8005918":"TTLU","8005920":"MTFD","8005925":"TTUS","8005927":"MTZ","8005929":"HT","8005930":"EUBD","8005931":"RUW","8005935":"KUBP","8005937":"RUEB","8005940":"MUS","8005942":"RUEM","8005943":"RUEN","8005945":"SUG","8005946":"TTUG","8005947":"NU","8005948":"MUF","8005949":"TUH","8005950":"FUR","8005952":"TUO","8005954":"TUDT","8005955":"TU  F","8005962":"MURO","8005963":"RUN","8005966":"NUDF","8005967":"NUND","8005970":"KUN","8005971":"EUK","8005972":"FUKO","8005975":"MUAG","8005976":"NUA","8005979":"TBB","8005983":"TUE","8005986":"MUFG","8005989":"TUG","8005991":"MUH","8005993":"MUHN","8005995":"NUT","8005997":"TUK","8005998":"TUL","8006001":"HUNL","8006006":"MUG","8006008":"TURB","8006017":"NUS","8006019":"SUSZ","8006030":"TUA","8006031":"FUCH","8006032":"KURF","8006035":"KUR","8006036":"KURR","8006037":"MURS","8006039":"TURS","8006041":"HUS","8006048":"MUTG","8006052":"NVA","8006053":"TV","8006054":"KVA","8006056":"HVA","8006058":"AVF","8006059":"MVS","8006060":"HVEC","8006061":"HVCH","8006062":"AVLS","8006064":"EVLR","8006065":"NVE","8006067":"NVN","8006068":"FVOE","8006076":"HV","8006078":"HVWH","8006083":"FVR","8006085":"NVK","8006086":"NVI","8006089":"HVIN","8006090":"HVIS","8006091":"HVLO","8006094":"MVRN","8006095":"HVOE","8006098":"EVD","8006100":"SVO","8006101":"MVG","8006104":"HVOL","8006109":"EVOK","8006112":"HVOP","8006116":"HVHP","8006117":"EVRD","8006118":"EVRO","8006120":"NV","8006125":"RWCH","8006131":"MWAE","8006132":"FWAE","8006134":"NWAF","8006135":"TWHF","8006136":"FWFK","8006137":"RWG","8006139":"EWAL","8006144":"HWAZ","8006147":"NWA","8006148":"AWK","8006154":"TWG","8006155":"NWDH","8006156":"SWAB","8006157":"TWY","8006159":"RWA","8006163":"NWLM","8006167":"RWU, RWU S","8006170":"SWL","8006171":"TWH","8006172":"HWKD","8006175":"FWF","8006181":"NWLD","8006183":"FWAH","8006184":"MWHN","8006189":"MHSN","8006190":"MWKN","8006191":"KWAP","8006193":"HWSR","8006194":"EEHT","8006197":"AOW","8006198":"AWCH","8006200":"TWW","8006203":"TWAN","8006206":"EWAF","8006207":"EWEM","8006210":"MWGU","8006212":"TWV, TWVH","8006213":"AWA","8006215":"RWR","8006217":"TWA","8006218":"MWBG","8006219":"MWSG","8006222":"SWAS","8006224":"MWAS","8006226":"EWAT","8006227":"EWHP","8006229":"FWST","8006232":"FWCK","8006233":"HWED","8006236":"AWL","8006237":"HWEE","8006240":"KWEE","8006243":"KWEG","8006252":"SWE","8006256":"MWEI","8006257":"NWGR","8006258":"MWDB","8006261":"RWD","8006264":"NWDG","8006266":"NWHR","8006267":"NWHF","8006268":"TSWF","8006270":"HWUE","8006271":"TW","8006272":"RW","8006273":"RWEI","8006277":"TWEL","8006279":"MWLB","8006280":"KWES","8006281":"TWLH","8006289":"TWR","8006290":"TWRW","8006292":"RWSS","8006293":"FWEK","8006294":"TELI","8006296":"TWSN","8006298":"NWG","8006300":"NWEO","8006303":"KWEH","8006304":"FWN","8006306":"FWI","8006309":"MWZH","8006312":"FWZ","8006313":"FWES","8006315":"SWN","8006319":"AWBS","8006320":"EWSE","8006321":"RWEL","8006323":"EWVE","8006330":"AWE","8006331":"TWD","8006336":"HWSN","8006339":"EWHL","8006340":"FWDF","8006342":"EWER","8006346":"TWER","8006347":"NWRB","8006348":"EWRN","8006349":"NWFD, NWFH","8006353":"MWHA","8006356":"EWFK","8006357":"AWBU","8006358":"HWES","8006359":"MWS","8006360":"EWBH","8006361":"EWBV","8006363":"MWDF","8006366":"MWM","8006367":"HWTH","8006369":"AWLA","8006373":"TWSH","8006376":"TWX","8006378":"MWHS","8006379":"EWSM","8006380":"NWL","8006383":"EWN","8006386":"EWET","8006389":"EWIC","8006390":"NWK","8006391":"KWIC","8006392":"SWK","8006401":"FWRA","8006402":"HWRN","8006403":"NWU","8006404":"FWO","8006407":"FWE","8006408":"FWIG","8006409":"FWS","8006414":"NWDC","8006416":"TWID","8006417":"RWI","8006418":"NWIE","8006421":"RWS","8006426":"NWI","8006432":"TWIB","8006436":"HWIH","8006440":"TWL","8006441":"RWSW","8006445":"HW","8006448":"NWHD","8006449":"HWBD","8006454":"FWLM","8006455":"NWIG","8006456":"TWLB","8006459":"FWTH","8006460":"AWIR","8006461":"SWIG","8006463":"SWIN","8006465":"FWIN","8006466":"EWIL","8006468":"RWND","8006472":"NWB","8006473":"NWIN","8006475":"AWG","8006476":"NWKH","8006479":"TWI","8006481":"SWI","8006482":"HWIN","8006483":"SWNW","8006484":"AWI","8006485":"TWIN","8006486":"EWTB","8006488":"NWN","8006489":"AWIM","8006498":"KWIR","8006499":"FWIR","8006501":"EWIN","8006503":"HWIS","8006505":"EWIK","8006508":"RMHH","8006509":"RMLB","8006510":"EWIA","8006511":"RMNS","8006513":"TSUN","8006514":"EEHH","8006516":"KWIS","8006517":"TWIT","8006520":"HWTM","8006524":"FWZN","8006527":"AWRT","8006528":"FWX","8006529":"FWOE","8006531":"RWRZ","8006533":"MWNS","8006534":"FWRR","8006535":"FWOD","8006536":"RWRD","8006537":"MWTI","8006541":"AWLF","8006544":"RWO","8006545":"TWO","8006546":"FWON","8006548":"FWFG","8006550":"MWO","8006552":"HWOB","8006554":"NWM","8006555":"SWFS","8006559":"AWOL","8006561":"HWWI","8006570":"AWRE","8006572":"AWST","8006575":"EWAP","8006577":"EWGD","8006578":"EWGT","8006581":"SWB","8006582":"NWS","8006586":"NWZ","8006588":"NWBZ","8006590":"EWUF","8006592":"HWUL","8006596":"KWBA","8006607":"KWL, KWLP","8006616":"KWRO","8006618":"KWSO","8006619":"KWS","8006620":"KWU","8006623":"KWZ","8006624":"NWLZ","8006625":"TWUM","8006626":"TWUN","8006627":"SWU","8006629":"RWY","8006630":"KX","8006634":"NZA","8006635":"NZ","8006641":"RZ","8006642":"TEZL","8006643":"FZK","8006644":"FZR","8006646":"FZH","8006648":"FZEP","8006659":"KZI","8006660":"NZF","8006661":"RZIM","8006662":"TZI","8006663":"FZM","8006664":"NZI","8006666":"NZIK","8006667":"RVLZ","8006670":"MZHP","8006671":"MZO","8006672":"RZT","8006673":"KZU","8006676":"TZU","8006678":"RZHN","8006679":"RZUN","8006680":"SZW","8006684":"NZWL","8006685":"NZWU","8006686":"RZW","8006687":"FZW","8006688":"MUSM","8006690":"FFGA","8006691":"FFTA","8006692":"FHAU","8006696":"MNPS","8006698":"TSS","8006699":"TSFS","8006700":"TSMI","8006704":"ALTK","8006705":"ARES","8006706":"AKS","8006707":"FHMD","8006709":"EDRN","8006710":"EBOH","8006711":"EBOW","8006712":"EHGW","8006713":"KLMH, KLMI","8006714":"KSV","8006717":"MVAD","8006718":"KWV","8006719":"KWO","8006730":"MNM","8006743":"TSNS","8006745":"NSTT","8006749":"AHFS","8006750":"ANWS","8007273":"AWAH","8007357":"SURM","8007441":"RNST","8007442":"RWB","8007443":"RESN","8007444":"RHM","8007445":"RAG","8007482":"SRAM","8007768":"HNDM","8007790":"ANSW","8007856":"NWDM","8007857":"RSAI","8007858":"RSFL","8007859":"RKPW","8007860":"RSHF","8007868":"SLCJ","8010001":"DAD","8010003":"LA","8010004":"WA","8010006":"DAF","8010007":"UA","8010008":"LACF","8010009":"LAL","8010011":"DAUO","8010012":"DAUU","8010013":"LBB","8010014":"UBL","8010016":"WDO","8010017":"WFW","8010018":"WK","8010019":"UKO","8010020":"ULS","8010021":"USZ","8010022":"DSA","8010026":"DBZ","8010029":"BBES","8010031":"BBIG","8010032":"UBK","8010033":"WBG","8010035":"BKH, BKLH","8010036":"BLI, BLO","8010040":"DKUR","8010041":"BSW, BSWP","8010043":"LBG","8010044":"DBF","8010046":"LBEU","8010047":"LBZ","8010048":"UBKN","8010049":"DBW","8010050":"LBT","8010051":"WBL","8010053":"BBF, BBFD","8010054":"UBM","8010055":"UBD","8010056":"LBLG","8010059":"LBOR","8010060":"LB","8010061":"UBR","8010064":"WBR","8010066":"WB","8010067":"UBF","8010069":"BC","8010070":"LCBO","8010071":"LCBW","8010072":"DCW","8010073":"BCS","8010074":"DCR","8010076":"LDL","8010077":"LD","8010078":"LDB","8010079":"BDKO, BDKU","8010080":"DDE","8010081":"UDST","8010084":"LGND","8010085":"DH","8010086":"LMR, LMRH","8010088":"DKT","8010089":"DN, DN  A","8010091":"DRR","8010092":"DEB","8010093":"WE","8010094":"DEIB","8010095":"LEG","8010096":"LEI","8010097":"UEI","8010099":"BEW","8010100":"BEB","8010101":"UE, UE  P","8010102":"UEN","8010103":"LF, LF  O, LF  U","8010105":"UEIP","8010106":"DFA","8010108":"DFL","8010109":"BFHS, BFLH","8010110":"UF","8010111":"BFO","8010113":"BFP","8010115":"DFR","8010116":"DFH, DHG","8010117":"WTV","8010118":"UFT","8010119":"LFE","8010120":"BFUW","8010121":"LGG","8010122":"LGH","8010123":"LGN","8010124":"URD","8010125":"UG","8010126":"UGS","8010129":"DGL","8010130":"DGLS","8010131":"DG","8010133":"UGW","8010134":"DGZ","8010136":"UGO","8010137":"UGD","8010139":"WGW","8010140":"UGR","8010141":"WGV","8010142":"UGM","8010144":"DGR","8010145":"UGH","8010146":"LGC","8010150":"BGRU","8010151":"LGSN","8010152":"LGT","8010153":"WG","8010154":"LGK","8010155":"LHME","8010156":"WHL","8010157":"LHB","8010158":"LHL","8010159":"LH, LHG","8010160":"LHN","8010161":"LEGO, LEGOB","8010162":"LHAD, LHADB","8010163":"DHD","8010166":"DHN","8010168":"LHE","8010169":"LHR","8010170":"UHR","8010171":"BHC","8010172":"LHWU","8010173":"WHO","8010174":"BHOR, BHR","8010175":"WNRR","8010176":"WHOR","8010177":"BHW","8010178":"UI","8010179":"WJK","8010182":"BJUE","8010183":"BSEO","8010184":"DC","8010185":"DCD, DCS","8010186":"LKRS","8010189":"BKI","8010191":"LKM","8010193":"BKW","8010194":"LKO","8010195":"LK","8010196":"UKS","8010198":"UKU","8010199":"WLD","8010201":"WLG","8010202":"DLH","8010203":"UL","8010204":"LKMR","8010205":"LL, LL  T","8010206":"LLC","8010207":"LLEL","8010208":"LLPD, LLPDH","8010209":"LLP","8010210":"WLI","8010212":"DL","8010213":"WLK","8010214":"WLO","8010215":"BLF","8010216":"WL","8010217":"BLB","8010220":"BLN","8010222":"LW","8010224":"LM","8010226":"LMN","8010227":"WMA","8010228":"LMAG","8010229":"DMEH","8010230":"UM","8010231":"LMEI","8010232":"LMG","8010233":"BMIP","8010234":"DMHD","8010235":"UMH","8010236":"BMB","8010238":"LNA","8010239":"BNAU","8010240":"UNM","8010241":"WN","8010242":"UND","8010243":"LNK","8010244":"DNM","8010246":"WNRW","8010248":"WNS","8010249":"DNE","8010250":"WNT","8010253":"DNR","8010254":"LNHG","8010255":"BHF, BOSB","8010256":"UN","8010259":"DOZ","8010261":"LOE","8010264":"UO","8010266":"LO","8010267":"WPM","8010268":"WP","8010269":"LPG","8010272":"DPI","8010273":"WPZ","8010274":"UPL","8010275":"DP","8010279":"BPDP","8010280":"BPDC","8010281":"LPT","8010282":"WPL","8010284":"WPI","8010285":"DPR","8010287":"WPR","8010288":"UPR","8010290":"LQB","8010291":"LQ","8010292":"DRB, DRB B","8010293":"DRBK, DRBW","8010296":"LRW","8010297":"DR","8010299":"LRN","8010300":"WRV","8010301":"DRON","8010302":"LR","8010304":"WR","8010305":"URTB","8010306":"UR","8010307":"URS","8010308":"BRU","8010309":"US","8010310":"LSW","8010311":"LSL","8010312":"USG","8010315":"USM","8010317":"DSB","8010318":"LSB","8010321":"LSH","8010322":"WSN","8010324":"WS","8010325":"WSGN, WSGR","8010327":"BSN","8010328":"USD","8010329":"USH","8010330":"BSP","8010331":"DEG","8010332":"LSF","8010333":"DSPH","8010334":"LS","8010335":"LSS","8010336":"DSRB","8010337":"DSTO","8010338":"WSR","8010339":"WSB","8010341":"BST, BSTV","8010342":"USF","8010343":"LSTF","8010345":"USL","8010347":"WT","8010348":"WTE","8010349":"UTEU","8010350":"UTH","8010351":"LTG","8010352":"UTR","8010353":"BUK","8010354":"UUTL","8010355":"WV","8010357":"BGU","8010359":"DWA","8010361":"WWR","8010364":"LWEG","8010365":"UWE","8010366":"UWM","8010367":"DWS","8010368":"UW","8010370":"BWW","8010371":"BWR, BWRO, BWRU","8010372":"DWR","8010373":"BWE","8010374":"LWD","8010375":"UWH","8010376":"BWG","8010377":"BWP","8010378":"BWHO","8010380":"DWT","8010381":"WWI","8010382":"WW","8010383":"DWIO","8010384":"WWK","8010385":"UWK","8010386":"BWRZ","8010387":"UWF","8010388":"DWD","8010389":"BWUS","8010390":"LZ","8010391":"UZL","8010393":"DZ","8010395":"BZO","8010396":"WZS","8010397":"DZW","8010398":"DZA","8010399":"WF","8010400":"DNKW","8010403":"BCHB, BCHS","8010404":"BSPA, BSPD","8010405":"BWS, BWSS","8010406":"BZOO, BZOS","8011003":"BAF, BAHR","8011004":"BAFR","8011005":"BAFN","8011011":"WAHU","8011014":"BARO","8011016":"BAD","8011017":"WAF","8011018":"LALT","8011019":"DAG","8011025":"WATR","8011027":"WALW","8011028":"UACH","8011029":"UAMM","8011031":"WAH","8011033":"DAMD","8011034":"BART","8011038":"LAMS","8011039":"DAMH","8011042":"LANG","8011043":"LAG","8011044":"WAK","8011046":"BKAR, BKRW","8011048":"LAB","8011051":"UAP","8011053":"LAF","8011054":"UAR","8011055":"UASD","8011057":"UAE","8011058":"UJS","8011059":"DAUH","8011064":"BAHH","8011065":"UB","8011066":"UBB","8011067":"UBBZ","8011068":"DBM","8011071":"LDBG","8011072":"DBEL","8011074":"UBKZ","8011077":"LBLS","8011078":"BBLW","8011079":"BBSP","8011085":"UBS","8011088":"WWIL","8011091":"DBJ","8011093":"BBKL","8011095":"DBAG","8011097":"BBG","8011098":"BBO","8011100":"BBAI","8011102":"BGB, BGS","8011103":"UBGS","8011106":"UBAS","8011111":"LBAR","8011112":"LBAS","8011113":"BPAF, BSKR, BSKV","8011115":"DBAM","8011116":"BBA","8011119":"LBBZ","8011125":"WBES, WBESD","8011131":"LBEI","8011132":"LBGH","8011133":"LBLL","8011138":"UBEN","8011139":"UBH","8011140":"WBE","8011144":"UBGE","8011149":"WBER","8011150":"LBWZ","8011154":"BBKR","8011155":"BALE, BALX","8011160":"BHBF, BL, BLS","8011162":"BOK, BOKN, BOKO, BOKR, BOKS","8011168":"LBGF","8011169":"LBGS","8011170":"LBGW, LBWD","8011172":"UBE","8011173":"BBST","8011177":"LBEN","8011178":"UBEU","8011179":"BBE","8011181":"LBYD","8011183":"UBA","8011184":"LBF","8011185":"DBIE","8011187":"LBSR","8011188":"WBT","8011190":"LBIF","8011191":"WBI","8011199":"DBH","8011205":"WBLS","8011206":"UBN","8011208":"UBHA","8011210":"LBD","8011211":"BBLU","8011213":"WBLK","8011215":"WBO","8011219":"UBOD","8011222":"LBWE","8011226":"LBOK","8011228":"LBOE","8011230":"WBZ","8011238":"BBK","8011242":"LBL","8011248":"WBRH","8011250":"BBRA","8011252":"LBA","8011255":"LBS","8011256":"LBSO","8011257":"DBDL","8011258":"WBDN","8011260":"LBN","8011264":"DBTD","8011265":"UBRT","8011267":"UBZ","8011269":"BBSN","8011270":"WBTF","8011271":"BBRK","8011277":"LBRP","8011281":"WBUH","8011282":"BBUZ","8011284":"BBUW","8011290":"LBZG","8011293":"WBSG","8011294":"LBU","8011296":"LBGK","8011297":"DBU","8011298":"DBWD","8011302":"LBOW","8011304":"UBU","8011306":"BFRI, BFST, BFSTT","8011307":"WCA","8011308":"BCAP","8011311":"WCW","8011312":"UKSO","8011314":"WCOK","8011315":"DCL","8011318":"BCSO, BSDO","8011319":"BCO","8011320":"DCB","8011322":"LCW","8011323":"LCBS","8011325":"DCU","8011326":"WCZ","8011334":"BDAB","8011335":"UDA","8011336":"UDW","8011339":"LDA","8011340":"BDT","8011344":"WDWE","8011346":"LDAR","8011354":"DDT","8011355":"LDK","8011356":"WDM","8011361":"LDS","8011363":"LDAL","8011364":"LDMO","8011371":"LDTZ","8011376":"LDI","8011378":"UDN","8011383":"LDT","8011385":"DDIF","8011387":"LDOB","8011388":"LDF","8011390":"LDO","8011397":"UDOE","8011398":"DDO","8011399":"DKTF","8011402":"LDN","8011403":"WDS","8011406":"UDG","8011408":"WDOW","8011409":"BDF","8011414":"BDR","8011415":"LDD","8011416":"DBPL","8011417":"DGRS","8011418":"DIG","8011419":"DCT","8011420":"DD","8011421":"DKE","8011422":"DNSH","8011423":"DPS, DPSA","8011424":"DRK","8011425":"DSTT","8011426":"DSTH","8011427":"DTR","8011428":"DZSW","8011430":"BDW","8011431":"DHFR","8011433":"LDM","8011438":"WDU","8011442":"WDT","8011446":"DEBR","8011449":"UEK","8011450":"UEC","8011451":"DKR","8011453":"UEFT","8011455":"LEGD","8011456":"WEGS","8011460":"LEST","8011462":"LEF","8011468":"UEIW","8011471":"BEHS","8011472":"UED","8011476":"UELG","8011477":"DLD","8011480":"UER","8011481":"WELM","8011482":"BEZ","8011484":"LEK","8011486":"LELT","8011487":"UELB","8011488":"UELK","8011489":"UEX","8011491":"LE, LE  H","8011495":"LEW","8011496":"LER","8011500":"UEO","8011502":"UEBI","8011503":"UEGI","8011507":"DER","8011512":"UERN","8011519":"UEH","8011520":"UET","8011523":"WEV","8011529":"DFUS","8011531":"WFBG","8011533":"BFS","8011536":"WFDF","8011537":"LFMW","8011540":"BFIH","8011541":"BFIN","8011542":"BFW","8011544":"LFG","8011545":"LFL","8011549":"LFD","8011550":"LFDE","8011553":"DFK","8011554":"DFKS","8011556":"DFRS","8011557":"BFPN","8011559":"BFRS","8011560":"LFA","8011563":"BFR","8011564":"LFK","8011567":"UFO","8011569":"DFD","8011570":"DHGW","8011571":"LFZ","8011572":"WFD","8011573":"UFB, UFB B","8011574":"BFDF","8011578":"UFR","8011582":"WFRR","8011585":"WFRK","8011586":"LFI","8011587":"LFIO","8011588":"LFB","8011591":"BFUS","8011592":"WGA","8011594":"UGSM","8011596":"LGA","8011598":"LGW","8011599":"LGAL","8011602":"UGBH","8011603":"UGB","8011609":"DGEI","8011611":"WGE","8011619":"UGLB","8011623":"UGZ","8011624":"UGBG","8011626":"LGE","8011628":"DGD","8011629":"UGT","8011630":"LGWS","8011632":"LGI","8011636":"DGHU","8011637":"DGLA","8011641":"WGF","8011643":"UGL","8011646":"WGNV","8011654":"LGOR","8011656":"DGWH","8011657":"UGSB","8011662":"LGOE","8011665":"LGM","8011667":"BGM","8011668":"BGO","8011671":"WGOL","8011672":"BGZ","8011673":"LGO","8011674":"BGOR","8011676":"DKH","8011678":"UGOS","8011681":"WGRB","8011683":"LG","8011685":"LGRK","8011687":"UGTA","8011689":"WGR","8011691":"WGRA","8011694":"WGWS","8011695":"BGBS, BGRI","8011697":"UGRD","8011699":"LGPN","8011700":"UGN","8011702":"WGBN","8011703":"LGB","8011705":"LGRI","8011707":"WGI","8011709":"DGO","8011711":"LGOH, LGOS","8011712":"DGT","8011714":"LGRL","8011718":"WGB","8011723":"WGKW","8011725":"LGZ","8011726":"WGLS","8011729":"WGLI","8011730":"WGP","8011735":"WGS","8011740":"BGSB, BGSBS","8011745":"LGD","8011746":"UGG","8011749":"DGC","8011750":"UGFA","8011751":"DGRT","8011752":"LGKL","8011753":"LGL","8011754":"UGNH","8011755":"LGP","8011756":"BGR","8011758":"DGRF","8011759":"UGRU","8011761":"DGAU","8011762":"UGC","8011763":"LGS","8011766":"LGWU","8011770":"DGN","8011771":"LGRA","8011773":"DGBA","8011776":"WGRG","8011778":"WSRB","8011788":"BGSW","8011790":"DGF","8011791":"UGU","8011792":"UHSN","8011794":"LHD","8011795":"BHAH","8011796":"LHMT","8011797":"WHK","8011799":"DHW","8011801":"DHND","8011802":"DHA","8011805":"BHB","8011808":"LHBO","8011809":"LHBS","8011813":"LHNI","8011814":"LHT, LHTS","8011815":"WHAM","8011818":"BHGB","8011820":"UH","8011821":"UHNO","8011822":"UHRS","8011825":"DHMU","8011834":"UHAU","8011838":"LHEW","8011843":"DHDS","8011844":"DHDG","8011848":"WHEG","8011849":"UHT","8011852":"UHD","8011853":"BHEL","8011855":"DHLF","8011860":"UHRH","8011861":"DHS","8011862":"UHK","8011863":"BHE","8011864":"WHB","8011867":"LHZW","8011869":"UHET","8011871":"UHN","8011878":"DHE","8011891":"UHOO","8011894":"BHL","8011895":"UHOL","8011900":"LHRA","8011901":"BHH, BHSH","8011904":"DHO","8011905":"LHM","8011908":"WHOL","8011909":"LHZ","8011910":"UHF","8011912":"DHU","8011913":"LHSN","8011914":"LHGT","8011915":"UHP","8011922":"BHWN","8011923":"BHUB","8011924":"WHU","8011925":"UHUE","8011928":"DHUN","8011929":"LIB","8011932":"UIR","8011933":"LIG","8011934":"UIM","8011935":"UIP","8011937":"DIR","8011940":"BJF","8011944":"BJW","8011945":"BJWO","8011946":"LJV","8011951":"WJAS","8011952":"LJEB","8011953":"WJER","8011956":"UJP","8011957":"UJW","8011958":"UJZ","8011959":"LJES","8011960":"LJN","8011961":"LJZ","8011962":"WJT","8011963":"DJA","8011966":"DJZ","8011968":"BJA, BJAB","8011970":"DCKI","8011971":"DCM","8011974":"DCBH","8011979":"DCC","8011980":"DCSI","8011981":"BKAB","8011983":"LKF","8011985":"UKA","8011988":"DKA","8011993":"UKF, UKF B","8011994":"WKT","8011995":"WKAR","8012000":"UKL","8012002":"WKV","8012006":"BKE","8012007":"UKIE","8012009":"WKJ","8012011":"LKIM","8012012":"UKI","8012014":"LKD, LKD H","8012016":"BKDF","8012021":"WKB","8012033":"UKFA","8012034":"UKJ","8012036":"DKRD","8012037":"DKMA","8012040":"LKK","8012043":"BKG","8012044":"DKC","8012045":"DKN","8012046":"LKLM","8012047":"BKL","8012053":"DKLB","8012061":"BKOD","8012064":"UKOE","8012066":"LKB","8012067":"DKB","8012072":"DKO, DKOH","8012075":"UKZ","8012079":"DKTW","8012080":"LKTU","8012083":"BKOW","8012084":"BKOS","8012088":"UKR","8012089":"BFIK","8012092":"UKD","8012093":"WKG","8012096":"BKRM, BKRMM","8012097":"LKNZ","8012105":"DKRP","8012107":"UKPR","8012108":"WKR","8012109":"WKRP","8012113":"DKRU","8012114":"LKRP","8012115":"DKU","8012117":"LKUH","8012127":"WKUM","8012129":"BKUM","8012138":"DRAT","8012141":"LKYA","8012143":"WLA","8012145":"BLW","8012146":"WLAK","8012147":"LLBG","8012148":"LLAS","8012150":"DLAB","8012155":"ULF","8012156":"LLGS","8012159":"ULAO","8012160":"ULAW","8012161":"LLAG","8012162":"LLWD","8012163":"DLW","8012164":"DLWM","8012167":"ULCH","8012169":"BLH","8012170":"DLST","8012171":"ULA","8012174":"DLZ","8012175":"BLA","8012178":"LLSB","8012180":"ULE","8012181":"LSEL","8012183":"LFLU","8012184":"LLB","8012186":"LLMK","8012187":"LMDR","8012188":"LLG","8012190":"LLH","8012192":"LLK","8012193":"LLMH","8012194":"LLST","8012195":"LLT","8012196":"LLN","8012197":"LLW","8012198":"DLS","8012199":"ULL","8012200":"LLES","8012202":"LLWP","8012203":"DLFD","8012204":"LSVS","8012205":"BLTS","8012207":"ULBN","8012211":"LLWN","8012212":"LLWS","8012213":"ULEU","8012215":"BLE","8012220":"DLIG","8012221":"WLH","8012223":"DLTS","8012224":"DLI","8012225":"ULIT","8012226":"WLBT","8012228":"LLWZ","8012231":"DLIM","8012232":"DLM","8012233":"LLI","8012236":"LLIN","8012237":"BLNG","8012241":"LLO","8012249":"DLO","8012250":"BLOH","8012252":"ULHO","8012253":"BSTH","8012257":"BLU","8012259":"LLUC","8012260":"BLD","8012262":"WLOW","8012263":"LLBS","8012264":"WLST","8012268":"WLF","8012269":"WLW","8012271":"WLKL","8012274":"WLTW","8012279":"LEL","8012280":"LWET","8012282":"LWP","8012284":"LMAC","8012285":"LLA","8012287":"LMSO","8012289":"LMGE","8012291":"LMSA","8012292":"LMS","8012295":"LMW","8012300":"LMAS","8012302":"LMBN","8012304":"LMAN","8012305":"LMAR","8012308":"LMA","8012309":"LMAM","8012311":"LMKS","8012312":"UML","8012314":"UMAH","8012315":"BMQU","8012316":"WMTF","8012317":"UMT","8012318":"DMEA","8012320":"UME","8012321":"WMK","8012322":"BMZ","8012323":"DMA","8012326":"DME","8012327":"DMT","8012328":"LME","8012329":"WMCH","8012332":"UMEN","8012333":"UMGH","8012334":"UMHO","8012339":"LMGB","8012341":"BMZD, BMZDN","8012342":"LMF","8012343":"LLVD","8012344":"LMIA","8012351":"LMST","8012352":"LMT","8012354":"LMI","8012355":"LMIZ","8012358":"WMI","8012362":"WMIS","8012367":"UMSK","8012369":"DMW","8012370":"BMX","8012371":"LMRN","8012373":"LMGI","8012375":"LMLK","8012376":"WMOE","8012377":"WMN","8012378":"LMGN","8012381":"LMOS","8012384":"WMOI","8012388":"DML","8012390":"LMCH","8012391":"BMC","8012392":"LMCZ","8012393":"LMUA","8012394":"DMHL","8012400":"BMR","8012401":"UMU","8012407":"DMUL","8012408":"DMH","8012409":"LMD","8012410":"LNHM","8012412":"DNA","8012413":"WNAS","8012414":"LNAU","8012415":"UNMO","8012416":"LNH","8012417":"UNE","8012418":"WNL","8012421":"WNA","8012423":"LNI","8012424":"LNDG","8012425":"LNS","8012428":"WNED","8012429":"UNRO","8012430":"DNZU","8012436":"WNWO","8012438":"WNB","8012440":"UAT","8012443":"UNS","8012445":"BT","8012452":"UNHI","8012454":"DNF","8012456":"BNH","8012458":"BNE","8012460":"DNKO","8012463":"LNWY","8012465":"UNME","8012467":"LN","8012468":"UNH","8012469":"BNP","8012470":"DNP","8012471":"DNZ","8012472":"UNU","8012474":"WNG","8012475":"BNTB","8012478":"LNW, LNW H","8012479":"BNZ","8012482":"DNDR","8012483":"DNBO","8012485":"WNW","8012487":"LNF","8012489":"BNDL","8012490":"LNR","8012491":"DNOW","8012492":"UNDO","8012493":"UNP","8012494":"UNIW","8012497":"DNDS","8012498":"UNSK","8012500":"UNI","8012502":"UNTA","8012503":"DNI","8012504":"UNWL","8012505":"DNWZ","8012506":"LNM","8012507":"LNB","8012509":"DNB","8012511":"UNOH","8012512":"UNA","8012516":"UNSA","8012523":"DNUN","8012524":"UOGR","8012526":"LOH","8012527":"UOLA","8012528":"DOBL","8012530":"DOZO","8012532":"UOR","8012533":"UORO","8012534":"DOH","8012535":"DOSC","8012537":"BOB","8012540":"DOG","8012541":"UOB","8012546":"LOL","8012549":"BOD","8012550":"DOR","8012551":"BOEG","8012552":"LOEH","8012553":"DOE","8012554":"DOV","8012555":"WOE","8012563":"UOG","8012565":"BORT","8012567":"UOM","8012568":"LOB","8012570":"LOST","8012572":"LON","8012576":"DOU","8012582":"WGMS","8012583":"WGM","8012584":"WGMW","8012593":"DOF","8012594":"DOK","8012595":"DON","8012596":"DOS","8012597":"LOTW","8012599":"LOV","8012603":"WPF","8012604":"UPM","8012605":"BPA","8012609":"WPA","8012610":"WPO","8012611":"WPS","8012614":"WPAU","8012615":"UPA","8012619":"LPE","8012621":"BPO","8012622":"WPB","8012623":"LPB","8012627":"WPE","8012628":"BPE","8012629":"LPRO","8012636":"BPIL","8012637":"WPIN","8012639":"DPK","8012640":"DPIC","8012641":"DPIN","8012643":"WPLM","8012646":"DPW","8012650":"BP","8012651":"WPSW","8012654":"WPOE","8012656":"LPOE","8012657":"UPS","8012658":"UPSU","8012660":"DPOM","8012661":"DPO","8012662":"DPSC","8012663":"UPF","8012666":"BPD, BPDH","8012668":"LPZ, LPZH","8012669":"LPZS","8012673":"LPRZ","8012675":"UPZ","8012676":"LPI","8012677":"WPRZ","8012678":"LPRL","8012679":"DPRO","8012680":"DPRW","8012681":"BPW","8012682":"LPR","8012683":"WPRA","8012684":"WPRO","8012685":"DPUL","8012688":"DPT","8012697":"LRK","8012698":"BRAD","8012699":"DRAG","8012700":"DRBT","8012701":"DRBZ","8012703":"WRDN","8012704":"LRA","8012705":"LRI","8012707":"LRH","8012710":"WRAK","8012711":"WRMB","8012713":"BRSF","8012716":"WRW","8012719":"DRD","8012723":"URAU","8012724":"DRU","8012727":"DRBG","8012729":"WRDL","8012731":"LRB","8012733":"BRC","8012734":"LRF","8012735":"BRE","8012737":"WRA","8012738":"DRCH","8012739":"DRC","8012742":"URN","8012743":"URDN","8012750":"URH","8012751":"URM","8012756":"URR","8012757":"LRE","8012758":"WRST","8012759":"DRTH","8012762":"WRIO","8012763":"WRI","8012766":"URIE","8012767":"BRI","8012769":"URGS","8012770":"URI","8012775":"DROW","8012777":"LROD","8012781":"DRDF","8012785":"WRGT","8012787":"UROH","8012788":"LROI","8012796":"UROS","8012801":"WRHP","8012803":"WRB","8012805":"WRHO","8012806":"WRK","8012807":"WRMA","8012811":"UROT","8012816":"BRO","8012817":"LRMF","8012819":"WRZ","8012823":"DRUG","8012824":"WRU","8012826":"USAE","8012830":"LSAD","8012831":"BSAH","8012832":"WSAG","8012835":"WSAM","8012839":"WSAF","8012840":"WSAN","8012841":"WSTZ","8012843":"WSZ","8012852":"USCK","8012854":"USKM","8012855":"BSH","8012856":"WST","8012862":"LSIS","8012863":"LSDW","8012864":"DSWK","8012865":"LSD","8012867":"LSP","8012869":"DGRA","8012870":"BSFE","8012881":"USMS","8012888":"DSMI","8012889":"DSM","8012890":"DSML","8012895":"BSB","8012897":"BSNZ","8012898":"DSN","8012899":"USU","8012902":"WSBG","8012903":"BSBD","8012907":"LSBE","8012908":"DSCK","8012914":"BSOE","8012918":"WSCN","8012919":"USCS","8012923":"BSCH","8012927":"USP","8012929":"USWL","8012933":"WSAH","8012934":"BSHE","8012940":"WSMI","8012941":"BSRO","8012942":"BSKL","8012943":"WSC","8012944":"WSCT","8012946":"DSKH","8012947":"DSU","8012951":"WSS","8012953":"WSL","8012954":"WSWZ","8012957":"BSIS","8012959":"DSEB","8012960":"WSMH","8012961":"USE","8012965":"USB","8012966":"BSEE","8012967":"LSNA","8012968":"WSEE","8012973":"BSLO","8012975":"DSRH","8012981":"DSEN","8012984":"USEL","8012993":"USI","8012998":"USGN","8013002":"DSOL","8013003":"DSOH","8013004":"USOL","8013005":"LSK","8013008":"USO","8013009":"USON","8013010":"USOO","8013011":"USOW","8013017":"WSP","8013018":"WSPO","8013021":"BSTA, BSTAB","8013022":"DWH","8013023":"USTM","8013025":"USR","8013029":"DSTU","8013033":"DSTI","8013034":"USTN","8013036":"USTA","8013037":"USTH","8013039":"LSFD","8013040":"WSNB","8013046":"LSV","8013047":"DSTN","8013051":"WSE","8013057":"DSTL","8013058":"BSTW","8013061":"USHM","8013062":"WSRR","8013064":"BSTN","8013069":"WSTK","8013070":"LSTG","8013072":"WSBN","8013073":"WSLT","8013074":"USUE","8013077":"USLH","8013079":"WSU","8013080":"DSY","8013083":"LTH","8013084":"LTM","8013085":"LTMW","8013087":"DTA","8013089":"UTA","8013090":"WTA","8013092":"DTB","8013093":"LTC","8013095":"LTNH","8013097":"LTE","8013100":"BTL","8013104":"WTHN","8013105":"WTOW","8013106":"WTI","8013109":"BTPI","8013110":"LTT","8013111":"LTTO","8013112":"LTL","8013114":"DTH","8013115":"LT","8013123":"BTHR","8013124":"DTFN","8013125":"LTLM","8013129":"UTP","8013131":"WTO","8013137":"BTN","8013138":"LTRL","8013141":"BTZ","8013144":"DTRE","8013145":"BTZN","8013146":"BTZS","8013150":"UTB","8013156":"WUMH","8013158":"LUS","8013159":"UUD","8013160":"LUEB","8013162":"WUM","8013164":"UUS","8013165":"BUD","8013166":"BUS","8013168":"DUD","8013171":"UUZ","8013172":"UUM","8013174":"UUW","8013177":"WUTZ","8013179":"UVA","8013180":"LVA","8013182":"LVT","8013183":"BVLZ","8013184":"UVF","8013185":"BVLT","8013186":"WVE","8013188":"BV","8013191":"UVU","8013192":"UVI","8013194":"LVG","8013198":"WVOG","8013201":"DVO","8013202":"UVO","8013205":"LWH","8013210":"BWA","8013215":"UWD","8013217":"UWAL","8013220":"LWWZ","8013221":"UWL","8013222":"WWL","8013223":"UWN","8013224":"UWNS","8013226":"UWA","8013230":"LWAN","8013236":"WWM","8013237":"WWMW","8013238":"WWAN","8013244":"UWTL","8013245":"UWS","8013247":"DWSN","8013248":"LWF","8013250":"LWST","8013251":"UWEM","8013253":"DWEI","8013254":"UWEA","8013256":"UWMB","8013258":"WWSN","8013259":"LWG","8013261":"UWWE","8013266":"UWMT","8013267":"DWE, DWEW","8013268":"DWX","8013269":"DWXB","8013271":"LWL","8013272":"BWZ","8013275":"LWND","8013279":"WWLS","8013280":"DWND","8013285":"BWER","8013286":"LWDE","8013291":"UWTH","8013295":"DWES","8013297":"LWZE","8013305":"BWSU","8013313":"WWLD","8013315":"UWIR","8013318":"UWIP","8013319":"LWIP","8013322":"WWT","8013324":"DWIM","8013329":"UWLH","8013333":"UWOF","8013334":"UWOL","8013335":"LWO","8013336":"LWOR","8013344":"LWLS","8013345":"BWOL","8013348":"DWU","8013349":"UWFN","8013350":"BWUE","8013352":"WWSF","8013354":"WWST","8013357":"LWU","8013360":"UWCH","8013361":"LWZ","8013362":"LWZW","8013365":"LWUZ","8013366":"UWU","8013368":"DZT","8013370":"WZN","8013371":"LZA","8013373":"WZAR","8013376":"BZS","8013377":"WZE","8013378":"WZEN","8013381":"DZNH","8013383":"UZLW","8013384":"LZD","8013389":"LZE","8013392":"BZF","8013393":"WZIN","8013396":"UZU","8013398":"UZE","8013402":"LZI","8013406":"BZIL","8013413":"DZL","8013414":"LZBR","8013418":"LZGL","8013424":"DZSC","8013425":"LZBN","8013428":"LZS","8013432":"LSBU","8013433":"DZWP","8013436":"DZWZ","8013437":"DZWO","8013439":"LBK","8013444":"DM","8013445":"DPA","8013447":"LGDG","8013448":"LHSS","8013450":"DCH, DCHP","8013452":"ULB","8013455":"LMHR","8013456":"LMB","8013461":"DOT","8013465":"LSBF","8013467":"BBEL","8013468":"BBZS","8013470":"BBER, BBRN","8013471":"LBO","8013472":"BBRI","8013474":"UCB","8013475":"DF","8013476":"DPL","8013477":"BE, BERK","8013479":"BFKS","8013480":"BFLZ","8013481":"BGOL","8013483":"BHD, BHND","8013485":"LMTW","8013487":"BOR, BORB","8013489":"BPOT","8013490":"DRBN","8013492":"BSE, BSE M","8013493":"BNY","8013547":"UHL","8013548":"UHER","8017041":"MGRI","8017042":"MUGR","8017442":"DPM","8070002":"BBIS","8070003":"FFLF","8070004":"FFLU","8070005":"THDV","8070086":"HKWA","8070088":"FMHD","8070090":"FOMP","8070091":"FOLM","8070092":"FOKL","8070096":"RAM","8070097":"RSMM","8070170":"RDUN","8070483":"KMAH","8070704":"KASZ","8070734":"HNMU","8073410":"LZIO","8077434":"RNHF","8077771":"RRZB","8077773":"RST","8079056":"TTUZ","8079069":"EOLT","8079083":"SNO","8079089":"TAEW","8079095":"HHN","8079097":"HLEA, HLEG","8079140":"KKBL","8079146":"RNFL, RNFS","8079147":"SHW","8079151":"FWED","8079152":"LVTT","8079604":"WTIW","8079605":"AHZH","8079616":"RSII","8079629":"WRTF","8079632":"FFME","8080040":"BAS","8080070":"BBAB","8080100":"BBFE","8080170":"BBGS, BBSH","8080190":"BBI, BBIW","8080200":"BBOR","8080260":"BDL","8080280":"LDLO","8080340":"BEIW","8080370":"BETN, BWUR","8080440":"BFD, BFRD","8080450":"BTLS","8080560":"LDBR","8080570":"LRO","8080580":"LSBR","8080590":"LSUE","8080600":"LWN","8080610":"LZO","8080620":"LHNZ","8080630":"EHWS","8080660":"LMGH","8080680":"BHGM","8080710":"BHOW","8080720":"BHN","8080750":"BHPG, BHPN","8080840":"LCZ","8080930":"LSEH","8080970":"BMAH","8080980":"BMM","8081020":"BNG","8081150":"BPEN","8081210":"BRGT","8081220":"BSAM","8081260":"LSBS","8081270":"LSBO","8081290":"BSFL, BSNF","8081420":"BSTR","8081540":"BWI","8081560":"BZEP","8081580":"BZN, BZTH","8081586":"BSFD","8081688":"BWDF","8081722":"BLEN","8084070":"UGRI","8087020":"HVCS","8087039":"EHOH","8087061":"UHOS","8087062":"SMUE","8087063":"FKRS","8087064":"FOUS","8087065":"HWEH","8087067":"TWEB","8087080":"TMW","8089000":"BSZF","8089002":"BAHU","8089003":"BATS","8089004":"BBMW, BBW","8089005":"BBEV","8089006":"BRB","8089007":"BSCF","8089008":"BBOS","8089009":"BBGT","8089010":"BBCH","8089011":"BGFB, BGSS","8089012":"BFB","8089013":"BFA, BFAL","8089014":"BGSE","8089016":"BGBA","8089017":"BHKM","8089018":"BHUM","8089019":"BJB","8089020":"BLST","8089022":"BMEA","8089023":"BMEX","8089024":"BNB","8089025":"BHLS","8089026":"BNPL","8089027":"BORS","8089030":"BPWA","8089031":"BPOE","8089032":"BPOF, BPOP","8089033":"BPLA","8089034":"BPRS","8089035":"BRW","8089036":"BRST","8089037":"BSAP","8089038":"BSC","8089039":"BSAL","8089040":"BSPH","8089041":"BSTO","8089042":"BSDG","8089043":"BTP","8089044":"BTOR","8089045":"BWRS","8089047":"BWKR, BWKRR, BWKS","8089048":"BWOK","8089050":"BYOR","8089051":"BGGS","8089052":"BADL","8089053":"BSRW","8089054":"BAGL","8089055":"BBDF","8089056":"BBKB, BBLB","8089057":"BBU","8089058":"BFRU","8089059":"BFFO","8089060":"BFRH","8089061":"BFOH","8089062":"BGD, BGWD","8089063":"BGA, BGAS, BQGAS","8089064":"BHED","8089065":"BHI","8089068":"BKAD, BKD","8089069":"BKP, BKPK","8089070":"BLRD","8089071":"BLWE","8089072":"BMDF, BMHL","8089074":"BMF","8089075":"BMAR, BMAZ","8089077":"BNK, BNKN","8089078":"BNIS, BNIW","8089079":"BOSP","8089080":"BPKR, BPKW","8089081":"BPHD","8089082":"BRD","8089084":"BRGB, BRGBT, BRH","8089085":"BSLS","8089087":"BSNH, BSNL","8089088":"BSPF","8089089":"BTG","8089090":"BTF, BTHF","8089091":"BTGN","8089092":"BWAI","8089093":"BWAB","8089094":"BWIG","8089095":"BWM","8089096":"BWIN","8089097":"BWHH","8089098":"BZD, BZFS","8089099":"BBRF","8089100":"BJUF, BJUN","8089101":"BEBD","8089102":"BKBO","8089103":"BARF","8089104":"BKHD","8089105":"BHER","8089106":"BIP","8089107":"BBUP","8089108":"BHO","8089109":"BHAL, BHLRS","8089110":"BMN","8089111":"BWES","8089112":"BHEI","8089113":"BLIH, BLIO","8089114":"BLAK","8089115":"BSDE","8089116":"BWH","8089118":"BBEU","8089119":"RNBG","8089131":"BWED","8089327":"BSO","8089328":"BMS","8089329":"BHST","8089330":"BOLS","8089331":"BPIC","8089472":"BLIS","8089473":"BOSS","8089537":"BJLB","8098096":"TS, TS  B, TS  T, TST","8098553":"AA, AAS"}+
\ No newline at end of file
diff --git a/client/src/helpers.js b/client/src/helpers.js
@@ -0,0 +1,97 @@
+
+
+export const ElementById = (id) => {
+	return document.getElementById(id);
+};
+
+export const showDiv = (id) => {
+	const element = document.getElementById(id);
+	if (element) element.classList.remove('hidden');
+};
+
+export const hideDiv = (id) => {
+	const element = document.getElementById(id);
+	if (element) element.classList.add('hidden');
+};
+
+export const padZeros = (str) => {
+	return ('00' + str).slice(-2);
+};
+
+export const isValidDate = (date) => {
+	const matches = /^(\d{4})[-\/](\d{2})[-\/](\d{2})$/.exec(date);
+	if (matches == null) {
+		return false;
+	}
+
+	const d = matches[3];
+	const m = matches[2]-1;
+	const y = matches[1];
+	const composedDate = new Date(y, m, d);
+	return composedDate.getDate() == d &&
+		   composedDate.getMonth() == m &&
+		   composedDate.getFullYear() == y;
+};
+
+export const formatDateTime = (date, format) => {
+	if (format != null) {
+		switch (format) {
+			case 'full':
+				return padZeros(date.getHours()) + ':' + padZeros(date.getMinutes()) + ', ' + date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
+				break;
+
+			case 'date':
+				return date.getDate() + '.' + (date.getMonth() + 1) + '.' + date.getFullYear();
+				break;
+
+			default:
+				return false;
+				break;
+		}
+
+	}
+
+	if (date.toLocaleDateString() !== new Date().toLocaleDateString()) {
+		return padZeros(date.getHours()) + ':' + padZeros(date.getMinutes()) + ', ' + date.getDate() + '.' + (date.getMonth() + 1) + '.';
+	} else {
+		return padZeros(date.getHours()) + ':' + padZeros(date.getMinutes());
+	}
+};
+
+export const formatDuration = (duration) => {
+	const mins = duration / 60000;
+	const h = Math.floor(mins / 60);
+	const m = mins % 60;
+
+	if (h > 0) {
+		return h+'h '+m+'min';
+	}
+
+	return m+'min';
+};
+
+export const formatFromTo = obj => {
+	if (obj.type === "stop")
+		return obj.id;
+	else if (obj.address)
+		return {
+			latitude: obj.latitude,
+			longitude: obj.longitude,
+			address: obj.address,
+		};
+	else
+		return {
+			id: obj.id,
+			latitude: obj.latitude,
+			longitude: obj.longitude,
+		};
+};
+
+export const getFrom = journeys => {
+	return journeys[0].legs[0].origin;
+};
+
+export const getTo = journeys => {
+	return journeys[0].legs[journeys[0].legs.length-1].destination;
+};
+
diff --git a/client/src/journeyView.js b/client/src/journeyView.js
@@ -0,0 +1,220 @@
+import { getSettings } from './dataStorage.js';
+import { showDiv, hideDiv, ElementById, formatDateTime, formatDuration } from './helpers.js';
+import { ConsoleLog, parseName, ds100Names, t, timeTemplate, getJourneys, addJourneys, refreshJourneys } from './app_functions.js';
+import { showModal } from './overlays.js';
+import { get } from './api.js';
+import { go } from './router.js';
+import { html, render } from 'lit-html';
+
+const remarksModalTemplate = (type, remarks) => html`
+	<table class="remarks">
+		${remarks.map(element => html`
+			<tr>
+			<td>
+				<span class="remark icon-${type}"></span>
+				<span>${element.text}</span>
+			</td>
+			</tr>
+		`)}
+	</table>
+`;
+
+const getAdditionalName = (line) => {
+	const splitName = line.name.split(" ");
+	if (splitName.length === 2 && line.fahrtNr && line.fahrtNr != splitName[1])
+		return `${splitName[0]} ${line.fahrtNr}`;
+	else
+		return null;
+};
+
+const travelynxTemplate = (settings, element) => {
+	if (settings.travelynx && element.line && element.line.mode === 'train') {
+		let trainName = getAdditionalName(element.line) || element.line.name;
+
+		return html`
+			<a class="link icon-travelynx" href="https://travelynx.de/s/${element.origin.id}?train=${encodeURIComponent(trainName)}"></a>
+		`;
+	}
+}
+
+const showRemarksModal = (type, remarks) => {
+	showModal(t('remarks'), remarksModalTemplate(type, remarks));
+};
+const remarksTemplate = ([type, remarks]) => !!remarks.length ? html`
+	<a class="link icon-${type}" @click=${() => showRemarksModal(type, remarks)}></a>
+` : '';
+
+const legTemplate = (settings) => (leg) => {
+	const allRemarks = leg.remarks || [];
+	const remarks = {
+		"status": allRemarks.filter(r => r.type === 'status'),
+		"hint": allRemarks.filter(r => r.type === 'hint'),
+		"other": allRemarks.filter(r => r.type !== 'status' && r.type !== 'hint'),
+	};
+
+	let marudorUrl = null;
+	if (leg.line && (leg.line.product == "nationalExpress" || leg.line.product == "national" || leg.line.product == "regionalExp" || leg.line.product == "regional")) {
+		marudorUrl = 'https://marudor.de/details/' + encodeURIComponent(getAdditionalName(leg.line) || leg.line.name) + '/' + Number(leg.plannedDeparture);
+	}
+
+	return html`
+		${leg.walking ? html`
+			<p class="walk">${t('walkinfo', parseName(leg.arrival), leg.distance)}</p>
+		` : leg.transfer ? html`
+			<p class="transfer">${t('transferinfo', parseName(leg.arrival))}</p>
+		` : leg.change ? html`
+			<p class="change">${t('changeinfo', formatDuration(leg.duration))}</p>
+		` : html`
+			<div class="card">
+			<table>
+				<thead>
+					<tr>
+						<td colspan="4">
+							<span>${marudorUrl ? html`
+								<a href="${marudorUrl}">${leg.line.name} → ${leg.direction}</a>
+							` : html `
+								${leg.line.name} → ${leg.direction}
+							`}
+							${leg.cancelled ? html`<b class="cancelled-text">${t('cancelled-ride')}</b>` : ''}
+							${Object.entries(remarks).map(remarksTemplate)}
+							${travelynxTemplate(settings, leg)}</span>
+						</td>
+					</tr>
+					<tr>
+						<td colspan="4">
+							<div class="train-details">
+								${getAdditionalName(leg.line) ? html`
+									<div class="train-detail">
+										Trip: ${getAdditionalName(leg.line)}
+									</div>
+								` : ''}
+								${leg.line.trainType ? html`
+									<div class="train-detail">
+										Train type: ${leg.line.trainType}
+									</div>
+								` : ''}
+								<div class="train-detail">
+									Duration: ${formatDuration(leg.arrival - leg.departure)}
+								</div>
+							</div>
+						</td>
+					</tr>
+					<tr>
+						<th>${t('arrival')}</th>
+						<th>${t('departure')}</th>
+						<th class="station-column">${t('station')}</th>
+						<th>${t('platform')}</th>
+					</tr>
+				</thead>
+				<tbody>
+					${(leg.stopovers || []).map(stop => html`
+						<tr class="stop ${stop.cancelled ? 'cancelled' : ''}">
+							<td><span>${timeTemplate(stop, "arrival")}</span></td>
+							<td><span>${timeTemplate(stop, "departure")}</span></td>
+							<td><span>${stop.stop.name} ${ds100Names(stop.stop.id)}</span></td>
+							<td><span>${stopPlatformTemplate(stop)}</span></td>
+						</tr>
+					`)}
+				</tbody>
+			</table>
+			</div>
+		`}
+	`;
+};
+
+const journeyTemplate = (settings, data, requestId, journeyId) => {
+	const duration = data.legs[data.legs.length - 1].arrival - data.legs[0].departure;
+
+	const legs = [];
+	let changes = 0;
+	let lastArrival;
+	for (let leg of data.legs) {
+		if (!leg.walking && !leg.transfer) {
+
+			// add change
+			if (lastArrival) {
+				const duration = leg.departure - lastArrival;
+
+				legs.push({
+					change: true,
+					duration,
+				});
+			}
+			changes++;
+
+			lastArrival = leg.arrival;
+		} else if (legs.length) {
+
+			// if this is a walking leg and it is the first one, we don't want to
+			// insert a 0 minutes change entry for this
+			lastArrival = leg.arrival;
+		}
+		legs.push(leg);
+	}
+
+	return html`
+		<div class="journey">
+			<header>
+				<a class="back icon-back" href="#/${requestId}"></a>
+				<div class="header-content">
+					<h3>${parseName(data.legs[0].origin)} → ${parseName(data.legs[data.legs.length - 1].destination)}</h3>
+					<p><b>${t('duration')}: ${formatDuration(duration)} | ${t('changes')}: ${changes-1} | ${t('date')}: ${formatDateTime(data.legs[0].plannedDeparture, 'date')}</b></p>
+				</div>
+				<a class="reload icon-reload" title="{{LABEL_RELOAD}}" @click=${() => refreshJourneyView(requestId, journeyId)}>{{LABEL_RELOAD}}</a>
+			</header>
+
+			${legs.map(legTemplate(settings))}
+		</div>
+	`;
+};
+
+const platformTemplate = (data) => html`
+	${data.arrivalPlatform != data.plannedArrivalPlatform ? html`
+		<b>${data.arrivalPlatform}</b>
+	` : (data.plannedArrivalPlatform ? data.plannedArrivalPlatform : '-')}
+`;
+
+const stopPlatformTemplate = (data) => {
+	if (data.departurePlatform) {
+		if (data.departurePlatform != data.plannedDeparturePlatform) {
+			return html`<b>${data.departurePlatform}</b>`;
+		} else {
+			return data.plannedDeparturePlatform;
+		}
+	} else if (data.arrivalPlatform) {
+		if (data.arrivalPlatform != data.plannedArrivalPlatform) {
+			return html`<b>${data.arrivalPlatform}</b>`;
+		} else {
+			return data.plannedArrivalPlatform;
+		}
+	} else {
+		return '-'
+	}
+};
+
+export const journeyView = async (match) => {
+	const settings = await getSettings();
+	const reqId = match[0];
+	const journeyId = Number(match[1]);
+
+	let all = await getJourneys(reqId);
+	if (!((journeyId + all.indexOffset) in all.journeys)) all = await refreshJourneys(reqId, false);
+	const data = all.journeys[journeyId + all.indexOffset];
+
+	ConsoleLog(data);
+	render(journeyTemplate(settings, data, reqId, journeyId), ElementById('content'));
+
+	/*const history_id = dataStorage.journeysHistory.findIndex(obj => obj.reqId === reqId);
+
+	if (dataStorage.journeysHistory[history_id] !== undefined) {
+		dataStorage.journeysHistory[history_id].journeyId = journeyId;
+		saveDataStorage();
+	}*/
+};
+
+const refreshJourneyView = async (reqId, journeyId) => {
+	document.querySelector('.reload').classList.add('spinning');
+	await refreshJourneys(reqId, true);
+	journeyView([reqId, journeyId]);
+	document.querySelector('.reload').classList.remove('spinning');
+};
diff --git a/client/src/journeysView.js b/client/src/journeysView.js
@@ -0,0 +1,166 @@
+import { showDiv, hideDiv, ElementById, formatDuration, formatFromTo, getFrom, getTo, padZeros } from './helpers.js';
+import { parseName, ConsoleLog, t, timeTemplate, getJourneys, addJourneys } from './app_functions.js';
+import { getSettings, modifySettings } from './dataStorage.js';
+import { setupCanvas } from './canvas.js';
+import { post } from './api.js';
+import { go } from './router.js';
+import { html, render } from 'lit-html';
+import { showAlertModal } from './overlays.js';
+
+const journeysTemplate = (settings, data) => html`
+	<div class="journeys">
+		<header id="header">
+			<a class="back icon-back" href="#/" title="${t('back')}">${t('back')}</a>
+			<div class="header-content">
+				<h3>${t('from')}: ${parseName(getFrom(data.journeys))}</h3>
+				<div>
+					<h3>${t('to')}: ${parseName(getTo(data.journeys))}</h3>
+					<div class="mode-changers">
+						<a @click=${changeMode('table')} class="${settings.journeysViewMode === 'table' ? 'active' : ''}">
+							<div class="icon-table"></div>
+							<span>Table</span>
+						</a>
+						<a @click=${changeMode('canvas')} class="${settings.journeysViewMode === 'canvas' ? 'active' : ''}">
+							<div class="icon-canvas"></div>
+							<span>Canvas</span>
+						</a>
+						${settings.showMap ? html`
+							<a @click=${changeMode('map')} class="${settings.journeysViewMode === 'map' ? 'active' : ''}">
+								<div class="icon-map"></div>
+								<span>Map</span>
+							</a>
+						` : ''}
+					</div>
+				</div>
+			</div>
+			<a class="back invisible" href="#/"></a>
+		</header>
+
+		${settings.journeysViewMode === 'canvas' ? html`
+			<div id="journeysCanvas">
+				<canvas id="canvas"></canvas>
+			</div>
+		` : ""}
+		${settings.journeysViewMode === 'map' ? html`
+			<div id="journeysMap">
+			</div>
+		` : ""}
+		${settings.journeysViewMode === 'table' ? html`
+			<a class="loadMore icon-arrow2 flipped" title="${t('label_earlier')}" @click=${() => moreJourneys(data.slug, 'earlier')}"></a>
+
+			<div class="card">
+			<table>
+				<thead>
+					<tr>
+						<th>${t('departure')}</th>
+						<th>${t('arrival')}</th>
+						<th>${t('duration')}</th>
+						<th>${t('changes')}</th>
+						<th>${t('products')}</th>
+						${settings.showPrices ? html`<th>Price</th>` : ''}
+						<th></th>
+					</tr>
+				</thead>
+				<tbody>
+					${Object.entries(data.journeys).map(([key, val]) => journeyOverviewTemplate(settings, val, data.slug, key - data.indexOffset))}
+				</tbody>
+			</table>
+			</div>
+
+			<a class="loadMore icon-arrow2" title="${t('label_later')}" @click=${() => moreJourneys(data.slug, "later")}></a>
+		` : ""}
+	</div>
+`;
+
+const journeyOverviewTemplate = (settings, entry, slug, key) => {
+	let firstLeg = entry.legs[0];
+	let lastLeg = entry.legs[entry.legs.length - 1];
+	let changes = 0;
+	let products = {};
+	let productsString = "";
+	let changesDuration = 0;
+	let cancelled = false;
+
+	let duration = Number(lastLeg.arrival) - Number(firstLeg.departure);
+
+	for (let leg of entry.legs) {
+		if (leg.cancelled) cancelled = true;
+		if (leg.isWalking || leg.isTransfer) continue;
+
+		changes = changes+1;
+
+		if (leg.line) {
+			const productName = leg.line.name.split(" ")[0];
+			if (!products[productName]) products[productName] = [];
+		}
+		//if (leg.line && leg.line.trainTypeShort) products[leg.line.productName].push(leg.line.trainTypeShort);
+	}
+
+	productsString = Object.entries(products).map(([prod, types]) => {
+		if (types.length >= 2) {
+			prod += " (" + types.join(", ") + ")";
+		} else if (types.length) {
+			prod += " " + types[0];
+		}
+		return prod;
+	}).join(", ");
+
+	return html`
+	<tr @click=${() => go('/'+slug + '/' + key)}">
+		<td><span>${timeTemplate(firstLeg, 'departure')}</span></td>
+		<td><span>${timeTemplate(lastLeg, 'arrival')}</span></td>
+		<td title="${changesDuration > 0 ? 'including '+formatDuration(changesDuration)+' transfer durations' : ''}"><span>${formatDuration(duration)}</span></td>
+		<td><span>${changes-1}</span></td>
+		<td><span>${productsString}</span></td>
+		${settings.showPrices ? html`<td><span>${formatPrice(entry.price)}</span></td>` : ''}
+		<td><a class="details-button icon-arrow3"></a></td>
+	</tr>`;
+}
+
+const formatPrice = price => {
+	if (!price) return '-';
+	console.log(price);
+	const currencies = { USD: '$', EUR: '€', GBP: '£' };
+	let ret = currencies[price.currency] || price.currency;
+	ret += Math.floor(price.amount);
+	ret += '.';
+	ret += padZeros(price.amount * 100 % 100, 2);
+	return ret;
+};
+
+export const journeysView = async (match, isUpdate) => {
+	const slug = match[0];
+
+	const settings = await getSettings();
+	const data = await getJourneys(slug);
+
+	render(journeysTemplate(settings, data), ElementById('content'));
+
+	if (settings.journeysViewMode === 'canvas') setupCanvas(data, isUpdate);
+	if (settings.journeysViewMode === 'map') {
+		const module = await import('./map.js');
+		module.setupMap(data, isUpdate);
+	}
+};
+
+const changeMode = (mode) => {
+	return async () => {
+		await modifySettings(settings => {
+			settings.journeysViewMode = mode;
+			return settings;
+		});
+		const match = /^\/([a-zA-Z0-9]+)$/.exec(window.location.hash.slice(1)).slice(1);
+		journeysView(match);
+	};
+};
+
+export const moreJourneys  = async (slug, mode) => {
+	const settings = await getSettings();
+	const data = await post(`savedJourneys/${slug}/${mode}`, {
+		stopovers: true,
+		polylines: settings.showMap || false,
+		tickets: settings.showPrices || false,
+	});
+	await addJourneys(data);
+	journeysView([slug], true);
+};
diff --git a/client/src/languages.js b/client/src/languages.js
@@ -0,0 +1,115 @@
+export const languages = {
+	'de': {
+		'access_full':        'Barrierefrei',
+		'access_none':        'keine Einschränkungen',
+		'access_partial':     'Bedingt barrierefrei',
+		'accessibility':      'Barrierefreiheit',
+		'arrival':            'Ankunft',
+		'bus':                'Bus',
+		'cancelled-ride':     'Fahrt entfällt!',
+		'changeinfo':         '{} Umstiegsdauer',
+		'changes':            'Umstiege',
+		'clearstorage':       'lokale Daten löschen',
+		'datasource':         'Datenquelle',
+		'date':               'Datum',
+		'de':                 'Deutsch',
+		'departure':          'Abfahrt',
+		'duration':           'Dauer',
+		'dzug':               'D-Zug',
+		'en':                 'Englisch',
+		'ferry':              'Fähre',
+		'from':               'Von',
+		'graphical':          'Graphische Darstellung in der Verbindungsübersicht',
+		'iceonly':            'ICE',
+		'iconly':             'IC',
+		'journeyoverview':    'Verbindungsübersicht aufrufen',
+		'label_earlier':      'Frühere Verbindungen',
+		'label_later':        'Spätere Verbindungen',
+		'lang_short':         'de',
+		'language':           'Sprache',
+		'lastjourney':        'Letzte gewälte Verbindung aufrufen',
+		'longdistancetrain':  'Fernverkehr',
+		'optional':           '(optional)',
+		'options':            'Optionen',
+		'platform':           'Gleis',
+		'products':           'Produkte',
+		'regionaltrain':      'Regionalverkehr',
+		'remarks':            'Hinweise',
+		'save':               'Speichern',
+		'search':             'Suchen',
+		'setfromto':          'Als Von/Nach setzen',
+		'settings':           'Einstellungen',
+		'showdebug':          'Schreibe Debug Nachrichten ins Log',
+		'showds100':          'Zeige RIL100 Kürzel (wenn verfügbar)',
+		'station':            'Station',
+		'suburbantrain':      'S-Bahn',
+		'subway':             'U-Bahn',
+		'swap':               'Von/Nach tauschen',
+		'taxi':               'Taxi',
+		'time':               'Uhrzeit',
+		'to':                 'Nach',
+		'tram':               'Tram',
+		'transferinfo':       'Reise nach {}',
+		'travelynx-checkin':  'Travelynx checkin anzeigen?',
+		'update':             'Anwendung updaten',
+		'via':                'Ãœber',
+		'walkinfo':           'Laufe nach {} (ca. {} Meter)'
+	},
+
+	'en': {
+		'access_full':       'full',
+		'access_none':       'none',
+		'access_partial':    'partial',
+		'accessibility':     'Accessibillity',
+		'arrival':           'Arrival',
+		'bus':               'Bus',
+		'cancelled-ride':    'Cancelled!',
+		'changeinfo':        '{} change duration',
+		'changes':           'Changes',
+		'clearstorage':      'Remove local data',
+		'datasource':        'Data source',
+		'date':              'Date',
+		'de':                'German',
+		'departure':         'Departure',
+		'duration':          'Duration',
+		'dzug':              'D-Zug',
+		'en':                'English',
+		'ferry':             'Ferry',
+		'from':              'From',
+		'graphical':         'Graphical overview for journeys',
+		'iceonly':           'ICE',
+		'iconly':            'IC',
+		'journeyoverview':   'Go to journeysoverview',
+		'label_earlier':     'Earlier connections',
+		'label_later':       'Later connections',
+		'lang_short':        'en',
+		'language':          'Language',
+		'lastjourney':       'Go to last selected journey',
+		'longdistancetrain': 'Long distance trains',
+		'optional':          '(optional)',
+		'options':           'Options',
+		'platform':          'Platform',
+		'products':          'Products',
+		'regionaltrain':     'Regional trains',
+		'remarks':           'Remarks',
+		'save':              'Save',
+		'search':            'Search',
+		'setfromto':         'Set as from/to',
+		'settings':          'Settings',
+		'showdebug':         'Write debug messages to log',
+		'showds100':         'Show DS100 (if available)',
+		'station':           'Station',
+		'suburbantrain':     'Suburban Trains',
+		'subway':            'Subway',
+		'swap':              'Swap from/to',
+		'taxi':              'Taxi',
+		'time':              'Time',
+		'to':                'To',
+		'tram':              'Tram',
+		'transferinfo':      'Travel to {}',
+		'travelynx-checkin': 'show travelynx checkin?',
+		'update':            'Update application',
+		'via':               'Via',
+		'walkinfo':          'Walk to {} (apprx. {} meters)'
+	}
+}
diff --git a/client/src/main.js b/client/src/main.js
@@ -0,0 +1,30 @@
+import { route, go, start } from './router.js';
+import { searchView } from './searchView.js';
+import { journeysView } from './journeysView.js';
+import { journeyView } from './journeyView.js';
+import { applySettings } from './app_functions.js';
+import { getSettings } from './dataStorage.js';
+import { showDiv, hideDiv, ElementById } from './helpers.js';
+
+(async () => {
+	const settings = await getSettings();
+	await applySettings(settings);
+
+	route(/^\/$/, searchView);
+	route(/^\/([a-zA-Z0-9]+)$/, journeysView);
+	route(/^\/([a-zA-Z0-9]+)\/([-0-9]+)$/, journeyView);
+
+	hideDiv('overlay')
+	if (!window.location.hash.length) go('/');
+	start();
+}) ()
+
+//const sw = navigator.serviceWorker;
+//export let registration;
+//if (sw) {
+//	sw.register('service-worker.js', {
+//		scope: './'
+//	}).then(function(reg) {
+//		registration = reg;
+//	});
+//}
diff --git a/client/src/map.js b/client/src/map.js
@@ -0,0 +1,72 @@
+import Map from 'ol/Map';
+import View from 'ol/View';
+import { Tile as TileLayer, Vector as VectorLayer } from 'ol/layer';
+import Feature from 'ol/Feature';
+import GeoJSON from 'ol/format/GeoJSON';
+import { XYZ as XYZSource, Vector as VectorSource } from 'ol/source';
+import { Circle as CircleStyle, Stroke, Style } from 'ol/style';
+import { getSquaredTolerance } from 'ol/renderer/vector';
+
+import { moreJourneys } from './journeysView.js';
+
+const vectorSource = new VectorSource({ });
+const view = new View({
+	  center: [0, 0],
+	  zoom: 1,
+});
+
+const vectorLayer = new VectorLayer({
+	source: vectorSource,
+	style: (feature) => feature.values_.style,
+});
+
+const map = new Map({
+	layers: [
+		new TileLayer({
+			source: new XYZSource({
+				url: "https://cartodb-basemaps-{a-d}.global.ssl.fastly.net/light_all/{z}/{x}/{y}.png",
+			}),
+		}),
+		vectorLayer,
+	],
+	controls: [],
+	view,
+});
+
+export const setupMap = (data, isUpdate) => {
+	map.setTarget(document.getElementById('journeysMap'));
+
+	const geojson = {
+		type: 'FeatureCollection',
+		features: [],
+	};
+
+	for (let journey of data.journeys) {
+		const i = data.journeys.indexOf(journey) / data.journeys.length;
+		const color = `hsl(${i * 360}, 50%, 50%)`;
+		const style = new Style({
+			stroke: new Stroke({
+				color,
+				width: 5,
+			}),
+		});
+		for (let leg of journey.legs) {
+			if (!leg.polyline) continue;
+			geojson.features.push({
+				type: 'Feature',
+				geometry: {
+					type: 'LineString',
+					coordinates: leg.polyline.features .map(point => point.geometry.coordinates),
+				},
+				properties: { journey, style },
+			});
+		}
+	}
+
+	vectorSource.clear();
+	vectorSource.addFeatures(new GeoJSON({
+		featureProjection: 'EPSG:3857',
+	}).readFeatures(geojson));
+
+	view.fit(vectorSource.getFeatures()[0].getGeometry().getExtent(), {size: [1000, 1000], padding: [420, 420, 420, 420]});
+};
diff --git a/client/src/overlays.js b/client/src/overlays.js
@@ -0,0 +1,54 @@
+
+
+import { showDiv, hideDiv, ElementById } from './helpers.js';
+import { html, render } from 'lit-html';
+
+export const showAlertModal = (text) => {
+	showDiv('overlay');
+	render(html`
+		<div class="modal">
+			<div class="box alert">
+				${text}
+				<div class="button" @click=${hideOverlay}>OK</div>
+			</div>
+		</div>
+	`, ElementById('overlay'));
+};
+
+export const showSelectModal = (content) => {
+	showDiv('overlay');
+	render(html`
+		<div class="modal">
+			<div class="box select">
+				${content}
+				<a @click=${hideOverlay}>Close</a>
+			</div>
+		</div>
+	`, ElementById('overlay'));
+};
+
+export const showModal = (title, content) => {
+	showDiv('overlay');
+	render(html`
+		<div class="modal-dialog">
+			<div id="modal-content" class="modal-content">
+				<div class="modal-header">
+					<div class="modal-close" @click=${() => hideDiv('overlay')}></div>
+					<h4 class="modal-title">${title}</h4>
+				</div>
+				<div class="modal-body">${content}</div>
+			</div>
+		</div>
+	`, ElementById('overlay'));
+};
+
+export const showLoader = () => {
+	showDiv('overlay');
+	render(html`
+		<div class="loading">
+			<div class="spinner"></div>
+		</div>
+	`, document.getElementById('overlay'));
+};
+
+export const hideOverlay = () => hideDiv('overlay');
diff --git a/client/src/router.js b/client/src/router.js
@@ -0,0 +1,23 @@
+const routes = [];
+
+export const route = (pattern, handler) => {
+	routes.push({
+		pattern: pattern,
+		handler: handler
+	});
+};
+
+export const go = (dest) => {
+	window.location.hash = '#' + dest;
+};
+
+export const start = () => {
+	const dest = window.location.hash.slice(1);
+	for (let route of routes) {
+		const match = route.pattern.exec(dest);
+		if (!match) continue;
+		return route.handler(match.slice(1));
+	}
+};
+
+window.addEventListener('hashchange', start);
diff --git a/client/src/searchView.js b/client/src/searchView.js
@@ -0,0 +1,461 @@
+import { showDiv, ElementById, padZeros, isValidDate, formatFromTo } from './helpers.js';
+import { parseName, ConsoleLog, t, loadDS100, getJourneys, addJourneys } from './app_functions.js';
+import { getSettings, modifySettings, getJourneysHistory } from './dataStorage.js';
+import { get, post } from './api.js';
+import { go } from './router.js';
+import { html, render } from 'lit-html';
+import { showAlertModal, showSelectModal, showLoader, hideOverlay} from './overlays.js';
+import { showSettings } from './settingsView.js';
+
+let suggestionsCache     = {
+	from: {},
+	via: {},
+	to: {},
+};
+
+let currDate             = new Date();
+let fromValue            = '';
+let viaValue             = '';
+let toValue              = '';
+let isArrValue           = false;
+let dateValue            = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());;
+let timeValue            = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
+
+const searchTemplate = (settings, journeysHistory) => html`
+	<div id="searchView" class="center">
+		<form class="search" onsubmit="return false;">
+			<div class="title">
+				<div class="logo icon-logo"></div>
+				<h1>TrainSearch</h1>
+			</div>
+			<label for="from">${t('from')}:</label>
+			<input type="text" name="from" id="from" placeholder="${t('from')}" value="${fromValue}" autocomplete="off" @focus=${startTyping} @blur=${stopTyping} @keyup=${onKeyup} @keydown=${onKeydown} required>
+			<div class="suggestions" id="fromSuggestions"></div>
+
+			<label for="via" class="hidden">${t('via')}:</label>
+			<input type="text" name="via" id="via" placeholder="${t('via')} ${t('optional')}" value="${viaValue}" autocomplete="off" @focus=${startTyping} @blur=${stopTyping} @keyup=${onKeyup} @keydown=${onKeydown} required class="hidden">
+			<div class="suggestions" id="viaSuggestions" class="hidden"></div>
+
+			<label for="to">${t('to')}:</label>
+			<input type="text" name="to" id="to" placeholder="${t('to')}" value="${toValue}" autocomplete="off" @focus=${startTyping} @blur=${stopTyping} @keyup=${onKeyup} @keydown=${onKeydown} required>
+			<div class="suggestions" id="toSuggestions"></div>
+
+			<div class="row">
+				<label class="switch">
+					<input type="checkbox" id="isarr" name="isarr" ?checked=${isArrValue}>
+					<span class="slider ${t('lang_short')}"></span>
+					<label for="isarr"> <br></label>
+				</label>
+
+				<label for="date">${t('date')}:</label>
+				<input type="date" name="date" id="date" value="${dateValue}" placeholder="${t('date')}" pattern="[0-9]{4}-[0-9]{2}-[0-9]{2}" @keydown=${onKeypressSubmit} required>
+
+				<label for="time"><br>${t('time')}:</label>
+				<input type="time" name="time" id="time" value="${timeValue}" placeholder="${t('time')}" pattern="[0-9]{2}:[0-9]{2}" @keydown=${onKeypressSubmit} required>
+			</div>
+
+			<div class="row">
+				<span class="hidden">${t('products')}:</span>
+				<div class="selector">
+					${settings.advancedSelection ? html`
+					<input type="checkbox" id="nationalExpress" name="nationalExpress" checked>
+					<label class="icon-ice" for="nationalExpress" title="${t('iceonly')}">${t('iceonly')}<br></label>
+
+					<input type="checkbox" id="national" name="national" checked>
+					<label class="icon-ic" for="national" title="${t('iconly')}">${t('iconly')}<br></label>
+					` : html`
+					<input type="checkbox" id="national" name="national" checked>
+					<label class="icon-icice" for="national" title="${t('longdistancetrain')}">${t('longdistancetrain')}<br></label>
+					`}
+
+					${settings.advancedSelection ? html`
+					<input type="checkbox" id="regionalExp" name="regionalExp" checked>
+					<label class="icon-dzug" for="regionalExp" title="${t('dzug')}">${t('dzug')}<br></label>
+
+					<input type="checkbox" id="regional" name="regional" checked>
+					<label class="icon-regional" for="regional" title="${t('regionaltrain')}">${t('regionaltrain')}<br></label>
+					` : html`
+					<input type="checkbox" id="regional" name="regional" checked>
+					<label class="icon-regional" for="regional" title="${t('regionaltrain')}">${t('regionaltrain')}<br></label>
+					`}
+
+					<input type="checkbox" id="suburban" name="suburban" checked>
+					<label class="icon-suburban" for="suburban" title="${t('suburbantrain')}">${t('suburbantrain')}<br></label>
+
+					<input type="checkbox" id="subway" name="subway" checked>
+					<label class="icon-subway" for="subway" title="${t('subway')}">${t('subway')}<br></label>
+
+					<input type="checkbox" id="tram" name="tram" checked>
+					<label class="icon-tram" for="tram" title="${t('tram')}">${t('tram')}<br></label>
+
+					<input type="checkbox" id="bus" name="bus" checked>
+					<label class="icon-bus" for="bus" title="${t('bus')}">${t('bus')}<br></label>
+
+					<input type="checkbox" id="ferry" name="ferry" checked>
+					<label class="icon-ferry" for="ferry" title="${t('ferry')}">${t('ferry')}<br></label>
+
+					<input type="checkbox" id="taxi" name="taxi" checked>
+					<label class="icon-taxi" for="taxi" title="${t('taxi')}">${t('taxi')}<br></label>
+				</div>
+
+				<span class="hidden">{{LABEL_ACCESSIBILITY}}:</span>
+				<div class="selector">
+					<input type="radio" id="accessibilityNone" name="accessibility" value="none" ?checked=${settings.accessibility === "none"}>
+					<label class="icon-walk-fast" for="accessibilityNone" title="{{LABEL_ACCESSIBILITY_NONE}}">{{LABEL_ACCESSIBILITY_NONE}}<br></label>
+
+					<input type="radio" id="accessibilityPartial" name="accessibility" value="partial" ?checked=${settings.accessibility === "partial"}>
+					<label class="icon-walk" for="accessibilityPartial" title="{{LABEL_ACCESSIBILITY_PARTIAL}}">{{LABEL_ACCESSIBILITY_PARTIAL}}<br></label>
+
+					<input type="radio" id="accessibilityComplete" name="accessibility" value="complete" ?checked=${settings.accessibility === "complete"}>
+					<label class="icon-weelchair" for="accessibilityComplete" title="{{LABEL_ACCESSIBILITY_FULL}}">{{LABEL_ACCESSIBILITY_FULL}}<br></label>
+				</div>
+
+				<div class="selector">
+					<div class="btn icon-swap" title="${t('swap')}" @click=${swapFromTo}></div>
+					<div class="btn icon-settings" title="${t('settings')}" @click=${showSettings}></div>
+				</div>
+
+				<div class="btn go" tabindex="0" id="go" @click=${search}>
+					${t('search')}
+					<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2L4.5 20.29l.71.71L12 18l6.79 3 .71-.71z"/></svg>
+				</div>
+			</div>
+
+
+		${journeysHistory.length ? html`
+			<input type="checkbox" id="btn-history" class="btn history hidden">
+			<label for="btn-history" class="loadMore icon-arrow2"></label>
+			${journeysHistoryTemplate(journeysHistory)}
+		` : ''}
+
+		</div>
+	</div>
+`;
+
+const journeysHistoryTemplate = (journeysHistory) => html`
+	<div class="history">
+		${journeysHistory.map(element => html`
+		<div class="row history" @click=${() => {journeysHistoryAction(journeysHistory, element)}}">
+			<div class="history from">
+				<small>${t('from')}:</small><br>
+				${parseName(element.fromPoint)}
+				${element.viaPoint ? html`
+					<div class="history via">
+						<small>${t('via')} ${parseName(element.viaPoint)}</small>
+					</div>
+				` : ''}
+			</div>
+			<div class="history arrow icon-arrow1"></div>
+			<div class="history to">
+				<small>${t('to')}:</small><br>
+				${parseName(element.toPoint)}
+			</div>
+		</div>
+		`)}
+	</div>
+`;
+
+const journeysHistoryAction = (journeysHistory, element) => {
+	ConsoleLog(element);
+	showSelectModal(html`
+		<a @click=${() => {setFromHistory(journeysHistory.length - 1 - journeysHistory.indexOf(element));hideOverlay()}}>${t('setfromto')}</a>
+		<a @click=${() => {go("/"+element.slug);hideOverlay();}}>${t('journeyoverview')}</a>
+		${element.journeyId === '' ? '' : html`
+			<a @click=${() => {go("/"+element.slug+"/"+element.journeyId);hideOverlay();}}>${t('lastjourney')}</a>
+		`}
+	`);
+};
+
+export const searchView = async () => {
+	const settings = await getSettings();
+	const journeysHistory = (await getJourneysHistory()).slice().reverse();	
+	render(searchTemplate(settings, journeysHistory), ElementById('content'));
+
+	ElementById('from').focus();
+
+	for (let [product, enabled] of Object.entries(settings.products)) {
+		let el = ElementById(product);
+		if (!el) continue;
+		ElementById(product).checked = enabled;
+	}
+};
+
+export const search = async (requestId) => {
+	await modifySettings(settings => {
+		settings.products = readProductSelection(settings);
+		settings.accessibility = document.querySelector('input[name="accessibility"]:checked').value;
+		return settings;
+	});
+	const settings = await getSettings();
+
+	const provider      = settings.provider;
+	let   isDep         = !ElementById('isarr').checked;
+	let   date          = ElementById('date').value;
+	let   time          = ElementById('time').value;
+	let   timestamp     = '';
+	let   from          = '';
+	let   via           = '';
+	let   to            = '';
+
+	currDate   = new Date();
+	fromValue  = ElementById('from').value;
+	viaValue   = ElementById('via').value;
+	toValue    = ElementById('to').value;
+	dateValue  = ElementById('date').value;
+	timeValue  = ElementById('time').value;
+	isArrValue = ElementById('isarr').checked;
+
+	if (date !== '') {
+		if (!isValidDate(date)) {
+			showAlertModal('Invalid date');
+			return;
+		}
+	} else {
+		date = currDate.getFullYear()+'-'+padZeros(currDate.getMonth()+1)+'-'+padZeros(currDate.getDate());
+	}
+
+	if (time !== '') {
+		if (!new RegExp('([0-1][0-9]|2[0-3]):([0-5][0-9])').test(time)) {
+			showAlertModal('Invalid time');
+			return;
+		}
+	} else {
+		time = padZeros(currDate.getHours())+':'+padZeros(currDate.getMinutes());
+	}
+
+	if (Object.entries(suggestionsCache.from).length !== 0) {
+		from = suggestionsCache.from;
+	} else {
+		let suggestions = await get("locations",  {"query": fromValue, "results": 1}, true);
+
+		if (!suggestions[0]) {
+    		showAlertModal("Invalid From");
+			return;
+  		}
+
+		from = suggestions[0]
+	}
+
+	if (ElementById('via').value == "") {
+		via = null;
+	} else if (Object.entries(suggestionsCache.via).length !== 0) {
+		via = suggestionsCache.via;
+	} else {
+		let suggestions = await get("locations",  {"query": viaValue, "results": 1}, true);
+
+		if (!suggestions[0]) {
+			showAlertModal("Invalid Via");
+			return;
+		}
+
+		via = suggestions[0]
+	}
+
+	if (Object.entries(suggestionsCache.to).length !== 0) {
+		to = suggestionsCache.to;
+	} else {
+		let suggestions = await get("locations",  {"query": toValue, "results": 1}, true);
+
+		if (!suggestions[0]) {
+			showAlertModal("Invalid To");
+			return;
+  		}
+
+		to = suggestions[0]
+	}
+
+	const split_date = date.split('-');
+	const split_time = time.split(':');
+
+	timestamp = Math.round(new Date(split_date[0], split_date[1]-1, split_date[2], split_time[0], split_time[1]).getTime()/1000);
+
+	ConsoleLog(timestamp+'///'+date+' '+time+':00');
+
+	let params = {
+		from: formatFromTo(from),
+		to: formatFromTo(to),
+		stopovers: true,
+		polylines: settings.showMap || false,
+		tickets: settings.showPrices || false,
+		results: 6,
+		//"accessibility": settings.accessibility,
+		...settings.products,
+	};
+
+	if (via) params.viaPoint = via;
+
+	if (isDep)
+		params.departure = timestamp;
+	else
+		params.arrival = timestamp;
+
+	const data = await post("savedJourneys", params);
+	addJourneys(data);
+	go('/' + data.slug);
+	return false;
+};
+
+const suggestionsTemplate = (suggestions, inputId) => html`
+  <div class="suggestionsbox" @mouseover=${mouseOverSuggestions} @mouseout=${stopMouseOverSuggestions}>
+  	${suggestions.map(element => html`
+  		<p class="suggestion" @click=${() => setSuggestion(encodeURI(JSON.stringify(element)), inputId)}>${parseName(element)}</p>
+  	`)}
+  </div>
+`;
+
+const loadSuggestions = async (e, input) => {
+	const val = e.target.value;
+	suggestionsCache[e.target.id] = {};
+	const suggestions = val ? await get("locations",  {"query": val, "results": 10}, true) : [];
+	const suggestionsEl = ElementById(e.target.id+'Suggestions');
+	render(suggestionsTemplate(suggestions, e.target.id), suggestionsEl);
+};
+
+export const setSuggestion  = (data, inputId) => {
+	if (typeof data === 'string') {
+		data = JSON.parse(decodeURI(data));
+	}
+
+	suggestionsCache[inputId] = data;
+	ElementById(inputId).value = parseName(data);
+
+	if (inputId === 'from') {
+		ElementById('fromSuggestions').classList.remove('mouseover');
+		ElementById('to').focus();
+	} else if (inputId === 'via') {
+		ElementById('viaSuggestions').classList.remove('mouseover');
+		ElementById('to').focus();
+	} else if (inputId === 'to') {
+		ElementById('toSuggestions').classList.remove('mouseover');
+		ElementById('to').blur();
+	}
+};
+
+export const swapFromTo  = () => {
+	suggestionsCache.from = [suggestionsCache.to, suggestionsCache.to = suggestionsCache.from][0];
+
+	let from = ElementById('from');
+	let to   = ElementById('to');
+
+	from.value = [to.value, to.value = from.value][0];
+};
+
+export const setFromHistory = async id => {
+	const entry = await getJourneysHistory()[id];
+	if (!entry) return;
+	setSuggestion(entry.fromPoint, 'from');
+	setSuggestion(entry.toPoint, 'to');
+};
+
+export const readProductSelection  = settings => {
+	const splitExp = settings.advancedSelection;
+	return {
+		"nationalExpress": splitExp ? ElementById('nationalExpress').checked : ElementById('national').checked,
+		"national":        ElementById('national').checked,
+		"regionalExp":     splitExp ? ElementById('regionalExp').checked : ElementById('regional').checked,
+		"regional":        ElementById('regional').checked,
+		"suburban":        ElementById('suburban').checked,
+		"bus":             ElementById('bus').checked,
+		"ferry":           ElementById('ferry').checked,
+		"subway":          ElementById('subway').checked,
+		"tram":            ElementById('tram').checked,
+		"taxi":            ElementById('taxi').checked
+	};
+};
+
+const startTyping = (e) => {
+	ElementById(e.target.id+'Suggestions').classList.add('typing');
+	if (e.target.id == 'from') ElementById('toSuggestions').classList.remove('mouseover');
+	if (e.target.id == 'to') ElementById('fromSuggestions').classList.remove('mouseover');
+};
+
+const stopTyping = (e) => {
+	ElementById(e.target.id+'Suggestions').classList.remove('typing');
+};
+
+const mouseOverSuggestions = (e) => {
+  let el = e.target;
+  let i = 0;
+  while (i++ < 10 && el.id !== 'fromSuggestions' && el.id !== 'viaSuggestions' && el.id !== 'toSuggestions') el = el.parentElement;
+	el.classList.add('mouseover');
+};
+
+const stopMouseOverSuggestions = (e) => {
+  let el = e.target;
+  let i = 0;
+  while (i++ < 10 && el.id !== 'fromSuggestions' && el.id !== 'viaSuggestions'&& el.id !== 'toSuggestions') el = el.parentElement;
+	el.classList.remove('mouseover');
+};
+
+const onKeyup = (e) => {
+	let which = e.which || e.keyCode;
+
+	let forbiddeKeys = [13, 38, 40];
+
+	if (!forbiddeKeys.includes(which)) {
+		loadSuggestions(e, e.target.id);
+	}
+};
+
+
+const onKeydown = (e) => {
+	let which = e.which || e.keyCode;
+
+	if (which == 13) { // enter
+		if (!ElementById('selected')) {
+			document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).click();
+			if (e.target.id === 'to') ElementById('go').click();
+		} else {
+			let elem = ElementById('selected')
+			elem.id = '';
+			elem.click();
+		}
+		return false;
+	}
+
+	if (which == 40) { // keydown
+		if (!ElementById('selected')) {
+			document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).id = 'selected';
+		} else {
+			let currElem = ElementById('selected');
+			let nextElem = currElem.nextElementSibling;
+
+			if (nextElem == null) {
+				nextElem = document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).id = 'selected';
+			}
+
+			currElem.id = '';
+			nextElem.id = 'selected';
+		}
+
+		return false;
+	}
+
+	if (which == 38) { // keydown
+		if (!ElementById('selected')) {
+			document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:first-child`).id = 'selected';
+		} else {
+			let currElem = ElementById('selected');
+			let prevElem = currElem.previousElementSibling;
+
+			if (prevElem == null) {
+				prevElem = document.querySelector(`#${e.target.id}Suggestions>.suggestionsbox>:last-child`).id = 'selected';
+			}
+
+			currElem.id = '';
+			prevElem.id = 'selected';
+		}
+
+		return false;
+	}
+
+	return true;
+};
+
+const onKeypressSubmit = (e) => {
+  if (e.which == 13 || e.keyCode == 13) { // enter
+    ElementById('go').click();
+    return false;
+  }
+  return true;
+};
diff --git a/client/src/settingsView.js b/client/src/settingsView.js
@@ -0,0 +1,60 @@
+import { getSettings, modifySettings, clearDataStorage } from './dataStorage.js';
+import { showModal } from './overlays.js';
+import { hideDiv, ElementById } from './helpers.js';
+import { ConsoleLog, t, applySettings } from './app_functions.js';
+import { html, render } from 'lit-html';
+import { searchView } from './searchView.js';
+
+export const showSettings = async () => {
+	const settings = await getSettings();
+	showModal(t('settings'), settingsTemplate(settings))
+};
+
+const settingsTemplate = settings => html`
+  <div id="settingsView">
+		<b>${t('options')}:</b><br>
+		<label><input type="checkbox" ?checked=${settings.showRIL100Names} id="ril100"> ${t('showds100')}</label><br>
+		<label><input type="checkbox" ?checked=${settings.writeDebugLog} id="debug-messages"> ${t('showdebug')}</label><br>
+		<label><input type="checkbox" ?checked=${settings.travelynx} id="travelynx"> ${t('travelynx-checkin')}</label><br>
+		<label><input type="checkbox" ?checked=${settings.advancedSelection} id="advancedSelection">ADVANCED® selection of trains</label><br>
+		<br>
+		<b>${t('language')}:</b><br>
+		<label><input type="radio" name="language" ?checked=${settings.language === "en"} value="en"> ${t('en')}</label><br>
+		<label><input type="radio" name="language" ?checked=${settings.language === "de"} value="de"> ${t('de')}</label><br>
+		<br>
+		<b>Experimental Features:</b><br>
+		<label><input type="checkbox" ?checked=${settings.showMap} id="feature-map"> Show geographic map</label><br>
+		<label><input type="checkbox" ?checked=${settings.showPrices} id="feature-prices"> Show prices</label><br>
+	
+		<button class="button" id="clear" @click=${clearDataStorage}><span>${t('clearstorage')}</span></button>
+		<button class="button" id="save" @click=${saveSettings}><span>${t('save')}</span></button>
+
+		<button class="button" id="quit" style="float:right;" @click=${newAll}><span>Quit Sibelius</span></button>
+	</div>
+`;
+
+const rebuildCache = () => {
+	ConsoleLog('sw update');
+	registration.update();
+	location.reload();
+};
+
+const newAll = () => {
+	ElementById('clear').innerText = "New All";
+};
+
+const saveSettings  = async () => {
+	await modifySettings(settings => {
+		settings.language = document.querySelector('input[name="language"]:checked').value;
+		settings.showRIL100Names = ElementById('ril100').checked;
+		settings.writeDebugLog = ElementById('debug-messages').checked;
+		settings.travelynx = ElementById('travelynx').checked;
+		settings.advancedSelection = ElementById('advancedSelection').checked;
+		settings.showMap = ElementById('feature-prices').checked;
+		settings.showPrices = ElementById('feature-map').checked;
+		return settings;
+	});
+	await applySettings(await getSettings());
+	searchView();
+	hideDiv('overlay');
+};
diff --git a/server/.gitignore b/server/.gitignore
@@ -0,0 +1,2 @@
+node_modules
+database
diff --git a/server/index.js b/server/index.js
@@ -0,0 +1,124 @@
+const level = require('level');
+const { promisify } = require('util');
+
+const createClient = require('hafas-client');
+const profile = require('hafas-client/p/db');
+const hafas = createClient(profile, 'trainsearch');
+
+const createServer = require('hafas-rest-api');
+const port = 1234;
+
+let db;
+
+const generateSlug = () => {
+	const len = 8;
+	let result = '';
+	const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
+	for (let i = 0; i < len; i++)
+		result += characters.charAt(Math.floor(Math.random() * characters.length));
+	return result;
+};
+
+const postJourneys = async (from, to, opt) => {
+	const res = await hafas.journeys(from, to, opt);
+	res.slug = generateSlug();
+	res.indexOffset = 0;
+	opt.from = from;
+	opt.to = to;
+	const {
+		polylines, stopovers, tickets, remarks, language, results,
+		...strippedOpt
+	} = opt;
+	await db.put(res.slug, JSON.stringify({
+		...res,
+		params: strippedOpt,
+		journeys: res.journeys.map(x => x.refreshToken),
+	}));
+	return {
+		...res,
+		params: opt,
+	};
+};
+
+const getJourneys = async (slug, opt) => {
+	const saved = JSON.parse(await db.get(slug));
+	const journeys = await Promise.all(saved.journeys.map(x => hafas.refreshJourney(x, opt)));
+	return {
+		...saved,
+		params: { ...saved.params, ...opt },
+		journeys,
+	};
+};
+
+const createMoreJourneys = mode => async (slug, opt) => {
+	const saved = JSON.parse(await db.get(slug));
+	opt[mode+'Than'] = saved[mode+'Ref'];
+	const res = {
+		...saved,
+		...await hafas.journeys(saved.params.from, saved.params.to, opt)
+	};
+
+	let journeys = await Promise.all(saved.journeys.map(x => hafas.refreshJourney(x, opt)));
+	if (mode === 'earlier') {
+		journeys = res.journeys.concat(journeys);
+		res.indexOffset += res.journeys.length;
+		// keep old laterRef
+		res.laterRef = saved.laterRef;
+	} else {
+		journeys = journeys.concat(res.journeys);
+		// keep old earlierRef
+		res.earlierRef = saved.earlierRef;
+	}
+
+	await db.put(slug, JSON.stringify({
+		...res,
+		journeys: journeys.map(x => x.refreshToken),
+	}));
+	return {
+		...res,
+		params: { ...saved.params, ...opt },
+		journeys,
+	};
+};
+
+const serverConfig = {
+	hostname: 'trainsear.ch',
+	name: 'TrainSearch',
+	aboutPage: false,
+};
+
+const postJourneysRoute = createServer({
+	...hafas,
+	journeys: postJourneys,
+	profile,
+}, serverConfig, () => {}).routes["/journeys"];
+
+const getJourneysRoute = createServer({
+	...hafas,
+	refreshJourney: getJourneys,
+	profile,
+}, serverConfig, () => {}).routes["/journeys/:ref"];
+
+const postMoreJourneysRoute = mode => createServer({
+	...hafas,
+	refreshJourney: createMoreJourneys(mode),
+	profile,
+}, serverConfig, () => {}).routes["/journeys/:ref"];
+
+const server = createServer(hafas, serverConfig, (api) => {
+	api.post('/savedJourneys', postJourneysRoute);
+	api.get('/savedJourneys/:ref', getJourneysRoute);
+	api.post('/savedJourneys/:ref/earlier', postMoreJourneysRoute('earlier'));
+	api.post('/savedJourneys/:ref/later', postMoreJourneysRoute('later'));
+});
+
+(async () => {
+	db = await promisify(level)('database');
+
+	server.listen(port, (err) => {
+		if (err)
+			console.error(err);
+		else
+			console.log('listening on port ' + port);
+	});
+}) ()
diff --git a/server/package-lock.json b/server/package-lock.json
@@ -0,0 +1,1431 @@
+{
+  "name": "trainsearch-server",
+  "version": "1.0.0",
+  "lockfileVersion": 1,
+  "requires": true,
+  "dependencies": {
+    "abstract-leveldown": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/abstract-leveldown/-/abstract-leveldown-7.0.0.tgz",
+      "integrity": "sha512-mFAi5sB/UjpNYglrQ4irzdmr2mbQtE94OJbrAYuK2yRARjH/OACinN1meOAorfnaLPMQdFymSQMlkiDm9AXXKQ==",
+      "requires": {
+        "buffer": "^6.0.3",
+        "is-buffer": "^2.0.5",
+        "level-concat-iterator": "^3.0.0",
+        "level-supports": "^2.0.0",
+        "queue-microtask": "^1.2.3"
+      }
+    },
+    "accepts": {
+      "version": "1.3.7",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
+      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
+      "requires": {
+        "mime-types": "~2.1.24",
+        "negotiator": "0.6.2"
+      }
+    },
+    "argparse": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
+      "requires": {
+        "sprintf-js": "~1.0.2"
+      }
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
+      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
+    },
+    "atomic-sleep": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz",
+      "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ=="
+    },
+    "base64-js": {
+      "version": "1.5.1",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+      "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA=="
+    },
+    "body-parser": {
+      "version": "1.19.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
+      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
+      "requires": {
+        "bytes": "3.1.0",
+        "content-type": "~1.0.4",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "on-finished": "~2.3.0",
+        "qs": "6.7.0",
+        "raw-body": "2.4.0",
+        "type-is": "~1.6.17"
+      },
+      "dependencies": {
+        "bytes": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+        },
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        },
+        "qs": {
+          "version": "6.7.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+        }
+      }
+    },
+    "buffer": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+      "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+      "requires": {
+        "base64-js": "^1.3.1",
+        "ieee754": "^1.2.1"
+      }
+    },
+    "bytes": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
+      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg="
+    },
+    "cached-hafas-client": {
+      "version": "4.0.1",
+      "resolved": "https://registry.npmjs.org/cached-hafas-client/-/cached-hafas-client-4.0.1.tgz",
+      "integrity": "sha512-C97oHCECu2sFwyJpW3z3WH74v9X+FkBLOIOdhmaXeRxZRJSqrRhV+XI0OsogTit2RGuiQo5Ge6QETY9LRJqoow==",
+      "requires": {
+        "common-prefix": "^1.1.0",
+        "debug": "^4.0.0",
+        "ioredis": "^4.22.0",
+        "lodash": "^4.17.10",
+        "quick-lru": "^5.1.1",
+        "shallow-clone": "^3.0.1"
+      }
+    },
+    "catering": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/catering/-/catering-2.0.0.tgz",
+      "integrity": "sha512-aD/WmxhGwUGsVPrj8C80vH7C7GphJilYVSdudoV4u16XdrLF7CVyfBmENsc4tLTVsJJzCRid8GbwJ7mcPLee6Q=="
+    },
+    "character-entities-html4": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-html4/-/character-entities-html4-1.1.4.tgz",
+      "integrity": "sha512-HRcDxZuZqMx3/a+qrzxdBKBPUpxWEq9xw2OPZ3a/174ihfrQKVsFhqtthBInFy1zZ9GgZyFXOatNujm8M+El3g=="
+    },
+    "character-entities-legacy": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/character-entities-legacy/-/character-entities-legacy-1.1.4.tgz",
+      "integrity": "sha512-3Xnr+7ZFS1uxeiUDvV02wQ+QDbc55o97tIV5zHScSPJpcLm/r0DFPcoY3tYRp+VZukxuMeKgXYmsXQHO05zQeA=="
+    },
+    "cluster-key-slot": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.0.tgz",
+      "integrity": "sha512-2Nii8p3RwAPiFwsnZvukotvow2rIHM+yQ6ZcBXGHdniadkYGZYiGmkHJIbZPIV9nfv7m/U1IPMVVcAhoWFeklw=="
+    },
+    "common-prefix": {
+      "version": "1.1.0",
+      "resolved": "https://registry.npmjs.org/common-prefix/-/common-prefix-1.1.0.tgz",
+      "integrity": "sha1-46Xqf6+u/H64TnYFI+GvuYX5DwA="
+    },
+    "compressible": {
+      "version": "2.0.18",
+      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz",
+      "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==",
+      "requires": {
+        "mime-db": ">= 1.43.0 < 2"
+      }
+    },
+    "compression": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
+      "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
+      "requires": {
+        "accepts": "~1.3.5",
+        "bytes": "3.0.0",
+        "compressible": "~2.0.16",
+        "debug": "2.6.9",
+        "on-headers": "~1.0.2",
+        "safe-buffer": "5.1.2",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        }
+      }
+    },
+    "content-disposition": {
+      "version": "0.5.3",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
+      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
+      "requires": {
+        "safe-buffer": "5.1.2"
+      },
+      "dependencies": {
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        }
+      }
+    },
+    "content-type": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+    },
+    "cookie": {
+      "version": "0.4.0",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
+      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg=="
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
+      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw="
+    },
+    "cors": {
+      "version": "2.8.5",
+      "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz",
+      "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==",
+      "requires": {
+        "object-assign": "^4",
+        "vary": "^1"
+      }
+    },
+    "date-fns": {
+      "version": "2.23.0",
+      "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.23.0.tgz",
+      "integrity": "sha512-5ycpauovVyAk0kXNZz6ZoB9AYMZB4DObse7P3BPWmyEjXNORTI8EJ6X0uaSAq4sCHzM1uajzrkr6HnsLQpxGXA=="
+    },
+    "debug": {
+      "version": "4.3.2",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+      "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+      "requires": {
+        "ms": "2.1.2"
+      }
+    },
+    "deferred-leveldown": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/deferred-leveldown/-/deferred-leveldown-6.0.0.tgz",
+      "integrity": "sha512-F6CLAZzNeURojlH4MCigZr54tNz+xDSi06YXsDr5uLSKeF3JKnvnQWTqd+RETh2hbWTJR3qDzGicQOWS5ZQ1BQ==",
+      "requires": {
+        "abstract-leveldown": "^7.0.0",
+        "inherits": "^2.0.3"
+      }
+    },
+    "denque": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/denque/-/denque-1.5.0.tgz",
+      "integrity": "sha512-CYiCSgIF1p6EUByQPlGkKnP1M9g0ZV3qMIrqMqZqdwazygIA/YP2vrbcyl1h/WppKJTdl1F85cXIle+394iDAQ=="
+    },
+    "depd": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
+      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak="
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
+      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
+      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
+    },
+    "emoji-regex": {
+      "version": "6.1.1",
+      "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-6.1.1.tgz",
+      "integrity": "sha1-xs0OwbBkLio8Z6ETfvxeeW2k+I4="
+    },
+    "encodeurl": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
+      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k="
+    },
+    "encoding-down": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/encoding-down/-/encoding-down-7.0.0.tgz",
+      "integrity": "sha512-hor6z2W/ZrVqDYMawQp7VtfEt6BrvYw+mgjWLauUMZsIBjMt1/k5aa+JreLbtjwJdkjrZ39TU+pV5GpHPGRpog==",
+      "requires": {
+        "abstract-leveldown": "^7.0.0",
+        "inherits": "^2.0.3",
+        "level-codec": "^10.0.0",
+        "level-errors": "^3.0.0"
+      }
+    },
+    "entities": {
+      "version": "2.0.3",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.3.tgz",
+      "integrity": "sha512-MyoZ0jgnLvB2X3Lg5HqpFmn1kybDiIfEQmKzTb5apr51Rb+T3KdmMiqa70T+bhGnyv7bQ6WMj2QMHpGMmlrUYQ=="
+    },
+    "errno": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/errno/-/errno-1.0.0.tgz",
+      "integrity": "sha512-3zV5mFS1E8/1bPxt/B0xxzI1snsg3uSCIh6Zo1qKg6iMw93hzPANk9oBFzSFBFrwuVoQuE3rLoouAUfwOAj1wQ==",
+      "requires": {
+        "prr": "~1.0.1"
+      }
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
+      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
+    },
+    "etag": {
+      "version": "1.8.1",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
+      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc="
+    },
+    "express": {
+      "version": "4.17.1",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
+      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
+      "requires": {
+        "accepts": "~1.3.7",
+        "array-flatten": "1.1.1",
+        "body-parser": "1.19.0",
+        "content-disposition": "0.5.3",
+        "content-type": "~1.0.4",
+        "cookie": "0.4.0",
+        "cookie-signature": "1.0.6",
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "finalhandler": "~1.1.2",
+        "fresh": "0.5.2",
+        "merge-descriptors": "1.0.1",
+        "methods": "~1.1.2",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "path-to-regexp": "0.1.7",
+        "proxy-addr": "~2.0.5",
+        "qs": "6.7.0",
+        "range-parser": "~1.2.1",
+        "safe-buffer": "5.1.2",
+        "send": "0.17.1",
+        "serve-static": "1.14.1",
+        "setprototypeof": "1.1.1",
+        "statuses": "~1.5.0",
+        "type-is": "~1.6.18",
+        "utils-merge": "1.0.1",
+        "vary": "~1.1.2"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        },
+        "qs": {
+          "version": "6.7.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
+          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
+        },
+        "safe-buffer": {
+          "version": "5.1.2",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
+        }
+      }
+    },
+    "express-pino-logger": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/express-pino-logger/-/express-pino-logger-6.0.0.tgz",
+      "integrity": "sha512-YjBnalqgsNylRnWEpQGf8YzBP54stpoqX/o+SnpGr04OB7dRIQlsC1qvutFOyRjhLhXIWCe43pYJcjp9zM1Ccg==",
+      "requires": {
+        "pino-http": "^5.3.0"
+      }
+    },
+    "fast-redact": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.0.1.tgz",
+      "integrity": "sha512-kYpn4Y/valC9MdrISg47tZOpYBNoTXKgT9GYXFpHN/jYFs+lFkPoisY+LcBODdKVMY96ATzvzsWv+ES/4Kmufw=="
+    },
+    "fast-safe-stringify": {
+      "version": "2.0.8",
+      "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.8.tgz",
+      "integrity": "sha512-lXatBjf3WPjmWD6DpIZxkeSsCOwqI0maYMpgDlx8g4U2qi4lbjA9oH/HD2a87G+KfsUmo5WbJFmqBZlPxtptag=="
+    },
+    "fast-url-parser": {
+      "version": "1.1.3",
+      "resolved": "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz",
+      "integrity": "sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0=",
+      "requires": {
+        "punycode": "^1.3.2"
+      }
+    },
+    "finalhandler": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
+      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
+      "requires": {
+        "debug": "2.6.9",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "on-finished": "~2.3.0",
+        "parseurl": "~1.3.3",
+        "statuses": "~1.5.0",
+        "unpipe": "~1.0.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          }
+        },
+        "ms": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+          "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+        }
+      }
+    },
+    "flatstr": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/flatstr/-/flatstr-1.0.12.tgz",
+      "integrity": "sha512-4zPxDyhCyiN2wIAtSLI6gc82/EjqZc1onI4Mz/l0pWrAlsSfYH/2ZIcU+e3oA2wDwbzIWNKwa23F8rh6+DRWkw=="
+    },
+    "forwarded": {
+      "version": "0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
+      "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="
+    },
+    "fresh": {
+      "version": "0.5.2",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
+      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac="
+    },
+    "github-slugger": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.3.0.tgz",
+      "integrity": "sha512-gwJScWVNhFYSRDvURk/8yhcFBee6aFjye2a7Lhb2bUyRulpIoek9p0I9Kt7PT67d/nUlZbFu8L9RLiA0woQN8Q==",
+      "requires": {
+        "emoji-regex": ">=6.0.0 <=6.1.1"
+      }
+    },
+    "hafas-client": {
+      "version": "file:../../hafas-client",
+      "requires": {
+        "@derhuerst/br2nl": "^1.0.0",
+        "@derhuerst/round-robin-scheduler": "^1.0.4",
+        "capture-stack-trace": "^1.0.0",
+        "content-type": "^1.0.4",
+        "create-hash": "^1.2.0",
+        "fetch-ponyfill": "^7.0.0",
+        "google-polyline": "^1.0.3",
+        "gps-distance": "0.0.4",
+        "https-proxy-agent": "^5.0.0",
+        "lodash": "^4.17.5",
+        "luxon": "^1.3.0",
+        "object-scan": "^13.0.0",
+        "p-retry": "^4.1.0",
+        "p-throttle": "^4.1.1",
+        "pinkie-promise": "^2.0.1",
+        "qs": "^6.6.0",
+        "slugg": "^1.2.0",
+        "vbb-parse-line": "^1.0.0",
+        "vbb-parse-ticket": "^0.2.1",
+        "vbb-short-station-name": "^1.0.1",
+        "vbb-stations": "^7.1.0",
+        "vbb-translate-ids": "^4.0.0"
+      },
+      "dependencies": {
+        "@derhuerst/br2nl": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/@derhuerst/br2nl/-/br2nl-1.0.0.tgz",
+          "integrity": "sha512-aGzqSMKM9eqHd9orDSe7yOvekRM9EMt9Jbc9vAG+a3jbn50WOTThVQX20c75yk0WBmu+6A5hdHGRM49dlp0I9w=="
+        },
+        "@derhuerst/round-robin-scheduler": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/@derhuerst/round-robin-scheduler/-/round-robin-scheduler-1.0.4.tgz",
+          "integrity": "sha512-2oOeCz+wrLspXUNHET1ToHYK0nRbxzWRr3cRi9tSUzUdG2OEvw5myLdk7JSjueOWKmD26OHSh1M3SS3XSQ1w5w=="
+        },
+        "@types/retry": {
+          "version": "0.12.1",
+          "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.1.tgz",
+          "integrity": "sha512-xoDlM2S4ortawSWORYqsdU+2rxdh4LRW9ytc3zmT37RIKQh6IHyKwwtKhKis9ah8ol07DCkZxPt8BBvPjC6v4g=="
+        },
+        "agent-base": {
+          "version": "6.0.2",
+          "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
+          "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==",
+          "requires": {
+            "debug": "4"
+          }
+        },
+        "call-bind": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
+          "integrity": "sha512-7O+FbCihrB5WGbFYesctwmTKae6rOiIzmz1icreWJ+0aA7LJfuqhEso2T9ncpcFtzMQtzXf2QGGueWJGTYsqrA==",
+          "requires": {
+            "function-bind": "^1.1.1",
+            "get-intrinsic": "^1.0.2"
+          }
+        },
+        "capture-stack-trace": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.1.tgz",
+          "integrity": "sha512-mYQLZnx5Qt1JgB1WEiMCf2647plpGeQ2NMR/5L0HNZzGQo4fuSPnK+wjfPnKZV0aiJDgzmWqqkV/g7JD+DW0qw=="
+        },
+        "cipher-base": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz",
+          "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==",
+          "requires": {
+            "inherits": "^2.0.1",
+            "safe-buffer": "^5.0.1"
+          }
+        },
+        "content-type": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
+          "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA=="
+        },
+        "create-hash": {
+          "version": "1.2.0",
+          "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
+          "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
+          "requires": {
+            "cipher-base": "^1.0.1",
+            "inherits": "^2.0.1",
+            "md5.js": "^1.3.4",
+            "ripemd160": "^2.0.1",
+            "sha.js": "^2.4.0"
+          }
+        },
+        "debug": {
+          "version": "4.3.2",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz",
+          "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==",
+          "requires": {
+            "ms": "2.1.2"
+          }
+        },
+        "fetch-ponyfill": {
+          "version": "7.1.0",
+          "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz",
+          "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==",
+          "requires": {
+            "node-fetch": "~2.6.1"
+          }
+        },
+        "function-bind": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
+          "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
+        },
+        "get-intrinsic": {
+          "version": "1.1.1",
+          "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.1.1.tgz",
+          "integrity": "sha512-kWZrnVM42QCiEA2Ig1bG8zjoIMOgxWwYCEeNdwY6Tv/cOSeGpcoX4pXHfKUxNKVoArnrEr2e9srnAxxGIraS9Q==",
+          "requires": {
+            "function-bind": "^1.1.1",
+            "has": "^1.0.3",
+            "has-symbols": "^1.0.1"
+          }
+        },
+        "google-polyline": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/google-polyline/-/google-polyline-1.0.3.tgz",
+          "integrity": "sha512-36BnqVxmVcR8lTvzO6aeXdICNChAwQLlfMkR1P9IBpTWE8hA6bAbQHCVArwMHB5WIMq9owywtAkjioe3crNq4Q=="
+        },
+        "gps-distance": {
+          "version": "0.0.4",
+          "resolved": "https://registry.npmjs.org/gps-distance/-/gps-distance-0.0.4.tgz",
+          "integrity": "sha1-8LSoFyxmj97AZSkaSZm5YfGRbRA="
+        },
+        "has": {
+          "version": "1.0.3",
+          "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
+          "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
+          "requires": {
+            "function-bind": "^1.1.1"
+          }
+        },
+        "has-symbols": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz",
+          "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw=="
+        },
+        "hash-base": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz",
+          "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==",
+          "requires": {
+            "inherits": "^2.0.4",
+            "readable-stream": "^3.6.0",
+            "safe-buffer": "^5.2.0"
+          }
+        },
+        "https-proxy-agent": {
+          "version": "5.0.0",
+          "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz",
+          "integrity": "sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA==",
+          "requires": {
+            "agent-base": "6",
+            "debug": "4"
+          }
+        },
+        "inherits": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+          "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+        },
+        "lodash": {
+          "version": "4.17.21",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+          "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+        },
+        "lodash.get": {
+          "version": "4.4.2",
+          "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz",
+          "integrity": "sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk="
+        },
+        "luxon": {
+          "version": "1.28.0",
+          "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
+          "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ=="
+        },
+        "md5.js": {
+          "version": "1.3.5",
+          "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
+          "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
+          "requires": {
+            "hash-base": "^3.0.0",
+            "inherits": "^2.0.1",
+            "safe-buffer": "^5.1.2"
+          }
+        },
+        "ms": {
+          "version": "2.1.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+        },
+        "node-fetch": {
+          "version": "2.6.1",
+          "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
+          "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
+        },
+        "object-inspect": {
+          "version": "1.11.0",
+          "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.11.0.tgz",
+          "integrity": "sha512-jp7ikS6Sd3GxQfZJPyH3cjcbJF6GZPClgdV+EFygjFLQ5FmW/dRUnTd9PQ9k0JhoNDabWFbpF1yCdSWCC6gexg=="
+        },
+        "object-scan": {
+          "version": "13.9.3",
+          "resolved": "https://registry.npmjs.org/object-scan/-/object-scan-13.9.3.tgz",
+          "integrity": "sha512-gb27kO8ovRqt9V3BfPygvV/Dfd5cIk+QEX/V5D85M7kYimkcb9iTyKZLjSaojyPJUk/Ugr7yU36xaKaIVHbMOA=="
+        },
+        "p-retry": {
+          "version": "4.6.1",
+          "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.1.tgz",
+          "integrity": "sha512-e2xXGNhZOZ0lfgR9kL34iGlU8N/KO0xZnQxVEwdeOvpqNDQfdnxIYizvWtK8RglUa3bGqI8g0R/BdfzLMxRkiA==",
+          "requires": {
+            "@types/retry": "^0.12.0",
+            "retry": "^0.13.1"
+          }
+        },
+        "p-throttle": {
+          "version": "4.1.1",
+          "resolved": "https://registry.npmjs.org/p-throttle/-/p-throttle-4.1.1.tgz",
+          "integrity": "sha512-TuU8Ato+pRTPJoDzYD4s7ocJYcNSEZRvlxoq3hcPI2kZDZ49IQ1Wkj7/gDJc3X7XiEAAvRGtDzdXJI0tC3IL1g=="
+        },
+        "pinkie": {
+          "version": "2.0.4",
+          "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
+          "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
+        },
+        "pinkie-promise": {
+          "version": "2.0.1",
+          "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
+          "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
+          "requires": {
+            "pinkie": "^2.0.0"
+          }
+        },
+        "qs": {
+          "version": "6.10.1",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.1.tgz",
+          "integrity": "sha512-M528Hph6wsSVOBiYUnGf+K/7w0hNshs/duGsNXPUCLH5XAqjEtiPGwNONLV0tBH8NoGb0mvD5JubnUTrujKDTg==",
+          "requires": {
+            "side-channel": "^1.0.4"
+          }
+        },
+        "readable-stream": {
+          "version": "3.6.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+          "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+          "requires": {
+            "inherits": "^2.0.3",
+            "string_decoder": "^1.1.1",
+            "util-deprecate": "^1.0.1"
+          }
+        },
+        "retry": {
+          "version": "0.13.1",
+          "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz",
+          "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg=="
+        },
+        "ripemd160": {
+          "version": "2.0.2",
+          "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
+          "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
+          "requires": {
+            "hash-base": "^3.0.0",
+            "inherits": "^2.0.1"
+          }
+        },
+        "safe-buffer": {
+          "version": "5.2.1",
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+          "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+        },
+        "sha.js": {
+          "version": "2.4.11",
+          "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
+          "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
+          "requires": {
+            "inherits": "^2.0.1",
+            "safe-buffer": "^5.0.1"
+          }
+        },
+        "side-channel": {
+          "version": "1.0.4",
+          "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
+          "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==",
+          "requires": {
+            "call-bind": "^1.0.0",
+            "get-intrinsic": "^1.0.2",
+            "object-inspect": "^1.9.0"
+          }
+        },
+        "slugg": {
+          "version": "1.2.1",
+          "resolved": "https://registry.npmjs.org/slugg/-/slugg-1.2.1.tgz",
+          "integrity": "sha1-51KvIkGvPycURjxd4iXOpHYIdAo="
+        },
+        "string_decoder": {
+          "version": "1.3.0",
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+          "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+          "requires": {
+            "safe-buffer": "~5.2.0"
+          }
+        },
+        "util-deprecate": {
+          "version": "1.0.2",
+          "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+          "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+        },
+        "vbb-parse-line": {
+          "version": "1.0.0",
+          "resolved": "https://registry.npmjs.org/vbb-parse-line/-/vbb-parse-line-1.0.0.tgz",
+          "integrity": "sha512-/xtFJAWmoulUD3kWX9kPQyn9tDMncuGu22Bfe1C1/Pwf/pJAGd7zKA1IpRf9rrdEP+AN1ECD6SHsGbNcqLbR5w=="
+        },
+        "vbb-parse-ticket": {
+          "version": "0.2.1",
+          "resolved": "https://registry.npmjs.org/vbb-parse-ticket/-/vbb-parse-ticket-0.2.1.tgz",
+          "integrity": "sha512-Di1/AOrKGrGTBfdrZZXSCmq73E/RVuGys12BAFraHu5Swwj/TTXfvV8FrnHifCHEMoZIfLmH4avnF7xVa+46Sw=="
+        },
+        "vbb-short-station-name": {
+          "version": "1.0.1",
+          "resolved": "https://registry.npmjs.org/vbb-short-station-name/-/vbb-short-station-name-1.0.1.tgz",
+          "integrity": "sha512-3pAW9RtwqTeQvTABYRJVkBNmbxkCBxrQyALNRkG+owiZUgt4yT3aH2ln25TV0EzEqZzgjVjcK1RwOyL/MMYz5w=="
+        },
+        "vbb-stations": {
+          "version": "7.3.1",
+          "resolved": "https://registry.npmjs.org/vbb-stations/-/vbb-stations-7.3.1.tgz",
+          "integrity": "sha512-mLr7kG9YI3Z9hYTKUvxkMjo0TBr8B8fADPNsUAQ1pLbJmVRUwBWX5oug1EDsqyG2MiuKwiPWJqu4OfNEcXF8Sg==",
+          "requires": {
+            "lodash.get": "^4.4.2"
+          }
+        },
+        "vbb-translate-ids": {
+          "version": "4.0.0",
+          "resolved": "https://registry.npmjs.org/vbb-translate-ids/-/vbb-translate-ids-4.0.0.tgz",
+          "integrity": "sha512-acc8aCheKRO10vEMIN7a/1chAkD30sW28MUkLbylOtCHD7aGOTGnB6ztGeszFER8qpx915pMyoWggGteF4vB3g=="
+        }
+      }
+    },
+    "hafas-rest-api": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/hafas-rest-api/-/hafas-rest-api-3.6.0.tgz",
+      "integrity": "sha512-HbucvFgZmuliPqn7k/lx3QWNg+NeN7Gu6AcyYNR+7hKl3DwSvqXLKSZ7U47PjV3G5Nkr8LkZrYYUnr9TKWPqPw==",
+      "requires": {
+        "compression": "^1.7.2",
+        "cors": "^2.8.4",
+        "date-fns": "^2.12.0",
+        "express": "^4.16.2",
+        "express-pino-logger": "^6.0.0",
+        "github-slugger": "^1.3.0",
+        "hsts": "^2.1.0",
+        "http-link-header": "^1.0.2",
+        "lodash": "^4.17.15",
+        "luxon": "^1.21.1",
+        "markdown-it": "^10.0.0",
+        "on-headers": "^1.0.2",
+        "parse-human-relative-time": "^2.0.2",
+        "pino": "^6.11.0",
+        "shorthash": "0.0.2",
+        "stringify-entities": "^3.0.0"
+      }
+    },
+    "hsts": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/hsts/-/hsts-2.2.0.tgz",
+      "integrity": "sha512-ToaTnQ2TbJkochoVcdXYm4HOCliNozlviNsg+X2XQLQvZNI/kCHR9rZxVYpJB3UPcHz80PgxRyWQ7PdU1r+VBQ==",
+      "requires": {
+        "depd": "2.0.0"
+      },
+      "dependencies": {
+        "depd": {
+          "version": "2.0.0",
+          "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
+          "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="
+        }
+      }
+    },
+    "http-errors": {
+      "version": "1.7.2",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
+      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
+      "requires": {
+        "depd": "~1.1.2",
+        "inherits": "2.0.3",
+        "setprototypeof": "1.1.1",
+        "statuses": ">= 1.5.0 < 2",
+        "toidentifier": "1.0.0"
+      },
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.3",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
+        }
+      }
+    },
+    "http-link-header": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/http-link-header/-/http-link-header-1.0.3.tgz",
+      "integrity": "sha512-nARK1wSKoBBrtcoESlHBx36c1Ln/gnbNQi1eB6MeTUefJIT3NvUOsV15bClga0k38f0q/kN5xxrGSDS3EFnm9w=="
+    },
+    "iconv-lite": {
+      "version": "0.4.24",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
+      "requires": {
+        "safer-buffer": ">= 2.1.2 < 3"
+      }
+    },
+    "ieee754": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+      "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="
+    },
+    "inherits": {
+      "version": "2.0.4",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+    },
+    "ioredis": {
+      "version": "4.27.7",
+      "resolved": "https://registry.npmjs.org/ioredis/-/ioredis-4.27.7.tgz",
+      "integrity": "sha512-lqvFFmUyGIHlrNyDvBoakzy1+ioJzNyoP6CP97GWtdTjWq9IOAnv6l0HUTsqhvd/z9etGgtrDHZ4kWCMAwNkug==",
+      "requires": {
+        "cluster-key-slot": "^1.1.0",
+        "debug": "^4.3.1",
+        "denque": "^1.1.0",
+        "lodash.defaults": "^4.2.0",
+        "lodash.flatten": "^4.4.0",
+        "lodash.isarguments": "^3.1.0",
+        "p-map": "^2.1.0",
+        "redis-commands": "1.7.0",
+        "redis-errors": "^1.2.0",
+        "redis-parser": "^3.0.0",
+        "standard-as-callback": "^2.1.0"
+      }
+    },
+    "ipaddr.js": {
+      "version": "1.9.1",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
+      "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="
+    },
+    "is-buffer": {
+      "version": "2.0.5",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
+      "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ=="
+    },
+    "kind-of": {
+      "version": "6.0.3",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+      "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw=="
+    },
+    "level": {
+      "version": "7.0.0",
+      "resolved": "https://registry.npmjs.org/level/-/level-7.0.0.tgz",
+      "integrity": "sha512-QrBnjcWywalh86ms9hfizvxT5aBHrgWEu6rLChS9tFE2wwFU3aI1r0v+2SSZIyeUr4O4PFo8+sCc1kebahdhlw==",
+      "requires": {
+        "level-js": "^6.0.0",
+        "level-packager": "^6.0.0",
+        "leveldown": "^6.0.0"
+      }
+    },
+    "level-codec": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/level-codec/-/level-codec-10.0.0.tgz",
+      "integrity": "sha512-QW3VteVNAp6c/LuV6nDjg7XDXx9XHK4abmQarxZmlRSDyXYk20UdaJTSX6yzVvQ4i0JyWSB7jert0DsyD/kk6g==",
+      "requires": {
+        "buffer": "^6.0.3"
+      }
+    },
+    "level-concat-iterator": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/level-concat-iterator/-/level-concat-iterator-3.0.0.tgz",
+      "integrity": "sha512-UHGiIdj+uiFQorOrURRvJF3Ei0uHc89ciM/aRi0qsWDV2f0HXypeXUPhJKL6DsONgSR76Pc0AI4sKYEYYRn2Dg=="
+    },
+    "level-errors": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/level-errors/-/level-errors-3.0.0.tgz",
+      "integrity": "sha512-MZXOQT061uEjxxxq4C/Jf+M3RdEKK9e3NbxlN7yOp1LDYoLVAhE2i1j0b7XqXfl8FjFtUL7phwr3Sn0wXXoMqA==",
+      "requires": {
+        "errno": "^1.0.0"
+      }
+    },
+    "level-iterator-stream": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmjs.org/level-iterator-stream/-/level-iterator-stream-5.0.0.tgz",
+      "integrity": "sha512-wnb1+o+CVFUDdiSMR/ZymE2prPs3cjVLlXuDeSq9Zb8o032XrabGEXcTCsBxprAtseO3qvFeGzh6406z9sOTRA==",
+      "requires": {
+        "inherits": "^2.0.4",
+        "readable-stream": "^3.4.0"
+      }
+    },
+    "level-js": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/level-js/-/level-js-6.0.0.tgz",
+      "integrity": "sha512-7dp7JuaoQoqKW4ZGvrV1RB5f51/ktLdEo9fSDsh3Ofmg7sKCMu3X0CIngbY/IUz/YyskhN7LRvEVIkZHCY3LKQ==",
+      "requires": {
+        "abstract-leveldown": "^7.0.0",
+        "buffer": "^6.0.3",
+        "inherits": "^2.0.3",
+        "ltgt": "^2.1.2"
+      }
+    },
+    "level-packager": {
+      "version": "6.0.0",
+      "resolved": "https://registry.npmjs.org/level-packager/-/level-packager-6.0.0.tgz",
+      "integrity": "sha512-me656XRWfOVqs9wc+mWckZ6Rb1GuP33ndN4ZntDXwXFspX8cGA++Y+YqJsdE/mjTiipTuxXf047Z4rV62nOVuw==",
+      "requires": {
+        "encoding-down": "^7.0.0",
+        "levelup": "^5.0.0"
+      }
+    },
+    "level-supports": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/level-supports/-/level-supports-2.0.0.tgz",
+      "integrity": "sha512-8UJgzo1pvWP1wq80ZlkL19fPeK7tlyy0sBY90+2pj0x/kvzHCoLDWyuFJJMrsTn33oc7hbMkS3SkjCxMRPHWaw=="
+    },
+    "leveldown": {
+      "version": "6.0.1",
+      "resolved": "https://registry.npmjs.org/leveldown/-/leveldown-6.0.1.tgz",
+      "integrity": "sha512-D1fz5G58UrLBg5pXcN1pNxWtNLXwBiZsYt06XqjhD5zBHj/ws7xvZe3K0ZAhCbYuL9b4nbRCim8Z15HYWL2exQ==",
+      "requires": {
+        "abstract-leveldown": "^7.0.0",
+        "napi-macros": "~2.0.0",
+        "node-gyp-build": "~4.2.1"
+      }
+    },
+    "levelup": {
+      "version": "5.0.1",
+      "resolved": "https://registry.npmjs.org/levelup/-/levelup-5.0.1.tgz",
+      "integrity": "sha512-MJvQgBRQmB+E5+d6Qbxqm05N4U9NzOxGNhXx0rR8maRBwmVuVV+m4IV3N4HzZJW8JwiJ0jj92RZaytcD+Hr1CA==",
+      "requires": {
+        "catering": "^2.0.0",
+        "deferred-leveldown": "^6.0.0",
+        "level-errors": "^3.0.0",
+        "level-iterator-stream": "^5.0.0",
+        "level-supports": "^2.0.0",
+        "queue-microtask": "^1.2.3"
+      }
+    },
+    "linkify-it": {
+      "version": "2.2.0",
+      "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-2.2.0.tgz",
+      "integrity": "sha512-GnAl/knGn+i1U/wjBz3akz2stz+HrHLsxMwHQGofCDfPvlf+gDKN58UtfmUquTY4/MXeE2x7k19KQmeoZi94Iw==",
+      "requires": {
+        "uc.micro": "^1.0.1"
+      }
+    },
+    "lodash": {
+      "version": "4.17.21",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
+    },
+    "lodash.defaults": {
+      "version": "4.2.0",
+      "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+      "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
+    },
+    "lodash.flatten": {
+      "version": "4.4.0",
+      "resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
+      "integrity": "sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8="
+    },
+    "lodash.isarguments": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+      "integrity": "sha1-L1c9hcaiQon/AGY7SRwdM4/zRYo="
+    },
+    "ltgt": {
+      "version": "2.2.1",
+      "resolved": "https://registry.npmjs.org/ltgt/-/ltgt-2.2.1.tgz",
+      "integrity": "sha1-81ypHEk/e3PaDgdJUwTxezH4fuU="
+    },
+    "luxon": {
+      "version": "1.28.0",
+      "resolved": "https://registry.npmjs.org/luxon/-/luxon-1.28.0.tgz",
+      "integrity": "sha512-TfTiyvZhwBYM/7QdAVDh+7dBTBA29v4ik0Ce9zda3Mnf8on1S5KJI8P2jKFZ8+5C0jhmr0KwJEO/Wdpm0VeWJQ=="
+    },
+    "markdown-it": {
+      "version": "10.0.0",
+      "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-10.0.0.tgz",
+      "integrity": "sha512-YWOP1j7UbDNz+TumYP1kpwnP0aEa711cJjrAQrzd0UXlbJfc5aAq0F/PZHjiioqDC1NKgvIMX+o+9Bk7yuM2dg==",
+      "requires": {
+        "argparse": "^1.0.7",
+        "entities": "~2.0.0",
+        "linkify-it": "^2.0.0",
+        "mdurl": "^1.0.1",
+        "uc.micro": "^1.0.5"
+      }
+    },
+    "mdurl": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz",
+      "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4="
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
+      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g="
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
+      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E="
+    },
+    "methods": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
+      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4="
+    },
+    "mime": {
+      "version": "1.6.0",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
+      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg=="
+    },
+    "mime-db": {
+      "version": "1.49.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.49.0.tgz",
+      "integrity": "sha512-CIc8j9URtOVApSFCQIF+VBkX1RwXp/oMMOrqdyXSBXq5RWNEsRfyj1kiRnQgmNXmHxPoFIxOroKA3zcU9P+nAA=="
+    },
+    "mime-types": {
+      "version": "2.1.32",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.32.tgz",
+      "integrity": "sha512-hJGaVS4G4c9TSMYh2n6SQAGrC4RnfU+daP8G7cSCmaqNjiOoUY0VHCMS42pxnQmVF1GWwFhbHWn3RIxCqTmZ9A==",
+      "requires": {
+        "mime-db": "1.49.0"
+      }
+    },
+    "ms": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+      "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+    },
+    "napi-macros": {
+      "version": "2.0.0",
+      "resolved": "https://registry.npmjs.org/napi-macros/-/napi-macros-2.0.0.tgz",
+      "integrity": "sha512-A0xLykHtARfueITVDernsAWdtIMbOJgKgcluwENp3AlsKN/PloyO10HtmoqnFAQAcxPkgZN7wdfPfEd0zNGxbg=="
+    },
+    "negotiator": {
+      "version": "0.6.2",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
+      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw=="
+    },
+    "node-gyp-build": {
+      "version": "4.2.3",
+      "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.2.3.tgz",
+      "integrity": "sha512-MN6ZpzmfNCRM+3t57PTJHgHyw/h4OWnZ6mR8P5j/uZtqQr46RRuDE/P+g3n0YR/AiYXeWixZZzaip77gdICfRg=="
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
+      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
+      "requires": {
+        "ee-first": "1.1.1"
+      }
+    },
+    "on-headers": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
+      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA=="
+    },
+    "p-map": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/p-map/-/p-map-2.1.0.tgz",
+      "integrity": "sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw=="
+    },
+    "parse-human-relative-time": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmjs.org/parse-human-relative-time/-/parse-human-relative-time-2.0.2.tgz",
+      "integrity": "sha512-ZFejCYR0BO7/9B76w7Ur/GWpI6uu/Y2cyHrnZrOPs6jwF7zYrnzXR1fzp3LTqQ3TIVJwiyy5OM1ZHxIBz/i8rA=="
+    },
+    "parseurl": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
+      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
+      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w="
+    },
+    "pino": {
+      "version": "6.13.0",
+      "resolved": "https://registry.npmjs.org/pino/-/pino-6.13.0.tgz",
+      "integrity": "sha512-mRXSTfa34tbfrWqCIp1sUpZLqBhcoaGapoyxfEwaWwJGMpLijlRdDKIQUyvq4M3DUfFH5vEglwSw8POZYwbThA==",
+      "requires": {
+        "fast-redact": "^3.0.0",
+        "fast-safe-stringify": "^2.0.8",
+        "flatstr": "^1.0.12",
+        "pino-std-serializers": "^3.1.0",
+        "quick-format-unescaped": "^4.0.3",
+        "sonic-boom": "^1.0.2"
+      },
+      "dependencies": {
+        "pino-std-serializers": {
+          "version": "3.2.0",
+          "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-3.2.0.tgz",
+          "integrity": "sha512-EqX4pwDPrt3MuOAAUBMU0Tk5kR/YcCM5fNPEzgCO2zJ5HfX0vbiH9HbJglnyeQsN96Kznae6MWD47pZB5avTrg=="
+        }
+      }
+    },
+    "pino-http": {
+      "version": "5.6.0",
+      "resolved": "https://registry.npmjs.org/pino-http/-/pino-http-5.6.0.tgz",
+      "integrity": "sha512-sf1SsfkgsOb8UaK/DdXu9N036lxkeyOcHBMvHNbDAjfg8pFU0c6/SqrrY9OAK8VhW+Ej80KhA+rF8o8sArquxA==",
+      "requires": {
+        "fast-url-parser": "^1.1.3",
+        "pino": "^6.13.0",
+        "pino-std-serializers": "^4.0.0"
+      }
+    },
+    "pino-std-serializers": {
+      "version": "4.0.0",
+      "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-4.0.0.tgz",
+      "integrity": "sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q=="
+    },
+    "proxy-addr": {
+      "version": "2.0.7",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
+      "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
+      "requires": {
+        "forwarded": "0.2.0",
+        "ipaddr.js": "1.9.1"
+      }
+    },
+    "prr": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
+      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY="
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
+      "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
+    },
+    "queue-microtask": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
+      "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A=="
+    },
+    "quick-format-unescaped": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.3.tgz",
+      "integrity": "sha512-MaL/oqh02mhEo5m5J2rwsVL23Iw2PEaGVHgT2vFt8AAsr0lfvQA5dpXo9TPu0rz7tSBdUPgkbam0j/fj5ZM8yg=="
+    },
+    "quick-lru": {
+      "version": "5.1.1",
+      "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
+      "integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
+    },
+    "range-parser": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
+      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="
+    },
+    "raw-body": {
+      "version": "2.4.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
+      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
+      "requires": {
+        "bytes": "3.1.0",
+        "http-errors": "1.7.2",
+        "iconv-lite": "0.4.24",
+        "unpipe": "1.0.0"
+      },
+      "dependencies": {
+        "bytes": {
+          "version": "3.1.0",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
+          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
+        }
+      }
+    },
+    "readable-stream": {
+      "version": "3.6.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz",
+      "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==",
+      "requires": {
+        "inherits": "^2.0.3",
+        "string_decoder": "^1.1.1",
+        "util-deprecate": "^1.0.1"
+      }
+    },
+    "redis-commands": {
+      "version": "1.7.0",
+      "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.7.0.tgz",
+      "integrity": "sha512-nJWqw3bTFy21hX/CPKHth6sfhZbdiHP6bTawSgQBlKOVRG7EZkfHbbHwQJnrE4vsQf0CMNE+3gJ4Fmm16vdVlQ=="
+    },
+    "redis-errors": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/redis-errors/-/redis-errors-1.2.0.tgz",
+      "integrity": "sha1-62LSrbFeTq9GEMBK/hUpOEJQq60="
+    },
+    "redis-parser": {
+      "version": "3.0.0",
+      "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-3.0.0.tgz",
+      "integrity": "sha1-tm2CjNyv5rS4pCin3vTGvKwxyLQ=",
+      "requires": {
+        "redis-errors": "^1.0.0"
+      }
+    },
+    "safe-buffer": {
+      "version": "5.2.1",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+      "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="
+    },
+    "safer-buffer": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+    },
+    "send": {
+      "version": "0.17.1",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
+      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
+      "requires": {
+        "debug": "2.6.9",
+        "depd": "~1.1.2",
+        "destroy": "~1.0.4",
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "etag": "~1.8.1",
+        "fresh": "0.5.2",
+        "http-errors": "~1.7.2",
+        "mime": "1.6.0",
+        "ms": "2.1.1",
+        "on-finished": "~2.3.0",
+        "range-parser": "~1.2.1",
+        "statuses": "~1.5.0"
+      },
+      "dependencies": {
+        "debug": {
+          "version": "2.6.9",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
+          "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
+          "requires": {
+            "ms": "2.0.0"
+          },
+          "dependencies": {
+            "ms": {
+              "version": "2.0.0",
+              "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
+              "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
+            }
+          }
+        },
+        "ms": {
+          "version": "2.1.1",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg=="
+        }
+      }
+    },
+    "serve-static": {
+      "version": "1.14.1",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
+      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
+      "requires": {
+        "encodeurl": "~1.0.2",
+        "escape-html": "~1.0.3",
+        "parseurl": "~1.3.3",
+        "send": "0.17.1"
+      }
+    },
+    "setprototypeof": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
+      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw=="
+    },
+    "shallow-clone": {
+      "version": "3.0.1",
+      "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
+      "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==",
+      "requires": {
+        "kind-of": "^6.0.2"
+      }
+    },
+    "shorthash": {
+      "version": "0.0.2",
+      "resolved": "https://registry.npmjs.org/shorthash/-/shorthash-0.0.2.tgz",
+      "integrity": "sha1-WbJo7sveWQOLMNogK8+93rLEpOs="
+    },
+    "sonic-boom": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-1.4.1.tgz",
+      "integrity": "sha512-LRHh/A8tpW7ru89lrlkU4AszXt1dbwSjVWguGrmlxE7tawVmDBlI1PILMkXAxJTwqhgsEeTHzj36D5CmHgQmNg==",
+      "requires": {
+        "atomic-sleep": "^1.0.0",
+        "flatstr": "^1.0.12"
+      }
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
+    },
+    "standard-as-callback": {
+      "version": "2.1.0",
+      "resolved": "https://registry.npmjs.org/standard-as-callback/-/standard-as-callback-2.1.0.tgz",
+      "integrity": "sha512-qoRRSyROncaz1z0mvYqIE4lCd9p2R90i6GxW3uZv5ucSu8tU7B5HXUP1gG8pVZsYNVaXjk8ClXHPttLyxAL48A=="
+    },
+    "statuses": {
+      "version": "1.5.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
+      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow="
+    },
+    "string_decoder": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+      "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+      "requires": {
+        "safe-buffer": "~5.2.0"
+      }
+    },
+    "stringify-entities": {
+      "version": "3.1.0",
+      "resolved": "https://registry.npmjs.org/stringify-entities/-/stringify-entities-3.1.0.tgz",
+      "integrity": "sha512-3FP+jGMmMV/ffZs86MoghGqAoqXAdxLrJP4GUdrDN1aIScYih5tuIO3eF4To5AJZ79KDZ8Fpdy7QJnK8SsL1Vg==",
+      "requires": {
+        "character-entities-html4": "^1.0.0",
+        "character-entities-legacy": "^1.0.0",
+        "xtend": "^4.0.0"
+      }
+    },
+    "toidentifier": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
+      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
+    },
+    "type-is": {
+      "version": "1.6.18",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
+      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
+      "requires": {
+        "media-typer": "0.3.0",
+        "mime-types": "~2.1.24"
+      }
+    },
+    "uc.micro": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-1.0.6.tgz",
+      "integrity": "sha512-8Y75pvTYkLJW2hWQHXxoqRgV7qb9B+9vFEtidML+7koHUFapnVJAZ6cKs+Qjz5Aw3aZWHMC6u0wJE3At+nSGwA=="
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
+      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
+    },
+    "utils-merge": {
+      "version": "1.0.1",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
+      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM="
+    },
+    "vary": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
+      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw="
+    },
+    "xtend": {
+      "version": "4.0.2",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
+      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
+    }
+  }
+}
diff --git a/server/package.json b/server/package.json
@@ -0,0 +1,17 @@
+{
+  "name": "trainsearch-server",
+  "version": "1.0.0",
+  "description": "",
+  "main": "index.js",
+  "scripts": {
+    "test": "echo \"Error: no test specified\" && exit 1"
+  },
+  "author": "",
+  "license": "AGPL-3.0",
+  "dependencies": {
+    "cached-hafas-client": "^4.0.1",
+    "hafas-client": "../../hafas-client",
+    "hafas-rest-api": "^3.6.0",
+    "level": "^7.0.0"
+  }
+}