File Coverage

blib/lib/Bio/Phylo/Listable.pm
Criterion Covered Total %
statement 155 209 74.1
branch 31 64 48.4
condition 17 28 60.7
subroutine 32 39 82.0
pod 22 22 100.0
total 257 362 70.9


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