File Coverage

blib/lib/Bio/Phylo/Listable.pm
Criterion Covered Total %
statement 158 212 74.5
branch 31 64 48.4
condition 17 28 60.7
subroutine 33 40 82.5
pod 22 22 100.0
total 261 366 71.3


line stmt bran cond sub pod time code
1             package Bio::Phylo::Listable;
2 51     51   337 use strict;
  51         92  
  51         1250  
3 51     51   253 use warnings;
  51         82  
  51         1038  
4 51     51   14646 use Bio::Phylo::ListableRole;
  51         147  
  51         309  
5 51     51   330 use base 'Bio::Phylo::ListableRole';
  51         105  
  51         5016  
6 51     51   320 use Bio::Phylo::Util::Exceptions 'throw';
  51         101  
  51         2030  
7 51     51   284 use Bio::Phylo::Util::CONSTANT qw':all';
  51         91  
  51         43148  
8              
9             {
10             my $logger = __PACKAGE__->get_logger;
11              
12             # $fields array necessary for object destruction
13             my @fields = \(
14             my (
15             %entities, # XXX strong reference
16             %index,
17             %listeners,
18             %sets,
19             )
20             );
21              
22              
23             =head1 NAME
24              
25             Bio::Phylo::Listable - List of things, super class for many objects
26              
27             =head1 SYNOPSIS
28              
29             No direct usage, parent class. Methods documented here
30             are available for all objects that inherit from it.
31              
32             =head1 DESCRIPTION
33              
34             A listable object is an object that contains multiple smaller objects of the
35             same type. For example: a tree contains nodes, so it's a listable object.
36              
37             This class contains methods that are useful for all listable objects: Matrices
38             (i.e. sets of matrix objects), individual Matrix objects, Datum objects (i.e.
39             character state sequences), Taxa, Forest, Tree and Node objects.
40              
41             =head1 METHODS
42              
43             =head2 ARRAY METHODS
44              
45             =over
46              
47             =item insert()
48              
49             Pushes an object into its container.
50              
51             Type : Mutator
52             Title : insert
53             Usage : $obj->insert($other_obj);
54             Function: Pushes an object into its container.
55             Returns : A Bio::Phylo::Listable object.
56             Args : A Bio::Phylo::* object.
57              
58             =cut
59              
60             sub insert {
61 10526     10526 1 28541 my ( $self, @obj ) = @_;
62 10526 100 100     36906 if ( @obj and $self->can_contain(@obj) ) {
63 10513         21529 my $id = $self->get_id;
64 10513         14138 push @{ $entities{$id} }, @obj;
  10513         38194  
65 10513         18617 for (@obj) {
66 93117 100 66     170795 ref $_ && UNIVERSAL::can($_,'_set_container') && $_->_set_container($self);
67             }
68             $self->notify_listeners( 'insert', @obj )
69 10513 100 66     27925 if $listeners{$id} and @{ $listeners{$id} };
  9543         41271  
70 10513         27138 return $self;
71             }
72             else {
73 13         86 throw 'ObjectMismatch' => "Failed insertion: [@obj] in [$self]";
74             }
75             }
76              
77             =item insert_at_index()
78              
79             Inserts argument object in container at argument index.
80              
81             Type : Mutator
82             Title : insert_at_index
83             Usage : $obj->insert_at_index($other_obj, $i);
84             Function: Inserts $other_obj at index $i in container $obj
85             Returns : A Bio::Phylo::Listable object.
86             Args : A Bio::Phylo::* object.
87              
88             =cut
89              
90             sub insert_at_index {
91 9831     9831 1 16627 my ( $self, $obj, $index ) = @_;
92 9831         49183 $logger->debug("inserting '$obj' in '$self' at index $index");
93 9831 50 33     33949 if ( defined $obj and $self->can_contain($obj) ) {
94 9831         19585 my $id = $self->get_id;
95 9831         23508 $entities{$id}->[$index] = $obj;
96 9831 100       21594 if ( looks_like_implementor( $obj, '_set_container' ) ) {
97 9817         24218 $obj->_set_container($self);
98             }
99             $self->notify_listeners( 'insert_at_index', $obj )
100 9831 50 33     23625 if $listeners{$id} and @{ $listeners{$id} };
  0         0  
101 9831         22348 return $self;
102             }
103             else {
104 0         0 throw 'ObjectMismatch' => 'Failed insertion!';
105             }
106             }
107              
108             =item delete()
109              
110             Deletes argument from container.
111              
112             Type : Mutator
113             Title : delete
114             Usage : $obj->delete($other_obj);
115             Function: Deletes an object from its container.
116             Returns : A Bio::Phylo::Listable object.
117             Args : A Bio::Phylo::* object.
118             Note : Be careful with this method: deleting
119             a node from a tree like this will
120             result in undefined references in its
121             neighbouring nodes. Its children will
122             have their parent reference become
123             undef (instead of pointing to their
124             grandparent, as collapsing a node would
125             do). The same is true for taxon objects
126             that reference datum objects: if the
127             datum object is deleted from a matrix
128             (say), the taxon will now hold undefined
129             references.
130              
131             =cut
132              
133             sub delete {
134 653     653 1 969 my ( $self, $obj ) = @_;
135 653         1226 my $id = $self->get_id;
136 653 50       1651 if ( $self->can_contain($obj) ) {
137 653         1208 my $object_id = $obj->get_id;
138 653         934 my $occurence_counter = 0;
139 653 50       1591 if ( my $i = $index{$id} ) {
140 0         0 for my $j ( 0 .. $i ) {
141 0 0       0 if ( $entities{$id}->[$j]->get_id == $object_id ) {
142 0         0 $occurence_counter++;
143             }
144             }
145             }
146             my @modified =
147 653         820 grep { $_->get_id != $object_id } @{ $entities{$id} };
  58987         95112  
  653         1278  
148 653         2623 $entities{$id} = \@modified;
149 653         1469 $index{$id} -= $occurence_counter;
150             }
151             else {
152 0         0 throw 'ObjectMismatch' =>
153             "Invocant object cannot contain argument object";
154             }
155             $self->notify_listeners( 'delete', $obj )
156 653 100 66     1772 if $listeners{$id} and @{ $listeners{$id} };
  274         1428  
157 653         1467 return $self;
158             }
159              
160             =item clear()
161              
162             Empties container object.
163              
164             Type : Mutator
165             Title : clear
166             Usage : $obj->clear();
167             Function: Clears the container.
168             Returns : A Bio::Phylo::Listable object.
169             Args : Note.
170             Note :
171              
172             =cut
173              
174             sub clear {
175 745     745 1 1030 my $self = shift;
176 745         1330 my $id = $self->get_id;
177 745         1583 $entities{$id} = [];
178             $self->notify_listeners('clear')
179 745 100 66     1864 if $listeners{$id} and @{ $listeners{$id} };
  75         344  
180 745         1175 return $self;
181             }
182              
183             =item keep_entities()
184              
185             Keeps the container's contents specified by an array reference of indices.
186              
187             Type : Mutator
188             Title : keep_entities
189             Usage : $list->keep_entities([9,7,7,6]);
190             Function: Keeps a subset of contents
191             Returns : A Bio::Phylo::Listable object.
192             Args : An array reference of indices
193              
194             =cut
195              
196             sub keep_entities {
197 20     20 1 25 my ( $self, $indices_array_ref ) = @_;
198 20         38 my $id = $self->get_id;
199 20   50     37 my $ent = $entities{$id} || [];
200 20         26 my @contents = @{$ent};
  20         38  
201 20         28 my @pruned = @contents[ @{$indices_array_ref} ];
  20         40  
202 20         28 $entities{$id} = \@pruned;
203 20         48 return $self;
204             }
205              
206             =item get_entities()
207              
208             Returns a reference to an array of objects contained by the listable object.
209              
210             Type : Accessor
211             Title : get_entities
212             Usage : my @entities = @{ $obj->get_entities };
213             Function: Retrieves all entities in the container.
214             Returns : A reference to a list of Bio::Phylo::*
215             objects.
216             Args : none.
217              
218             =cut
219              
220             sub get_entities {
221 155892   100 155892 1 269661 return $entities{ $_[0]->get_id } || [];
222             }
223            
224 56     56   117 sub _get_things { $entities{shift->get_id} }
225             sub _set_things : Clonable DeepClonable {
226 56     56   81 my ( $self, $things ) = @_;
227 56         119 $entities{$self->get_id} = $things;
228 56         172 $self->notify_listeners( '_set_things', $things );
229 56         114 return $self;
230 51     51   399 }
  51         127  
  51         255  
231              
232             =back
233              
234             =head2 ITERATOR METHODS
235              
236             =over
237              
238             =item first()
239              
240             Jumps to the first element contained by the listable object.
241              
242             Type : Iterator
243             Title : first
244             Usage : my $first_obj = $obj->first;
245             Function: Retrieves the first
246             entity in the container.
247             Returns : A Bio::Phylo::* object
248             Args : none.
249              
250             =cut
251              
252             sub first {
253 73     73 1 201 my $self = shift;
254 73         202 my $id = $self->get_id;
255 73         202 $index{$id} = 0;
256 73         341 return $entities{$id}->[0];
257             }
258              
259             =item last()
260              
261             Jumps to the last element contained by the listable object.
262              
263             Type : Iterator
264             Title : last
265             Usage : my $last_obj = $obj->last;
266             Function: Retrieves the last
267             entity in the container.
268             Returns : A Bio::Phylo::* object
269             Args : none.
270              
271             =cut
272              
273             sub last {
274 1     1 1 2 my $self = shift;
275 1         3 my $id = $self->get_id;
276 1         2 $index{$id} = $#{ $entities{$id} };
  1         4  
277 1         4 return $entities{$id}->[-1];
278             }
279              
280             =item current()
281              
282             Returns the current focal element of the listable object.
283              
284             Type : Iterator
285             Title : current
286             Usage : my $current_obj = $obj->current;
287             Function: Retrieves the current focal
288             entity in the container.
289             Returns : A Bio::Phylo::* object
290             Args : none.
291              
292             =cut
293              
294             sub current {
295 0     0 1 0 my $self = shift;
296 0         0 my $id = $self->get_id;
297 0 0       0 if ( !defined $index{$id} ) {
298 0         0 $index{$id} = 0;
299             }
300 0         0 return $entities{$id}->[ $index{$id} ];
301             }
302              
303             =item next()
304              
305             Returns the next focal element of the listable object.
306              
307             Type : Iterator
308             Title : next
309             Usage : my $next_obj = $obj->next;
310             Function: Retrieves the next focal
311             entity in the container.
312             Returns : A Bio::Phylo::* object
313             Args : none.
314              
315             =cut
316              
317             sub next {
318 0     0 1 0 my $self = shift;
319 0         0 my $id = $self->get_id;
320 0 0       0 if ( !defined $index{$id} ) {
    0          
321 0         0 $index{$id} = 0;
322 0         0 return $entities{$id}->[ $index{$id} ];
323             }
324 0         0 elsif ( ( $index{$id} + 1 ) <= $#{ $entities{$id} } ) {
325 0         0 $index{$id}++;
326 0         0 return $entities{$id}->[ $index{$id} ];
327             }
328             else {
329 0         0 return;
330             }
331             }
332              
333             =item previous()
334              
335             Returns the previous element of the listable object.
336              
337             Type : Iterator
338             Title : previous
339             Usage : my $previous_obj = $obj->previous;
340             Function: Retrieves the previous
341             focal entity in the container.
342             Returns : A Bio::Phylo::* object
343             Args : none.
344              
345             =cut
346              
347             sub previous {
348 0     0 1 0 my $self = shift;
349 0         0 my $id = $self->get_id;
350              
351             # either undef or 0
352 0 0       0 if ( !$index{$id} ) {
    0          
353 0         0 return;
354             }
355             elsif ( 1 <= $index{$id} ) {
356 0         0 $index{$id}--;
357 0         0 return $entities{$id}->[ $index{$id} ];
358             }
359             else {
360 0         0 return;
361             }
362             }
363              
364             =item current_index()
365              
366             Returns the current internal index of the container.
367              
368             Type : Accessor
369             Title : current_index
370             Usage : my $last_index = $obj->current_index;
371             Function: Returns the current internal
372             index of the container or 0
373             Returns : An integer
374             Args : none.
375              
376             =cut
377              
378 0 0   0 1 0 sub current_index { $index{ ${ $_[0] } } || 0 }
  0         0  
379              
380 56     56   109 sub _get_index { $index{shift->get_id} }
381              
382             sub _set_index : Clonable {
383 56     56   87 my ( $self, $idx ) = @_;
384 56         92 $index{ $self->get_id } = $idx;
385 56         109 return $self;
386 51     51   27005 }
  51         133  
  51         213  
387              
388             =item last_index()
389              
390             Returns the highest valid index of the container.
391              
392             Type : Generic query
393             Title : last_index
394             Usage : my $last_index = $obj->last_index;
395             Function: Returns the highest valid
396             index of the container.
397             Returns : An integer
398             Args : none.
399              
400             =cut
401              
402 0     0 1 0 sub last_index { $#{ $entities{ ${ $_[0] } } } }
  0         0  
  0         0  
403              
404             =back
405              
406             =head2 UTILITY METHODS
407              
408             =over
409              
410             =item set_listener()
411              
412             Attaches a listener (code ref) which is executed when contents change.
413              
414             Type : Utility method
415             Title : set_listener
416             Usage : $object->set_listener( sub { my $object = shift; } );
417             Function: Attaches a listener (code ref) which is executed when contents change.
418             Returns : Invocant.
419             Args : A code reference.
420             Comments: When executed, the code reference will receive $object
421             (the container) as its first argument.
422              
423             =cut
424              
425             sub set_listener {
426 962     962 1 1930 my ( $self, $listener ) = @_;
427 962         2375 my $id = $self->get_id;
428 962 50       2526 if ( not $listeners{$id} ) {
429 962         2184 $listeners{$id} = [];
430             }
431 962 50       2619 if ( looks_like_instance( $listener, 'CODE' ) ) {
432 962         1366 push @{ $listeners{$id} }, $listener;
  962         2776  
433             }
434             else {
435 0         0 throw 'BadArgs' => "$listener not a CODE reference";
436             }
437             }
438             sub _set_listeners : Clonable {
439 56     56   74 my ( $self, $l ) = @_;
440 56         104 $listeners{$self->get_id} = $l;
441 56         118 return $self;
442 51     51   15672 }
  51         120  
  51         198  
443 56     56   123 sub _get_listeners { $listeners{shift->get_id} }
444              
445             =item notify_listeners()
446              
447             Notifies listeners of changed contents.
448              
449             Type : Utility method
450             Title : notify_listeners
451             Usage : $object->notify_listeners;
452             Function: Notifies listeners of changed contents.
453             Returns : Invocant.
454             Args : NONE.
455             Comments:
456              
457             =cut
458              
459             sub notify_listeners {
460 9948     9948 1 22563 my ( $self, @args ) = @_;
461 9948         19879 my $id = $self->get_id;
462 9948 100       23501 if ( $listeners{$id} ) {
463 9918         13958 for my $l ( @{ $listeners{$id} } ) {
  9918         18220  
464 9918         24088 $l->( $self, @args );
465             }
466             }
467 9948         17402 return $self;
468             }
469              
470             =back
471              
472             =head2 SETS MANAGEMENT
473              
474             Many Bio::Phylo objects are segmented, i.e. they contain one or more subparts
475             of the same type. For example, a matrix contains multiple rows; each row
476             contains multiple cells; a tree contains nodes, and so on. (Segmented objects
477             all inherit from Bio::Phylo::Listable, i.e. the class whose documentation you're
478             reading here.) In many cases it is useful to be able to define subsets of the
479             contents of segmented objects, for example sets of taxon objects inside a taxa
480             block. The Bio::Phylo::Listable object allows this through a number of methods
481             (add_set, remove_set, add_to_set, remove_from_set etc.). Those methods delegate
482             the actual management of the set contents to the L<Bio::Phylo::Set> object.
483             Consult the documentation for L<Bio::Phylo::Set> for a code sample.
484              
485             =over
486              
487             =item add_set()
488              
489             Type : Mutator
490             Title : add_set
491             Usage : $obj->add_set($set)
492             Function: Associates a Bio::Phylo::Set object with the container
493             Returns : Invocant
494             Args : A Bio::Phylo::Set object
495              
496             =cut
497              
498             # here we create a listener that updates the set
499             # object when the associated container changes
500             my $create_set_listeners = sub {
501             my ( $self, $set ) = @_;
502             my $listener = sub {
503             my ( $listable, $method, $obj ) = @_;
504             if ( $method eq 'delete' ) {
505             $listable->remove_from_set( $obj, $set );
506             }
507             elsif ( $method eq 'clear' ) {
508             $set->clear;
509             }
510             };
511             return $listener;
512             };
513              
514             sub add_set {
515 4     4 1 10 my ( $self, $set ) = @_;
516 4         12 my $listener = $create_set_listeners->( $self, $set );
517 4         16 $self->set_listener($listener);
518 4         11 my $id = $self->get_id;
519 4 50       13 $sets{$id} = {} if not $sets{$id};
520 4         11 my $setid = $set->get_id;
521 4         9 $sets{$id}->{$setid} = $set;
522 4         9 return $self;
523             }
524            
525             =item set_sets()
526              
527             Type : Mutator
528             Title : set_sets
529             Usage : $obj->set_sets([ $s1, $s2, $s3 ])
530             Function: Assigns all Bio::Phylo::Set objects to the container
531             Returns : Invocant
532             Args : An array ref of Bio::Phylo::Set objects
533              
534             =cut
535            
536             sub set_sets : Clonable {
537 56     56 1 85 my ( $self, $sets ) = @_;
538 56         100 my $id = $self->get_id;
539 56         115 $sets{$id} = {};
540 56 50       112 if ( $sets ) {
541 56         61 for my $set ( @{ $sets } ) {
  56         96  
542 0         0 $sets{$id}->{$set->get_id} = $set;
543             }
544             }
545 56         107 return $self;
546 51     51   23033 }
  51         115  
  51         229  
547              
548             =item remove_set()
549              
550             Type : Mutator
551             Title : remove_set
552             Usage : $obj->remove_set($set)
553             Function: Removes association between a Bio::Phylo::Set object and the container
554             Returns : Invocant
555             Args : A Bio::Phylo::Set object
556              
557             =cut
558              
559             sub remove_set {
560 0     0 1 0 my ( $self, $set ) = @_;
561 0         0 my $id = $self->get_id;
562 0 0       0 $sets{$id} = {} if not $sets{$id};
563 0         0 my $setid = $set->get_id;
564 0         0 delete $sets{$id}->{$setid};
565 0         0 return $self;
566             }
567              
568             =item get_sets()
569              
570             Type : Accessor
571             Title : get_sets
572             Usage : my @sets = @{ $obj->get_sets() };
573             Function: Retrieves all associated Bio::Phylo::Set objects
574             Returns : Invocant
575             Args : None
576              
577             =cut
578              
579             sub get_sets {
580 60     60 1 102 my $self = shift;
581 60         117 my $id = $self->get_id;
582 60 100       156 $sets{$id} = {} if not $sets{$id};
583 60         73 return [ values %{ $sets{$id} } ];
  60         161  
584             }
585              
586             =item is_in_set()
587              
588             Type : Test
589             Title : is_in_set
590             Usage : @do_something if $listable->is_in_set($obj,$set);
591             Function: Returns whether or not the first argument is listed in the second argument
592             Returns : Boolean
593             Args : $obj - an object that may, or may not be in $set
594             $set - the Bio::Phylo::Set object to query
595             Notes : This method makes two assumptions:
596             i) the $set object is associated with the container,
597             i.e. add_set($set) has been called previously
598             ii) the $obj object is part of the container
599             If either assumption is violated a warning message
600             is printed.
601              
602             =cut
603              
604             sub is_in_set {
605 22     22 1 125 my ( $self, $obj, $set ) = @_;
606 22 50 33     64 if ( looks_like_object($set,_SET_) and $sets{ $self->get_id }->{ $set->get_id } ) {
607 22         52 my $i = $self->get_index_of($obj);
608 22 50       40 if ( defined $i ) {
609 22 100       38 return $set->get_by_index($i) ? 1 : 0;
610             }
611             else {
612 0         0 $logger->warn("Container doesn't contain that object.");
613             }
614             }
615             else {
616 0         0 $logger->warn("That set is not associated with this container.");
617             }
618             }
619              
620             =item add_to_set()
621              
622             Type : Mutator
623             Title : add_to_set
624             Usage : $listable->add_to_set($obj,$set);
625             Function: Adds first argument to the second argument
626             Returns : Invocant
627             Args : $obj - an object to add to $set
628             $set - the Bio::Phylo::Set object to add to
629             Notes : this method assumes that $obj is already
630             part of the container. If that assumption is
631             violated a warning message is printed.
632              
633             =cut
634              
635             sub add_to_set {
636 14     14 1 25 my ( $self, $obj, $set ) = @_;
637 14         23 my $id = $self->get_id;
638 14 50       29 $sets{$id} = {} if not $sets{$id};
639 14         36 my $i = $self->get_index_of($obj);
640 14 50       24 if ( defined $i ) {
641 14         38 $set->insert_at_index( 1 => $i );
642 14         26 my $set_id = $set->get_id;
643 14 50       28 if ( not exists $sets{$id}->{$set_id} ) {
644 0         0 my $listener = $create_set_listeners->( $self, $set );
645 0         0 $self->set_listener($listener);
646             }
647 14         22 $sets{$id}->{$set_id} = $set;
648             }
649             else {
650 0         0 $logger->warn(
651             "Container doesn't contain the object you're adding to the set."
652             );
653             }
654 14         28 return $self;
655             }
656              
657             =item remove_from_set()
658              
659             Type : Mutator
660             Title : remove_from_set
661             Usage : $listable->remove_from_set($obj,$set);
662             Function: Removes first argument from the second argument
663             Returns : Invocant
664             Args : $obj - an object to remove from $set
665             $set - the Bio::Phylo::Set object to remove from
666             Notes : this method assumes that $obj is already
667             part of the container. If that assumption is
668             violated a warning message is printed.
669              
670             =cut
671              
672             sub remove_from_set {
673 0     0 1   my ( $self, $obj, $set ) = @_;
674 0           my $id = $self->get_id;
675 0 0         $sets{$id} = {} if not $sets{$id};
676 0           my $i = $self->get_index_of($obj);
677 0 0         if ( defined $i ) {
678 0           $set->insert_at_index( $i => 0 );
679 0           $sets{$id}->{ $set->get_id } = $set;
680             }
681             else {
682 0           $logger->warn(
683             "Container doesn't contain the object you're adding to the set."
684             );
685             }
686 0           return $self;
687             }
688              
689             =begin comment
690              
691             Type : Internal method
692             Title : _cleanup
693             Usage : $listable->_cleanup;
694             Function: Called during object destruction, for cleanup of instance data
695             Returns :
696             Args :
697              
698             =end comment
699              
700             =cut
701              
702             sub _cleanup : Destructor {
703 32073     32073   37697 my $self = shift;
704 32073         49752 my $id = $self->get_id;
705 32073         47388 for my $field (@fields) {
706 128292         200872 delete $field->{$id};
707             }
708 51     51   29615 }
  51         122  
  51         212  
