The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
MANIFEST 57
META.json 1515
META.yml 33
MYMETA.json 650
MYMETA.yml 390
Makefile.PL 11
README.md 088
README.txt 720
lib/Bio/Phylo/Factory.pm 03
lib/Bio/Phylo/Forest/DrawNode.pm 9670
lib/Bio/Phylo/Forest/DrawNodeRole.pm 0573
lib/Bio/Phylo/Forest/DrawTree.pm 12520
lib/Bio/Phylo/Forest/DrawTreeRole.pm 0760
lib/Bio/Phylo/Forest/Node.pm 1212
lib/Bio/Phylo/Forest/NodeRole.pm 641
lib/Bio/Phylo/Forest/Tree.pm 2725
lib/Bio/Phylo/Forest/TreeRole.pm 14
lib/Bio/Phylo/Forest.pm 390
lib/Bio/Phylo/Listable.pm 6069
lib/Bio/Phylo/Matrices/Character.pm 2024
lib/Bio/Phylo/Matrices/Characters.pm 561
lib/Bio/Phylo/Matrices/Datatype.pm 742
lib/Bio/Phylo/Matrices/Datum.pm 2119
lib/Bio/Phylo/Matrices/DatumRole.pm 3538
lib/Bio/Phylo/Matrices/Matrix.pm 2641
lib/Bio/Phylo/Matrices/MatrixRole.pm 469
lib/Bio/Phylo/Matrices/TypeSafeData.pm 474
lib/Bio/Phylo/Matrices.pm 390
lib/Bio/Phylo/Mediators/TaxaMediator.pm 941
lib/Bio/Phylo/NeXML/Meta.pm 220
lib/Bio/Phylo/NeXML/Writable.pm 6961
lib/Bio/Phylo/Parsers/Abstract.pm 411
lib/Bio/Phylo/Parsers/Fastq.pm 11
lib/Bio/Phylo/Parsers/Nexml.pm 25
lib/Bio/Phylo/Parsers/Nexus.pm 1921
lib/Bio/Phylo/Taxa/TaxaLinker.pm 11
lib/Bio/Phylo/Taxa/Taxon.pm 6421
lib/Bio/Phylo/Taxa/TaxonLinker.pm 1710
lib/Bio/Phylo/Treedrawer.pm 40
lib/Bio/Phylo/Unparsers/Nwmsrdf.pm 0152
lib/Bio/Phylo/Util/CONSTANT/Int.pm 01
lib/Bio/Phylo/Util/CONSTANT.pm 07
lib/Bio/Phylo/Util/Logger.pm 731
lib/Bio/Phylo/Util/MOP.pm 2579
lib/Bio/Phylo.pm 148155
lib/Bio/PhyloRole.pm 7544
t/03-node.t 02
t/19-svg.t 2738
t/20-nexml.t 13
t/35-processing.t 129
t/37-memory.t 824
t/47-clone.t 099
t/48-drawnoderole.t 026
t/49-drawtreerole.t 027
54 files changed (This is a version diff) 40932588
@@ -3,8 +3,8 @@ lib/Bio/Phylo.pm
 lib/Bio/Phylo/EvolutionaryModels.pm
 lib/Bio/Phylo/Factory.pm
 lib/Bio/Phylo/Forest.pm
-lib/Bio/Phylo/Forest/DrawNode.pm
-lib/Bio/Phylo/Forest/DrawTree.pm
+lib/Bio/Phylo/Forest/DrawNodeRole.pm
+lib/Bio/Phylo/Forest/DrawTreeRole.pm
 lib/Bio/Phylo/Forest/Node.pm
 lib/Bio/Phylo/Forest/NodeRole.pm
 lib/Bio/Phylo/Forest/Tree.pm
@@ -107,6 +107,7 @@ lib/Bio/Phylo/Unparsers/Mrp.pm
 lib/Bio/Phylo/Unparsers/Newick.pm
 lib/Bio/Phylo/Unparsers/Nexml.pm
 lib/Bio/Phylo/Unparsers/Nexus.pm
+lib/Bio/Phylo/Unparsers/Nwmsrdf.pm
 lib/Bio/Phylo/Unparsers/Pagel.pm
 lib/Bio/Phylo/Unparsers/Phylip.pm
 lib/Bio/Phylo/Unparsers/Phyloxml.pm
@@ -125,9 +126,7 @@ lib/Bio/PhyloRole.pm
 LICENSE
 Makefile.PL
 MANIFEST			This list of files
-MYMETA.json
-MYMETA.yml
-README.txt
+README.md
 t/00-load.t
 t/01-phylo.t
 t/02-newick.t
@@ -174,6 +173,9 @@ t/43-adjacency.t
 t/44-tnrs.t
 t/45-fastq.t
 t/46-noformat.t
+t/47-clone.t
+t/48-drawnoderole.t
+t/49-drawtreerole.t
 t/perl-critic.t
 t/perlcriticrc
 t/pod-coverage.t
@@ -4,7 +4,7 @@
       "Rutger Vos"
    ],
    "dynamic_config" : 1,
-   "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150",
+   "generated_by" : "ExtUtils::MakeMaker version 6.8, CPAN::Meta::Converter version 2.132830",
    "license" : [
       "perl_5"
    ],
@@ -22,27 +22,27 @@
    "prereqs" : {
       "build" : {
          "requires" : {
-            "ExtUtils::MakeMaker" : 0
+            "ExtUtils::MakeMaker" : "0"
          }
       },
       "configure" : {
          "requires" : {
-            "ExtUtils::MakeMaker" : 0
+            "ExtUtils::MakeMaker" : "0"
          }
       },
       "runtime" : {
          "recommends" : {
-            "GD" : 0,
-            "JSON" : 0,
-            "List::Util" : 0,
-            "Math::CDF" : 0,
-            "Math::Random" : 0,
-            "PDF::API2" : 0,
-            "SVG" : 0,
-            "SWF::Builder" : 0,
-            "XML::LibXML" : 0,
-            "XML::Twig" : 0,
-            "XML::XML2JSON" : 0
+            "GD" : "0",
+            "JSON" : "0",
+            "List::Util" : "0",
+            "Math::CDF" : "0",
+            "Math::Random" : "0",
+            "PDF::API2" : "0",
+            "SVG" : "0",
+            "SWF::Builder" : "0",
+            "XML::LibXML" : "0",
+            "XML::Twig" : "0",
+            "XML::XML2JSON" : "0"
          },
          "requires" : {}
       }
@@ -61,5 +61,5 @@
       },
       "x_MailingList" : "mailto:bio-phylo@googlegroups.com"
    },
-   "version" : "0.56"
+   "version" : "0.58"
 }
@@ -7,7 +7,7 @@ build_requires:
 configure_requires:
   ExtUtils::MakeMaker: 0
 dynamic_config: 1
-generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150'
+generated_by: 'ExtUtils::MakeMaker version 6.8, CPAN::Meta::Converter version 2.132830'
 license: perl
 meta-spec:
   url: http://module-build.sourceforge.net/META-spec-v1.4.html
@@ -31,9 +31,9 @@ recommends:
   XML::XML2JSON: 0
 requires: {}
 resources:
+  MailingList: mailto:bio-phylo@googlegroups.com
   bugtracker: https://github.com/rvosa/bio-phylo/issues
   homepage: http://biophylo.blogspot.com/
   license: http://dev.perl.org/licenses/
   repository: git://github.com/rvosa/bio-phylo.git
