]> git.p6c8.net - devedit.git/blob - modules/Command.pm
- If a file shall be copied and the destination file already exists, a confirmation...
[devedit.git] / modules / Command.pm
1 package Command;
2
3 #
4 # Dev-Editor - Module Command
5 #
6 # Execute Dev-Editor's commands
7 #
8 # Author: Patrick Canterino <patshaping@gmx.net>
9 # Last modified: 2003-12-18
10 #
11
12 use strict;
13
14 use vars qw(@EXPORT);
15
16 use File::Access;
17 use File::Copy;
18 use File::Path;
19
20 use HTML::Entities;
21 use Output;
22 use POSIX qw(strftime);
23 use Tool;
24
25 my $script = $ENV{'SCRIPT_NAME'};
26
27 my %dispatch = ('show' => \&exec_show,
28 'beginedit' => \&exec_beginedit,
29 'canceledit' => \&exec_unlock,
30 'endedit' => \&exec_endedit,
31 'mkdir' => \&exec_mkdir,
32 'mkfile' => \&exec_mkfile,
33 'workwithfile' => \&exec_workwithfile,
34 'workwithdir' => \&exec_workwithdir,
35 'copy' => \&exec_copy,
36 'rename' => \&exec_rename,
37 'remove' => \&exec_remove,
38 'rmdir' => \&exec_rmdir,
39 'unlock' => \&exec_unlock
40 );
41
42 ### Export ###
43
44 use base qw(Exporter);
45
46 @EXPORT = qw(exec_command);
47
48 # exec_command()
49 #
50 # Execute the specified command
51 #
52 # Params: 1. Command to execute
53 # 2. Reference to user input hash
54 # 3. Reference to config hash
55 #
56 # Return: Output of the command (Scalar Reference)
57
58 sub exec_command($$$)
59 {
60 my ($command,$data,$config) = @_;
61
62 return error("Unknown command: $command") unless($dispatch{$command});
63
64 my $output = &{$dispatch{$command}}($data,$config);
65 return $output;
66 }
67
68 # exec_show()
69 #
70 # View a directory or a file
71 #
72 # Params: 1. Reference to user input hash
73 # 2. Reference to config hash
74 #
75 # Return: Output of the command (Scalar Reference)
76
77 sub exec_show($$)
78 {
79 my ($data,$config) = @_;
80 my $physical = $data->{'physical'};
81 my $virtual = $data->{'virtual'};
82 my $output;
83
84 if(-d $physical)
85 {
86 # Create directory listing
87
88 my $direntries = dir_read($physical);
89 return error("Reading of directory $virtual failed.",upper_path($virtual)) unless($direntries);
90
91 my $files = $direntries->{'files'};
92 my $dirs = $direntries->{'dirs'};
93
94 $output .= htmlhead("Directory listing of $virtual");
95 $output .= equal_url($config->{'httproot'},$virtual);
96 $output .= "<hr>\n\n<pre>\n";
97
98 # Create the link to the upper directory
99 # (only if we are not in the root directory)
100
101 unless($virtual eq "/")
102 {
103 my $upper = $physical."/..";
104 my @stat = stat($upper);
105
106 $output .= " [SUBDIR] ";
107 $output .= strftime("%d.%m.%Y %H:%M",localtime($stat[9]));
108 $output .= " " x 10;
109 $output .= "<a href=\"$script?command=show&file=".encode_entities(upper_path($virtual))."\">../</a>\n";
110 }
111
112 # Get the length of the longest file/directory name
113
114 my $max_name_len = 0;
115
116 foreach(@$dirs,@$files)
117 {
118 my $length = length($_);
119 $max_name_len = $length if($length > $max_name_len);
120 }
121
122 # Directories
123
124 foreach my $dir(@$dirs)
125 {
126 my @stat = stat($physical."/".$dir);
127 my $virt_path = encode_entities($virtual.$dir."/");
128
129 $output .= " ";
130 $output .= "[SUBDIR] ";
131 $output .= strftime($config->{'timeformat'},localtime($stat[9]));
132 $output .= " " x 10;
133 $output .= "<a href=\"$script?command=show&file=$virt_path\">".encode_entities($dir)."/</a>";
134 $output .= " " x ($max_name_len - length($dir) - 1)."\t (";
135 $output .= "<a href=\"$script?command=workwithdir&file=$virt_path\">Work with directory</a>)\n";
136 }
137
138 # Files
139
140 foreach my $file(@$files)
141 {
142 my $phys_path = $physical."/".$file;
143 my $virt_path = encode_entities($virtual.$file);
144
145 my @stat = stat($phys_path);
146 my $in_use = $data->{'uselist'}->in_use($virtual.$file);
147
148 $output .= " " x (10 - length($stat[7]));
149 $output .= $stat[7];
150 $output .= " ";
151 $output .= strftime($config->{'timeformat'},localtime($stat[9]));
152 $output .= " " x 10;
153 $output .= encode_entities($file);
154 $output .= " " x ($max_name_len - length($file))."\t (";
155
156 # Link "View"
157
158 if(-r $phys_path && -T $phys_path)
159 {
160 $output .= "<a href=\"$script?command=show&file=$virt_path\">View</a>";
161 }
162 else
163 {
164 $output .= '<span style="color:#C0C0C0" title="';
165
166 $output .= (not -r $phys_path) ? "Not readable" :
167 (-B $phys_path) ? "Binary file" : "";
168
169 $output .= '">View</span>';
170 }
171
172 $output .= " | ";
173
174 # Link "Edit"
175
176 if(-w $phys_path && -r $phys_path && -T $phys_path && not $in_use)
177 {
178 $output .= "<a href=\"$script?command=beginedit&file=$virt_path\">Edit</a>";
179 }
180 else
181 {
182 $output .= '<span style="color:#C0C0C0" title="';
183
184 $output .= (not -r $phys_path) ? "Not readable" :
185 (not -w $phys_path) ? "Read only" :
186 (-B $phys_path) ? "Binary file" :
187 ($in_use) ? "In use" : "";
188
189 $output .= '">Edit</span>';
190 }
191
192 # Link "Do other stuff"
193
194 $output .= " | <a href=\"$script?command=workwithfile&file=$virt_path\">Work with file</a>)\n";
195 }
196
197 $output .= "</pre>\n\n<hr>\n\n";
198
199 # Bottom of directory listing
200 # (Fields for creating files and directories)
201
202 $output .= <<END;
203 <table border="0">
204 <tr>
205 <form action="$script">
206 <input type="hidden" name="command" value="mkdir">
207 <input type="hidden" name="curdir" value="$virtual">
208 <td>Create new directory:</td>
209 <td>$virtual <input type="text" name="newfile"> <input type="submit" value="Create!"></td>
210 </form>
211 </tr>
212 <tr>
213 <td>Create new file:</td>
214 <form action="$script">
215 <input type="hidden" name="command" value="mkfile">
216 <input type="hidden" name="curdir" value="$virtual">
217 <td>$virtual <input type="text" name="newfile"> <input type="submit" value="Create!"></td>
218 </form>
219 </tr>
220 </table>
221
222 <hr>
223 END
224 $output .= htmlfoot;
225 }
226 else
227 {
228 # View a file
229
230 return error("You have not enough permissions to view this file.",upper_path($virtual)) unless(-r $physical);
231
232 # Check on binary files
233 # We have to do it in this way, or empty files
234 # will be recognized as binary files
235
236 unless(-T $physical)
237 {
238 # Binary file
239
240 return error("This editor is not able to view/edit binary files.",upper_path($virtual));
241 }
242 else
243 {
244 # Text file
245
246 $output = htmlhead("Contents of file ".encode_entities($virtual));
247 $output .= equal_url($config->{'httproot'},$virtual);
248 $output .= dir_link($virtual);
249
250 $output .= '<div style="background-color:#FFFFE0;border:1px solid black;margin-top:10px;width:100%">'."\n";
251 $output .= '<pre style="color:#0000C0;">'."\n";
252 $output .= encode_entities(${file_read($physical)});
253 $output .= "\n</pre>\n</div>";
254
255 $output .= htmlfoot;
256 }
257 }
258
259 return \$output;
260 }
261
262 # exec_beginedit
263 #
264 # Lock a file and display a form to edit it
265 #
266 # Params: 1. Reference to user input hash
267 # 2. Reference to config hash
268 #
269 # Return: Output of the command (Scalar Reference)
270
271 sub exec_beginedit($$)
272 {
273 my ($data,$config) = @_;
274 my $physical = $data->{'physical'};
275 my $virtual = $data->{'virtual'};
276 my $uselist = $data->{'uselist'};
277
278 return error("You cannot edit directories.",upper_path($virtual)) if(-d $physical);
279 return error_in_use($virtual) if($uselist->in_use($virtual));
280 return error("You have not enough permissions to edit this file.",upper_path($virtual)) unless(-r $physical && -w $physical);
281
282 # Check on binary files
283
284 unless(-T $physical)
285 {
286 # Binary file
287
288 return error("This editor is not able to view/edit binary files.",upper_path($virtual));
289 }
290 else
291 {
292 # Text file
293
294 $uselist->add_file($virtual);
295 $uselist->save;
296
297 my $dir = upper_path($virtual);
298 my $content = encode_entities(${file_read($physical)});
299
300 my $equal_url = equal_url($config->{'httproot'},$virtual);
301
302 $virtual = encode_entities($virtual);
303
304 my $output = htmlhead("Edit file $virtual");
305 $output .= $equal_url;
306 $output .= <<END;
307 <p><b style="color:#FF0000">Caution!</b> This file is locked for other users while you are editing it. To unlock it, click <i>Save and exit</i> or <i>Exit WITHOUT saving</i>. Please <b>don't</b> click the <i>Reload</i> button in your browser! This will confuse the editor.</p>
308
309 <form action="$script" method="get">
310 <input type="hidden" name="command" value="canceledit">
311 <input type="hidden" name="file" value="$virtual">
312 <p><input type="submit" value="Exit WITHOUT saving"></p>
313 </form>
314
315 <form action="$script" method="post">
316 <input type="hidden" name="command" value="endedit">
317 <input type="hidden" name="file" value="$virtual">
318
319 <table width="100%" border="1">
320 <tr>
321 <td width="50%" align="center">
322 <input type="hidden" name="file" value="$virtual">
323 <input type="checkbox" name="saveas" value="1"> Save as new file: $dir <input type=text name="newfile" value=""></td>
324 <td width="50%" align="center"><input type="checkbox" name="encode_iso" value="1"> Encode ISO-8859-1 special chars</td>
325 </tr>
326 <tr>
327 <td align="center"><input type="reset" value="Reset form"></td>
328 <td align="center"><input type="submit" value="Save and exit"></td>
329 </tr>
330 </table>
331
332 <textarea name="filecontent" rows="25" cols="120">$content</textarea>
333 </form>
334 END
335
336 $output .= htmlfoot;
337
338 return \$output;
339 }
340 }
341
342 # exec_endedit()
343 #
344 # Save a file, unlock it and return to directory view
345 #
346 # Params: 1. Reference to user input hash
347 # 2. Reference to config hash
348 #
349 # Return: Output of the command (Scalar Reference)
350
351 sub exec_endedit($$)
352 {
353 my ($data,$config) = @_;
354 my $physical = $data->{'physical'};
355 my $virtual = $data->{'virtual'};
356 my $content = $data->{'cgi'}->param('filecontent');
357
358 return error("You cannot edit directories.") if(-d $physical);
359 return error("You have not enough permissions to edit this file.",upper_path($virtual)) unless(-r $physical && -w $physical);
360
361 # Normalize newlines
362
363 $content =~ s/\015\012|\012|\015/\n/g;
364
365 if($data->{'cgi'}->param('encode_iso'))
366 {
367 # Encode all ISO-8859-1 special chars
368
369 $content = encode_entities($content,"\200-\377");
370 }
371
372 if($data->{'cgi'}->param('saveas'))
373 {
374 # Create the new filename
375
376 $physical = $data->{'new_physical'};
377 $virtual = $data->{'new_virtual'};
378 }
379
380 if(file_save($physical,\$content))
381 {
382 # Saving of the file was successful - so unlock it!
383
384 return exec_unlock($data,$config);
385 }
386 else
387 {
388 return error("Saving of file '".encode_entities($virtual)."' failed'. The file could be damaged, please check it's integrity.",upper_path($virtual));
389 }
390 }
391
392 # exec_mkfile()
393 #
394 # Create a file and return to directory view
395 #
396 # Params: 1. Reference to user input hash
397 # 2. Reference to config hash
398 #
399 # Return: Output of the command (Scalar Reference)
400
401 sub exec_mkfile($$)
402 {
403 my ($data,$config) = @_;
404 my $new_physical = $data->{'new_physical'};
405 my $new_virtual = $data->{'new_virtual'};
406 my $dir = upper_path($new_virtual);
407 $new_virtual = encode_entities($new_virtual);
408
409 return error("A file or directory called '$new_virtual' already exists.",$dir) if(-e $new_physical);
410
411 file_create($new_physical) or return error("Could not create file '$new_virtual'.",$dir);
412 return devedit_reload({command => 'show', file => $dir});
413 }
414
415 # exec_mkdir()
416 #
417 # Create a directory and return to directory view
418 #
419 # Params: 1. Reference to user input hash
420 # 2. Reference to config hash
421 #
422 # Return: Output of the command (Scalar Reference)
423
424 sub exec_mkdir($$)
425 {
426 my ($data,$config) = @_;
427 my $new_physical = $data->{'new_physical'};
428 my $new_virtual = $data->{'new_virtual'};
429 my $dir = upper_path($new_virtual);
430 $new_virtual = encode_entities($new_virtual);
431
432 return error("A file or directory called '$new_virtual' already exists.",$dir) if(-e $new_physical);
433
434 mkdir($new_physical,0777) or return error("Could not create directory '$new_virtual'.",$dir);
435 return devedit_reload({command => 'show', file => $dir});
436 }
437
438 # exec_workwithfile()
439 #
440 # Display a form for renaming/copying/removing/unlocking a file
441 #
442 # Params: 1. Reference to user input hash
443 # 2. Reference to config hash
444 #
445 # Return: Output of the command (Scalar Reference)
446
447 sub exec_workwithfile($$)
448 {
449 my ($data,$config) = @_;
450 my $physical = $data->{'physical'};
451 my $virtual = $data->{'virtual'};
452 my $unused = $data->{'uselist'}->unused($virtual);
453
454 my $dir = encode_entities(upper_path($virtual));
455
456 my $output = htmlhead("Work with file ".encode_entities($virtual));
457 $output .= equal_url($config->{'httproot'},$virtual);
458
459 $virtual = encode_entities($virtual);
460
461 $output .= dir_link($virtual);
462 $output .= "<p><b>Note:</b> On UNIX systems, filenames are <b>case-sensitive</b>!</p>\n\n";
463
464 $output .= "<p>Someone else is currently editing this file. So not all features are available.</p>\n\n" unless($unused);
465
466 $output .= "<hr>\n\n";
467
468 # Copying of the file is always allowed - but we need read access
469
470 if(-r $physical)
471 {
472 $output .= <<END;
473 <h2>Copy</h2>
474
475 <form action="$script">
476 <input type="hidden" name="command" value="copy">
477 <input type="hidden" name="file" value="$virtual">
478 <p>Copy file '$virtual' to:<br>$dir <input type="text" name="newfile" size="30"> <input type="submit" value="Copy!"></p>
479 </form>
480
481 <hr>
482
483 END
484 }
485
486 if($unused)
487 {
488 # File is not locked
489 # Allow renaming and deleting the file
490
491 $output .= <<END;
492 <h2>Move/rename</h2>
493
494 <form action="$script">
495 <input type="hidden" name="command" value="rename">
496 <input type="hidden" name="file" value="$virtual">
497 <p>Move/Rename file '$virtual' to:<br>$dir <input type="text" name="newfile" size="30"> <input type="submit" value="Move/Rename!"></p>
498 </form>
499
500 <hr>
501
502 <h2>Remove</h2>
503
504 <p>Click on the button below to remove the file '$virtual'.</p>
505
506 <form action="$script" method="get">
507 <input type="hidden" name="file" value="$virtual">
508 <input type="hidden" name="command" value="remove">
509 <p><input type="submit" value="Remove!"></p>
510 </form>
511 END
512 }
513 else
514 {
515 # File is locked
516 # Just display a button for unlocking it
517
518 $output .= <<END;
519 <h2>Unlock file</h2>
520
521 <p>Someone else is currently editing this file. At least, the file is marked so. Maybe, someone who was editing the file has forgotten to unlock it. In this case (and <b>only</b> in this case) you can unlock the file using this button:</p>
522
523 <form action="$script" method="get">
524 <input type="hidden" name="file" value="$virtual">
525 <input type="hidden" name="command" value="unlock">
526 <p><input type="submit" value="Unlock file '$virtual'"></p>
527 </form>
528 END
529 }
530
531 $output .= "\n<hr>";
532 $output .= htmlfoot;
533
534 return \$output;
535 }
536
537 # exec_workwithdir()
538 #
539 # Display a form for renaming/removing a directory
540 #
541 # Params: 1. Reference to user input hash
542 # 2. Reference to config hash
543 #
544 # Return: Output of the command (Scalar Reference)
545
546 sub exec_workwithdir($$)
547 {
548 my ($data,$config) = @_;
549 my $physical = $data->{'physical'};
550 my $virtual = $data->{'virtual'};
551
552 my $dir = encode_entities(upper_path($virtual));
553
554 my $output = htmlhead("Work with directory ".encode_entities($virtual));
555 $output .= equal_url($config->{'httproot'},$virtual);
556
557 $virtual = encode_entities($virtual);
558
559 $output .= dir_link($virtual);
560 $output .= "<p><b>Note:</b> On UNIX systems, filenames are <b>case-sensitive</b>!</p>\n\n";
561 $output .= "<hr>\n\n";
562
563 $output .= <<END;
564 <h2>Move/rename</h2>
565
566 <form action="$script">
567 <input type="hidden" name="command" value="rename">
568 <input type="hidden" name="file" value="$virtual">
569 <p>Move/Rename directory '$virtual' to: $dir <input type="text" name="newfile" size="50"> <input type="submit" value="Move/Rename!"></p>
570 </form>
571
572 <hr>
573
574 <h2>Remove</h2>
575
576 <p>Click on the button below to completely remove the directory '$virtual' and oll of it's files and sub directories.</p>
577
578 <form action="$script" method="get">
579 <input type="hidden" name="file" value="$virtual">
580 <input type="hidden" name="command" value="rmdir">
581 <p><input type="submit" value="Remove!"></p>
582 </form>
583 END
584
585 $output .= "\n<hr>";
586 $output .= htmlfoot;
587
588 return \$output;
589 }
590
591 # exec_copy()
592 #
593 # Copy a file and return to directory view
594 #
595 # Params: 1. Reference to user input hash
596 # 2. Reference to config hash
597 #
598 # Return: Output of the command (Scalar Reference)
599
600 sub exec_copy($$)
601 {
602 my ($data,$config) = @_;
603 my $physical = $data->{'physical'};
604 my $virtual = encode_entities($data->{'virtual'});
605 my $new_physical = $data->{'new_physical'};
606 my $new_virtual = $data->{'new_virtual'};
607 my $dir = upper_path($new_virtual);
608 $new_virtual = encode_entities($new_virtual);
609
610 return error("This editor is not able to copy directories.") if(-d $physical);
611 return error("You have not enough permissions to copy this file.") unless(-r $physical);
612
613 if(-e $new_physical)
614 {
615 if(-d $new_physical)
616 {
617 return error("A directory called '$new_virtual' already exists. You cannot replace a directory by a file!",$dir);
618 }
619 elsif(not $data->{'cgi'}->param('confirmed'))
620 {
621 $dir = encode_entities($dir);
622
623 my $output = htmlhead("Replace existing file");
624 $output .= <<"END";
625 <p>A file called '$new_virtual' already exists. Do you want to replace it?</p>
626
627 <form action="$script" method="get">
628 <input type="hidden" name="command" value="copy">
629 <input type="hidden" name="file" value="$virtual">
630 <input type="hidden" name="newfile" value="$new_virtual">
631 <input type="hidden" name="confirmed" value="1">
632
633 <p><input type="submit" value="Yes"></p>
634 </form>
635
636 <form action="$script" method="get">
637 <input type="hidden" name="command" value="show">
638 <input type="hidden" name="file" value="$dir">
639
640 <p><input type="submit" value="No"></p>
641 </form>
642 END
643
644 $output .= htmlfoot;
645
646 return \$output;
647 }
648 }
649
650 if($data->{'uselist'}->in_use($data->{'new_virtual'}))
651 {
652 return error("The target file '$new_virtual' already exists and it is edited by someone else.",$dir);
653 }
654
655 copy($physical,$new_physical) or return error("Could not copy '$virtual' to '$new_virtual'",upper_path($virtual));
656 return devedit_reload({command => 'show', file => $dir});
657 }
658
659 # exec_rename()
660 #
661 # Rename/move a file and return to directory view
662 #
663 # Params: 1. Reference to user input hash
664 # 2. Reference to config hash
665 #
666 # Return: Output of the command (Scalar Reference)
667
668 sub exec_rename($$)
669 {
670 my ($data,$config) = @_;
671 my $physical = $data->{'physical'};
672 my $virtual = $data->{'virtual'};
673 my $new_physical = $data->{'new_physical'};
674 my $new_virtual = $data->{'new_virtual'};
675 my $dir = upper_path($new_virtual);
676 $new_virtual = encode_entities($new_virtual);
677
678 return error_in_use($virtual) if($data->{'uselist'}->in_use($virtual));
679
680 if(-e $new_physical)
681 {
682 return error("A file or directory called '$new_virtual' already exists and this editor is currently not able to ask to overwrite the existing file or directory.",upper_path($virtual));
683 }
684
685 rename($physical,$new_physical) or return error("Could not move/rename '".encode_entities($virtual)."' to '$new_virtual'.",upper_path($virtual));
686 return devedit_reload({command => 'show', file => $dir});
687 }
688
689 # exec_remove()
690 #
691 # Remove a file and return to directory view
692 #
693 # Params: 1. Reference to user input hash
694 # 2. Reference to config hash
695 #
696 # Return: Output of the command (Scalar Reference)
697
698 sub exec_remove($$)
699 {
700 my ($data,$config) = @_;
701 my $physical = $data->{'physical'};
702 my $virtual = $data->{'virtual'};
703
704 return exec_rmdir($data,$config) if(-d $physical);
705 return error_in_use($virtual) if($data->{'uselist'}->in_use($virtual));
706
707 unlink($physical) or return error("Could not delete file '".encode_entities($virtual)."'.",upper_path($virtual));
708 return devedit_reload({command => 'show', file => upper_path($virtual)});
709 }
710
711 # exec_rmdir()
712 #
713 # Remove a directory and return to directory view
714 #
715 # Params: 1. Reference to user input hash
716 # 2. Reference to config hash
717 #
718 # Return: Output of the command (Scalar Reference)
719
720 sub exec_rmdir($$)
721 {
722 my ($data,$config) = @_;
723 my $physical = $data->{'physical'};
724 my $virtual = $data->{'virtual'};
725
726 return exec_remove($data,$config) if(not -d $physical);
727
728 if($data->{'cgi'}->param('confirmed'))
729 {
730 rmtree($physical);
731 return devedit_reload({command => 'show', file => upper_path($virtual)});
732 }
733 else
734 {
735 my $dir = encode_entities(upper_path($virtual));
736 my $output;
737
738 $output = htmlhead("Remove directory $virtual");
739 $output .= equal_url($config->{'httproot'},$virtual);
740
741 $virtual = encode_entities($virtual);
742
743 $output .= dir_link($virtual);
744
745 $output .= <<"END";
746 <p>Do you really want to remove the directory '$virtual' and all of it's files and sub directories?</p>
747
748 <form action="$script" method="get">
749 <input type="hidden" name="command" value="rmdir">
750 <input type="hidden" name="file" value="$virtual">
751 <input type="hidden" name="confirmed" value="1">
752
753 <p><input type="submit" value="Yes"></p>
754 </form>
755
756 <form action="$script" method="get">
757 <input type="hidden" name="command" value="show">
758 <input type="hidden" name="file" value="$dir">
759
760 <p><input type="submit" value="No"></p>
761 </form>
762 END
763
764 $output .= htmlfoot;
765
766 return \$output;
767 }
768 }
769
770 # exec_unlock()
771 #
772 # Remove a file from the list of used files and
773 # return to directory view
774 #
775 # Params: 1. Reference to user input hash
776 # 2. Reference to config hash
777 #
778 # Return: Output of the command (Scalar Reference)
779
780 sub exec_unlock($$)
781 {
782 my ($data,$config) = @_;
783 my $virtual = $data->{'virtual'};
784 my $uselist = $data->{'uselist'};
785
786 $uselist->remove_file($virtual);
787 $uselist->save;
788
789 return devedit_reload({command => 'show', file => upper_path($virtual)});
790 }
791
792 # it's true, baby ;-)
793
794 1;
795
796 #
797 ### End ###

patrick-canterino.de