| line | stmt | bran | cond | sub | pod | time | code | 
| 1 |  |  |  |  |  |  | # $Revision: 1.5 $ $Date: 2006/03/02 21:00:28 $ $Author: estrabd $ | 
| 2 |  |  |  |  |  |  |  | 
| 3 |  |  |  |  |  |  | package FLAT::Legacy::FA::DFA; | 
| 4 |  |  |  |  |  |  |  | 
| 5 | 3 |  |  | 3 |  | 3392 | use base 'FLAT::Legacy::FA'; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 255 |  | 
| 6 | 3 |  |  | 3 |  | 18 | use strict; | 
|  | 3 |  |  |  |  | 5 |  | 
|  | 3 |  |  |  |  | 67 |  | 
| 7 | 3 |  |  | 3 |  | 11 | use Carp; | 
|  | 3 |  |  |  |  | 3 |  | 
|  | 3 |  |  |  |  | 160 |  | 
| 8 |  |  |  |  |  |  |  | 
| 9 | 3 |  |  | 3 |  | 1560 | use FLAT::Legacy::FA::NFA; | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 95 |  | 
| 10 | 3 |  |  | 3 |  | 1326 | use FLAT::Legacy::FA::RE; | 
|  | 3 |  |  |  |  | 8 |  | 
|  | 3 |  |  |  |  | 99 |  | 
| 11 | 3 |  |  | 3 |  | 20 | use Data::Dumper; | 
|  | 3 |  |  |  |  | 4 |  | 
|  | 3 |  |  |  |  | 13309 |  | 
| 12 |  |  |  |  |  |  |  | 
| 13 |  |  |  |  |  |  | sub new { | 
| 14 | 121 |  |  | 121 | 0 | 231 | my $class = shift; | 
| 15 | 121 |  |  |  |  | 936 | bless { | 
| 16 |  |  |  |  |  |  | _START_STATE => undef,  # start states -> plural! | 
| 17 |  |  |  |  |  |  | _STATES => [],          # Set of all states | 
| 18 |  |  |  |  |  |  | _FINAL_STATES => [],    # Set of final states, subset of _STATES | 
| 19 |  |  |  |  |  |  | _SYMBOLS => [],         # Symbols | 
| 20 |  |  |  |  |  |  | _TRANSITIONS => {},     # Transition table | 
| 21 |  |  |  |  |  |  | }, $class; | 
| 22 |  |  |  |  |  |  | } | 
| 23 |  |  |  |  |  |  |  | 
| 24 |  |  |  |  |  |  | sub jump_start { | 
| 25 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 26 | 0 |  |  |  |  | 0 | my $DFA = FLAT::Legacy::FA::DFA->new(); | 
| 27 | 0 |  |  |  |  | 0 | my $symbol = shift; | 
| 28 | 0 | 0 |  |  |  | 0 | if (!defined($symbol)) { | 
| 29 |  |  |  |  |  |  | # add 1 state that is the start and final state | 
| 30 | 0 |  |  |  |  | 0 | $DFA->add_state(0); | 
| 31 |  |  |  |  |  |  | # set start and final | 
| 32 | 0 |  |  |  |  | 0 | $DFA->set_start(0); | 
| 33 | 0 |  |  |  |  | 0 | $DFA->add_final(0); | 
| 34 |  |  |  |  |  |  | } else { | 
| 35 | 0 |  |  |  |  | 0 | chomp($symbol); | 
| 36 |  |  |  |  |  |  | # add states | 
| 37 | 0 |  |  |  |  | 0 | $DFA->add_state(0,1); | 
| 38 |  |  |  |  |  |  | # add symbol | 
| 39 | 0 |  |  |  |  | 0 | $DFA->add_symbol($symbol); | 
| 40 |  |  |  |  |  |  | # set start and final | 
| 41 | 0 |  |  |  |  | 0 | $DFA->set_start(0); | 
| 42 | 0 |  |  |  |  | 0 | $DFA->add_final(1); | 
| 43 |  |  |  |  |  |  | # add single transition | 
| 44 | 0 |  |  |  |  | 0 | $DFA->add_transition(0,$symbol,1); | 
| 45 |  |  |  |  |  |  | } | 
| 46 | 0 |  |  |  |  | 0 | return $DFA; | 
| 47 |  |  |  |  |  |  | } | 
| 48 |  |  |  |  |  |  |  | 
| 49 |  |  |  |  |  |  | sub load_file { | 
| 50 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 51 | 0 |  |  |  |  | 0 | my $file = shift; | 
| 52 | 0 | 0 |  |  |  | 0 | if (-e $file) { | 
| 53 | 0 |  |  |  |  | 0 | open (DFA,"<$file"); | 
| 54 | 0 |  |  |  |  | 0 | my $string = undef; | 
| 55 | 0 |  |  |  |  | 0 | while () { | 
| 56 | 0 |  |  |  |  | 0 | $string .= $_; | 
| 57 |  |  |  |  |  |  | } | 
| 58 | 0 |  |  |  |  | 0 | close (DFA); | 
| 59 | 0 |  |  |  |  | 0 | $self->load_string($string); | 
| 60 |  |  |  |  |  |  | } | 
| 61 |  |  |  |  |  |  | } | 
| 62 |  |  |  |  |  |  |  | 
| 63 |  |  |  |  |  |  | sub load_string { | 
| 64 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 65 | 0 |  |  |  |  | 0 | my $string = shift; | 
| 66 | 0 |  |  |  |  | 0 | my @lines = split("\n",$string); | 
| 67 | 0 |  |  |  |  | 0 | my $CURR_STATE = undef; | 
| 68 | 0 |  |  |  |  | 0 | foreach (@lines) { | 
| 69 |  |  |  |  |  |  | # strip comments | 
| 70 | 0 |  |  |  |  | 0 | $_ =~ s/\s*#.*$//; | 
| 71 |  |  |  |  |  |  | # check if line is a state, transition, or keyword | 
| 72 | 0 | 0 | 0 |  |  | 0 | if (m/^\s*([\w\d]*)\s*:\s*$/) { | 
|  |  | 0 | 0 |  |  |  |  | 
|  |  | 0 |  |  |  |  |  | 
| 73 |  |  |  |  |  |  | #print STDERR "Found transitions for state $1\n"; | 
| 74 | 0 |  |  |  |  | 0 | $self->add_state($1); | 
| 75 | 0 |  |  |  |  | 0 | $CURR_STATE = $1; | 
| 76 |  |  |  |  |  |  | } elsif (m/^\s*([\w\d]*)\s*([\w\d,]*)\s*$/ && ! m/^$/) { | 
| 77 |  |  |  |  |  |  | # treat as transition | 
| 78 |  |  |  |  |  |  | #print STDERR "Input: '$1' goes to $2\n"; | 
| 79 | 0 |  |  |  |  | 0 | my @s = split(',',$2); | 
| 80 | 0 |  |  |  |  | 0 | $self->add_transition($CURR_STATE,$1,@s); | 
| 81 | 0 |  |  |  |  | 0 | $self->add_symbol($1); | 
| 82 |  |  |  |  |  |  | } elsif (m/^\s*([\w\d]*)\s*::\s*([\w\d,]*)\s*$/ && ! m/^$/) { | 
| 83 |  |  |  |  |  |  | # Check for known header keywords | 
| 84 | 0 |  |  |  |  | 0 | my $val = $2; | 
| 85 | 0 | 0 |  |  |  | 0 | if ($1 =~ m/START/i) { | 
|  |  | 0 |  |  |  |  |  | 
| 86 | 0 |  |  |  |  | 0 | $self->set_start($val); | 
| 87 |  |  |  |  |  |  | } elsif ($1 =~ m/FINAL/i) { | 
| 88 | 0 |  |  |  |  | 0 | my @s = split(',',$val); | 
| 89 | 0 |  |  |  |  | 0 | $self->add_final(@s); | 
| 90 |  |  |  |  |  |  | } else { | 
| 91 | 0 |  |  |  |  | 0 | print STDERR "WARNING: $1 is not a valid header...\n"; | 
| 92 |  |  |  |  |  |  | } | 
| 93 |  |  |  |  |  |  | } | 
| 94 |  |  |  |  |  |  | } | 
| 95 |  |  |  |  |  |  | } | 
| 96 |  |  |  |  |  |  |  | 
| 97 |  |  |  |  |  |  | sub clone { | 
| 98 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 99 | 0 |  |  |  |  | 0 | my $DFA = FLAT::Legacy::FA::DFA->new(); | 
| 100 | 0 |  |  |  |  | 0 | $DFA->add_state($self->get_states()); | 
| 101 | 0 |  |  |  |  | 0 | $DFA->add_final($self->get_final()); | 
| 102 | 0 |  |  |  |  | 0 | $DFA->add_symbol($self->get_symbols()); | 
| 103 | 0 |  |  |  |  | 0 | $DFA->set_start($self->get_start()); | 
| 104 | 0 |  |  |  |  | 0 | foreach my $state ($self->get_states()) { | 
| 105 | 0 |  |  |  |  | 0 | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 106 | 0 |  |  |  |  | 0 | $DFA->add_transition($state,$symbol,$self->{_TRANSITIONS}{$state}{$symbol}); | 
| 107 |  |  |  |  |  |  | } | 
| 108 |  |  |  |  |  |  | } | 
| 109 | 0 |  |  |  |  | 0 | return $DFA; | 
| 110 |  |  |  |  |  |  | } | 
| 111 |  |  |  |  |  |  |  | 
| 112 |  |  |  |  |  |  | sub to_nfa { | 
| 113 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 114 | 0 |  |  |  |  | 0 | my $NFA = FLAT::Legacy::FA::NFA->new(); | 
| 115 | 0 |  |  |  |  | 0 | $NFA->add_state($self->get_states()); | 
| 116 | 0 |  |  |  |  | 0 | $NFA->add_final($self->get_final()); | 
| 117 | 0 |  |  |  |  | 0 | $NFA->add_symbol($self->get_symbols()); | 
| 118 | 0 |  |  |  |  | 0 | $NFA->set_start($self->get_start()); | 
| 119 | 0 |  |  |  |  | 0 | foreach my $state ($self->get_states()) { | 
| 120 | 0 |  |  |  |  | 0 | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 121 | 0 |  |  |  |  | 0 | $NFA->add_transition($state,$symbol,$self->{_TRANSITIONS}{$state}{$symbol}); | 
| 122 |  |  |  |  |  |  | } | 
| 123 |  |  |  |  |  |  | } | 
| 124 | 0 |  |  |  |  | 0 | return $NFA; | 
| 125 |  |  |  |  |  |  | } | 
| 126 |  |  |  |  |  |  |  | 
| 127 |  |  |  |  |  |  | sub minimize() { | 
| 128 | 120 |  |  | 120 | 0 | 763 | my $self = shift; | 
| 129 | 120 |  |  |  |  | 210 | my @PI1 = (); | 
| 130 |  |  |  |  |  |  | # Anon sub used to get group # | 
| 131 |  |  |  |  |  |  | my $state2group = sub { | 
| 132 | 4575 |  |  | 4575 |  | 3285 | my $array = shift; | 
| 133 | 4575 |  |  |  |  | 2945 | my $state = shift; | 
| 134 | 4575 |  |  |  |  | 2836 | my $c = 0; | 
| 135 | 4575 |  |  |  |  | 3116 | foreach my $x (@{$array}) { | 
|  | 4575 |  |  |  |  | 4131 |  | 
| 136 | 8314 |  |  |  |  | 4857 | foreach my $y (@{$x}) { | 
|  | 8314 |  |  |  |  | 6281 |  | 
| 137 | 73679 | 100 |  |  |  | 86476 | return $c if ($y eq $state); | 
| 138 |  |  |  |  |  |  | } | 
| 139 | 3739 |  |  |  |  | 3015 | $c++; | 
| 140 |  |  |  |  |  |  | } | 
| 141 | 120 |  |  |  |  | 713 | }; | 
| 142 |  |  |  |  |  |  | # Anon sub attempts to identify identical 2d arrays | 
| 143 |  |  |  |  |  |  | my $getsig = sub { | 
| 144 | 240 |  |  | 240 |  | 242 | my $array = shift; | 
| 145 | 240 |  |  |  |  | 305 | my @str = (); | 
| 146 | 240 |  |  |  |  | 188 | foreach my $x (@{$array}) { | 
|  | 240 |  |  |  |  | 258 |  | 
| 147 | 920 |  |  |  |  | 570 | my $str = crypt(join('',@{$x}),0); | 
|  | 920 |  |  |  |  | 2526 |  | 
| 148 | 920 |  |  |  |  | 956 | push(@str,$str); | 
| 149 |  |  |  |  |  |  | } | 
| 150 | 240 |  |  |  |  | 490 | @str = sort(@str); | 
| 151 | 240 |  |  |  |  | 912 | return join('',@str); | 
| 152 | 120 |  |  |  |  | 483 | }; | 
| 153 |  |  |  |  |  |  | # Anon sub removes duplicate and dead state | 
| 154 |  |  |  |  |  |  | my $cleanup = sub { | 
| 155 | 1354 |  |  | 1354 |  | 1043 | my $oldname = shift; | 
| 156 | 1354 |  |  |  |  | 949 | my $newname = shift; | 
| 157 | 1354 |  |  |  |  | 933 | my $i = 0; | 
| 158 |  |  |  |  |  |  | # will add $newstate as long as it is not already there | 
| 159 | 1354 |  |  |  |  | 1489 | my @new = (); | 
| 160 | 1354 |  |  |  |  | 2098 | foreach my $state ($self->get_states()) { | 
| 161 |  |  |  |  |  |  | # just remove state | 
| 162 | 29976 | 100 |  |  |  | 33772 | if ($state ne $oldname) { | 
| 163 | 28622 |  |  |  |  | 19515 | push(@new,$state); | 
| 164 |  |  |  |  |  |  | } | 
| 165 | 29976 |  |  |  |  | 69838 | $self->{_STATES} = [@new]; | 
| 166 |  |  |  |  |  |  | } | 
| 167 |  |  |  |  |  |  | # replace name if start state | 
| 168 | 1354 | 50 |  |  |  | 3408 | if ($self->is_start($oldname)) { | 
| 169 | 0 |  |  |  |  | 0 | $self->set_start($newname); | 
| 170 |  |  |  |  |  |  | } | 
| 171 |  |  |  |  |  |  | # replace transitions | 
| 172 | 1354 |  |  |  |  | 1093 | foreach my $state (keys %{$self->{_TRANSITIONS}}) { | 
|  | 1354 |  |  |  |  | 4738 |  | 
| 173 | 29976 |  |  |  |  | 16783 | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 29976 |  |  |  |  | 33943 |  | 
| 174 |  |  |  |  |  |  | # rename destination states | 
| 175 | 37117 | 100 |  |  |  | 46937 | if ($self->{_TRANSITIONS}{$state}{$symbol} eq $oldname) { | 
| 176 | 1101 |  |  |  |  | 1126 | $self->{_TRANSITIONS}{$state}{$symbol} = $newname; | 
| 177 |  |  |  |  |  |  | } | 
| 178 |  |  |  |  |  |  | # rename start state | 
| 179 | 37117 | 100 |  |  |  | 45195 | if ($state eq $oldname) { | 
| 180 | 1763 |  |  |  |  | 2658 | $self->add_transition($newname,$symbol,$self->{_TRANSITIONS}{$state}{$symbol}); | 
| 181 |  |  |  |  |  |  | } | 
| 182 |  |  |  |  |  |  | } | 
| 183 | 29976 | 100 |  |  |  | 39707 | if ($state eq $oldname) { | 
| 184 |  |  |  |  |  |  | # delete all transitions of old state | 
| 185 | 1354 |  |  |  |  | 2482 | delete($self->{_TRANSITIONS}{$state}); | 
| 186 |  |  |  |  |  |  | } | 
| 187 |  |  |  |  |  |  | } | 
| 188 |  |  |  |  |  |  | # replace final states | 
| 189 | 1354 |  |  |  |  | 2481 | $i = 0; | 
| 190 | 1354 |  |  |  |  | 2559 | foreach ($self->get_final()) { | 
| 191 | 3393 | 100 |  |  |  | 3973 | if ($_ eq $oldname) { | 
| 192 | 88 | 50 |  |  |  | 197 | if ($self->is_final($newname)) { | 
| 193 | 88 |  |  |  |  | 259 | $self->remove_final($oldname); | 
| 194 |  |  |  |  |  |  | } else { | 
| 195 | 0 |  |  |  |  | 0 | $self->{_FINAL_STATES}[$i] = $newname; | 
| 196 |  |  |  |  |  |  | } | 
| 197 |  |  |  |  |  |  | } | 
| 198 | 3393 |  |  |  |  | 2563 | $i++; | 
| 199 |  |  |  |  |  |  | } | 
| 200 | 1354 |  |  |  |  | 2557 | return; | 
| 201 | 120 |  |  |  |  | 542 | }; | 
| 202 |  |  |  |  |  |  | # Step 1 - create a group containing 2 sets of states: accepting (F) and non-accepting (S-F) | 
| 203 | 120 |  |  |  |  | 196 | my @tmp = (); | 
| 204 | 120 |  |  |  |  | 323 | foreach ($self->get_states()) { | 
| 205 | 2034 | 100 |  |  |  | 3125 | if (!$self->is_final($_)) { | 
| 206 | 1697 |  |  |  |  | 2173 | push(@tmp,$_); | 
| 207 |  |  |  |  |  |  | } | 
| 208 |  |  |  |  |  |  | } | 
| 209 | 120 |  |  |  |  | 334 | push(@PI1,[$self->get_final()]); | 
| 210 | 120 |  |  |  |  | 350 | push(@PI1,[@tmp]); | 
| 211 | 120 |  |  |  |  | 186 | undef @tmp; | 
| 212 |  |  |  |  |  |  | # Steps 2 & 3 - get final group of partitions through an iterative process | 
| 213 |  |  |  |  |  |  | # ...aka - figure out what states can be merged into one | 
| 214 | 120 |  |  |  |  | 213 | my $sig_before = 'x'; | 
| 215 | 120 |  |  |  |  | 149 | my $sig_after = 'y'; | 
| 216 | 120 |  |  |  |  | 256 | while ($sig_before ne $sig_after) { | 
| 217 |  |  |  |  |  |  | # print Dumper(@PI1); | 
| 218 | 120 |  |  |  |  | 243 | my %PI2 = (); | 
| 219 | 120 |  |  |  |  | 171 | my $group_number = 0; | 
| 220 | 120 |  |  |  |  | 218 | foreach my $group_ref (@PI1) { | 
| 221 | 240 |  |  |  |  | 205 | foreach my $group_state (@{$group_ref}) { | 
|  | 240 |  |  |  |  | 290 |  | 
| 222 | 2034 |  |  |  |  | 2379 | my $mygroup = $state2group->(\@PI1,$group_state); # seed with own group number | 
| 223 | 2034 |  |  |  |  | 3460 | foreach my $symbol ($self->get_symbols()) { | 
| 224 | 4056 | 100 |  |  |  | 5761 | if ($self->has_transition_on($group_state,$symbol)) { | 
| 225 | 2541 |  |  |  |  | 3317 | my $trans_to_group = $state2group->(\@PI1,$self->get_transition_on($group_state,$symbol)); | 
| 226 | 2541 |  |  |  |  | 3588 | $mygroup .= $trans_to_group.$symbol; | 
| 227 |  |  |  |  |  |  | } | 
| 228 |  |  |  |  |  |  | } | 
| 229 | 2034 | 50 |  |  |  | 2889 | if (defined($mygroup)) { | 
| 230 | 2034 | 100 |  |  |  | 2963 | if (!defined($PI2{$mygroup})) { | 
| 231 | 680 |  |  |  |  | 1296 | $PI2{$mygroup} = []; | 
| 232 |  |  |  |  |  |  | } | 
| 233 | 2034 |  |  |  |  | 1390 | push(@{$PI2{$mygroup}},$group_state); | 
|  | 2034 |  |  |  |  | 3249 |  | 
| 234 |  |  |  |  |  |  | } | 
| 235 |  |  |  |  |  |  | } | 
| 236 | 240 |  |  |  |  | 305 | $group_number++; | 
| 237 |  |  |  |  |  |  | } | 
| 238 |  |  |  |  |  |  | # copy to @PI1 | 
| 239 | 120 |  |  |  |  | 420 | @PI1 = sort(@PI1); | 
| 240 | 120 |  |  |  |  | 245 | $sig_before = $getsig->(\@PI1); | 
| 241 | 120 |  |  |  |  | 283 | @PI1 = (); | 
| 242 | 120 |  |  |  |  | 334 | foreach my $g (keys(%PI2)) { | 
| 243 | 680 |  |  |  |  | 638 | push(@PI1,$PI2{$g}); | 
| 244 |  |  |  |  |  |  | } | 
| 245 | 120 |  |  |  |  | 758 | @PI1 = sort(@PI1); | 
| 246 | 120 |  |  |  |  | 207 | $sig_after = $getsig->(\@PI1); | 
| 247 |  |  |  |  |  |  | } | 
| 248 |  |  |  |  |  |  | # Steps 4 & 5 - reduce final subgroups into a single representative | 
| 249 | 120 |  |  |  |  | 186 | my @removed = (); | 
| 250 | 120 |  |  |  |  | 207 | foreach my $group_ref (@PI1) { | 
| 251 | 680 |  |  |  |  | 521 | my $rep = shift(@{$group_ref}); | 
|  | 680 |  |  |  |  | 738 |  | 
| 252 | 680 |  |  |  |  | 515 | foreach my $group_state (@{$group_ref}) { | 
|  | 680 |  |  |  |  | 663 |  | 
| 253 | 1354 |  |  |  |  | 2282 | foreach my $symbol ($self->get_symbols) { | 
| 254 | 2701 |  |  |  |  | 3202 | my $trans = $self->get_transition_on($group_state); | 
| 255 | 2701 | 50 |  |  |  | 4246 | if (defined($trans)) { | 
| 256 | 0 |  |  |  |  | 0 | $self->add_transition($rep,$symbol,$trans); | 
| 257 |  |  |  |  |  |  | } | 
| 258 |  |  |  |  |  |  | } | 
| 259 | 1354 |  |  |  |  | 1804 | $cleanup->($group_state,$rep); | 
| 260 |  |  |  |  |  |  | #print STDERR "removed $group_state\n"; | 
| 261 | 1354 |  |  |  |  | 1770 | push(@removed,$group_state); | 
| 262 |  |  |  |  |  |  | } | 
| 263 |  |  |  |  |  |  | } | 
| 264 | 120 |  |  |  |  | 2889 | return @removed; | 
| 265 |  |  |  |  |  |  | } | 
| 266 |  |  |  |  |  |  |  | 
| 267 |  |  |  |  |  |  | sub delete_state { | 
| 268 | 0 |  |  | 0 | 0 | 0 | my $self = shift(); | 
| 269 | 0 |  |  |  |  | 0 | my @del_states = @_; | 
| 270 | 0 |  |  |  |  | 0 | foreach my $del_state (@del_states) { | 
| 271 | 0 | 0 |  |  |  | 0 | if ($del_state eq $self->get_start()) { | 
| 272 | 0 |  |  |  |  | 0 | print STDERR "WARNING: The start state, $del_state, is being deleted!\n"; | 
| 273 | 0 |  |  |  |  | 0 | $self->set_start(''); | 
| 274 |  |  |  |  |  |  | } | 
| 275 | 0 | 0 |  |  |  | 0 | if ($self->is_final($del_state)) { | 
| 276 | 0 |  |  |  |  | 0 | print STDERR "WARNING: A final state, $del_state, is being deleted!\n"; | 
| 277 | 0 |  |  |  |  | 0 | my $c = 0; | 
| 278 | 0 |  |  |  |  | 0 | foreach my $f ($self->get_final()) { | 
| 279 | 0 | 0 |  |  |  | 0 | if ($f eq $del_state) { | 
| 280 | 0 |  |  |  |  | 0 | delete($self->{_FINAL_STATES}[$c]); | 
| 281 | 0 |  |  |  |  | 0 | last; | 
| 282 |  |  |  |  |  |  | } | 
| 283 | 0 |  |  |  |  | 0 | $c++; | 
| 284 |  |  |  |  |  |  | } | 
| 285 |  |  |  |  |  |  | } | 
| 286 | 0 |  |  |  |  | 0 | my @new = (); | 
| 287 | 0 |  |  |  |  | 0 | foreach my $f ($self->get_states()) { | 
| 288 | 0 | 0 |  |  |  | 0 | if ($f ne $del_state) { | 
| 289 | 0 |  |  |  |  | 0 | push(@new,$f); | 
| 290 |  |  |  |  |  |  | } | 
| 291 | 0 |  |  |  |  | 0 | $self->{_STATES} = [@new]; | 
| 292 |  |  |  |  |  |  | } | 
| 293 | 0 | 0 |  |  |  | 0 | if (defined($self->{_TRANSITIONS}{$del_state})) { | 
| 294 | 0 |  |  |  |  | 0 | delete($self->{_TRANSITIONS}{$del_state}); | 
| 295 |  |  |  |  |  |  | } | 
| 296 |  |  |  |  |  |  | # delete transitions | 
| 297 | 0 |  |  |  |  | 0 | foreach my $state (keys %{$self->{_TRANSITIONS}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 298 | 0 |  |  |  |  | 0 | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 299 | 0 |  |  |  |  | 0 | my $trans = $self->get_transition_on($state,$symbol); | 
| 300 | 0 | 0 |  |  |  | 0 | if (defined($trans)) { | 
| 301 | 0 | 0 |  |  |  | 0 | if ($trans eq $del_state) { | 
| 302 | 0 |  |  |  |  | 0 | delete($self->{_TRANSITIONS}{$state}{$symbol}); | 
| 303 |  |  |  |  |  |  | } | 
| 304 |  |  |  |  |  |  | } | 
| 305 |  |  |  |  |  |  | } | 
| 306 |  |  |  |  |  |  | } | 
| 307 |  |  |  |  |  |  | } | 
| 308 | 0 |  |  |  |  | 0 | return; | 
| 309 |  |  |  |  |  |  | } | 
| 310 |  |  |  |  |  |  |  | 
| 311 |  |  |  |  |  |  | sub rename_state { | 
| 312 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 313 | 0 |  |  |  |  | 0 | my $oldname = shift; | 
| 314 | 0 |  |  |  |  | 0 | my $newname = shift; | 
| 315 |  |  |  |  |  |  | # make sure $oldname is an actual state in this FA | 
| 316 | 0 | 0 |  |  |  | 0 | if (!$self->is_state($newname)) { | 
| 317 | 0 | 0 |  |  |  | 0 | if ($self->is_state($oldname)) { | 
| 318 |  |  |  |  |  |  | # replace name in _STATES array | 
| 319 | 0 |  |  |  |  | 0 | my $i = 0; | 
| 320 | 0 |  |  |  |  | 0 | foreach ($self->get_states()) { | 
| 321 | 0 | 0 |  |  |  | 0 | if ($_ eq $oldname) { | 
| 322 | 0 |  |  |  |  | 0 | $self->{_STATES}[$i] = $newname; | 
| 323 | 0 |  |  |  |  | 0 | last; | 
| 324 |  |  |  |  |  |  | } | 
| 325 | 0 |  |  |  |  | 0 | $i++; | 
| 326 |  |  |  |  |  |  | } | 
| 327 |  |  |  |  |  |  | # replace name if start state | 
| 328 | 0 | 0 |  |  |  | 0 | if ($self->is_start($oldname)) { | 
| 329 | 0 |  |  |  |  | 0 | $self->set_start($newname); | 
| 330 |  |  |  |  |  |  | } | 
| 331 |  |  |  |  |  |  | # replace transitions | 
| 332 | 0 |  |  |  |  | 0 | foreach my $state (keys %{$self->{_TRANSITIONS}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 333 | 0 |  |  |  |  | 0 | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 334 |  |  |  |  |  |  | # rename destination states | 
| 335 | 0 | 0 |  |  |  | 0 | if ($self->{_TRANSITIONS}{$state}{$symbol} eq $oldname) { | 
| 336 | 0 |  |  |  |  | 0 | $self->{_TRANSITIONS}{$state}{$symbol} = $newname; | 
| 337 |  |  |  |  |  |  | } | 
| 338 |  |  |  |  |  |  | # rename start state | 
| 339 | 0 | 0 |  |  |  | 0 | if ($state eq $oldname) { | 
| 340 | 0 |  |  |  |  | 0 | $self->add_transition($newname,$symbol,$self->{_TRANSITIONS}{$state}{$symbol}); | 
| 341 |  |  |  |  |  |  | } | 
| 342 |  |  |  |  |  |  | } | 
| 343 | 0 | 0 |  |  |  | 0 | if ($state eq $oldname) { | 
| 344 |  |  |  |  |  |  | # delete all transitions of old state | 
| 345 | 0 |  |  |  |  | 0 | delete($self->{_TRANSITIONS}{$state}); | 
| 346 |  |  |  |  |  |  | } | 
| 347 |  |  |  |  |  |  | } | 
| 348 |  |  |  |  |  |  | # replace final states | 
| 349 | 0 |  |  |  |  | 0 | $i = 0; | 
| 350 | 0 |  |  |  |  | 0 | foreach ($self->get_final()) { | 
| 351 | 0 | 0 |  |  |  | 0 | if ($_ eq $oldname) { | 
| 352 | 0 |  |  |  |  | 0 | $self->{_FINAL_STATES}[$i] = $newname; | 
| 353 |  |  |  |  |  |  | } | 
| 354 | 0 |  |  |  |  | 0 | $i++; | 
| 355 |  |  |  |  |  |  | } | 
| 356 |  |  |  |  |  |  | # | 
| 357 |  |  |  |  |  |  | } else { | 
| 358 | 0 |  |  |  |  | 0 | print STDERR "Warning: $oldname is not a current state\n"; | 
| 359 |  |  |  |  |  |  | } | 
| 360 |  |  |  |  |  |  | } else { | 
| 361 | 0 |  |  |  |  | 0 | print STDERR "Warning: $newname is a current state\n"; | 
| 362 |  |  |  |  |  |  | } | 
| 363 | 0 |  |  |  |  | 0 | return; | 
| 364 |  |  |  |  |  |  | } | 
| 365 |  |  |  |  |  |  |  | 
| 366 |  |  |  |  |  |  | # Adds symbol | 
| 367 |  |  |  |  |  |  | sub rename_symbol { | 
| 368 | 0 |  |  | 0 | 0 | 0 | my $self = shift; | 
| 369 | 0 |  |  |  |  | 0 | my $oldsymbol = shift; | 
| 370 | 0 |  |  |  |  | 0 | my $newsymbol = shift; | 
| 371 |  |  |  |  |  |  | # make sure $oldsymbol is a symbol and do not bother if | 
| 372 |  |  |  |  |  |  | # $newsymbol ne $oldsymbol | 
| 373 | 0 | 0 | 0 |  |  | 0 | if ($self->is_symbol($oldsymbol) && $newsymbol ne $oldsymbol) { | 
| 374 |  |  |  |  |  |  | # change in $self->{_SYMBOLS} | 
| 375 | 0 |  |  |  |  | 0 | my $i = 0; | 
| 376 | 0 |  |  |  |  | 0 | foreach ($self->get_symbols()) { | 
| 377 | 0 | 0 |  |  |  | 0 | if ($_ eq $oldsymbol) { | 
| 378 | 0 |  |  |  |  | 0 | $self->{_SYMBOLS}[$i] = $newsymbol; | 
| 379 | 0 |  |  |  |  | 0 | last; | 
| 380 |  |  |  |  |  |  | } | 
| 381 | 0 |  |  |  |  | 0 | $i++; | 
| 382 |  |  |  |  |  |  | } | 
| 383 |  |  |  |  |  |  | # change in $self->{_TRANSITIONS} | 
| 384 |  |  |  |  |  |  | # replace transition symbols | 
| 385 | 0 |  |  |  |  | 0 | foreach my $state (keys %{$self->{_TRANSITIONS}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 386 | 0 |  |  |  |  | 0 | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  | 0 |  | 
| 387 | 0 | 0 |  |  |  | 0 | if ($symbol eq $oldsymbol) { | 
| 388 | 0 |  |  |  |  | 0 | $self->add_transition($state,$newsymbol,$self->{_TRANSITIONS}{$state}{$symbol}); | 
| 389 | 0 |  |  |  |  | 0 | delete($self->{_TRANSITIONS}{$state}{$symbol}); | 
| 390 |  |  |  |  |  |  | } | 
| 391 |  |  |  |  |  |  | } | 
| 392 |  |  |  |  |  |  | } | 
| 393 |  |  |  |  |  |  | } else { | 
| 394 | 0 |  |  |  |  | 0 | print STDERR "Warning: '$oldsymbol' is not a current symbol\n"; | 
| 395 |  |  |  |  |  |  | } | 
| 396 | 0 |  |  |  |  | 0 | return; | 
| 397 |  |  |  |  |  |  | } | 
| 398 |  |  |  |  |  |  |  | 
| 399 |  |  |  |  |  |  | sub add_transition { | 
| 400 | 4304 |  |  | 4304 | 0 | 3784 | my $self = shift; | 
| 401 | 4304 |  |  |  |  | 4015 | my $state = shift; | 
| 402 | 4304 |  |  |  |  | 3249 | my $symbol = shift; | 
| 403 | 4304 |  |  |  |  | 13467 | $self->{_TRANSITIONS}{$state}{$symbol} = shift; | 
| 404 | 4304 |  |  |  |  | 5611 | return; | 
| 405 |  |  |  |  |  |  | } | 
| 406 |  |  |  |  |  |  |  | 
| 407 |  |  |  |  |  |  | sub get_transition_on { | 
| 408 | 5242 |  |  | 5242 | 0 | 3771 | my $self = shift; | 
| 409 | 5242 |  |  |  |  | 3418 | my $state = shift; | 
| 410 | 5242 |  |  |  |  | 3332 | my $symbol = shift; | 
| 411 | 5242 |  |  |  |  | 3389 | my $ret = undef; | 
| 412 | 5242 | 100 | 66 |  |  | 7137 | if ($self->is_state($state) && $self->is_symbol($symbol)) { | 
| 413 | 2541 | 50 |  |  |  | 5999 | if (defined($self->{_TRANSITIONS}{$state}{$symbol})) { | 
| 414 | 2541 |  |  |  |  | 4699 | $ret = $self->{_TRANSITIONS}{$state}{$symbol}; | 
| 415 |  |  |  |  |  |  | } | 
| 416 |  |  |  |  |  |  | } | 
| 417 | 5242 |  |  |  |  | 10184 | return $ret; | 
| 418 |  |  |  |  |  |  | } | 
| 419 |  |  |  |  |  |  |  | 
| 420 |  |  |  |  |  |  | sub reverse_dfa { | 
| 421 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 422 | 0 |  |  |  |  |  | print "Convert to NFA, reverse that, then convert back to DFA and minimize...\n"; | 
| 423 |  |  |  |  |  |  | } | 
| 424 |  |  |  |  |  |  |  | 
| 425 |  |  |  |  |  |  | sub to_gdl { | 
| 426 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 427 | 0 |  |  |  |  |  | my $gdl = "graph: {\ndisplay_edge_labels: yes \n"; | 
| 428 | 0 |  |  |  |  |  | foreach my $state ($self->get_states()) { | 
| 429 | 0 |  |  |  |  |  | my $style = "borderstyle: solid "; | 
| 430 | 0 | 0 |  |  |  |  | if ($self->is_final($state)) { | 
| 431 | 0 |  |  |  |  |  | $style = "borderstyle:double bordercolor:red"; | 
| 432 |  |  |  |  |  |  | } | 
| 433 |  |  |  |  |  |  | # define node (state) | 
| 434 | 0 |  |  |  |  |  | $gdl .= "node: { title:\"$state\" shape:circle $style }\n"; | 
| 435 |  |  |  |  |  |  | # define transitions | 
| 436 | 0 |  |  |  |  |  | foreach my $symbol ($self->get_symbols()) { | 
| 437 | 0 | 0 |  |  |  |  | if (defined($self->{_TRANSITIONS}{$state}{$symbol})) { | 
| 438 | 0 |  |  |  |  |  | $gdl .= "edge: { source: \"$state\" target: \"$self->{_TRANSITIONS}{$state}{$symbol}\" label: \"$symbol\" arrowstyle: line }\n"; | 
| 439 |  |  |  |  |  |  | } | 
| 440 |  |  |  |  |  |  | } | 
| 441 |  |  |  |  |  |  | } | 
| 442 | 0 |  |  |  |  |  | $gdl .= "}"; | 
| 443 | 0 |  |  |  |  |  | return $gdl; | 
| 444 |  |  |  |  |  |  | } | 
| 445 |  |  |  |  |  |  |  | 
| 446 |  |  |  |  |  |  | sub info { | 
| 447 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 448 | 0 |  |  |  |  |  | my $out = ''; | 
| 449 | 0 |  |  |  |  |  | $out .= sprintf ("States         : "); | 
| 450 | 0 |  |  |  |  |  | foreach ($self->get_states()) { | 
| 451 | 0 |  |  |  |  |  | $out .= sprintf "'$_' "; | 
| 452 |  |  |  |  |  |  | } | 
| 453 | 0 |  |  |  |  |  | $out .= sprintf ("\nStart State    : '%s'\n",$self->get_start()); | 
| 454 | 0 |  |  |  |  |  | $out .= sprintf ("Final State(s) : "); | 
| 455 | 0 |  |  |  |  |  | foreach ($self->get_final()) { | 
| 456 | 0 |  |  |  |  |  | $out .= sprintf "'$_' "; | 
| 457 |  |  |  |  |  |  | } | 
| 458 | 0 |  |  |  |  |  | $out .= sprintf ("\nAlphabet       : "); | 
| 459 | 0 |  |  |  |  |  | foreach ($self->get_symbols()) { | 
| 460 | 0 |  |  |  |  |  | $out .= sprintf "'$_' "; | 
| 461 |  |  |  |  |  |  | } | 
| 462 | 0 |  |  |  |  |  | $out .= sprintf ("\nTransitions    :\n"); | 
| 463 | 0 |  |  |  |  |  | foreach ($self->get_states()) { | 
| 464 | 0 |  |  |  |  |  | my $state = $_; | 
| 465 | 0 |  |  |  |  |  | foreach (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 466 | 0 |  |  |  |  |  | my $i = $_; | 
| 467 | 0 |  |  |  |  |  | my $is_final = ''; | 
| 468 | 0 | 0 |  |  |  |  | if ($self->is_final($self->{_TRANSITIONS}{$state}{$i})) { | 
| 469 | 0 |  |  |  |  |  | $is_final = '**'; | 
| 470 |  |  |  |  |  |  | } | 
| 471 | 0 |  |  |  |  |  | $out .= sprintf ("\t('%s'),'%s' --> '%s' %s\n",$state,$i,$self->{_TRANSITIONS}{$state}{$i},$is_final); | 
| 472 |  |  |  |  |  |  | } | 
| 473 |  |  |  |  |  |  | } | 
| 474 | 0 |  |  |  |  |  | $out .= sprintf "(** denotes final state)\n"; | 
| 475 | 0 |  |  |  |  |  | return $out; | 
| 476 |  |  |  |  |  |  | } | 
| 477 |  |  |  |  |  |  |  | 
| 478 |  |  |  |  |  |  | sub serialize { | 
| 479 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 480 | 0 |  |  |  |  |  | my $out = ''; | 
| 481 | 0 |  |  |  |  |  | $out .= sprintf("START :: %s\n",$self->get_start()); | 
| 482 | 0 |  |  |  |  |  | $out .= sprintf("FINAL :: "); | 
| 483 | 0 |  |  |  |  |  | $out .= sprintf("%s\n\n",join(',',$self->get_final())); | 
| 484 | 0 |  |  |  |  |  | foreach my $state ($self->get_states()) { | 
| 485 | 0 |  |  |  |  |  | $out .= sprintf("%s:\n",$state); | 
| 486 | 0 |  |  |  |  |  | foreach my $symbol (keys %{$self->{_TRANSITIONS}{$state}}) { | 
|  | 0 |  |  |  |  |  |  | 
| 487 | 0 |  |  |  |  |  | $out .= sprintf("$symbol %s\n",$self->get_transition_on($state,$symbol)); | 
| 488 |  |  |  |  |  |  | } | 
| 489 | 0 |  |  |  |  |  | $out .= sprintf("\n"); | 
| 490 |  |  |  |  |  |  | } | 
| 491 | 0 |  |  |  |  |  | return $out; | 
| 492 |  |  |  |  |  |  | } | 
| 493 |  |  |  |  |  |  |  | 
| 494 |  |  |  |  |  |  | sub is_valid { | 
| 495 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 496 | 0 |  |  |  |  |  | my $string = shift; | 
| 497 | 0 |  |  |  |  |  | my $ok = 0; | 
| 498 | 0 |  |  |  |  |  | my $bad = 0; | 
| 499 | 0 |  |  |  |  |  | my $curr = $self->get_start(); | 
| 500 | 0 |  |  |  |  |  | my @symbols = split(//,$string); | 
| 501 | 0 | 0 |  |  |  |  | if (defined($curr)) { | 
| 502 | 0 |  |  |  |  |  | while (@symbols) { | 
| 503 | 0 |  |  |  |  |  | my $s = shift @symbols; | 
| 504 |  |  |  |  |  |  | # make sure that the symbol is in the alphabet | 
| 505 | 0 | 0 |  |  |  |  | if ($self->is_symbol($s)) { | 
| 506 | 0 |  |  |  |  |  | $curr = $self->get_transition_on($curr,$s); | 
| 507 |  |  |  |  |  |  | # make sure that the transition is defined | 
| 508 | 0 | 0 |  |  |  |  | if (!defined($curr)) { | 
| 509 | 0 |  |  |  |  |  | $bad++; | 
| 510 | 0 |  |  |  |  |  | last; | 
| 511 |  |  |  |  |  |  | } | 
| 512 |  |  |  |  |  |  | } else { | 
| 513 | 0 |  |  |  |  |  | $bad++; | 
| 514 | 0 |  |  |  |  |  | last; | 
| 515 |  |  |  |  |  |  | } | 
| 516 |  |  |  |  |  |  | } | 
| 517 |  |  |  |  |  |  | # make sure that no symbols are left in the string, | 
| 518 |  |  |  |  |  |  | #	that the current state (if defined) is a final state | 
| 519 |  |  |  |  |  |  | #	that something $bad has not happened - namely a bad symbol or undefined transition | 
| 520 | 0 | 0 | 0 |  |  |  | if (!@symbols && $self->is_final($curr) && !$bad) { | 
|  |  |  | 0 |  |  |  |  | 
| 521 | 0 |  |  |  |  |  | $ok++; | 
| 522 |  |  |  |  |  |  | } | 
| 523 |  |  |  |  |  |  | } | 
| 524 | 0 |  |  |  |  |  | return $ok; | 
| 525 |  |  |  |  |  |  | } | 
| 526 |  |  |  |  |  |  |  | 
| 527 |  |  |  |  |  |  | sub get_last_state { | 
| 528 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 529 | 0 |  |  |  |  |  | my $string = shift; | 
| 530 | 0 |  |  |  |  |  | my $ok = 0; | 
| 531 | 0 |  |  |  |  |  | my $bad = 0; | 
| 532 | 0 |  |  |  |  |  | my $curr = $self->get_start(); | 
| 533 | 0 |  |  |  |  |  | my $prev = undef; | 
| 534 | 0 |  |  |  |  |  | my @symbols = split(//,$string); | 
| 535 | 0 | 0 |  |  |  |  | if (defined($curr)) { | 
| 536 | 0 |  |  |  |  |  | while (@symbols) { | 
| 537 | 0 |  |  |  |  |  | my $s = shift @symbols; | 
| 538 |  |  |  |  |  |  | # make sure that the symbol is in the alphabet | 
| 539 | 0 | 0 |  |  |  |  | if ($self->is_symbol($s)) { | 
| 540 | 0 |  |  |  |  |  | $prev = $curr; | 
| 541 | 0 |  |  |  |  |  | $curr = $self->get_transition_on($curr,$s); | 
| 542 |  |  |  |  |  |  | # make sure that the transition is defined | 
| 543 | 0 | 0 |  |  |  |  | if (!defined($curr)) { | 
| 544 | 0 |  |  |  |  |  | last; | 
| 545 |  |  |  |  |  |  | } | 
| 546 |  |  |  |  |  |  | } else { | 
| 547 | 0 |  |  |  |  |  | last; | 
| 548 |  |  |  |  |  |  | } | 
| 549 |  |  |  |  |  |  | } | 
| 550 |  |  |  |  |  |  | } | 
| 551 | 0 |  |  |  |  |  | return $curr; | 
| 552 |  |  |  |  |  |  | } | 
| 553 |  |  |  |  |  |  |  | 
| 554 |  |  |  |  |  |  | sub get_path { | 
| 555 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 556 | 0 |  |  |  |  |  | my $string = shift; | 
| 557 | 0 |  |  |  |  |  | my $ok = 0; | 
| 558 | 0 |  |  |  |  |  | my $bad = 0; | 
| 559 | 0 |  |  |  |  |  | my $curr = $self->get_start(); | 
| 560 | 0 |  |  |  |  |  | my @symbols = split(//,$string); | 
| 561 | 0 |  |  |  |  |  | my @path = (); | 
| 562 | 0 |  |  |  |  |  | push (@path,$curr); | 
| 563 | 0 | 0 |  |  |  |  | if (defined($curr)) { | 
| 564 | 0 |  |  |  |  |  | while (@symbols) { | 
| 565 | 0 |  |  |  |  |  | my $s = shift @symbols; | 
| 566 |  |  |  |  |  |  | # make sure that the symbol is in the alphabet | 
| 567 | 0 | 0 |  |  |  |  | if ($self->is_symbol($s)) { | 
| 568 | 0 |  |  |  |  |  | $curr = $self->get_transition_on($curr,$s); | 
| 569 | 0 |  |  |  |  |  | push (@path,$curr); | 
| 570 |  |  |  |  |  |  | # make sure that the transition is defined | 
| 571 | 0 | 0 |  |  |  |  | if (!defined($curr)) { | 
| 572 | 0 |  |  |  |  |  | last; | 
| 573 |  |  |  |  |  |  | } | 
| 574 |  |  |  |  |  |  | } else { | 
| 575 | 0 |  |  |  |  |  | last; | 
| 576 |  |  |  |  |  |  | } | 
| 577 |  |  |  |  |  |  | } | 
| 578 |  |  |  |  |  |  | } | 
| 579 | 0 |  |  |  |  |  | return @path; | 
| 580 |  |  |  |  |  |  | } | 
| 581 |  |  |  |  |  |  |  | 
| 582 |  |  |  |  |  |  | sub generate_random { | 
| 583 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 584 |  |  |  |  |  |  | } | 
| 585 |  |  |  |  |  |  |  | 
| 586 |  |  |  |  |  |  | sub pump_strings { | 
| 587 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 588 | 0 |  |  |  |  |  | return "Coming soon!"; | 
| 589 |  |  |  |  |  |  | } | 
| 590 |  |  |  |  |  |  |  | 
| 591 |  |  |  |  |  |  | sub init_string_pump { | 
| 592 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 593 | 0 |  |  |  |  |  | return "Coming soon!"; | 
| 594 |  |  |  |  |  |  | } | 
| 595 |  |  |  |  |  |  |  | 
| 596 |  |  |  |  |  |  | sub pump_next { | 
| 597 | 0 |  |  | 0 | 0 |  | my $self = shift; | 
| 598 | 0 |  |  |  |  |  | return "Coming soon!"; | 
| 599 |  |  |  |  |  |  | } | 
| 600 |  |  |  |  |  |  |  | 
| 601 |  |  |  |  |  |  | 1; | 
| 602 |  |  |  |  |  |  |  | 
| 603 |  |  |  |  |  |  | __END__ |