locales
[kivitendo-erp.git] / SL / DBUtils.pm
1 package SL::DBUtils;
2
3 use SL::Util qw(trim);
4
5 require Exporter;
6 our @ISA = qw(Exporter);
7
8 our @EXPORT = qw(conv_i conv_date conv_dateq do_query selectrow_query do_statement
9              dump_query quote_db_date like
10              selectfirst_hashref_query selectfirst_array_query
11              selectall_hashref_query selectall_array_query selectcol_array_query
12              selectall_as_map
13              selectall_ids
14              prepare_execute_query prepare_query
15              create_sort_spec does_table_exist
16              add_token check_trgm);
17
18 use strict;
19
20 sub conv_i {
21   my ($value, $default) = @_;
22   return (defined($value) && "$value" ne "") ? $value * 1 : $default;
23 }
24
25 # boolean escape
26 sub conv_b {
27   my ($value, $default) = @_;
28   return !defined $value && defined $default ? $default
29        :          $value                     ? 't'
30        :                                       'f';
31 }
32
33 sub conv_date {
34   my ($value) = @_;
35   return undef if !defined $value;
36   $value = trim($value);
37   return $value eq "" ? undef : $value;
38 }
39
40 sub conv_dateq {
41   my ($value) = @_;
42   if (defined($value) && "$value" ne "") {
43     $value =~ s/\'/\'\'/g;
44     return "'$value'";
45   }
46   return "NULL";
47 }
48
49 sub do_query {
50   $main::lxdebug->enter_sub(2);
51
52   my ($form, $dbh, $query) = splice(@_, 0, 3);
53
54   dump_query(LXDebug->QUERY(), '', $query, @_);
55
56   my $result;
57   if (0 == scalar(@_)) {
58     $result = $dbh->do($query)            || $form->dberror($query);
59   } else {
60     $result = $dbh->do($query, undef, @_) || $form->dberror($query . " (" . join(", ", @_) . ")");
61   }
62
63   $main::lxdebug->leave_sub(2);
64
65   return $result;
66 }
67
68 sub selectrow_query { &selectfirst_array_query }
69
70 sub do_statement {
71   $main::lxdebug->enter_sub(2);
72
73   my ($form, $sth, $query) = splice(@_, 0, 3);
74
75   dump_query(LXDebug->QUERY(), '', $query, @_);
76
77   my $result;
78   if (0 == scalar(@_)) {
79     $result = $sth->execute()   || $form->dberror($query);
80   } else {
81     $result = $sth->execute(@_) || $form->dberror($query . " (" . join(", ", @_) . ")");
82   }
83
84   $main::lxdebug->leave_sub(2);
85
86   return $result;
87 }
88
89 sub dump_query {
90   my ($level, $msg, $query) = splice(@_, 0, 3);
91
92   my $self_filename = 'SL/DBUtils.pm';
93   my $filename      = $self_filename;
94   my ($caller_level, $line, $subroutine);
95   while ($filename =~ m{$self_filename$}) {
96     (undef, $filename, $line, $subroutine) = caller $caller_level++;
97   }
98
99   while ($query =~ /\?/) {
100     my $value = shift || '';
101     $value =~ s/\'/\\\'/g;
102     $value = "'${value}'";
103     $query =~ s/\?/$value/;
104   }
105
106   $query =~ s/[\n\s]+/ /g;
107
108   $msg .= " " if ($msg);
109
110   my $info = "$subroutine called from $filename:$line\n";
111
112   $main::lxdebug->message($level, $info . $msg . $query);
113 }
114
115 sub quote_db_date {
116   my ($str) = @_;
117
118   return "NULL" unless defined $str;
119   return "current_date" if $str =~ /current_date/;
120
121   $str =~ s/\'/\'\'/g;
122   return "'$str'";
123 }
124
125 sub prepare_query {
126   $main::lxdebug->enter_sub(2);
127
128   my ($form, $dbh, $query) = splice(@_, 0, 3);
129
130   dump_query(LXDebug->QUERY(), '', $query, @_);
131
132   my $sth = $dbh->prepare($query) || $form->dberror($query);
133
134   $main::lxdebug->leave_sub(2);
135
136   return $sth;
137 }
138
139 sub prepare_execute_query {
140   $main::lxdebug->enter_sub(2);
141
142   my ($form, $dbh, $query) = splice(@_, 0, 3);
143
144   dump_query(LXDebug->QUERY(), '', $query, @_);
145
146   my $sth = $dbh->prepare($query) || $form->dberror($query);
147   if (scalar(@_) != 0) {
148     $sth->execute(@_) || $form->dberror($query . " (" . join(", ", @_) . ")");
149   } else {
150     $sth->execute() || $form->dberror($query);
151   }
152
153   $main::lxdebug->leave_sub(2);
154
155   return $sth;
156 }
157
158 sub selectall_hashref_query {
159   $main::lxdebug->enter_sub(2);
160
161   my ($form, $dbh, $query) = splice(@_, 0, 3);
162
163   dump_query(LXDebug->QUERY(), '', $query, @_);
164
165   # this works back 'til at least DBI 1.46 on perl 5.8.4 on Debian Sarge (2004)
166   my $result = $dbh->selectall_arrayref($query, { Slice => {} }, @_)
167     or $form->dberror($query . (@_ ? " (" . join(", ", @_) . ")" : ''));
168
169   $main::lxdebug->leave_sub(2);
170
171   return wantarray ? @{ $result } : $result;
172 }
173
174 sub selectall_array_query { goto &selectcol_array_query; }
175
176 sub selectcol_array_query {
177   $main::lxdebug->enter_sub(2);
178
179   my ($form, $dbh, $query) = splice(@_, 0, 3);
180
181   my $sth = prepare_execute_query($form, $dbh, $query, @_);
182   my @result = @{ $dbh->selectcol_arrayref($sth) };
183   $sth->finish();
184
185   $main::lxdebug->leave_sub(2);
186
187   return @result;
188 }
189
190 sub selectfirst_hashref_query {
191   $main::lxdebug->enter_sub(2);
192
193   my ($form, $dbh, $query) = splice(@_, 0, 3);
194
195   my $sth = prepare_execute_query($form, $dbh, $query, @_);
196   my $ref = $sth->fetchrow_hashref();
197   $sth->finish();
198
199   $main::lxdebug->leave_sub(2);
200
201   return $ref;
202 }
203
204 sub selectfirst_array_query {
205   $main::lxdebug->enter_sub(2);
206
207   my ($form, $dbh, $query) = splice(@_, 0, 3);
208
209   my $sth = prepare_execute_query($form, $dbh, $query, @_);
210   my @ret = $sth->fetchrow_array();
211   $sth->finish();
212
213   $main::lxdebug->leave_sub(2);
214
215   return @ret;
216 }
217
218 sub selectall_as_map {
219   $main::lxdebug->enter_sub(2);
220
221   my ($form, $dbh, $query, $key_col, $value_col) = splice(@_, 0, 5);
222
223   my $sth = prepare_execute_query($form, $dbh, $query, @_);
224
225   my %hash;
226   if ('' eq ref $value_col) {
227     while (my $ref = $sth->fetchrow_hashref()) {
228       $hash{$ref->{$key_col} // ''} = $ref->{$value_col};
229     }
230   } else {
231     while (my $ref = $sth->fetchrow_hashref()) {
232       $hash{$ref->{$key_col} // ''} = { map { $_ => $ref->{$_} } @{ $value_col } };
233     }
234   }
235
236   $sth->finish();
237
238   $main::lxdebug->leave_sub(2);
239
240   return %hash;
241 }
242
243 sub selectall_ids {
244   $main::lxdebug->enter_sub(2);
245
246   my ($form, $dbh, $query, $key_col) = splice(@_, 0, 4);
247
248   my $sth = prepare_execute_query($form, $dbh, $query, @_);
249
250   my @ids;
251   while (my $ref = $sth->fetchrow_arrayref()) {
252     push @ids, $ref->[$key_col];
253   }
254
255   $sth->finish;
256
257   $main::lxdebug->leave_sub(2);
258
259   return @ids;
260 }
261
262 sub create_sort_spec {
263   $main::lxdebug->enter_sub(2);
264
265   my %params = @_;
266
267   # Safety check:
268   $params{defs}    || die;
269   $params{default} || die;
270
271   # The definition of valid columns to sort by.
272   my $defs        = $params{defs};
273
274   # The column name to sort by. Use the default column name if none was given.
275   my %result      = ( 'column' => $params{column} || $params{default} );
276
277   # Overwrite the column name with the default column name if the other one is not valid.
278   $result{column} = $params{default} unless ($defs->{ $result{column} });
279
280   # The sort direction. true means 'sort ascending', false means 'sort descending'.
281   $result{dir}    = defined $params{dir}         ? $params{dir}
282                   : defined $params{default_dir} ? $params{default_dir}
283                   :                                1;
284   $result{dir}    = $result{dir} ?     1 :      0;
285   my $asc_desc    = $result{dir} ? 'ASC' : 'DESC';
286
287   # Create the SQL code.
288   my $cols        = $defs->{ $result{column} };
289   $result{sql}    = join ', ', map { "${_} ${asc_desc}" } @{ ref $cols eq 'ARRAY' ? $cols : [ $cols ] };
290
291   $main::lxdebug->leave_sub(2);
292
293   return %result;
294 }
295
296 sub does_table_exist {
297   $main::lxdebug->enter_sub(2);
298
299   my $dbh    = shift;
300   my $table  = shift;
301
302   my $result = 0;
303
304   if ($dbh) {
305     my $sth = $dbh->table_info('', '', $table, 'TABLE');
306     if ($sth) {
307       $result = $sth->fetchrow_hashref();
308       $sth->finish();
309     }
310   }
311
312   $main::lxdebug->leave_sub(2);
313
314   return $result;
315 }
316
317 # add token to values.
318 # usage:
319 #  add_token(
320 #    \@where_tokens,
321 #    \@where_values,
322 #    col => 'id',
323 #    val => [ 23, 34, 17 ]
324 #    esc => \&conf_i
325 #  )
326 #  will append to the given arrays:
327 #   -> 'id IN (?, ?, ?)'
328 #   -> (conv_i(23), conv_i(34), conv_i(17))
329 #
330 #  features:
331 #   - don't care if one or multiple values are given. singlewill result in 'col = ?'
332 #   - pass escape routines
333 #   - expand for future method
334 #   - no need to type "push @where_tokens, 'id = ?'" over and over again
335 sub add_token {
336   my $tokens = shift() || [];
337   my $values = shift() || [];
338   my %params = @_;
339   my $col    = $params{col};
340   my $val    = $params{val};
341   my $escape = $params{esc} || sub { $_ };
342   my $method = $params{esc} =~ /^start|end|substr$/ ? 'ILIKE' : $params{method} || '=';
343
344   $val = [ $val ] unless ref $val eq 'ARRAY';
345
346   my %escapes = (
347     id     => \&conv_i,
348     bool   => \&conv_b,
349     date   => \&conv_date,
350     start  => sub { trim($_[0]) . '%' },
351     end    => sub { '%' . trim($_[0]) },
352     substr => sub { like($_[0]) },
353   );
354
355   my $_long_token = sub {
356     my $op = shift;
357     sub {
358       my $col = shift;
359       return scalar @_ ? join ' OR ', ("$col $op ?") x scalar @_,
360            :             undef;
361     }
362   };
363
364   my %methods = (
365     '=' => sub {
366       my $col = shift;
367       return scalar @_ >  1 ? sprintf '%s IN (%s)', $col, join ', ', ("?") x scalar @_
368            : scalar @_ == 1 ? sprintf '%s = ?',     $col
369            :                  undef;
370     },
371     map({ $_ => $_long_token->($_) } qw(LIKE ILIKE >= <= > <)),
372   );
373
374   $method = $methods{$method} || $method;
375   $escape = $escapes{$escape} || $escape;
376
377   my $token = $method->($col, @{ $val });
378   my @vals  = map { $escape->($_) } @{ $val };
379
380   return unless $token;
381
382   push @{ $tokens }, $token;
383   push @{ $values }, @vals;
384
385   return ($token, @vals);
386 }
387
388 sub like {
389   my ($string) = @_;
390
391   return "%" . SL::Util::trim($string // '') . "%";
392 }
393
394 sub role_is_superuser {
395   my ($dbh, $login)  = @_;
396   my ($is_superuser) = $dbh->selectrow_array(qq|SELECT usesuper FROM pg_user WHERE usename = ?|, undef, $login);
397
398   return $is_superuser;
399 }
400
401 sub check_trgm {
402   my ($dbh)  = @_;
403
404   my $version = $dbh->selectrow_array(qq|SELECT installed_version FROM pg_available_extensions WHERE name = 'pg_trgm'|);
405
406   return !!$version;
407 }
408
409 1;
410
411
412 __END__
413
414 =encoding utf-8
415
416 =head1 NAME
417
418 SL::DBUtils.pm: All about database connections in kivitendo
419
420 =head1 SYNOPSIS
421
422   use DBUtils;
423
424   conv_i($str, $default)
425   conv_date($str)
426   conv_dateq($str)
427   quote_db_date($date)
428
429   my $dbh = SL::DB->client->dbh;
430
431   do_query($form, $dbh, $query)
432   do_statement($form, $sth, $query)
433
434   dump_query($level, $msg, $query)
435   prepare_execute_query($form, $dbh, $query)
436
437   my $all_results_ref       = selectall_hashref_query($form, $dbh, $query)
438   my $first_result_hash_ref = selectfirst_hashref_query($form, $dbh, $query);
439
440   my @first_result =  selectfirst_array_query($form, $dbh, $query);
441   my @first_result =  selectrow_query($form, $dbh, $query);
442
443   my @values = selectcol_array_query($form, $dbh, $query);
444
445   my %sort_spec = create_sort_spec(%params);
446
447 =head1 DESCRIPTION
448
449 DBUtils provides wrapper functions for low level database retrieval. It saves
450 you the trouble of mucking around with statement handles for small database
451 queries and does exception handling in the common cases for you.
452
453 Query and retrieval functions share the parameter scheme:
454
455   query_or_retrieval(C<FORM, DBH, QUERY[, BINDVALUES]>)
456
457 =over 4
458
459 =item *
460
461 C<FORM> is used for error handling only. It can be omitted in theory, but should
462 not. In most cases you will call it with C<$::form>.
463
464 =item *
465
466 C<DBH> is a handle to the database, as returned by the C<DBI::connect> routine.
467 If you don't have an active connection, you can use
468 C<SL::DB->client->dbh> or get a C<Rose::DB::Object> handle from any RDBO class with
469 C<<SL::DB::Part->new->db->dbh>>. In both cases the handle will have AutoCommit set.
470
471 See C<PITFALLS AND CAVEATS> for common errors.
472
473 =item *
474
475 C<QUERY> must be exactly one query. You don't need to include the terminal
476 C<;>. There must be no tainted data interpolated into the string. Instead use
477 the DBI placeholder syntax.
478
479 =item *
480
481 All additional parameters will be used as C<BINDVALUES> for the query. Note
482 that DBI can't bind arrays to a C<id IN (?)>, so you will need to generate a
483 statement with exactly one C<?> for each bind value. DBI can however bind
484 DateTime objects, and you should always pass these for date selections.
485
486 =back
487
488 =head1 PITFALLS AND CAVEATS
489
490 =head2 Locking
491
492 As mentioned above, there are two sources of database handles in the program:
493 C<<$::form->get_standard_dbh>> and C<<SL::DB::Object->new->db->dbh>>. It's easy
494 to produce deadlocks when using both of them. To reduce the likelyhood of
495 locks, try to obey these rules:
496
497 =over 4
498
499 =item *
500
501 In a controller that uses Rose objects, never use C<get_standard_dbh>.
502
503 =item *
504
505 In backend code, that has no preference, always accept the database handle as a
506 parameter from the controller.
507
508 =back
509
510 =head2 Exports
511
512 C<DBUtils> is one of the last modules in the program to use C<@EXPORT> instead
513 of C<@EXPORT_OK>. This means it will flood your namespace with its functions,
514 causing potential clashes. When writing new code, always either export nothing
515 and call directly:
516
517   use SL::DBUtils ();
518   DBUtils::selectall_hashref_query(...)
519
520 or export only what you need:
521
522   use SL::DBUtils qw(selectall_hashref_query);
523   selectall_hashref_query(...)
524
525
526 =head2 Performance
527
528 Since it is really easy to write something like
529
530   my $all_parts = selectall_hashref_query($::form, $dbh, 'SELECT * FROM parts');
531
532 people do so from time to time. When writing code, consider this a ticking
533 timebomb. Someone out there has a database with 1mio parts in it, and this
534 statement just gobbled up 2GB of memory and timeouted the request.
535
536 Parts may be the obvious example, but the same applies to customer, vendors,
537 records, projects or custom variables.
538
539
540 =head1 QUOTING FUNCTIONS
541
542 =over 4
543
544 =item conv_i STR
545
546 =item conv_i STR,DEFAULT
547
548 Converts STR to an integer. If STR is empty, returns DEFAULT. If no DEFAULT is
549 given, returns undef.
550
551 =item conv_date STR
552
553 Converts STR to a date string. If STR is emptry, returns undef.
554
555 =item conv_dateq STR
556
557 Database version of conv_date. Quotes STR before returning. Returns 'NULL' if
558 STR is empty.
559
560 =item quote_db_date STR
561
562 Treats STR as a database date, quoting it. If STR equals current_date returns
563 an escaped version which is treated as the current date by Postgres.
564
565 Returns C<'NULL'> if STR is empty.
566
567 =item like STR
568
569 Turns C<STR> into an argument suitable for SQL's C<LIKE> and C<ILIKE>
570 operators by Trimming the string C<STR> (removes leading and trailing
571 whitespaces) and prepending and appending C<%>.
572
573 =back
574
575 =head1 QUERY FUNCTIONS
576
577 =over 4
578
579 =item do_query FORM,DBH,QUERY,ARRAY
580
581 Uses DBI::do to execute QUERY on DBH using ARRAY for binding values. FORM is
582 only needed for error handling, but should always be passed nevertheless. Use
583 this for insertions or updates that don't need to be prepared.
584
585 Returns the result of DBI::do which is -1 in case of an error and the number of
586 affected rows otherwise.
587
588 =item do_statement FORM,STH,QUERY,ARRAY
589
590 Uses DBI::execute to execute QUERY on DBH using ARRAY for binding values. As
591 with do_query, FORM is only used for error handling. If you are unsure what to
592 use, refer to the documentation of DBI::do and DBI::execute.
593
594 Returns the result of DBI::execute which is -1 in case of an error and the
595 number of affected rows otherwise.
596
597 =item prepare_execute_query FORM,DBH,QUERY,ARRAY
598
599 Prepares and executes QUERY on DBH using DBI::prepare and DBI::execute. ARRAY
600 is passed as binding values to execute.
601
602 =back
603
604 =head1 RETRIEVAL FUNCTIONS
605
606 =over 4
607
608 =item selectfirst_array_query FORM,DBH,QUERY,ARRAY
609
610 =item selectrow_query FORM,DBH,QUERY,ARRAY
611
612 Prepares and executes a query using DBUtils functions, retrieves the first row
613 from the database, and returns it as an arrayref of the first row.
614
615 =item selectfirst_hashref_query FORM,DBH,QUERY,ARRAY
616
617 Prepares and executes a query using DBUtils functions, retrieves the first row
618 from the database, and returns it as a hashref of the first row.
619
620 =item selectall_hashref_query FORM,DBH,QUERY,ARRAY
621
622 Prepares and executes a query using DBUtils functions, retrieves all data from
623 the database, and returns it in hashref mode. This is slightly confusing, as
624 the data structure will actually be a reference to an array, containing
625 hashrefs for each row.
626
627
628 =item selectall_array_query FORM,DBH,QUERY,ARRAY
629
630 Deprecated, see C<selectcol_array_query>
631
632 =item selectcol_array_query FORM,DBH,QUERY,ARRAY
633
634 Prepares and executes a query using DBUtils functions, retrieves the values of
635 the first result column and returns the values as an array.
636
637 =item selectall_as_map FORM,DBH,QUERY,KEY_COL,VALUE_COL,ARRAY
638
639 Prepares and executes a query using DBUtils functions, retrieves all data from
640 the database, and creates a hash from the results using KEY_COL as the column
641 for the hash keys and VALUE_COL for its values.
642
643 =back
644
645 =head1 UTILITY FUNCTIONS
646
647 =over 4
648
649 =item create_sort_spec
650
651   params:
652     defs        => { },         # mandatory
653     default     => 'name',      # mandatory
654     column      => 'name',
655     default_dir => 0|1,
656     dir         => 0|1,
657
658   returns hash:
659     column      => 'name',
660     dir         => 0|1,
661     sql         => 'SQL code',
662
663 This function simplifies the creation of SQL code for sorting
664 columns. It uses a hashref of valid column names, the column name and
665 direction requested by the user, the application defaults for the
666 column name and the direction and returns the actual column name,
667 direction and SQL code that can be used directly in a query.
668
669 The parameter 'defs' is a hash reference. The keys are the column
670 names as they may come from the application. The values are either
671 scalars with SQL code or array references of SQL code. Example:
672
673   defs => {
674     customername => 'lower(customer.name)',
675     address      => [ 'lower(customer.city)', 'lower(customer.street)' ],
676   }
677
678 'default' is the default column name to sort by. It must be a key of
679 'defs' and should not be come from user input.
680
681 The 'column' parameter is the column name as requested by the
682 application (e.g. if the user clicked on a column header in a
683 report). If it is invalid then the 'default' parameter will be used
684 instead.
685
686 'default_dir' is the default sort direction. A true value means 'sort
687 ascending', a false one 'sort descending'. 'default_dir' defaults to
688 '1' if undefined.
689
690 The 'dir' parameter is the sort direction as requested by the
691 application (e.g. if the user clicked on a column header in a
692 report). If it is undefined then the 'default_dir' parameter will be
693 used instead.
694
695 =item check_trgm
696
697 Checks if the postgresextension pg_trgm is installed and return trueish
698 or falsish.
699
700 =back
701
702 =head1 DEBUG FUNCTIONS
703
704 =over 4
705
706 =item dump_query LEVEL,MSG,QUERY,ARRAY
707
708 Dumps a query using LXDebug->message, using LEVEL for the debug-level of
709 LXDebug. If MSG is given, it preceeds the QUERY dump in the logfiles. ARRAY is
710 used to interpolate the '?' placeholders in QUERY, the resulting QUERY can be
711 copy-pasted into a database frontend for debugging. Note that this method is
712 also automatically called by each of the other QUERY FUNCTIONS, so there is in
713 general little need to invoke it manually.
714
715 =back
716
717 =head1 EXAMPLES
718
719 =over 4
720
721 =item Retrieving a whole table:
722
723   $query = qq|SELECT id, pricegroup FROM pricegroup|;
724   $form->{PRICEGROUPS} = selectall_hashref_query($form, $dbh, $query);
725
726 =item Retrieving a single value:
727
728   $query = qq|SELECT nextval('glid')|;
729   ($new_id) = selectrow_query($form, $dbh, $query);
730
731 =item Retrieving all values from a column:
732
733   $query = qq|SELECT id FROM units|;
734   @units = selectcol_array_query($form, $dbh, $query);
735
736 =item Using binding values:
737
738   $query = qq|UPDATE ar SET paid = amount + paid, storno = 't' WHERE id = ?|;
739   do_query($form, $dbh, $query, $id);
740
741 =item A more complicated example, using dynamic binding values:
742
743   my @values;
744
745   if ($form->{language_values} ne "") {
746     $query = qq|
747       SELECT l.id, l.description, tr.translation, tr.longdescription
748       FROM language l
749       LEFT JOIN translation tr ON (tr.language_id = l.id AND tr.parts_id = ?)
750     |;
751     @values = (conv_i($form->{id}));
752   } else {
753     $query = qq|SELECT id, description FROM language|;
754   }
755
756   my $languages = selectall_hashref_query($form, $dbh, $query, @values);
757
758 =back
759
760 =head1 MODULE AUTHORS
761
762   Moritz Bunkus E<lt>m.bunkus@linet-services.deE<gt>
763   Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
764
765 =head1 DOCUMENTATION AUTHORS
766
767   Udo Spallek E<lt>udono@gmx.netE<gt>
768   Sven Schöling E<lt>s.schoeling@linet-services.deE<gt>
769
770 =head1 COPYRIGHT AND LICENSE
771
772 Copyright 2007 by kivitendo Community
773
774 This program is free software; you can redistribute it and/or modify
775 it under the terms of the GNU General Public License as published by
776 the Free Software Foundation; either version 2 of the License, or
777 (at your option) any later version.
778
779 This program is distributed in the hope that it will be useful,
780 but WITHOUT ANY WARRANTY; without even the implied warranty of
781 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
782 GNU General Public License for more details.
783 You should have received a copy of the GNU General Public License
784 along with this program; if not, write to the Free Software
785 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
786
787 =cut