minotor 1.0.7 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -3
- package/README.md +3 -2
- package/dist/cli.mjs +604 -531
- package/dist/cli.mjs.map +1 -1
- package/dist/gtfs/stops.d.ts +19 -5
- package/dist/gtfs/transfers.d.ts +5 -4
- package/dist/gtfs/trips.d.ts +7 -5
- package/dist/gtfs/utils.d.ts +7 -8
- package/dist/parser.cjs.js +569 -501
- package/dist/parser.cjs.js.map +1 -1
- package/dist/parser.esm.js +569 -501
- package/dist/parser.esm.js.map +1 -1
- package/dist/router.cjs.js +1 -1
- package/dist/router.cjs.js.map +1 -1
- package/dist/router.d.ts +3 -3
- package/dist/router.esm.js +1 -1
- package/dist/router.esm.js.map +1 -1
- package/dist/router.umd.js +1 -1
- package/dist/router.umd.js.map +1 -1
- package/dist/routing/__tests__/route.test.d.ts +1 -0
- package/dist/routing/query.d.ts +7 -7
- package/dist/routing/result.d.ts +3 -3
- package/dist/routing/route.d.ts +1 -0
- package/dist/stops/proto/stops.d.ts +5 -4
- package/dist/stops/stops.d.ts +10 -1
- package/dist/stops/stopsIndex.d.ts +21 -4
- package/dist/timetable/proto/timetable.d.ts +21 -18
- package/dist/timetable/timetable.d.ts +38 -14
- package/package.json +4 -3
- package/src/cli/repl.ts +13 -10
- package/src/gtfs/__tests__/parser.test.ts +50 -579
- package/src/gtfs/__tests__/stops.test.ts +181 -112
- package/src/gtfs/__tests__/transfers.test.ts +170 -12
- package/src/gtfs/__tests__/trips.test.ts +212 -141
- package/src/gtfs/__tests__/utils.test.ts +4 -4
- package/src/gtfs/parser.ts +22 -13
- package/src/gtfs/stops.ts +63 -28
- package/src/gtfs/transfers.ts +14 -6
- package/src/gtfs/trips.ts +110 -47
- package/src/gtfs/utils.ts +11 -11
- package/src/router.ts +2 -4
- package/src/routing/__tests__/route.test.ts +112 -0
- package/src/routing/__tests__/router.test.ts +234 -244
- package/src/routing/query.ts +7 -7
- package/src/routing/result.ts +9 -6
- package/src/routing/route.ts +11 -0
- package/src/routing/router.ts +26 -24
- package/src/stops/__tests__/io.test.ts +9 -8
- package/src/stops/__tests__/stopFinder.test.ts +45 -36
- package/src/stops/io.ts +8 -5
- package/src/stops/proto/stops.proto +8 -7
- package/src/stops/proto/stops.ts +68 -38
- package/src/stops/stops.ts +13 -1
- package/src/stops/stopsIndex.ts +50 -7
- package/src/timetable/__tests__/io.test.ts +40 -49
- package/src/timetable/__tests__/timetable.test.ts +50 -58
- package/src/timetable/io.ts +69 -56
- package/src/timetable/proto/timetable.proto +22 -17
- package/src/timetable/proto/timetable.ts +94 -184
- package/src/timetable/timetable.ts +62 -29
|
@@ -13,18 +13,18 @@ import {
|
|
|
13
13
|
describe('timetable io', () => {
|
|
14
14
|
const stopsAdjacency: StopsAdjacency = new Map([
|
|
15
15
|
[
|
|
16
|
-
|
|
16
|
+
1,
|
|
17
17
|
{
|
|
18
|
-
transfers: [{ destination:
|
|
18
|
+
transfers: [{ destination: 2, type: 'RECOMMENDED' }],
|
|
19
19
|
routes: ['route1'],
|
|
20
20
|
},
|
|
21
21
|
],
|
|
22
22
|
[
|
|
23
|
-
|
|
23
|
+
2,
|
|
24
24
|
{
|
|
25
25
|
transfers: [
|
|
26
26
|
{
|
|
27
|
-
destination:
|
|
27
|
+
destination: 1,
|
|
28
28
|
type: 'GUARANTEED',
|
|
29
29
|
minTransferTime: Duration.fromMinutes(3),
|
|
30
30
|
},
|
|
@@ -37,36 +37,30 @@ describe('timetable io', () => {
|
|
|
37
37
|
[
|
|
38
38
|
'route1',
|
|
39
39
|
{
|
|
40
|
-
stopTimes: [
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
departure: Time.fromHMS(1, 10, 10),
|
|
62
|
-
pickUpType: 'REGULAR',
|
|
63
|
-
dropOffType: 'REGULAR',
|
|
64
|
-
},
|
|
65
|
-
],
|
|
66
|
-
stops: ['stop1', 'stop2'],
|
|
40
|
+
stopTimes: new Uint32Array([
|
|
41
|
+
Time.fromHMS(0, 16, 40).toSeconds(),
|
|
42
|
+
Time.fromHMS(0, 16, 50).toSeconds(),
|
|
43
|
+
Time.fromHMS(0, 33, 20).toSeconds(),
|
|
44
|
+
Time.fromHMS(0, 33, 30).toSeconds(),
|
|
45
|
+
Time.fromHMS(0, 50, 0).toSeconds(),
|
|
46
|
+
Time.fromHMS(0, 50, 10).toSeconds(),
|
|
47
|
+
Time.fromHMS(1, 10, 0).toSeconds(),
|
|
48
|
+
Time.fromHMS(1, 10, 10).toSeconds(),
|
|
49
|
+
]),
|
|
50
|
+
pickUpDropOffTypes: new Uint8Array([
|
|
51
|
+
0,
|
|
52
|
+
0, // REGULAR
|
|
53
|
+
1,
|
|
54
|
+
0, // NOT_AVAILABLE, REGULAR
|
|
55
|
+
0,
|
|
56
|
+
0, // REGULAR
|
|
57
|
+
0,
|
|
58
|
+
0, // REGULAR
|
|
59
|
+
]),
|
|
60
|
+
stops: new Uint32Array([1, 2]),
|
|
67
61
|
stopIndices: new Map([
|
|
68
|
-
[
|
|
69
|
-
[
|
|
62
|
+
[1, 0],
|
|
63
|
+
[2, 1],
|
|
70
64
|
]),
|
|
71
65
|
serviceRouteId: 'gtfs1',
|
|
72
66
|
},
|
|
@@ -74,24 +68,22 @@ describe('timetable io', () => {
|
|
|
74
68
|
[
|
|
75
69
|
'route2',
|
|
76
70
|
{
|
|
77
|
-
stopTimes: [
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
],
|
|
91
|
-
stops: ['stop2', 'stop1'],
|
|
71
|
+
stopTimes: new Uint32Array([
|
|
72
|
+
Time.fromHMS(1, 6, 40).toSeconds(),
|
|
73
|
+
Time.fromHMS(1, 6, 50).toSeconds(),
|
|
74
|
+
Time.fromHMS(1, 23, 20).toSeconds(),
|
|
75
|
+
Time.fromHMS(1, 23, 30).toSeconds(),
|
|
76
|
+
]),
|
|
77
|
+
pickUpDropOffTypes: new Uint8Array([
|
|
78
|
+
0,
|
|
79
|
+
0, // REGULAR
|
|
80
|
+
0,
|
|
81
|
+
0, // REGULAR
|
|
82
|
+
]),
|
|
83
|
+
stops: new Uint32Array([2, 1]),
|
|
92
84
|
stopIndices: new Map([
|
|
93
|
-
[
|
|
94
|
-
[
|
|
85
|
+
[2, 0],
|
|
86
|
+
[1, 1],
|
|
95
87
|
]),
|
|
96
88
|
serviceRouteId: 'gtfs2',
|
|
97
89
|
},
|
|
@@ -122,7 +114,7 @@ describe('timetable io', () => {
|
|
|
122
114
|
it('should find the earliest trip for stop1 on route1', () => {
|
|
123
115
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
124
116
|
const route = sampleTimetable.getRoute('route1')!;
|
|
125
|
-
const tripIndex = sampleTimetable.findEarliestTrip(route,
|
|
117
|
+
const tripIndex = sampleTimetable.findEarliestTrip(route, 1);
|
|
126
118
|
assert.strictEqual(tripIndex, 0);
|
|
127
119
|
});
|
|
128
120
|
|
|
@@ -132,7 +124,7 @@ describe('timetable io', () => {
|
|
|
132
124
|
const afterTime = Time.fromHMS(0, 25, 0);
|
|
133
125
|
const tripIndex = sampleTimetable.findEarliestTrip(
|
|
134
126
|
route,
|
|
135
|
-
|
|
127
|
+
1,
|
|
136
128
|
undefined,
|
|
137
129
|
afterTime,
|
|
138
130
|
);
|
|
@@ -145,7 +137,7 @@ describe('timetable io', () => {
|
|
|
145
137
|
const afterTime = Time.fromHMS(0, 58, 20);
|
|
146
138
|
const tripIndex = sampleTimetable.findEarliestTrip(
|
|
147
139
|
route,
|
|
148
|
-
|
|
140
|
+
1,
|
|
149
141
|
undefined,
|
|
150
142
|
afterTime,
|
|
151
143
|
);
|
|
@@ -154,24 +146,24 @@ describe('timetable io', () => {
|
|
|
154
146
|
it('should return undefined if the stop on a trip has pick up not available', () => {
|
|
155
147
|
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
156
148
|
const route = sampleTimetable.getRoute('route1')!;
|
|
157
|
-
const tripIndex = sampleTimetable.findEarliestTrip(route,
|
|
149
|
+
const tripIndex = sampleTimetable.findEarliestTrip(route, 2);
|
|
158
150
|
assert.strictEqual(tripIndex, 1);
|
|
159
151
|
});
|
|
160
152
|
it('should find reachable routes from a set of stop IDs', () => {
|
|
161
|
-
const fromStops = new Set([
|
|
153
|
+
const fromStops = new Set([1]);
|
|
162
154
|
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
163
155
|
assert.strictEqual(reachableRoutes.size, 1);
|
|
164
|
-
assert.strictEqual(reachableRoutes.get('route1'),
|
|
156
|
+
assert.strictEqual(reachableRoutes.get('route1'), 1);
|
|
165
157
|
});
|
|
166
158
|
|
|
167
159
|
it('should find no reachable routes if starting from a non-existent stop', () => {
|
|
168
|
-
const fromStops = new Set([
|
|
160
|
+
const fromStops = new Set([5]);
|
|
169
161
|
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops);
|
|
170
162
|
assert.strictEqual(reachableRoutes.size, 0);
|
|
171
163
|
});
|
|
172
164
|
|
|
173
165
|
it('should find reachable routes filtered by transport modes', () => {
|
|
174
|
-
const fromStops = new Set([
|
|
166
|
+
const fromStops = new Set([1]);
|
|
175
167
|
const reachableRoutes = sampleTimetable.findReachableRoutes(fromStops, [
|
|
176
168
|
'BUS',
|
|
177
169
|
]);
|
package/src/timetable/io.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { Duration } from './duration.js';
|
|
2
2
|
import {
|
|
3
|
-
PickUpDropOffType as ProtoPickUpDropOffType,
|
|
4
3
|
RoutesAdjacency as ProtoRoutesAdjacency,
|
|
5
4
|
RouteType as ProtoRouteType,
|
|
6
5
|
ServiceRoutesMap as ProtoServiceRoutesMap,
|
|
@@ -8,9 +7,7 @@ import {
|
|
|
8
7
|
Transfer as ProtoTransfer,
|
|
9
8
|
TransferType as ProtoTransferType,
|
|
10
9
|
} from './proto/timetable.js';
|
|
11
|
-
import { Time } from './time.js';
|
|
12
10
|
import {
|
|
13
|
-
PickUpDropOffType,
|
|
14
11
|
Route,
|
|
15
12
|
RoutesAdjacency,
|
|
16
13
|
RouteType,
|
|
@@ -20,6 +17,59 @@ import {
|
|
|
20
17
|
TransferType,
|
|
21
18
|
} from './timetable.js';
|
|
22
19
|
|
|
20
|
+
const isLittleEndian = (() => {
|
|
21
|
+
const buffer = new ArrayBuffer(4);
|
|
22
|
+
const view = new DataView(buffer);
|
|
23
|
+
view.setUint32(0, 0x12345678);
|
|
24
|
+
return new Uint8Array(buffer)[0] === 0x78;
|
|
25
|
+
})();
|
|
26
|
+
|
|
27
|
+
const STANDARD_ENDIANNESS = true; // true = little-endian
|
|
28
|
+
|
|
29
|
+
function uint32ArrayToBytes(array: Uint32Array): Uint8Array {
|
|
30
|
+
if (isLittleEndian === STANDARD_ENDIANNESS) {
|
|
31
|
+
return new Uint8Array(array.buffer, array.byteOffset, array.byteLength);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// If endianness doesn't match, we need to swap byte order
|
|
35
|
+
const result = new Uint8Array(array.length * 4);
|
|
36
|
+
const view = new DataView(result.buffer);
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < array.length; i++) {
|
|
39
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
40
|
+
view.setUint32(i * 4, array[i]!, STANDARD_ENDIANNESS);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function bytesToUint32Array(bytes: Uint8Array): Uint32Array {
|
|
47
|
+
if (bytes.byteLength % 4 !== 0) {
|
|
48
|
+
throw new Error(
|
|
49
|
+
'Byte array length must be a multiple of 4 to convert to Uint32Array',
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// If system endianness matches our standard, we can create a view directly
|
|
54
|
+
if (isLittleEndian === STANDARD_ENDIANNESS) {
|
|
55
|
+
return new Uint32Array(
|
|
56
|
+
bytes.buffer,
|
|
57
|
+
bytes.byteOffset,
|
|
58
|
+
bytes.byteLength / 4,
|
|
59
|
+
);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// If endianness doesn't match, we need to swap byte order
|
|
63
|
+
const result = new Uint32Array(bytes.byteLength / 4);
|
|
64
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
65
|
+
|
|
66
|
+
for (let i = 0; i < result.length; i++) {
|
|
67
|
+
result[i] = view.getUint32(i * 4, STANDARD_ENDIANNESS);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return result;
|
|
71
|
+
}
|
|
72
|
+
|
|
23
73
|
export const serializeStopsAdjacency = (
|
|
24
74
|
stopsAdjacency: StopsAdjacency,
|
|
25
75
|
): ProtoStopsAdjacency => {
|
|
@@ -28,7 +78,7 @@ export const serializeStopsAdjacency = (
|
|
|
28
78
|
};
|
|
29
79
|
|
|
30
80
|
stopsAdjacency.forEach(
|
|
31
|
-
(value: { transfers: Transfer[]; routes: string[] }, key:
|
|
81
|
+
(value: { transfers: Transfer[]; routes: string[] }, key: number) => {
|
|
32
82
|
protoStopsAdjacency.stops[key] = {
|
|
33
83
|
transfers: value.transfers.map((transfer) => ({
|
|
34
84
|
destination: transfer.destination,
|
|
@@ -54,13 +104,9 @@ export const serializeRoutesAdjacency = (
|
|
|
54
104
|
|
|
55
105
|
routesAdjacency.forEach((value: Route, key: string) => {
|
|
56
106
|
protoRoutesAdjacency.routes[key] = {
|
|
57
|
-
stopTimes: value.stopTimes
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
pickUpType: serializePickUpDropOffType(stopTimes.pickUpType),
|
|
61
|
-
dropOffType: serializePickUpDropOffType(stopTimes.dropOffType),
|
|
62
|
-
})),
|
|
63
|
-
stops: value.stops,
|
|
107
|
+
stopTimes: uint32ArrayToBytes(value.stopTimes),
|
|
108
|
+
pickUpDropOffTypes: value.pickUpDropOffTypes,
|
|
109
|
+
stops: uint32ArrayToBytes(value.stops),
|
|
64
110
|
serviceRouteId: value.serviceRouteId,
|
|
65
111
|
};
|
|
66
112
|
});
|
|
@@ -92,7 +138,8 @@ export const deserializeStopsAdjacency = (
|
|
|
92
138
|
): StopsAdjacency => {
|
|
93
139
|
const stopsAdjacency: StopsAdjacency = new Map();
|
|
94
140
|
|
|
95
|
-
Object.entries(protoStopsAdjacency.stops).forEach(([
|
|
141
|
+
Object.entries(protoStopsAdjacency.stops).forEach(([keyStr, value]) => {
|
|
142
|
+
const key = parseInt(keyStr, 10);
|
|
96
143
|
stopsAdjacency.set(key, {
|
|
97
144
|
transfers: value.transfers.map(
|
|
98
145
|
(transfer: ProtoTransfer): Transfer => ({
|
|
@@ -116,21 +163,17 @@ export const deserializeRoutesAdjacency = (
|
|
|
116
163
|
const routesAdjacency: RoutesAdjacency = new Map();
|
|
117
164
|
|
|
118
165
|
Object.entries(protoRoutesAdjacency.routes).forEach(([key, value]) => {
|
|
166
|
+
const stops = bytesToUint32Array(value.stops);
|
|
167
|
+
const indices = new Map<number, number>();
|
|
168
|
+
for (let i = 0; i < stops.length; i++) {
|
|
169
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
170
|
+
indices.set(stops[i]!, i);
|
|
171
|
+
}
|
|
119
172
|
routesAdjacency.set(key, {
|
|
120
|
-
stopTimes: value.stopTimes
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
stopTimes.pickUpType !== undefined
|
|
125
|
-
? parsePickUpDropOffType(stopTimes.pickUpType)
|
|
126
|
-
: 'REGULAR',
|
|
127
|
-
dropOffType:
|
|
128
|
-
stopTimes.dropOffType !== undefined
|
|
129
|
-
? parsePickUpDropOffType(stopTimes.dropOffType)
|
|
130
|
-
: 'REGULAR',
|
|
131
|
-
})),
|
|
132
|
-
stops: value.stops,
|
|
133
|
-
stopIndices: new Map(value.stops.map((stop, index) => [stop, index])),
|
|
173
|
+
stopTimes: bytesToUint32Array(value.stopTimes),
|
|
174
|
+
pickUpDropOffTypes: value.pickUpDropOffTypes,
|
|
175
|
+
stops: stops,
|
|
176
|
+
stopIndices: indices,
|
|
134
177
|
serviceRouteId: value.serviceRouteId,
|
|
135
178
|
});
|
|
136
179
|
});
|
|
@@ -233,33 +276,3 @@ const serializeRouteType = (type: RouteType): ProtoRouteType => {
|
|
|
233
276
|
return ProtoRouteType.MONORAIL;
|
|
234
277
|
}
|
|
235
278
|
};
|
|
236
|
-
|
|
237
|
-
const parsePickUpDropOffType = (
|
|
238
|
-
type: ProtoPickUpDropOffType,
|
|
239
|
-
): PickUpDropOffType => {
|
|
240
|
-
switch (type) {
|
|
241
|
-
case ProtoPickUpDropOffType.MUST_PHONE_AGENCY:
|
|
242
|
-
return 'MUST_PHONE_AGENCY';
|
|
243
|
-
case ProtoPickUpDropOffType.MUST_COORDINATE_WITH_DRIVER:
|
|
244
|
-
return 'MUST_COORDINATE_WITH_DRIVER';
|
|
245
|
-
case ProtoPickUpDropOffType.NOT_AVAILABLE:
|
|
246
|
-
return 'NOT_AVAILABLE';
|
|
247
|
-
default:
|
|
248
|
-
return 'REGULAR';
|
|
249
|
-
}
|
|
250
|
-
};
|
|
251
|
-
|
|
252
|
-
const serializePickUpDropOffType = (
|
|
253
|
-
type: PickUpDropOffType,
|
|
254
|
-
): ProtoPickUpDropOffType | undefined => {
|
|
255
|
-
switch (type) {
|
|
256
|
-
case 'REGULAR':
|
|
257
|
-
return undefined;
|
|
258
|
-
case 'NOT_AVAILABLE':
|
|
259
|
-
return ProtoPickUpDropOffType.NOT_AVAILABLE;
|
|
260
|
-
case 'MUST_COORDINATE_WITH_DRIVER':
|
|
261
|
-
return ProtoPickUpDropOffType.MUST_COORDINATE_WITH_DRIVER;
|
|
262
|
-
case 'MUST_PHONE_AGENCY':
|
|
263
|
-
return ProtoPickUpDropOffType.MUST_PHONE_AGENCY;
|
|
264
|
-
}
|
|
265
|
-
};
|
|
@@ -2,23 +2,28 @@ syntax = "proto3";
|
|
|
2
2
|
|
|
3
3
|
package minotor.timetable;
|
|
4
4
|
|
|
5
|
-
enum PickUpDropOffType {
|
|
6
|
-
NOT_AVAILABLE = 0;
|
|
7
|
-
MUST_PHONE_AGENCY = 1;
|
|
8
|
-
MUST_COORDINATE_WITH_DRIVER = 2;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
message StopTimes {
|
|
12
|
-
int32 arrival = 1;
|
|
13
|
-
int32 departure = 2;
|
|
14
|
-
optional PickUpDropOffType pickUpType = 3;
|
|
15
|
-
optional PickUpDropOffType dropOffType = 4;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
5
|
message Route {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Arrivals and departures encoded as a 32 bit uint array.
|
|
8
|
+
* Format: [arrival1, departure1, arrival2, departure2, etc.]
|
|
9
|
+
*/
|
|
10
|
+
bytes stopTimes = 1;
|
|
11
|
+
/**
|
|
12
|
+
* PickUp and DropOff types represented as an 8 bit uint array.
|
|
13
|
+
* Values:
|
|
14
|
+
* 0: REGULAR
|
|
15
|
+
* 1: NOT_AVAILABLE
|
|
16
|
+
* 2: MUST_PHONE_AGENCY
|
|
17
|
+
* 3: MUST_COORDINATE_WITH_DRIVER
|
|
18
|
+
* Format: [pickupTypeStop1, dropOffTypeStop1, pickupTypeStop2, dropOffTypeStop2, etc.]
|
|
19
|
+
*/
|
|
20
|
+
bytes pickUpDropOffTypes = 2;
|
|
21
|
+
/**
|
|
22
|
+
* Stops encoded as a 32 bit uint array.
|
|
23
|
+
* Format: [stop1, stop2, stop3, etc.]
|
|
24
|
+
*/
|
|
25
|
+
bytes stops = 3;
|
|
26
|
+
string serviceRouteId = 4;
|
|
22
27
|
}
|
|
23
28
|
|
|
24
29
|
message RoutesAdjacency {
|
|
@@ -33,7 +38,7 @@ enum TransferType {
|
|
|
33
38
|
}
|
|
34
39
|
|
|
35
40
|
message Transfer {
|
|
36
|
-
|
|
41
|
+
uint32 destination = 1;
|
|
37
42
|
TransferType type = 2;
|
|
38
43
|
optional int32 minTransferTime = 3;
|
|
39
44
|
}
|