timetable
Version:
Using GTFS and other sources to produce beautiful and usable timetables for public transport.
344 lines (302 loc) • 10.9 kB
JavaScript
// Generated by CoffeeScript 1.7.1
(function() {
var $, ASYNC, COURSES, DEV, P, REGISTRY, TRM, alert, badge, debug, echo, help, info, log, options, rainbow, rpr, urge, warn, whisper,
__slice = [].slice;
TRM = require('coffeenode-trm');
rpr = TRM.rpr.bind(TRM);
badge = 'TIMETABLE/READER';
log = TRM.get_logger('plain', badge);
info = TRM.get_logger('info', badge);
whisper = TRM.get_logger('whisper', badge);
alert = TRM.get_logger('alert', badge);
debug = TRM.get_logger('debug', badge);
warn = TRM.get_logger('warn', badge);
help = TRM.get_logger('help', badge);
urge = TRM.get_logger('urge', badge);
echo = TRM.echo.bind(TRM);
rainbow = TRM.rainbow.bind(TRM);
ASYNC = require('async');
REGISTRY = require('./REGISTRY');
COURSES = require('./COURSES');
P = require('pipedreams');
$ = P.$.bind(P);
options = require('../options');
DEV = options['mode'] === 'dev';
/* TAINT very Berlin-specific method, shouldnt appear here */
this.normalize_berlin_station_name = function(name) {
name = name.replace(/\s+\(Berlin\)(\s+Bus)?$/, '');
if (!/^(U|S) Olympiastadion/.test(name)) {
name = name.replace(/^(U|S\+U|S)\s+/, '');
}
name = name.replace(/^(Alexanderplatz) Bhf\/(.+)$/, '$1 ($2)');
name = name.replace(/^(Lichtenberg) Bhf\/(.+)$/, '$1 ($2)');
name = name.replace(/^(Alexanderplatz) Bhf/, '$1');
name = name.replace(/^(Zoologischer Garten) Bhf/, '$1');
name = name.replace(/^(Gesundbrunnen) Bhf/, '$1');
name = name.replace(/^(Potsdamer Platz) Bhf/, '$1');
name = name.replace(/^(Lichtenberg) Bhf/, '$1');
name = name.replace(/^(Friedrichstr\.) Bhf/, '$1');
name = name.replace(/^(Jungfernheide) Bhf/, '$1');
name = name.replace(/^(Stadtmitte) U[26]/, '$1');
name = name.replace(/str\./g, 'straße');
name = name.replace(/\s+Str\./g, ' Straße');
return name;
};
this.$rn_normalize_station_name = function(key) {
return $((function(_this) {
return function(_arg, handler) {
var name, node, record;
record = _arg[0], node = _arg[1];
name = node[key];
if (name == null) {
return handler(new Error("unable to find key " + (rpr(key)) + " in\n" + (rpr(node))));
}
node[key] = _this.normalize_berlin_station_name(name);
return handler(null, [record, node]);
};
})(this));
};
this.$remove_gtfs_fields = function() {
return $(function(node, handler) {
var name;
for (name in node) {
if (/^%gtfs/.test(name)) {
delete node[name];
}
}
return handler(null, node);
});
};
this.$side_by_side = function() {
return $(function(node, handler) {
var name, record, value;
record = {};
for (name in node) {
value = node[name];
record[name] = value;
}
return handler(null, [record, node]);
});
};
this.$rn_one_by_one = function() {
var on_data;
on_data = function(_arg) {
var node, record;
record = _arg[0], node = _arg[1];
this.emit('data', record);
return this.emit('data', node);
};
return P.through(on_data, null);
};
this.$rn_add_ids_etc = function(label) {
var idx;
idx = 0;
return $(function(_arg, handler) {
var node, node_id, record;
record = _arg[0], node = _arg[1];
node['~isa'] = 'node';
node['~label'] = label;
record['node-id'] = node_id = node['id'] = "timetable/" + label + "/" + idx;
node['record-id'] = record['id'];
delete node['gtfs-id'];
delete node['gtfs-type'];
idx += 1;
return handler(null, [record, node]);
});
};
this.read_agency_nodes = function(registry, handler) {
var input;
input = registry.createReadStream({
keys: false,
gte: 'gtfs/agency',
lte: 'gtfs/agency\xff'
});
return input.pipe(this.$side_by_side()).pipe(this.$rn_add_agency_id_etc()).pipe(P.$collect_sample(1, function(_, sample) {
return whisper('agency', sample);
})).pipe(this.$rn_one_by_one()).pipe(REGISTRY.$register(registry)).pipe(P.$on_end(function() {
return handler(null);
}));
};
this.$rn_add_agency_id_etc = function() {
return $(function(_arg, handler) {
var node, node_id, record;
record = _arg[0], node = _arg[1];
node['~isa'] = 'node';
node['~label'] = 'agency';
record['node-id'] = node_id = node['id'] = record['id'].replace(/^gtfs\/([^-_]+)[-_]+$/, 'timetable/$1');
delete node['gtfs-id'];
node['record-id'] = record['id'];
delete node['gtfs-type'];
return handler(null, [record, node]);
});
};
this.read_station_nodes = function(registry, handler) {
var input, ratio;
ratio = DEV ? 1 / 5000 : 1;
input = registry.createReadStream({
keys: false,
gte: 'gtfs/stops',
lte: 'gtfs/stops\xff'
});
return input.pipe(P.$sample(ratio, {
headers: true,
seed: 5
})).pipe(this.$side_by_side()).pipe(this.$rn_normalize_station_name('name')).pipe(this.$rn_add_ids_etc('station')).pipe(P.$collect_sample(1, function(_, sample) {
return whisper('station', sample);
})).pipe(this.$rn_one_by_one()).pipe(REGISTRY.$register(registry)).pipe(P.$on_end(function() {
return handler(null);
}));
};
this.read_route_nodes = function(registry, handler) {
var input;
input = registry.createReadStream({
keys: false,
gte: 'gtfs/routes',
lte: 'gtfs/routes\xff'
});
return input.pipe(this.$side_by_side()).pipe(this.$rn_add_ids_etc('route')).pipe(P.$collect_sample(1, function(_, sample) {
return whisper('route', sample);
})).pipe(this.$rn_agency_id_from_gtfs(registry)).pipe(this.$rn_one_by_one()).pipe(REGISTRY.$register(registry)).pipe(P.$on_end(function() {
return handler(null);
}));
};
this.$rn_agency_id_from_gtfs = function(registry) {
return $(function(_arg, handler) {
var gtfs_agency_id, node, record;
record = _arg[0], node = _arg[1];
gtfs_agency_id = node['gtfs-agency-id'];
return registry.get("gtfs/agency/" + gtfs_agency_id, function(error, gtfs_agency_record) {
if (error != null) {
return handler(error);
}
node['agency-id'] = gtfs_agency_record['node-id'];
delete node['gtfs-agency-id'];
return handler(null, [record, node]);
});
});
};
this.read_tour_nodes = function(registry, handler) {
/* OBS implies reading courses and halts. */
var input, ratio;
ratio = DEV ? 1 / 5000 : 1;
input = registry.createReadStream({
keys: false,
gte: 'gtfs/trips',
lte: 'gtfs/trips\xff'
});
return input.pipe(this.$side_by_side()).pipe(P.$sample(ratio, {
headers: true,
seed: 5
})).pipe(P.$collect_sample(1, function(_, sample) {
return whisper('station', sample);
})).pipe(this.$rn_one_by_one()).pipe(P.$on_end(function() {
return handler(null);
}));
};
this.$clean_trip_arr_dep = function() {
/* Replace the first stoptime's arrival and the last stoptime's departure time from the trip. */
return $(function(node, handler) {
var last_idx;
last_idx = node['%gtfs-stoptimes'].length - 1;
node['%gtfs-stoptimes'][0]['arr'] = null;
node['%gtfs-stoptimes'][last_idx]['dep'] = null;
return handler(null, node);
});
};
this.$tour_from_trip = function(registry) {
return $((function(_this) {
return function(node, handler) {
var course, gtfs_routes_id, headsign, reltrip_info, route, route_id, tour;
reltrip_info = COURSES.reltrip_info_from_abstrip(node);
course = COURSES.registered_course_from_reltrip_info(registry, reltrip_info);
headsign = _this.normalize_berlin_station_name(reltrip_info['headsign']);
gtfs_routes_id = node['%gtfs-routes-id'];
route = registry['%gtfs']['routes'][gtfs_routes_id];
route_id = route['id'];
tour = {
'~isa': 'node',
'~label': 'tour',
'course-id': reltrip_info['course-id'],
'route-id': route_id,
'headsign': headsign,
'offset.hhmmss': reltrip_info['offset.hhmmss'],
'offset.s': reltrip_info['offset.s']
};
return handler(null, tour);
};
})(this));
};
this.$add_tour_id = function() {
var idxs;
idxs = {};
return $((function(_this) {
return function(node, handler) {
var idx, route_id;
route_id = node['route-id'];
idx = idxs[route_id] = (idxs[route_id] != null ? idxs[route_id] : idxs[route_id] = 0) + 1;
node['id'] = "tour/" + route_id + "/" + idx;
return handler(null, node);
};
})(this));
};
this.main = function(registry, handler) {
var message, messages, method, method_name, no_method, no_source, node_type, ok_types, t0, tasks, _fn, _i, _j, _k, _len, _len1, _len2, _ref, _ref1;
t0 = 1 * new Date();
tasks = [];
no_source = [];
no_method = [];
ok_types = [];
_ref = options['data']['node-types'];
_fn = (function(_this) {
return function(method_name, method) {
return tasks.push(function(async_handler) {
help("" + badge + "/" + method_name);
return method(registry, function() {
var P;
P = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
info("" + badge + "/" + method_name);
return async_handler.apply(null, P);
});
});
};
})(this);
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
node_type = _ref[_i];
if (node_type !== 'agency' && node_type !== 'station' && node_type !== 'route' && node_type !== 'tour') {
warn("skipping " + node_type);
continue;
}
method_name = "read_" + node_type + "_nodes";
method = this[method_name];
if (method == null) {
no_method.push("no method to read nodes of type " + (rpr(node_type)) + "; skipping");
continue;
}
method = method.bind(this);
ok_types.push(node_type);
_fn(method_name, method);
}
_ref1 = [no_source, no_method];
for (_j = 0, _len1 = _ref1.length; _j < _len1; _j++) {
messages = _ref1[_j];
for (_k = 0, _len2 = messages.length; _k < _len2; _k++) {
message = messages[_k];
warn(message);
}
}
info("reading data for " + ok_types.length + " type(s)");
info(" (" + (ok_types.join(', ')) + ")");
ASYNC.series(tasks, (function(_this) {
return function(error) {
var t1;
if (error != null) {
throw error;
}
t1 = 1 * new Date();
urge('dt:', (t1 - t0) / 1000);
return handler(null, registry);
};
})(this));
return null;
};
}).call(this);