File Coverage

blib/lib/PostScript/CDCover.pm
Criterion Covered Total %
statement 32 118 27.1
branch 2 40 5.0
condition 5 27 18.5
subroutine 11 22 50.0
pod 4 7 57.1
total 54 214 25.2


line stmt bran cond sub pod time code
1             package PostScript::CDCover;
2 4     4   33093 use strict;
  4         10  
  4         226  
3              
4             # $Id: CDCover.pm,v 1.9 2004/05/28 22:05:20 cbouvi Exp $
5             #
6             # Copyright (C) 2004 Cédric Bouvier
7             #
8             # This library is free software; you can redistribute it and/or modify it
9             # under the terms of the GNU General Public License as published by the Free
10             # Software Foundation; either version 2 of the License, or (at your option)
11             # any later version.
12             #
13             # This library is distributed in the hope that it will be useful, but WITHOUT
14             # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15             # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
16             # more details.
17             #
18             # You should have received a copy of the GNU General Public License along with
19             # this library; if not, write to the Free Software Foundation, Inc., 59 Temple
20             # Place, Suite 330, Boston, MA 02111-1307 USA
21              
22             # $Log: CDCover.pm,v $
23             # Revision 1.9 2004/05/28 22:05:20 cbouvi
24             # Forced boolean options to 1 and 0. Updated POD
25             #
26             # Revision 1.8 2004/05/28 21:32:26 cbouvi
27             # Updated POD
28             #
29             # Revision 1.7 2004/05/26 22:01:13 cbouvi
30             # Added POD
31             #
32             # Revision 1.6 2004/05/26 21:01:37 cbouvi
33             # Added comments.
34             # Files appear now one level deeper than their directory.
35             # Fixed the removal of the root directory.
36             #
37             # Revision 1.5 2004/05/22 21:07:47 cbouvi
38             # Fixed starting depth and difference between files and dirs depth
39             #
40             # Revision 1.4 2004/05/21 20:51:45 cbouvi
41             # Moved all the functionality to PostScript::CDCover
42             #
43             # Revision 1.3 2004/05/10 21:26:48 cbouvi
44             # Added $VERSION
45             #
46             # Revision 1.2 2004/05/04 21:21:31 cbouvi
47             # Added output() method. Remove non strictly Cover related options
48             #
49             # Revision 1.1 2004/04/11 19:36:32 cbouvi
50             # Started conversion of pscdcover to PostScript::CDCover
51             #
52              
53 4     4   25 use vars qw/ $VERSION /;
  4         8  
  4         367  
54             $VERSION = 1.0;
55              
56 4     4   25 use File::Basename qw/ dirname /;
  4         10  
  4         486  
57 4     4   26 use File::Path qw/ mkpath /;
  4         8  
  4         7965  