-  x_MailingList: mailto:bio-phylo@googlegroups.com
-version: 0.56
+version: 0.58
@@ -1,65 +0,0 @@
-{
-   "abstract" : "An object-oriented Perl toolkit for analyzing and manipulating phyloinformatic data.",
-   "author" : [
-      "Rutger Vos"
-   ],
-   "dynamic_config" : 0,
-   "generated_by" : "ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150",
-   "license" : [
-      "perl_5"
-   ],
-   "meta-spec" : {
-      "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec",
-      "version" : "2"
-   },
-   "name" : "Bio-Phylo",
-   "no_index" : {
-      "directory" : [
-         "t",
-         "inc"
-      ]
-   },
-   "prereqs" : {
-      "build" : {
-         "requires" : {
-            "ExtUtils::MakeMaker" : 0
-         }
-      },
-      "configure" : {
-         "requires" : {
-            "ExtUtils::MakeMaker" : 0
-         }
-      },
-      "runtime" : {
-         "recommends" : {
-            "GD" : 0,
-            "JSON" : 0,
-            "List::Util" : 0,
-            "Math::CDF" : 0,
-            "Math::Random" : 0,
-            "PDF::API2" : 0,
-            "SVG" : 0,
-            "SWF::Builder" : 0,
-            "XML::LibXML" : 0,
-            "XML::Twig" : 0,
-            "XML::XML2JSON" : 0
-         },
-         "requires" : {}
-      }
-   },
-   "release_status" : "stable",
-   "resources" : {
-      "bugtracker" : {
-         "web" : "https://github.com/rvosa/bio-phylo/issues"
-      },
-      "homepage" : "http://biophylo.blogspot.com/",
-      "license" : [
-         "http://dev.perl.org/licenses/"
-      ],
-      "repository" : {
-         "url" : "git://github.com/rvosa/bio-phylo.git"
-      },
-      "x_MailingList" : "mailto:bio-phylo@googlegroups.com"
-   },
-   "version" : "0.56"
-}
@@ -1,39 +0,0 @@
----
-abstract: 'An object-oriented Perl toolkit for analyzing and manipulating phyloinformatic data.'
-author:
-  - 'Rutger Vos'
-build_requires:
-  ExtUtils::MakeMaker: 0
-configure_requires:
-  ExtUtils::MakeMaker: 0
-dynamic_config: 0
-generated_by: 'ExtUtils::MakeMaker version 6.62, CPAN::Meta::Converter version 2.112150'
-license: perl
-meta-spec:
-  url: http://module-build.sourceforge.net/META-spec-v1.4.html
-  version: 1.4
-name: Bio-Phylo
-no_index:
-  directory:
-    - t
-    - inc
-recommends:
-  GD: 0
-  JSON: 0
-  List::Util: 0
-  Math::CDF: 0
-  Math::Random: 0
-  PDF::API2: 0
-  SVG: 0
-  SWF::Builder: 0
-  XML::LibXML: 0
-  XML::Twig: 0
-  XML::XML2JSON: 0
-requires: {}
-resources:
-  bugtracker: https://github.com/rvosa/bio-phylo/issues
-  homepage: http://biophylo.blogspot.com/
-  license: http://dev.perl.org/licenses/
-  repository: git://github.com/rvosa/bio-phylo.git
-  x_MailingList: mailto:bio-phylo@googlegroups.com
-version: 0.56
@@ -21,7 +21,7 @@ my %recommended = (
 check_prereq( keys %recommended );
 
 my %parms = (
-    'NAME'         => 'Bio-Phylo',
+    'NAME'         => 'Bio::Phylo', # EU::MM apparently now wants Package::Name
     'AUTHOR'       => 'Rutger Vos',
     'PL_FILES'     => {},
     'EXE_FILES'    => [],
@@ -0,0 +1,88 @@
+Bio::Phylo
+==========
+
+An object-oriented Perl toolkit for analyzing and manipulating phyloinformatic data. 
+
+DESCRIPTION
+-----------
+Phylogenetics is the branch of evolutionary biology that deals with reconstructing and 
+analyzing the tree of life. This distribution provides objects and methods to aid in 
+handling and analyzing phylogenetic data.
+
+COMPATABILITY
+-------------
+Bio::Phylo installs without problems on most popular, current platforms (Win32, OSX, 
+Linux, Solaris, IRIX, FreeBSD, OpenBSD, NetBSD), on Perl versions >= 5.8.0
+
+For a list of automated test results visit:
+
+http://testers.cpan.org/show/Bio-Phylo.html
+
+Currently, the build status is:
+
+[![Build Status](https://travis-ci.org/rvosa/bio-phylo.svg?branch=master)](https://travis-ci.org/rvosa/bio-phylo)
+
+INSTALLATION
+------------
+Bio::Phylo has no dependencies for its core install. However, some additional 
+functionality will not work (e.g. XML parsing) until the CPAN module that enables it has 
+been installed (e.g. XML::Twig). You can install these at a later date if and when need 
+arises. If any of such additional CPAN modules are found to be missing at installation 
+time, a warning will be emitted, but installation can continue.
+
+To install the Bio::Phylo distribution itself, run the
+following commands: 
+
+perl Makefile.PL
+make
+make test
+make install
+ 
+(For platform specific information on what 'make' command to use, check "perl -V:make". 
+On Windows this usually returns "make='nmake';", which means you'll need the free 'nmake' 
+utility)
+
+AUTHORS
+-------
+Rutger Vos
+Jason Caravas
+Klaas Hartmann
+Mark A. Jensen
+Chase Miller
+Aki Mimoto
+
+BUGS
+----
+Please report any bugs or feature requests on the GitHub bug tracker:
+
+https://github.com/rvosa/bio-phylo/issues
+ 
+ACKNOWLEDGEMENTS
+----------------
+The authors would like to thank the BioPerl project for providing the community
+with a terrific toolkit that other software, such as this, can be built on
+(http://www.bioperl.org); and Arne Mooers from the FAB* lab (http://www.sfu.ca/~fabstar) 
+for comments and requests.
+
+The research leading to these results has received funding from the European
+Community's Seventh Framework Programme (FP7/2007-2013) under grant agreement
+no. 237046.
+
+SEE ALSO
+--------
+Read the manual: perldoc Bio::Phylo::Manual
+
+CITATION
+--------
+If you use Bio::Phylo in published research, please cite it:
+
+Rutger A Vos, Jason Caravas, Klaas Hartmann, Mark A Jensen
+and Chase Miller, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
+BMC Bioinformatics 12:63.
+doi:10.1186/1471-2105-12-63
+
+COPYRIGHT & LICENSE
+-------------------
+Copyright 2005-2014 Rutger Vos, All Rights Reserved. This program is free software; 
+you can redistribute it and/or modify it under the same terms as Perl itself.
+
@@ -1,72 +0,0 @@
-Bio::Phylo - An object-oriented Perl toolkit for analyzing and manipulating phyloinformatic data. 
-
-DESCRIPTION
-
-Phylogenetics is the branch of evolutionary biology that deals with reconstructing and analyzing the tree of life. This distribution provides objects and methods to aid in handling and analyzing phylogenetic data.
-
-COMPATABILITY
- 
-Bio::Phylo installs without problems on most popular, current platforms (Win32, OSX, Linux, Solaris, IRIX, FreeBSD, OpenBSD, NetBSD), on Perl versions >= 5.8.0
-
-For a list of automated test results visit:
-
-http://testers.cpan.org/show/Bio-Phylo.html
-
-INSTALLATION
-
-Bio::Phylo has no dependencies for its core install. However, some additional functionality will not work (e.g. XML parsing) until the CPAN module that enables it has been installed (e.g. XML::Twig). You can install these at a later date if and when need arises. If any of such additional CPAN modules are found to be missing at installation time, a warning will be emitted, but installation can continue.
-
-To install the Bio::Phylo distribution itself, run the
-following commands: 
-
-perl Makefile.PL
-make
-make test
-make install
- 
-(For platform specific information on what 'make' command to use, check "perl -V:make". On Windows this usually returns "make='nmake';", which means you'll need the free 'nmake' utility)
-
-AUTHORS
-
-Rutger Vos
-Jason Caravas
-Klaas Hartmann
-Mark A. Jensen
-Chase Miller
-Aki Mimoto
-
-BUGS
-
-Please report any bugs or feature requests to bug-bio-phylo@rt.cpan.org, or through the web 
-interface at http://rt.cpan.org/NoAuth/ReportBug.html?Queue=Bio-Phylo I will be notified, 
-and then you'll automatically be notified of progress on your bug as I make changes. 
- 
-ACKNOWLEDGEMENTS
-
-The authors would like to thank the BioPerl project for providing the community
-with a terrific toolkit that other software, such as this, can be built on
-(http://www.bioperl.org); and Arne Mooers from the FAB* lab (http://www.sfu.ca/~fabstar) for
-comments and requests.
-
-The research leading to these results has received funding from the [European
-Community's] Seventh Framework Programme ([FP7/2007-2013] under grant agreement
-n� [237046].
-
-SEE ALSO
-
-Read the manual: perldoc Bio::Phylo::Manual
-
-CITATION
-
-If you use Bio::Phylo in published research, please cite it:
-
-Rutger A Vos, Jason Caravas, Klaas Hartmann, Mark A Jensen
-and Chase Miller, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
-BMC Bioinformatics 12:63.
-doi:10.1186/1471-2105-12-63
-
-COPYRIGHT & LICENSE
-
-Copyright 2005-2011 Rutger Vos, All Rights Reserved. This program is free software; 
-you can redistribute it and/or modify it under the same terms as Perl itself.
-
@@ -182,6 +182,9 @@ sub AUTOLOAD {
         $path =~ s|::|/|g;
         $path .= '.pm';
         if ( not $INC{$path} ) {
+            
+            # here we need to do a string eval use so that the
+            # entire symbol table is populated
             require $path;
         }
         return $class{$type}->new(@_);
@@ -1,967 +0,0 @@
-package Bio::Phylo::Forest::DrawNode;
-use strict;
-use base 'Bio::Phylo::Forest::Node';
-{
-
-    # @fields array necessary for object destruction
-    my @fields = \(
-        my (
-            %x,                 %y,               %radius,
-            %tip_radius,        %node_colour,     %node_outline_colour,
-            %node_shape,        %node_image,      %branch_color,
-            %branch_shape,      %branch_width,    %branch_style,
-            %collapsed,         %collapsed_width, %font_face,
-            %font_size,         %font_style,      %font_color,      
-            %text_horiz_offset, %text_vert_offset, %rotation
-        )
-    );
-
-=head1 NAME
-
-Bio::Phylo::Forest::DrawNode - Tree node with extra methods for tree drawing
-
-=head1 SYNOPSIS
-
- # see Bio::Phylo::Forest::Node
-
-=head1 DESCRIPTION
-
-This module defines a node object and its methods. The node is fairly
-syntactically rich in terms of navigation, and additional getters are provided to
-further ease navigation from node to node. Typical first daughter -> next sister
-traversal and recursion is possible, but there are also shrinkwrapped methods
-that return for example all terminal descendants of the focal node, or all
-internals, etc.
-
-Node objects are inserted into tree objects, although technically the tree
-object is only a container holding all the nodes together. Unless there are
-orphans all nodes can be reached without recourse to the tree object.
-
-In addition, this subclass of the default node object L<Bio::Phylo::Forest::Node>
-has getters and setters for drawing trees and nodes, e.g. X/Y coordinates, font
-and text attributes, etc.
-
-=head1 METHODS
-
-=head2 MUTATORS
-
-=over
-
-=item set_collapsed()
-
- Type    : Mutator
- Title   : set_collapsed
- Usage   : $node->set_collapsed(1);
- Function: Sets whether the node's descendants are shown as collapsed into a triangle
- Returns : $self
- Args    : true or false value
-
-=cut
-
-    sub set_collapsed {
-        my ( $self, $collapsed ) = @_;
-        my $id = $self->get_id;
-        $collapsed{$id} = $collapsed;
-        return $self;
-    }
-
-=item set_collapsed_clade_width()
-
-Sets collapsed clade width.
-
- Type    : Mutator
- Title   : set_collapsed_clade_width
- Usage   : $tree->set_collapsed_clade_width(6);
- Function: sets the width of collapsed clade triangles relative to uncollapsed tips
- Returns :
- Args    : Positive number
-
-=cut
-
-    sub set_collapsed_clade_width {
-        my ( $self, $width ) = @_;
-        my $id = $self->get_id;
-        $collapsed_width{$id} = $width;
-        return $self;
-    }
-
-=item set_x()
-
- Type    : Mutator
- Title   : set_x
- Usage   : $node->set_x($x);
- Function: Sets x
- Returns : $self
- Args    : x
-
-=cut
-
-    sub set_x {
-        my ( $self, $x ) = @_;
-        #my $id = $self->get_id;
-        #$x{$id} = $x;
-        $self->set_meta_object( 'map:x' => $x );
-        return $self;
-    }
-
-=item set_y()
-
- Type    : Mutator
- Title   : set_y
- Usage   : $node->set_y($y);
- Function: Sets y
- Returns : $self
- Args    : y
-
-=cut
-
-    sub set_y {
-        my ( $self, $y ) = @_;
-        #my $id = $self->get_id;
-        #$y{$id} = $y;
-        $self->set_meta_object( 'map:y' => $y );
-        return $self;
-    }
-
-=item set_radius()
-
- Type    : Mutator
- Title   : set_radius
- Usage   : $node->set_radius($radius);
- Function: Sets radius
- Returns : $self
- Args    : radius
-
-=cut
-
-    sub set_radius {
-        my ( $self, $radius ) = @_;
-        my $id = $self->get_id;
-        $radius{$id} = $radius;
-        return $self;
-    }
-    *set_node_radius = \&set_radius;
-
-=item set_tip_radius()
-
- Type    : Mutator
- Title   : set_tip_node_radius
- Usage   : $tree->set_tip_radius($node_radius);
- Function: Sets tip radius
- Returns : $self
- Args    : tip radius
-
-=cut
-
-    sub set_tip_radius {
-        my ( $self, $r ) = @_;
-        my $id = $self->get_id;
-        $tip_radius{$id} = $r;
-        return $self;
-    }
-
-=item set_node_colour()
-
- Type    : Mutator
- Title   : set_node_colour
- Usage   : $node->set_node_colour($node_colour);
- Function: Sets node_colour
- Returns : $self
- Args    : node_colour
-
-=cut
-
-    sub set_node_colour {
-        my ( $self, $node_colour ) = @_;
-        my $id = $self->get_id;
-        $node_colour{$id} = $node_colour;
-        return $self;
-    }
-    *set_node_color = \&set_node_colour;
-
-=item set_node_outline_colour()
-
- Type    : Mutator
- Title   : set_node_outline_colour
- Usage   : $node->set_node_outline_colour($node_outline_colour);
- Function: Sets node outline colour
- Returns : $self
- Args    : node_colour
-
-=cut
-
-    sub set_node_outline_colour {
-        my ( $self, $node_colour ) = @_;
-        my $id = $self->get_id;
-        $node_outline_colour{$id} = $node_colour;
-        return $self;
-    }
-
-=item set_node_shape()
-
- Type    : Mutator
- Title   : set_node_shape
- Usage   : $node->set_node_shape($node_shape);
- Function: Sets node_shape
- Returns : $self
- Args    : node_shape
-
-=cut
-
-    sub set_node_shape {
-        my ( $self, $node_shape ) = @_;
-        my $id = $self->get_id;
-        $node_shape{$id} = $node_shape;
-        return $self;
-    }
-
-=item set_node_image()
-
- Type    : Mutator
- Title   : set_node_image
- Usage   : $node->set_node_image($node_image);
- Function: Sets node_image
- Returns : $self
- Args    : node_image
-
-=cut
-
-    sub set_node_image {
-        my ( $self, $node_image ) = @_;
-        my $id = $self->get_id;
-        $node_image{$id} = $node_image;
-        return $self;
-    }
-
-=item set_branch_color()
-
- Type    : Mutator
- Title   : set_branch_color
- Usage   : $node->set_branch_color($branch_color);
- Function: Sets branch_color
- Returns : $self
- Args    : branch_color
-
-=cut
-
-    sub set_branch_color {
-        my ( $self, $branch_color ) = @_;
-        my $id = $self->get_id;
-        $branch_color{$id} = $branch_color;
-        return $self;
-    }
-    *set_branch_colour = \&set_branch_color;
-
-=item set_branch_shape()
-
- Type    : Mutator
- Title   : set_branch_shape
- Usage   : $node->set_branch_shape($branch_shape);
- Function: Sets branch_shape
- Returns : $self
- Args    : branch_shape
-
-=cut
-
-    sub set_branch_shape {
-        my ( $self, $branch_shape ) = @_;
-        my $id = $self->get_id;
-        $branch_shape{$id} = $branch_shape;
-        return $self;
-    }
-
-=item set_branch_width()
-
- Type    : Mutator
- Title   : set_branch_width
- Usage   : $node->set_branch_width($branch_width);
- Function: Sets branch width
- Returns : $self
- Args    : branch_width
-
-=cut
-
-    sub set_branch_width {
-        my ( $self, $branch_width ) = @_;
-        my $id = $self->get_id;
-        $branch_width{$id} = $branch_width;
-        return $self;
-    }
-
-=item set_branch_style()
-
- Type    : Mutator
- Title   : set_branch_style
- Usage   : $node->set_branch_style($branch_style);
- Function: Sets branch style
- Returns : $self
- Args    : branch_style
-
-=cut
-
-    sub set_branch_style {
-        my ( $self, $branch_style ) = @_;
-        my $id = $self->get_id;
-        $branch_style{$id} = $branch_style;
-        return $self;
-    }
-
-=item set_font_face()
-
- Type    : Mutator
- Title   : set_font_face
- Usage   : $node->set_font_face($font_face);
- Function: Sets font_face
- Returns : $self
- Args    : font_face
-
-=cut
-
-    sub set_font_face {
-        my ( $self, $font_face ) = @_;
-        my $id = $self->get_id;
-        $font_face{$id} = $font_face;
-        return $self;
-    }
-
-=item set_font_size()
-
- Type    : Mutator
- Title   : set_font_size
- Usage   : $node->set_font_size($font_size);
- Function: Sets font_size
- Returns : $self
- Args    : font_size
-
-=cut
-
-    sub set_font_size {
-        my ( $self, $font_size ) = @_;
-        my $id = $self->get_id;
-        $font_size{$id} = $font_size;
-        return $self;
-    }
-
-=item set_font_style()
-
- Type    : Mutator
- Title   : set_font_style
- Usage   : $node->set_font_style($font_style);
- Function: Sets font_style
- Returns : $self
- Args    : font_style
-
-=cut
-
-    sub set_font_style {
-        my ( $self, $font_style ) = @_;
-        my $id = $self->get_id;
-        $font_style{$id} = $font_style;
-        return $self;
-    }
-
-=item set_font_colour()
-
- Type    : Mutator
- Title   : set_font_colour
- Usage   : $node->set_font_colour($color);
- Function: Sets font_colour
- Returns : font_colour
- Args    : A color, which, depending on the underlying tree drawer, can either
-           be expressed as a word ('red'), a hex code ('#00CC00') or an rgb
-           statement ('rgb(0,255,0)')
-
-=cut
-    
-    sub set_font_colour {
-        my ($self, $colour) = @_;
-        my $id = $self->get_id;
-        $font_color{$id} = $colour;
-        return $self;
-    }
-    *set_font_color = \&set_font_colour;
-
-=item set_text_horiz_offset()
-
- Type    : Mutator
- Title   : set_text_horiz_offset
- Usage   : $node->set_text_horiz_offset($text_horiz_offset);
- Function: Sets text_horiz_offset
- Returns : $self
- Args    : text_horiz_offset
-
-=cut
-
-    sub set_text_horiz_offset {
-        my ( $self, $text_horiz_offset ) = @_;
-        my $id = $self->get_id;
-        $text_horiz_offset{$id} = $text_horiz_offset;
-        return $self;
-    }
-
-=item set_text_vert_offset()
-
- Type    : Mutator
- Title   : set_text_vert_offset
- Usage   : $node->set_text_vert_offset($text_vert_offset);
- Function: Sets text_vert_offset
- Returns : $self
- Args    : text_vert_offset
-
-=cut
-
-    sub set_text_vert_offset {
-        my ( $self, $text_vert_offset ) = @_;
-        my $id = $self->get_id;
-        $text_vert_offset{$id} = $text_vert_offset;
-        return $self;
-    }
-
-=item set_rotation()
-
- Type    : Mutator
- Title   : set_rotation
- Usage   : $node->set_rotation($rotation);
- Function: Sets rotation
- Returns : $self
- Args    : rotation
-
-=cut
-
-    sub set_rotation {
-        my ( $self, $rotation ) = @_;
-        my $id = $self->get_id;
-        $rotation{$id} = $rotation;
-        return $self;
-    }
-
-=back
-
-=head2 ACCESSORS
-
-=over
-
-=item get_collapsed()
-
- Type    : Mutator
- Title   : get_collapsed
- Usage   : something() if $node->get_collapsed();
- Function: Gets whether the node's descendants are shown as collapsed into a triangle
- Returns : true or false value
- Args    : NONE
-
-=cut
-
-    sub get_collapsed {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $collapsed{$id};
-    }
-
-=item get_first_daughter()
-
-Gets invocant's first daughter.
-
- Type    : Accessor
- Title   : get_first_daughter
- Usage   : my $f_daughter = $node->get_first_daughter;
- Function: Retrieves a node's leftmost daughter.
- Returns : Bio::Phylo::Forest::Node
- Args    : NONE
-
-=cut
-
-    sub get_first_daughter {
-        my $self = shift;
-        if ( $self->get_collapsed ) {
-            return;
-        }
-        else {
-            return $self->SUPER::get_first_daughter;
-        }
-    }
-
-=item get_last_daughter()
-
-Gets invocant's last daughter.
-
- Type    : Accessor
- Title   : get_last_daughter
- Usage   : my $l_daughter = $node->get_last_daughter;
- Function: Retrieves a node's rightmost daughter.
- Returns : Bio::Phylo::Forest::Node
- Args    : NONE
-
-=cut
-
-    sub get_last_daughter {
-        my $self = shift;
-        if ( $self->get_collapsed ) {
-            return;
-        }
-        else {
-            return $self->SUPER::get_last_daughter;
-        }
-    }
-
-=item get_children()
-
-Gets invocant's immediate children.
-
- Type    : Query
- Title   : get_children
- Usage   : my @children = @{ $node->get_children };
- Function: Returns an array reference of immediate
-           descendants, ordered from left to right.
- Returns : Array reference of
-           Bio::Phylo::Forest::Node objects.
- Args    : NONE
-
-=cut
-
-    sub get_children {
-        my $self = shift;
-        if ( $self->get_collapsed ) {
-            return [];
-        }
-        else {
-            return $self->SUPER::get_children;
-        }
-    }
-
-=item get_x()
-
- Type    : Accessor
- Title   : get_x
- Usage   : my $x = $node->get_x();
- Function: Gets x
- Returns : x
- Args    : NONE
-
-=cut
-
-    sub get_x {
-        #my $self = shift;
-        #my $id   = $self->get_id;
-        #return $x{$id};
-        shift->get_meta_object('map:x');
-    }
-
-=item get_y()
-
- Type    : Accessor
- Title   : get_y
- Usage   : my $y = $node->get_y();
- Function: Gets y
- Returns : y
- Args    : NONE
-
-=cut
-
-    sub get_y {
-        #my $self = shift;
-        #my $id   = $self->get_id;
-        #return $y{$id};
-        shift->get_meta_object('map:y');
-    }
-
-=item get_radius()
-
- Type    : Accessor
- Title   : get_radius
- Usage   : my $radius = $node->get_radius();
- Function: Gets radius
- Returns : radius
- Args    : NONE
-
-=cut
-
-    sub get_radius {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $radius{$id};
-    }
-
-=item get_node_colour()
-
- Type    : Accessor
- Title   : get_node_colour
- Usage   : my $node_colour = $node->get_node_colour();
- Function: Gets node_colour
- Returns : node_colour
- Args    : NONE
-
-=cut
-
-    sub get_node_colour {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_colour{$id};
-    }
-    *get_node_color = \&get_node_colour;
-
-=item get_node_outline_colour()
-
- Type    : Accessor
- Title   : get_node_outline_colour
- Usage   : my $node_outline_colour = $node->get_node_outline_colour();
- Function: Gets node outline colour
- Returns : node_colour
- Args    : NONE
-
-=cut
-
-    sub get_node_outline_colour {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_outline_colour{$id};
-    }
-
-=item get_node_shape()
-
- Type    : Accessor
- Title   : get_node_shape
- Usage   : my $node_shape = $node->get_node_shape();
- Function: Gets node_shape
- Returns : node_shape
- Args    : NONE
-
-=cut
-
-    sub get_node_shape {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_shape{$id};
-    }
-
-=item get_node_image()
-
- Type    : Accessor
- Title   : get_node_image
- Usage   : my $node_image = $node->get_node_image();
- Function: Gets node_image
- Returns : node_image
- Args    : NONE
-
-=cut
-
-    sub get_node_image {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_image{$id};
-    }
-
-=item get_collapsed_clade_width()
-
-Gets collapsed clade width.
-
- Type    : Mutator
- Title   : get_collapsed_clade_width
- Usage   : $w = $tree->get_collapsed_clade_width();
- Function: gets the width of collapsed clade triangles relative to uncollapsed tips
- Returns : Positive number
- Args    : None
-
-=cut
-
-    sub get_collapsed_clade_width {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $collapsed_width{$id};
-    }
-
-=item get_branch_color()
-
- Type    : Accessor
- Title   : get_branch_color
- Usage   : my $branch_color = $node->get_branch_color();
- Function: Gets branch_color
- Returns : branch_color
- Args    : NONE
-
-=cut
-
-    sub get_branch_color {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_color{$id};
-    }
-    *get_branch_colour = \&get_branch_color;
-
-=item get_branch_shape()
-
- Type    : Accessor
- Title   : get_branch_shape
- Usage   : my $branch_shape = $node->get_branch_shape();
- Function: Gets branch_shape
- Returns : branch_shape
- Args    : NONE
-
-=cut
-
-    sub get_branch_shape {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_shape{$id};
-    }
-
-=item get_branch_width()
-
- Type    : Accessor
- Title   : get_branch_width
- Usage   : my $branch_width = $node->get_branch_width();
- Function: Gets branch_width
- Returns : branch_width
- Args    : NONE
-
-=cut
-
-    sub get_branch_width {
-        my $self = shift;
-        if ( my $node = shift ) {
-            return $node->get_branch_width;
-        }
-        else {
-            my $id = $self->get_id;
-            return $branch_width{$id};
-        }
-    }
-
-=item get_branch_style()
-
- Type    : Accessor
- Title   : get_branch_style
- Usage   : my $branch_style = $node->get_branch_style();
- Function: Gets branch_style
- Returns : branch_style
- Args    : NONE
-
-=cut
-
-    sub get_branch_style {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_style{$id};
-    }
-
-=item get_font_face()
-
- Type    : Accessor
- Title   : get_font_face
- Usage   : my $font_face = $node->get_font_face();
- Function: Gets font_face
- Returns : font_face
- Args    : NONE
-
-=cut
-
-    sub get_font_face {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $font_face{$id};
-    }
-
-=item get_font_size()
-
- Type    : Accessor
- Title   : get_font_size
- Usage   : my $font_size = $node->get_font_size();
- Function: Gets font_size
- Returns : font_size
- Args    : NONE
-
-=cut
-
-    sub get_font_size {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $font_size{$id};
-    }
-
-=item get_font_style()
-
- Type    : Accessor
- Title   : get_font_style
- Usage   : my $font_style = $node->get_font_style();
- Function: Gets font_style
- Returns : font_style
- Args    : NONE
-
-=cut
-
-    sub get_font_style {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $font_style{$id};
-    }
-
-=item get_font_colour()
-
- Type    : Accessor
- Title   : get_font_colour
- Usage   : my $color = $node->get_font_colour();
- Function: Gets font_colour
- Returns : font_colour
- Args    : NONE
-
-=cut
-    
-    sub get_font_colour {
-        my $self = shift;
-        my $id = $self->get_id;
-        return $font_color{$id};
-    }
-    *get_font_color = \&get_font_colour;
-
-=item get_text_horiz_offset()
-
- Type    : Accessor
- Title   : get_text_horiz_offset
- Usage   : my $text_horiz_offset = $node->get_text_horiz_offset();
- Function: Gets text_horiz_offset
- Returns : text_horiz_offset
- Args    : NONE
-
-=cut
-
-    sub get_text_horiz_offset {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $text_horiz_offset{$id};
-    }
-
-=item get_text_vert_offset()
-
- Type    : Accessor
- Title   : get_text_vert_offset
- Usage   : my $text_vert_offset = $node->get_text_vert_offset();
- Function: Gets text_vert_offset
- Returns : text_vert_offset
- Args    : NONE
-
-=cut
-
-    sub get_text_vert_offset {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $text_vert_offset{$id};
-    }
-
-=item get_rotation()
-
- Type    : Accessor
- Title   : get_rotation
- Usage   : my $rotation = $node->get_rotation();
- Function: Gets rotation
- Returns : rotation
- Args    : NONE
-
-=cut
-
-    sub get_rotation {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $rotation{$id};
-    }
-
-=back
-
-=head2 SERIALIZERS
-
-=over
-
-=item to_json()
-
-Serializes object to JSON string
-
- Type    : Serializer
- Title   : to_json()
- Usage   : print $obj->to_json();
- Function: Serializes object to JSON string
- Returns : String 
- Args    : None
- Comments:
-
-=cut
-
-    sub to_json {
-        my $node = shift;
-        my %args = (
-            'get_x'                 => 'x',
-            'get_y'                 => 'y',
-            'get_radius'            => 'radius',
-            'get_node_colour'       => 'node_colour',
-            'get_node_shape'        => 'node_shape',
-            'get_node_image'        => 'image',
-            'get_branch_color'      => 'branch_color',
-            'get_branch_shape'      => 'branch_shape',
-            'get_branch_width'      => 'width',
-            'get_branch_style'      => 'style',
-            'get_font_face'         => 'font_face',
-            'get_font_size'         => 'font_size',
-            'get_font_style'        => 'font_style',
-            'get_link'              => 'link',
-            'get_text_horiz_offset' => 'horiz_offset',
-            'get_text_vert_offset'  => 'vert_offset',
-        );
-        return $node->SUPER::to_json(%args);
-    }
-
-=begin comment
-
- Type    : Internal method
- Title   : _cleanup
- Usage   : $trees->_cleanup;
- Function: Called during object destruction, for cleanup of instance data
- Returns : 
- Args    :
-
-=end comment
-
-=cut
-
-    sub _cleanup {
-        my $self = shift;
-        my $id   = $self->get_id;
-        for my $field (@fields) {
-            delete $field->{$id};
-        }
-    }
-
-=back
-
-=cut
-
-    # podinherit_insert_token
-
-=head1 SEE ALSO
-
-There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo> 
-for any user or developer questions and discussions.
-
-=over
-
-=item L<Bio::Phylo::Forest::Node>
-
-This object inherits from L<Bio::Phylo::Forest::Node>, so methods
-defined there are also applicable here.
-
-=item L<Bio::Phylo::Manual>
-
-Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
-
-=back
-
-=head1 CITATION
-
-If you use Bio::Phylo in published research, please cite it:
-
-B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
-and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
-I<BMC Bioinformatics> B<12>:63.
-L<http://dx.doi.org/10.1186/1471-2105-12-63>
-
-=cut
-
-}
-1;
@@ -0,0 +1,573 @@
+package Bio::Phylo::Forest::DrawNodeRole;
+use strict;
+use Carp;
+use Bio::Phylo::Forest::NodeRole;
+use base 'Bio::Phylo::Forest::NodeRole';
+{
+
+	our $AUTOLOAD;
+	my @properties = qw(x y radius tip_radius node_color node_outline_color
+	node_shape node_image branch_color branch_shape branch_width branch_style
+	collapsed collapsed_width font_face font_size font_style font_color
+	text_horiz_offset text_vert_offset rotation);
+
+=head1 NAME
+
+Bio::Phylo::Forest::DrawNode - Tree node with extra methods for tree drawing
+
+=head1 SYNOPSIS
+
+ # see Bio::Phylo::Forest::Node
+
+=head1 DESCRIPTION
+
+This module defines a node object and its methods. The node is fairly
+syntactically rich in terms of navigation, and additional getters are provided to
+further ease navigation from node to node. Typical first daughter -> next sister
+traversal and recursion is possible, but there are also shrinkwrapped methods
+that return for example all terminal descendants of the focal node, or all
+internals, etc.
+
+Node objects are inserted into tree objects, although technically the tree
+object is only a container holding all the nodes together. Unless there are
+orphans all nodes can be reached without recourse to the tree object.
+
+In addition, this subclass of the default node object L<Bio::Phylo::Forest::Node>
+has getters and setters for drawing trees and nodes, e.g. X/Y coordinates, font
+and text attributes, etc.
+
+=head1 METHODS
+
+=head2 MUTATORS
+
+=over
+
+=item set_collapsed()
+
+ Type    : Mutator
+ Title   : set_collapsed
+ Usage   : $node->set_collapsed(1);
+ Function: Sets whether the node's descendants are shown as collapsed into a triangle
+ Returns : $self
+ Args    : true or false value
+
+=item set_collapsed_clade_width()
+
+Sets collapsed clade width.
+
+ Type    : Mutator
+ Title   : set_collapsed_clade_width
+ Usage   : $tree->set_collapsed_clade_width(6);
+ Function: sets the width of collapsed clade triangles relative to uncollapsed tips
+ Returns :
+ Args    : Positive number
+
+=item set_x()
+
+ Type    : Mutator
+ Title   : set_x
+ Usage   : $node->set_x($x);
+ Function: Sets x
+ Returns : $self
+ Args    : x
+
+=item set_y()
+
+ Type    : Mutator
+ Title   : set_y
+ Usage   : $node->set_y($y);
+ Function: Sets y
+ Returns : $self
+ Args    : y
+
+=item set_radius()
+
+ Type    : Mutator
+ Title   : set_radius
+ Usage   : $node->set_radius($radius);
+ Function: Sets radius
+ Returns : $self
+ Args    : radius
+
+=cut
+
+    *set_node_radius = \&set_radius;
+
+=item set_tip_radius()
+
+ Type    : Mutator
+ Title   : set_tip_node_radius
+ Usage   : $tree->set_tip_radius($node_radius);
+ Function: Sets tip radius
+ Returns : $self
+ Args    : tip radius
+
+=item set_node_color()
+
+ Type    : Mutator
+ Title   : set_node_color
+ Usage   : $node->set_node_color($node_color);
+ Function: Sets node_color
+ Returns : $self
+ Args    : node_color
+
+=item set_node_outline_color()
+
+ Type    : Mutator
+ Title   : set_node_outline_color
+ Usage   : $node->set_node_outline_color($node_outline_color);
+ Function: Sets node outline color
+ Returns : $self
+ Args    : node_color
+
+=item set_node_shape()
+
+ Type    : Mutator
+ Title   : set_node_shape
+ Usage   : $node->set_node_shape($node_shape);
+ Function: Sets node_shape
+ Returns : $self
+ Args    : node_shape
+
+=item set_node_image()
+
+ Type    : Mutator
+ Title   : set_node_image
+ Usage   : $node->set_node_image($node_image);
+ Function: Sets node_image
+ Returns : $self
+ Args    : node_image
+
+=item set_branch_color()
+
+ Type    : Mutator
+ Title   : set_branch_color
+ Usage   : $node->set_branch_color($branch_color);
+ Function: Sets branch_color
+ Returns : $self
+ Args    : branch_color
+
+=item set_branch_shape()
+
+ Type    : Mutator
+ Title   : set_branch_shape
+ Usage   : $node->set_branch_shape($branch_shape);
+ Function: Sets branch_shape
+ Returns : $self
+ Args    : branch_shape
+
+=item set_branch_width()
+
+ Type    : Mutator
+ Title   : set_branch_width
+ Usage   : $node->set_branch_width($branch_width);
+ Function: Sets branch width
+ Returns : $self
+ Args    : branch_width
+
+=item set_branch_style()
+
+ Type    : Mutator
+ Title   : set_branch_style
+ Usage   : $node->set_branch_style($branch_style);
+ Function: Sets branch style
+ Returns : $self
+ Args    : branch_style
+
+=item set_font_face()
+
+ Type    : Mutator
+ Title   : set_font_face
+ Usage   : $node->set_font_face($font_face);
+ Function: Sets font_face
+ Returns : $self
+ Args    : font_face
+
+=item set_font_size()
+
+ Type    : Mutator
+ Title   : set_font_size
+ Usage   : $node->set_font_size($font_size);
+ Function: Sets font_size
+ Returns : $self
+ Args    : font_size
+
+=item set_font_style()
+
+ Type    : Mutator
+ Title   : set_font_style
+ Usage   : $node->set_font_style($font_style);
+ Function: Sets font_style
+ Returns : $self
+ Args    : font_style
+
+=item set_font_color()
+
+ Type    : Mutator
+ Title   : set_font_color
+ Usage   : $node->set_font_color($color);
+ Function: Sets font_color
+ Returns : font_color
+ Args    : A color, which, depending on the underlying tree drawer, can either
+           be expressed as a word ('red'), a hex code ('#00CC00') or an rgb
+           statement ('rgb(0,255,0)')
+
+=item set_text_horiz_offset()
+
+ Type    : Mutator
+ Title   : set_text_horiz_offset
+ Usage   : $node->set_text_horiz_offset($text_horiz_offset);
+ Function: Sets text_horiz_offset
+ Returns : $self
+ Args    : text_horiz_offset
+
+=item set_text_vert_offset()
+
+ Type    : Mutator
+ Title   : set_text_vert_offset
+ Usage   : $node->set_text_vert_offset($text_vert_offset);
+ Function: Sets text_vert_offset
+ Returns : $self
+ Args    : text_vert_offset
+
+=item set_rotation()
+
+ Type    : Mutator
+ Title   : set_rotation
+ Usage   : $node->set_rotation($rotation);
+ Function: Sets rotation
+ Returns : $self
+ Args    : rotation
+
+=back
+
+=head2 ACCESSORS
+
+=over
+
+=item get_collapsed()
+
+ Type    : Mutator
+ Title   : get_collapsed
+ Usage   : something() if $node->get_collapsed();
+ Function: Gets whether the node's descendants are shown as collapsed into a triangle
+ Returns : true or false value
+ Args    : NONE
+
+=item get_first_daughter()
+
+Gets invocant's first daughter.
+
+ Type    : Accessor
+ Title   : get_first_daughter
+ Usage   : my $f_daughter = $node->get_first_daughter;
+ Function: Retrieves a node's leftmost daughter.
+ Returns : Bio::Phylo::Forest::Node
+ Args    : NONE
+
+=cut
+
+    sub get_first_daughter {
+        my $self = shift;
+        if ( $self->get_collapsed ) {
+            return;
+        }
+        else {
+            return $self->SUPER::get_first_daughter;
+        }
+    }
+
+=item get_last_daughter()
+
+Gets invocant's last daughter.
+
+ Type    : Accessor
+ Title   : get_last_daughter
+ Usage   : my $l_daughter = $node->get_last_daughter;
+ Function: Retrieves a node's rightmost daughter.
+ Returns : Bio::Phylo::Forest::Node
+ Args    : NONE
+
+=cut
+
+    sub get_last_daughter {
+        my $self = shift;
+        if ( $self->get_collapsed ) {
+            return;
+        }
+        else {
+            return $self->SUPER::get_last_daughter;
+        }
+    }
+
+=item get_children()
+
+Gets invocant's immediate children.
+
+ Type    : Query
+ Title   : get_children
+ Usage   : my @children = @{ $node->get_children };
+ Function: Returns an array reference of immediate
+           descendants, ordered from left to right.
+ Returns : Array reference of
+           Bio::Phylo::Forest::Node objects.
+ Args    : NONE
+
+=cut
+
+    sub get_children {
+        my $self = shift;
+        if ( $self->get_collapsed ) {
+            return [];
+        }
+        else {
+            return $self->SUPER::get_children;
+        }
+    }
+
+=item get_x()
+
+ Type    : Accessor
+ Title   : get_x
+ Usage   : my $x = $node->get_x();
+ Function: Gets x
+ Returns : x
+ Args    : NONE
+
+=item get_y()
+
+ Type    : Accessor
+ Title   : get_y
+ Usage   : my $y = $node->get_y();
+ Function: Gets y
+ Returns : y
+ Args    : NONE
+
+=item get_radius()
+
+ Type    : Accessor
+ Title   : get_radius
+ Usage   : my $radius = $node->get_radius();
+ Function: Gets radius
+ Returns : radius
+ Args    : NONE
+
+=item get_node_color()
+
+ Type    : Accessor
+ Title   : get_node_color
+ Usage   : my $node_color = $node->get_node_color();
+ Function: Gets node_color
+ Returns : node_color
+ Args    : NONE
+
+=item get_node_outline_color()
+
+ Type    : Accessor
+ Title   : get_node_outline_color
+ Usage   : my $node_outline_color = $node->get_node_outline_color();
+ Function: Gets node outline color
+ Returns : node_color
+ Args    : NONE
+
+=item get_node_shape()
+
+ Type    : Accessor
+ Title   : get_node_shape
+ Usage   : my $node_shape = $node->get_node_shape();
+ Function: Gets node_shape
+ Returns : node_shape
+ Args    : NONE
+
+=item get_node_image()
+
+ Type    : Accessor
+ Title   : get_node_image
+ Usage   : my $node_image = $node->get_node_image();
+ Function: Gets node_image
+ Returns : node_image
+ Args    : NONE
+
+=item get_collapsed_clade_width()
+
+Gets collapsed clade width.
+
+ Type    : Mutator
+ Title   : get_collapsed_clade_width
+ Usage   : $w = $tree->get_collapsed_clade_width();
+ Function: gets the width of collapsed clade triangles relative to uncollapsed tips
+ Returns : Positive number
+ Args    : None
+
+=item get_branch_color()
+
+ Type    : Accessor
+ Title   : get_branch_color
+ Usage   : my $branch_color = $node->get_branch_color();
+ Function: Gets branch_color
+ Returns : branch_color
+ Args    : NONE
+
+=item get_branch_shape()
+
+ Type    : Accessor
+ Title   : get_branch_shape
+ Usage   : my $branch_shape = $node->get_branch_shape();
+ Function: Gets branch_shape
+ Returns : branch_shape
+ Args    : NONE
+
+=item get_branch_width()
+
+ Type    : Accessor
+ Title   : get_branch_width
+ Usage   : my $branch_width = $node->get_branch_width();
+ Function: Gets branch_width
+ Returns : branch_width
+ Args    : NONE
+
+=item get_branch_style()
+
+ Type    : Accessor
+ Title   : get_branch_style
+ Usage   : my $branch_style = $node->get_branch_style();
+ Function: Gets branch_style
+ Returns : branch_style
+ Args    : NONE
+
+=item get_font_face()
+
+ Type    : Accessor
+ Title   : get_font_face
+ Usage   : my $font_face = $node->get_font_face();
+ Function: Gets font_face
+ Returns : font_face
+ Args    : NONE
+
+=item get_font_size()
+
+ Type    : Accessor
+ Title   : get_font_size
+ Usage   : my $font_size = $node->get_font_size();
+ Function: Gets font_size
+ Returns : font_size
+ Args    : NONE
+
+=item get_font_style()
+
+ Type    : Accessor
+ Title   : get_font_style
+ Usage   : my $font_style = $node->get_font_style();
+ Function: Gets font_style
+ Returns : font_style
+ Args    : NONE
+
+=item get_font_color()
+
+ Type    : Accessor
+ Title   : get_font_color
+ Usage   : my $color = $node->get_font_color();
+ Function: Gets font_color
+ Returns : font_color
+ Args    : NONE
+
+=item get_text_horiz_offset()
+
+ Type    : Accessor
+ Title   : get_text_horiz_offset
+ Usage   : my $text_horiz_offset = $node->get_text_horiz_offset();
+ Function: Gets text_horiz_offset
+ Returns : text_horiz_offset
+ Args    : NONE
+
+=item get_text_vert_offset()
+
+ Type    : Accessor
+ Title   : get_text_vert_offset
+ Usage   : my $text_vert_offset = $node->get_text_vert_offset();
+ Function: Gets text_vert_offset
+ Returns : text_vert_offset
+ Args    : NONE
+
+=item get_rotation()
+
+ Type    : Accessor
+ Title   : get_rotation
+ Usage   : my $rotation = $node->get_rotation();
+ Function: Gets rotation
+ Returns : rotation
+ Args    : NONE
+
+=back
+
+=cut
+
+	sub AUTOLOAD {
+		my $self = shift;
+		my $method = $AUTOLOAD;
+		$method =~ s/.+://; # strip package name
+		$method =~ s/colour/color/; # map British/Canadian to American :)
+		
+		# if the user calls some non-existant method, try to do the
+		# usual way, with this message, from perspective of caller
+		my $template = 'Can\'t locate object method "%s" via package "%s"';		
+		
+		if ( $method =~ /^set_(.+)$/ ) {
+			my $prop = $1;
+			if ( grep { /^\Q$prop\E$/ } @properties ) {
+				my $value = shift;
+				return $self->set_meta_object( "map:$prop" => $value );
+			}
+			else {
+				croak sprintf $template, $method, __PACKAGE__;
+			}
+		}
+		elsif ( $method =~ /^get_(.+)$/ ) {
+			my $prop = $1;
+			if ( grep { /^\Q$prop\E$/ } @properties ) {
+				my $value = shift;
+				return $self->get_meta_object( "map:$prop" );
+			}
+			else {
+				croak sprintf $template, $method, __PACKAGE__;
+			}			
+		}
+		else {
+			croak sprintf $template, $method, __PACKAGE__;
+		}
+	}
+
+
+    # podinherit_insert_token
+
+=head1 SEE ALSO
+
+There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo> 
+for any user or developer questions and discussions.
+
+=over
+
+=item L<Bio::Phylo::Forest::Node>
+
+This object inherits from L<Bio::Phylo::Forest::Node>, so methods
+defined there are also applicable here.
+
+=item L<Bio::Phylo::Manual>
+
+Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
+
+=back
+
+=head1 CITATION
+
+If you use Bio::Phylo in published research, please cite it:
+
+B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
+and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
+I<BMC Bioinformatics> B<12>:63.
+L<http://dx.doi.org/10.1186/1471-2105-12-63>
+
+=cut
+
+}
+1;
@@ -1,1252 +0,0 @@
-package Bio::Phylo::Forest::DrawTree;
-use strict;
-use base 'Bio::Phylo::Forest::Tree';
-use Bio::Phylo::Forest::DrawNode;
-use Bio::Phylo::Util::CONSTANT 'looks_like_hash';
-{
-
-    # @fields array necessary for object destruction
-    my @fields = \(
-        my (
-            %width,             %height,         %node_radius,
-            %tip_radius,        %node_colour,    %node_shape,
-            %node_image,        %branch_color,   %branch_shape,
-            %branch_width,      %branch_style,   %collapsed_width,
-            %font_face,         %font_size,      %font_style,
-            %margin,            %margin_top,     %margin_bottom,
-            %margin_left,       %margin_right,   %padding,
-            %padding_top,       %padding_bottom, %padding_left,
-            %padding_right,     %mode,           %shape,
-            %text_horiz_offset, %text_vert_offset,
-        )
-    );
-
-=head1 NAME
-
-Bio::Phylo::Forest::DrawTree - Tree with extra methods for tree drawing
-
-=head1 SYNOPSIS
-
- # see Bio::Phylo::Forest::Tree
-
-=head1 DESCRIPTION
-
-The object models a phylogenetic tree, a container of Bio::Phylo::For-
-est::Node objects. The tree object inherits from Bio::Phylo::Listable,
-so look there for more methods.
-
-In addition, this subclass of the default tree object L<Bio::Phylo::Forest::Tree>
-has getters and setters for drawing trees, e.g. font and text attributes, etc.
-
-=head1 METHODS
-
-=head2 CONSTRUCTORS
-
-=over
-
-=item new()
-
-Tree constructor.
-
- Type    : Constructor
- Title   : new
- Usage   : my $tree = Bio::Phylo::Forest::DrawTree->new;
- Function: Instantiates a Bio::Phylo::Forest::DrawTree object.
- Returns : A Bio::Phylo::Forest::DrawTree object.
- Args    : No required arguments.
-
-=cut
-
-    sub new {
-        my $class = shift;
-        my %args  = looks_like_hash @_;
-        if ( not $args{'-tree'} ) {
-            return $class->SUPER::new(@_);
-        }
-        else {
-            my $tree = $args{'-tree'};
-            my $self = $tree->clone;
-            bless $self, $class;
-            $self->visit( sub { bless shift, 'Bio::Phylo::Forest::DrawNode' } );
-            delete $args{'-tree'};
-            for my $key ( keys %args ) {
-                my $method = $key;
-                $method =~ s/^-/set_/;
-                $self->$method( $args{$key} );
-            }
-            return $self;
-        }
-    }
-
-=back
-
-=head2 MUTATORS
-
-=over
-
-=item set_width()
-
- Type    : Mutator
- Title   : set_width
- Usage   : $tree->set_width($width);
- Function: Sets width
- Returns : $self
- Args    : width
-
-=cut
-
-    sub set_width {
-        my ( $self, $width ) = @_;
-        my $id = $self->get_id;
-        $width{$id} = $width;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_height()
-
- Type    : Mutator
- Title   : set_height
- Usage   : $tree->set_height($height);
- Function: Sets height
- Returns : $self
- Args    : height
-
-=cut
-
-    sub set_height {
-        my ( $self, $height ) = @_;
-        my $id = $self->get_id;
-        $height{$id} = $height;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_node_radius()
-
- Type    : Mutator
- Title   : set_node_radius
- Usage   : $tree->set_node_radius($node_radius);
- Function: Sets node_radius
- Returns : $self
- Args    : node_radius
-
-=cut
-
-    sub set_node_radius {
-        my ( $self, $node_radius ) = @_;
-        my $id = $self->get_id;
-        $node_radius{$id} = $node_radius;
-        $self->_apply_to_nodes( 'set_radius', $node_radius );
-        return $self;
-    }
-
-=item set_tip_radius()
-
- Type    : Mutator
- Title   : set_tip_node_radius
- Usage   : $tree->set_tip_radius($node_radius);
- Function: Sets tip radius
- Returns : $self
- Args    : tip radius
-
-=cut
-
-    sub set_tip_radius {
-        my ( $self, $r ) = @_;
-        my $id = $self->get_id;
-        $tip_radius{$id} = $r;
-        $self->_apply_to_nodes( 'set_tip_radius', $r );
-        return $self;
-    }
-
-=item set_node_colour()
-
- Type    : Mutator
- Title   : set_node_colour
- Usage   : $tree->set_node_colour($node_colour);
- Function: Sets node_colour
- Returns : $self
- Args    : node_colour
-
-=cut
-
-    sub set_node_colour {
-        my ( $self, $node_colour ) = @_;
-        my $id = $self->get_id;
-        $node_colour{$id} = $node_colour;
-        $self->_apply_to_nodes( 'set_node_colour', $node_colour );
-        return $self;
-    }
-    *set_node_color = \&set_node_colour;
-
-=item set_node_shape()
-
- Type    : Mutator
- Title   : set_node_shape
- Usage   : $tree->set_node_shape($node_shape);
- Function: Sets node_shape
- Returns : $self
- Args    : node_shape
-
-=cut
-
-    sub set_node_shape {
-        my ( $self, $node_shape ) = @_;
-        my $id = $self->get_id;
-        $node_shape{$id} = $node_shape;
-        $self->_apply_to_nodes( 'set_node_shape', $node_shape );
-        return $self;
-    }
-
-=item set_node_image()
-
- Type    : Mutator
- Title   : set_node_image
- Usage   : $tree->set_node_image($node_image);
- Function: Sets node_image
- Returns : $self
- Args    : node_image
-
-=cut
-
-    sub set_node_image {
-        my ( $self, $node_image ) = @_;
-        my $id = $self->get_id;
-        $node_image{$id} = $node_image;
-        $self->_apply_to_nodes( 'set_node_image', $node_image );
-        return $self;
-    }
-
-=item set_collapsed_clade_width()
-
-Sets collapsed clade width.
-
- Type    : Mutator
- Title   : set_collapsed_clade_width
- Usage   : $tree->set_collapsed_clade_width(6);
- Function: sets the width of collapsed clade triangles relative to uncollapsed tips
- Returns :
- Args    : Positive number
-
-=cut
-
-    sub set_collapsed_clade_width {
-        my ( $self, $width ) = @_;
-        my $id = $self->get_id;
-        $collapsed_width{$id} = $width;
-        $self->_apply_to_nodes( 'set_collapsed_clade_width', $width );
-        return $self;
-    }
-
-=item set_branch_color()
-
- Type    : Mutator
- Title   : set_branch_color
- Usage   : $tree->set_branch_color($branch_color);
- Function: Sets branch_color
- Returns : $self
- Args    : branch_color
-
-=cut
-
-    sub set_branch_color {
-        my ( $self, $branch_color ) = @_;
-        my $id = $self->get_id;
-        $branch_color{$id} = $branch_color;
-        $self->_apply_to_nodes( 'set_branch_color', $branch_color );
-        return $self;
-    }
-    *set_branch_colour = \&set_branch_colour;
-
-=item set_branch_shape()
-
- Type    : Mutator
- Title   : set_branch_shape
- Usage   : $tree->set_branch_shape($branch_shape);
- Function: Sets branch_shape
- Returns : $self
- Args    : branch_shape
-
-=cut
-
-    sub set_branch_shape {
-        my ( $self, $branch_shape ) = @_;
-        my $id = $self->get_id;
-        $branch_shape{$id} = $branch_shape;
-        $self->_apply_to_nodes( 'set_branch_shape', $branch_shape );
-        return $self;
-    }
-
-=item set_branch_width()
-
- Type    : Mutator
- Title   : set_branch_width
- Usage   : $tree->set_branch_width($branch_width);
- Function: Sets branch width
- Returns : $self
- Args    : branch_width
-
-=cut
-
-    sub set_branch_width {
-        my ( $self, $branch_width ) = @_;
-        my $id = $self->get_id;
-        $branch_width{$id} = $branch_width;
-        $self->_apply_to_nodes( 'set_branch_width', $branch_width );
-        return $self;
-    }
-
-=item set_branch_style()
-
- Type    : Mutator
- Title   : set_branch_style
- Usage   : $tree->set_branch_style($branch_style);
- Function: Sets branch style
- Returns : $self
- Args    : branch_style
-
-=cut
-
-    sub set_branch_style {
-        my ( $self, $branch_style ) = @_;
-        my $id = $self->get_id;
-        $branch_style{$id} = $branch_style;
-        $self->_apply_to_nodes( 'set_branch_style', $branch_style );
-        return $self;
-    }
-
-=item set_font_face()
-
- Type    : Mutator
- Title   : set_font_face
- Usage   : $tree->set_font_face($font_face);
- Function: Sets font_face
- Returns : $self
- Args    : font face, Verdana, Arial, Serif
-
-=cut
-
-    sub set_font_face {
-        my ( $self, $font_face ) = @_;
-        my $id = $self->get_id;
-        $font_face{$id} = $font_face;
-        $self->_apply_to_nodes( 'set_font_face', $font_face );
-        return $self;
-    }
-
-=item set_font_size()
-
- Type    : Mutator
- Title   : set_font_size
- Usage   : $tree->set_font_size($font_size);
- Function: Sets font_size
- Returns : $self
- Args    : Font size in pixels
-
-=cut
-
-    sub set_font_size {
-        my ( $self, $font_size ) = @_;
-        my $id = $self->get_id;
-        $font_size{$id} = $font_size;
-        $self->_apply_to_nodes( 'set_font_size', $font_size );
-        return $self;
-    }
-
-=item set_font_style()
-
- Type    : Mutator
- Title   : set_font_style
- Usage   : $tree->set_font_style($font_style);
- Function: Sets font_style
- Returns : $self
- Args    : Font style, e.g. Italic
-
-=cut
-
-    sub set_font_style {
-        my ( $self, $font_style ) = @_;
-        my $id = $self->get_id;
-        $font_style{$id} = $font_style;
-        $self->_apply_to_nodes( 'set_font_style', $font_style );
-        return $self;
-    }
-
-=item set_margin()
-
- Type    : Mutator
- Title   : set_margin
- Usage   : $tree->set_margin($margin);
- Function: Sets margin
- Returns : $self
- Args    : margin
-
-=cut
-
-    sub set_margin {
-        my ( $self, $margin ) = @_;
-        my $id = $self->get_id;
-        $margin{$id} = $margin;
-        for my $setter (qw(top bottom left right)) {
-            my $method = 'set_margin_' . $setter;
-            $self->$method($margin);
-        }
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_margin_top()
-
- Type    : Mutator
- Title   : set_margin_top
- Usage   : $tree->set_margin_top($margin_top);
- Function: Sets margin_top
- Returns : $self
- Args    : margin_top
-
-=cut
-
-    sub set_margin_top {
-        my ( $self, $margin_top ) = @_;
-        my $id = $self->get_id;
-        $margin_top{$id} = $margin_top;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_margin_bottom()
-
- Type    : Mutator
- Title   : set_margin_bottom
- Usage   : $tree->set_margin_bottom($margin_bottom);
- Function: Sets margin_bottom
- Returns : $self
- Args    : margin_bottom
-
-=cut
-
-    sub set_margin_bottom {
-        my ( $self, $margin_bottom ) = @_;
-        my $id = $self->get_id;
-        $margin_bottom{$id} = $margin_bottom;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_margin_left()
-
- Type    : Mutator
- Title   : set_margin_left
- Usage   : $tree->set_margin_left($margin_left);
- Function: Sets margin_left
- Returns : $self
- Args    : margin_left
-
-=cut
-
-    sub set_margin_left {
-        my ( $self, $margin_left ) = @_;
-        my $id = $self->get_id;
-        $margin_left{$id} = $margin_left;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_margin_right()
-
- Type    : Mutator
- Title   : set_margin_right
- Usage   : $tree->set_margin_right($margin_right);
- Function: Sets margin_right
- Returns : $self
- Args    : margin_right
-
-=cut
-
-    sub set_margin_right {
-        my ( $self, $margin_right ) = @_;
-        my $id = $self->get_id;
-        $margin_right{$id} = $margin_right;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_padding()
-
- Type    : Mutator
- Title   : set_padding
- Usage   : $tree->set_padding($padding);
- Function: Sets padding
- Returns : $self
- Args    : padding
-
-=cut
-
-    sub set_padding {
-        my ( $self, $padding ) = @_;
-        my $id = $self->get_id;
-        $padding{$id} = $padding;
-        for my $setter (qw(top bottom left right)) {
-            my $method = 'set_padding_' . $setter;
-            $self->$method($padding);
-        }
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_padding_top()
-
- Type    : Mutator
- Title   : set_padding_top
- Usage   : $tree->set_padding_top($padding_top);
- Function: Sets padding_top
- Returns : $self
- Args    : padding_top
-
-=cut
-
-    sub set_padding_top {
-        my ( $self, $padding_top ) = @_;
-        my $id = $self->get_id;
-        $padding_top{$id} = $padding_top;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_padding_bottom()
-
- Type    : Mutator
- Title   : set_padding_bottom
- Usage   : $tree->set_padding_bottom($padding_bottom);
- Function: Sets padding_bottom
- Returns : $self
- Args    : padding_bottom
-
-=cut
-
-    sub set_padding_bottom {
-        my ( $self, $padding_bottom ) = @_;
-        my $id = $self->get_id;
-        $padding_bottom{$id} = $padding_bottom;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_padding_left()
-
- Type    : Mutator
- Title   : set_padding_left
- Usage   : $tree->set_padding_left($padding_left);
- Function: Sets padding_left
- Returns : $self
- Args    : padding_left
-
-=cut
-
-    sub set_padding_left {
-        my ( $self, $padding_left ) = @_;
-        my $id = $self->get_id;
-        $padding_left{$id} = $padding_left;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_padding_right()
-
- Type    : Mutator
- Title   : set_padding_right
- Usage   : $tree->set_padding_right($padding_right);
- Function: Sets padding_right
- Returns : $self
- Args    : padding_right
-
-=cut
-
-    sub set_padding_right {
-        my ( $self, $padding_right ) = @_;
-        my $id = $self->get_id;
-        $padding_right{$id} = $padding_right;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_mode()
-
- Type    : Mutator
- Title   : set_mode
- Usage   : $tree->set_mode($mode);
- Function: Sets mode
- Returns : $self
- Args    : mode, e.g. 'CLADO' or 'PHYLO'
-
-=cut
-
-    sub set_mode {
-        my ( $self, $mode ) = @_;
-        my $id = $self->get_id;
-        $mode{$id} = $mode;
-        $self->_redraw;
-        return $self;
-    }
-
-=item set_shape()
-
- Type    : Mutator
- Title   : set_shape
- Usage   : $tree->set_shape($shape);
- Function: Sets shape
- Returns : $self
- Args    : shape, e.g. 'RECT', 'CURVY', 'DIAG'
-
-=cut
-
-    sub set_shape {
-        my ( $self, $shape ) = @_;
-        my $id = $self->get_id;
-        $shape{$id} = $shape;
-        return $self;
-    }
-
-=item set_text_horiz_offset()
-
- Type    : Mutator
- Title   : set_text_horiz_offset
- Usage   : $tree->set_text_horiz_offset($text_horiz_offset);
- Function: Sets text_horiz_offset
- Returns : $self
- Args    : text_horiz_offset
-
-=cut
-
-    sub set_text_horiz_offset {
-        my ( $self, $text_horiz_offset ) = @_;
-        my $id = $self->get_id;
-        $text_horiz_offset{$id} = $text_horiz_offset;
-        $self->_apply_to_nodes( 'set_text_horiz_offset', $text_horiz_offset );
-        return $self;
-    }
-
-=item set_text_vert_offset()
-
- Type    : Mutator
- Title   : set_text_vert_offset
- Usage   : $tree->set_text_vert_offset($text_vert_offset);
- Function: Sets text_vert_offset
- Returns : $self
- Args    : text_vert_offset
-
-=cut
-
-    sub set_text_vert_offset {
-        my ( $self, $text_vert_offset ) = @_;
-        my $id = $self->get_id;
-        $text_vert_offset{$id} = $text_vert_offset;
-        $self->_apply_to_nodes( 'set_text_vert_offset', $text_vert_offset );
-        return $self;
-    }
-
-=back
-
-=head2 ACCESSORS
-
-=over
-
-=item get_width()
-
- Type    : Accessor
- Title   : get_width
- Usage   : my $width = $tree->get_width();
- Function: Gets width
- Returns : width
- Args    : NONE
-
-=cut
-
-    sub get_width {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $width{$id};
-    }
-
-=item get_height()
-
- Type    : Accessor
- Title   : get_height
- Usage   : my $height = $tree->get_height();
- Function: Gets height
- Returns : height
- Args    : NONE
-
-=cut
-
-    sub get_height {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $height{$id};
-    }
-
-=item get_node_radius()
-
- Type    : Accessor
- Title   : get_node_radius
- Usage   : my $node_radius = $tree->get_node_radius();
- Function: Gets node_radius
- Returns : node_radius
- Args    : NONE
-
-=cut
-
-    sub get_node_radius {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_radius{$id};
-    }
-
-=item get_node_colour()
-
- Type    : Accessor
- Title   : get_node_colour
- Usage   : my $node_colour = $tree->get_node_colour();
- Function: Gets node_colour
- Returns : node_colour
- Args    : NONE
-
-=cut
-
-    sub get_node_colour {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_colour{$id};
-    }
-    *get_node_color = \&get_node_colour;
-
-=item get_node_shape()
-
- Type    : Accessor
- Title   : get_node_shape
- Usage   : my $node_shape = $tree->get_node_shape();
- Function: Gets node_shape
- Returns : node_shape
- Args    : NONE
-
-=cut
-
-    sub get_node_shape {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_shape{$id};
-    }
-
-=item get_node_image()
-
- Type    : Accessor
- Title   : get_node_image
- Usage   : my $node_image = $tree->get_node_image();
- Function: Gets node_image
- Returns : node_image
- Args    : NONE
-
-=cut
-
-    sub get_node_image {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $node_image{$id};
-    }
-
-=item get_collapsed_clade_width()
-
-Gets collapsed clade width.
-
- Type    : Mutator
- Title   : get_collapsed_clade_width
- Usage   : $w = $tree->get_collapsed_clade_width();
- Function: gets the width of collapsed clade triangles relative to uncollapsed tips
- Returns : Positive number
- Args    : None
-
-=cut
-
-    sub get_collapsed_clade_width {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $collapsed_width{$id};
-    }
-
-=item get_branch_color()
-
- Type    : Accessor
- Title   : get_branch_color
- Usage   : my $branch_color = $tree->get_branch_color();
- Function: Gets branch_color
- Returns : branch_color
- Args    : NONE
-
-=cut
-
-    sub get_branch_color {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_color{$id};
-    }
-    *get_branch_colour = \&get_branch_color;
-
-=item get_branch_shape()
-
- Type    : Accessor
- Title   : get_branch_shape
- Usage   : my $branch_shape = $tree->get_branch_shape();
- Function: Gets branch_shape
- Returns : branch_shape
- Args    : NONE
-
-=cut
-
-    sub get_branch_shape {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_shape{$id};
-    }
-
-=item get_branch_width()
-
- Type    : Accessor
- Title   : get_branch_width
- Usage   : my $branch_width = $tree->get_branch_width();
- Function: Gets branch_width
- Returns : branch_width
- Args    : NONE
-
-=cut
-
-    sub get_branch_width {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_width{$id};
-    }
-
-=item get_branch_style()
-
- Type    : Accessor
- Title   : get_branch_style
- Usage   : my $branch_style = $tree->get_branch_style();
- Function: Gets branch_style
- Returns : branch_style
- Args    : NONE
-
-=cut
-
-    sub get_branch_style {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $branch_style{$id};
-    }
-
-=item get_font_face()
-
- Type    : Accessor
- Title   : get_font_face
- Usage   : my $font_face = $tree->get_font_face();
- Function: Gets font_face
- Returns : font_face
- Args    : NONE
-
-=cut
-
-    sub get_font_face {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $font_face{$id};
-    }
-
-=item get_font_size()
-
- Type    : Accessor
- Title   : get_font_size
- Usage   : my $font_size = $tree->get_font_size();
- Function: Gets font_size
- Returns : font_size
- Args    : NONE
-
-=cut
-
-    sub get_font_size {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $font_size{$id};
-    }
-
-=item get_font_style()
-
- Type    : Accessor
- Title   : get_font_style
- Usage   : my $font_style = $tree->get_font_style();
- Function: Gets font_style
- Returns : font_style
- Args    : NONE
-
-=cut
-
-    sub get_font_style {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $font_style{$id};
-    }
-
-=item get_margin()
-
- Type    : Accessor
- Title   : get_margin
- Usage   : my $margin = $tree->get_margin();
- Function: Gets margin
- Returns : margin
- Args    : NONE
-
-=cut
-
-    sub get_margin {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $margin{$id};
-    }
-
-=item get_margin_top()
-
- Type    : Accessor
- Title   : get_margin_top
- Usage   : my $margin_top = $tree->get_margin_top();
- Function: Gets margin_top
- Returns : margin_top
- Args    : NONE
-
-=cut
-
-    sub get_margin_top {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $margin_top{$id};
-    }
-
-=item get_margin_bottom()
-
- Type    : Accessor
- Title   : get_margin_bottom
- Usage   : my $margin_bottom = $tree->get_margin_bottom();
- Function: Gets margin_bottom
- Returns : margin_bottom
- Args    : NONE
-
-=cut
-
-    sub get_margin_bottom {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $margin_bottom{$id};
-    }
-
-=item get_margin_left()
-
- Type    : Accessor
- Title   : get_margin_left
- Usage   : my $margin_left = $tree->get_margin_left();
- Function: Gets margin_left
- Returns : margin_left
- Args    : NONE
-
-=cut
-
-    sub get_margin_left {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $margin_left{$id};
-    }
-
-=item get_margin_right()
-
- Type    : Accessor
- Title   : get_margin_right
- Usage   : my $margin_right = $tree->get_margin_right();
- Function: Gets margin_right
- Returns : margin_right
- Args    : NONE
-
-=cut
-
-    sub get_margin_right {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $margin_right{$id};
-    }
-
-=item get_padding()
-
- Type    : Accessor
- Title   : get_padding
- Usage   : my $padding = $tree->get_padding();
- Function: Gets padding
- Returns : padding
- Args    : NONE
-
-=cut
-
-    sub get_padding {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $padding{$id};
-    }
-
-=item get_padding_top()
-
- Type    : Accessor
- Title   : get_padding_top
- Usage   : my $padding_top = $tree->get_padding_top();
- Function: Gets padding_top
- Returns : padding_top
- Args    : NONE
-
-=cut
-
-    sub get_padding_top {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $padding_top{$id};
-    }
-
-=item get_padding_bottom()
-
- Type    : Accessor
- Title   : get_padding_bottom
- Usage   : my $padding_bottom = $tree->get_padding_bottom();
- Function: Gets padding_bottom
- Returns : padding_bottom
- Args    : NONE
-
-=cut
-
-    sub get_padding_bottom {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $padding_bottom{$id};
-    }
-
-=item get_padding_left()
-
- Type    : Accessor
- Title   : get_padding_left
- Usage   : my $padding_left = $tree->get_padding_left();
- Function: Gets padding_left
- Returns : padding_left
- Args    : NONE
-
-=cut
-
-    sub get_padding_left {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $padding_left{$id};
-    }
-
-=item get_padding_right()
-
- Type    : Accessor
- Title   : get_padding_right
- Usage   : my $padding_right = $tree->get_padding_right();
- Function: Gets padding_right
- Returns : padding_right
- Args    : NONE
-
-=cut
-
-    sub get_padding_right {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $padding_right{$id};
-    }
-
-=item get_mode()
-
- Type    : Accessor
- Title   : get_mode
- Usage   : my $mode = $tree->get_mode();
- Function: Gets mode
- Returns : mode
- Args    : NONE
-
-=cut
-
-    sub get_mode {
-        my $self = shift;
-        my $id   = $self->get_id;
-        if ( $self->is_cladogram ) {
-            $mode{$id} = 'CLADO';
-        }
-        return $mode{$id};
-    }
-
-=item get_shape()
-
- Type    : Accessor
- Title   : get_shape
- Usage   : my $shape = $tree->get_shape();
- Function: Gets shape
- Returns : shape
- Args    : NONE
-
-=cut
-
-    sub get_shape {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $shape{$id};
-    }
-
-=item get_text_horiz_offset()
-
- Type    : Accessor
- Title   : get_text_horiz_offset
- Usage   : my $text_horiz_offset = $tree->get_text_horiz_offset();
- Function: Gets text_horiz_offset
- Returns : text_horiz_offset
- Args    : NONE
-
-=cut
-
-    sub get_text_horiz_offset {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $text_horiz_offset{$id};
-    }
-
-=item get_text_vert_offset()
-
- Type    : Accessor
- Title   : get_text_vert_offset
- Usage   : my $text_vert_offset = $tree->get_text_vert_offset();
- Function: Gets text_vert_offset
- Returns : text_vert_offset
- Args    : NONE
-
-=cut
-
-    sub get_text_vert_offset {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $text_vert_offset{$id};
-    }
-
-=begin comment
-
-This method re-computes the node coordinates
-
-=end comment
-
-=cut
-
-    sub _redraw {
-        my $self = shift;
-        my ( $width, $height ) = ( $self->get_width, $self->get_height );
-        my $tips_seen  = 0;
-        my $total_tips = $self->calc_number_of_terminals();
-        my $tallest    = $self->get_root->calc_max_path_to_tips;
-        my $maxnodes   = $self->get_root->calc_max_nodes_to_tips;
-        my $is_clado   = $self->get_mode =~ m/^c/i;
-        $self->visit_depth_first(
-            '-post' => sub {
-                my $node = shift;
-                my ( $x, $y );
-                if ( $node->is_terminal ) {
-                    $tips_seen++;
-                    $y = ( $height / $total_tips ) * $tips_seen;
-                    $x =
-                        $is_clado
-                      ? $width
-                      : ( $width / $tallest ) * $node->calc_path_to_root;
-                }
-                else {
-                    my @children = @{ $node->get_children };
-                    $y += $_->get_y for @children;
-                    $y /= scalar @children;
-                    $x =
-                        $is_clado
-                      ? $width -
-                      ( ( $width / $maxnodes ) * $node->calc_max_nodes_to_tips )
-                      : ( $width / $tallest ) * $node->calc_path_to_root;
-                }
-                $node->set_y($y);
-                $node->set_x($x);
-            }
-        );
-    }
-
-=begin comment
-
-This method applies settings for nodes globally.
-
-=end comment
-
-=cut
-
-    sub _apply_to_nodes {
-        my ( $self, $method, $value ) = @_;
-        $self->visit( sub { shift->$method($value) } );
-    }
-
-=begin comment
-
- Type    : Internal method
- Title   : _cleanup
- Usage   : $trees->_cleanup;
- Function: Called during object destruction, for cleanup of instance data
- Returns : 
- Args    :
-
-=end comment
-
-=cut
-
-    sub _cleanup {
-        my $self = shift;
-        my $id   = $self->get_id;
-        for my $field (@fields) {
-            delete $field->{$id};
-        }
-    }
-
-=back
-
-=cut
-
-    # podinherit_insert_token
-
-=head1 SEE ALSO
-
-There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo> 
-for any user or developer questions and discussions.
-
-=over
-
-=item L<Bio::Phylo::Forest::Tree>
-
-This object inherits from L<Bio::Phylo::Forest::Tree>, so methods
-defined there are also applicable here.
-
-=item L<Bio::Phylo::Manual>
-
-Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
-
-=back
-
-=head1 CITATION
-
-If you use Bio::Phylo in published research, please cite it:
-
-B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
-and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
-I<BMC Bioinformatics> B<12>:63.
-L<http://dx.doi.org/10.1186/1471-2105-12-63>
-
-=cut
-
-}
-1;
@@ -0,0 +1,760 @@
+package Bio::Phylo::Forest::DrawTreeRole;
+use strict;
+use Carp;
+use Bio::Phylo::Forest::TreeRole;
+use base 'Bio::Phylo::Forest::TreeRole';
+use Bio::Phylo::Forest::DrawNodeRole;
+use Bio::Phylo::Util::CONSTANT 'looks_like_hash';
+{
+
+	our $AUTOLOAD;
+	my @properties = qw(width height node_radius tip_radius node_color node_shape
+	node_image branch_color branch_shape branch_width branch_style collapsed_width
+	font_face font_size font_style margin margin_top margin_bottom margin_left 
+	margin_right padding padding_top padding_bottom padding_left padding_right
+	mode shape text_horiz_offset text_vert_offset);
+
+=head1 NAME
+
+Bio::Phylo::Forest::DrawTree - Tree with extra methods for tree drawing
+
+=head1 SYNOPSIS
+
+ # see Bio::Phylo::Forest::Tree
+
+=head1 DESCRIPTION
+
+The object models a phylogenetic tree, a container of Bio::Phylo::For-
+est::Node objects. The tree object inherits from Bio::Phylo::Listable,
+so look there for more methods.
+
+In addition, this subclass of the default tree object L<Bio::Phylo::Forest::Tree>
+has getters and setters for drawing trees, e.g. font and text attributes, etc.
+
+=head1 METHODS
+
+=head2 CONSTRUCTORS
+
+=over
+
+=item new()
+
+Tree constructor.
+
+ Type    : Constructor
+ Title   : new
+ Usage   : my $tree = Bio::Phylo::Forest::DrawTree->new;
+ Function: Instantiates a Bio::Phylo::Forest::DrawTree object.
+ Returns : A Bio::Phylo::Forest::DrawTree object.
+ Args    : No required arguments.
+
+=cut
+
+    sub new {
+        my $class = shift;
+        my %args  = looks_like_hash @_;
+        if ( not $args{'-tree'} ) {
+            return $class->SUPER::new(@_);
+        }
+        else {
+            my $tree = $args{'-tree'};
+            my $self = $tree->clone;
+            bless $self, $class;
+            for my $node ( @{ $self->get_entities } ) {
+            	bless $node, 'Bio::Phylo::Forest::DrawNode';
+            }              
+            
+            delete $args{'-tree'};
+            for my $key ( keys %args ) {
+                my $method = $key;
+                $method =~ s/^-/set_/;
+                $self->$method( $args{$key} );
+            }
+            return $self;
+        }
+    }
+
+=back
+
+=head2 MUTATORS
+
+=over
+
+=item set_width()
+
+ Type    : Mutator
+ Title   : set_width
+ Usage   : $tree->set_width($width);
+ Function: Sets width
+ Returns : $self
+ Args    : width
+
+=item set_height()
+
+ Type    : Mutator
+ Title   : set_height
+ Usage   : $tree->set_height($height);
+ Function: Sets height
+ Returns : $self
+ Args    : height
+
+=item set_node_radius()
+
+ Type    : Mutator
+ Title   : set_node_radius
+ Usage   : $tree->set_node_radius($node_radius);
+ Function: Sets node_radius
+ Returns : $self
+ Args    : node_radius
+
+=item set_tip_radius()
+
+ Type    : Mutator
+ Title   : set_tip_node_radius
+ Usage   : $tree->set_tip_radius($node_radius);
+ Function: Sets tip radius
+ Returns : $self
+ Args    : tip radius
+
+=item set_node_colour()
+
+ Type    : Mutator
+ Title   : set_node_colour
+ Usage   : $tree->set_node_colour($node_colour);
+ Function: Sets node_colour
+ Returns : $self
+ Args    : node_colour
+
+=item set_node_shape()
+
+ Type    : Mutator
+ Title   : set_node_shape
+ Usage   : $tree->set_node_shape($node_shape);
+ Function: Sets node_shape
+ Returns : $self
+ Args    : node_shape
+
+=item set_node_image()
+
+ Type    : Mutator
+ Title   : set_node_image
+ Usage   : $tree->set_node_image($node_image);
+ Function: Sets node_image
+ Returns : $self
+ Args    : node_image
+
+=item set_collapsed_clade_width()
+
+Sets collapsed clade width.
+
+ Type    : Mutator
+ Title   : set_collapsed_clade_width
+ Usage   : $tree->set_collapsed_clade_width(6);
+ Function: sets the width of collapsed clade triangles relative to uncollapsed tips
+ Returns :
+ Args    : Positive number
+
+=item set_branch_color()
+
+ Type    : Mutator
+ Title   : set_branch_color
+ Usage   : $tree->set_branch_color($branch_color);
+ Function: Sets branch_color
+ Returns : $self
+ Args    : branch_color
+
+=item set_branch_shape()
+
+ Type    : Mutator
+ Title   : set_branch_shape
+ Usage   : $tree->set_branch_shape($branch_shape);
+ Function: Sets branch_shape
+ Returns : $self
+ Args    : branch_shape
+
+=item set_branch_width()
+
+ Type    : Mutator
+ Title   : set_branch_width
+ Usage   : $tree->set_branch_width($branch_width);
+ Function: Sets branch width
+ Returns : $self
+ Args    : branch_width
+
+=item set_branch_style()
+
+ Type    : Mutator
+ Title   : set_branch_style
+ Usage   : $tree->set_branch_style($branch_style);
+ Function: Sets branch style
+ Returns : $self
+ Args    : branch_style
+
+=item set_font_face()
+
+ Type    : Mutator
+ Title   : set_font_face
+ Usage   : $tree->set_font_face($font_face);
+ Function: Sets font_face
+ Returns : $self
+ Args    : font face, Verdana, Arial, Serif
+
+=item set_font_size()
+
+ Type    : Mutator
+ Title   : set_font_size
+ Usage   : $tree->set_font_size($font_size);
+ Function: Sets font_size
+ Returns : $self
+ Args    : Font size in pixels
+
+=item set_font_style()
+
+ Type    : Mutator
+ Title   : set_font_style
+ Usage   : $tree->set_font_style($font_style);
+ Function: Sets font_style
+ Returns : $self
+ Args    : Font style, e.g. Italic
+
+=item set_margin()
+
+ Type    : Mutator
+ Title   : set_margin
+ Usage   : $tree->set_margin($margin);
+ Function: Sets margin
+ Returns : $self
+ Args    : margin
+
+=item set_margin_top()
+
+ Type    : Mutator
+ Title   : set_margin_top
+ Usage   : $tree->set_margin_top($margin_top);
+ Function: Sets margin_top
+ Returns : $self
+ Args    : margin_top
+
+=item set_margin_bottom()
+
+ Type    : Mutator
+ Title   : set_margin_bottom
+ Usage   : $tree->set_margin_bottom($margin_bottom);
+ Function: Sets margin_bottom
+ Returns : $self
+ Args    : margin_bottom
+
+=item set_margin_left()
+
+ Type    : Mutator
+ Title   : set_margin_left
+ Usage   : $tree->set_margin_left($margin_left);
+ Function: Sets margin_left
+ Returns : $self
+ Args    : margin_left
+
+=item set_margin_right()
+
+ Type    : Mutator
+ Title   : set_margin_right
+ Usage   : $tree->set_margin_right($margin_right);
+ Function: Sets margin_right
+ Returns : $self
+ Args    : margin_right
+
+=item set_padding()
+
+ Type    : Mutator
+ Title   : set_padding
+ Usage   : $tree->set_padding($padding);
+ Function: Sets padding
+ Returns : $self
+ Args    : padding
+
+=item set_padding_top()
+
+ Type    : Mutator
+ Title   : set_padding_top
+ Usage   : $tree->set_padding_top($padding_top);
+ Function: Sets padding_top
+ Returns : $self
+ Args    : padding_top
+
+=item set_padding_bottom()
+
+ Type    : Mutator
+ Title   : set_padding_bottom
+ Usage   : $tree->set_padding_bottom($padding_bottom);
+ Function: Sets padding_bottom
+ Returns : $self
+ Args    : padding_bottom
+
+=item set_padding_left()
+
+ Type    : Mutator
+ Title   : set_padding_left
+ Usage   : $tree->set_padding_left($padding_left);
+ Function: Sets padding_left
+ Returns : $self
+ Args    : padding_left
+
+=item set_padding_right()
+
+ Type    : Mutator
+ Title   : set_padding_right
+ Usage   : $tree->set_padding_right($padding_right);
+ Function: Sets padding_right
+ Returns : $self
+ Args    : padding_right
+
+=item set_mode()
+
+ Type    : Mutator
+ Title   : set_mode
+ Usage   : $tree->set_mode($mode);
+ Function: Sets mode
+ Returns : $self
+ Args    : mode, e.g. 'CLADO' or 'PHYLO'
+
+=item set_shape()
+
+ Type    : Mutator
+ Title   : set_shape
+ Usage   : $tree->set_shape($shape);
+ Function: Sets shape
+ Returns : $self
+ Args    : shape, e.g. 'RECT', 'CURVY', 'DIAG'
+
+=item set_text_horiz_offset()
+
+ Type    : Mutator
+ Title   : set_text_horiz_offset
+ Usage   : $tree->set_text_horiz_offset($text_horiz_offset);
+ Function: Sets text_horiz_offset
+ Returns : $self
+ Args    : text_horiz_offset
+
+=item set_text_vert_offset()
+
+ Type    : Mutator
+ Title   : set_text_vert_offset
+ Usage   : $tree->set_text_vert_offset($text_vert_offset);
+ Function: Sets text_vert_offset
+ Returns : $self
+ Args    : text_vert_offset
+
+=back
+
+=head2 ACCESSORS
+
+=over
+
+=item get_width()
+
+ Type    : Accessor
+ Title   : get_width
+ Usage   : my $width = $tree->get_width();
+ Function: Gets width
+ Returns : width
+ Args    : NONE
+
+=item get_height()
+
+ Type    : Accessor
+ Title   : get_height
+ Usage   : my $height = $tree->get_height();
+ Function: Gets height
+ Returns : height
+ Args    : NONE
+
+=item get_node_radius()
+
+ Type    : Accessor
+ Title   : get_node_radius
+ Usage   : my $node_radius = $tree->get_node_radius();
+ Function: Gets node_radius
+ Returns : node_radius
+ Args    : NONE
+
+=item get_node_colour()
+
+ Type    : Accessor
+ Title   : get_node_colour
+ Usage   : my $node_colour = $tree->get_node_colour();
+ Function: Gets node_colour
+ Returns : node_colour
+ Args    : NONE
+
+=item get_node_shape()
+
+ Type    : Accessor
+ Title   : get_node_shape
+ Usage   : my $node_shape = $tree->get_node_shape();
+ Function: Gets node_shape
+ Returns : node_shape
+ Args    : NONE
+
+=item get_node_image()
+
+ Type    : Accessor
+ Title   : get_node_image
+ Usage   : my $node_image = $tree->get_node_image();
+ Function: Gets node_image
+ Returns : node_image
+ Args    : NONE
+
+=item get_collapsed_clade_width()
+
+Gets collapsed clade width.
+
+ Type    : Mutator
+ Title   : get_collapsed_clade_width
+ Usage   : $w = $tree->get_collapsed_clade_width();
+ Function: gets the width of collapsed clade triangles relative to uncollapsed tips
+ Returns : Positive number
+ Args    : None
+
+=item get_branch_color()
+
+ Type    : Accessor
+ Title   : get_branch_color
+ Usage   : my $branch_color = $tree->get_branch_color();
+ Function: Gets branch_color
+ Returns : branch_color
+ Args    : NONE
+
+=item get_branch_shape()
+
+ Type    : Accessor
+ Title   : get_branch_shape
+ Usage   : my $branch_shape = $tree->get_branch_shape();
+ Function: Gets branch_shape
+ Returns : branch_shape
+ Args    : NONE
+
+=item get_branch_width()
+
+ Type    : Accessor
+ Title   : get_branch_width
+ Usage   : my $branch_width = $tree->get_branch_width();
+ Function: Gets branch_width
+ Returns : branch_width
+ Args    : NONE
+
+=item get_branch_style()
+
+ Type    : Accessor
+ Title   : get_branch_style
+ Usage   : my $branch_style = $tree->get_branch_style();
+ Function: Gets branch_style
+ Returns : branch_style
+ Args    : NONE
+
+=item get_font_face()
+
+ Type    : Accessor
+ Title   : get_font_face
+ Usage   : my $font_face = $tree->get_font_face();
+ Function: Gets font_face
+ Returns : font_face
+ Args    : NONE
+
+=item get_font_size()
+
+ Type    : Accessor
+ Title   : get_font_size
+ Usage   : my $font_size = $tree->get_font_size();
+ Function: Gets font_size
+ Returns : font_size
+ Args    : NONE
+
+=item get_font_style()
+
+ Type    : Accessor
+ Title   : get_font_style
+ Usage   : my $font_style = $tree->get_font_style();
+ Function: Gets font_style
+ Returns : font_style
+ Args    : NONE
+
+=item get_margin()
+
+ Type    : Accessor
+ Title   : get_margin
+ Usage   : my $margin = $tree->get_margin();
+ Function: Gets margin
+ Returns : margin
+ Args    : NONE
+
+=item get_margin_top()
+
+ Type    : Accessor
+ Title   : get_margin_top
+ Usage   : my $margin_top = $tree->get_margin_top();
+ Function: Gets margin_top
+ Returns : margin_top
+ Args    : NONE
+
+=item get_margin_bottom()
+
+ Type    : Accessor
+ Title   : get_margin_bottom
+ Usage   : my $margin_bottom = $tree->get_margin_bottom();
+ Function: Gets margin_bottom
+ Returns : margin_bottom
+ Args    : NONE
+
+=item get_margin_left()
+
+ Type    : Accessor
+ Title   : get_margin_left
+ Usage   : my $margin_left = $tree->get_margin_left();
+ Function: Gets margin_left
+ Returns : margin_left
+ Args    : NONE
+
+=item get_margin_right()
+
+ Type    : Accessor
+ Title   : get_margin_right
+ Usage   : my $margin_right = $tree->get_margin_right();
+ Function: Gets margin_right
+ Returns : margin_right
+ Args    : NONE
+
+=item get_padding()
+
+ Type    : Accessor
+ Title   : get_padding
+ Usage   : my $padding = $tree->get_padding();
+ Function: Gets padding
+ Returns : padding
+ Args    : NONE
+
+=item get_padding_top()
+
+ Type    : Accessor
+ Title   : get_padding_top
+ Usage   : my $padding_top = $tree->get_padding_top();
+ Function: Gets padding_top
+ Returns : padding_top
+ Args    : NONE
+
+=item get_padding_bottom()
+
+ Type    : Accessor
+ Title   : get_padding_bottom
+ Usage   : my $padding_bottom = $tree->get_padding_bottom();
+ Function: Gets padding_bottom
+ Returns : padding_bottom
+ Args    : NONE
+
+=item get_padding_left()
+
+ Type    : Accessor
+ Title   : get_padding_left
+ Usage   : my $padding_left = $tree->get_padding_left();
+ Function: Gets padding_left
+ Returns : padding_left
+ Args    : NONE
+
+=item get_padding_right()
+
+ Type    : Accessor
+ Title   : get_padding_right
+ Usage   : my $padding_right = $tree->get_padding_right();
+ Function: Gets padding_right
+ Returns : padding_right
+ Args    : NONE
+
+=item get_mode()
+
+ Type    : Accessor
+ Title   : get_mode
+ Usage   : my $mode = $tree->get_mode();
+ Function: Gets mode
+ Returns : mode
+ Args    : NONE
+
+=cut
+
+    sub get_mode {
+        my $self = shift;
+        if ( $self->is_cladogram ) {
+            return 'CLADO';
+        }
+        return $self->get_meta_object( 'map:mode' );
+    }
+
+=item get_shape()
+
+ Type    : Accessor
+ Title   : get_shape
+ Usage   : my $shape = $tree->get_shape();
+ Function: Gets shape
+ Returns : shape
+ Args    : NONE
+
+=item get_text_horiz_offset()
+
+ Type    : Accessor
+ Title   : get_text_horiz_offset
+ Usage   : my $text_horiz_offset = $tree->get_text_horiz_offset();
+ Function: Gets text_horiz_offset
+ Returns : text_horiz_offset
+ Args    : NONE
+
+=item get_text_vert_offset()
+
+ Type    : Accessor
+ Title   : get_text_vert_offset
+ Usage   : my $text_vert_offset = $tree->get_text_vert_offset();
+ Function: Gets text_vert_offset
+ Returns : text_vert_offset
+ Args    : NONE
+
+=begin comment
+
+This method re-computes the node coordinates
+
+=end comment
+
+=cut
+
+    sub _redraw {
+        my $self = shift;
+        my ( $width, $height ) = ( $self->get_width, $self->get_height );
+        my $tips_seen  = 0;
+        my $total_tips = $self->calc_number_of_terminals();
+        if ( my $root = $self->get_root ) {
+			my $tallest    = $root->calc_max_path_to_tips;
+			my $maxnodes   = $root->calc_max_nodes_to_tips;
+			my $is_clado   = $self->get_mode =~ m/^c/i;
+			$self->visit_depth_first(
+				'-post' => sub {
+					my $node = shift;
+					my ( $x, $y );
+					if ( $node->is_terminal ) {
+						$tips_seen++;
+						$y = ( $height / $total_tips ) * $tips_seen;
+						$x =
+							$is_clado
+						  ? $width
+						  : ( $width / $tallest ) * $node->calc_path_to_root;
+					}
+					else {
+						my @children = @{ $node->get_children };
+						$y += $_->get_y for @children;
+						$y /= scalar @children;
+						$x =
+							$is_clado
+						  ? $width -
+						  ( ( $width / $maxnodes ) * $node->calc_max_nodes_to_tips )
+						  : ( $width / $tallest ) * $node->calc_path_to_root;
+					}
+					$node->set_y($y);
+					$node->set_x($x);
+				}
+			);
+        }
+    }
+
+
+=back
+
+=cut
+
+	sub AUTOLOAD {
+		my $self = shift;
+		my $method = $AUTOLOAD;
+		$method =~ s/.+://; # strip package names
+		$method =~ s/colour/color/; # map Canadian/British to American :)
+		
+		# if the user calls some non-existant method, try to do the
+		# usual way, with this message, from perspective of caller
+		my $template = 'Can\'t locate object method "%s" via package "%s"';
+		
+		# handler set_* method calls
+		if ( $method =~ /^set_(.+)$/ ) {
+			my $prop = $1;
+
+			# test if this is actually settable			
+			if ( grep { /^\Q$prop\E$/ } @properties ) {
+				my $value = shift;
+			
+				# these are properties that must be applied to all nodes
+				if ( $prop =~ /_(?:node|tip|branch|clade|font|text)_/ ) {
+					$self->visit(sub{
+						my $node = shift;
+						$node->$method($value);
+					});
+				}
+			
+				# these are properties that must be expanded to left/right/top/bottom
+				if ( $prop =~ /_(?:margin|padding)$/ ) {
+					for my $pos ( qw(left right top bottom) ) {
+						my $expanded = $method . '_' . $pos;
+						$self->$expanded($value);
+					}
+				}
+			
+				# also apply the property to the tree itself
+				$self->set_meta_object( "map:$prop" => $value );
+				$self->_redraw;
+				return $self;
+			}
+			else {				
+				croak sprintf $template, $method, __PACKAGE__;
+			}
+		}
+		elsif ( $method =~ /^get_(.+)$/ ) {
+			my $prop = $1;
+			
+			# test if this is actually gettable			
+			if ( grep { /^\Q$prop\E$/ } @properties ) {
+			
+				# return the annotation
+				return $self->get_meta_object( "map:$prop" );
+			}
+			else {				
+				croak sprintf $template, $method, __PACKAGE__;
+			}			
+		}
+		else {
+			croak sprintf $template, $method, __PACKAGE__;
+		}	
+	}
+
+    # podinherit_insert_token
+
+=head1 SEE ALSO
+
+There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo> 
+for any user or developer questions and discussions.
+
+=over
+
+=item L<Bio::Phylo::Forest::Tree>
+
+This object inherits from L<Bio::Phylo::Forest::Tree>, so methods
+defined there are also applicable here.
+
+=item L<Bio::Phylo::Manual>
+
+Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
+
+=back
+
+=head1 CITATION
+
+If you use Bio::Phylo in published research, please cite it:
+
+B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
+and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
+I<BMC Bioinformatics> B<12>:63.
+L<http://dx.doi.org/10.1186/1471-2105-12-63>
+
+=cut
+
+}
+1;
@@ -1,7 +1,7 @@
 package Bio::Phylo::Forest::Node;
 use strict;
-use Bio::Phylo::Forest::NodeRole;
-use base qw'Bio::Phylo::Forest::NodeRole';
+use Bio::Phylo::Forest::DrawNodeRole;
+use base qw'Bio::Phylo::Forest::DrawNodeRole';
 use Bio::Phylo::Util::CONSTANT qw':objecttypes /looks_like/';
 use Bio::Phylo::Util::Exceptions 'throw';
 use Scalar::Util 'weaken';
@@ -102,7 +102,7 @@ Sets argument as invocant's parent.
 
 =cut
 
-    sub set_parent : Mutator {
+    sub set_parent : Clonable {
         my ( $self, $parent ) = @_;
         if ( $parent and looks_like_object $parent, $TYPE_CONSTANT ) {
             $parent->set_child($self);
@@ -127,7 +127,7 @@ Sets argument as invocant's child.
 
 =cut
 
-    sub set_child : Mutator {
+    sub set_child {
         my ( $self, $child, $i ) = @_;
 
         # bad args?
@@ -194,7 +194,7 @@ Sets argument as invocant's child.
         $set_raw_child->( $self, $child, $i );
         return $self;
     }
-
+    
 =item set_branch_length()
 
 Sets argument as invocant's branch length.
@@ -211,7 +211,7 @@ Sets argument as invocant's branch length.
 
 =cut
 
-    sub set_branch_length : Mutator {
+    sub set_branch_length : Clonable {
         my ( $self, $bl ) = @_;
         my $id = $self->get_id;
         if ( defined $bl && looks_like_number $bl && !ref $bl ) {
@@ -242,7 +242,7 @@ Sets what tree invocant belongs to
 
 =cut
 
-    sub set_tree : Mutator {
+    sub set_tree : Clonable {
         my ( $self, $tree ) = @_;
         my $id = $self->get_id;
         if ($tree) {
@@ -273,7 +273,7 @@ Gets invocant's parent.
 
 =cut
 
-    sub get_parent : Mutator { return $get_parent->(shift) }    
+    sub get_parent { return $get_parent->(shift) }    
 
 =item get_branch_length()
 
@@ -292,7 +292,7 @@ Gets invocant's branch length.
 
 =cut
 
-    sub get_branch_length : Accessor { return $get_branch_length->(shift) }
+    sub get_branch_length { return $get_branch_length->(shift) }
 
 =item get_children()
 
@@ -309,7 +309,7 @@ Gets invocant's immediate children.
 
 =cut
 
-    sub get_children : Accessor { return $get_children->(shift) }
+    sub get_children { return $get_children->(shift) }
     
 =item get_tree()
 
@@ -324,7 +324,7 @@ Returns the tree invocant belongs to
 
 =cut
 
-    sub get_tree : Accessor {
+    sub get_tree {
         my $self = shift;
         my $id   = $self->get_id;
         return $tree{$id};
@@ -343,7 +343,7 @@ Returns the tree invocant belongs to
 
 =cut
 
-    sub _cleanup : Protected {
+    sub _cleanup : Destructor {
         my $self = shift;
         my $id   = $self->get_id;
         for my $field (@fields) {
@@ -104,7 +104,7 @@ Node constructor.
 
 =cut
 
-    sub new {
+    sub new : Constructor {
 
         # could be child class
         my $class = shift;
@@ -1872,69 +1872,6 @@ Visits nodes in a level order traversal.
 
 =back
 
-=head2 UTILITY METHODS
-
-=over
-
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : Optional: a hash of code references to 
-           override reflection-based getter/setter copying
-
-           my $clone = $object->clone(  
-               'set_forest' => sub {
-                   my ( $self, $clone ) = @_;
-                   for my $forest ( @{ $self->get_forests } ) {
-                       $clone->set_forest( $forest );
-                   }
-               },
-               'set_matrix' => sub {
-                   my ( $self, $clone ) = @_;
-                   for my $matrix ( @{ $self->get_matrices } ) {
-                       $clone->set_matrix( $matrix );
-                   }
-           );
-
- Comments: Cloning is currently experimental, use with caution.
-           It works on the assumption that the output of get_foo
-           called on the invocant is to be provided as argument
-           to set_foo on the clone - such as 
-           $clone->set_name( $self->get_name ). Sometimes this 
-           doesn't work, for example where this symmetry doesn't
-           exist, or where the return value of get_foo isn't valid
-           input for set_foo. If such a copy fails, a warning is 
-           emitted. To make sure all relevant attributes are copied
-           into the clone, additional code references can be 
-           provided, as in the example above. Typically, this is
-           done by overrides of this method in child classes.
-
-=cut
-
-    sub clone {
-        my $self = shift;
-        $logger->info("cloning $self");
-        my %subs = @_;
-
-        # we'll clone relatives in the tree, so no raw copying
-        $subs{'set_parent'}          = sub { };
-        $subs{'set_first_daughter'}  = sub { };
-        $subs{'set_last_daughter'}   = sub { };
-        $subs{'set_next_sister'}     = sub { };
-        $subs{'set_previous_sister'} = sub { };
-        $subs{'set_child'}           = sub { };
-        $subs{'insert'}              = sub { };
-        return $self->SUPER::clone(%subs);
-    }
-
-=back
-
 =head2 SERIALIZERS
 
 =over
@@ -1,7 +1,7 @@
 package Bio::Phylo::Forest::Tree;
 use strict;
-use Bio::Phylo::Forest::TreeRole;
-use base 'Bio::Phylo::Forest::TreeRole';
+use Bio::Phylo::Forest::DrawTreeRole;
+use base qw'Bio::Phylo::Forest::DrawTreeRole';
 {
     my @fields = \( my ( %default, %rooted ) );
 
@@ -56,7 +56,7 @@ Sets tree to be interpreted as unrooted.
 
 =cut
 
-    sub set_as_unrooted : Mutator {
+    sub set_as_unrooted {
         my $self = shift;
         $rooted{ $self->get_id } = 1;
         return $self;
@@ -78,7 +78,7 @@ Sets tree to be the default tree in a forest
 
 =cut
 
-    sub set_as_default : Mutator {
+    sub set_as_default {
         my $self = shift;
         if ( my $forest = $self->_get_container ) {
             if ( my $tree = $forest->get_default_tree ) {
@@ -105,7 +105,7 @@ Sets tree to NOT be the default tree in a forest
 
 =cut
 
-    sub set_not_default : Mutator {
+    sub set_not_default {
         my $self = shift;
         $default{ $self->get_id } = 0;
         return $self;
@@ -133,7 +133,7 @@ Test if tree is default tree.
 
 =cut
 
-    sub is_default : Accessor {
+    sub is_default {
         my $self = shift;
         return !!$default{ $self->get_id };
     }
@@ -157,7 +157,7 @@ Test if tree is rooted.
 
 =cut
 
-    sub is_rooted : Accessor {
+    sub is_rooted {
         my $self = shift;
         my $id   = $self->get_id;
         if ( defined $rooted{$id} ) {
@@ -172,26 +172,8 @@ Test if tree is rooted.
         return 0;
     }
 
-=back
-
-=head2 SERIALIZERS
-
-=over
-
-=begin comment
-
- Type    : Internal method
- Title   : _cleanup
- Usage   : $trees->_cleanup;
- Function: Called during object destruction, for cleanup of instance data
- Returns : 
- Args    :
-
-=end comment
-
-=cut
-
-    sub _cleanup : Protected {
+    # the following methods are purely for internal consumption
+    sub _cleanup : Destructor {
         my $self = shift;
         if ( defined( my $id = $self->get_id ) ) {
             for my $field (@fields) {
@@ -199,6 +181,22 @@ Test if tree is rooted.
             }
         }
     }
+    
+    sub _set_rooted : Clonable {
+        my ( $self, $r ) = @_;
+        $rooted{$self->get_id} = $r;
+        return $self;
+    }
+    
+    sub _get_rooted { $rooted{shift->get_id} }
+    
+    sub _set_default : Clonable {
+        my ( $self, $d ) = @_;
+        $default{$self->get_id} = $d;
+        return $self;
+    }
+    
+    sub _get_default { $default{shift->get_id} }
 
 =back
 
@@ -25,6 +25,9 @@ my $LOADED_WRAPPERS = 0;
                 elsif ( $method eq 'delete' ) {
                     $node->set_tree();
                 }
+                elsif ( $method eq '_set_things' ) {
+                    $_->set_tree($self) for @{ $node };
+                }
             }
         },
     );
@@ -75,7 +78,7 @@ Tree constructor.
 
 =cut
 
-    sub new {
+    sub new : Constructor {
 
         # could be child class
         my $class = shift;
@@ -38,45 +38,6 @@ The Bio::Phylo::Forest object models a set of trees. The object subclasses the
 L<Bio::Phylo::Listable> object, so look there for more methods available to
 forest objects.
 
-=head1 METHODS
-
-=head2 CONSTRUCTOR
-
-=over
-
-=item new()
-
-Forest constructor.
-
- Type    : Constructor
- Title   : new
- Usage   : my $trees = Bio::Phylo::Forest->new;
- Function: Instantiates a Bio::Phylo::Forest object.
- Returns : A Bio::Phylo::Forest object.
- Args    : None required, though see the superclass
-           Bio::Phylo::Listable from which this
-           object inherits.
-
-=cut
-
-    # 	sub new {
-    #
-    # 		# could be child class
-    # 		my $class = shift;
-    #
-    # 		# notify user
-    # 		$logger->info("constructor called for '$class'");
-    #
-    # 		# recurse up inheritance tree, get ID
-    # 		my $self = $class->SUPER::new( '-tag' => __PACKAGE__->_tag, @_ );
-    #
-    # 		# local fields would be set here
-    #
-    # 		return $self;
-    # 	}
-
-=back
-
 =head1 CALCULATIONS
 
 =over
@@ -56,7 +56,7 @@ Pushes an object into its container.
 
 =cut
 
-    sub insert : Mutator {
+    sub insert {
         my ( $self, @obj ) = @_;
         if ( @obj and $self->can_contain(@obj) ) {
             my $id = $self->get_id;
@@ -86,7 +86,7 @@ Inserts argument object in container at argument index.
 
 =cut    
 
-    sub insert_at_index : Mutator {
+    sub insert_at_index {
         my ( $self, $obj, $index ) = @_;
         $logger->debug("inserting '$obj' in '$self' at index $index");
         if ( defined $obj and $self->can_contain($obj) ) {
@@ -129,7 +129,7 @@ Deletes argument from container.
 
 =cut
 
-    sub delete : Mutator {
+    sub delete {
         my ( $self, $obj ) = @_;
         my $id = $self->get_id;
         if ( $self->can_contain($obj) ) {
@@ -170,7 +170,7 @@ Empties container object.
 
 =cut
 
-    sub clear : Mutator {
+    sub clear {
         my $self = shift;
         my $id   = $self->get_id;
         $entities{$id} = [];
@@ -192,7 +192,7 @@ Keeps the container's contents specified by an array reference of indices.
 
 =cut
 
-    sub keep_entities : Mutator {
+    sub keep_entities {
         my ( $self, $indices_array_ref ) = @_;
         my $id       = $self->get_id;
         my $ent      = $entities{$id} || [];
@@ -216,9 +216,17 @@ Returns a reference to an array of objects contained by the listable object.
 
 =cut
 
-    sub get_entities : Accessor {
+    sub get_entities {
         return $entities{ $_[0]->get_id } || [];
     }
+    
+    sub _get_things { $entities{shift->get_id} }
+    sub _set_things : Clonable DeepClonable {
+        my ( $self, $things ) = @_;
+        $entities{$self->get_id} = $things;
+        $self->notify_listeners( '_set_things', $things );
+        return $self;
+    }
 
 =back
 
@@ -240,7 +248,7 @@ Jumps to the first element contained by the listable object.
 
 =cut
 
-    sub first : Accessor Mutator {
+    sub first {
         my $self = shift;
         my $id   = $self->get_id;
         $index{$id} = 0;
@@ -261,7 +269,7 @@ Jumps to the last element contained by the listable object.
 
 =cut
 
-    sub last : Accessor Mutator {
+    sub last {
         my $self = shift;
         my $id   = $self->get_id;
         $index{$id} = $#{ $entities{$id} };
@@ -282,7 +290,7 @@ Returns the current focal element of the listable object.
 
 =cut
 
-    sub current : Accessor Mutator {
+    sub current {
         my $self = shift;
         my $id   = $self->get_id;
         if ( !defined $index{$id} ) {
@@ -305,7 +313,7 @@ Returns the next focal element of the listable object.
 
 =cut
 
-    sub next : Accessor Mutator {
+    sub next {
         my $self = shift;
         my $id   = $self->get_id;
         if ( !defined $index{$id} ) {
@@ -335,7 +343,7 @@ Returns the previous element of the listable object.
 
 =cut
 
-    sub previous : Accessor Mutator {
+    sub previous {
         my $self = shift;
         my $id   = $self->get_id;
 
@@ -356,17 +364,25 @@ Returns the previous element of the listable object.
 
 Returns the current internal index of the container.
 
- Type    : Generic query
+ Type    : Accessor
  Title   : current_index
  Usage   : my $last_index = $obj->current_index;
  Function: Returns the current internal 
-           index of the container.
+           index of the container or 0
  Returns : An integer
  Args    : none.
 
 =cut
 
-    sub current_index : Accessor { $index{ ${ $_[0] } } || 0 }
+    sub current_index { $index{ ${ $_[0] } } || 0 }
+
+    sub _get_index { $index{shift->get_id} }  
+
+    sub _set_index : Clonable {
+        my ( $self, $idx ) = @_;
+        $index{ $self->get_id } = $idx;
+        return $self;
+    }
 
 =item last_index()
 
@@ -382,7 +398,7 @@ Returns the highest valid index of the container.
 
 =cut
 
-    sub last_index : Accessor { $#{ $entities{ ${ $_[0] } } } }
+    sub last_index { $#{ $entities{ ${ $_[0] } } } }
 
 =back
 
@@ -405,7 +421,7 @@ Attaches a listener (code ref) which is executed when contents change.
 
 =cut
 
-    sub set_listener : Mutator {
+    sub set_listener {
         my ( $self, $listener ) = @_;
         my $id = $self->get_id;
         if ( not $listeners{$id} ) {
@@ -418,6 +434,12 @@ Attaches a listener (code ref) which is executed when contents change.
             throw 'BadArgs' => "$listener not a CODE reference";
         }
     }
+    sub _set_listeners : Clonable {
+        my ( $self, $l ) = @_;
+        $listeners{$self->get_id} = $l;
+        return $self;
+    }
+    sub _get_listeners { $listeners{shift->get_id} }
 
 =item notify_listeners()
 
@@ -433,7 +455,7 @@ Notifies listeners of changed contents.
 
 =cut
 
-    sub notify_listeners : Accessor {
+    sub notify_listeners {
         my ( $self, @args ) = @_;
         my $id = $self->get_id;
         if ( $listeners{$id} ) {
@@ -444,42 +466,6 @@ Notifies listeners of changed contents.
         return $self;
     }
 
-=item clone()
-
-Clones container.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a deep copy of the container.
- Returns : A copy of the container.
- Args    : NONE.
- Comments: Cloning is currently experimental, use with caution.
-
-=cut
-
-    sub clone : Accessor {
-        my $self = shift;
-        $logger->info("cloning $self");
-        my %subs = @_;
-
-        # some extra logic to copy characters from source to target
-        if ( not exists $subs{'insert'} ) {
-            $subs{'insert'} = sub {
-                my ( $obj, $clone ) = @_;
-                my $clone_id = $clone->get_id;
-                for my $ent ( @{ $obj->get_entities } ) {
-                    my $copy = $ent;
-                    if ( looks_like_implementor( $ent, 'clone' ) ) {
-                        $copy = $ent->clone;
-                    }
-                    push @{ $entities{$clone_id} }, $copy;
-                }
-            };
-        }
-        return $self->SUPER::clone(%subs);
-    }
-
 =back
 
 =head2 SETS MANAGEMENT
@@ -524,7 +510,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
         return $listener;
     };
 
-    sub add_set : Mutator {
+    sub add_set {
         my ( $self, $set ) = @_;
         my $listener = $create_set_listeners->( $self, $set );
         $self->set_listener($listener);
@@ -534,6 +520,29 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
         $sets{$id}->{$setid} = $set;
         return $self;
     }
+    
+=item set_sets()
+
+ Type    : Mutator
+ Title   : set_sets
+ Usage   : $obj->set_sets([ $s1, $s2, $s3 ])
+ Function: Assigns all Bio::Phylo::Set objects to the container
+ Returns : Invocant
+ Args    : An array ref of Bio::Phylo::Set objects
+
+=cut    
+    
+    sub set_sets : Clonable {
+        my ( $self, $sets ) = @_;
+        my $id = $self->get_id;
+        $sets{$id} = {};
+        if ( $sets ) {
+            for my $set ( @{ $sets } ) {
+                $sets{$id}->{$set->get_id} = $set;
+            }
+        }
+        return $self;
+    }
 
 =item remove_set()
 
@@ -546,7 +555,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
 
 =cut    
 
-    sub remove_set : Mutator {
+    sub remove_set {
         my ( $self, $set ) = @_;
         my $id = $self->get_id;
         $sets{$id} = {} if not $sets{$id};
@@ -566,7 +575,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
 
 =cut 
 
-    sub get_sets : Accessor {
+    sub get_sets {
         my $self = shift;
         my $id   = $self->get_id;
         $sets{$id} = {} if not $sets{$id};
@@ -591,7 +600,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
 
 =cut 
 
-    sub is_in_set : Accessor {
+    sub is_in_set {
         my ( $self, $obj, $set ) = @_;        
         if ( looks_like_object($set,_SET_) and $sets{ $self->get_id }->{ $set->get_id } ) {
             my $i = $self->get_index_of($obj);
@@ -622,7 +631,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
 
 =cut 
 
-    sub add_to_set : Mutator {
+    sub add_to_set {
         my ( $self, $obj, $set ) = @_;
         my $id = $self->get_id;
         $sets{$id} = {} if not $sets{$id};
@@ -659,7 +668,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
 
 =cut
 
-    sub remove_from_set : Mutator {
+    sub remove_from_set {
         my ( $self, $obj, $set ) = @_;
         my $id = $self->get_id;
         $sets{$id} = {} if not $sets{$id};
@@ -689,7 +698,7 @@ Consult the documentation for L<Bio::Phylo::Set> for a code sample.
 
 =cut
 
-    sub _cleanup : Protected {
+    sub _cleanup : Destructor {
         my $self = shift;
         my $id   = $self->get_id;
         for my $field (@fields) {
@@ -39,7 +39,7 @@ type is to facilitate NeXML serialization of characters and their annotations.
 
 =cut
 
-sub set_weight {
+sub set_weight : Clonable {
     my ( $self, $weight ) = @_;
     if ( looks_like_number $weight ) {
         if ( my ($meta) = @{ $self->get_meta('bp:charWeight') } ) {
@@ -53,9 +53,11 @@ sub set_weight {
                 )
             );
         }
-        return $self;
     }
-    throw 'BadNumber' => "'$weight' is not a number";
+    elsif ( defined $weight ) {
+        throw 'BadNumber' => "'$weight' is not a number";
+    }
+    return $self;    
 }
 
 =item set_codonpos()
@@ -69,23 +71,27 @@ sub set_weight {
 
 =cut
 
-sub set_codonpos {
+sub set_codonpos : Clonable {
     my ( $self, $codonpos ) = @_;
-    if ( $codonpos == 1 || $codonpos == 2 || $codonpos == 3 ) {
-        if ( my ($meta) = @{ $self->get_meta('bp:codonPos') } ) {
-            $meta->set_triple( 'bp:codonPos' => $codonpos );
+    if ( $codonpos ) {
+        if ( $codonpos == 1 || $codonpos == 2 || $codonpos == 3 ) {
+            if ( my ($meta) = @{ $self->get_meta('bp:codonPos') } ) {
+                $meta->set_triple( 'bp:codonPos' => $codonpos );
+            }
+            else {
+                $self->add_meta(
+                    $fac->create_meta(
+                        '-namespaces' => { 'bp' => _NS_BIOPHYLO_ },
+                        '-triple'     => { 'bp:codonPos' => $codonpos },
+                    )
+                );
+            }
         }
-        else {
-            $self->add_meta(
-                $fac->create_meta(
-                    '-namespaces' => { 'bp' => _NS_BIOPHYLO_ },
-                    '-triple'     => { 'bp:codonPos' => $codonpos },
-                )
-            );
-        }
-        return $self;
+        elsif ( defined $codonpos ) {
+            throw 'BadNumber' => "'$codonpos' is not a valid 1-based codon position";
+        }   
     }
-    throw 'BadNumber' => "'$codonpos' is not a valid 1-based codon position";
+    return $self;
 }
 
 =back
@@ -106,9 +112,7 @@ sub set_codonpos {
 =cut
 
 sub get_weight {
-    my $self = shift;
-    my $weight = $self->get_meta_object('bp:charWeight');
-    return defined $weight ? $weight : 1;
+    shift->get_meta_object('bp:charWeight');
 }
 
 =item get_codonpos()
@@ -22,61 +22,6 @@ this may expand in the future.
 
 =head1 METHODS
 
-=head2 UTILITY METHODS
-
-=over
-
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : Optional: a hash of code references to 
-           override reflection-based getter/setter copying
-
-           my $clone = $object->clone(  
-               'set_forest' => sub {
-                   my ( $self, $clone ) = @_;
-                   for my $forest ( @{ $self->get_forests } ) {
-                       $clone->set_forest( $forest );
-                   }
-               },
-               'set_matrix' => sub {
-                   my ( $self, $clone ) = @_;
-                   for my $matrix ( @{ $self->get_matrices } ) {
-                       $clone->set_matrix( $matrix );
-                   }
-           );
-
- Comments: Cloning is currently experimental, use with caution.
-           It works on the assumption that the output of get_foo
-           called on the invocant is to be provided as argument
-           to set_foo on the clone - such as 
-           $clone->set_name( $self->get_name ). Sometimes this 
-           doesn't work, for example where this symmetry doesn't
-           exist, or where the return value of get_foo isn't valid
-           input for set_foo. If such a copy fails, a warning is 
-           emitted. To make sure all relevant attributes are copied
-           into the clone, additional code references can be 
-           provided, as in the example above. Typically, this is
-           done by overrides of this method in child classes.
-
-=cut
-
-    sub clone {
-        my $self = shift;
-        my %subs = @_;
-        $subs{'set_xml_id'} = sub { };
-        $subs{'set_tag'} = sub { };
-        return $self->SUPER::clone(%subs);
-    }
-
-=back
-
 =head2 SERIALIZERS
 
 =over
@@ -106,7 +51,7 @@ sub to_xml {
 sub _validate  { 1 }
 sub _container { _NONE_ }
 sub _type      { _CHARACTERS_ }
-sub _tag       { '' }
+sub _tag       { 'chars' }
 
 =back
 
@@ -3,7 +3,7 @@ use strict;
 use base 'Bio::Phylo::NeXML::Writable';
 use Bio::Phylo::Factory;
 use Bio::Phylo::Util::Exceptions 'throw';
-use Bio::Phylo::Util::CONSTANT qw'_DOMCREATOR_ /looks_like/';
+use Bio::Phylo::Util::CONSTANT qw'_DOMCREATOR_ _DATATYPE_ /looks_like/';
 {
     my $logger = __PACKAGE__->get_logger;
     my $fac    = Bio::Phylo::Factory->new();
@@ -50,7 +50,7 @@ Datatype constructor.
 
 =cut
 
-    sub new {
+    sub new : Constructor {
         my $class = shift;
 
         # constructor called with type string
@@ -107,7 +107,7 @@ Sets state lookup table.
 
 =cut
 
-    sub set_lookup {
+    sub set_lookup : Clonable {
         my ( $self, $lookup ) = @_;
         my $id = $self->get_id;
 
@@ -142,7 +142,7 @@ Sets missing data symbol.
 
 =cut
 
-    sub set_missing {
+    sub set_missing : Clonable {
         my ( $self, $missing ) = @_;
         my $id = $self->get_id;
         if ( $missing ne $self->get_gap ) {
@@ -169,7 +169,7 @@ Sets gap symbol.
 
 =cut
 
-    sub set_gap {
+    sub set_gap : Clonable {
         my ( $self, $gap ) = @_;
         if ( not $gap eq $self->get_missing ) {
             $gap{ $self->get_id } = $gap;
@@ -181,6 +181,25 @@ Sets gap symbol.
         return $self;
     }
 
+=item set_metas_for_states()
+
+Assigns all metadata annotations for all state symbols
+
+ Type    : Mutator
+ Title   : set_metas_for_states
+ Usage   : $obj->set_metas_for_states({ $state => [ $m1, $m2 ] });
+ Function: Assigns all metadata annotations for all state symbols
+ Returns : Modified object.
+ Args    : A hash reference of state symbols with metadata arrays
+
+=cut
+    
+    sub set_metas_for_states : Clonable {
+        my ( $self, $metas ) = @_;
+        $meta{$self->get_id} = $metas;
+        return $self;
+    }
+    
 =item add_meta_for_state()
 
 Adds a metadata annotation for a state symbol
@@ -521,7 +540,7 @@ Gets metadata annotations (if any) for the provided state symbol
 
  Type    : Accessor
  Title   : get_meta_for_state
- Usage   : my $meta = @{ $obj->get_meta_for_state };
+ Usage   : my @meta = @{ $obj->get_meta_for_state };
  Function: Gets metadata annotations for a state symbol
  Returns : An array reference of Bio::Phylo::NeXML::Meta objects
  Args    : A state symbol
@@ -537,6 +556,21 @@ Gets metadata annotations (if any) for the provided state symbol
         return [];
     }
 
+=item get_metas_for_states()
+
+Gets metadata annotations (if any) for all state symbols
+
+ Type    : Accessor
+ Title   : get_metas_for_states
+ Usage   : my @meta = @{ $obj->get_metas_for_states };
+ Function: Gets metadata annotations for state symbols
+ Returns : An array reference of Bio::Phylo::NeXML::Meta objects
+ Args    : None
+
+=cut
+    
+    sub get_metas_for_states { $meta{shift->get_id} }
+
 =back
 
 =head2 TESTS
@@ -742,7 +776,7 @@ Joins argument array ref of characters following appropriate rules.
         return CORE::join( '', @{$array} );
     }
 
-    sub _cleanup {
+    sub _cleanup : Destructor {
         my $self = shift;
         $logger->debug("cleaning up '$self'");
         my $id = $self->get_id;
@@ -978,6 +1012,7 @@ Analog to to_xml.
         return $elt;
     }
     sub _tag { 'states' }
+    sub _type { _DATATYPE_ }
 
 =back
 
@@ -70,17 +70,20 @@ Sets invocant weight.
 
 =cut
 
-    sub set_weight : Mutator {
+    sub set_weight : Clonable {
         my ( $self, $weight ) = @_;
         my $id = $self->get_id;
-        $weight = 1 if not defined $weight;
         if ( looks_like_number $weight ) {
             $weight{$id} = $weight;
             $logger->info("setting weight '$weight'");
         }
-        elsif ( !looks_like_number $weight ) {
+        elsif ( defined $weight ) {
             throw 'BadNumber' => 'Not a number!';
         }
+        else {
+            $weight{$id} = undef;
+        }
+        return $self;
     }
 
 =item set_position()
@@ -96,16 +99,19 @@ Set invocant starting position.
 
 =cut
 
-    sub set_position : Mutator {
+    sub set_position : Clonable {
         my ( $self, $pos ) = @_;
-        $pos = 1 if not defined $pos;
         if ( looks_like_number $pos && $pos >= 1 && $pos / int($pos) == 1 ) {
             $position{ $self->get_id } = $pos;
             $logger->info("setting position '$pos'");
         }
-        else {
+        elsif ( defined $pos ) {
             throw 'BadNumber' => "'$pos' not a positive integer!";
         }
+        else {
+            $position{ $self->get_id } = undef;
+        }
+        return $self;
     }
 
 =item set_annotation()
@@ -130,7 +136,7 @@ Sets single annotation.
 
 =cut
 
-    sub set_annotation : Mutator {
+    sub set_annotation {
         my $self = shift;
         if (@_) {
             my %opt = looks_like_hash @_;
@@ -190,7 +196,7 @@ Sets list of annotations.
 
 =cut
 
-    sub set_annotations : Mutator {
+    sub set_annotations : Clonable {
         my $self = shift;
         my @anno;
         if ( scalar @_ == 1 and looks_like_instance( $_[0], 'ARRAY' ) ) {
@@ -245,11 +251,7 @@ Gets invocant weight.
 
 =cut
 
-    sub get_weight : Accessor {
-        my $self   = shift;
-        my $weight = $weight{ $self->get_id };
-        return defined $weight ? $weight : 1;
-    }
+    sub get_weight { $weight{ shift->get_id } }
 
 =item get_position()
 
@@ -264,11 +266,7 @@ Gets invocant starting position.
 
 =cut
 
-    sub get_position : Accessor {
-        my $self = shift;
-        my $pos  = $position{ $self->get_id };
-        return defined $pos ? $pos : 1;
-    }
+    sub get_position { $position{ shift->get_id } }
 
 =item get_annotation()
 
@@ -288,7 +286,7 @@ Retrieves character annotation (hashref).
 
 =cut
 
-    sub get_annotation : Accessor {
+    sub get_annotation {
         my $self = shift;
         my $id   = $self->get_id;
         if (@_) {
@@ -328,12 +326,12 @@ Retrieves character annotations (array ref).
 
 =cut
 
-    sub get_annotations : Accessor {
+    sub get_annotations {
         my $self = shift;
         return $annotations{ $self->get_id } || [];
     }
 
-    sub _cleanup : Protected {
+    sub _cleanup : Destructor {
         my $self = shift;
         $logger->info("cleaning up '$self'");
         if ( defined( my $id = $self->get_id ) ) {
@@ -13,9 +13,9 @@ my $LOADED_WRAPPERS = 0;
     my $logger             = __PACKAGE__->get_logger;
     my $TYPE_CONSTANT      = _DATUM_;
     my $CONTAINER_CONSTANT = _MATRIX_;
-    {
-    my @fields             = \( my ( %weight, %position, %annotations ) );
-    }
+    #{
+    #my @fields             = \( my ( %weight, %position, %annotations ) );
+    #}
 
 =head1 NAME
 
@@ -77,7 +77,7 @@ Datum object constructor.
 
 =cut
 
-    sub new {
+    sub new : Constructor {
 
         # could be child class
         my $class = shift;
@@ -205,7 +205,7 @@ Sets character state(s)
             }
         }
         my $missing  = $self->get_missing;
-        my $position = $self->get_position;
+        my $position = $self->get_position || 1;
         for ( 1 .. $position - 1 ) {
             unshift @data, $missing;
         }
@@ -323,13 +323,11 @@ Gets invocant number of characters.
 
     sub get_length {
         my $self = shift;
-
-        #        $logger->info("Chars: @char");
         if ( my $matrix = $self->_get_container ) {
             return $matrix->get_nchar;
         }
         else {
-            return scalar( @{ $self->get_entities } ) + $self->get_position - 1;
+            return scalar( @{ $self->get_entities } ) + ( $self->get_position || 1 ) - 1;
         }
     }
 
@@ -349,7 +347,7 @@ Gets state at argument index.
     sub get_by_index {
         my ( $self, $index ) = @_;
         $logger->debug($index);
-        my $offset = $self->get_position - 1;
+        my $offset = ( $self->get_position || 1 ) - 1;
         return $self->get_type_object->get_missing if $offset > $index;
         my $val = $self->SUPER::get_by_index( $index - $offset );
         return defined $val ? $val : $self->get_type_object->get_missing;
@@ -511,6 +509,37 @@ Calculates occurrences of states.
         return \%counts;
     }
 
+=item calc_distance()
+
+Calculates the distance between the invocant and argument
+
+ Type    : Calculation
+ Title   : calc_distance
+ Usage   : my $dist = $datum1->calc_distance($datum2);
+ Function: Calculates pairwise distance
+ Returns : A number, the distance per site
+ Args    : Another datum to calculate the distance to
+ Comments: Assumes the sequences are aligned. Calculates
+           substitutions / total non-missing sites.
+=cut
+
+	sub calc_distance {
+		my ( $self, $other ) = @_;
+		my @c1 = $self->get_char;
+		my @c2 = $other->get_char; 
+		my $t = $self->get_type_object;
+		my $m = $t->get_missing;
+		my $g = $t->get_gap;
+		my $subst = 0;
+		my $total = 0;
+		for my $i ( 0 .. $#c1 ) {
+			next if $c1[$i] eq $m or $c1[$i] eq $g or $c2[$i] eq $m or $c2[$i] eq $g;
+			$subst += $c1[$i] ne $c2[$i];
+			$total++;
+		}
+		return $total ? $subst / $total : 9**9**9;
+	}
+
 =item calc_state_frequencies()
 
 Calculates the frequencies of the states observed in the matrix.
@@ -689,32 +718,6 @@ Validates invocant data contents.
         }
     }
 
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : None.
- Comments: Cloning is currently experimental, use with caution.
-
-=cut
-
-    sub clone {
-        my $self = shift;
-        my %subs = @_;
-
-        # some extra logic to copy characters from source to target
-        $subs{'set_char'} = 0;
-
-        # some logic to copy annotations
-        $subs{'set_annotation'} = 0;
-        return $self->SUPER::clone(%subs);
-    }
-
 =item to_xml()
 
 Serializes datum to nexml format.
@@ -134,7 +134,7 @@ Sets argument state labels.
 
 =cut
 
-    sub set_statelabels {
+    sub set_statelabels : Clonable {
         my ( $self, $statelabels ) = @_;
 
         # it's an array ref, but what about its contents?
@@ -174,7 +174,7 @@ Normally you never have to use this.
 
 =cut
 
-    sub set_characters {
+    sub set_characters : Clonable DeepClonable {
         my ( $self, $characters ) = @_;
         if ( looks_like_object $characters, _CHARACTERS_ ) {
             $characters{ $self->get_id } = $characters;
@@ -195,9 +195,9 @@ Defines matrix gapmode.
 
 =cut
 
-    sub set_gapmode {
+    sub set_gapmode : Clonable {
         my ( $self, $gapmode ) = @_;
-        $gapmode{ $self->get_id } = !!$gapmode;
+        $gapmode{ $self->get_id } = $gapmode;
         return $self;
     }
 
@@ -214,21 +214,26 @@ Assigns match symbol.
 
 =cut
 
-    sub set_matchchar {
+    sub set_matchchar : Clonable {
         my ( $self, $match ) = @_;
-        my $missing = $self->get_missing;
-        my $gap     = $self->get_gap;
-        if ( $match eq $missing ) {
-            throw 'BadArgs' =>
-              "Match character '$match' already in use as missing character";
-        }
-        elsif ( $match eq $gap ) {
-            throw 'BadArgs' =>
-              "Match character '$match' already in use as gap character";
-        }
-        else {
-            $matchchar{ $self->get_id } = $match;
-        }
+	if ( $match ) {
+	    my $missing = $self->get_missing;
+	    my $gap     = $self->get_gap;
+	    if ( $match eq $missing ) {
+		throw 'BadArgs' =>
+		  "Match character '$match' already in use as missing character";
+	    }
+	    elsif ( $match eq $gap ) {
+		throw 'BadArgs' =>
+		  "Match character '$match' already in use as gap character";
+	    }
+	    else {
+		$matchchar{ $self->get_id } = $match;
+	    }
+	}
+	else {
+	    $matchchar{ $self->get_id } = undef;
+	}
         return $self;
     }
 
@@ -246,9 +251,14 @@ Defines matrix 'polymorphism' interpretation.
 
 =cut
 
-    sub set_polymorphism {
+    sub set_polymorphism : Clonable {
         my ( $self, $poly ) = @_;
-        $polymorphism{ $self->get_id } = !!$poly;
+        if ( defined $poly ) {
+            $polymorphism{ $self->get_id } = $poly;
+        }
+        else {
+            delete $polymorphism{ $self->get_id };
+        }
         return $self;
     }
 
@@ -266,9 +276,14 @@ Defines matrix case sensitivity interpretation.
 
 =cut
 
-    sub set_respectcase {
+    sub set_respectcase : Clonable {
         my ( $self, $case_sensitivity ) = @_;
-        $case_sensitivity{ $self->get_id } = !!$case_sensitivity;
+        if ( defined $case_sensitivity ) {
+            $case_sensitivity{ $self->get_id } = $case_sensitivity;
+        }
+        else {
+            delete $case_sensitivity{ $self->get_id };
+        }
         return $self;
     }
 
@@ -339,7 +354,7 @@ Returns matrix match character.
 
 =cut
 
-    sub get_matchchar { $matchchar{ $_[0]->get_id } || '.' }
+    sub get_matchchar { $matchchar{ $_[0]->get_id } }
 
 =item get_polymorphism()
 
@@ -355,7 +370,7 @@ Returns matrix 'polymorphism' interpretation.
 
 =cut
 
-    sub get_polymorphism { $polymorphism{ $_[0]->get_id } }
+    sub get_polymorphism { $polymorphism{ shift->get_id } }
 
 =item get_respectcase()
 
@@ -371,9 +386,9 @@ Returns matrix case sensitivity interpretation.
 
 =cut
 
-    sub get_respectcase { $case_sensitivity{ $_[0]->get_id } }
+    sub get_respectcase { $case_sensitivity{ shift->get_id } }
 
-    sub _cleanup {
+    sub _cleanup : Destructor {
         my $self = shift;
         my $id = $self->get_id;
         for (@inside_out_arrays) {
@@ -138,7 +138,7 @@ Matrix constructor.
 
 =cut
 
-    sub new {
+    sub new : Constructor {
 
         # could be child class
         my $class = shift;
@@ -476,7 +476,7 @@ Calculates number of characters.
         my $self  = shift;
         my $nchar = 0;
         for my $row ( @{ $self->get_entities } ) {
-            my $offset    = $row->get_position - 1;
+            my $offset    = ( $row->get_position || 1 ) - 1;
             my $rowlength = scalar @{ $row->get_entities };
             $rowlength += $offset;
             $nchar = $rowlength if $rowlength > $nchar;
@@ -1002,44 +1002,6 @@ Creates jackknifed clone.
         return $self->keep_chars( \@indices );
     }
 
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : NONE
-
-=cut
-
-    sub clone {
-        my $self = shift;
-        $logger->info("cloning $self");
-        my %subs = @_;
-
-        # we'll clone datum objects, so no raw copying
-        $subs{'set_raw'} = sub { };
-
-        # we'll use the set/get_special_symbols method
-        $subs{'set_missing'}    = sub { };
-        $subs{'set_gap'}        = sub { };
-        $subs{'set_matchchar'}  = sub { };
-		$subs{'set_characters'} = sub {
-            my ( $obj, $clone ) = @_;
-			my $chars = $obj->get_characters;
-			my $clone_chars = $obj->get_characters->clone;
-			$clone->set_characters( $clone_chars );
-		};
-		$subs{'set_taxa'} = sub {
-			my ( $obj, $clone ) = @_;
-			$clone->set_taxa( $obj->make_taxa );
-		};
-        return $self->SUPER::clone(%subs);
-    }
-
 =item insert()
 
 Insert argument in invocant.
@@ -1067,18 +1029,17 @@ Insert argument in invocant.
             throw 'ObjectMismatch' => 'object is of wrong data type';
         }
         my $taxon1 = $obj->get_taxon;
+        my $mname = $self->get_name || $self->get_internal_name;
         for my $ents ( @{ $self->get_entities } ) {
             if ( $obj->get_id == $ents->get_id ) {
                 throw 'ObjectMismatch' => 'row already inserted';
             }
             if ($taxon1) {
+				my $tname = $taxon1->get_name;
                 my $taxon2 = $ents->get_taxon;
                 if ( $taxon2 && $taxon1->get_id == $taxon2->get_id ) {
-                    $logger->warn(
-'datum linking to same taxon already existed, concatenating instead'
-                    );
-                    $ents->concat($obj);
-                    return $self;
+                	my $tmpl = 'Note: a row linking to %s already exists in matrix %s';
+                    $logger->warn(sprintf $tmpl,$tname,$mname);
                 }
             }
         }
@@ -1213,7 +1174,9 @@ Creates a taxa block from the objects contents if none exists yet.
                     $taxa{$name} = $factory->create_taxon( '-name' => $name );
                 }
             }
-            $taxa->insert( map { $taxa{$_} } sort { $a cmp $b } keys %taxa );
+			if ( keys %taxa ) {
+				$taxa->insert( map { $taxa{$_} } sort { $a cmp $b } keys %taxa );
+			}
             $self->set_taxa($taxa);
             return $taxa;
         }
@@ -49,7 +49,7 @@ TypeSafeData constructor.
 
 =cut    
 
-    sub new {
+    sub new : Constructor {
 
         # is child class
         my $class = shift;
@@ -142,7 +142,7 @@ Set missing data symbol.
 
     sub set_missing {
         my ( $self, $missing ) = @_;
-        if ( $self->can('get_matchchar') and $missing eq $self->get_matchchar )
+        if ( $self->can('get_matchchar') and $self->get_matchchar and $missing eq $self->get_matchchar )
         {
             throw 'BadArgs' =>
               "Missing character '$missing' already in use as match character";
@@ -169,7 +169,7 @@ Set gap data symbol.
 
     sub set_gap {
         my ( $self, $gap ) = @_;
-        if ( $self->can('get_matchchar') and $gap eq $self->get_matchchar ) {
+        if ( $self->can('get_matchchar') and $self->get_matchchar and $self->get_matchchar eq $gap ) {
             throw 'BadArgs' =>
               "Gap character '$gap' already in use as match character";
         }
@@ -219,7 +219,7 @@ Set data type object.
 
 =cut
 
-    sub set_type_object {
+    sub set_type_object : Clonable DeepClonable {
         my ( $self, $obj ) = @_;
         $logger->info("setting character type object");
         $type{ $self->get_id } = $obj;
@@ -335,49 +335,6 @@ Get data type object.
 
 =back
 
-=head2 UTILITY METHODS
-
-=over
-
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : NONE
-
-=cut
-
-    sub clone {
-        my $self = shift;
-        $logger->info("cloning $self");
-        my %subs = @_;
-
-        # we'll create type object during construction
-        $subs{'set_type'}    = 0;
-        $subs{'set_missing'} = 0;
-        $subs{'set_gap'}     = 0;
-        $subs{'set_lookup'}  = 0;
-
-        # we'll override this, the type object is created from scratch
-        $subs{'set_type_object'} = 0;
-
-        # this will create type object during construction
-        $subs{'new'} = [
-            '-type'    => $self->get_type,
-            '-missing' => $self->get_missing,
-            '-gap'     => $self->get_gap,
-            '-lookup'  => $self->get_lookup,
-        ];
-        return $self->SUPER::clone(%subs);
-    }
-
-=back
-
 =head2 INTERFACE METHODS
 
 =over
@@ -14,7 +14,6 @@ This class has no internal state, no cleanup is necessary.
 {
     my $TYPE      = _MATRICES_;
     my $CONTAINER = _NONE_;
-    my $logger    = __PACKAGE__->get_logger;
 
 =head1 NAME
 
@@ -36,40 +35,6 @@ The L<Bio::Phylo::Matrices> object models a set of matrices. It inherits from
 the L<Bio::Phylo::Listable> object, and so the filtering methods of that object
 are available to apply to a set of matrices.
 
-=head1 METHODS
-
-=head2 CONSTRUCTOR
-
-=over
-
-=item new()
-
-Matrices constructor.
-
- Type    : Constructor
- Title   : new
- Usage   : my $matrices = Bio::Phylo::Matrices->new;
- Function: Initializes a Bio::Phylo::Matrices object.
- Returns : A Bio::Phylo::Matrices object.
- Args    : None required.
-
-=cut
-
-    #    sub new {
-    #        # could be child class
-    #        my $class = shift;
-    #
-    #        # notify user
-    #        $logger->info("constructor called for '$class'");
-    #
-    #        # recurse up inheritance tree, get ID
-    #        my $self = $class->SUPER::new( @_ );
-    #
-    #        # local fields would be set here
-    #
-    #        return $self;
-    #    }
-
 =begin comment
 
  Type    : Internal method
@@ -100,10 +65,6 @@ Matrices constructor.
 
     sub _type { $TYPE }
 
-=back
-
-=cut
-
     # podinherit_insert_token
 
 =head1 SEE ALSO
@@ -1,13 +1,11 @@
 package Bio::Phylo::Mediators::TaxaMediator;
 use strict;
-use Scalar::Util qw'weaken';
-use Bio::Phylo::Util::Logger;
+use Scalar::Util qw'weaken isweak';
+use Bio::Phylo::Util::Logger ':simple';
 use Bio::Phylo::Util::Exceptions;
 use Bio::Phylo::Util::CONSTANT ':objecttypes';
 
-# XXX this class only has weak references
 {
-    my $logger = Bio::Phylo::Util::Logger->new;
     my $self;
     my ( @object, %id_by_type, %one_to_one, %one_to_many );
 
@@ -54,11 +52,11 @@ TaxaMediator constructor.
         my $class = shift;
 
         # notify user
-        $logger->info("constructor called for '$class'");
+        DEBUG "constructor called for '$class'";
 
         # singleton class
         if ( not $self ) {
-            $logger->debug("first time instantiation of singleton");
+            INFO "first time instantiation of singleton";
             $self = \$class;
             bless $self, $class;
         }
@@ -101,7 +99,17 @@ Stores argument in invocant's cache.
 
                 # store in object cache
                 $object[$id] = $obj;
-                weaken $object[$id];
+                
+                # in the one-to-many relationships we only weaken the
+                # references to the many objects so that the get cleaned up
+                #Êwhen they go out of scope. When the are unregistered and
+                #Êthere is no more many object that references the one object,
+                # the one object's reference needs to be weakened as well so
+                # that it is cleaned up when it is no longer reachable from
+                # elsewhere.
+                #if ( $type != _TAXA_ && $type != _TAXON_ ) {
+                    weaken $object[$id];
+                #}
                 return $self;
             }
         }
@@ -125,7 +133,19 @@ Removes argument from invocant's cache.
         my ( $self, $obj ) = @_;
 
         my $id = $obj->get_id;
+        
         if ( defined $id ) {
+            my $taxa_id = $one_to_one{$id};
+            
+            # decrease reference count of taxa block if we are the last pointer
+            # to it
+            if ( $taxa_id ) {
+                my @others = keys %{ $one_to_many{$taxa_id} };
+                if ( @others == 1 ) {
+                    weaken $object[$taxa_id];
+                }
+                delete $one_to_many{$taxa_id}->{$id};
+            }            
             
             # remove from object cache
             if ( exists $object[$id] ) {
@@ -137,10 +157,11 @@ Removes argument from invocant's cache.
                 delete $one_to_one{$id};
             }
             
-            # remove from one-to-many mapping
+            # remove from one-to-many mapping if I am taxa
             if ( exists $one_to_many{$id} ) {
                 delete $one_to_many{$id};    
             }
+            
         }
         return $self;
     }
@@ -175,6 +196,17 @@ Creates link between objects.
         my ( $one_id, $many_id ) = ( $one->get_id, $many->get_id );
         $one_to_one{$many_id} = $one_id;
         $one_to_many{$one_id} = {} unless $one_to_many{$one_id};
+
+        # once other objects start referring to the taxon we want
+        # these references to keep the taxon "alive" until all other
+        # objects pointing to it have gone out of scope, in which
+        # case the reference must be weakened again, so that it
+        # might get cleaned up also
+        if (isweak($object[$one_id]) ) {
+            my $strong = $object[$one_id];
+            $object[$one_id] = $strong;
+        }
+        
         $one_to_many{$one_id}->{$many_id} = $many->_type;
         return $self;
     }
@@ -273,7 +305,7 @@ Removes link between objects.
             my $target = $self->get_link( '-source' => $many );
             $one_id = $target->get_id if $target;
         }
-        delete $one_to_many{$one_id}->{$many_id} if $one_to_many{$one_id};          
+        delete $one_to_many{$one_id}->{$many_id} if $one_id and $one_to_many{$one_id};          
         delete $one_to_one{$many_id};
     }
 
@@ -172,7 +172,7 @@ Populates the triple, assuming that the invocant is attached to a subject.
 
 =cut    
 
-    sub set_triple {
+    sub set_triple : Clonable {
         my ( $self, $property, $content ) = @_;
         if ( ref($property) && ref($property) eq 'HASH' ) {
             ( $property, $content ) = each %{$property};
@@ -188,6 +188,24 @@ Populates the triple, assuming that the invocant is attached to a subject.
 
 =over
 
+=item get_triple ()
+
+Returns predicate and object for the triple
+
+ Type    : Accessor
+ Title   : get_triple
+ Usage   : my ( $predicate, $object ) = $anno->get_triple;
+ Function: Returns triple
+ Returns : Predicate and object of a triple
+ Args    : NONE
+
+=cut
+
+    sub get_triple {
+	my $self = shift;
+	return $self->get_predicate, $self->get_object;
+    }
+
 =item get_object()
 
 Returns triple object
@@ -406,7 +424,7 @@ L<http://dx.doi.org/10.1186/1471-2105-12-63>
     sub _type      { $TYPE_CONSTANT }
     sub _container { $CONTAINER_CONSTANT }
 
-    sub _cleanup {
+    sub _cleanup : Destructor {
         my $id = shift->get_id;
         delete $_->{$id} for @fields;
     }
@@ -18,7 +18,7 @@ use Bio::Phylo::Util::CONSTANT qw'/looks_like/ :namespaces :objecttypes';
         'xsi' => _NS_XSI_,
         'rdf' => _NS_RDF_,
         'xsd' => _NS_XSD_,
-	'map' => _NS_PHYLOMAP_,
+		'map' => _NS_PHYLOMAP_,
     );
     my @fields =
       \( my ( %tag, %id, %attributes, %identifiable, %suppress_ns, %meta, %url ) );
@@ -88,7 +88,7 @@ This is the superclass for all objects that can be serialized to NeXML
 
 =cut
 
-    sub set_suppress_ns {
+    sub set_suppress_ns : Clonable {
         my $self = shift;
         my $id   = $self->get_id;
         $suppress_ns{$id} = 1;
@@ -130,7 +130,9 @@ This is the superclass for all objects that can be serialized to NeXML
                 $meta{$id} = [];
             }
             push @{ $meta{$id} }, $meta_obj;
-            $self->set_attributes( 'about' => '#' . $self->get_xml_id );
+            if ( $self->is_identifiable ) {
+            	$self->set_attributes( 'about' => '#' . $self->get_xml_id );
+            }
         }
         return $self;
     }
@@ -189,20 +191,44 @@ This is the superclass for all objects that can be serialized to NeXML
  Function: Attaches a $predicate => $object pair to the invocant
  Returns : $self
  Args    : $predicate => (a valid curie of a known namespace)
-	   $object => (an object value)
+	       $object => (an object value)
 
 =cut    
 
     sub set_meta_object {
-	my ( $self, $predicate, $object ) = @_;
-	if ( my ($meta) = @{ $self->get_meta($predicate) } ) {
-	    $meta->set_triple( $predicate => $object );
-	}
-	else {
-	    $self->add_meta( $fac->create_meta( '-triple' => { $predicate => $object } ) );
-	}
-	return $self;
+		my ( $self, $predicate, $object ) = @_;
+		if ( my ($meta) = @{ $self->get_meta($predicate) } ) {
+			$meta->set_triple( $predicate => $object );
+		}
+		else {
+			$self->add_meta( $fac->create_meta( '-triple' => { $predicate => $object } ) );
+		}
+		return $self;
     }
+
+=item set_meta()
+
+ Type    : Mutator
+ Title   : set_meta
+ Usage   : $obj->set_meta([ $m1, $m2, $m3 ]);
+ Function: Assigns all metadata objects
+ Returns : $self
+ Args    : An array ref of metadata objects
+
+=cut  
+	
+	sub set_meta : Clonable {
+		my ( $self, $meta ) = @_;
+		if ( $meta && @{ $meta } ) {
+			$meta{$self->get_id} = $meta;
+            $self->set_attributes( 'about' => '#' . $self->get_xml_id );			
+		}
+		else {
+			$meta{$self->get_id} = [];
+			$self->unset_attribute( 'about' );
+		}
+		return $self;
+	}
     
 =item set_identifiable()
 
@@ -221,9 +247,9 @@ Typically, this is done internally - you will probably never use this method.
 
 =cut
 
-    sub set_identifiable {
+    sub set_identifiable : Clonable {
         my $self = shift;
-        $identifiable{ $self->get_id } = !!shift;
+        $identifiable{ $self->get_id } = shift;
         return $self;
     }
 
@@ -244,7 +270,7 @@ xml element structure called <node/>
 
 =cut
 
-    sub set_tag {
+    sub set_tag : Clonable {
         my ( $self, $tag ) = @_;
 
         # _ is ok; see http://www.w3.org/TR/2004/REC-xml-20040204/#NT-NameChar
@@ -272,7 +298,7 @@ Sets invocant name.
 
 =cut
 
-    sub set_name {
+    sub set_name : Clonable {
         my ( $self, $name ) = @_;
         if ( defined $name ) {
             return $self->set_attributes( 'label' => $name );
@@ -365,9 +391,11 @@ the physical location of the containing document.
 
 =cut
 
-    sub set_base_uri {
+    sub set_base_uri : Clonable {
         my ( $self, $uri ) = @_;
-        $self->set_attributes( 'xml:base' => $uri );
+        if ( $uri ) {
+        	$self->set_attributes( 'xml:base' => $uri );
+        }
         return $self;
     }
 
@@ -386,10 +414,12 @@ allow clickable links, such as SVG or RSS.
 
 =cut
 
-    sub set_link {
+    sub set_link : Clonable {
         my ( $self, $url ) = @_;
-        my $id = $self->get_id;
-        $url{$id} = $url;
+        if ( $url ) {
+    	    my $id = $self->get_id;
+	        $url{$id} = $url;
+        }
         return $self;
     }
 
@@ -693,6 +723,11 @@ Retrieves attributes for the element.
         if ( defined $self->is_identifiable and not $self->is_identifiable ) {
             delete $attrs->{'id'};
         }
+        
+        # process the about attribute
+        if ( not @{ $self->get_meta } and $attrs->{'about'} ) {
+        	delete $attrs->{'about'};
+        }
 	
 		# set the otus attribute
         if ( $self->can('get_taxa') ) {
@@ -701,8 +736,7 @@ Retrieves attributes for the element.
                   if looks_like_instance( $taxa, 'Bio::Phylo' );
             }
             else {
-                throw 'ObjectMismatch' =>
-                  "$self can link to a taxa element, but doesn't";
+                $logger->error("$self can link to a taxa element, but doesn't");
             }
         }
 	
@@ -814,11 +848,7 @@ allow clickable links, such as SVG or RSS.
 
 =cut
 
-    sub get_link {
-        my $self = shift;
-        my $id   = $self->get_id;
-        return $url{$id};
-    }
+    sub get_link { $url{ shift->get_id } }
 
 =item get_dom_elt()
 
@@ -883,6 +913,7 @@ method indicates whether that is the case.
         my $self = shift;
         return $identifiable{ $self->get_id };
     }
+    *get_identifiable = \&is_identifiable;
 
 =item is_ns_suppressed()
 
@@ -899,46 +930,7 @@ method indicates whether that is the case.
     sub is_ns_suppressed {
         return $suppress_ns{ shift->get_id };
     }
-
-=back
-
-=head2 CLONER
-
-=over
-
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : NONE.
- Comments: Cloning is currently experimental, use with caution.
-
-=cut
-
-    sub clone {
-        my $self = shift;
-        $logger->info("cloning $self");
-        my %subs = @_;
-
-        # some extra logic to copy characters from source to target
-        if ( not exists $subs{'add_meta'} ) {
-            $subs{'add_meta'} = sub {
-                my ( $obj, $clone ) = @_;
-                for my $meta ( @{ $obj->get_meta } ) {
-                    $clone->add_meta($meta);
-                }
-            };
-        }
-
-	# we do this by executing add_meta(get_meta()) so skip here
-	$subs{'set_meta_object'} = sub {};
-        return $self->SUPER::clone(%subs);
-    }
+    *get_suppress_ns = \&is_ns_suppressed;
 
 =back
 
@@ -1051,7 +1043,7 @@ Serializes object to CDAO RDF/XML string
 		);
 	}
 
-    sub _cleanup {
+    sub _cleanup : Destructor {
         my $self = shift;
         my $id   = $self->get_id;
         for my $field (@fields) {
@@ -169,8 +169,11 @@ sub _process {
     my $self = shift;
     if ( $self->_return_is_scalar ) {
         my $result = $self->_parse;
-        if ( $self->_project ) {
-            return $self->_project->insert($result);
+        if ( my $p = $self->_project ) {
+        	if ( my $meta = $self->_project_meta ) {
+        		$p->add_meta($_) for @{ $meta };
+        	}
+            return $p->insert($result);
         }
         else {
             return $result;
@@ -178,8 +181,11 @@ sub _process {
     }
     else {
         my @result = $self->_parse;
-        if ( $self->_project ) {
-            return $self->_project->insert(@result);
+        if ( my $p = $self->_project ) {
+        	if ( my $meta = $self->_project_meta ) {
+        		$p->add_meta($_) for @{ $meta };
+        	}        
+            return $p->insert(@result);
         }
         else {
             return [@result];
@@ -196,6 +202,7 @@ sub _string {
     my $string = do { local $/; <$handle> };
     return $string;
 }
+sub _project_meta {};
 sub _logger   { $logger }
 sub _project  { shift->{'_proj'} }
 sub _handle   { shift->{'_handle'} }
@@ -53,7 +53,7 @@ sub _parse {
 
     my ( $readseq, $readphred );
     my ( $id, $seq, $phred );
-    LINE: for my $line ( <$fh> ) {
+    LINE: while( my $line = $fh->getline ) {
         chomp $line;
 
         # found the FASTQ id line
@@ -215,11 +215,13 @@ sub _parse {
     my $ordered_blocks = $self->{'_blocks'};
 
     # prepare the requested return...
-    my $temp_project =
-      pop( @{$ordered_blocks} );    # nexml root tag is processed last!
+    my $temp_project = pop( @{$ordered_blocks} ); # nexml root tag is processed last!
+    $self->{'_project_meta'} = $temp_project->get_meta;
     return @{$ordered_blocks};
 }
 
+sub _project_meta { shift->{'_project_meta'} }
+
 # element handler
 sub _handle_nexml {
     my ( $twig, $nexml_elt, $self ) = @_;
@@ -404,6 +406,7 @@ sub _handle_chars {
     # now process character sets
     $self->_process_set($definitions_elt,$characters);
     push @{ $self->{'_blocks'} }, $matrix_obj;
+    $self->_logger->info( $self->_pos . " Processed block id: $matrix_id" );
 }
 
 # here we create a hash keyed on column ids => state ids => state symbols
@@ -1215,25 +1215,27 @@ sub _semicolon {
         $characters->add_set($set);
         my $range = $self->{'_charset'}->{'range'};
         my @range;
-        while ( @{ $range } ) {
-            my $index = shift @{ $range };
-            if ( $range->[0] && $range->[0] eq '-' ) {
-                shift @{ $range };
-                my $end = shift @{ $range };
-                push @range, ( $index - 1 ) .. ( $end - 1 );
-            }
-            else {
-                push @range, ( $index - 1 );
-            }
-        }
-        for my $i ( @range ) {
-            my $character = $characters->get_by_index($i);
-            if ( $character ) {
-                $characters->add_to_set($character,$set);
-            }
-            else {
-                throw 'API' => "No character at index $i";
-            }
+        if ( ref($range) eq 'ARRAY' ) {
+			while ( @{ $range } ) {
+				my $index = shift @{ $range };
+				if ( $range->[0] && $range->[0] eq '-' ) {
+					shift @{ $range };
+					my $end = shift @{ $range };
+					push @range, ( $index - 1 ) .. ( $end - 1 );
+				}
+				else {
+					push @range, ( $index - 1 );
+				}
+			}
+			for my $i ( @range ) {
+				my $character = $characters->get_by_index($i);
+				if ( $character ) {
+					$characters->add_to_set($character,$set);
+				}
+				else {
+					throw 'API' => "No character at index $i";
+				}
+			}
         }
         $self->{'_charset'} = {};        
     }
@@ -48,7 +48,7 @@ Associates invocant with Bio::Phylo::Taxa argument.
 
 =cut
 
-sub set_taxa {
+sub set_taxa : Clonable DeepClonable {
     my ( $self, $taxa ) = @_;
     if ( $taxa and looks_like_object $taxa, $TYPE_CONSTANT ) {
         $logger->info("setting taxa '$taxa'");
@@ -51,7 +51,7 @@ Bio::Phylo::Taxa::Taxon - Operational taxonomic unit
  }
 
  # crossreference tree and taxa
- $tree->crossreference($taxa);
+ $tree->cross_reference($taxa);
 
  # iterate over nodes
  while ( my $node = $tree->next ) {
@@ -71,37 +71,6 @@ cross-referencing datum objects and tree nodes.
 
 =head1 METHODS
 
-=head2 CONSTRUCTOR
-
-=over
-
-=item new()
-
-Taxon constructor.
-
- Type    : Constructor
- Title   : new
- Usage   : my $taxon = Bio::Phylo::Taxa::Taxon->new;
- Function: Instantiates a Bio::Phylo::Taxa::Taxon
-           object.
- Returns : A Bio::Phylo::Taxa::Taxon object.
- Args    : none.
-
-=cut
-
-    #     sub new {
-    #         # could be child class
-    #         my $class = shift;
-    #
-    #         # notify user
-    #         $logger->info("constructor called for '$class'");
-    #
-    #         # go up inheritance tree, eventually get an ID
-    #         return $class->SUPER::new( '-tag' => __PACKAGE__->_tag, @_ );
-    #     }
-
-=back
-
 =head2 MUTATORS
 
 =over
@@ -121,9 +90,17 @@ Associates argument data with invocant.
 
 =cut
 
-    sub set_data {
+    sub set_data : Clonable {
         my ( $self, $datum ) = @_;
-        if ( looks_like_object $datum, $DATUM_CONSTANT ) {
+        if ( not defined $datum ) {
+            return $self;
+        }
+        elsif ( ref $datum eq 'ARRAY' ) {
+            for my $d ( @{ $datum } ) {
+                $self->set_data($d);
+            }        
+        }
+        elsif ( looks_like_object $datum, $DATUM_CONSTANT ) {
             $mediator->set_link(
                 '-one'  => $self,
                 '-many' => $datum,
@@ -146,9 +123,17 @@ Associates argument node with invocant.
 
 =cut
 
-    sub set_nodes {
+    sub set_nodes : Clonable {
         my ( $self, $node ) = @_;
-        if ( looks_like_object $node, $NODE_CONSTANT ) {
+        if ( not defined $node ) {
+            return $self;
+        }        
+        elsif ( ref $node eq 'ARRAY' ) {
+            for my $n ( @{ $node } ) {
+                $self->set_nodes($n);
+            }
+        }
+        elsif ( looks_like_object $node, $NODE_CONSTANT ) {
             $mediator->set_link(
                 '-one'  => $self,
                 '-many' => $node,
@@ -260,34 +245,6 @@ Retrieves associated node objects.
 
 =begin comment
 
-Taxon destructor.
-
- Type    : Destructor
- Title   : DESTROY
- Usage   : $phylo->DESTROY
- Function: Destroys Phylo object
- Alias   :
- Returns : TRUE
- Args    : none
- Comments: You don't really need this,
-           it is called automatically when
-           the object goes out of scope.
-
-=end comment
-
-=cut
-
-    sub DESTROY {
-        my $self = shift;
-
-        # notify user
-        #$logger->debug("destructor called for '$self'");
-        # recurse up inheritance tree for cleanup
-        $self->SUPER::DESTROY;
-    }
-
-=begin comment
-
  Type    : Internal method
  Title   : _container
  Usage   : $taxon->_container;
@@ -1,12 +1,13 @@
 package Bio::Phylo::Taxa::TaxonLinker;
 use Bio::Phylo::Mediators::TaxaMediator;
 use Bio::Phylo::Util::Exceptions;
-use Bio::Phylo::Util::Logger;
+use Bio::Phylo::Util::MOP;
+use Bio::Phylo::Util::Logger ':simple';
 use Bio::Phylo::Util::CONSTANT qw'_TAXON_ looks_like_object';
 use strict;
 {
     my $TAXON_CONSTANT = _TAXON_;
-    my $logger         = Bio::Phylo::Util::Logger->new;
+    my $mediator = 'Bio::Phylo::Mediators::TaxaMediator';
 
 =head1 NAME
 
@@ -53,19 +54,15 @@ Links the invocant object to a taxon object.
 
 =cut
 
-    sub set_taxon {
+    sub set_taxon : Clonable {
         my ( $self, $taxon ) = @_;
         if ( $taxon and looks_like_object $taxon, $TAXON_CONSTANT ) {
-            $logger->info("setting taxon '$taxon'");
-            Bio::Phylo::Mediators::TaxaMediator->set_link(
-                '-one'  => $taxon,
-                '-many' => $self,
-            );
+            INFO "setting taxon '$taxon'";
+            $mediator->set_link( '-one'  => $taxon, '-many' => $self );
         }
         else {
-            $logger->info("re-setting taxon link");
-            Bio::Phylo::Mediators::TaxaMediator->remove_link(
-                '-many' => $self );
+            INFO "re-setting taxon link";
+            $mediator->remove_link( '-many' => $self );
         }
         return $self;
     }
@@ -86,7 +83,7 @@ Unlinks the invocant object from any taxon object.
 
     sub unset_taxon {
         my $self = shift;
-        $logger->debug("unsetting taxon");
+        DEBUG "unsetting taxon";
         $self->set_taxon();
         return $self;
     }
@@ -113,11 +110,7 @@ Retrieves the Bio::Phylo::Taxa::Taxon object linked to the invocant.
 =cut
 
     sub get_taxon {
-        return Bio::Phylo::Mediators::TaxaMediator->get_link( '-source' => shift );
-    }
-
-    sub _cleanup {
-        my $self = shift;
+        $mediator->get_link( '-source' => shift );
     }
 
 =back
@@ -1,7 +1,6 @@
 package Bio::Phylo::Treedrawer;
 use strict;
 use Bio::Phylo::Util::Logger;
-use Bio::Phylo::Forest::DrawTree;
 use Bio::Phylo::Util::Exceptions 'throw';
 use Bio::Phylo::Util::CONSTANT qw'_TREE_ /looks_like/ _PI_';
 
@@ -398,9 +397,6 @@ Sets tree to draw.
 sub set_tree {
     my ( $self, $tree ) = @_;
     if ( looks_like_object $tree, _TREE_ ) {
-        if ( not $tree->isa('Bio::Phylo::Forest::DrawTree') ) {
-            $tree = Bio::Phylo::Forest::DrawTree->new( '-tree' => $tree );
-        }
         $self->{'TREE'} = $tree->negative_to_zero;
     }
     return $self;
@@ -0,0 +1,152 @@
+package Bio::Phylo::Unparsers::Nwmsrdf;
+use strict;
+use base 'Bio::Phylo::Unparsers::Abstract';
+use Bio::Phylo::Util::Exceptions 'throw';
+use Bio::Phylo::Util::CONSTANT qw':objecttypes looks_like_object';
+
+=head1 NAME
+
+Bio::Phylo::Unparsers::Nwmsrdf - Serializer used by Bio::Phylo::IO, no serviceable parts inside
+
+=head1 DESCRIPTION
+
+This unparser produces multistate character state matrices for the "Network" 
+(L<http://www.fluxus-engineering.com/sharenet.htm>) program. These files by Network's 
+conventions have the .rdf extension, which has nothing to do with RDF. The matrices are
+represented as follows:
+
+=over
+
+=item Only variable columns are shown. The header includes the column number.
+
+=item The end of each character row has the frequency of the haplotype. By default this
+is 1, other values can be specified by adding an annotation to the row in question:
+
+	$row->set_meta_object( 'bp:haplotype_frequency' => 2 );
+
+=item The bottom of the file lists the weight of each column. By default this is 10, other
+values can be specified by adding a weight to the character:
+
+	$char->set_weight( 15 );
+
+=item Taxon names must be variable in the first 6 characters as they are truncated to 
+this length.
+
+=back
+
+=cut
+
+sub _to_string {
+    my $self = shift;
+    
+    # get the matrix object
+    my $obj  = $self->{'PHYLO'};
+    my $matrix;
+    eval { $matrix = $obj if looks_like_object $obj, _MATRIX_; };
+    if ($@) {
+        undef($@);
+        eval {
+            ($matrix) = @{ $obj->get_matrices }
+              if looks_like_object $obj, _PROJECT_;
+        };
+        if ( $@ or not $matrix ) {
+            throw 'ObjectMismatch' => 'Invalid object!';
+        }
+    }
+
+	# build the matrix hash, record column numbers    
+	my $nchar = $matrix->get_nchar;
+	my $raw   = $matrix->get_raw;
+	my %result = map { $_->[0] => '' } @{ $raw };
+	my @cols;
+	my ( $missing, $gap ) = ( $matrix->get_missing, $matrix->get_gap );
+	for my $i ( 1 .. $nchar ) {
+		my %seen;
+		my %state;
+		for my $row ( @{ $raw } ) {
+			my $state = $row->[$i];
+			$state{$row->[0]} = $state;
+			$seen{$state}++ if $state ne $missing and $state ne $gap;
+		}
+		if ( scalar(keys(%seen)) > 1 ) {
+			push @cols, $i;
+			$result{$_} .= $state{$_} for keys %state;
+		}
+	}
+	
+	# build the header with column numbers
+	my $result = '';
+	my @header;
+	push @header, ' ' x 7 for 1 .. 6;
+	for my $c ( @cols ) {
+		my @parts = split //, $c;
+		for my $i ( 0 .. $#header ) {
+			my $val = defined($parts[$i]) ? $parts[$i] : ' ';
+			$header[$i] .= $val;
+		}
+	}
+	$result .= join "\n", @header;
+	$result .= "\n";
+	
+	# build the matrix
+	for my $name ( map { $_->[0] } @{ $raw } ) {
+		if ( length($name) <= 6 ) {
+			$result .= $name . ( ' ' x ( 7 - length($name) ) );
+		}
+		else {
+			$result .= substr( $name, 0, 6 ) . ' ';
+		}
+		$result .= $result{$name} . '  ';
+		my $freq = $matrix->get_by_name($name)->get_meta_object('bp:haplotype_frequency') || 1;
+		$result .= $freq . "\n";
+	}
+	$result .= "\n";
+	
+	# build the character weights
+	my $characters = $matrix->get_characters;
+	my @weights;
+	for my $i ( @cols ) {
+		my $weight = $characters->get_by_index($i-1)->get_weight;
+		$weight = 10 if not defined $weight;
+		push @weights, $weight;
+	}
+	for ( my $i = 0; $i <= $#weights; $i += 124 ) {
+		my $max = $i+124 < $#weights ? $i+124 : $#weights;
+		$result .= join '', @weights[$i..$max];
+		$result .= "\n";
+	}
+	return $result;
+}
+
+# podinherit_insert_token
+
+=head1 SEE ALSO
+
+There is a mailing list at L<https://groups.google.com/forum/#!forum/bio-phylo> 
+for any user or developer questions and discussions.
+
+=over
+
+=item L<Bio::Phylo::IO>
+
+The nwmsrdf unparser is called by the L<Bio::Phylo::IO> object.
+Look there to learn how to create phylip formatted files.
+
+=item L<Bio::Phylo::Manual>
+
+Also see the manual: L<Bio::Phylo::Manual> and L<http://rutgervos.blogspot.com>.
+
+=back
+
+=head1 CITATION
+
+If you use Bio::Phylo in published research, please cite it:
+
+B<Rutger A Vos>, B<Jason Caravas>, B<Klaas Hartmann>, B<Mark A Jensen>
+and B<Chase Miller>, 2011. Bio::Phylo - phyloinformatic analysis using Perl.
+I<BMC Bioinformatics> B<12>:63.
+L<http://dx.doi.org/10.1186/1471-2105-12-63>
+
+=cut
+
+1;
@@ -28,6 +28,7 @@ sub _CHARACTER_ ()     { 25 }
 sub _SET_ ()           { 26 }
 sub _MODEL_ ()         { 27 }
 sub _OPERATION_ ()     { 28 }
+sub _DATATYPE_ ()      { 29 }
 
 =head1 NAME
 
@@ -38,6 +38,7 @@ BEGIN {
       _SET_
       _MODEL_
       _OPERATION_
+      _DATATYPE_
       looks_like_number
       looks_like_object
       looks_like_hash
@@ -64,6 +65,7 @@ BEGIN {
       _NS_TNRS_
       _NS_FIGTREE_
       _NS_PHYLOMAP_
+      _NS_BIOVEL_
     );
     %EXPORT_TAGS = (
         'all'         => [@EXPORT_OK],
@@ -99,6 +101,7 @@ BEGIN {
               _SET_
               _MODEL_
               _OPERATION_
+              _DATATYPE_
             )
         ],
         'functions' => [
@@ -131,6 +134,7 @@ BEGIN {
               _NS_TNRS_
               _NS_FIGTREE_
               _NS_PHYLOMAP_
+              _NS_BIOVEL_
             )
         ]
     );
@@ -159,6 +163,7 @@ sub _NS_TB2PURL_ ()  { 'http://purl.org/phylo/treebase/phylows/' }
 sub _NS_TNRS_ ()     { 'http://phylotastic.org/tnrs/terms#' }
 sub _NS_FIGTREE_ ()  { 'http://tree.bio.ed.ac.uk/software/figtree/terms#' }
 sub _NS_PHYLOMAP_ () { 'http://purl.org/phylo/phylomap/terms#' }
+sub _NS_BIOVEL_ ()   { 'http://biovel.eu/terms#' }
 
 our $NS = {
     'tnrs' => _NS_TNRS_(),
@@ -175,6 +180,7 @@ our $NS = {
     'nex'  => _NS_NEXML_(),
     'dc'   => _NS_DC_(),
     'owl'  => _NS_OWL_(),
+    'bv'   => _NS_BIOVEL_(),
     'dcterms' => _NS_DCTERMS_(),
     'fig'     => _NS_FIGTREE_(),
 };
@@ -209,6 +215,7 @@ sub _CHARACTER_ ()     { Bio::Phylo::Util::CONSTANT::Int::_CHARACTER_ }
 sub _SET_ ()           { Bio::Phylo::Util::CONSTANT::Int::_SET_ }
 sub _MODEL_ ()         { Bio::Phylo::Util::CONSTANT::Int::_MODEL_ }
 sub _OPERATION_ ()     { Bio::Phylo::Util::CONSTANT::Int::_OPERATION_ }
+sub _DATATYPE_ ()      { Bio::Phylo::Util::CONSTANT::Int::_DATATYPE_ }
 
 # for PhyloWS
 sub _HTTP_SC_SEE_ALSO_ () { '303 See Other' }
@@ -170,13 +170,37 @@ BEGIN {
         return $VERBOSITY{'*'};
     }
     
-    # alias for singleton methods
-    no warnings 'once';
-    *fatal = \&FATAL;
-    *error = \&ERROR;
-    *warn  = \&WARN;
-    *info  = \&INFO;
-    *debug = \&DEBUG;
+    # aliases for singleton methods
+    sub fatal {
+		my $self = shift;
+		$TRACEBACK++;
+		FATAL shift;
+		$TRACEBACK--;
+	}
+    sub error {
+		my $self = shift;
+		$TRACEBACK++;
+		ERROR shift;
+		$TRACEBACK--;
+	}
+	sub warn {
+		my $self = shift;
+		$TRACEBACK++;
+		WARN shift;
+		$TRACEBACK--;
+	}
+	sub info {
+		my $self = shift;
+		$TRACEBACK++;
+		INFO shift;
+		$TRACEBACK--;
+	}
+	sub debug {
+		my $self = shift;
+		$TRACEBACK++;
+		DEBUG shift;
+		$TRACEBACK--;
+	}
     
     # empty destructor so we don't go up inheritance tree at the end
     sub DESTROY {}  
@@ -13,9 +13,15 @@ Bio::Phylo::Util::MOP - Meta-object programming, no serviceable parts inside
 
 =cut
 
-# 
+# this will be populated when the attribute handlers are triggered
 my %methods;
 
+# this will progressively store/memoize all superclasses for given classes
+my %classes;
+
+# this will progressively store/memoize the methods for given classes
+my %class_methods;
+
 # this might be used to check the interface of alien subclasses
 sub import {
     
@@ -48,7 +54,7 @@ sub get_method {
 # @methods = @{ $mop->get_implementations( 'new', $obj || $package ) };
 sub get_implementations {
 	my ( $self, $method, $obj ) = @_;
-	my @methods = grep { $_->{name} eq $method } @{ $self->get_methods($obj) };
+	my @methods = grep { $_->{'name'} eq $method } @{ $self->get_methods($obj) };
 	return \@methods;
 }
 
@@ -56,9 +62,19 @@ sub get_implementations {
 sub get_classes {
     my ( $self, $obj, $all ) = @_;
     my $class = ref $obj || $obj;
-    my ( $seen, $isa ) = ( {}, [] );
-    _recurse_isa($class, $isa, $seen, $all);
-    return $isa;
+    
+    # return if already cached
+    if ( $classes{$class} ) {
+    	return $classes{$class};
+    }
+    
+    # compute, cache, return
+    else {
+    	my ( $seen, $isa ) = ( {}, [] );
+	    _recurse_isa($class, $isa, $seen, $all);
+	    $classes{$class} = $isa;
+    	return $isa;
+    }
 }
 
 # starting from $class, push all superclasses (+$class) into @$isa,
@@ -83,39 +99,58 @@ sub _recurse_isa {
 # my @methods = @{ $mop->get_methods($obj) };
 sub get_methods {
     my ( $self, $obj ) = @_;
-    my $isa = $self->get_classes($obj);
-    my @methods;
-	for my $package ( @{ $isa } ) {
+    my $class = ref $obj || $obj;
+    
+    # return if already cached
+    if ( $class_methods{$class} ) {
+    	return $class_methods{$class};
+    }
+    
+    # compute, cache, return
+    else {
+		my $isa = $self->get_classes($obj);
+		my @methods;
+		for my $package ( @{ $isa } ) {
 
-		my %symtable = %{ $self->get_symtable($package) };		
+			my %symtable = %{ $self->get_symtable($package) };		
 		
-		# at this point we have lots of things, we just want methods
-		for my $entry ( keys %symtable ) {
+			# at this point we have lots of things, we just want methods
+			for my $entry ( keys %symtable ) {
 			
-			# check if entry is a CODE reference
-			my $can = $package->can( $entry );
-			if ( ref $can eq 'CODE' ) {
-				push @methods, {
-					'package'    => $package,
-					'name'       => $entry,
-					'glob'       => $symtable{$entry},
-					'code'       => $can,
-				};
+				# check if entry is a CODE reference
+				my $can = $package->can( $entry );
+				if ( ref $can eq 'CODE' ) {
+					push @methods, {
+						'package'    => $package,
+						'name'       => $entry,
+						'glob'       => $symtable{$entry},
+						'code'       => $can,
+					};
+				}
 			}
 		}
-	}
-	return \@methods;        
+		$class_methods{$class} = \@methods;
+		return \@methods;  
+	}      
 }
 
 sub get_methods_by_attribute {
     my ( $self, $obj, $attribute ) = @_;
     my $isa = $self->get_classes($obj);
     my $methods = $methods{$attribute};
-    my %return;
+    my @return;
     for my $class ( @{ $isa } ) {
-        $return{$class} = $methods->{$class} if $methods->{$class};
+	if ( $methods->{$class} ) {
+	    for my $key ( keys %{ $methods->{$class} } ) {
+		push @return, {
+		    'package' => $class,
+		    'name'    => $key,
+		    'code'    => $methods->{$class}->{$key}
+		};
+	    }
+	}
     }
-    return \%return;
+    return \@return;
 }
 
 sub get_accessors {
@@ -143,6 +178,11 @@ sub get_clonables {
     return $self->get_methods_by_attribute($obj,'Clonable');
 }
 
+sub get_deep_clonables {
+    my ( $self, $obj ) = @_;
+    return $self->get_methods_by_attribute($obj,'DeepClonable');
+}
+
 sub get_destructors {
     my ( $self, $obj ) = @_;
     return $self->get_methods_by_attribute($obj,'Destructor');
@@ -158,6 +198,11 @@ sub get_statics {
     return $self->get_methods_by_attribute($obj,'Static');
 }
 
+sub get_serializers {
+    my ( $self, $obj ) = @_;
+    return $self->get_methods_by_attribute($obj,'Serializer');
+}
+
 sub _handler {
     eval {
         my ($package, $symbol, $referent, $attr, $data) = @_;
@@ -249,6 +294,15 @@ sub UNIVERSAL::Clonable : ATTR(CODE) {
     _handler(@_);  
 }
 
+sub UNIVERSAL::DeepClonable : ATTR(CODE) {
+	my ($package, $symbol, $referent, $attr, $data) = @_;
+    _handler(@_);  
+}
+
+sub UNIVERSAL::Serializer : ATTR(CODE) {
+	my ($package, $symbol, $referent, $attr, $data) = @_;
+    _handler(@_);  
+}
 
 1;
 
@@ -3,22 +3,17 @@ use strict;
 use Bio::PhyloRole;
 use base 'Bio::PhyloRole';
 
-# Because we use a roll-your-own looks_like_number from
-# Bio::Phylo::Util::CONSTANT, here we don't have to worry
-# about older core S::U versions that don't have it...
+# don't use Scalar::Util::looks_like_number directly, use wrapped version
 use Scalar::Util qw'weaken blessed';
-
-#... instead, Bio::Phylo::Util::CONSTANT can worry about it
-# in one location, perhaps using the S::U version, or a drop-in
 use Bio::Phylo::Util::CONSTANT '/looks_like/';
-use Bio::Phylo::Util::IDPool;    # creates unique object IDs
+use Bio::Phylo::Util::IDPool;             # creates unique object IDs
 use Bio::Phylo::Util::Exceptions 'throw'; # defines exception classes and throws
 use Bio::Phylo::Util::Logger;             # for logging, like log4perl/log4j
 use Bio::Phylo::Util::MOP;                # for traversing inheritance trees
 use Bio::Phylo::Identifiable;             # for storing unique IDs inside an instance
 
 our ( $logger, $COMPAT ) = Bio::Phylo::Util::Logger->new;
-our $VERSION = "0.56";
+our $VERSION = "0.58";
 
 # mediates one-to-many relationships between taxon and nodes,
 # taxon and sequences, taxa and forests, taxa and matrices.
@@ -139,7 +134,7 @@ argument "-name" in the constructor.
 
 =cut
 
-    sub new {
+    sub new : Constructor {
 
         # $class could be a child class, called from $class->SUPER::new(@_)
         # or an object, e.g. $node->new(%args) in which case we create a new
@@ -159,11 +154,12 @@ argument "-name" in the constructor.
         $objects{$id} = $self;
         weaken( $objects{$id} );
 		
-		# notify user
+	# notify user
         $logger->info("constructor called for '$class' - $id");
 
         # processing arguments
         if ( @_ and @_ = looks_like_hash @_ ) {
+	    $logger->info("processing arguments");
 
             # process all arguments
           ARG: while (@_) {
@@ -210,6 +206,7 @@ argument "-name" in the constructor.
                 }
             }
         }
+	$logger->info("done processing constructor arguments");
 
         # register with mediator
         # TODO this is irrelevant for some child classes,
@@ -217,9 +214,11 @@ argument "-name" in the constructor.
         # tips of the inheritance tree. The hack where we
         # skip over direct instances of Writable is so that
         # we don't register things like <format> and <matrix> tags
-        if ( ref $self ne 'Bio::Phylo::NeXML::Writable' ) {
+        if ( ref $self ne 'Bio::Phylo::NeXML::Writable' && ! $self->isa('Bio::Phylo::Matrices::Datatype') ) {
+	    $logger->info("going to register $self with $taxamediator");
             $taxamediator->register($self);
         }
+	$logger->info("done building object");
         return $self;
     }
 
@@ -245,9 +244,14 @@ Sets invocant GUID.
 
 =cut
 
-    sub set_guid {
+    sub set_guid : Clonable {
         my ( $self, $guid ) = @_;
-        $guid{ $self->get_id } = $guid;
+        if ( defined $guid ) {
+        	$guid{ $self->get_id } = $guid;
+        }
+        else {
+        	delete $guid{ $self->get_id };
+        }
         return $self;
     }
 
@@ -265,9 +269,14 @@ Sets invocant description.
 
 =cut
 
-    sub set_desc {
+    sub set_desc : Clonable {
         my ( $self, $desc ) = @_;
-        $desc{ $self->get_id } = $desc;
+        if ( defined $desc ) {
+        	$desc{ $self->get_id } = $desc;
+        }
+        else {
+        	delete $desc{ $self->get_id };
+        }
         return $self;
     }
 
@@ -286,7 +295,7 @@ Sets invocant score.
 
 =cut
 
-    sub set_score {
+    sub set_score : Clonable {
         my ( $self, $score ) = @_;
 
         # $score must be a number (or undefined)
@@ -297,13 +306,13 @@ Sets invocant score.
 
             # notify user
             $logger->info("setting score '$score'");
+	        $score{ $self->get_id } = $score;            
         }
         else {
             $logger->info("unsetting score");
+            delete $score{ $self->get_id };
         }
 
-        # this resets the score if $score was undefined
-        $score{ $self->get_id } = $score;
         return $self;
     }
 
@@ -329,7 +338,7 @@ Sets generic key/value pair(s).
 
 =cut
 
-    sub set_generic {
+    sub set_generic : Clonable {
         my $self = shift;
 
         # retrieve id just once, don't call $self->get_id in loops, inefficient
@@ -496,6 +505,36 @@ Attempts to fetch an in-memory object by its UID
         return $objects{$id};
     }
 
+=item get_logger()
+
+Returns a singleton reference to a Bio::Phylo::Util::Logger object
+
+ Type    : Accessor
+ Title   : get_logger
+ Usage   : my $logger = Bio::Phylo->get_logger
+ Function: Returns logger
+ Returns : A Bio::Phylo::Util::Logger object 
+ Args    : None
+
+=cut
+    
+    sub get_logger { $logger }
+
+=item VERSION()
+
+Returns the $VERSION string of this Bio::Phylo release
+
+ Type    : Accessor
+ Title   : VERSION
+ Usage   : my $version = Bio::Phylo->VERSION
+ Function: Returns version string
+ Returns : A string
+ Args    : None
+
+=cut
+    
+    sub VERSION { $VERSION }
+
 =item clone()
 
 Clones invocant.
@@ -510,80 +549,80 @@ Clones invocant.
 
 =cut
 
-    # TODO this needs overrides in a number of subclasses,
-    # in particular in Bio::Phylo::Taxa and Bio::Phylo::Taxa::Taxon
-    # classes because of the asymmetry between set_forest/get_forests,
-    # set_node/get_nodes etc.
     sub clone {
-        my ( $self, %subs ) = @_;
-
-        # may not work yet! warn user
-        $logger->info("cloning is experimental, use with caution");
-
-        # get inheritance tree
-        my ( $class, $isa, $seen ) = ( ref($self), [], {} );
-        _recurse_isa( $class, $isa, $seen );
-
-        # walk symbol table, get symmetrical set_foo/get_foo pairs
-        my %methods;
-        for my $package ( $class, @{$isa} ) {
-            my %symtable;
-            eval "\%symtable = \%${package}::";
-          SETTER: for my $setter ( keys %symtable ) {
-                next SETTER if $setter !~ m/^set_/;
-                my $getter = $setter;
-                $getter =~ s/^s/g/;
-                next SETTER if not exists $symtable{$getter};
-
-                # have a symmetrical set_foo/get_foo pair, check
-                # if they're code (not variables, for example)
-                my $get_ref = $class->can($getter);
-                my $set_ref = $class->can($setter);
-                if (    looks_like_instance( $get_ref, 'CODE' )
-                    and looks_like_instance( $set_ref, 'CODE' ) )
-                {
-                    $methods{$getter} = $setter;
-                }
-            }
-        }
-
-        # instantiate the clone
-        my @new;
-        if ( $subs{'new'} ) {
-            @new = @{ $subs{'new'} };
-            delete $subs{'new'};
-        }
-        my $clone = $class->new(@new);
+        my ( $self, $deep ) = @_;
+        $deep = 1 unless defined $deep;
+	
+	# compute and instantiate the constructor nearest to the tips of
+	# the inheritance tree
+	my $constructors = $mop->get_constructors($self); my $clone =
+	$constructors->[0]->{'code'}->(ref $self);
+
+	# keep track of which methods we've done, including overrides
+	my %seen;
+	
+	# do the deep cloning first
+	if ( $deep ) {
+	    
+	    # get the deeply clonable methods
+	    my $clonables = $mop->get_deep_clonables($self);
+	    for my $setter ( @{ $clonables } ) {
+		my $setter_name = $setter->{'name'};
+	
+		# only do this for the shallowest method with
+		# the same name: the others are overrided
+		if ( not $seen{$setter_name} ) {
+		    $seen{$setter_name}++;
+    
+		    # pass the output of the getter to the
+		    # input of the setter
+		    my $output = $self->_get_clonable_output($setter);
+		    my $input;
+		    if ( ref $output eq 'ARRAY' ) {
+			$input = [
+			    map { ref $_ ? $_->clone($deep) : $_ }
+			    @{ $output }
+			];
+		    }
+		    elsif ( $output and ref $output ) {
+			$input = $output->clone($deep);
+		    }
+		    $setter->{'code'}->($clone,$input);
+		}
+	    }
+	}
 		
-        # execute additional code refs
-        $_->( $self, $clone )
-          for ( grep { looks_like_instance( $_, 'CODE' ) } values %subs );		
-
-        # populate the clone
-        for my $getter ( keys %methods ) {
-            my $setter = $methods{$getter};
-            if ( exists $subs{$setter} ) {
-                $logger->info("method $setter for $clone overridden");
-                if ( looks_like_instance( $subs{$setter}, 'CODE' ) ) {
-                    $subs{$setter}->( $self, $clone );
-                }
-                delete $subs{$setter};
-            }
-            else {
-                eval {
-                    $logger->info("copying $getter => $setter");
-                    my $value = $self->$getter;
-                    if ( defined $value ) {
-                        $clone->$setter($value);
-                    }
-                };
-                if ($@) {
-                    $logger->warn("failed copy of $getter => $setter: \n$@");
-                }
-            }
-        }
-
-        return $clone;
+	# get the clonable methods
+	my $clonables = $mop->get_clonables($self);		
+	for my $setter ( @{ $clonables } ) {
+	    my $setter_name = $setter->{'name'};
+    
+	    # only do this for the shallowest method with the
+	    # same name: the others are overrided
+	    if ( not $seen{$setter_name} ) {
+		$seen{$setter_name}++;
+		my $output = $self->_get_clonable_output($setter);
+		$setter->{'code'}->($clone,$output);
+	    }		
+	}
+	return $clone;
+    }
+    
+    sub _get_clonable_output {
+	my ( $self, $setter ) = @_;
+	my $setter_name = $setter->{'name'};
+	
+	# assume getter/setter symmetry
+	my $getter_name = $setter_name;
+	$getter_name =~ s/^(_?)set_/$1get_/;
+	my $fqn = $setter->{'package'} . '::' . $getter_name;
+
+	# get the code reference for the fully qualified name of the getter
+	my $getter = $mop->get_method($fqn);
+
+	# pass the output of the getter to the input of the setter
+	my $output = $getter->($self);
+	return $output;
     }
 
 =begin comment
@@ -605,63 +644,33 @@ Invocant destructor.
 
 =cut
 
-    {
-        no warnings 'recursion';
-        my %isa_for_class;
-
-        sub DESTROY {
-            my $self = shift;
+	sub DESTROY {
+		my $self = shift;
 
-            # delete from get_obj_by_id
-            my $id;
-            if ( defined( $id = $self->get_id ) ) {
-                delete $objects{$id};
-            }
+		# delete from get_obj_by_id
+		my $id;
+		if ( defined( $id = $self->get_id ) ) {
+			delete $objects{$id};
+		}
 
-          # call *all* _cleanup methods, wouldn't work if simply SUPER::_cleanup
-          # given multiple inheritance
-			my $isa = $mop->get_classes($self);          
-            {
-                no strict 'refs';
-                for my $SUPER ( @{$isa} ) {
-                    if ( $SUPER->can('_cleanup') ) {
-                        my $cleanup = "${SUPER}::_cleanup";
-                        $self->$cleanup;
-                    }
-                }
-                use strict;
-            }
-			
-            #$logger->debug("done cleaning up '$self'"); # XXX
-            # cleanup from mediator
-            $taxamediator->unregister($self);
+		# do the cleanups
+		my @destructors = @{ $mop->get_destructors( $self ) };
+		for my $d ( @destructors ) {			
+			$d->{'code'}->( $self );
+		}
+		
+		# unregister from mediator
+		$taxamediator->unregister( $self );
 
-            # done cleaning up, id can be reclaimed
-            Bio::Phylo::Util::IDPool->_reclaim($self);
-        }
-    }
+		# done cleaning up, id can be reclaimed
+		Bio::Phylo::Util::IDPool->_reclaim( $self );
+	}
 
-    # starting from $class, push all superclasses (+$class) into @$isa,
-    # %$seen is just a helper to avoid getting stuck in cycles
-    sub _recurse_isa {
-        my ( $class, $isa, $seen ) = @_;
-        if ( not $seen->{$class} ) {
-            $seen->{$class} = 1;
-            push @{$isa}, $class;
-            my @isa;
-            {
-                no strict 'refs';
-                @isa = @{"${class}::ISA"};
-                use strict;
-            }
-            _recurse_isa( $_, $isa, $seen ) for @isa;
-        }
-    }
 
     # child classes probably should have a method like this,
     # if their objects hold internal state anyway (b/c they'll
     # be inside-out objects).
-    sub _cleanup {
+    sub _cleanup : Destructor {
         my $self = shift;
         my $id = $self->get_id;
 
@@ -694,10 +703,7 @@ Invocant destructor.
     # to have the objects of a has-a relationship fiddle with
     # their container we hide this method from abuse. Then
     # again, sometimes it's handy ;-)
-    sub _get_container {
-        my $self = shift;
-        return $container{ $self->get_id };
-    }
+    sub _get_container { $container{ shift->get_id } }
 
 =begin comment
 
@@ -721,8 +727,7 @@ Invocant destructor.
                 if ( $container->can_contain($self) ) {
                     if ( $container->contains($self) ) {
                         $container{$id} = $container;
-                        weaken( $container{$id} );
-                        return $self;
+                        weaken( $container{$id} );                        
                     }
                     else {
                         throw 'ObjectMismatch' => "'$self' not in '$container'";
@@ -738,8 +743,10 @@ Invocant destructor.
             }
         }
         else {
-            throw 'BadArgs' => "Argument not an object";
-        }
+			delete $container{$id};
+				#throw 'BadArgs' => "Argument not an object";
+		}
+		return $self;
     }
 
 =back
@@ -1,77 +1,10 @@
 package Bio::PhyloRole;
 use strict;
 use base 'Bio::Phylo::Identifiable';
-
-# ABSTRACT: Phyloinformatic analysis using Perl
-
-# Because we use a roll-your-own looks_like_number from
-# Bio::Phylo::Util::CONSTANT, here we don't have to worry
-# about older core S::U versions that don't have it...
-use Scalar::Util qw'weaken blessed';
-
-#... instead, Bio::Phylo::Util::CONSTANT can worry about it
-# in one location, perhaps using the S::U version, or a drop-in
 use Bio::Phylo::Util::CONSTANT '/looks_like/';
-use Bio::Phylo::Util::IDPool;    # creates unique object IDs
-use Bio::Phylo::Identifiable;    # for storing unique IDs inside an instance
-use Bio::Phylo::Util::Exceptions 'throw'; # defines exception classes and throws
-use Bio::Phylo::Util::Logger;             # for logging, like log4perl/log4j
-our ( $logger, $COMPAT ) = Bio::Phylo::Util::Logger->new;
-
-# mediates one-to-many relationships between taxon and nodes,
-# taxon and sequences, taxa and forests, taxa and matrices.
-# Read up on the Mediator design pattern to learn how this works.
-require Bio::Phylo::Mediators::TaxaMediator;
-
-# Include the revision number from subversion in $VERSION
-my $rev = '$Id: Phylo.pm 1660 2011-04-02 18:29:40Z rvos $';
-$rev =~ s/^[^\d]+(\d+)\b.*$/$1/;
-our $VERSION = "0.50";
-$VERSION .= "_$rev";
-{
-    my $taxamediator = 'Bio::Phylo::Mediators::TaxaMediator';
-
-    sub import {
-        my $class = shift;
-        if (@_) {
-            my %opt = looks_like_hash @_;
-            while ( my ( $key, $value ) = each %opt ) {
-                if ( $key =~ qr/^VERBOSE$/i ) {
-                    $logger->VERBOSE( '-level' => $value, -class => $class );
-                }
-                elsif ( $key =~ qr/^COMPAT$/i ) {
-                    $COMPAT = ucfirst( lc($value) );
-                }
-                else {
-                    throw 'BadArgs' =>
-                      "'$key' is not a valid argument for import";
-                }
-            }
-        }
-        return 1;
-    }
-
-    # the following hashes are used to hold state of inside-out objects. For
-    # example, $obj->set_name("name") is implemented as $name{ $obj->get_id }
-    # = $name. To avoid memory leaks (and subtle bugs, should a new object by
-    # the same id appear (though that shouldn't happen)), the hash slots
-    # occupied by $obj->get_id need to be reclaimed in the destructor. This
-    # is done by recursively calling the $obj->_cleanup methods in all of $obj's
-    # superclasses. To make that method easier to write, we create an  array
-    # with the local inside-out hashes here, so that we can just iterate over
-    # them anonymously during destruction cleanup. Other classes do something
-    # like this as well.
-    my @fields = \(
-        my (
-			%guid,
-            %desc,
-            %score,
-            %generic,
-            %cache,
-            %container,    # XXX weak reference
-            %objects       # XXX weak reference
-        )
-    );
+use Bio::Phylo::Identifiable;              # for storing unique IDs inside an instance
+use Bio::Phylo::Util::Exceptions 'throw';  # defines exception classes and throws
+use Bio::Phylo::Util::Logger;    # for logging, like log4perl/log4j
 
 =head1 NAME
 
@@ -115,264 +48,6 @@ in L<Bio::Phylo::Util::Logger> of use to localize problems.
 
 =head1 METHODS
 
-=head2 CONSTRUCTOR
-
-=over
-
-=item new()
-
-The Bio::Phylo root constructor is rarely used directly. Rather, many other 
-objects in Bio::Phylo internally go up the inheritance tree to this constructor. 
-The arguments shown here can therefore also be passed to any of the child 
-classes' constructors, which will pass them on up the inheritance tree. Generally, 
-constructors in Bio::Phylo subclasses can process as arguments all methods that 
-have set_* in their names. The arguments are named for the methods, but "set_" 
-has been replaced with a dash "-", e.g. the method "set_name" becomes the 
-argument "-name" in the constructor.
-
- Type    : Constructor
- Title   : new
- Usage   : my $phylo = Bio::Phylo->new;
- Function: Instantiates Bio::Phylo object
- Returns : a Bio::Phylo object 
- Args    : Optional, any number of setters. For example,
- 		   Bio::Phylo->new( -name => $name )
- 		   will call set_name( $name ) internally
-
-=cut
-
-    sub new {
-
-        # $class could be a child class, called from $class->SUPER::new(@_)
-        # or an object, e.g. $node->new(%args) in which case we create a new
-        # object that's bless into the same class as the invocant. No, that's
-        # not the same thing as a clone.
-        my $class = shift;
-        if ( my $reference = ref $class ) {
-            $class = $reference;
-        }
-
-        # happens only and exactly once because this
-        # root class is visited from every constructor
-        my $self = $class->SUPER::new();
-
-        # register for get_obj_by_id
-        my $id = $self->get_id;
-        $objects{$id} = $self;
-        weaken( $objects{$id} );
-		
-		# notify user
-        $logger->info("constructor called for '$class' - $id");
-
-        # processing arguments
-        if ( @_ and @_ = looks_like_hash @_ ) {
-
-            # process all arguments
-          ARG: while (@_) {
-                my $key   = shift @_;
-                my $value = shift @_;
-
-                # this is a bioperl arg, meant to set
-                # verbosity at a per class basis. In
-                # bioperl, the $verbose argument is
-                # subsequently carried around in that
-                # class, here we delegate that to the
-                # logger, which has roughly the same
-                # effect.
-                if ( $key eq '-verbose' ) {
-                    $logger->VERBOSE(
-                        '-level' => $value,
-                        '-class' => $class,
-                    );
-                    next ARG;
-                }
-
-                # notify user
-                $logger->debug(
-                    "processing constructor arg '${key}' => '${value}'");
-
-                # don't access data structures directly, call mutators
-                # in child classes or __PACKAGE__
-                my $mutator = $key;
-                $mutator =~ s/^-/set_/;
-
-                # backward compat fixes:
-                $mutator =~ s/^set_pos$/set_position/;
-                $mutator =~ s/^set_matrix$/set_raw/;
-                eval { $self->$mutator($value); };
-                if ($@) {
-                    if ( blessed $@ and $@->can('rethrow') ) {
-                        $@->rethrow;
-                    }
-                    elsif ( not ref($@)
-                        and $@ =~ /^Can't locate object method / )
-                    {
-                        throw 'BadArgs' =>
-"The named argument '${key}' cannot be passed to the constructor of ${class}";
-                    }
-                    else {
-                        throw 'Generic' => $@;
-                    }
-                }
-            }
-        }
-
-        # register with mediator
-        # TODO this is irrelevant for some child classes,
-        # so should be re-factored into somewhere nearer the
-        # tips of the inheritance tree. The hack where we
-        # skip over direct instances of Writable is so that
-        # we don't register things like <format> and <matrix> tags
-        if ( ref $self ne 'Bio::Phylo::NeXML::Writable' ) {
-            $taxamediator->register($self);
-        }
-        return $self;
-    }
-
-=back
-
-=head2 MUTATORS
-
-=over
-
-=item set_guid()
-
-Sets invocant GUID.
-
- Type    : Mutator
- Title   : set_guid
- Usage   : $obj->set_guid($guid);
- Function: Assigns an object's GUID.
- Returns : Modified object.
- Args    : A scalar
- Notes   : This field can be used for storing an identifier that is
-           unambiguous within a given content. For example, an LSID,
-	   a genbank accession number, etc.
-
-=cut
-
-    sub set_guid {
-        my ( $self, $guid ) = @_;
-        $guid{ $self->get_id } = $guid;
-        return $self;
-    }
-
-
-=item set_desc()
-
-Sets invocant description.
-
- Type    : Mutator
- Title   : set_desc
- Usage   : $obj->set_desc($desc);
- Function: Assigns an object's description.
- Returns : Modified object.
- Args    : Argument must be a string.
-
-=cut
-
-    sub set_desc {
-        my ( $self, $desc ) = @_;
-        $desc{ $self->get_id } = $desc;
-        return $self;
-    }
-
-=item set_score()
-
-Sets invocant score.
-
- Type    : Mutator
- Title   : set_score
- Usage   : $obj->set_score($score);
- Function: Assigns an object's numerical score.
- Returns : Modified object.
- Args    : Argument must be any of
-           perl's number formats, or undefined
-           to reset score.
-
-=cut
-
-    sub set_score {
-        my ( $self, $score ) = @_;
-
-        # $score must be a number (or undefined)
-        if ( defined $score ) {
-            if ( !looks_like_number($score) ) {
-                throw 'BadNumber' => "score \"$score\" is a bad number";
-            }
-
-            # notify user
-            $logger->info("setting score '$score'");
-        }
-        else {
-            $logger->info("unsetting score");
-        }
-
-        # this resets the score if $score was undefined
-        $score{ $self->get_id } = $score;
-        return $self;
-    }
-
-=item set_generic()
-
-Sets generic key/value pair(s).
-
- Type    : Mutator
- Title   : set_generic
- Usage   : $obj->set_generic( %generic );
- Function: Assigns generic key/value pairs to the invocant.
- Returns : Modified object.
- Args    : Valid arguments constitute:
-
-           * key/value pairs, for example:
-             $obj->set_generic( '-lnl' => 0.87565 );
-
-           * or a hash ref, for example:
-             $obj->set_generic( { '-lnl' => 0.87565 } );
-
-           * or nothing, to reset the stored hash, e.g.
-                $obj->set_generic( );
-
-=cut
-
-    sub set_generic {
-        my $self = shift;
-
-        # retrieve id just once, don't call $self->get_id in loops, inefficient
-        my $id = $self->get_id;
-
-     # this initializes the hash if it didn't exist yet, or resets it if no args
-        if ( !defined $generic{$id} || !@_ ) {
-            $generic{$id} = {};
-        }
-
-        # have args
-        if (@_) {
-            my %args;
-
-            # have a single arg, a hash ref
-            if ( scalar @_ == 1 && looks_like_instance( $_[0], 'HASH' ) ) {
-                %args = %{ $_[0] };
-            }
-
-            # multiple args, hopefully even size key/value pairs
-            else {
-                %args = looks_like_hash @_;
-            }
-
-            # notify user
-            $logger->info("setting generic key/value pairs %{args}");
-
-            # fill up the hash
-            foreach my $key ( keys %args ) {
-                $generic{$id}->{$key} = $args{$key};
-            }
-        }
-        return $self;
-    }
-
-=back
-
 =head2 ACCESSORS
 
 =over
@@ -442,132 +117,6 @@ Gets invocant's 'fallback' name (possibly autogenerated).
         }
     }
 
-=item get_guid()
-
-Gets invocant GUID.
-
- Type    : Accessor
- Title   : get_guid
- Usage   : my $guid = $obj->get_guid;
- Function: Assigns an object's GUID.
- Returns : Scalar.
- Args    : None
- Notes   : This field can be used for storing an identifier that is
-           unambiguous within a given content. For example, an LSID,
-	   a genbank accession number, etc.
-
-=cut
-
-    sub get_guid {
-	my $self = shift;
-	return $guid{ $self->get_id };
-    }
-
-=item get_desc()
-
-Gets invocant description.
-
- Type    : Accessor
- Title   : get_desc
- Usage   : my $desc = $obj->get_desc;
- Function: Returns the object's description (if any).
- Returns : A string
- Args    : None
-
-=cut
-
-    sub get_desc {
-        my $self = shift;
-        return $desc{ $self->get_id };
-    }
-
-=item get_score()
-
-Gets invocant's score.
-
- Type    : Accessor
- Title   : get_score
- Usage   : my $score = $obj->get_score;
- Function: Returns the object's numerical score (if any).
- Returns : A number
- Args    : None
-
-=cut
-
-    sub get_score {
-        my $self = shift;
-        $logger->debug("getting score");
-        return $score{ $self->get_id };
-    }
-
-=item get_generic()
-
-Gets generic hashref or hash value(s).
-
- Type    : Accessor
- Title   : get_generic
- Usage   : my $value = $obj->get_generic($key);
-           or
-           my %hash = %{ $obj->get_generic() };
- Function: Returns the object's generic data. If an
-           argument is used, it is considered a key
-           for which the associated value is returned.
-           Without arguments, a reference to the whole
-           hash is returned.
- Returns : A value or an array reference of values
- Args    : A key (string) or an array reference of keys
-
-=cut
-
-    sub get_generic {
-        my ( $self, $key ) = @_;
-
-        # retrieve just once
-        my $id = $self->get_id;
-
-        # might not even have a generic hash yet, make one on-the-fly
-        if ( not defined $generic{$id} ) {
-            $generic{$id} = {};
-        }
-
-        # have an argument
-        if ( defined $key ) {
-
-			if ( ref($key) eq 'ARRAY' ) {
-				my @result = @generic{@$key};
-				return \@result;
-			}
-			else {
-				# notify user
-				$logger->debug("getting value for key '$key'");
-				return $generic{$id}->{$key};
-			}
-        }
-
-        # no argument, wants whole hash
-        else {
-
-            # notify user
-            $logger->debug("retrieving generic hash");
-            return $generic{$id};
-        }
-    }
-
-=item get_logger()
-
-Gets a logger object.
-
- Type    : Accessor
- Title   : get_logger
- Usage   : my $logger = $obj->get_logger;
- Function: Returns a Bio::Phylo::Util::Logger object
- Returns : Bio::Phylo::Util::Logger
- Args    : None
-
-=cut
-
-    sub get_logger { $logger }
-
 =back
 
 =head2 PACKAGE METHODS
@@ -592,9 +141,6 @@ Attempts to execute argument string as method on invocant.
     sub get {
         my ( $self, $var ) = @_;
         if ( $self->can($var) ) {
-
-            # notify user
-            $logger->debug("retrieving return value for method '$var'");
             return $self->$var;
         }
         else {
@@ -603,24 +149,6 @@ Attempts to execute argument string as method on invocant.
         }
     }
 
-=item get_obj_by_id()
-
-Attempts to fetch an in-memory object by its UID
-
- Type    : Accessor
- Title   : get_obj_by_id
- Usage   : my $obj = Bio::Phylo->get_obj_by_id($uid);
- Function: Fetches an object from the IDPool cache
- Returns : A Bio::Phylo object 
- Args    : A unique id
-
-=cut
-
-    sub get_obj_by_id {
-        my ( $class, $id ) = @_;
-        return $objects{$id};
-    }
-
 =item to_string()
 
 Serializes object to general purpose string
@@ -653,96 +181,6 @@ desc: $desc
 SERIALIZED_OBJECT
     }
 
-=item clone()
-
-Clones invocant.
-
- Type    : Utility method
- Title   : clone
- Usage   : my $clone = $object->clone;
- Function: Creates a copy of the invocant object.
- Returns : A copy of the invocant.
- Args    : None.
- Comments: Cloning is currently experimental, use with caution.
-
-=cut
-
-    # TODO this needs overrides in a number of subclasses,
-    # in particular in Bio::Phylo::Taxa and Bio::Phylo::Taxa::Taxon
-    # classes because of the asymmetry between set_forest/get_forests,
-    # set_node/get_nodes etc.
-    sub clone {
-        my ( $self, %subs ) = @_;
-
-        # may not work yet! warn user
-        $logger->info("cloning is experimental, use with caution");
-
-        # get inheritance tree
-        my ( $class, $isa, $seen ) = ( ref($self), [], {} );
-        _recurse_isa( $class, $isa, $seen );
-
-        # walk symbol table, get symmetrical set_foo/get_foo pairs
-        my %methods;
-        for my $package ( $class, @{$isa} ) {
-            my %symtable;
-            eval "\%symtable = \%${package}::";
-          SETTER: for my $setter ( keys %symtable ) {
-                next SETTER if $setter !~ m/^set_/;
-                my $getter = $setter;
-                $getter =~ s/^s/g/;
-                next SETTER if not exists $symtable{$getter};
-
-                # have a symmetrical set_foo/get_foo pair, check
-                # if they're code (not variables, for example)
-                my $get_ref = $class->can($getter);
-                my $set_ref = $class->can($setter);
-                if (    looks_like_instance( $get_ref, 'CODE' )
-                    and looks_like_instance( $set_ref, 'CODE' ) )
-                {
-                    $methods{$getter} = $setter;
-                }
-            }
-        }
-
-        # instantiate the clone
-        my @new;
-        if ( $subs{'new'} ) {
-            @new = @{ $subs{'new'} };
-            delete $subs{'new'};
-        }
-        my $clone = $class->new(@new);
-		
-        # execute additional code refs
-        $_->( $self, $clone )
-          for ( grep { looks_like_instance( $_, 'CODE' ) } values %subs );		
-
-        # populate the clone
-        for my $getter ( keys %methods ) {
-            my $setter = $methods{$getter};
-            if ( exists $subs{$setter} ) {
-                $logger->info("method $setter for $clone overridden");
-                if ( looks_like_instance( $subs{$setter}, 'CODE' ) ) {
-                    $subs{$setter}->( $self, $clone );
-                }
-                delete $subs{$setter};
-            }
-            else {
-                eval {
-                    $logger->info("copying $getter => $setter");
-                    my $value = $self->$getter;
-                    if ( defined $value ) {
-                        $clone->$setter($value);
-                    }
-                };
-                if ($@) {
-                    $logger->warn("failed copy of $getter => $setter: \n$@");
-                }
-            }
-        }
-
-        return $clone;
-    }
-
 =item VERBOSE()
 
 Getter and setter for the verbosity level. Refer to L<Bio::Phylo::Util::Logger> for more
@@ -766,10 +204,8 @@ info on available verbosity levels.
         my $class = shift;
         if (@_) {
             my %opt = looks_like_hash @_;
-            $logger->VERBOSE(%opt);
+            Bio::Phylo::Util::Logger::VERBOSE(%opt);
 
-            # notify user
-            $logger->info("Changed verbosity level to '$opt{-level}'");
         }
         return $Bio::Phylo::Util::Logger::VERBOSE;
     }
@@ -796,191 +232,6 @@ doi:10.1186/1471-2105-12-63
 CITATION
     }
 
-=item VERSION()
-
-Gets version number (including revision number).
-
- Type    : Accessor
- Title   : VERSION
- Usage   : $phylo->VERSION;
- Function: Returns version number
-           (including SVN revision number).
- Alias   :
- Returns : SCALAR
- Args    : NONE
- Comments:
-
-=cut
-
-    sub VERSION { $VERSION }
-
-=begin comment
-
-Invocant destructor.
-
- Type    : Destructor
- Title   : DESTROY
- Usage   : $phylo->DESTROY
- Function: Destroys Phylo object
- Alias   :
- Returns : TRUE
- Args    : none
- Comments: You don't really need this,
-           it is called automatically when
-           the object goes out of scope.
-
-=end comment
-
-=cut
-
-    {
-        no warnings 'recursion';
-        my %isa_for_class;
-
-        sub DESTROY {
-            my $self = shift;
-
-            # delete from get_obj_by_id
-            my $id;
-            if ( defined( $id = $self->get_id ) ) {
-                delete $objects{$id};
-            }
-
-            # build full @ISA from child to here
-            my $class = ref $self;
-            my $isa;
-            unless ( $isa = $isa_for_class{$class} ) {
-                $isa = [];
-                my $seen = {};
-                _recurse_isa( $class, $isa, $seen );
-                $isa_for_class{$class} = $isa;
-            }
-
-          # call *all* _cleanup methods, wouldn't work if simply SUPER::_cleanup
-          # given multiple inheritance
-            {
-                no strict 'refs';
-                for my $SUPER ( @{$isa} ) {
-                    if ( $SUPER->can('_cleanup') ) {
-                        my $cleanup = "${SUPER}::_cleanup";
-                        $self->$cleanup;
-                    }
-                }
-                use strict;
-            }
-
-            #$logger->debug("done cleaning up '$self'"); # XXX
-            # cleanup from mediator
-            $taxamediator->unregister($self);
-
-            # done cleaning up, id can be reclaimed
-            Bio::Phylo::Util::IDPool->_reclaim($self);
-        }
-    }
-
-    # starting from $class, push all superclasses (+$class) into @$isa,
-    # %$seen is just a helper to avoid getting stuck in cycles
-    sub _recurse_isa {
-        my ( $class, $isa, $seen ) = @_;
-        if ( not $seen->{$class} ) {
-            $seen->{$class} = 1;
-            push @{$isa}, $class;
-            my @isa;
-            {
-                no strict 'refs';
-                @isa = @{"${class}::ISA"};
-                use strict;
-            }
-            _recurse_isa( $_, $isa, $seen ) for @isa;
-        }
-    }
-
-    # child classes probably should have a method like this,
-    # if their objects hold internal state anyway (b/c they'll
-    # be inside-out objects).
-    sub _cleanup {
-        my $self = shift;
-
-        #$logger->debug("cleaning up '$self'"); # XXX
-        my $id = $self->get_id;
-
-        # cleanup local fields
-        if ( defined $id ) {
-            for my $field (@fields) {
-                delete $field->{$id};
-            }
-        }
-    }
-
-=begin comment
-
- Type    : Internal method
- Title   : _get_container
- Usage   : $phylo->_get_container;
- Function: Retrieves the object that contains the invocant (e.g. for a node,
-           returns the tree it is in).
- Returns : Bio::Phylo::* object
- Args    : None
-
-=end comment
-
-=cut
-
-    # this is the converse of $listable->get_entities, i.e.
-    # every entity in a listable object holds a reference
-    # to its container. We actually use this surprisingly
-    # rarely, and because I read somewhere (heh) it's bad
-    # to have the objects of a has-a relationship fiddle with
-    # their container we hide this method from abuse. Then
-    # again, sometimes it's handy ;-)
-    sub _get_container {
-        my $self = shift;
-        return $container{ $self->get_id };
-    }
-
-=begin comment
-
- Type    : Internal method
- Title   : _set_container
- Usage   : $phylo->_set_container($obj);
- Function: Creates a reference from the invocant to the object that contains
-           it (e.g. for a node, creates a reference to the tree it is in).
- Returns : Bio::Phylo::* object
- Args    : A Bio::Phylo::Listable object
-
-=end comment
-
-=cut
-
-    sub _set_container {
-        my ( $self, $container ) = @_;
-        my $id = $self->get_id;
-        if ( blessed $container ) {
-            if ( $container->can('can_contain') ) {
-                if ( $container->can_contain($self) ) {
-                    if ( $container->contains($self) ) {
-                        $container{$id} = $container;
-                        weaken( $container{$id} );
-                        return $self;
-                    }
-                    else {
-                        throw 'ObjectMismatch' => "'$self' not in '$container'";
-                    }
-                }
-                else {
-                    throw 'ObjectMismatch' =>
-                      "'$container' cannot contain '$self'";
-                }
-            }
-            else {
-                throw 'ObjectMismatch' => "Invalid objects";
-            }
-        }
-        else {
-            throw 'BadArgs' => "Argument not an object";
-        }
-    }
-
 =back
 
 =head1 SEE ALSO
@@ -1001,5 +252,4 @@ L<http://dx.doi.org/10.1186/1471-2105-12-63>
 
 =cut
 
-}
 1;
@@ -126,6 +126,7 @@ ok( $trees[3]->get_root->get_name eq 'root', '73 reroot tree' );
     my $preterminal = $tree->get_by_name('n1');
     ok( $preterminal->is_preterminal, '75 is preterminal' );
 }
+=pod
 {
     my $newick =
       '(H:1,(G:1,(F:1,(E:1,(D:1,(C:1,(A:1,B:1):1):1):1)sub:1):1):1):0;';
@@ -137,6 +138,7 @@ ok( $trees[3]->get_root->get_name eq 'root', '73 reroot tree' );
       parse( '-format' => 'newick', '-string' => $subnewick )->first;
     ok( $subtree1->calc_symdiff($subtree2) == 0, '76 clone subtree' );
 }
+=cut
 is($node->get_mrca($node), $node);
 is($node->calc_patristic_distance($node), 0);
 is($node->calc_nodal_distance($node), 0);
@@ -1,41 +1,52 @@
-# $Id: 19-svg.t 838 2009-03-04 20:47:20Z rvos $
+#!/usr/bin/perl
+use strict;
+use warnings;
 use Test::More;
+use Bio::Phylo::IO 'parse';
 
 BEGIN {
     eval { require SVG };
     if ($@) {
         plan 'skip_all' => 'SVG not installed';
-    }
-    else {
-        plan 'tests' => 13;
+        done_testing();
     }
 }
-use strict;
-use lib 'lib/';
-use Bio::Phylo::IO;
-require Bio::Phylo::Treedrawer;
+
+# test if the module can be loaded
+BEGIN {
+	use_ok('Bio::Phylo::Treedrawer');
+}
+
+# test if the drawer can be instantiated
+my $treedrawer = new_ok('Bio::Phylo::Treedrawer');
+
+# parse a tree object
 my $tree = Bio::Phylo::IO->parse(
-    -format => 'newick',
-    -string => '((A:1,B:1)n1:1,C:1)n2:0;'
+    '-format' => 'newick',
+    '-string' => '((A:1,B:1)n1:1,C:1)n2:0;'
 )->first;
-my $treedrawer = Bio::Phylo::Treedrawer->new;
-ok( $treedrawer->set_width(400),            'test 1' );
-ok( $treedrawer->set_height(600),           'test 2' );
-ok( $treedrawer->set_mode('clado'),         'test 3' );
-ok( $treedrawer->set_shape('curvy'),        'test 4' );
-ok( $treedrawer->set_padding(50),           'test 5' );
-ok( $treedrawer->set_node_radius(0),        'test 6' );
-ok( $treedrawer->set_text_horiz_offset(10), 'test 7' );
-ok( $treedrawer->set_text_vert_offset(3),   'test 8' );
-ok( $treedrawer->set_text_width(150),       'test 9' );
-ok( $treedrawer->set_tree($tree),           'test 10' );
-ok( $treedrawer->set_format('svg'),         'test 11' );
+
+# test basic drawer setters
+ok( $treedrawer->set_width(400),            'set width' );
+ok( $treedrawer->set_height(600),           'set height' );
+ok( $treedrawer->set_mode('clado'),         'set mode to clado' );
+ok( $treedrawer->set_shape('curvy'),        'set shape to curvy' );
+ok( $treedrawer->set_padding(50),           'set padding' );
+ok( $treedrawer->set_node_radius(0),        'set node radius' );
+ok( $treedrawer->set_text_horiz_offset(10), 'set text horiz offset' );
+ok( $treedrawer->set_text_vert_offset(3),   'set text vert offset' );
+ok( $treedrawer->set_text_width(150),       'set text width' );
+ok( $treedrawer->set_tree($tree),           'set tree' );
+ok( $treedrawer->set_format('svg'),         'set out format' );
 ok(
     $treedrawer->set_scale_options(
-        -width => '100%',
-        -minor => '2%',
-        -major => '10%'
+        '-width' => '100%',
+        '-minor' => '2%',
+        '-major' => '10%'
     ),
-    'test 12'
+    'set scale options'
 );
-ok( $treedrawer->draw, 'test 13' );
+
+# test drawing 
+ok( $treedrawer->draw, 'draw' );
+done_testing();
\ No newline at end of file
@@ -1,3 +1,4 @@
+#!/usr/bin/perl
 use Test::More;
 
 BEGIN {
@@ -18,8 +19,9 @@ use Bio::Phylo::IO qw'parse unparse';
 use Bio::Phylo::Util::Logger;
 use Data::Dumper;
 use Bio::Phylo::Factory;
+
 my $fac = Bio::Phylo::Factory->new;
-my $XML_PATH = $ENV{'NEXML_ROOT'} . '/examples' || '../examples';    # TODO fixme
+my $XML_PATH = $ENV{'NEXML_ROOT'} . '/examples';
 
 # here we just parse a file with only taxon elements
 my $taxa = parse( '-format' => 'nexml', '-file' => "$XML_PATH/taxa.xml" )->[0];
@@ -1,18 +1,15 @@
-# $Id: 19-svg.t 838 2009-03-04 20:47:20Z rvos $
+#!/usr/bin/perl
 use Test::More 'no_plan';
 use strict;
 use Bio::Phylo::IO 'parse';
 use Bio::Phylo::Treedrawer;
 use Bio::Phylo::Util::Logger ':levels';
-use Bio::Phylo::Factory;
-my $factory = Bio::Phylo::Factory->new;
-$factory->register_class( 'tree' => 'Bio::Phylo::Forest::DrawTree' );
-$factory->register_class( 'node' => 'Bio::Phylo::Forest::DrawNode' );
+
 my $tree = parse(
     -format  => 'newick',
     -string  => do { local $/; <DATA> },
-    -factory => $factory
 )->first;
+
 $tree->visit(
     sub {
         my $node = shift;
@@ -27,12 +24,12 @@ $tree->visit(
     }
 );
 my $treedrawer = Bio::Phylo::Treedrawer->new(
-    -width       => 800,
-    -height      => 600,
-    -shape       => 'RECT',         # curvogram
-    -mode        => 'PHYLO',        # phylogram
-    -format      => 'Processing',
-    -node_radius => 40,
+    '-width'       => 800,
+    '-height'      => 600,
+    '-shape'       => 'RECT',         # curvogram
+    '-mode'        => 'PHYLO',        # phylogram
+    '-format'      => 'Processing',
+    '-node_radius' => 40,
 );
 $treedrawer->set_tree($tree);
 ok( $treedrawer->draw );
@@ -1,3 +1,4 @@
+#!/usr/bin/perl
 use Test::More 'no_plan';
 use strict;
 use Bio::Phylo;
@@ -37,8 +38,11 @@ my $fac = Bio::Phylo::Factory->new;
         $taxa->insert($taxon);
         ( $taxon_id, $taxa_id ) = ( $taxon->get_id, $taxa->get_id );
     }
-    ok( ! Bio::Phylo->get_obj_by_id($taxon_id), 'test taxon in taxa destruction' );
-    ok( ! Bio::Phylo->get_obj_by_id($taxa_id), 'test taxon in taxa destruction' );
+SKIP: {
+	skip "please fix cyclical references in objects contained by Listables", 1, 1;
+	ok( ! Bio::Phylo->get_obj_by_id($taxon_id), 'test contained taxon in taxa destruction' );
+}
+    ok( ! Bio::Phylo->get_obj_by_id($taxa_id), 'test container taxa destruction' );
 }
 
 # test node destruction
@@ -70,8 +74,11 @@ my $fac = Bio::Phylo::Factory->new;
         $tree->insert($node);
         ( $node_id, $tree_id ) = ( $node->get_id, $tree->get_id );
     }
-    ok( ! Bio::Phylo->get_obj_by_id($node_id), 'test node in tree destruction' );
-    ok( ! Bio::Phylo->get_obj_by_id($tree_id), 'test node in tree destruction' );
+SKIP: {
+	skip "please fix cyclical references in objects contained by Listables", 1, 1;    
+    ok( ! Bio::Phylo->get_obj_by_id($node_id), 'test contained node in tree destruction' );
+}
+    ok( ! Bio::Phylo->get_obj_by_id($tree_id), 'test container tree destruction' );
 }
 
 # test nodes in tree destruction
@@ -85,8 +92,11 @@ my $fac = Bio::Phylo::Factory->new;
         $tree->insert($child,$parent);
         ( $n1, $n2, $t ) = ( $child->get_id, $parent->get_id, $tree->get_id );
     }
+SKIP: {
+	skip "please fix cyclical references in objects contained by Listables", 2, 1;    
     ok( ! Bio::Phylo->get_obj_by_id($n1), 'test nodes in tree destruction' );
     ok( ! Bio::Phylo->get_obj_by_id($n2), 'test nodes in tree destruction' );
+}
     ok( ! Bio::Phylo->get_obj_by_id($t), 'test nodes in tree destruction' );
 }
 
@@ -119,8 +129,11 @@ my $fac = Bio::Phylo::Factory->new;
         $matrix->insert($datum);
         ( $m, $d ) = ( $matrix->get_id, $datum->get_id );
     }
-    ok( ! Bio::Phylo->get_obj_by_id($m), 'test datum in matrix destruction' );
-    ok( ! Bio::Phylo->get_obj_by_id($d), 'test datum in matrix destruction' );
+    ok( ! Bio::Phylo->get_obj_by_id($m), 'test container matrix destruction' );
+SKIP: {
+	skip "please fix cyclical references in objects contained by Listables", 1, 1;    
+    ok( ! Bio::Phylo->get_obj_by_id($d), 'test contained datum in matrix destruction' );
+}
 }
 
 # test entire project
@@ -145,10 +158,13 @@ my $fac = Bio::Phylo::Factory->new;
         $ids{$proj->get_id} = ref $proj;
         for my $id ( sort { $a <=> $b } keys %ids ) {
             ok( ref Bio::Phylo->get_obj_by_id($id) eq $ids{$id}, "Found $ids{$id} $id" );
-        }        
+        }      
     }
     for my $id ( sort { $a <=> $b } keys %ids ) {
-        ok( ! Bio::Phylo->get_obj_by_id($id), "$ids{$id} $id has been destroyed" );
+SKIP: {
+	skip "please fix cyclical references in objects contained by Listables", 1, 1;   
+    ok( ! Bio::Phylo->get_obj_by_id($id), "$ids{$id} $id has been destroyed" );
+}
     }
 }
 
@@ -0,0 +1,99 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More 'no_plan';
+use Bio::Phylo::Factory;
+use Bio::Phylo::Taxa::Taxon;
+use Bio::Phylo::Forest::Node;
+use Bio::Phylo::Forest::Tree;
+use Bio::Phylo::Matrices::Matrix;
+
+my $fac = Bio::Phylo::Factory->new;
+
+# clone a node
+{    
+    my $node = $fac->create_node( '-branch_length' => 1 );
+    my $clone = $node->clone;
+    ok( $clone->get_branch_length == $node->get_branch_length, "copied node property" );
+}
+
+# clone a tree  
+{
+    my $tree = $fac->create_tree;
+    $tree->set_as_unrooted;
+    $tree->set_as_default;
+    my $clone = $tree->clone;
+    ok( $clone->is_default == $tree->is_default, "copied default flag" );
+    ok( $clone->is_rooted  == $tree->is_rooted, "copied rootedness" );
+}
+
+# clone a taxon    
+{
+    my $taxon = $fac->create_taxon(
+	'-name'     => 'foo',
+	'-xml_id'   => 'bar',
+	'-tag'      => 'baz',
+	'-base_uri' => 'urn:example.org:taxon',
+	'-link'     => 'http://example.org/taxon',
+	'-identifiable' => 1,
+	'-suppress_ns'  => 1,
+    );
+    my $clone = $taxon->clone;
+    ok( $clone->get_name eq $taxon->get_name, "copied XML label" );
+    ok( $clone->get_xml_id ne $taxon->get_xml_id, "NOT copied XML ID" );
+    ok( $clone->get_tag eq $taxon->get_tag, "copied XML tag" );
+    ok( $clone->get_base_uri eq $taxon->get_base_uri, "copied base URI" );
+    ok( $clone->get_link eq $taxon->get_link, "copied link" );
+    ok( $clone->is_identifiable == $taxon->is_identifiable, "copied identifiability" );
+    ok( $clone->is_ns_suppressed == $taxon->is_ns_suppressed, "copied NS suppression" );
+}
+
+# test recursive deep cloning
+{    
+    my $matrix = $fac->create_matrix( 
+	    '-type' => 'dna',
+	    '-raw'  => [ [ 'taxon1' => 'acgtcg' ], [ 'taxon2' => 'acgtcg' ] ],
+    );
+    my $taxa = $matrix->make_taxa;
+    $matrix->get_characters->set_name("MyChars");
+    my $shallow = $matrix->clone(0);
+    my $deep = $matrix->clone(1);
+    
+    # still the same reference
+    ok( $matrix->get_characters->get_id == $shallow->get_characters->get_id,
+       "shallow clone delegates to same reference" );
+    ok( $taxa->get_id == $shallow->get_taxa->get_id,
+       "shallow clone delegates to same reference");
+    
+    # characters and taxa were also cloned
+    ok( $matrix->get_characters->get_id != $deep->get_characters->get_id,
+       "deep clone delegates to different reference" );
+    
+    # this previously didn't work because the implicitly created taxa block
+    # was immediately unreachable so it was cleaned up. we now keep the
+    # pointer from matrix to taxa unweakened so this doesn't happen and the
+    # test passes.
+    ok( $taxa->get_id != $deep->get_taxa->get_id,
+       "deep clone delegates to different reference" );	
+    ok( $deep->get_taxa->get_ntax == 2, "same number of taxa" );
+    ok( $deep->get_taxa->first->get_id != $taxa->first->get_id, "different object IDs" );
+    ok( $shallow->get_taxa->first->get_id == $taxa->first->get_id, "same object IDs" );
+    
+    # test if properties were cloned
+    ok( $matrix->get_characters->get_name eq $shallow->get_characters->get_name,
+       "shallow clone has same delegated object properties");
+    ok( $matrix->get_characters->get_name eq $deep->get_characters->get_name,
+       "deep clone has copied object properties");
+}
+
+# test tree cloning
+{
+    my $tree = $fac->create_tree;
+    my $root = $fac->create_node( '-name' => 'root' );
+    $tree->insert($root);
+    my $clone = $tree->clone;
+    ok( $tree->get_id != $clone->get_id, "trivial tree cloning 1" );
+    ok( $tree->get_root->get_id != $clone->get_root->get_id, "trivial tree cloning 2");
+    ok( $tree->get_root->get_name eq $clone->get_root->get_name, "trivial tree cloning 3");
+    
+}
\ No newline at end of file
@@ -0,0 +1,26 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More 'no_plan';
+
+BEGIN {
+	use_ok('Bio::Phylo::Forest::DrawNodeRole');
+}
+
+my $node = new_ok('Bio::Phylo::Forest::DrawNodeRole');
+
+my @properties = qw(x y radius tip_radius node_color node_outline_color
+node_shape node_image branch_color branch_shape branch_width branch_style
+collapsed collapsed_width font_face font_size font_style font_color
+text_horiz_offset text_vert_offset rotation);
+
+for my $p ( @properties ) {
+	my $setter = "set_$p";
+	my $getter = "get_$p";
+	my $value = 'foo';
+	ok( $node->$setter($value), "set $p" );
+	ok( $node->$getter eq $value, "get $p returns $value" );
+}
+
+eval { $node->DOES_NOT_EXIST };
+ok( $@ =~ /Can't locate object method "DOES_NOT_EXIST"/ );
\ No newline at end of file
@@ -0,0 +1,27 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+use Test::More 'no_plan';
+
+BEGIN {
+	use_ok('Bio::Phylo::Forest::DrawTreeRole');
+}
+
+my $tree = new_ok('Bio::Phylo::Forest::DrawTreeRole');
+
+my @properties = qw(width height node_radius tip_radius node_color node_shape
+node_image branch_color branch_shape branch_width branch_style collapsed_width
+font_face font_size font_style margin margin_top margin_bottom margin_left 
+margin_right padding padding_top padding_bottom padding_left padding_right
+mode shape text_horiz_offset text_vert_offset);
+
+for my $p ( @properties ) {
+	my $setter = "set_$p";
+	my $getter = "get_$p";
+	my $value = 'CLADO';
+	ok( $tree->$setter($value), "set $p" );
+	ok( $tree->$getter eq $value, "get $p returns $value" );
+}
+
+eval { $tree->DOES_NOT_EXIST };
+ok( $@ =~ /Can't locate object method "DOES_NOT_EXIST"/ );
\ No newline at end of file