diff --git a/lib/App/MasterUtils.pm b/lib/App/MasterUtils.pm
index c74110b1035d540fcb3d4893f86159772866cf4e..1d212d1dda13ef0889c5e2fe31488f79386e0db7 100644
--- a/lib/App/MasterUtils.pm
+++ b/lib/App/MasterUtils.pm
@@ -93,8 +93,15 @@ sub search_eki
     }
     else
     {
-	my $final = @results[0];
-	return $final->{'index'};
+	if (scalar @results > 1)
+	{
+	    Log::w "Ambiguous search for query $query";
+	}
+	else
+	{
+	    my $final = $results[0];
+	    return $final->{'index'};
+	}
     }
 }
 
diff --git a/lib/App/Navi.pm b/lib/App/Navi.pm
index 08489d923d5903f7612ce7b474ad15546e138008..ed44e8a943c7c5c14e6f4798c6201ec860282efb 100644
--- a/lib/App/Navi.pm
+++ b/lib/App/Navi.pm
@@ -214,11 +214,43 @@ sub Raptor_simple
 	    }
 	    
 	}
+
+	my @next_marked;
+	# Look at foot-paths
+	foreach my $ref (@marked)
+	{
+	    if ($ref->{'direction'} == 1) { next; }
+	    my $p = $ref->{'eki'};
+	    foreach my $fp (@{ $master->{'transfer_times'} })
+	    {
+		my $pprime;
+		if ($fp->{'where'}->[0] eq $p)
+		{
+		    $pprime = $fp->{'where'}->[1];
+		}
+		if ($fp->{'where'}->[1] eq $p)
+		{
+		    $pprime = $fp->{'where'}->[0];
+		}
+		if (defined $pprime)
+		{
+		    $taus{$pprime}[$k] = min
+			$taus{$pprime}[$k],
+			$taus{$p}[$k] + $fp->{'time'}
+		    ;
+		    push @next_marked, { eki => $pprime, direction => 0 };
+		    push @next_marked, { eki => $pprime, direction => 1 };
+		    $from{$pprime} = $p;
+		    Log::d "Marking station $pprime";
+		}
+	    }
+	}
+
+	push @marked, @next_marked;
 	
-	if ($#Q == 0)
+	if (scalar @Q == 0)
 	{
-	    # TODO return a route
-	    return;
+	    last;
 	}
     }
 
@@ -231,9 +263,27 @@ sub Raptor_simple
     
     while ($pos ne $from_id)
     {
-	unshift @legs, $earliest{$pos};
-
 	my $source = $from{$pos};
+
+	# Was this station reached on foot?
+	my $on_foot = 0;
+	foreach my $transfer (@{ $master->{'transfer_times'} })
+	{
+	    my $where = $transfer->{'where'};
+	    if ($where->[0] eq $pos && $where->[1] eq $source ||
+		$where->[0] eq $source && $where->[1] eq $pos)
+	    {
+		$on_foot = 1;
+		unshift @legs, $transfer;
+		last;
+	    }
+	}
+	
+	if (!$on_foot)
+	{
+	    unshift @legs, $earliest{$pos};
+	}
+
 	$pos = $source;
 	unshift @path, $pos;
     }
