Bc stops data as JSON (#7)

* Start script to generate BC data

* Finished BC data

* moved file slightly to account for future addition of OCCT and added /stops endpoint to server

---------

Co-authored-by: Pagwin <git@pagwin.xyz>
This commit is contained in:
Levi Lesches 2025-04-24 16:39:18 -04:00 committed by GitHub
parent 8b58db6c6d
commit c39cbab3dd
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 10047 additions and 11 deletions

View file

@ -26,7 +26,7 @@ json object describing a route, I'm planning on this having an infinite cache ti
"times":[ "times":[
{"dotw": "Mo, Tu, We, Th, Fr, Sa or Su", "time": "HH:MM"}, {"dotw": "Mo, Tu, We, Th, Fr, Sa or Su", "time": "HH:MM"},
] ]
}, },
... ...
] ]
}, },
@ -36,6 +36,19 @@ json object describing a route, I'm planning on this having an infinite cache ti
} }
``` ```
## `GET /stops`
```yaml
[
{
"name": {name},
"longitude": {longitude},
"latitude": {latitude},
# "provider": {occt|bc},
"routeID":
}
]
## `/stops/{id}` ## `/stops/{id}`
```yaml ```yaml

149
src/client/bin/bc.dart Normal file
View file

@ -0,0 +1,149 @@
import "dart:convert";
import "dart:io";
import "package:csv/csv.dart";
/// Utils on [Map].
extension MapUtils<K, V> on Map<K, V> {
/// Gets all the keys and values as 2-element records.
Iterable<(K, V)> get records => entries.map((entry) => (entry.key, entry.value));
}
extension on Directory {
String operator /(String child) => "$path/$child";
}
final serverDir = Directory("../server");
final dataDir = Directory(serverDir / "data/BCT");
final tripsFile = File(dataDir / "stop_times.txt");
final routesFile = File(dataDir / "trips.txt");
final stopsFile = File(dataDir / "stops.txt");
final routeNamesFile = File(dataDir / "routes.txt");
final outputFile = File(serverDir / "GET_STOPS.json");
extension type TripID(String id) { }
extension type StopID(String id) { }
extension type RouteID(String id) { }
class Stop {
final StopID id;
final double latitude;
final double longitude;
final String name;
final String description;
final String provider;
final Set<String> routes = {};
Stop({
required this.id,
required this.latitude,
required this.longitude,
required this.name,
required this.description,
required this.provider,
});
Map<String, dynamic> toJson() => {
"id": id.id,
"name": name,
"description": description,
"latitude": latitude,
"longitude": longitude,
"provider": provider,
"routes": routes.toList(),
};
}
final converter = CsvCodec(shouldParseNumbers: false).decoder;
Future<Map<TripID, Set<StopID>>> getTrips() async {
final contents = await tripsFile.readAsString();
final csv = converter.convert(contents);
final result = <TripID, Set<StopID>>{};
for (final row in csv.skip(1)) {
final tripId = TripID(row[0]);
final stopId = StopID(row[3]);
result[tripId] ??= <StopID>{};
result[tripId]!.add(stopId);
}
return result;
}
Future<Map<TripID, RouteID>> getRoutes() async {
final contents = await routesFile.readAsString();
final csv = converter.convert(contents);
final result = <TripID, RouteID>{};
for (final row in csv.skip(1)) {
final routeID = RouteID(row[0]);
final tripID = TripID(row[2]);
result[tripID] = routeID;
}
return result;
}
Future<Map<RouteID, String>> getRouteNames() async {
final contents = await routeNamesFile.readAsString();
final csv = converter.convert(contents);
return {
for (final row in csv.skip(1))
RouteID(row[0]): row[3],
};
}
Future<Map<StopID, Stop>> getStops() async {
final contents = await stopsFile.readAsString();
final csv = converter.convert(contents);
final result = <StopID, Stop>{};
for (final row in csv.skip(1)) {
final stopID = StopID(row[0]);
final name = row[2];
final description = row[3];
final latitude = double.parse(row[4]);
final longitude = double.parse(row[5]);
final stop = Stop(
id: stopID,
name: name,
description: description,
latitude: latitude,
longitude: longitude,
provider: "BC Transit",
);
result[stopID] = stop;
}
return result;
}
void findRoutesForStops({
required Iterable<Stop> stops,
required Map<TripID, Set<StopID>> trips,
required Map<TripID, RouteID> routes,
required Map<RouteID, String> routeNames,
}) {
for (final stop in stops) {
for (final (tripID, trip) in trips.records) {
if (!trip.contains(stop.id)) continue;
final routeID = routes[tripID]!;
final routeName = routeNames[routeID]!;
stop.routes.add(routeName);
}
}
}
Future<void> outputJson(Iterable<Stop> stops) async {
final result = [
for (final stop in stops)
stop.toJson(),
];
const encoder = JsonEncoder.withIndent(" ");
final contents = encoder.convert(result);
await outputFile.writeAsString(contents);
}
void main() async {
final trips = await getTrips();
final routes = await getRoutes();
final stops = await getStops();
final routeNames = await getRouteNames();
findRoutesForStops(stops: stops.values, trips: trips, routes: routes, routeNames: routeNames);
await outputJson(stops.values);
}

View file

@ -53,4 +53,6 @@ class ApiService extends Service {
), ),
PathStep.fromJson, PathStep.fromJson,
); );
} }

426
src/client/pubspec.lock Normal file
View file

@ -0,0 +1,426 @@
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
args:
dependency: transitive
description:
name: args
sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04
url: "https://pub.dev"
source: hosted
version: "2.7.0"
async:
dependency: transitive
description:
name: async
sha256: "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb"
url: "https://pub.dev"
source: hosted
version: "2.13.0"
boolean_selector:
dependency: transitive
description:
name: boolean_selector
sha256: "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea"
url: "https://pub.dev"
source: hosted
version: "2.1.2"
build_cli_annotations:
dependency: transitive
description:
name: build_cli_annotations
sha256: b59d2769769efd6c9ff6d4c4cede0be115a566afc591705c2040b707534b1172
url: "https://pub.dev"
source: hosted
version: "2.1.0"
characters:
dependency: transitive
description:
name: characters
sha256: f71061c654a3380576a52b451dd5532377954cf9dbd272a78fc8479606670803
url: "https://pub.dev"
source: hosted
version: "1.4.0"
clock:
dependency: transitive
description:
name: clock
sha256: fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b
url: "https://pub.dev"
source: hosted
version: "1.1.2"
collection:
dependency: transitive
description:
name: collection
sha256: "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76"
url: "https://pub.dev"
source: hosted
version: "1.19.1"
convert:
dependency: transitive
description:
name: convert
sha256: b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68
url: "https://pub.dev"
source: hosted
version: "3.1.2"
csslib:
dependency: transitive
description:
name: csslib
sha256: "09bad715f418841f976c77db72d5398dc1253c21fb9c0c7f0b0b985860b2d58e"
url: "https://pub.dev"
source: hosted
version: "1.0.2"
csv:
dependency: "direct main"
description:
name: csv
sha256: c6aa2679b2a18cb57652920f674488d89712efaf4d3fdf2e537215b35fc19d6c
url: "https://pub.dev"
source: hosted
version: "6.0.0"
dhttpd:
dependency: "direct dev"
description:
name: dhttpd
sha256: "2e24765d7569b8e0a02a441e3cf96f09cca69dfecba646e7e9f6b3ab45a2f3fe"
url: "https://pub.dev"
source: hosted
version: "4.1.0"
fake_async:
dependency: transitive
description:
name: fake_async
sha256: "5368f224a74523e8d2e7399ea1638b37aecfca824a3cc4dfdf77bf1fa905ac44"
url: "https://pub.dev"
source: hosted
version: "1.3.3"
fixnum:
dependency: "direct main"
description:
name: fixnum
sha256: b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be
url: "https://pub.dev"
source: hosted
version: "1.1.1"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
flutter_plugin_android_lifecycle:
dependency: transitive
description:
name: flutter_plugin_android_lifecycle
sha256: "5a1e6fb2c0561958d7e4c33574674bda7b77caaca7a33b758876956f2902eea3"
url: "https://pub.dev"
source: hosted
version: "2.0.27"
flutter_test:
dependency: "direct dev"
description: flutter
source: sdk
version: "0.0.0"
flutter_web_plugins:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
go_router:
dependency: "direct main"
description:
name: go_router
sha256: f02fd7d2a4dc512fec615529824fdd217fecb3a3d3de68360293a551f21634b3
url: "https://pub.dev"
source: hosted
version: "14.8.1"
google_maps:
dependency: transitive
description:
name: google_maps
sha256: "4d6e199c561ca06792c964fa24b2bac7197bf4b401c2e1d23e345e5f9939f531"
url: "https://pub.dev"
source: hosted
version: "8.1.1"
google_maps_flutter:
dependency: "direct main"
description:
name: google_maps_flutter
sha256: b42ff7f3875a5eedbe388d883100561b85c62beed1c39ad66dd60537c75bb424
url: "https://pub.dev"
source: hosted
version: "2.12.0"
google_maps_flutter_android:
dependency: transitive
description:
name: google_maps_flutter_android
sha256: "0ede4ae8326335c0c007c8c7a8c9737449263123385e2bdf49f3e71103b2dc2e"
url: "https://pub.dev"
source: hosted
version: "2.16.0"
google_maps_flutter_ios:
dependency: transitive
description:
name: google_maps_flutter_ios
sha256: ef72c822930ce69515cb91c10cd88cfb8b26296f765808a43cbc9a10eaffacfe
url: "https://pub.dev"
source: hosted
version: "2.15.0"
google_maps_flutter_platform_interface:
dependency: transitive
description:
name: google_maps_flutter_platform_interface
sha256: "970c8f766c02909c7be282dea923c971f83a88adaf07f8871d0aacebc3b07bb2"
url: "https://pub.dev"
source: hosted
version: "2.11.1"
google_maps_flutter_web:
dependency: transitive
description:
name: google_maps_flutter_web
sha256: a45786ea6691cc7cdbe2cf3ce2c2daf4f82a885745666b4a36baada3a4e12897
url: "https://pub.dev"
source: hosted
version: "0.5.12"
html:
dependency: "direct main"
description:
name: html
sha256: "1fc58edeaec4307368c60d59b7e15b9d658b57d7f3125098b6294153c75337ec"
url: "https://pub.dev"
source: hosted
version: "0.15.5"
http:
dependency: "direct main"
description:
name: http
sha256: fe7ab022b76f3034adc518fb6ea04a82387620e19977665ea18d30a1cf43442f
url: "https://pub.dev"
source: hosted
version: "1.3.0"
http_parser:
dependency: transitive
description:
name: http_parser
sha256: "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571"
url: "https://pub.dev"
source: hosted
version: "4.1.2"
leak_tracker:
dependency: transitive
description:
name: leak_tracker
sha256: "6bb818ecbdffe216e81182c2f0714a2e62b593f4a4f13098713ff1685dfb6ab0"
url: "https://pub.dev"
source: hosted
version: "10.0.9"
leak_tracker_flutter_testing:
dependency: transitive
description:
name: leak_tracker_flutter_testing
sha256: f8b613e7e6a13ec79cfdc0e97638fddb3ab848452eff057653abd3edba760573
url: "https://pub.dev"
source: hosted
version: "3.0.9"
leak_tracker_testing:
dependency: transitive
description:
name: leak_tracker_testing
sha256: "6ba465d5d76e67ddf503e1161d1f4a6bc42306f9d66ca1e8f079a47290fb06d3"
url: "https://pub.dev"
source: hosted
version: "3.0.1"
logging:
dependency: transitive
description:
name: logging
sha256: c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61
url: "https://pub.dev"
source: hosted
version: "1.3.0"
matcher:
dependency: transitive
description:
name: matcher
sha256: dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2
url: "https://pub.dev"
source: hosted
version: "0.12.17"
material_color_utilities:
dependency: transitive
description:
name: material_color_utilities
sha256: f7142bb1154231d7ea5f96bc7bde4bda2a0945d2806bb11670e30b850d56bdec
url: "https://pub.dev"
source: hosted
version: "0.11.1"
meta:
dependency: transitive
description:
name: meta
sha256: e3641ec5d63ebf0d9b41bd43201a66e3fc79a65db5f61fc181f04cd27aab950c
url: "https://pub.dev"
source: hosted
version: "1.16.0"
mime:
dependency: transitive
description:
name: mime
sha256: "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6"
url: "https://pub.dev"
source: hosted
version: "2.0.0"
path:
dependency: transitive
description:
name: path
sha256: "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5"
url: "https://pub.dev"
source: hosted
version: "1.9.1"
plugin_platform_interface:
dependency: transitive
description:
name: plugin_platform_interface
sha256: "4820fbfdb9478b1ebae27888254d445073732dae3d6ea81f0b7e06d5dedc3f02"
url: "https://pub.dev"
source: hosted
version: "2.1.8"
polyline_tools:
dependency: "direct main"
description:
name: polyline_tools
sha256: "8c523335bb8d16fb0c7835916ed94d97d9a063a4386e9193bd6e8fe233591df9"
url: "https://pub.dev"
source: hosted
version: "0.0.2"
sanitize_html:
dependency: transitive
description:
name: sanitize_html
sha256: "12669c4a913688a26555323fb9cec373d8f9fbe091f2d01c40c723b33caa8989"
url: "https://pub.dev"
source: hosted
version: "2.1.0"
shelf:
dependency: transitive
description:
name: shelf
sha256: e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12
url: "https://pub.dev"
source: hosted
version: "1.4.2"
shelf_static:
dependency: transitive
description:
name: shelf_static
sha256: c87c3875f91262785dade62d135760c2c69cb217ac759485334c5857ad89f6e3
url: "https://pub.dev"
source: hosted
version: "1.1.3"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.0"
source_span:
dependency: transitive
description:
name: source_span
sha256: "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c"
url: "https://pub.dev"
source: hosted
version: "1.10.1"
stack_trace:
dependency: transitive
description:
name: stack_trace
sha256: "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1"
url: "https://pub.dev"
source: hosted
version: "1.12.1"
stream_channel:
dependency: transitive
description:
name: stream_channel
sha256: "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
stream_transform:
dependency: transitive
description:
name: stream_transform
sha256: ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871
url: "https://pub.dev"
source: hosted
version: "2.1.1"
string_scanner:
dependency: transitive
description:
name: string_scanner
sha256: "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43"
url: "https://pub.dev"
source: hosted
version: "1.4.1"
term_glyph:
dependency: transitive
description:
name: term_glyph
sha256: "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e"
url: "https://pub.dev"
source: hosted
version: "1.2.2"
test_api:
dependency: transitive
description:
name: test_api
sha256: fb31f383e2ee25fbbfe06b40fe21e1e458d14080e3c67e7ba0acfde4df4e0bbd
url: "https://pub.dev"
source: hosted
version: "0.7.4"
typed_data:
dependency: transitive
description:
name: typed_data
sha256: f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006
url: "https://pub.dev"
source: hosted
version: "1.4.0"
vector_math:
dependency: transitive
description:
name: vector_math
sha256: "80b3257d1492ce4d091729e3a67a60407d227c27241d6927be0130c98e741803"
url: "https://pub.dev"
source: hosted
version: "2.1.4"
very_good_analysis:
dependency: "direct dev"
description:
name: very_good_analysis
sha256: "1fb637c0022034b1f19ea2acb42a3603cbd8314a470646a59a2fb01f5f3a8629"
url: "https://pub.dev"
source: hosted
version: "6.0.0"
vm_service:
dependency: transitive
description:
name: vm_service
sha256: ddfa8d30d89985b96407efce8acbdd124701f96741f2d981ca860662f1c0dc02
url: "https://pub.dev"
source: hosted
version: "15.0.0"
web:
dependency: "direct main"
description:
name: web
sha256: "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a"
url: "https://pub.dev"
source: hosted
version: "1.1.1"
sdks:
dart: ">=3.7.0-0 <4.0.0"
flutter: ">=3.27.0"

View file

@ -8,6 +8,7 @@ environment:
dependencies: dependencies:
fixnum: ^1.1.1 fixnum: ^1.1.1
csv: ^6.0.0
flutter: flutter:
sdk: flutter sdk: flutter
go_router: ^14.2.7 go_router: ^14.2.7

9427
src/server/bct_stops.json Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,7 @@
import { Router } from "@oak/acorn"; import { Router } from "@oak/acorn";
import { db_setup, select_closest } from "./db.ts"; import { db_setup, select_closest } from "./db.ts";
import { DatabaseSync } from "node:sqlite"; import { DatabaseSync } from "node:sqlite";
import { json_mime_add, substitute_base_name_, cors_add } from "./utils.ts"; import { cors_add, json_mime_add, substitute_base_name_ } from "./utils.ts";
import { assert } from "@std/assert"; import { assert } from "@std/assert";
import neo4j from "https://deno.land/x/neo4j_driver_lite@5.28.1/mod.ts"; import neo4j from "https://deno.land/x/neo4j_driver_lite@5.28.1/mod.ts";
@ -9,7 +9,8 @@ import { graph_setup } from "./graph.ts";
const usingDocker = true; const usingDocker = true;
const root_url: string = usingDocker const root_url: string = usingDocker
? Deno.env.get("ROOT_URL") as string : "http://localhost:8080/api"; ? Deno.env.get("ROOT_URL") as string
: "http://localhost:8080/api";
assert(root_url, "ROOT_URL env var not defined"); assert(root_url, "ROOT_URL env var not defined");
// bind values we're actually using // bind values we're actually using
@ -21,7 +22,7 @@ const substitute_base_name = substitute_base_name_.bind(
const { hostname, port } = { hostname: "0.0.0.0", port: 80 }; const { hostname, port } = { hostname: "0.0.0.0", port: 80 };
const neo4jHost = usingDocker ? "neo4j" : "127.0.0.1"; // localhost does NOT work const neo4jHost = usingDocker ? "neo4j" : "127.0.0.1"; // localhost does NOT work
const graph_driver = neo4j.driver( const graph_driver = neo4j.driver(
`neo4j://${neo4jHost}:7687`, `neo4j://${neo4jHost}:7687`,
neo4j.auth.basic("neo4j", "your_password"), neo4j.auth.basic("neo4j", "your_password"),
@ -71,6 +72,21 @@ router.get(
} }
}, },
); );
router.get(
"/stops",
async (_ctx) => {
try {
const bytes = await Deno.readFile(`bct_stops.json`);
const headers = new Headers();
json_mime_add(headers);
cors_add(headers);
return new Response(bytes, { headers });
} catch (_) {
return new Response("", { status: 404 });
}
},
);
router.get( router.get(
"/stops/:id", "/stops/:id",
async (ctx) => { async (ctx) => {
@ -133,15 +149,16 @@ router.get(
{ {
trip: { trip: {
href: `${root_url}/trips/BCT_R51_inb_T08`, href: `${root_url}/trips/BCT_R51_inb_T08`,
polyline: "ivz_GtswmMEQo@P]Ko@_Dg@gByBfCcBjBWX]^Ua@[u@uFdGqErFoDxDiIrIaG|FwGlFyCvCo@r@{@tAq@vAu@vBy@~C_CbJaBhFgF`SY~@YNi@?cDuA_@u@NqAf@{@lAw@vAArBl@jGxB`DlARt@iAnF_BrCi@tBl@Vl@}BEw@p@iAPw@zAaHLYNG|BbArAp@XBNGPOb@{AtAiF@o@s@c@}E}Bg@QS~AzCnALe@X[t@\\r@\\RR?XKr@g@fB_AfDOR[B{@_@aAg@_Bs@_@PWV]FsLeEiCs@eAHaAd@w@xA]jAk@h@uAYKYDs@q@MMCGQ@O?c@_B_@Uj@]P[g@[q@YiAg@sHMmAy@_C}@wCuD{Ja@wA@mAbBkElAyDZuD\\iD^mAh@s@`DcCfBoDzA_DXeBr@iNZoHKkA}@kB{@i@}@QmERmBBw@Om@_@g@c@m@m@Y_AScAImABmAHs@RMFWIc@YIS^H`AGtBVhC^jA|@fAfAj@x@T`JSb@Pn@Zf@bA^tAQjFm@vLQhD]nAoAnCiBhDiDdCk@`ASv@y@fIUzAqBlFmA|BxF`QjHyFo@eAeAqBM{@Hu@Pe@|CaGhCwD\\_@bA}Ah@qAdAiDjAqDtAqDd@q@jAo@~Ce@`DE~CCjAl@hAzBl@pBd@xC@hCY~Co@fBeCrGgB~BcAjA}A|BoErIuBnEm@`Au@b@yANaASuAcA_DbEi@bASzACdBEbDo@pBLT|@b@rKrBbAf@\\^Jp@]~AsFdVqBfI_Kx_@sAlH}@xIk@dHOpCEjCAd@P|IXdLZlDf@tD`DnR\\vCLjDEpFa@~Fs@rI}CrVSdDKhG@pVR|Td@|k@BbQTj@|C~Cl@|DlD|TPjAfBpIp@~EvBhL|BpLxAnIaC|@gE`BL`A`@tB]t@SCaBu@iB{@iDqALhDFzC~Bb@nAg@hCh@p@J", polyline:
"ivz_GtswmMEQo@P]Ko@_Dg@gByBfCcBjBWX]^Ua@[u@uFdGqErFoDxDiIrIaG|FwGlFyCvCo@r@{@tAq@vAu@vBy@~C_CbJaBhFgF`SY~@YNi@?cDuA_@u@NqAf@{@lAw@vAArBl@jGxB`DlARt@iAnF_BrCi@tBl@Vl@}BEw@p@iAPw@zAaHLYNG|BbArAp@XBNGPOb@{AtAiF@o@s@c@}E}Bg@QS~AzCnALe@X[t@\\r@\\RR?XKr@g@fB_AfDOR[B{@_@aAg@_Bs@_@PWV]FsLeEiCs@eAHaAd@w@xA]jAk@h@uAYKYDs@q@MMCGQ@O?c@_B_@Uj@]P[g@[q@YiAg@sHMmAy@_C}@wCuD{Ja@wA@mAbBkElAyDZuD\\iD^mAh@s@`DcCfBoDzA_DXeBr@iNZoHKkA}@kB{@i@}@QmERmBBw@Om@_@g@c@m@m@Y_AScAImABmAHs@RMFWIc@YIS^H`AGtBVhC^jA|@fAfAj@x@T`JSb@Pn@Zf@bA^tAQjFm@vLQhD]nAoAnCiBhDiDdCk@`ASv@y@fIUzAqBlFmA|BxF`QjHyFo@eAeAqBM{@Hu@Pe@|CaGhCwD\\_@bA}Ah@qAdAiDjAqDtAqDd@q@jAo@~Ce@`DE~CCjAl@hAzBl@pBd@xC@hCY~Co@fBeCrGgB~BcAjA}A|BoErIuBnEm@`Au@b@yANaASuAcA_DbEi@bASzACdBEbDo@pBLT|@b@rKrBbAf@\\^Jp@]~AsFdVqBfI_Kx_@sAlH}@xIk@dHOpCEjCAd@P|IXdLZlDf@tD`DnR\\vCLjDEpFa@~Fs@rI}CrVSdDKhG@pVR|Td@|k@BbQTj@|C~Cl@|DlD|TPjAfBpIp@~EvBhL|BpLxAnIaC|@gE`BL`A`@tB]t@SCaBu@iB{@iDqALhDFzC~Bb@nAg@hCh@p@J",
}, },
enter_bus: { enter_bus: {
href: `${root_url}/stops/BCT_95103`, href: `${root_url}/stops/BCT_95103`,
latitude: 42.101991, latitude: 42.101991,
longitude: -75.83611, longitude: -75.83611,
time: "00:00" time: "00:00",
}, },
exit_bus:{ exit_bus: {
href: `${root_url}/stops/BCT_1`, href: `${root_url}/stops/BCT_1`,
latitude: 42.101354, latitude: 42.101354,
longitude: -75.910801, longitude: -75.910801,
@ -151,15 +168,16 @@ router.get(
{ {
trip: { trip: {
href: `${root_url}/trips/BCT_R28otb_T11`, href: `${root_url}/trips/BCT_R28otb_T11`,
polyline: "az}_GvjinM}KiBQsHw@y@oDiEmFeGgFcGyAcB_@c@HcA^qL^gL@w@UyFMcIEkBi@aTi@aREmBCeAi@D_Id@sJl@{GZsRnAw@DASUsLGgBI]MUc@a@UEWBw@Vw@j@y@Nc@FYBj@jFJfAkDx@qAVcA^UFFfCD`AnIc@jH]pIi@rDSzJk@vKo@fDQbF[Di@a@oN_@mNe@eMs@qSW_Ha@{L[}Ie@mL_@mJBoAPyA^iATm@T_@R]l@_@zCgA`@QrBfEVLlATN^D^HPL?XGLQN[CYQQUBS@W@SCoAUSSUc@wAaDkA`@{@^gA`@m@^g@hAa@z@Wv@MrABp@L~FPjDXbI^fLPbEHhDd@tMd@pMj@jNP~GLbFVnK\\pJVfJHpDJrERzGH`FJdENlHN`DCbCUbHEbBQ`GObDGr@|@hA|DlE`F`GvDhE`DnDRrHrDf@Xo@nCl@", polyline:
"az}_GvjinM}KiBQsHw@y@oDiEmFeGgFcGyAcB_@c@HcA^qL^gL@w@UyFMcIEkBi@aTi@aREmBCeAi@D_Id@sJl@{GZsRnAw@DASUsLGgBI]MUc@a@UEWBw@Vw@j@y@Nc@FYBj@jFJfAkDx@qAVcA^UFFfCD`AnIc@jH]pIi@rDSzJk@vKo@fDQbF[Di@a@oN_@mNe@eMs@qSW_Ha@{L[}Ie@mL_@mJBoAPyA^iATm@T_@R]l@_@zCgA`@QrBfEVLlATN^D^HPL?XGLQN[CYQQUBS@W@SCoAUSSUc@wAaDkA`@{@^gA`@m@^g@hAa@z@Wv@MrABp@L~FPjDXbI^fLPbEHhDd@tMd@pMj@jNP~GLbFVnK\\pJVfJHpDJrERzGH`FJdENlHN`DCbCUbHEbBQ`GObDGr@|@hA|DlE`F`GvDhE`DnDRrHrDf@Xo@nCl@",
}, },
enter_bus:{ enter_bus: {
href: `${root_url}/stops/BCT_2802`, href: `${root_url}/stops/BCT_2802`,
latitude: 42.100982, latitude: 42.100982,
longitude: -75.91097, longitude: -75.91097,
time: "00:00", time: "00:00",
}, },
exit_bus:{ exit_bus: {
href: `${root_url}/stops/BCT_2804`, href: `${root_url}/stops/BCT_2804`,
latitude: 42.105488, latitude: 42.105488,
longitude: -75.906281, longitude: -75.906281,
@ -181,4 +199,4 @@ router.get(
); );
console.log(`Ready! Listening on ${hostname}:${port}`); console.log(`Ready! Listening on ${hostname}:${port}`);
router.listen({ hostname, port}); router.listen({ hostname, port });