709              
710             =back
711              
712             =cut
713              
714             # podinherit_insert_token
715              
716             =head1 SEE ALSO
717              
718             There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo>
719             for any user or developer questions and discussions.
720              
721             Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
722              
723             =head2 Objects inheriting from Bio::Phylo::Listable
724              
725             =over
726              
727             =item L<Bio::Phylo::Forest>
728              
729             Iterate over a set of trees.
730              
731             =item L<Bio::Phylo::Forest::Tree>
732              
733             Iterate over nodes in a tree.
734              
735             =item L<Bio::Phylo::Forest::Node>
736              
737             Iterate of children of a node.
738              
739             =item L<Bio::Phylo::Matrices>
740              
741             Iterate over a set of matrices.
742              
743             =item L<Bio::Phylo::Matrices::Matrix>
744              
745             Iterate over the datum objects in a matrix.
746              
747             =item L<Bio::Phylo::Matrices::Datum>
748              
749             Iterate over the characters in a datum.
750              
751             =item L<Bio::Phylo::Taxa>
752              
753             Iterate over a set of taxa.
754              
755             =back
756              
757             =head2 Superclasses
758              
759             =over
760              
761             =item L<Bio::Phylo::NeXML::Writable>
762              
763             This object inherits from L<Bio::Phylo::NeXML::Writable>, so methods
764             defined there are also applicable here.
765              
766             =back
767              
768             =head1 CITATION
769              
770             If you use Bio::Phylo in published research, please cite it:
771              
772             B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
773             and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
774             I<BMC Bioinformatics> B<12>:63.
775             L<http://dx.doi.org/10.1186/1471-2105-12-63>
776              
777             =cut
778              
779             }
780             1;