Update Changes.
[p5sagit/p5-mst-13.2.git] / pod / perldebtut.pod
CommitLineData
10862624 1=head1 NAME
2
3perldebtut - Perl debugging tutorial
4
5=head1 DESCRIPTION
6
7A (very) lightweight introduction in the use of the perl debugger, and a
8pointer to existing, deeper sources of information on the subject of debugging
7218dffe 9perl programs.
10862624 10
11There's an extraordinary number of people out there who don't appear to know
12anything about using the perl debugger, though they use the language every
13day.
14This is for them.
15
16
17=head1 use strict
18
7218dffe 19First of all, there's a few things you can do to make your life a lot more
20straightforward when it comes to debugging perl programs, without using the
21debugger at all. To demonstrate, here's a simple script with a problem:
10862624 22
23 #!/usr/bin/perl
cea6626f 24
10862624 25 $var1 = 'Hello World'; # always wanted to do that :-)
26 $var2 = "$varl\n";
cea6626f 27
10862624 28 print $var2;
29 exit;
30
31While this compiles and runs happily, it probably won't do what's expected,
32namely it doesn't print "Hello World\n" at all; It will on the other hand do
33exactly what it was told to do, computers being a bit that way inclined. That
34is, it will print out a newline character, and you'll get what looks like a
35blank line. It looks like there's 2 variables when (because of the typo)
36there's really 3:
37
38 $var1 = 'Hello World'
39 $varl = undef
40 $var2 = "\n"
41
42To catch this kind of problem, we can force each variable to be declared
43before use by pulling in the strict module, by putting 'use strict;' after the
44first line of the script.
45
46Now when you run it, perl complains about the 3 undeclared variables and we
47get four error messages because one variable is referenced twice:
cea6626f 48
10862624 49 Global symbol "$var1" requires explicit package name at ./t1 line 4.
50 Global symbol "$var2" requires explicit package name at ./t1 line 5.
51 Global symbol "$varl" requires explicit package name at ./t1 line 5.
52 Global symbol "$var2" requires explicit package name at ./t1 line 7.
7218dffe 53 Execution of ./hello aborted due to compilation errors.
10862624 54
55Luvverly! and to fix this we declare all variables explicitly and now our
56script looks like this:
57
58 #!/usr/bin/perl
59 use strict;
cea6626f 60
10862624 61 my $var1 = 'Hello World';
62 my $varl = '';
63 my $var2 = "$varl\n";
cea6626f 64
10862624 65 print $var2;
66 exit;
67
68We then do (always a good idea) a syntax check before we try to run it again:
69
70 > perl -c hello
71 hello syntax OK
72
73And now when we run it, we get "\n" still, but at least we know why. Just
74getting this script to compile has exposed the '$varl' (with the letter 'l)
75variable, and simply changing $varl to $var1 solves the problem.
76
77
492652be 78=head1 Looking at data and -w and v
10862624 79
80Ok, but how about when you want to really see your data, what's in that
81dynamic variable, just before using it?
82
83 #!/usr/bin/perl
84 use strict;
85
86 my $key = 'welcome';
87 my %data = (
88 'this' => qw(that),
89 'tom' => qw(and jerry),
90 'welcome' => q(Hello World),
91 'zip' => q(welcome),
92 );
93 my @data = keys %data;
94
95 print "$data{$key}\n";
96 exit;
97
98Looks OK, after it's been through the syntax check (perl -c scriptname), we
99run it and all we get is a blank line again! Hmmmm.
cea6626f 100
10862624 101One common debugging approach here, would be to liberally sprinkle a few print
102statements, to add a check just before we print out our data, and another just
103after:
104
105 print "All OK\n" if grep($key, keys %data);
106 print "$data{$key}\n";
107 print "done: '$data{$key}'\n";
108
109And try again:
cea6626f 110
10862624 111 > perl data
112 All OK
cea6626f 113
10862624 114 done: ''
115
116After much staring at the same piece of code and not seeing the wood for the
117trees for some time, we get a cup of coffee and try another approach. That
7218dffe 118is, we bring in the cavalry by giving perl the 'B<-d>' switch on the command
10862624 119line:
120
121 > perl -d data
122 Default die handler restored.
123
124 Loading DB routines from perl5db.pl version 1.07
125 Editor support available.
126
127 Enter h or `h h' for help, or `man perldebug' for more help.
128
129 main::(./data:4): my $key = 'welcome';
130
131Now, what we've done here is to launch the built-in perl debugger on our
132script. It's stopped at the first line of executable code and is waiting for
133input.
134
135Before we go any further, you'll want to know how to quit the debugger: use
7218dffe 136just the letter 'B<q>', not the words 'quit' or 'exit':
10862624 137
138 DB<1> q
139 >
cea6626f 140
10862624 141That's it, you're back on home turf again.
142
7218dffe 143
144=head1 help
145
10862624 146Fire the debugger up again on your script and we'll look at the help menu.
492652be 147There's a couple of ways of calling help: a simple 'B<h>' will get the summary
148help list, 'B<|h>' (pipe-h) will pipe the help through your pager (which is
149(probably 'more' or 'less'), and finally, 'B<h h>' (h-space-h) will give you
150the entire help screen. Here is the summary page:
151
152DB<1>h
153List/search source lines: Control script execution:
154 l [ln|sub] List source code T Stack trace
155 - or . List previous/current line s [expr] Single step [in expr]
156 v [line] View around line n [expr] Next, steps over subs
157 f filename View source in file <CR/Enter> Repeat last n or s
158 /pattern/ ?patt? Search forw/backw r Return from subroutine
159 M Show module versions c [ln|sub] Continue until position
160Debugger controls: L List break/watch/actions
161 o [...] Set debugger options t [expr] Toggle trace [trace expr]
162 <[<]|{[{]|>[>] [cmd] Do pre/post-prompt b [ln|event|sub] [cnd] Set breakpoint
163 ! [N|pat] Redo a previous command B ln|* Delete a/all breakpoints
164 H [-num] Display last num commands a [ln] cmd Do cmd before line
165 = [a val] Define/list an alias A ln|* Delete a/all actions
166 h [db_cmd] Get help on command w expr Add a watch expression
167 h h Complete help page W expr|* Delete a/all watch expressions
168 |[|]db_cmd Send output to pager ![!] syscmd Run cmd in a subprocess
169 q or ^D Quit R Attempt a restart
170Data Examination: expr Execute perl code, also see: s,n,t expr
171 x|m expr Evals expr in list context, dumps the result or lists methods.
172 p expr Print expression (uses script's current package).
173 S [[!]pat] List subroutine names [not] matching pattern
174 V [Pk [Vars]] List Variables in Package. Vars can be ~pattern or !pattern.
175 X [Vars] Same as "V current_package [Vars]".
176For more help, type h cmd_letter, or run man perldebug for all docs.
cea6626f 177
10862624 178More confusing options than you can shake a big stick at! It's not as bad as
179it looks and it's very useful to know more about all of it, and fun too!
180
7218dffe 181There's a couple of useful ones to know about straight away. You wouldn't
492652be 182think we're using any libraries at all at the moment, but 'B<M>' will show
183which modules are currently loaded, and their version number, while 'B<m>'
184will show the methods, and 'B<S>' shows all subroutines (by pattern) as
185shown below. 'B<V>' and 'B<X>' show variables in the program by package
186scope and can be constrained by pattern.
10862624 187
188 DB<2>S str
189 dumpvar::stringify
190 strict::bits
191 strict::import
192 strict::unimport
7218dffe 193
194Using 'X' and cousins requires you not to use the type identifiers ($@%), just
195the 'name':
196
197 DM<3>X ~err
198 FileHandle(stderr) => fileno(2)
cea6626f 199
7218dffe 200Remember we're in our tiny program with a problem, we should have a look at
492652be 201where we are, and what our data looks like. First of all let's view some code
202at our present position (the first line of code in this case), via 'B<v>':
10862624 203
492652be 204 DB<4> v
10862624 205 1 #!/usr/bin/perl
206 2: use strict;
207 3
208 4==> my $key = 'welcome';
209 5: my %data = (
210 6 'this' => qw(that),
211 7 'tom' => qw(and jerry),
212 8 'welcome' => q(Hello World),
213 9 'zip' => q(welcome),
214 10 );
215
216At line number 4 is a helpful pointer, that tells you where you are now. To
492652be 217see more code, type 'v' again:
cea6626f 218
492652be 219 DB<4> v
10862624 220 8 'welcome' => q(Hello World),
221 9 'zip' => q(welcome),
222 10 );
223 11: my @data = keys %data;
224 12: print "All OK\n" if grep($key, keys %data);
225 13: print "$data{$key}\n";
226 14: print "done: '$data{$key}'\n";
227 15: exit;
228
7218dffe 229And if you wanted to list line 5 again, type 'l 5', (note the space):
10862624 230
231 DB<4> l 5
232 5: my %data = (
cea6626f 233
10862624 234In this case, there's not much to see, but of course normally there's pages of
7218dffe 235stuff to wade through, and 'l' can be very useful. To reset your view to the
236line we're about to execute, type a lone period '.':
10862624 237
7218dffe 238 DB<5> .
10862624 239 main::(./data_a:4): my $key = 'welcome';
cea6626f 240
10862624 241The line shown is the one that is about to be executed B<next>, it hasn't
7218dffe 242happened yet. So while we can print a variable with the letter 'B<p>', at
243this point all we'd get is an empty (undefined) value back. What we need to
244do is to step through the next executable statement with an 'B<s>':
cea6626f 245
10862624 246 DB<6> s
247 main::(./data_a:5): my %data = (
248 main::(./data_a:6): 'this' => qw(that),
249 main::(./data_a:7): 'tom' => qw(and jerry),
250 main::(./data_a:8): 'welcome' => q(Hello World),
251 main::(./data_a:9): 'zip' => q(welcome),
252 main::(./data_a:10): );
253
254Now we can have a look at that first ($key) variable:
255
256 DB<7> p $key
257 welcome
258
259line 13 is where the action is, so let's continue down to there via the letter
7218dffe 260'B<c>', which by the way, inserts a 'one-time-only' breakpoint at the given
261line or sub routine:
10862624 262
263 DB<8> c 13
264 All OK
265 main::(./data_a:13): print "$data{$key}\n";
cea6626f 266
10862624 267We've gone past our check (where 'All OK' was printed) and have stopped just
268before the meat of our task. We could try to print out a couple of variables
269to see what is happening:
270
271 DB<9> p $data{$key}
cea6626f 272
7218dffe 273Not much in there, lets have a look at our hash:
cea6626f 274
10862624 275 DB<10> p %data
276 Hello Worldziptomandwelcomejerrywelcomethisthat
277
278 DB<11> p keys %data
279 Hello Worldtomwelcomejerrythis
cea6626f 280
7218dffe 281Well, this isn't very easy to read, and using the helpful manual (B<h h>), the
282'B<x>' command looks promising:
10862624 283
284 DB<12> x %data
285 0 'Hello World'
286 1 'zip'
287 2 'tom'
288 3 'and'
289 4 'welcome'
290 5 undef
291 6 'jerry'
292 7 'welcome'
293 8 'this'
294 9 'that'
295
b1866b2d 296That's not much help, a couple of welcomes in there, but no indication of
7218dffe 297which are keys, and which are values, it's just a listed array dump and, in
10862624 298this case, not particularly helpful. The trick here, is to use a B<reference>
299to the data structure:
300
301 DB<13> x \%data
302 0 HASH(0x8194bc4)
303 'Hello World' => 'zip'
304 'jerry' => 'welcome'
305 'this' => 'that'
306 'tom' => 'and'
307 'welcome' => undef
308
309The reference is truly dumped and we can finally see what we're dealing with.
310Our quoting was perfectly valid but wrong for our purposes, with 'and jerry'
311being treated as 2 separate words rather than a phrase, thus throwing the
312evenly paired hash structure out of alignment.
313
7218dffe 314The 'B<-w>' switch would have told us about this, had we used it at the start,
10862624 315and saved us a lot of trouble:
316
317 > perl -w data
318 Odd number of elements in hash assignment at ./data line 5.
319
320We fix our quoting: 'tom' => q(and jerry), and run it again, this time we get
321our expected output:
322
323 > perl -w data
324 Hello World
325
326
7218dffe 327While we're here, take a closer look at the 'B<x>' command, it's really useful
10862624 328and will merrily dump out nested references, complete objects, partial objects
a31a806a 329- just about whatever you throw at it:
10862624 330
da75cd15 331Let's make a quick object and x-plode it, first we'll start the debugger:
10862624 332it wants some form of input from STDIN, so we give it something non-commital,
333a zero:
334
335 > perl -de 0
336 Default die handler restored.
337
338 Loading DB routines from perl5db.pl version 1.07
339 Editor support available.
340
341 Enter h or `h h' for help, or `man perldebug' for more help.
342
343 main::(-e:1): 0
344
345Now build an on-the-fly object over a couple of lines (note the backslash):
346
347 DB<1> $obj = bless({'unique_id'=>'123', 'attr'=> \
348 cont: {'col' => 'black', 'things' => [qw(this that etc)]}}, 'MY_class')
349
350And let's have a look at it:
cea6626f 351
10862624 352 DB<2> x $obj
353 0 MY_class=HASH(0x828ad98)
354 'attr' => HASH(0x828ad68)
355 'col' => 'black'
356 'things' => ARRAY(0x828abb8)
357 0 'this'
358 1 'that'
359 2 'etc'
360 'unique_id' => 123
361 DB<3>
362
363Useful, huh? You can eval nearly anything in there, and experiment with bits
364of code or regexes until the cows come home:
365
366 DB<3> @data = qw(this that the other atheism leather theory scythe)
cea6626f 367
10862624 368 DB<4> p 'saw -> '.($cnt += map { print "\t:\t$_\n" } grep(/the/, sort @data))
369 atheism
370 leather
371 other
372 scythe
373 the
374 theory
375 saw -> 6
376
7218dffe 377If you want to see the command History, type an 'B<H>':
10862624 378
379 DB<5> H
380 4: p 'saw -> '.($cnt += map { print "\t:\t$_\n" } grep(/the/, sort @data))
381 3: @data = qw(this that the other atheism leather theory scythe)
382 2: x $obj
383 1: $obj = bless({'unique_id'=>'123', 'attr'=>
384 {'col' => 'black', 'things' => [qw(this that etc)]}}, 'MY_class')
385 DB<5>
cea6626f 386
7218dffe 387And if you want to repeat any previous command, use the exclamation: 'B<!>':
10862624 388
389 DB<5> !4
390 p 'saw -> '.($cnt += map { print "$_\n" } grep(/the/, sort @data))
391 atheism
392 leather
393 other
394 scythe
395 the
396 theory
397 saw -> 12
398
7218dffe 399For more on references see L<perlref> and L<perlreftut>
400
10862624 401
402=head1 Stepping through code
403
d1f7ad93 404Here's a simple program which converts between Celsius and Fahrenheit, it too
10862624 405has a problem:
406
407 #!/usr/bin/perl -w
408 use strict;
409
410 my $arg = $ARGV[0] || '-c20';
411
412 if ($arg =~ /^\-(c|f)((\-|\+)*\d+(\.\d+)*)$/) {
413 my ($deg, $num) = ($1, $2);
414 my ($in, $out) = ($num, $num);
415 if ($deg eq 'c') {
416 $deg = 'f';
417 $out = &c2f($num);
418 } else {
419 $deg = 'c';
420 $out = &f2c($num);
421 }
422 $out = sprintf('%0.2f', $out);
423 $out =~ s/^((\-|\+)*\d+)\.0+$/$1/;
424 print "$out $deg\n";
425 } else {
426 print "Usage: $0 -[c|f] num\n";
427 }
428 exit;
429
430 sub f2c {
431 my $f = shift;
432 my $c = 5 * $f - 32 / 9;
433 return $c;
434 }
435
436 sub c2f {
437 my $c = shift;
438 my $f = 9 * $c / 5 + 32;
439 return $f;
440 }
441
442
d1f7ad93 443For some reason, the Fahrenheit to Celsius conversion fails to return the
10862624 444expected output. This is what it does:
445
446 > temp -c0.72
447 33.30 f
cea6626f 448
10862624 449 > temp -f33.3
450 162.94 c
cea6626f 451
10862624 452Not very consistent! We'll set a breakpoint in the code manually and run it
453under the debugger to see what's going on. A breakpoint is a flag, to which
a31a806a 454the debugger will run without interruption, when it reaches the breakpoint, it
10862624 455will stop execution and offer a prompt for further interaction. In normal
456use, these debugger commands are completely ignored, and they are safe - if a
457little messy, to leave in production code.
cea6626f 458
10862624 459 my ($in, $out) = ($num, $num);
460 $DB::single=2; # insert at line 9!
461 if ($deg eq 'c')
462 ...
cea6626f 463
10862624 464 > perl -d temp -f33.3
465 Default die handler restored.
466
467 Loading DB routines from perl5db.pl version 1.07
468 Editor support available.
469
470 Enter h or `h h' for help, or `man perldebug' for more help.
471
472 main::(temp:4): my $arg = $ARGV[0] || '-c100';
473
7218dffe 474We'll simply continue down to our pre-set breakpoint with a 'B<c>':
10862624 475
476 DB<1> c
477 main::(temp:10): if ($deg eq 'c') {
478
492652be 479Followed by a view command to see where we are:
cea6626f 480
492652be 481 DB<1> v
10862624 482 7: my ($deg, $num) = ($1, $2);
483 8: my ($in, $out) = ($num, $num);
484 9: $DB::single=2;
485 10==> if ($deg eq 'c') {
486 11: $deg = 'f';
487 12: $out = &c2f($num);
488 13 } else {
489 14: $deg = 'c';
490 15: $out = &f2c($num);
491 16 }
492
493And a print to show what values we're currently using:
494
7218dffe 495 DB<1> p $deg, $num
10862624 496 f33.3
13a2d996 497
10862624 498We can put another break point on any line beginning with a colon, we'll use
499line 17 as that's just as we come out of the subroutine, and we'd like to
500pause there later on:
cea6626f 501
7218dffe 502 DB<2> b 17
cea6626f 503
10862624 504There's no feedback from this, but you can see what breakpoints are set by
505using the list 'L' command:
506
7218dffe 507 DB<3> L
10862624 508 temp:
509 17: print "$out $deg\n";
510 break if (1)
511
512Note that to delete a breakpoint you use 'd' or 'D'.
513
514Now we'll continue down into our subroutine, this time rather than by line
492652be 515number, we'll use the subroutine name, followed by the now familiar 'v':
10862624 516
7218dffe 517 DB<3> c f2c
10862624 518 main::f2c(temp:30): my $f = shift;
519
492652be 520 DB<4> v
7218dffe 521 24: exit;
522 25
523 26 sub f2c {
524 27==> my $f = shift;
525 28: my $c = 5 * $f - 32 / 9;
526 29: return $c;
527 30 }
528 31
529 32 sub c2f {
530 33: my $c = shift;
531
532
533Note that if there was a subroutine call between us and line 29, and we wanted
534to B<single-step> through it, we could use the 'B<s>' command, and to step
535over it we would use 'B<n>' which would execute the sub, but not descend into
536it for inspection. In this case though, we simply continue down to line 29:
537
538 DB<4> c 29
539 main::f2c(temp:29): return $c;
13a2d996 540
10862624 541And have a look at the return value:
542
7218dffe 543 DB<5> p $c
10862624 544 162.944444444444
545
546This is not the right answer at all, but the sum looks correct. I wonder if
547it's anything to do with operator precedence? We'll try a couple of other
548possibilities with our sum:
549
7218dffe 550 DB<6> p (5 * $f - 32 / 9)
10862624 551 162.944444444444
cea6626f 552
7218dffe 553 DB<7> p 5 * $f - (32 / 9)
10862624 554 162.944444444444
cea6626f 555
7218dffe 556 DB<8> p (5 * $f) - 32 / 9
10862624 557 162.944444444444
cea6626f 558
7218dffe 559 DB<9> p 5 * ($f - 32) / 9
10862624 560 0.722222222222221
561
562:-) that's more like it! Ok, now we can set our return variable and we'll
563return out of the sub with an 'r':
564
7218dffe 565 DB<10> $c = 5 * ($f - 32) / 9
cea6626f 566
7218dffe 567 DB<11> r
10862624 568 scalar context return from main::f2c: 0.722222222222221
cea6626f 569
10862624 570Looks good, let's just continue off the end of the script:
571
7218dffe 572 DB<12> c
10862624 573 0.72 c
574 Debugged program terminated. Use q to quit or R to restart,
575 use O inhibit_exit to avoid stopping after program termination,
576 h q, h R or h O to get additional info.
577
578A quick fix to the offending line (insert the missing parentheses) in the
579actual program and we're finished.
580
581
582=head1 Placeholder for a, w, t, T
583
7218dffe 584Actions, watch variables, stack traces etc.: on the TODO list.
10862624 585
586 a
cea6626f 587
492652be 588 w
cea6626f 589
10862624 590 t
cea6626f 591
10862624 592 T
593
594
7218dffe 595=head1 REGULAR EXPRESSIONS
10862624 596
597Ever wanted to know what a regex looked like? You'll need perl compiled with
598the DEBUGGING flag for this one:
cea6626f 599
10862624 600 > perl -Dr -e '/^pe(a)*rl$/i'
601 Compiling REx `^pe(a)*rl$'
602 size 17 first at 2
603 rarest char
604 at 0
605 1: BOL(2)
606 2: EXACTF <pe>(4)
607 4: CURLYN[1] {0,32767}(14)
608 6: NOTHING(8)
609 8: EXACTF <a>(0)
610 12: WHILEM(0)
611 13: NOTHING(14)
612 14: EXACTF <rl>(16)
613 16: EOL(17)
614 17: END(0)
615 floating `'$ at 4..2147483647 (checking floating) stclass `EXACTF <pe>'
616anchored(BOL) minlen 4
617 Omitting $` $& $' support.
13a2d996 618
10862624 619 EXECUTING...
620
621 Freeing REx: `^pe(a)*rl$'
622
623Did you really want to know? :-)
7218dffe 624For more gory details on getting regular expressions to work, have a look at
625L<perlre>, L<perlretut>, and to decode the mysterious labels (BOL and CURLYN,
626etc. above), see L<perldebguts>.
10862624 627
628
7218dffe 629=head1 OUTPUT TIPS
10862624 630
631To get all the output from your error log, and not miss any messages via
632helpful operating system buffering, insert a line like this, at the start of
633your script:
634
635 $|=1;
636
637To watch the tail of a dynamically growing logfile, (from the command line):
638
639 tail -f $error_log
640
641Wrapping all die calls in a handler routine can be useful to see how, and from
642where, they're being called, L<perlvar> has more information:
643
7218dffe 644 BEGIN { $SIG{__DIE__} = sub { require Carp; Carp::confess(@_) } }
10862624 645
646Various useful techniques for the redirection of STDOUT and STDERR filehandles
7218dffe 647are explained in L<perlopentut> and L<perlfaq8>.
10862624 648
649
650=head1 CGI
651
7218dffe 652Just a quick hint here for all those CGI programmers who can't figure out how
653on earth to get past that 'waiting for input' prompt, when running their CGI
654script from the command-line, try something like this:
10862624 655
656 > perl -d my_cgi.pl -nodebug
657
13a2d996 658Of course L<CGI> and L<perlfaq9> will tell you more.
10862624 659
660
661=head1 GUIs
662
663The command line interface is tightly integrated with an B<emacs> extension
664and there's a B<vi> interface too.
665
666You don't have to do this all on the command line, though, there are a few GUI
667options out there. The nice thing about these is you can wave a mouse over a
3958b146 668variable and a dump of its data will appear in an appropriate window, or in a
10862624 669popup balloon, no more tiresome typing of 'x $varname' :-)
670
671In particular have a hunt around for the following:
672
673B<ptkdb> perlTK based wrapper for the built-in debugger
674
675B<ddd> data display debugger
cea6626f 676
10862624 677B<PerlDevKit> and B<PerlBuilder> are NT specific
678
679NB. (more info on these and others would be appreciated).
680
681
7218dffe 682=head1 SUMMARY
10862624 683
684We've seen how to encourage good coding practices with B<use strict> and
685B<-w>. We can run the perl debugger B<perl -d scriptname> to inspect your
686data from within the perl debugger with the B<p> and B<x> commands. You can
687walk through your code, set breakpoints with B<b> and step through that code
688with B<s> or B<n>, continue with B<c> and return from a sub with B<r>. Fairly
689intuitive stuff when you get down to it.
690
691There is of course lots more to find out about, this has just scratched the
692surface. The best way to learn more is to use perldoc to find out more about
693the language, to read the on-line help (L<perldebug> is probably the next
694place to go), and of course, experiment.
695
696
697=head1 SEE ALSO
698
699L<perldebug>,
700L<perldebguts>,
701L<perldiag>,
702L<dprofpp>,
703L<perlrun>
704
705
706=head1 AUTHOR
707
708Richard Foley <richard@rfi.net> Copyright (c) 2000
709
710
711=head1 CONTRIBUTORS
712
713Various people have made helpful suggestions and contributions, in particular:
714
715Ronald J Kimball <rjk@linguist.dartmouth.edu>
716
7218dffe 717Hugo van der Sanden <hv@crypt0.demon.co.uk>
718
10c10266 719Peter Scott <Peter@PSDT.com>
10862624 720