2 # This program is free software; you can redistribute it and/or modify
3 # it under the terms of the GNU General Public License as published by
4 # the Free Software Foundation; either version 2 of the License, or
5 # (at your option) any later version.
7 # This program is distributed in the hope that it will be useful,
8 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # GNU General Public License for more details.
12 # You should have received a copy of the GNU General Public License
13 # along with this program; if not, write to the Free Software
14 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 use Audio
::MPD
::Collection
;
25 use Audio
::MPD
::Status
;
29 use base qw
[ Class
::Accessor
::Fast
];
30 __PACKAGE__
->mk_accessors( qw
[ _host _password _port collection version
] );
33 our $VERSION = '0.14.0';
40 # my $mpd = Audio::MPD->new( [$hostname], [$port], [$password] )
42 # This is the constructor for Audio::MPD. One can specify a $hostname, a
43 # $port, and a $password.
44 # If none is specified then defaults to environment vars MPD_HOST, MPD_PORT
45 # and MPD_PASSWORD. If those aren't set, defaults to 'localhost', 6600 and ''.
49 my ($host, $port, $password) = @_;
52 $host = $ENV{MPD_HOST
} || 'localhost' unless defined $host;
53 $port = $ENV{MPD_PORT
} || '6600' unless defined $port;
54 $password = $ENV{MPD_PASSWORD
} || '' unless defined $password;
56 # create & bless the object.
60 _password
=> $password,
64 # create the collection object and store it.
65 $self->collection( Audio
::MPD
::Collection
->new($self) );
67 # try to issue a ping to test connection - this can die.
79 # my @result = $mpd->_send_command( $command );
81 # This method is central to the module. It is responsible for interacting with
82 # mpd by sending the $command and reading output - that will be returned as an
83 # array of chomped lines (status line will not be returned).
85 # Note that currently, this method will connect to mpd before sending any
86 # command, and will disconnect after the command has been issued. This scheme
87 # is far from optimal, but allows us not to care about timeout disconnections.
89 # /!\ Note that we're using high-level, blocking sockets. This means that if
90 # the mpd server is slow, or hangs for whatever reason, or even crash abruptly,
91 # the program will be hung forever in this sub. The POE::Component::Client::MPD
92 # module is way safer - you're advised to use it instead of Audio::MPD.
94 # This method can die on several conditions:
95 # - if the server cannot be reached,
96 # - if it's not an mpd server,
97 # - if the password is incorrect,
98 # - or if the command is an invalid mpd command.
99 # In the latter case, the mpd error message will be returned.
102 my ($self, $command) = @_;
104 # try to connect to mpd.
105 my $socket = IO
::Socket
::INET
->new(
106 PeerAddr
=> $self->_host,
107 PeerPort
=> $self->_port
109 or die "Could not create socket: $!\n";
112 # parse version information.
113 $line = $socket->getline;
115 die "Not a mpd server - welcome string was: [$line]\n"
116 if $line !~ /^OK MPD (.+)$/;
120 if ( $self->_password ) {
121 $socket->print( 'password ' . $self->_password . "\n" );
122 $line = $socket->getline;
123 die $line if $line =~ s/^ACK //;
126 # ok, now we're connected - let's issue the command.
127 $socket->print( $command );
129 while (defined ( $line = $socket->getline ) ) {
131 die $line if $line =~ s/^ACK //; # oops - error.
132 last if $line =~ /^OK/; # end of output.
147 # -- MPD interaction: general commands
152 # Sends a ping command to the mpd server.
156 $self->_send_command( "ping\n" );
161 # my $version = $mpd->version;
163 # Return version of MPD server's connected.
165 # sub version {} # implemented as an accessor.
172 # Send a message to the MPD server telling it to shut down.
176 $self->_send_command("kill\n");
181 # $mpd->password( [$password] )
183 # Change password used to communicate with MPD server to $password.
184 # Empty string is assumed if $password is not supplied.
187 my ($self, $passwd) = @_;
189 $self->_password($passwd);
190 $self->ping; # ping sends a command, and thus the password is sent
195 # $mpd->updatedb( [$path] );
197 # Force mpd to recan its collection. If $path (relative to MPD's music
198 # directory) is supplied, MPD will only scan it - otherwise, MPD will rescan
199 # its whole collection.
202 my ($self, $path) = @_;
204 $self->_send_command("update $path\n");
209 # my @handlers = $mpd->urlhandlers;
211 # Return an array of supported URL schemes.
216 map { /^handler: (.+)$/ ?
$1 : () }
217 $self->_send_command("urlhandlers\n");
222 # -- MPD interaction: handling volume & output
225 # $mpd->volume( [+][-]$volume );
227 # Sets the audio output volume percentage to absolute $volume.
228 # If $volume is prefixed by '+' or '-' then the volume is changed relatively
232 my ($self, $volume) = @_;
234 if ($volume =~ /^(-|\+)(\d+)/ ) {
235 my $current = $self->status->volume;
236 $volume = $1 eq '+' ?
$current + $2 : $current - $2;
238 $self->_send_command("setvol $volume\n");
243 # $mpd->output_enable( $output );
245 # Enable the specified audio output. $output is the ID of the audio output.
248 my ($self, $output) = @_;
249 $self->_send_command("enableoutput $output\n");
254 # $mpd->output_disable( $output );
256 # Disable the specified audio output. $output is the ID of the audio output.
259 my ($self, $output) = @_;
260 $self->_send_command("disableoutput $output\n");
265 # -- MPD interaction: retrieving info from current state
270 # Return a hashref with the number of artists, albums, songs in the database,
271 # as well as mpd uptime, the playtime of the playlist / the database and the
272 # last update of the database.
277 map { /^([^:]+):\s+(\S+)$/ ?
($1 => $2) : () }
278 $self->_send_command( "stats\n" );
284 # my $status = $mpd->status;
286 # Return an Audio::MPD::Status object with various information on current
287 # MPD server settings. Check the embedded pod for more information on the
288 # available accessors.
292 my @output = $self->_send_command( "status\n" );
293 my $status = Audio
::MPD
::Status
->new( @output );
299 # my $list = $mpd->playlist;
301 # Return an arrayref of C<Audio::MPD::Item::Song>s, one for each of the
302 # songs in the current playlist.
307 my @lines = $self->_send_command("playlistinfo\n");
310 # parse lines in reverse order since "file:" comes first.
311 # therefore, let's first store every other parameter, and
312 # the "file:" line will trigger the object creation.
313 # of course, since we want to preserve the playlist order,
314 # this means that we're going to unshift the objects.
315 foreach my $line (reverse @lines) {
316 next unless $line =~ /^([^:]+):\s+(.+)$/;
318 next unless $1 eq 'file'; # last param of this item
319 unshift @list, Audio
::MPD
::Item
->new(%param);
327 # my $list = $mpd->pl_changes( $plversion );
329 # Return a list with all the songs (as API::Song objects) added to
330 # the playlist since playlist $plversion.
333 my ($self, $plid) = @_;
335 my @lines = $self->_send_command("plchanges $plid\n");
338 # parse lines in reverse order since "file:" comes first.
339 # therefore, let's first store every other parameter, and
340 # the "file:" line will trigger the object creation.
341 # of course, since we want to preserve the playlist order,
342 # this means that we're going to unshift the objects.
343 foreach my $line (reverse @lines) {
344 next unless $line =~ /^([^:]+):\s+(.+)$/;
346 next unless $1 eq 'file'; # last param of this item
347 unshift @list, Audio
::MPD
::Item
->new(%param);
355 # my $song = $mpd->current;
357 # Return an C<Audio::MPD::Item::Song> representing the song currently playing.
361 my @output = $self->_send_command("currentsong\n");
362 my %params = map { /^([^:]+):\s+(.+)$/ ?
($1=>$2) : () } @output;
363 return Audio
::MPD
::Item
->new( %params );
368 # my $song = $mpd->song( [$song] )
370 # Return an C<Audio::MPD::Item::Song> representing the song number C<$song>.
371 # If C<$song> is not supplied, returns the current song.
374 my ($self, $song) = @_;
375 return $self->current unless defined $song;
376 my @output = $self->_send_command("playlistinfo $song\n");
377 my %params = map { /^([^:]+):\s+(.+)$/ ?
($1=>$2) : () } @output;
378 return Audio
::MPD
::Item
->new( %params );
383 # my $song = $mpd->songid( [$songid] )
385 # Return an C<Audio::MPD::Item::Song> representing the song with id C<$songid>.
386 # If C<$songid> is not supplied, returns the current song.
389 my ($self, $songid) = @_;
390 return $self->current unless defined $songid;
391 my @output = $self->_send_command("playlistid $songid\n");
392 my %params = map { /^([^:]+):\s+(.+)$/ ?
($1=>$2) : () } @output;
393 return Audio
::MPD
::Item
->new( %params );
397 # -- MPD interaction: altering settings
400 # $mpd->repeat( [$repeat] );
402 # Set the repeat mode to $repeat (1 or 0). If $repeat is not specified then
403 # the repeat mode is toggled.
406 my ($self, $mode) = @_;
408 $mode = not $self->status->repeat
409 unless defined $mode; # toggle if no param
410 $mode = $mode ?
1 : 0; # force integer
411 $self->_send_command("repeat $mode\n");
416 # $mpd->random( [$random] );
418 # Set the random mode to $random (1 or 0). If $random is not specified then
419 # the random mode is toggled.
422 my ($self, $mode) = @_;
424 $mode = not $self->status->random
425 unless defined $mode; # toggle if no param
426 $mode = $mode ?
1 : 0; # force integer
427 $self->_send_command("random $mode\n");
432 # $mpd->fade( [$seconds] );
434 # Enable crossfading and set the duration of crossfade between songs. If
435 # $seconds is not specified or $seconds is 0, then crossfading is disabled.
438 my ($self, $value) = @_;
440 $self->_send_command("crossfade $value\n");
444 # -- MPD interaction: controlling playback
447 # $mpd->play( [$song] );
449 # Begin playing playlist at song number $song. If no argument supplied,
453 my ($self, $number) = @_;
455 $self->_send_command("play $number\n");
459 # $mpd->playid( [$songid] );
461 # Begin playing playlist at song ID $songid. If no argument supplied,
465 my ($self, $number) = @_;
467 $self->_send_command("playid $number\n");
472 # $mpd->pause( [$sate] );
474 # Pause playback. If $state is 0 then the current track is unpaused, if
475 # $state is 1 then the current track is paused.
477 # Note that if $state is not given, pause state will be toggled.
480 my ($self, $state) = @_;
481 $state ||= ''; # default is to toggle
482 $self->_send_command("pause $state\n");
493 $self->_send_command("stop\n");
500 # Play next song in playlist.
504 $self->_send_command("next\n");
510 # Play previous song in playlist.
514 $self->_send_command("previous\n");
519 # $mpd->seek( $time, [$song]);
521 # Seek to $time seconds in song number $song. If $song number is not specified
522 # then the perl module will try and seek to $time in the current song.
525 my ($self, $time, $song) = @_;
526 $time ||= 0; $time = int $time;
527 $song = $self->status->song if not defined $song; # seek in current song
528 $self->_send_command( "seek $song $time\n" );
533 # $mpd->seekid( $time, $songid );
535 # Seek to $time seconds in song ID $songid. If $song number is not specified
536 # then the perl module will try and seek to $time in the current song.
539 my ($self, $time, $song) = @_;
540 $time ||= 0; $time = int $time;
541 $song = $self->status->songid if not defined $song; # seek in current song
542 $self->_send_command( "seekid $song $time\n" );
546 # -- MPD interaction: handling playlist
549 # $mpd->add( $path );
551 # Add the song identified by $path (relative to MPD's music directory) to
552 # the current playlist. No return value.
555 my ($self, $path) = @_;
556 $self->_send_command( qq[add
"$path"\n] );
561 # $mpd->delete( $song [, $song [...] ] );
563 # Remove song number $song from the current playlist. No return value.
566 my ($self, @songs) = @_;
568 "command_list_begin\n"
569 . join( '', map { "delete $_\n" } @songs )
570 . "command_list_end\n";
571 $self->_send_command( $command );
576 # $mpd->deleteid( $songid [, $songid [...] ]);
578 # Remove the specified $songid from the current playlist. No return value.
581 my ($self, @songs) = @_;
583 "command_list_begin\n"
584 . join( '', map { "deleteid $_\n" } @songs )
585 . "command_list_end\n";
586 $self->_send_command( $command );
593 # Remove all the songs from the current playlist. No return value.
597 $self->_send_command("clear\n");
604 # Remove all of the songs from the current playlist *except* the current one.
609 my $status = $self->status;
610 my $cur = $status->song;
611 my $len = $status->playlistlength - 1;
614 "command_list_begin\n"
615 . join( '', map { $_ != $cur ?
"delete $_\n" : '' } reverse 0..$len )
616 . "command_list_end\n";
617 $self->_send_command( $command );
623 my ($self, $from, $to) = @_;
624 $self->_send_command("swap $from $to\n");
628 my ($self, $from, $to) = @_;
629 $self->_send_command("swapid $from $to\n");
634 $self->_send_command("shuffle\n");
638 my ($self, $song, $pos) = @_;
639 $self->_send_command("move $song $pos\n");
643 my ($self, $song, $pos) = @_;
644 $self->_send_command("moveid $song $pos\n");
648 my ($self, $playlist) = @_;
649 return unless defined $playlist;
650 $self->_send_command( qq[load
"$playlist"\n] );
654 my ($self, $playlist) = @_;
655 return unless defined $playlist;
656 $self->_send_command( qq[save
"$playlist"\n] );
660 if(!$self->_process_feedback)
662 # Does the playlist already exist?
663 if(${$self->get_error}[0] eq '56' && $config{'OVERWRITE_PLAYLIST'})
665 $self->rm($playlist);
666 $self->save($playlist);
679 my ($self, $playlist) = @_;
680 return unless defined $playlist;
681 $self->_send_command( qq[rm
"$playlist"\n] );
688 # -- MPD interaction: searching collection
691 # my @songs = $mpd->search( $type, $string, [$strict] );
693 # Search through MPD's database of music for matching songs, and return a
694 # list of associated Audio::MPD::Item::Song.
696 # $type is the field to search in: "title","artist","album", or "filename",
697 # and $string is the keyword(s) to seach for. If $strict is true then only
698 # exact matches are returned.
701 my ($self, $type, $string, $strict) = @_;
703 my $command = (!defined($strict) || $strict == 0 ?
'search' : 'find');
704 my @lines = $self->_send_command( qq[$command $type "$string"\n] );
707 # parse lines in reverse order since "file:" comes first.
708 # therefore, let's first store every other parameter, and
709 # the "file:" line will trigger the object creation.
710 # of course, since we want to preserve the playlist order,
711 # this means that we're going to unshift the objects.
712 foreach my $line (reverse @lines) {
713 next unless $line =~ /^([^:]+):\s+(.+)$/;
715 next unless $1 eq 'file'; # last param of this item
716 unshift @list, Audio
::MPD
::Item
->new(%param);
724 ###############################################################
726 #-------------------------------------------------------------#
727 # This section contains all methods not directly accessing #
728 # MPD, but may be useful for most people using the module. #
729 ###############################################################
732 my ($self, $type, $string) = @_;
733 my @results = $self->search($type, $string);
735 return unless @results;
738 "command_list_begin\n"
739 . join( '', map { qq[add
"$_->{file}"\n] } @results )
740 . "command_list_end\n";
741 $self->_send_command( $command );
746 sub get_time_format
{
749 # Get the time from MPD; example: 49:395 (seconds so far:total seconds)
750 my ($sofar, $total) = split /:/, $self->status->time;
751 return sprintf "%d:%02d/%d:%02d",
752 ($sofar / 60), # minutes so far
753 ($sofar % 60), # seconds - minutes so far
754 ($total / 60), # minutes total
755 ($total % 60);# seconds - minutes total
761 # Get the time from MPD; example: 49:395 (seconds so far:total seconds)
762 my ($sofar, $total) = split /:/, $self->status->time;
763 my $left = $total - $sofar;
765 # Store seconds for everything
767 $rv->{seconds_so_far
} = $sofar;
768 $rv->{seconds_total
} = $total;
769 $rv->{seconds_left
} = $left;
771 # Store the percentage; use one decimal point
774 ?
100*$rv->{seconds_so_far
}/$rv->{seconds_total
}
776 $rv->{percentage
} = sprintf "%.1f",$rv->{percentage
};
779 # Parse the time so far
780 my $min_so_far = ($sofar / 60);
781 my $sec_so_far = ($sofar % 60);
783 $rv->{time_so_far
} = sprintf("%d:%02d", $min_so_far, $sec_so_far);
784 $rv->{minutes_so_far
} = sprintf("%00d", $min_so_far);
785 $rv->{seconds_so_far
} = sprintf("%00d", $sec_so_far);
788 # Parse the total time
789 my $min_tot = ($total / 60);
790 my $sec_tot = ($total % 60);
792 $rv->{time_total
} = sprintf("%d:%02d", $min_tot, $sec_tot);
793 $rv->{minutes
} = $min_tot;
794 $rv->{seconds
} = $sec_tot;
796 # Parse the time left
797 my $min_left = ($left / 60);
798 my $sec_left = ($left % 60);
799 $rv->{time_left
} = sprintf("-%d:%02d", $min_left, $sec_left);
815 Audio::MPD - Class for talking to MPD (Music Player Daemon) servers
822 my $mpd = Audio::MPD->new();
830 Audio::MPD gives a clear object-oriented interface for talking to and
831 controlling MPD (Music Player Daemon) servers. A connection to the MPD
832 server is established as soon as a new Audio::MPD object is created.
833 Commands are then sent to the server as the class's methods are called.
842 =item new( [$host] [, $port] [, $password] )
844 This is the constructor for Audio::MPD. One can specify a $hostname, a
845 $port, and a $password.
847 If none is specified then defaults to environment vars MPD_HOST, MPD_PORT
848 and MPD_PASSWORD. If those aren't set, defaults to 'localhost', 6600 and ''.
853 =head2 Controlling the server
859 Sends a ping command to the mpd server.
862 =item $mpd->version()
864 Return the version number for the server we are connected to.
869 Send a message to the MPD server telling it to shut down.
872 =item $mpd->password( [$password] )
874 Change password used to communicate with MPD server to $password.
875 Empty string is assumed if $password is not supplied.
878 =item $mpd->updatedb( [$path] )
880 Force mpd to recan its collection. If $path (relative to MPD's music directory)
881 is supplied, MPD will only scan it - otherwise, MPD will rescan its whole
885 =item $mpd->urlhandlers()
887 Return an array of supported URL schemes.
893 =head2 Handling volume & output
897 =item $mpd->volume( [+][-]$volume )
899 Sets the audio output volume percentage to absolute $volume.
900 If $volume is prefixed by '+' or '-' then the volume is changed relatively
904 =item $mpd->output_enable( $output )
906 Enable the specified audio output. $output is the ID of the audio output.
909 =item $mpd->output_disable( $output )
911 Disable the specified audio output. $output is the ID of the audio output.
916 =head2 Retrieving info from current state
922 Return a hashref with the number of artists, albums, songs in the database,
923 as well as mpd uptime, the playtime of the playlist / the database and the
924 last update of the database
929 Return an C<Audio::MPD::Status> object with various information on current
930 MPD server settings. Check the embedded pod for more information on the
934 =item $mpd->playlist( )
936 Return an arrayref of C<Audio::MPD::Item::Song>s, one for each of the
937 songs in the current playlist.
940 =item $mpd->pl_changes( $plversion )
942 Return a list with all the songs (as API::Song objects) added to
943 the playlist since playlist $plversion.
946 =item $mpd->current( )
948 Return an C<Audio::MPD::Item::Song> representing the song currently playing.
951 =item $mpd->song( [$song] )
953 Return an C<Audio::MPD::Item::Song> representing the song number C<$song>. If
954 C<$song> is not supplied, returns the current song.
957 =item $mpd->songid( [$songid] )
959 Return an C<Audio::MPD::Item::Song> representing the song with id C<$songid>.
960 If C<$songid> is not supplied, returns the current song.
965 =head2 Altering MPD settings
969 =item $mpd->repeat( [$repeat] )
971 Set the repeat mode to $repeat (1 or 0). If $repeat is not specified then
972 the repeat mode is toggled.
975 =item $mpd->random( [$random] )
977 Set the random mode to $random (1 or 0). If $random is not specified then
978 the random mode is toggled.
981 =item $mpd->fade( [$seconds] )
983 Enable crossfading and set the duration of crossfade between songs.
984 If $seconds is not specified or $seconds is 0, then crossfading is disabled.
989 =head2 Controlling playback
993 =item $mpd->play( [$song] )
995 Begin playing playlist at song number $song. If no argument supplied,
999 =item $mpd->playid( [$songid] )
1001 Begin playing playlist at song ID $songid. If no argument supplied,
1005 =item $mpd->pause( [$state] )
1007 Pause playback. If C<$state> is 0 then the current track is unpaused,
1008 if $state is 1 then the current track is paused.
1010 Note that if C<$state> is not given, pause state will be toggled.
1020 Play next song in playlist.
1025 Play previous song in playlist.
1028 =item $mpd->seek( $time, [$song])
1030 Seek to $time seconds in song number $song. If $song number is not specified
1031 then the perl module will try and seek to $time in the current song.
1034 =item $mpd->seekid( $time, $songid )
1036 Seek to $time seconds in song ID $songid. If $song number is not specified
1037 then the perl module will try and seek to $time in the current song.
1042 =head2 Handling playlist
1046 =item $mpd->add( $path )
1048 Add the song identified by $path (relative to MPD's music directory) to the
1049 current playlist. No return value.
1052 =item $mpd->delete( $song )
1054 Remove song number $song from the current playlist. No return value.
1057 =item $mpd->deleteid( $songid )
1059 Remove the specified $songid from the current playlist. No return value.
1064 Remove all the songs from the current playlist. No return value.
1069 Remove all of the songs from the current playlist *except* the
1070 song currently playing.
1073 =item $mpd->swap( $song1, $song2 )
1075 Swap positions of song number $song1 and $song2 on the current playlist. No
1079 =item $mpd->swapid( $songid1, $songid2 )
1081 Swap the postions of song ID $songid1 with song ID $songid2 on the current
1082 playlist. No return value.
1085 =item $mpd->move( $song, $newpos )
1087 Move song number $song to the position $newpos. No return value.
1090 =item $mpd->moveid( $songid, $newpos )
1092 Move song ID $songid to the position $newpos. No return value.
1095 =item $mpd->shuffle()
1097 Shuffle the current playlist. No return value.
1100 =item $mpd->load( $playlist )
1102 Load list of songs from specified $playlist file. No return value.
1105 =item $mpd->save( $playlist )
1107 Save the current playlist to a file called $playlist in MPD's playlist
1108 directory. No return value.
1111 =item $mpd->rm( $playlist )
1113 Delete playlist named $playlist from MPD's playlist directory. No return value.
1118 =head2 Retrieving information from current playlist
1122 =item $mpd->get_time_format( )
1124 Returns the current position and duration of the current song.
1125 String is formatted at "M:SS/M:SS", with current time first and total time
1129 =item $mpd->get_time_info( )
1131 Return current timing information in various different formats
1132 contained in a hashref with the following keys:
1136 =item minutes_so_far
1138 =item seconds_so_far
1161 =head2 Searching the collection
1163 To search the collection, use the C<collection()> accessor, returning the
1164 associated C<Audio::MPD::Collection> object. You will then be able to call:
1166 $mpd->collection->random_song();
1168 See C<Audio::MPD::Collection> documentation for more details on available
1173 =item $mpd->search( $type, $string, [$strict] )
1175 Search through MPD's database of music for matching songs, and return a
1176 list of associated Audio::MPD::Item::Song.
1178 $type is the field to search in: "title","artist","album", or "filename", and
1179 $string is the keyword(s) to seach for. If $strict is true then only exact
1180 matches are returned.
1183 =item $mpd->searchadd( $type, $string )
1185 Perform the same action as $mpd->search(), but add any
1186 matching songs to the current playlist, instead of just returning
1187 information about them.
1195 You can find more information on the mpd project on its homepage at
1196 L<http://www.musicpd.org>, or its wiki L<http://mpd.wikia.com>.
1198 Regarding this Perl module, you can report bugs on CPAN via
1199 L<http://rt.cpan.org/Public/Bug/Report.html?Queue=Audio-MPD>.
1201 Audio::MPD development takes place on <audio-mpd@googlegroups.com>: feel free
1202 to join us. (use L<http://groups.google.com/group/audio-mpd> to sign in). Our
1203 subversion repository is located at L<https://svn.musicpd.org>.
1209 Jerome Quelin <jquelin@cpan.org>
1211 Original code by Tue Abrahamsen <tue.abrahamsen@gmail.com>, documented by
1212 Nicholas J. Humfrey <njh@aelius.com>.
1216 =head1 COPYRIGHT AND LICENSE
1218 Copyright (c) 2005 Tue Abrahamsen <tue.abrahamsen@gmail.com>
1220 Copyright (c) 2006 Nicholas J. Humfrey <njh@aelius.com>
1222 Copyright (c) 2007 Jerome Quelin <jquelin@cpan.org>
1225 This program is free software; you can redistribute it and/or modify
1226 it under the terms of the GNU General Public License as published by
1227 the Free Software Foundation; either version 2 of the License, or
1228 (at your option) any later version.
1230 This program is distributed in the hope that it will be useful,
1231 but WITHOUT ANY WARRANTY; without even the implied warranty of
1232 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1233 GNU General Public License for more details.