58              
59             package PostScript::CDCover::Directory;
60              
61             # Constructor
62             # Directory name as optional argument
63             sub new {
64              
65 0     0   0 my $proto = shift;
66 0   0     0 my $class = ref($proto) || $proto;
67              
68 0         0 my $self = bless {}, $class;
69 0 0       0 $self->{_name} = $_[0] if @_;
70 0         0 return $self;
71             }
72              
73             sub name {
74              
75 0     0   0 my $self = shift;
76 0   0     0 ($self->{_name}, @_ && ($self->{_name} = $_[0]))[0];
77             }
78              
79             # Returns the PostScript::CDCover::Directory object for a given subdirectory.
80             # If no argument is given, return $self.
81             # If the directory object does not exist, it is created.
82             sub directory {
83              
84 0     0   0 my ($self, $name) = @_;
85              
86 0 0       0 return $self unless $name;
87 0   0     0 return $self->{_directories}{$name} ||= new PostScript::CDCover::Directory $name;
88             }
89              
90             # Add a directory, somewhere in the subtree, i.e., if the new directory is more
91             # than one level below the current one, the actual addition is delegated to a
92             # first level subdirectory.
93             sub add_directory {
94              
95 0     0   0 my ($self, $path) = @_;
96              
97 0         0 $path =~ s|^[/\\]||;
98 0         0 my ($head, $rest) = split m|[/\\]|, $path, 2;
99 0         0 my $dir = $self->directory($head);
100 0 0       0 $dir->add_directory($rest) if $rest;
101             }
102              
103             # Add a file somewhere in the subtree. If the file does not belong to the
104             # current directory, the task of adding it is delegated to a subdirectory
105             # (which, in turn, can delegate to one of its own subdirectories, and so on).
106             sub add_file {
107              
108 0     0   0 my ($self, $path) = @_;
109              
110 0         0 $path =~ s|^[/\\]||;
111 0         0 my ($head, $rest) = split m|[/\\]|, $path, 2;
112 0 0       0 if ( $rest ) {
113 0         0 $self->directory($head)->add_file($rest);
114             }
115             else {
116 0         0 push @{$self->{_files}}, $head;
  0         0  
117             }
118             }
119              
120             # Returns a string consisting of all the calls to the Postscript program
121             # function file_title or folder_title for the current directory.
122             # A $depth parameter can optionally be specified for indentation.
123             # as_ps() will recursively call itself on every subdirectories with an
124             # incremented $depth, thus generating the output for all the subtree.
125             sub as_ps {
126              
127 0     0   0 my $self = shift;
128             # The root has an empty name and is not display. All the subdirectories
129             # start at level 0. The root is thus as it were at level -1
130 0 0       0 my $depth = @_ ? shift : -1;
131 0         0 my $indent = ' ' x $depth; # indentation in the Postscript source code
132              
133 0         0 my $name = PostScript::CDCover::_quote_paren($self->name());
134 0         0 my @output;
135              
136             # A line for the directory itself
137 0 0       0 @output = (qq{$indent($name) $depth folder_title}) if $name;
138              
139             # Now for its subdirectories
140 0         0 for ( sort keys %{$self->{_directories}} ) {
  0         0  
141 0         0 push @output, $self->{_directories}{$_}->as_ps($depth+1);
142             }
143              
144 0         0 ++$depth;
145             # And finally, its files
146 0 0       0 if ( $self->{_files} ) {
147 0         0 for ( sort @{$self->{_files}} ) {
  0         0  
148 0         0 my $n = PostScript::CDCover::_quote_paren($_);
149 0         0 push @output, qq{$indent ($n) $depth file_title};
150             }
151             }
152              
153 0         0 return join "\n", @output;
154             }
155              
156             package PostScript::CDCover;
157              
158             # returns the directory where CDCover.pm (this very file) resides.
159             sub dir {
160 2     2 0 10 (my $module = __PACKAGE__ ) =~ s|::|/|g;
161 2         274 dirname( $INC{"$module.pm"} )
162             }
163              
164             sub new {
165              
166 3     3 0 39 my $proto = shift;
167 3   33     50 my $class = ref($proto) || $proto;
168              
169 3         11 my $self = bless {}, $class;
170              
171 3         9 my %attr = @_;
172 3         26 while ( my ($attr, $value) = each %attr ) {
173 0         0 $attr =~ s/^-+//;
174 0         0 $attr = lc $attr;
175              
176 0         0 $self->$attr($value);
177             }
178 3         13 return $self;
179             }
180              
181             # Insert a backslash before any parenthesis
182             sub _quote_paren {
183              
184 1     1   6 local $_ = $_[0];
185 1         6 s/\(/\\(/g;
186 1         4 s/\)/\\)/g;
187 1         9 return $_;
188             }
189              
190             # Change an hexa triplet (like those used for colors in HTML or CSS) into a
191             # list of three decimal numbers suitable for PostScript setrgbcolor function.
192             sub _split_color {
193              
194 1     1   14 map $_/255, unpack 'xC3', pack 'N', $_[0];
195             }
196              
197             # An accessor (read/write) with a default value: the Postscript code is located
198             # in the same directory as CDCover.pm itself.
199             sub ps {
200              
201 2     2 1 9 my $self = shift;
202              
203             (
204 2   33     22 ($self->{_ps} ||= $self->dir() . '/pscdcover.ps'),
      33        
205             @_ && ($self->{_ps} = $_[0])
206             )[0];
207             }
208              
209             #
210             # _output
211             #
212             # This function outputs a chunk of text to "somewhere", this being a coderef,
213             # or file handle, or a reference to a string, or a filename.
214             # Code borrowed from the Template Toolkit by Andy Wardley.
215             #
216             sub _output {
217              
218 0     0   0 my ($where, $text, $binmode) = @_;
219 0         0 my $reftype = ref($where);
220 0         0 my $error;
221              
222 0 0       0 if ( $reftype eq 'CODE' ) {
    0          
    0          
    0          
223 0         0 $where->($text);
224             }
225             elsif ( $reftype eq 'GLOB' ) {
226 0         0 print $where $text;
227             }
228             elsif ($reftype eq 'SCALAR' ) {
229 0         0 $$where .= $text;
230             }
231             elsif ( UNIVERSAL::can($where, 'print') ) {
232 0         0 $where->print($text);
233             }
234             else {
235 0         0 $error = "Cannot determine target type ($where)\n";
236             }
237              
238 0         0 return $error;
239             }
240              
241             # Returns (after creating it if need be) the root directory object.
242             sub root_directory {
243              
244 0     0 0 0 my $self = shift;
245              
246 0   0     0 return $self->{_root_directory} ||= new PostScript::CDCover::Directory;
247             }
248              
249             # Adds a directory to the tree, after trimming the root directory
250             sub add_directory {
251              
252 0     0 1 0 my ($self, $dir) = @_;
253 0         0 my $root = quotemeta $self->root();
254              
255 0         0 $dir =~ s/^$root//;
256 0         0 $self->root_directory()->add_directory($dir);
257             }
258              
259             # Adds a file to the subtree.
260             sub add_file {
261              
262 0     0 1 0 my ($self, $file) = @_;
263 0         0 my $root = quotemeta $self->root();
264              
265 0         0 $file =~ s/^$root//;
266 0         0 $self->root_directory()->add_file($file);
267             }
268              
269             # Outputs the Postscript source code
270             sub flush {
271              
272 0     0 1 0 my $self = shift;
273              
274 0 0       0 open my $fh, $self->ps() or die "Cannot open @{[$self->ps()]}: $!\n";
  0         0  
275            
276 0         0 while ( <$fh> ) {
277 0 0       0 if ( my $in = (/#START_CONTENT#/ .. /#STOP_CONTENT#/) ) {
278             # Generate the Postscript code for the directory tree
279 0 0       0 next unless $in == 1; # only once
280 0         0 _output $self->output(), $self->root_directory()->as_ps();
281             }
282             else {
283             # Keyword substitution
284 0 0       0 s[#FORCE_ALL_PAGES#][$self->all() ? 1 : 0]e;
  0         0  
285 0         0 s[#CD_TITLE#] [_quote_paren($self->title())]e;
  0         0  
286 0 0       0 s[#COLUMNS#] [$self->columns() || 0]e;
  0         0  
287 0         0 s[#MIN_WIDTH#] [$self->minwidth()]e;
  0         0  
288 0 0       0 s[#SEPARATOR#] [$self->separator() ? 1 : 0]e;
  0         0  
289 0 0       0 s[#COLOR#] [$self->color() ? 1 : 0]e;
  0         0  
290 0         0 s[#CD_COLOR#] [join ' ', _split_color $self->cdcolor()]e;
  0         0  
291 0         0 s[#FOLDER_COLOR#] [join ' ', _split_color $self->foldercolor()]e;
  0         0  
292             # Remove the box drawing code if we don't want it
293 0 0 0     0 next if !$self->box() && /#START_BOX#/ .. /#STOP_BOX#/;
294              
295 0         0 _output $self->output(), $_;
296             }
297             }
298             }
299              
300             # Building accessors for configuration parameters.
301             # Each key in the hash will be turned into a method that returns the value of
302             # the corresponding attribute or sets it, when called with an argument. If a
303             # value is provided in the hash, the method will yield a default value.
304             {
305             my %attr = (
306             all => 0,
307             box => 1,
308             columns => 2,
309             minwidth => 25,
310             separator => 0,
311             title => undef,
312             color => 0,
313             cdcolor => 0xccd8e5,
314             foldercolor => 0xffff80,
315             output => \*STDOUT,
316             root => '/media/cdrom',
317             );
318              
319             while (my ($meth, $default) = each %attr ) {
320 4     4   28 no strict 'refs';
  4         7  
  4         813  
321             *$meth = sub {
322 4     4   12 my $self = shift;
323 4 100 66     65 ((defined($self->{"_$meth"}) ? $self->{"_$meth"} : $default),
324             @_ && ($self->{"_$meth"} = $_[0]))[0];
325             }
326             }
327             }
328              
329             1;
330              
331             =head1 NAME
332              
333             PostScript::CDCover - a simple module that generates CD covers in Postscript
334              
335             =head1 SYNOPSIS
336              
337             use PostScript::CDCover;
338              
339             my $cd = new PostScript::CDCover -root => 'root', -title => 'Backup';
340             $cd->add_file('root/sub1/file11');
341             $cd->add_file('root/sub1/file12');
342             $cd->add_file('root/sub2/file21');
343             $cd->add_file('root/sub2/file22');
344              
345             $cd->flush();
346              
347             =head1 DESCRIPTION
348              
349             This class generates a Postscript program that prints a CD cover suitable for a
350             CD jewel case. A directory tree is printed on the cover in columns, first on
351             the front page, then on the inner page (the one that is visible when the box is
352             open), and finally on the back label. All in all, the output consists of two A4
353             pages, one for the front and inner pages, and one for the back label. People
354             using exotic paper formats should still be able to print, provided that their
355             paper size is close enough to A4, as the labels are drawn rather far from the
356             paper edge. Notably, printing on Letter has been reported to not cause any
357             trouble.
358              
359             A title is printed on top of the front page, and on the sides of the back
360             label. Various attributes alter the behaviour of the module and the layout of
361             the generated cover.
362              
363             Typically, a program using this module should:
364              
365             =over 4
366              
367             =item *
368              
369             Instantiate the PostScript::CDCover class, possibly giving values to attributes
370             by passing arguments to the constructor. Setting these values can also be
371             achieved by calling the accessor methods directly.
372              
373             =item *
374              
375             Feed information about subdirectories and files in the directory tree by means
376             of the add_directory() and add_file() methods.
377              
378             =item *
379              
380             Call the flush() method to actually generate the Postscript program.
381              
382             =back
383              
384             Such a program (too usable actually to be called a mere example) is shipped
385             with this module: pscdcover(1)
386              
387             =head2 Editing the output
388              
389             The output generated by the flush() method can be directly printed or converted
390             to PDF or whatever. However, it has been designed to be easily modified, even
391             without much knowledge of the Postscript language.
392              
393             The layout of the file and directory names in the different columns and pages
394             is done by the PostScript program. This makes it possible and easy to edit the
395             resulting PostScript program with a text editor and remove some lines.
396              
397             The editable section looks like this (text within parentheses are the files and
398             directory names, the figure that follows it is the depth in the directory tree):
399              
400             (directory 1) 0 folder_title
401             (file 1) 1 file_title
402             (file 2) 1 file_title
403             (file 3) 1 file_title
404             (file 4) 1 file_title
405             (file 5) 1 file_title
406             (file 6) 1 file_title
407             (file 7) 1 file_title
408             (file 8) 1 file_title
409             (file 9) 1 file_title
410             (file 10) 1 file_title
411             (file 11) 1 file_title
412             (file 12) 1 file_title
413             (directory 2) 0 folder_title
414              
415             In order to shorten the list (so that it fits on the three pages, for
416             instance), you may simply change the above to:
417              
418             (directory 1) 0 folder_title
419             (...) 1 file_title
420             (lots of files) 1 file_title
421             (...) 1 file_title
422             (directory 2) 0 folder_title
423              
424             You need not worry about the final layout, whether a directory has changed
425             columns or not, all this is taken care of by the PostScript interpreter.
426              
427             =head2 Constructor
428              
429             new() creates and returns an instance of PostScript::CDCover. new() accepts as
430             arguments a list of key/value pairs to initialize attributes. Each value is
431             simply passed to the method named after the key. The key may optionally be
432             prefixed with a dash, and of course, the use of double-barrel arrows C<< => >>
433             is recommended for readability.
434              
435             These two code snippets are equivalent:
436              
437             my $cd = new PostScript::CDCover;
438             $cd->all(1);
439             $cd->box(1);
440             $cd->files(0);
441              
442             my $cd = new PostScript::CDCover -all => 1, -box => 1, -files => 0;
443              
444             =head2 Attributes
445              
446             Attributes are accessed through accessor methods. These methods, when called
447             without aN ARGUMENt, will return the attribute's value. With an argument, they
448             will set the attribute's value to that argument, and return the former value.
449              
450             When applicable, the default value is given in parentheses.
451              
452             =over 4
453              
454             =item B (I<0>)
455              
456             Forces the printing of all the pages (front and back), even if the whole
457             directory tree could be printed on only the first page.
458              
459             =item B (I<1>)
460              
461             By default, the edges of the cover are drawn in dim gray. Set this to 0 to
462             prevent this (only the text will be printed out). You probably want to leave
463             the default if you use cisors to cut the covers.
464              
465             =item B (I<0>)
466              
467             Generate color output: the CD and folder icons will be drawn in colors. The
468             colors can be changed with the C and C attributes.
469              
470             =item B (I<0xccd8e5>, i.e. light blue)
471              
472             =item B (I<0xffff80>, i.e. light yellow)
473              
474             Colors of the CD icon and folder icon, respectively. They should be the integer
475             value of an hexadecimal triplet representing the shares of red, green and blue
476             in the desired color, like those commonly found in HTML or CSS.
477              
478             =item B (I<2>)
479              
480             The number of columns to print on each page. When set to 0, the column widths
481             will be calculated dynamically, so that the longest filename in each column
482             fits.
483              
484             =item B (I<25>)
485              
486             The minimum allowed width for a column (in millimeters). If the room left on
487             the right side of the page is lower than this limit, the next column will be
488             printed on the next page. This option is only relevant with C set to
489             0.
490              
491             =item B (I<\*STDOUT>)
492              
493             Where the generated PostScript code will be written to. The value can be one
494             of: a file GLOB opened ready for output (the default is C<\*STDOUT>, meaning
495             the standard output), a reference to a scalar to which the output is appended,
496             a reference to a subroutine which is called, passing the output as a parameter,
497             or any object reference which implements a print() method (e.g. IO::Handle)
498             which will be called, passing the generated output as a parameter.
499              
500             =item B
501              
502             The path to the Postscript program. This is actually a template as it requires
503             some processing before being fed to the printer. By default, the template is
504             located in the same directory as the PostScript::CDCover module itself.
505              
506             =item B (I)
507              
508             The directory at the root of the CD-ROM, i.e., its mount point. This value will
509             be removed from entries added with add_directory() or add_file(), so that the
510             CD-ROM mount point does not show on the CD cover.
511              
512             =item B (I<0>)
513              
514             Set this to 1 to draw a line as column separator.
515              
516             =item B (I<undef>) </td> </tr> <tr> <td class="h" > <a name="517">517</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="518">518</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Provides a title for the CD. The title will be printed on top of the first </td> </tr> <tr> <td class="h" > <a name="519">519</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> page, and on the sides of the back label. </td> </tr> <tr> <td class="h" > <a name="520">520</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="521">521</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="522">522</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="523">523</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head2 Methods </td> </tr> <tr> <td class="h" > <a name="524">524</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="525">525</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =over 4 </td> </tr> <tr> <td class="h" > <a name="526">526</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="527">527</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item B<add_directory>(I<path>) </td> </tr> <tr> <td class="h" > <a name="528">528</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="529">529</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item B<add_file>(I<path>) </td> </tr> <tr> <td class="h" > <a name="530">530</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="531">531</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Adds a directory or a file to the CD content. The I<path> argument should start </td> </tr> <tr> <td class="h" > <a name="532">532</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> with the value of attribute root(). Both add_directory() and add_file() will </td> </tr> <tr> <td class="h" > <a name="533">533</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> call add_directory() for any parent directory along the way. Calling </td> </tr> <tr> <td class="h" > <a name="534">534</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> add_directory() is still useful for empty directories, non empty ones would be </td> </tr> <tr> <td class="h" > <a name="535">535</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> created when adding files within. </td> </tr> <tr> <td class="h" > <a name="536">536</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="537">537</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =item B<flush> </td> </tr> <tr> <td class="h" > <a name="538">538</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="539">539</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Generates the Postscript program, taking all the attributes and the contents into account. </td> </tr> <tr> <td class="h" > <a name="540">540</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> flush() can called repeatedly, changing a couple of attributes in between, e.g.: </td> </tr> <tr> <td class="h" > <a name="541">541</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="542">542</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> $cd->color(1); </td> </tr> <tr> <td class="h" > <a name="543">543</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> $cd->flush(); </td> </tr> <tr> <td class="h" > <a name="544">544</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> $cd->color(0); </td> </tr> <tr> <td class="h" > <a name="545">545</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> $cd->flush(); </td> </tr> <tr> <td class="h" > <a name="546">546</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="547">547</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =back </td> </tr> <tr> <td class="h" > <a name="548">548</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="549">549</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 BUGS </td> </tr> <tr> <td class="h" > <a name="550">550</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="551">551</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Very likely. </td> </tr> <tr> <td class="h" > <a name="552">552</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="553">553</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 SEE ALSO </td> </tr> <tr> <td class="h" > <a name="554">554</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="555">555</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> pscdcover(1) </td> </tr> <tr> <td class="h" > <a name="556">556</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="557">557</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =head1 AUTHOR </td> </tr> <tr> <td class="h" > <a name="558">558</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="559">559</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Copyright © 2004 </td> </tr> <tr> <td class="h" > <a name="560">560</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="561">561</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Cédric Bouvier <cbouvi@cpan.org> </td> </tr> <tr> <td class="h" > <a name="562">562</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="563">563</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> Thank you to Terry Gliedt, Sean the RIMBoy, Michael M. Tung for their help with </td> </tr> <tr> <td class="h" > <a name="564">564</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> bug fixing and enhancing, and to Andy Wardley (of Template Toolkit fame) whom I </td> </tr> <tr> <td class="h" > <a name="565">565</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> borrowed the versatile output destination code from. </td> </tr> <tr> <td class="h" > <a name="566">566</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s">   </td> </tr> <tr> <td class="h" > <a name="567">567</a> </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td >   </td> <td class="s"> =cut </td> </tr> </table> </body> </html>