@@ -243,7 +293,7 @@ sub Raptor_simple
     {
 	my %eki_jikoku = ( 'chaku' => undef, 'hatsu' => undef );
 
-	if ($i != $#path)
+	if ($i != $#path and !defined $legs[$i]->{'time'})
 	{
 	    my $next_frame = $earliest{$path[$i+1]};
 	    my $next_eki_pos = $next_frame->{'dir'}
@@ -254,7 +304,7 @@ sub Raptor_simple
 	    $eki_jikoku{'hatsu'} = $dep;
 	}
 
-	if ($i != 0)
+	if ($i != 0 and !defined $legs[$i-1]->{'time'})
 	{
 	    my $previous_frame = $earliest{$path[$i]};
 	    my $previous_eki_pos = $previous_frame->{'dir'}
@@ -264,44 +314,63 @@ sub Raptor_simple
 	    my $arr = Ressya::arr_time $previous_frame->{'service'}, $previous_eki_pos;
 	    $eki_jikoku{'chaku'} = $arr;
 	}   
-
+	
 	push @jikoku, \%eki_jikoku;
     }
 
     # Second crawl: visual output
     for (my $i = 0; $i < $#path; $i++)
     {
-	my $u = $legs[$i]->{'service'};
-	my $r = $legs[$i]->{'rosen'};
-	my $m = (defined $u->{'meisyo'}) ? ' ' . $u->{'meisyo'} : '';
-	
-	my $from_what = MasterUtils::get_ekimei $master, $path[$i];
-	my $from_dep = $jikoku[$i]->{'hatsu'};
-	my $to_what = MasterUtils::get_ekimei $master, $path[$i+1];
-	my $to_arr = $jikoku[$i+1]->{'chaku'};
-
-	print( (TimeUtils::format_time $from_dep)
-	       . "\t$from_what\n"
-	       . "\t|\n"
-	       . '(' . (TimeUtils::format_time_simple (TimeUtils::subtract_from $from_dep, $to_arr)) . ')'
-	       . "\t| "
-	       . (MasterUtils::get_rosenmei $master, $r)
-	       . ' '
-	       . (FrameUtils::get_syubetsu $master, $r, $u->{'syubetsu'})
-	       . "$m"
-	       . ' for '
-	       . (FrameUtils::get_destination $master, $r, $u->{'jikoku'}, 0, ($legs[$i]->{'dir'} == 0 ? 1 : 0))
-	       . "\n\tV\n"
-	       . (TimeUtils::format_time $to_arr)
-	       . "\t$to_what\n"
-	    );
-	if ($i != $#path - 1)
+	if (!defined $legs[$i]->{'time'})
 	{
-	    my $to_dep = $jikoku[$i+1]->{'hatsu'};
-	    print( '('
-		   . TimeUtils::format_time_simple (TimeUtils::subtract_from $to_arr, $to_dep)
-		   . ")\n"
-		)
+	    my $u = $legs[$i]->{'service'};
+	    my $r = $legs[$i]->{'rosen'};
+	    my $m = (defined $u->{'meisyo'}) ? ' ' . $u->{'meisyo'} : '';
+	    
+	    my $from_what = MasterUtils::get_ekimei $master, $path[$i];
+	    my $from_dep = $jikoku[$i]->{'hatsu'};
+	    my $to_what = MasterUtils::get_ekimei $master, $path[$i+1];
+	    my $to_arr = $jikoku[$i+1]->{'chaku'};
+
+	    print( (TimeUtils::format_time $from_dep)
+		   . "\t$from_what\n"
+		   . "\t|\n"
+		   . '(' . (TimeUtils::format_time_simple (TimeUtils::subtract_from $from_dep, $to_arr)) . ')'
+		   . "\t| "
+		   . (MasterUtils::get_rosenmei $master, $r)
+		   . ' '
+		   . (FrameUtils::get_syubetsu $master, $r, $u->{'syubetsu'})
+		   . "$m"
+		   . ' for '
+		   . (FrameUtils::get_destination $master, $r, $u->{'jikoku'}, 0, ($legs[$i]->{'dir'} == 0 ? 1 : 0))
+		   . "\n\tV\n"
+		   . (TimeUtils::format_time $to_arr)
+		   . "\t$to_what\n"
+		);
+	    
+	    if ($i != $#path - 1 && !defined $legs[$i+1]->{'time'})
+	    {
+		my $to_dep = $jikoku[$i+1]->{'hatsu'};
+		print( '('
+		       . TimeUtils::format_time_simple (TimeUtils::subtract_from $to_arr, $to_dep)
+		       . ")\tO\n"
+		    )
+	    }
+	    if ($i != $#path - 1 && defined $legs[$i+1]->{'time'})
+	    {
+		my $to_dep = $jikoku[$i+2]->{'hatsu'};
+		my $tt = $legs[$i+1]->{'time'};
+		my $total = TimeUtils::subtract_from $to_arr, $to_dep;
+		my $wait = TimeUtils::subtract_from $tt, $total;
+		print( '<'
+		       . (TimeUtils::format_time_simple $tt)
+		       . ">\t:\n"
+		       . '('
+		       . (TimeUtils::format_time_simple $wait)
+		       . ")\t:\n"
+		    )
+	    }
+
 	}
     }
 }
diff --git a/lib/App/Transfer.pm b/lib/App/Transfer.pm
new file mode 100644
index 0000000000000000000000000000000000000000..01d4a91c68a8c4a596cef213ebd83a882eac90c5
--- /dev/null
+++ b/lib/App/Transfer.pm
@@ -0,0 +1,28 @@
+package Transfer;
+
+use strict;
+use warnings;
+use Data::Printer;
+
+BEGIN
+{
+    unshift @INC, '.';
+}
+
+sub take_all
+{
+    shift;
+    return \@_;
+}
+
+sub format_tt
+{
+    shift;
+    my ($from, undef, $to, undef, $time) = @_;
+    my %frame;
+    $frame{'where'} = [$from, $to];
+    $frame{'time'} = $time;
+    return \%frame;
+}
+
+1;
diff --git a/src/oud2_parser.pl b/src/oud2_parser.pl
index c72ed24f567730b49568e9c3bcedad39665f8f88..29f9141497ddb8b9944d4b86ecf50939eb4c84cd 100644
--- a/src/oud2_parser.pl
+++ b/src/oud2_parser.pl
@@ -30,6 +30,7 @@ use List::Util qw(any);
 
 use App::Log;
 use App::Ts;
+use App::Transfer;
 use App::Ressya;
 use App::Frame;
 use App::FrameUtils;
@@ -37,6 +38,29 @@ use App::MasterUtils;
 use App::Dia;
 use App::Navi;
 
+
+# transfer_times grammar
+my $tt_rules = << 'endrule'
+lexeme default = latm => 1
+:start ::= ALL
+
+ALL			::= RULE+
+			    action => Transfer::take_all
+RULE			::= NAME SEP NAME SEP INT
+			    action => Transfer::format_tt
+
+:lexeme ~ NAME priority => -1
+NAME	   		~ [^\v\.]+
+INT			~ [\d]+
+:lexeme ~ SEP priority => 2
+SEP			~ [.]
+
+:discard		~ NEWLINE
+NEWLINE	       		~ [\s]+
+
+endrule
+    ;
+
 # .oud2 grammar
 my $oud_rules = << 'endrule'
 lexeme default = latm => 1
@@ -76,7 +100,6 @@ DIA_UP_SECTION		::= DIA_UP_BEGIN
 
 
 HEADER_BEGIN	      	::= 'FileType='
-			    action => Dia::begin_header_section
 
 ROSEN_BEGIN		::= 'Rosen.'
 ROSEN_NAME		::= 'Rosenmei=' NAME
@@ -105,15 +128,12 @@ SYUBETSU_SUB		::= SYUBETSU_NAME
 SYUBETSU_BEGIN 		~ 'Ressyasyubetsu.'
 SYUBETSU_NAME		::= 'Syubetsumei=' NAME
 			    action => Dia::second
-#SYUBETSU_RYAKU		::= 'Ryakusyou=' NAME
+# SYUBETSU_RYAKU       	::= 'Ryakusyou=' NAME
 # 			    action => Dia::second
 
 DIA_BEGIN		::= 'Dia.'
-			    action => Dia::begin_dia_section
 DIA_DOWN_BEGIN		::= 'Kudari.'
-			    action => Dia::dia_down_subsection
 DIA_UP_BEGIN		::= 'Nobori.'
-			    action => Dia::dia_up_subsection
 
 RESSYAS			::= RESSYA+
 			    action => Dia::take_all
@@ -218,16 +238,36 @@ my $oud_grammar = Marpa::R2::Scanless::G->new(
     }
     );
 
+my $tt_grammar = Marpa::R2::Scanless::G->new(
+    {
+	source => \$tt_rules,
+	trace_terminals => 1,
+    }
+    );
+
 my %master;
 
 my $dias_path = $ARGV[0];
 my $default_path = 'tests/dia/kyogoku.oud2';
 my $root_path = (defined $dias_path) ? $dias_path : '../oud2/';
 my $trains_path = $root_path . 'train/';
-
-opendir my $dir, $trains_path or die "Error opening $trains_path";
-my @trains = readdir $dir;
-closedir $dir;
+my $bus_path = $root_path . 'bus/';
+my $tt_path = $root_path . 'transfer_times';
+
+opendir my $tdir, $trains_path or die "Error opening $trains_path";
+opendir my $bdir, $bus_path or die "Error opening $bus_path";
+my @trains = readdir $tdir;
+my @bus = readdir $bdir;
+closedir $tdir;
+closedir $bdir;
+
+sub new_recce { return Marpa::R2::Scanless::R->new(
+		    {
+			grammar => $oud_grammar,
+			trace_terminals => 0,
+		    }
+		    );
+}
 
 # Parsing step.
 # Build "temporary" frames for each diagram.
@@ -238,12 +278,7 @@ foreach my $file (@trains)
     my $dia_file;
     # We need to rebuild the recognizer for each file.
     # This is actually a Marpa limitation.
-    my $recce = Marpa::R2::Scanless::R->new(
-    {
-	grammar => $oud_grammar,
-	trace_terminals => 0,
-    }
-    );
+    my $recce = new_recce ();
     
     my $train_path = $trains_path . $file;
     print 'Using file ' . $train_path . "\n";
@@ -263,6 +298,43 @@ foreach my $file (@trains)
 
     my %frame = %{ ${$recce->value()} };
     $frame{'id'} = $basename;
+    $frame{'is_train'} = 1;
+    Frame::frame_info \%frame;
+    
+    $master{'rosen'}{$basename} = \%frame;
+    
+    close $dia_file;
+}
+
+# Same thing with busses.
+foreach my $file (@bus)
+{
+    next if ($file =~ /^\.+$/);
+
+    my $dia_file;
+    # We need to rebuild the recognizer for each file.
+    # This is actually a Marpa limitation.
+    my $recce = new_recce ();
+    
+    my $abus_path = $bus_path . $file;
+    print 'Using file ' . $abus_path . "\n";
+    open $dia_file, '<:encoding(UTF-8):via(File::BOM)', $abus_path;
+
+    my $file_name = basename $file;
+    my $basename = substr $file_name, 0, -5;
+    print "Route id will be $basename\n";
+
+    read $dia_file, my $contents, -s $dia_file;
+
+    try { print $recce->read(\$contents) . ' bytes read.'; }
+    catch ($e) { print "Malformation in .oud file.\n$e\n"; }
+    print "\n";
+
+    # print $recce->show_progress();
+
+    my %frame = %{ ${$recce->value()} };
+    $frame{'id'} = $basename;
+    $frame{'is_train'} = 0;
     Frame::frame_info \%frame;
     
     $master{'rosen'}{$basename} = \%frame;
@@ -280,6 +352,8 @@ foreach my $file (@trains)
 my @master_ekis;
 foreach my $frame (values %{ $master{'rosen'} })
 {
+    my $is_train = $frame->{'is_train'};
+    
     my @old_ekis = @{ $frame->{'eki'} };
     my @new_ekis;
     my %dict;
@@ -311,14 +385,15 @@ foreach my $frame (values %{ $master{'rosen'} })
 	if ($restart) { next; }
 
 	# TODO Station has already been processed in another route
-	foreach my $old (keys %{ $master{'eki_index'} })
+	foreach my $existing (keys %{ $master{'eki_index'} })
 	{
-	    my $old_ref = MasterUtils::sta_from_id \%master, $old;
-	    if ($old_ref->{'ekimei'} eq $ekimei)
+	    my $existing_ref = MasterUtils::sta_from_id \%master, $existing;
+	    if ($existing_ref->{'ekimei'} eq $ekimei &&
+		$existing_ref->{'found_as_train_stop'} == $is_train)
 	    {
-		Log::i "Found $ekimei in the existing index (first found in " . $old_ref->{'found_in'} . " with id $old)";
+		Log::i "Found $ekimei in the existing index (first found in " . $existing_ref->{'found_in'} . " with id $existing)";
 		Log::i "Assuming this is the same station as the one processed earlier.";
-		push @new_ekis, $old;
+		push @new_ekis, $existing;
 		$restart = 1;
 		last;
 	    }
@@ -330,6 +405,7 @@ foreach my $frame (values %{ $master{'rosen'} })
 	print "Adding station $ekimei to master frame with id $id\n";
 	$new_struct{'ekimei'} = $ekimei;
 	$new_struct{'found_in'} = $frame->{'id'};
+	$new_struct{'found_as_train_stop'} = $is_train;
 	$master{'eki_index'}{$id} = \%new_struct;
 
 	push @new_ekis, $id;
@@ -342,9 +418,44 @@ foreach my $frame (values %{ $master{'rosen'} })
     $frame->{'eki'} = \@new_ekis;
 }
 
+# Parse transfer times
+my $recce = Marpa::R2::Scanless::R->new(
+    {
+	grammar => $tt_grammar,
+	trace_terminals => 0,
+    }
+    );
+open my $tt_file, '<:encoding(UTF-8):via(File::BOM)', $tt_path;
+
+print "Parsing transfer times\n";
+
+read $tt_file, my $tt_contents, -s $tt_file;
+try { print $recce->read(\$tt_contents) . ' bytes read.'; }
+catch ($e) { print "Malformation in transfer_times file.\n$e\n"; }
+print "\n";
+
+my $transfers = ${ $recce->value() };
+foreach my $transfer (@$transfers)
+{
+    my $where = $transfer->{'where'};
+    my $time = $transfer->{'time'};
+    print "Transfer time is $time' between $where->[0] and $where->[1]\n";
+    $transfer->{'where'} =
+	[
+	 (MasterUtils::search_eki \%master, $where->[0]),
+	 (MasterUtils::search_eki \%master, $where->[1])
+	];
+}
+
+$master{'transfer_times'} = $transfers;
+
 # FrameUtils::hassya_hyou \%master, 'sekihoku1_28';
 
-my $d = MasterUtils::search_eki \%master, '幾寅';
-my $a = MasterUtils::search_eki \%master, '音別';
+my $d = MasterUtils::search_eki \%master, '以久科';
+my $a = MasterUtils::search_eki \%master, '五十嵐';
+
+sub eki { return MasterUtils::search_eki \%master, $_[0]; }
+
+Navi::Raptor_simple \%master, $d, $a, 640;
 
-Navi::Raptor_simple \%master, $d, $a, 334;
+# FrameUtils::hassya_hyou \%master, (eki '古瀬');