[med-svn] [brig] 01/02: Imported Upstream version 0.95+dfsg

Andreas Tille tille at debian.org
Fri Nov 27 07:42:43 UTC 2015


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository brig.

commit a8e67907222cde49e0a454d265fd5be729b21586
Author: Andreas Tille <tille at debian.org>
Date:   Fri Nov 27 08:41:06 2015 +0100

    Imported Upstream version 0.95+dfsg
---
 COPYING.txt                                        |  674 ++++
 README.txt                                         |   56 +
 cgview/README                                      |  155 +
 cgview/ca/ualberta/stothard/cgview/Cgview.class    |  Bin 0 -> 41377 bytes
 .../ualberta/stothard/cgview/CgviewConstants.class |  Bin 0 -> 1621 bytes
 .../ualberta/stothard/cgview/CgviewFactory$1.class |  Bin 0 -> 1334 bytes
 .../ualberta/stothard/cgview/CgviewFactory$2.class |  Bin 0 -> 1336 bytes
 .../ualberta/stothard/cgview/CgviewFactory$3.class |  Bin 0 -> 1334 bytes
 .../ualberta/stothard/cgview/CgviewFactory$4.class |  Bin 0 -> 1336 bytes
 .../cgview/CgviewFactory$ElementDetails.class      |  Bin 0 -> 720 bytes
 .../ualberta/stothard/cgview/CgviewFactory.class   |  Bin 0 -> 57036 bytes
 .../stothard/cgview/CgviewFactoryPtt.class         |  Bin 0 -> 26400 bytes
 .../stothard/cgview/CgviewFactoryTab.class         |  Bin 0 -> 24352 bytes
 .../stothard/cgview/CgviewHTMLDocument.class       |  Bin 0 -> 9064 bytes
 cgview/ca/ualberta/stothard/cgview/CgviewIO.class  |  Bin 0 -> 33567 bytes
 .../cgview/Feature$SortFeatureRangesByStart.class  |  Bin 0 -> 798 bytes
 cgview/ca/ualberta/stothard/cgview/Feature.class   |  Bin 0 -> 4588 bytes
 .../ca/ualberta/stothard/cgview/FeatureRange.class |  Bin 0 -> 14055 bytes
 .../cgview/FeatureSlot$SortFeaturesByStart.class   |  Bin 0 -> 803 bytes
 .../ca/ualberta/stothard/cgview/FeatureSlot.class  |  Bin 0 -> 3778 bytes
 cgview/ca/ualberta/stothard/cgview/FileMover.class |  Bin 0 -> 2242 bytes
 .../ca/ualberta/stothard/cgview/InnerLabel.class   |  Bin 0 -> 6892 bytes
 cgview/ca/ualberta/stothard/cgview/Label.class     |  Bin 0 -> 6459 bytes
 .../ca/ualberta/stothard/cgview/LabelBounds.class  |  Bin 0 -> 1756 bytes
 cgview/ca/ualberta/stothard/cgview/Legend.class    |  Bin 0 -> 5861 bytes
 .../ca/ualberta/stothard/cgview/LegendItem.class   |  Bin 0 -> 4020 bytes
 .../ca/ualberta/stothard/cgview/OuterLabel.class   |  Bin 0 -> 7016 bytes
 cgview/ca/ualberta/stothard/cgview/Plasmid.class   |  Bin 0 -> 22469 bytes
 .../ca/ualberta/stothard/cgview/SeriesImage.class  |  Bin 0 -> 2362 bytes
 .../stothard/cgview/SortLabelsByForceLabel.class   |  Bin 0 -> 582 bytes
 .../stothard/cgview/SortLabelsByRadians.class      |  Bin 0 -> 589 bytes
 .../stothard/cgview/SortLabelsByRadiansShift.class |  Bin 0 -> 706 bytes
 .../stothard/cgview/SortLabelsByRadius.class       |  Bin 0 -> 844 bytes
 .../cgview/SortSeriesImageByZoomCenter.class       |  Bin 0 -> 603 bytes
 cgview/cgview_xml_builder/README                   |  284 ++
 cgview/cgview_xml_builder/cgview_xml_builder.pl    | 3757 ++++++++++++++++++++
 cgview/cgview_xml_builder/test.sh                  |   40 +
 cgview/includes/as_png.png                         |  Bin 0 -> 2825 bytes
 cgview/includes/as_svg.png                         |  Bin 0 -> 2859 bytes
 cgview/includes/expand_in.png                      |  Bin 0 -> 2733 bytes
 cgview/includes/expand_in_g.png                    |  Bin 0 -> 1329 bytes
 cgview/includes/expand_out.png                     |  Bin 0 -> 2588 bytes
 cgview/includes/expand_out_g.png                   |  Bin 0 -> 1271 bytes
 cgview/includes/full.png                           |  Bin 0 -> 2565 bytes
 cgview/includes/full_g.png                         |  Bin 0 -> 1283 bytes
 cgview/includes/help.html                          |  153 +
 cgview/includes/help.png                           |  Bin 0 -> 875 bytes
 cgview/includes/help_png.html                      |  135 +
 cgview/includes/info.js                            |   73 +
 cgview/includes/move_back.png                      |  Bin 0 -> 2375 bytes
 cgview/includes/move_back_g.png                    |  Bin 0 -> 1207 bytes
 cgview/includes/move_forward.png                   |  Bin 0 -> 2546 bytes
 cgview/includes/move_forward_g.png                 |  Bin 0 -> 1256 bytes
 cgview/includes/overlib.js                         | 1491 ++++++++
 cgview/includes/stylesheet.css                     |   19 +
 cgview/manifestinfo                                |    6 +
 .../src/ca/ualberta/stothard/cgview/Cgview.class   |  Bin 0 -> 41371 bytes
 cgview/src/ca/ualberta/stothard/cgview/Cgview.java | 3693 +++++++++++++++++++
 .../ualberta/stothard/cgview/CgviewConstants.class |  Bin 0 -> 1621 bytes
 .../ualberta/stothard/cgview/CgviewConstants.java  |  208 ++
 .../ualberta/stothard/cgview/CgviewFactory$1.class |  Bin 0 -> 1334 bytes
 .../ualberta/stothard/cgview/CgviewFactory$2.class |  Bin 0 -> 1336 bytes
 .../ualberta/stothard/cgview/CgviewFactory$3.class |  Bin 0 -> 1334 bytes
 .../ualberta/stothard/cgview/CgviewFactory$4.class |  Bin 0 -> 1336 bytes
 .../cgview/CgviewFactory$ElementDetails.class      |  Bin 0 -> 720 bytes
 .../ualberta/stothard/cgview/CgviewFactory.class   |  Bin 0 -> 57036 bytes
 .../ca/ualberta/stothard/cgview/CgviewFactory.java | 2847 +++++++++++++++
 .../stothard/cgview/CgviewFactoryPtt.class         |  Bin 0 -> 26400 bytes
 .../ualberta/stothard/cgview/CgviewFactoryPtt.java | 1534 ++++++++
 .../stothard/cgview/CgviewFactoryTab.class         |  Bin 0 -> 24352 bytes
 .../ualberta/stothard/cgview/CgviewFactoryTab.java | 1407 ++++++++
 .../stothard/cgview/CgviewHTMLDocument.class       |  Bin 0 -> 9064 bytes
 .../stothard/cgview/CgviewHTMLDocument.java        |  370 ++
 .../src/ca/ualberta/stothard/cgview/CgviewIO.class |  Bin 0 -> 33567 bytes
 .../src/ca/ualberta/stothard/cgview/CgviewIO.java  | 1713 +++++++++
 .../cgview/Feature$SortFeatureRangesByStart.class  |  Bin 0 -> 798 bytes
 .../src/ca/ualberta/stothard/cgview/Feature.class  |  Bin 0 -> 4588 bytes
 .../src/ca/ualberta/stothard/cgview/Feature.java   |  461 +++
 .../ca/ualberta/stothard/cgview/FeatureRange.class |  Bin 0 -> 14055 bytes
 .../ca/ualberta/stothard/cgview/FeatureRange.java  | 1205 +++++++
 .../cgview/FeatureSlot$SortFeaturesByStart.class   |  Bin 0 -> 803 bytes
 .../ca/ualberta/stothard/cgview/FeatureSlot.class  |  Bin 0 -> 3778 bytes
 .../ca/ualberta/stothard/cgview/FeatureSlot.java   |  322 ++
 .../ca/ualberta/stothard/cgview/FileMover.class    |  Bin 0 -> 2242 bytes
 .../src/ca/ualberta/stothard/cgview/FileMover.java |   61 +
 .../ca/ualberta/stothard/cgview/InnerLabel.class   |  Bin 0 -> 6892 bytes
 .../ca/ualberta/stothard/cgview/InnerLabel.java    |  462 +++
 cgview/src/ca/ualberta/stothard/cgview/Label.class |  Bin 0 -> 6459 bytes
 cgview/src/ca/ualberta/stothard/cgview/Label.java  |  498 +++
 .../ca/ualberta/stothard/cgview/LabelBounds.class  |  Bin 0 -> 1756 bytes
 .../ca/ualberta/stothard/cgview/LabelBounds.java   |  161 +
 .../src/ca/ualberta/stothard/cgview/Legend.class   |  Bin 0 -> 5861 bytes
 cgview/src/ca/ualberta/stothard/cgview/Legend.java |  447 +++
 .../ca/ualberta/stothard/cgview/LegendItem.class   |  Bin 0 -> 4020 bytes
 .../ca/ualberta/stothard/cgview/LegendItem.java    |  290 ++
 .../ca/ualberta/stothard/cgview/OuterLabel.class   |  Bin 0 -> 7016 bytes
 .../ca/ualberta/stothard/cgview/OuterLabel.java    |  455 +++
 .../src/ca/ualberta/stothard/cgview/Plasmid.class  |  Bin 0 -> 22469 bytes
 .../src/ca/ualberta/stothard/cgview/Plasmid.java   | 1237 +++++++
 .../ca/ualberta/stothard/cgview/SeriesImage.class  |  Bin 0 -> 2362 bytes
 .../ca/ualberta/stothard/cgview/SeriesImage.java   |  194 +
 .../stothard/cgview/SortLabelsByForceLabel.class   |  Bin 0 -> 582 bytes
 .../stothard/cgview/SortLabelsByForceLabel.java    |   26 +
 .../stothard/cgview/SortLabelsByRadians.class      |  Bin 0 -> 589 bytes
 .../stothard/cgview/SortLabelsByRadians.java       |   26 +
 .../stothard/cgview/SortLabelsByRadiansShift.class |  Bin 0 -> 706 bytes
 .../stothard/cgview/SortLabelsByRadiansShift.java  |   27 +
 .../stothard/cgview/SortLabelsByRadius.class       |  Bin 0 -> 844 bytes
 .../stothard/cgview/SortLabelsByRadius.java        |   44 +
 .../cgview/SortSeriesImageByZoomCenter.class       |  Bin 0 -> 603 bytes
 .../cgview/SortSeriesImageByZoomCenter.java        |   26 +
 .../ualberta/stothard/cgview/includes/as_png.png   |  Bin 0 -> 2825 bytes
 .../ualberta/stothard/cgview/includes/as_svg.png   |  Bin 0 -> 2859 bytes
 .../stothard/cgview/includes/expand_in.png         |  Bin 0 -> 2733 bytes
 .../stothard/cgview/includes/expand_in_g.png       |  Bin 0 -> 1329 bytes
 .../stothard/cgview/includes/expand_out.png        |  Bin 0 -> 2588 bytes
 .../stothard/cgview/includes/expand_out_g.png      |  Bin 0 -> 1271 bytes
 .../ca/ualberta/stothard/cgview/includes/full.png  |  Bin 0 -> 2565 bytes
 .../ualberta/stothard/cgview/includes/full_g.png   |  Bin 0 -> 1283 bytes
 .../ca/ualberta/stothard/cgview/includes/help.html |  153 +
 .../ca/ualberta/stothard/cgview/includes/help.png  |  Bin 0 -> 875 bytes
 .../stothard/cgview/includes/help_png.html         |  135 +
 .../ca/ualberta/stothard/cgview/includes/info.js   |   73 +
 .../stothard/cgview/includes/move_back.png         |  Bin 0 -> 2375 bytes
 .../stothard/cgview/includes/move_back_g.png       |  Bin 0 -> 1207 bytes
 .../stothard/cgview/includes/move_forward.png      |  Bin 0 -> 2546 bytes
 .../stothard/cgview/includes/move_forward_g.png    |  Bin 0 -> 1256 bytes
 .../ualberta/stothard/cgview/includes/overlib.js   | 1491 ++++++++
 .../stothard/cgview/includes/stylesheet.css        |   19 +
 default-BRIG.xml                                   |    8 +
 errorlog.xml                                       |  760 ++++
 profiles/Eight_rings.xml                           |    8 +
 profiles/Eight_rings.xml.jpg                       |  Bin 0 -> 29816 bytes
 profiles/Fifteen_rings.xml                         |    8 +
 profiles/Fifteen_rings.xml.jpg                     |  Bin 0 -> 26520 bytes
 profiles/Five_rings.xml                            |    8 +
 profiles/Five_rings.xml.jpg                        |  Bin 0 -> 23307 bytes
 profiles/Four_rings.xml                            |    8 +
 profiles/Four_rings.xml.jpg                        |  Bin 0 -> 23267 bytes
 profiles/Nine_rings.xml                            |    8 +
 profiles/Nine_rings.xml.jpg                        |  Bin 0 -> 32404 bytes
 profiles/One_ring.xml                              |    8 +
 profiles/One_ring.xml.jpg                          |  Bin 0 -> 16567 bytes
 profiles/Seven_rings.xml                           |    8 +
 profiles/Seven_rings.xml.jpg                       |  Bin 0 -> 28343 bytes
 profiles/Six_rings.xml                             |    8 +
 profiles/Six_rings.xml.jpg                         |  Bin 0 -> 25356 bytes
 profiles/Ten_rings.xml                             |    8 +
 profiles/Ten_rings.xml.jpg                         |  Bin 0 -> 32454 bytes
 profiles/Three_rings.xml                           |    8 +
 profiles/Three_rings.xml.jpg                       |  Bin 0 -> 21682 bytes
 profiles/Twenty_rings.xml                          |    8 +
 profiles/Twenty_rings.xml.jpg                      |  Bin 0 -> 24743 bytes
 profiles/Two_ring.xml                              |    8 +
 profiles/Two_rings.xml                             |    8 +
 profiles/Two_rings.xml.jpg                         |  Bin 0 -> 20567 bytes
 proteins.txt                                       |   64 +
 157 files changed, 27364 insertions(+)

diff --git a/COPYING.txt b/COPYING.txt
new file mode 100644
index 0000000..20d40b6
--- /dev/null
+++ b/COPYING.txt
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+  To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  You must make sure that they, too, receive
+or can get the source code.  And you must show them these terms so they
+know their rights.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+  Each version is given a distinguishing version number.  If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software: you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation, either version 3 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU General Public License does not permit incorporating your program
+into proprietary programs.  If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
\ No newline at end of file
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..6a60a9e
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,56 @@
+Copyright Nabil Alikhan 2010-2011.
+BRIG is a cross-platform (Windows/Mac/Unix) application that can display circular 
+comparisons between a large number of genomes, with a focus on handling genome 
+assembly data.
+
+MAJOR FEATURES:
+* Images show similarity between a central reference sequence and other sequences
+  as concentric rings.
+* BRIG will perform all BLAST comparisons and file parsing automatically via a
+  simple GUI.
+* Contig boundaries and read coverage can be displayed for draft genomes; 
+  customized graphs and annotations can be displayed.
+• Using a user-defined set of genes as input, BRIG can display gene presence, 
+  absence, truncation or sequence variation in a set of complete genomes, 
+  draft genomes or even raw, unassembled sequence data.
+* BRIG also accepts SAM-formatted read-mapping files enabling genomic regions 
+  present in unassembled sequence data from multiple samples to be compared 
+  simultaneously
+
+Available @ http://sourceforge.net/projects/brig/
+
+
+CHANGE-LOG
+Version 0.95
+*    Added SVG support
+*    Added .fa & .fasta as default fasta extentions.
+*    Changed 'Covert graph' module to use 454-Allcontigs.fna produced by Newbler.
+*	Contig mapping now accepts multi-FASTA as query.
+*	Improved graph modules to work better with BLAST+.
+*	Fixed errors loading custom annotations from tab-delimited files 
+	made by Microsoft Excel
+*	Fixed sorting error for showing red/blue boundaries in graphs
+*	Users can load boundaries in Multi-FASTA files in custom annotations
+	(selecting colour as alternating red/blue)
+*	Users can load individual files into data pool.
+
+INSTALLATION
+You require:
+* Java 1.6 or greater installed.
+* NCBI BLAST+ or BLAST legacy installed.
+
+To run it you need to:
+1.   Unzip BRIG-x.xx-dist.zip to a desired location
+2.   Run BRIG.jar
+
+LICENCE
+This program is free software: you can redistribute it and/or modify it under the terms 
+of the GNU General Public License as published by the Free Software Foundation, either
+version 3 of the License, or (at your option) any later version.
+
+This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
+PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with this 
+program.  If not, see <http://www.gnu.org/licenses/>.
diff --git a/cgview/README b/cgview/README
new file mode 100644
index 0000000..5d33c98
--- /dev/null
+++ b/cgview/README
@@ -0,0 +1,155 @@
+CGView - Circular Genome Viewer
+
+See the following link for full documentation:
+
+http://wishart.biology.ualberta.ca/cgview/
+
+Copyright (C) 2004 Paul Stothard
+
+Please cite the following paper:
+
+Stothard P, Wishart DS. Circular genome visualization and exploration
+using CGView. Bioinformatics. 21:537-539.
+
+This program is free software; you can redistribute it and/or it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 2 of the License, or (at your
+option) any later version.
+
+This program is distributed in the hope that it will be useful, but
+WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
+USA.
+
+Paul Stothard can be reached by email: stothard at ualberta.ca
+
+----------------------------------------------------------- 
+To test CGView, switch to the cgview directory. Try the following
+command, which generates a PNG image of the map described in the
+cybercell.xml file:
+
+>java -jar cgview.jar -i cybercell.xml -o cybercell.png -f png
+----------------------------------------------------------- 
+Running CGView:
+
+usage: java -jar cgview.jar [options]
+
+Where the options are:
+
+-A <integer> Specifies the label font size to use. This value
+overrides CGView's default label font size and label font size values
+specified in XML input.
+
+-c <integer> Specifies the base to center on when
+zooming. Optional. Default value is 1.
+
+-D <integer> Specifies the legend font size to use. This value
+overrides CGView's default legend font size and legend font size
+values specified in XML input.
+
+-d <real> A value between 0 and 1 that controls the density of tick
+marks. Use 0 for no tick marks or 1 for the default level of tick
+marks. Optional. Default value is 1.
+
+-E <boolean> Whether or not to include text as vector-based objects in
+SVG output. Optional. Default value is true.
+
+-e <boolean> Whether or not to exclude SVG output when generating a
+series of linked images using the -s option. Optional. Default value
+is false.
+
+-f <format> The format of the output: PNG, JPG, SVG, or
+SVGZ. Optional. Default value is PNG.
+
+-h <file>. HTML file to create. Optional. Default value is null.
+
+-H <integer>. The height of the map. This value overrides any value
+specified in the input file. Optional. Default value is set in the
+input file or by CGView.
+
+-i <file> The input file to parse. Required.
+
+-I <boolean> Whether or not to draw labels on the inside of the
+ backbone circle. Optional. Default is to draw labels on the inside
+ when a zoomed map is drawn.
+
+-L <integer> Specifies the width of a separate legend to use as the
+legend in HTML output. Optional. Default value is null. If generating
+a linked map series, place a file called legend.png in the includes
+directory that is created. If generating a single HTML file, place a
+file called legend.png into the same directory as the HTML file. When
+the map is rendered, the legend.png image is placed to the right of
+the map.
+
+-o <file> The image file to create. Required, unless -s used to
+specify that an image series is to be written to a directory. An image
+series is made up of PNG and SVG images.
+
+-p <path> The path to the image file in the HTML file created using
+the -h option. Optional. Default is the the value specified using the
+-o option.
+
+-r <boolean> Specifies whether or not legends should be
+hidden. Default value is F.
+
+-R <boolean> Specifies whether or not labels should be hidden. Default
+value is F.
+
+-s <directory> Empty directory to receive an image series. If this
+option is used, a series of zoomed views of the map is generated, and
+values for -c, -f, -h, -o, -p, -u, and -z are
+ignored. Optional. Default value is null.
+
+-S <boolean> Whether or not to reference external stylesheet in HTML
+output. Optional. Default value is false. Set to true automatically
+when -s option is used.
+
+-u <boolean> Whether or not to include calls to the overlib.js
+JavaScript library in HTML image maps for PNG and JPG
+images. Optional. Default value is true.
+
+-D <integer>  Specifies the ruler font size to use. This value
+overrides CGView's default ruler font size and ruler font size
+values specified in XML input.
+
+-W <integer>. The width of the map. This value overrides any value
+specified in the input file. Optional. Default value is set in the
+input file or by CGView.
+
+-x <zoom values>. Specifies the zoom values to be used when generating
+a series of linked maps using the -s option. The values are supplied
+as a comma separated list containing no spaces. The first value must
+be 1. Optional. Default value is 1,6,36.
+
+-z <floating point number> The factor to zoom in by. Optional. Default
+value is 1.0.
+
+Examples: 
+
+1. The command below will read an XML file called "cybercell.xml", and
+will generate a PNG image file called "my_picture.png". An HTML file
+called "view_image.html" will also be created. This HTML file will
+contain the "my_picture.png" image:
+
+java -jar cgview.jar -f png -i cybercell.xml -o my_picture.png -h
+view_image.html
+
+2. The command below will read an XML file called "cybercell.xml", and
+will generate a collection of linked images and HTML pages in the
+directory called "directory_for_series". The complete series can be
+explored by loading the file "index.html", which will be in the
+"directory_for_series" directory. Note that generating an image series
+can take more than an hour.
+
+java -jar cgview.jar -i cybercell.xml -s directory_for_series -x true
+
+Note: If you obtain an "Out of Memory" error when drawing a very large
+map, try increasing Java's heap size using the -Xmx option. For
+example, use the command: 
+
+java -jar -Xmx500m cgview.jar -i cybercell.xml -o cybercell.png -f png
diff --git a/cgview/ca/ualberta/stothard/cgview/Cgview.class b/cgview/ca/ualberta/stothard/cgview/Cgview.class
new file mode 100644
index 0000000..d369ca5
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/Cgview.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewConstants.class b/cgview/ca/ualberta/stothard/cgview/CgviewConstants.class
new file mode 100644
index 0000000..ed6d60b
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewConstants.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactory$1.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$1.class
new file mode 100644
index 0000000..5cd8b2e
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$1.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactory$2.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$2.class
new file mode 100644
index 0000000..4a00b0e
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$2.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactory$3.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$3.class
new file mode 100644
index 0000000..0820cb8
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$3.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactory$4.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$4.class
new file mode 100644
index 0000000..c0c99a9
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$4.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactory$ElementDetails.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$ElementDetails.class
new file mode 100644
index 0000000..af6e2f6
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactory$ElementDetails.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactory.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactory.class
new file mode 100644
index 0000000..3481424
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactory.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactoryPtt.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactoryPtt.class
new file mode 100644
index 0000000..a1f82bb
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactoryPtt.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewFactoryTab.class b/cgview/ca/ualberta/stothard/cgview/CgviewFactoryTab.class
new file mode 100644
index 0000000..69db822
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewFactoryTab.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewHTMLDocument.class b/cgview/ca/ualberta/stothard/cgview/CgviewHTMLDocument.class
new file mode 100644
index 0000000..4d86ddf
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewHTMLDocument.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/CgviewIO.class b/cgview/ca/ualberta/stothard/cgview/CgviewIO.class
new file mode 100644
index 0000000..fc46910
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/CgviewIO.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/Feature$SortFeatureRangesByStart.class b/cgview/ca/ualberta/stothard/cgview/Feature$SortFeatureRangesByStart.class
new file mode 100644
index 0000000..cc62b35
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/Feature$SortFeatureRangesByStart.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/Feature.class b/cgview/ca/ualberta/stothard/cgview/Feature.class
new file mode 100644
index 0000000..f123759
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/Feature.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/FeatureRange.class b/cgview/ca/ualberta/stothard/cgview/FeatureRange.class
new file mode 100644
index 0000000..47bbd76
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/FeatureRange.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/FeatureSlot$SortFeaturesByStart.class b/cgview/ca/ualberta/stothard/cgview/FeatureSlot$SortFeaturesByStart.class
new file mode 100644
index 0000000..5a85408
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/FeatureSlot$SortFeaturesByStart.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/FeatureSlot.class b/cgview/ca/ualberta/stothard/cgview/FeatureSlot.class
new file mode 100644
index 0000000..666b29c
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/FeatureSlot.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/FileMover.class b/cgview/ca/ualberta/stothard/cgview/FileMover.class
new file mode 100644
index 0000000..ae80500
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/FileMover.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/InnerLabel.class b/cgview/ca/ualberta/stothard/cgview/InnerLabel.class
new file mode 100644
index 0000000..43414c3
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/InnerLabel.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/Label.class b/cgview/ca/ualberta/stothard/cgview/Label.class
new file mode 100644
index 0000000..0e4fdb1
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/Label.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/LabelBounds.class b/cgview/ca/ualberta/stothard/cgview/LabelBounds.class
new file mode 100644
index 0000000..47b8073
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/LabelBounds.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/Legend.class b/cgview/ca/ualberta/stothard/cgview/Legend.class
new file mode 100644
index 0000000..8bc84f4
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/Legend.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/LegendItem.class b/cgview/ca/ualberta/stothard/cgview/LegendItem.class
new file mode 100644
index 0000000..c793d4c
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/LegendItem.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/OuterLabel.class b/cgview/ca/ualberta/stothard/cgview/OuterLabel.class
new file mode 100644
index 0000000..56980a5
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/OuterLabel.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/Plasmid.class b/cgview/ca/ualberta/stothard/cgview/Plasmid.class
new file mode 100644
index 0000000..eaa3ff2
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/Plasmid.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/SeriesImage.class b/cgview/ca/ualberta/stothard/cgview/SeriesImage.class
new file mode 100644
index 0000000..3dd15cb
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/SeriesImage.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.class b/cgview/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.class
new file mode 100644
index 0000000..4306929
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadians.class b/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadians.class
new file mode 100644
index 0000000..e4945b1
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadians.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.class b/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.class
new file mode 100644
index 0000000..1dcfff6
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadius.class b/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadius.class
new file mode 100644
index 0000000..e6e0093
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/SortLabelsByRadius.class differ
diff --git a/cgview/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.class b/cgview/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.class
new file mode 100644
index 0000000..a49121a
Binary files /dev/null and b/cgview/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.class differ
diff --git a/cgview/cgview_xml_builder/README b/cgview/cgview_xml_builder/README
new file mode 100644
index 0000000..c668f41
--- /dev/null
+++ b/cgview/cgview_xml_builder/README
@@ -0,0 +1,284 @@
+cgview_xml_builder.pl
+This script requires bioperl-1.4 or newer. 
+
+This script accepts a variety of input files pertaining to microbial
+genomes and generates an XML file for the CGView genome drawing
+program. There are several command line options for specifying which
+input files should be used, and for controlling which features should
+be drawn.
+
+The CGView software is available at:
+http://bioinformatics.org/cgview/download.html
+
+Stothard P, Wishart DS. Circular genome visualization and exploration
+using CGView. Bioinformatics. 21:537-539.
+
+To create a simple map, try the following:
+------------------------------------------
+
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -output R_denitrificans.xml -tick_density 0.7
+
+java -jar -Xmx1500m ../cgview.jar -i R_denitrificans.xml -o R_denitrificans.png -f png
+
+To create a more complex map, try the following:
+------------------------------------------------
+
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -output R_denitrificans_b.xml -orfs T -at_content T -at_skew T -genes sample_input/R_denitrificans.cogs
+
+java -jar -Xmx1500m ../cgview.jar -i R_denitrificans_b.xml -o R_denitrificans_b.png -f png
+
+
+Note:
+-----
+There are numerous options for displaying additional information on
+the maps created using this script. These options are described in
+detail below.
+
+If CGView runs out of memory (usually when an x-large map is drawn),
+increase the memory available to Java using '-Xmx' option. For
+example, try '-Xmx2000m'
+
+To see other examples, run the test.sh script. It may take more than
+an hour for all the examples to be created.
+
+To create smoother base composition plots, specify a larger sliding
+window value using the '-window' option in cgview_xml_builder.pl
+
+If the base composition plots appear to be comprised of lines, specify
+a smaller step value using the '-step' option in cgview_xml_builder.pl
+
+To reduce the number of tick marks, specify a smaller tick density
+value using the '-tick_density' option in cgview_xml_builder.pl
+
+
+Required command line parameters:
+---------------------------------
+
+-sequence - The microbial genome sequence in FASTA, EMBL, or GenBank
+format. [File]. Required.
+
+-output - The CGView XML file to create. [File]. Required.
+
+Optional command line parameters:
+---------------------------------
+#######Open reading frame options:
+#######---------------------------
+
+-reading_frames - Whether the positions of start and stop codons
+should be drawn. [T/F]. Default is F. Optional.
+
+-orfs - Whether open reading frames (ORFs) should be drawn, with each
+reading frame (1, 2, 3, -1, -2, -3) represented by a separate
+ring. [T/F]. Default is F. Optional.
+
+-combined_orfs - Whether open reading frames (ORFs) should be drawn,
+with each strand (forward, reverse) represented by a separate
+ring. [T/F]. Default is F. Optional.
+
+-orf_size - The minimum length of ORFs (in codons) to show when using
+the '-orfs' or '-combined_orfs' options. [Integer]. Default is
+100. Optional.
+
+-starts - The start codons to use when plotting open reading frames
+or stop and start codons. [String]. The default value is
+'atg|ttg|att|gtg|ctg'. Optional.
+
+-stops - The stop codons to use when plotting open reading frames or
+stop and start codons. [String]. The default value is
+'taa|tag|tga'. Optional.
+
+#######Base composition plot options:
+#######------------------------------
+
+-gc_content - Whether GC content should be shown. [T/F]. Default is
+T. Optional.
+
+-gc_skew - Whether GC skew should be shown. [T/F]. Default is
+F. Optional.
+
+-at_content - Whether AT content should be shown. [T/F]. Default is
+F. Optional.
+
+-at_skew - Whether AT skew should be shown. [T/F]. Default is
+F. Optional.
+
+-average - Whether the GC, GC skew, AT, and AT skew plots should show
+the deviation of each value from the average for the entire
+genome. The default method of plotting shows each value as
+calculated. Specifying "-average" allows plots to better show regions
+that differ from the rest of the genome, but the results cannot be
+easily compared between genomes. [T/F]. Default is T. Optional.
+
+-scale - Whether the GC, GC skew, AT, and AT skew plots should be
+scaled to fill the available Y-axis space on the map. This scaling
+allows differences to be observed more easily, but the results cannot
+be easily compared between genomes. [T/F]. Default is T. Optional.
+
+-step - The step value to use when generating the GC, GC skew, AT,
+and AT skew plots. This value should be decreased (to a minimum of 1)
+if in the final map the lines comprising the plots can be
+seen. [Integer]. Default is to let program choose step
+value. Optional.
+
+-window - The size of the sliding window for base composition
+plots. Using a larger window size gives smoother graphs, but may hide
+details. [Integer]. Default is to let program choose step
+value. Optional.
+
+#######Map appearance options:
+#######------------------------------
+
+-size - The size of the map. [small/medium/large/x-large]. Default is
+medium. Optional.
+
+-linear - Whether this genome is linear. Linear genomes are drawn as
+a circle with a line drawn between the start and end of the
+sequence. [T/F]. Default is to read this setting from the GenBank or
+EMBL file, if available, otherwise the value is set to F. Optional.
+
+-tick_density - The density of the tick marks on the map. Use a
+smaller value to make the ticks less dense. [Real between 0 and
+1]. Default is 0.5.
+
+-title - A title for the sequence, to appear on the
+map. [String]. Default is to obtain a title from the input sequence
+file (for FASTA, GenBank, and EMBL input). Optional.
+
+-details - Whether a sequence information legend should be
+drawn. [T/F]. Default is T. Optional.
+
+-legend - Whether a feature legend should be drawn. [T/F]. Default is
+T. Optional.
+
+-parse_reading_frame - Whether BLAST results should be split into
+separate feature rings on the map, based on the reading frame and
+strand of the query. Requires specially formatted BLAST
+results. [T/F]. Default is F. Optional.
+
+-show_queries - Whether faint boxes should be drawn to indicate the
+positions of the BLAST queries relative to the genome
+sequence. [T/F]. Default is F. Optional.
+
+-condensed - Whether thin feature rings should be used regardless of
+the size of the map. This option may be useful when numerous feature
+rings are drawn. [T/F]. Default is F. Optional.
+
+-feature_labels - Whether feature labels read from the GenBank or
+EMBL file should be drawn. [T/F]. Default is F. Optional.
+
+-gene_labels - Whether labels read using the '-genes' or
+'-expression' option should be drawn. [T/F]. Default is F. Optional.
+
+-hit_labels - Whether labels for BLAST hits read using the '-blast'
+option should be drawn. [T/F]. Default is F. Optional.
+
+-orf_labels - Whether labels for ORFs that are drawn using the
+'-orfs' or '-combined_orfs' should be shown. [T/F]. Default is
+F. Optional.
+
+-gene_decoration - Whether genes should be drawn as an arc or as an
+arrow. [String]. Default is 'arrow'.
+
+-global_label - Controls how drawing a zoomed map affects labels. Set
+to T to always show labels, F to always show no labels, or 'auto' to
+show labels when a zoomed map is drawn. When set to F, no labels are
+shown, regardless of the other label settings (-feature_labels,
+-gene_labels, -hit_labels, and -orf_labels). When set to T, labels are
+shown for those label settings that are set to T. When set to auto,
+labels are shown for those label settings that are T only when a
+zoomed map is drawn. [T/F/auto]. Default is T.
+
+-use_opacity - Whether BLAST hits should be drawn with partial opacity,
+so that overlapping hits can be visualized. [T/F]. Default is F.
+
+-show_sequence_features - Whether to draw features contained in the
+supplied '-sequence' file, if it is a GenBank or EMBL
+file. [T/F]. Default is T.
+
+-draw_divider_rings - Whether to draw divider rings between feature
+ rings. [T/F]. Default is F.
+
+#######Data source options:
+#######------------------------------
+
+-genes - One or more files containing gene position information for
+the genes in the genome. The file should be tab-delimited or
+comma-delimited and should have the following column titles, in the
+following order: 'seqname', 'source', 'feature', 'start', 'end',
+'score', 'strand', 'frame'. The first line in the file must be the
+column titles. For a given entry, 'seqname' should be the name of the
+gene, 'feature' should be the type of gene (CDS, rRNA, tRNA, other) or
+the single letter COG category (J for example). 'start' and 'end'
+should be integers between 1 and the length of the sequence, and the
+'start' value should be less than or equal to the 'end' regardless of
+the 'strand' value. The 'strand' value should be '+' for the forward
+strand and '-' for the reverse strand. All other values can be given
+as '.' or left blank, since they are ignored. These column titles are
+based on the specification of the GFF file format. If 'start' and
+'end' values are not supplied, but a 'seqname' is given, this script
+will attempt to get the 'start' and 'end' values from the sequence
+file. [Files]. Optional. Multiple files can be supplied using the
+genes option, as in the following example:
+
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -output R_denitrificans.xml -tick_density 0.7 -genes file1.txt file2.txt
+
+See http://www.sanger.ac.uk/Software/formats/GFF/ for more information
+on the GFF format.
+
+-analysis - One or more files containing gene expression information
+for the genes in the genome. The file should be tab-delimited or
+comma-delimited and should have the following column titles, in the
+following order: 'seqname', 'source', 'feature', 'start', 'end',
+'score', 'strand', 'frame'. The first line in the file must be the
+column titles. For a given entry, only the 'start', 'end', 'strand',
+and 'score' values are required. 'start' and 'end' should be integers
+between 1 and the length of the sequence, and the 'start' value should
+be less than or equal to the 'end' regardless of the 'strand'
+value. The 'strand' value should be '+' for the forward strand and '-'
+for the reverse strand. The 'score' value should be a real
+number, positive or negative. The other values can be given as '.' or
+left blank. These column titles are based on the specification of the
+GFF file format. If 'start' and 'end' values are not supplied, but a
+'seqname' is given, this script will attempt to get the 'start' and
+'end' values from the sequence file. [Files]. Optional. Multiple files
+can be supplied using the analysis option, as in the following example:
+
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -output R_denitrificans.xml -tick_density 0.7 -analysis file1.txt file2.txt
+
+See http://www.sanger.ac.uk/Software/formats/GFF/ for more information
+on the GFF format.
+
+-blast - One or more files of BLAST results to display. This option
+is used to display BLAST results from the local_blast_client.pl and
+remote_blast_client.pl scripts. These are available at:
+http://www.ualberta.ca/~stothard/software.html. When using the above
+scripts, the query should be split into multiple smaller sequences,
+using one of the following scripts: get_orfs.pl, get_cds.pl, or
+sequence_to_multi_fasta.pl. These are also available at the above
+URL. The file containing the multiple sequences is then BLASTed using
+local_blast_client.pl or remote_blast_client.pl. The BLAST results files
+can be passed to cgview_xml_builder using this option. The percent
+identity of each hit is plotted. [Files]. Optional. Multiple files can
+be supplied using the blast option, as in the following example:
+
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -output R_denitrificans.xml -tick_density 0.7 -blast file1.txt file2.txt
+
+#######Other options:
+#######------------------------------
+
+-verbose - Whether program progress should be written to standard
+output. [T/F]. Default is T. Optional.
+
+-log - A log file for recording progress and error
+messages. [File]. Default is to not write a log file.
+
+Exit status:
+------------
+
+If the script encounters an error it exits with a status of 1. If no
+error is encountered the script exits with a status of 0 upon
+completing.
+
+Written by Paul Stothard, University of Alberta
+
+stothard at ualberta.ca
diff --git a/cgview/cgview_xml_builder/cgview_xml_builder.pl b/cgview/cgview_xml_builder/cgview_xml_builder.pl
new file mode 100644
index 0000000..e50659c
--- /dev/null
+++ b/cgview/cgview_xml_builder/cgview_xml_builder.pl
@@ -0,0 +1,3757 @@
+#!/usr/bin/perl
+#
+#cgview_xml_builder.pl 
+#
+#Version 1.0
+#
+#This script requires bioperl-1.4 or newer. 
+#
+#See README
+#
+#Written by Paul Stothard, University of Alberta
+#
+#stothard at ualberta.ca
+
+use strict;
+use warnings;
+use Bio::SeqIO;
+use Getopt::Long;
+use Data::Dumper;
+
+my $MIN_ORF_SIZE = 25;
+my $MAX_ORF_SIZE = 1000;
+my $MIN_STEP = 1;
+my $MAX_STEP = 100;
+my $MIN_WINDOW = 1000;
+my $MAX_WINDOW = 10000;
+my $MIN_LENGTH = 1000;
+my $MAX_LENGTH = 20000000;
+
+my %options = (sequence => undef,
+	       output => undef,
+	       source_features => 'T',
+	       reading_frames => 'F',
+	       orfs => 'F',
+	       combined_orfs => 'F',
+	       orf_size => 100,
+	       starts => 'atg|ttg|att|gtg|ctg',
+	       stops => 'taa|tag|tga',
+	       gc_content => 'T',
+	       gc_skew => 'T',
+	       at_content => 'F',
+	       at_skew => 'F',
+	       average => 'T',
+	       scale => 'T',
+	       step => undef,
+	       window => undef,
+	       size => "medium",
+	       tick_density => 0.5,
+	       linear => undef,
+	       title => undef,
+	       details => 'T',
+	       legend => 'T',
+	       parse_reading_frame => 'F',
+	       show_queries => 'F',
+               condensed => 'F',
+               feature_labels => 'F',
+               gene_labels => 'F',
+               hit_labels => 'F',
+               orf_labels => 'F',
+	       global_label => 'T',
+               use_opacity => 'F',
+	       show_sequence_features => 'T',
+	       draw_divider_rings => 'F',
+	       font_size => undef,
+	       gene_decoration => undef,
+	       genes => undef,
+	       analysis => undef,
+	       blast => undef,
+	       verbose => 'T',
+	       log => undef);
+
+#Feel free to add your own COG letters and colors
+my %settings = (cogColors => {J => "rgb(128,0,0)", #maroon
+			      K => "rgb(0,0,128)", #navy  
+			      L => "rgb(128,0,128)", #purple  
+			      D => "rgb(185,148,101)", #light brown          
+			      O => "rgb(0,255,255)",  #aqua        
+			      M => "rgb(0,128,128)",  #teal
+			      N => "rgb(0,0,255)", #blue
+			      P => "rgb(234,165,42)", #orange
+			      T => "rgb(190,152,253)", #light purple
+			      C => "rgb(128,128,0)", #olive       
+			      G => "rgb(0,255,0)", #lime
+			      E => "rgb(0,128,0)", #green
+			      F => "rgb(255,0,255)", #fuchsia
+			      H => "rgb(241,199,200)", #light pink
+			      I => "rgb(255,0,0)", #red
+			      Q => "rgb(255,255,0)", #yellow
+			      R => "rgb(128,128,128)", #gray
+			      S => "rgb(192,192,192)", #sliver
+			      Unknown => "rgb(0,0,0)"}, #black
+
+		blastColors => ["rgb(0,128,128)",  #teal
+				"rgb(0,255,255)",  #aqua    
+				"rgb(234,165,42)", #orange
+				"rgb(190,152,253)", #light purple
+				"rgb(255,0,0)", #red
+				"rgb(0,0,255)", #blue
+				"rgb(128,128,0)", #olive 
+				"rgb(153,153,0)"], #yellow
+
+		analysisColors => ["rgb(0,128,0)", #green
+				     "rgb(241,199,200)", #light pink
+				     "rgb(255,0,255)", #fuchsia
+				     "rgb(0,153,153)", #light blue
+				     "rgb(0,153,0)", #green
+				     "rgb(153,153,0)"], #yellow	
+	
+		width => "3000",
+		height => "3000",
+		backboneRadius => "820",
+		backboneColor => "rgb(102,102,102)", #dark gray
+		backboneThickness => "20",
+		featureThickness => "30",    #was 40
+		featureThicknessPlot => "50", #was 45
+		featureSlotSpacing => "2",
+		rulerFontSize => "30",
+		rulerFontColor => "rgb(0,0,0)",
+		titleFontSize => "80",
+		labelFontSize => "30",
+		legendFontSize => "30",
+		maxTitleLength => "90",
+		maxLabelLength => "20",
+		maxLegendLength => "30",
+		plotLineThickness => "0.02",
+		proteinColor => "rgb(0,0,153)", #dark blue
+		tRNAColor => "rgb(153,0,0)",     #dark red
+		rRNAColor => "rgb(153,0,153)", #dark purple
+		otherColor => "rgb(51,51,51)", #dark gray
+		featureOpacity => "1.0",
+		featureOpacityOther => "0.5", #features of type 'other' are drawn with transparency so that underlying CDS can be seen
+		gcColorPos => "rgb(0,0,0)", #black
+		gcColorNeg => "rgb(0,0,0)", #black
+		atColorPos => "rgb(51,51,51)", #dark gray
+		atColorNeg => "rgb(51,51,51)", #dark gray
+		gcSkewColorPos => "rgb(0,153,0)",  #dark green
+		gcSkewColorNeg => "rgb(153,0,153)", #dark purple
+		atSkewColorPos => "rgb(153,153,0)", #dark yellow 
+		atSkewColorNeg => "rgb(0,0,153)", #dark blue
+		orfColor => "rgb(204,0,0)", #dark red
+   		startColor => "rgb(153,0,153)", #dark purple
+		stopColor => "rgb(204,0,0)", #dark red
+		backgroundColor => "white",
+		foregroundColor => "black",
+		sepColor => "rgb(0,51,0)", #dark green
+		tickColor => "rgb(0,51,0)", #dark green
+		labelLineLength => "200",
+		labelPlacementQuality => "good", #good, better, best
+		labelLineThickness => "4",
+		rulerPadding => "40",
+		tickThickness => "5",
+		arrowheadLength => "6",
+		minimumFeatureLength => "1.0",
+		moveInnerLabelsToOuter => "false",
+		tickLength => "20",
+		useInnerLabels => "true",
+		showBorder => "true",
+		isLinear => "false",
+		autoPlotSlotIncrease => 1,
+		maxFeatureSize => 50000); #maxFeatureSize is used to prevent large features ('source' for example) from obscuring other features
+
+my %global = (orfCount => 0,
+    	      ncbiGiLink => "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Text\&db=Protein\&dopt=genpept\&dispmax=20\&uid=",
+	      ncbiGeneLink => "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?db=gene\&cmd=Retrieve\&dopt=Graphics\&list_uids=",
+	      format => undef,
+              length => undef,
+              accession => undef,
+              topology => "circular");
+
+my %param = (options => \%options,
+	     settings => \%settings,
+	     global => \%global);
+		
+
+#read user options
+GetOptions ('sequence=s' => \$options{sequence},
+	    'output=s' => \$options{output},
+	    'source_features=s' => \$options{source_features},
+	    'reading_frames=s' => \$options{reading_frames},
+	    'orfs=s' => \$options{orfs},
+	    'combined_orfs=s' => \$options{combined_orfs},
+	    'orf_size=i' => \$options{orf_size},
+	    'starts=s' => \$options{starts},
+	    'stops=s' => \$options{stops},
+	    'gc_content=s' => \$options{gc_content},
+	    'gc_skew=s' => \$options{gc_skew},
+	    'at_content=s' => \$options{at_content},
+	    'at_skew=s' => \$options{at_skew},
+	    'average=s' => \$options{average},
+	    'scale=s' => \$options{scale},
+	    'step=i' => \$options{step},
+	    'window=i' => \$options{window},
+	    'size=s' => \$options{size},
+            'tick_density=f' => \$options{tick_density},
+	    'linear=s' => \$options{linear},
+	    'title=s' => \$options{title},
+	    'details=s' => \$options{details},
+	    'legend=s' => \$options{legend},
+	    'parse_reading_frame=s' =>\$options{parse_reading_frame},
+	    'show_queries=s' =>\$options{show_queries},
+	    'condensed=s' => \$options{condensed},
+            'feature_labels=s' => \$options{feature_labels},
+            'gene_labels=s' => \$options{gene_labels},
+            'hit_labels=s' => \$options{hit_labels},
+            'orf_labels=s' => \$options{orf_labels},
+	    'use_opacity=s' => \$options{use_opacity},
+            'show_sequence_features=s' => \$options{show_sequence_features},
+            'draw_divider_rings=s' => \$options{draw_divider_rings},
+	    'global_label=s' => \$options{global_label},
+            'font_size=s' => \$options{font_size},
+            'gene_decoration=s' => \$options{gene_decoration},
+	    'genes=s@{,}' => \$options{genes},
+	    'analysis=s@{,}' => \$options{analysis},
+	    'blast=s@{,}' => \$options{blast},
+	    'verbose=s' => \$options{verbose},
+	    'log=s' => \$options{log});
+
+
+#check for required options
+if (!(defined($param{options}->{sequence}))) {
+    die ("Please specify a sequence using the '-sequence' option.\n");
+}
+if (!(defined($param{options}->{output}))) {
+    die ("Please specify an output file using the '-output' option.\n");
+}
+
+#start log file
+if (defined($param{options}->{log})) {
+    _createLog($param{options}->{log});
+}
+
+#check some important values
+#-orf_size
+if ($options{orf_size} =~ m/(\d+)/) {
+    $options{orf_size} = $1;
+}
+else {
+    _message($param{options}, "-orf_size must be an integer value.");
+    die ("-orf_size must be an integer value.");
+}
+if ($options{orf_size} < $MIN_ORF_SIZE) {
+    _message($param{options}, "-orf_size must be greater than or equal to $MIN_ORF_SIZE.");
+    die ("-orf_size must be greater than or equal to $MIN_ORF_SIZE.");
+}
+if ($options{orf_size} > $MAX_ORF_SIZE) {
+    _message($param{options}, "-orf_size must be less than or equal to $MAX_ORF_SIZE.");
+    die ("-orf_size must be less than or equal to $MAX_ORF_SIZE.");
+}
+
+#-step
+if (defined($options{step})) {
+    if ($options{step} =~ m/(\d+)/) {
+	$options{step} = $1;
+    }
+    else {
+	_message($param{options}, "-step must be an integer value.");
+	die ("-step must be an integer value.");
+    }
+    if ($options{step} < $MIN_STEP) {
+	_message($param{options}, "-step must be greater than or equal to $MIN_STEP.");
+	die ("-step must be greater than or equal to $MIN_STEP.");
+    }
+    if ($options{step} > $MAX_STEP) {
+	_message($param{options}, "-step must be less than or equal to $MAX_STEP.");
+	die ("-step must be less than or equal to $MAX_STEP.");
+    }
+}
+
+#-window
+if (defined($options{window})) {
+    if ($options{window} =~ m/(\d+)/) {
+	$options{window} = $1;
+    }
+    else {
+	_message($param{options}, "-window must be an integer value.");
+	die ("-window must be an integer value.");
+    }
+    if ($options{window} < $MIN_WINDOW) {
+	_message($param{options}, "-window must be greater than or equal to $MIN_WINDOW.");
+	die ("-window must be greater than or equal to $MIN_WINDOW.");
+    }
+    if ($options{window} > $MAX_WINDOW) {
+	_message($param{options}, "-window must be less than or equal to $MAX_WINDOW.");
+	die ("-window must be less than or equal to $MAX_WINDOW.");
+    }
+}
+
+#-tick_density
+if ($options{tick_density} =~ m/([\d\.]+)/) {
+    $options{tick_density} = $1;
+}
+else {
+    _message($param{options}, "-tick_density must be a real value.");
+    die ("-tick_density must be a real value.");
+}
+if ($options{tick_density} < 0) {
+    _message($param{options}, "-tick_density must be greater than or equal to 0.");
+    die ("-tick_density must be greater than or equal to 0.");
+}
+if ($options{tick_density} > 1) {
+    _message($param{options}, "-tick_density must be less than or equal to 1.");
+    die ("-tick_density must be less than or equal to 1.");
+}
+
+#-global_label
+if ($options{global_label} =~ m/auto/i) {
+    $options{global_label} = "auto";
+}
+elsif ($options{global_label} =~ m/t/i) {
+    $options{global_label} = "true";
+}
+else {
+    $options{global_label} = "false";
+}
+
+
+#-starts
+if (defined($options{starts})) {
+    my @starts = split(/\|/, $options{starts});
+    foreach(@starts) {
+        if (!($_ =~ m/[a-z]{3}/)) {
+           _message($param{options}, "-starts must be given as codons separated by the '|', eg 'atg|ttg|att|gtg|ctg'. Be sure to include single quotes when passing as a command line argument.");
+           die ("-starts must be given as codons separated by the '|', eg 'atg|ttg|att|gtg|ctg'. Be sure to include single quotes when passing as a command line argument.");
+        }
+    }
+}
+
+#-stops
+if (defined($options{stops})) {
+    my @stops = split(/\|/, $options{stops});
+    foreach(@stops) {
+        if (!($_ =~ m/[a-z]{3}/)) {
+           _message($param{options}, "-stops must be given as codons separated by the '|', eg 'taa|tag|tga'. Be sure to include single quotes when passing as a command line argument.");
+           die ("-stops must be given as codons separated by the '|', eg 'taa|tag|tga'. Be sure to include single quotes when passing as a command line argument.");
+        }
+    }
+}
+
+#obtain BioPerl Bio::Seq sequence object
+#_getSeqObject also sets value of $global{format} to 'genbank', 'embl', 'raw', or 'fasta'
+my $seqObject = _getSeqObject(\%param);
+
+
+#get feature objects, go through them, find complex features, and divide them into new features.
+_expand_complex_features ($seqObject);
+
+#determine the length of the genome
+$global{length} = $seqObject->length();
+if (!(defined($global{length}))) {
+    _message($param{options}, "The sequence length could not be determined from the -sequence file $options{sequence}.");
+    die ("The sequence length could not be determined from the -sequence file $options{sequence}.");
+}
+
+if ($global{length} < $MIN_LENGTH) {
+    _message($param{options}, "The sequence must be longer than $MIN_LENGTH bases.");
+    die ("The sequence must be longer than $MIN_LENGTH bases.");
+}
+
+if ($global{length} > $MAX_LENGTH) {
+    _message($param{options}, "The sequence must be shorter than $MAX_LENGTH bases.");
+    die ("The sequence must be shorter than $MAX_LENGTH bases.");
+}
+
+#set window
+#these values may need to be adjusted
+if (!(defined($options{window}))) {
+    if ($global{length} < 1000) {
+        $options{window} = 10;
+    }
+    elsif ($global{length} < 10000) {
+        $options{window} = 50;
+    }
+    elsif ($global{length} < 100000) {
+        $options{window} = 500;
+    }
+    elsif ($global{length} < 1000000) {
+        $options{window} = 1000;
+    }
+    elsif ($global{length} < 10000000) {
+        $options{window} = 10000;
+    }
+    else {
+        $options{window} = 10000;
+    }
+}
+
+#set step.
+#these values may need to be adjusted
+#the step may need to be smaller when a larger map is drawn
+if (!(defined($options{step}))) {
+    if ($global{length} < 1000) {
+        $options{step} = 1;
+    }
+    elsif ($global{length} < 10000) {
+        $options{step} = 1;
+    }
+    elsif ($global{length} < 100000) {
+        $options{step} = 1;
+    }
+    elsif ($global{length} < 1000000) {
+        $options{step} = 10;
+    }
+    elsif ($global{length} < 10000000) {
+        $options{step} = 100;
+    }
+    else {
+        $options{step} = 100;
+    }
+
+    #adjust based on map size
+    if ($options{size} eq 'x-large') {
+        if ($options{step} == 10) {
+           $options{step} = 1;
+        }
+        elsif ($options{step} == 100) {
+           $options{step} = 10;
+        }
+    }
+
+    if ($options{size} eq 'large') {
+        if ($options{step} == 10) {
+           $options{step} = 5;
+        }
+        elsif ($options{step} == 100) {
+           $options{step} = 50;
+        }
+    }
+
+}
+
+#determine some global settings from sequence file
+if (($global{format} eq "embl") || ($global{format} eq "genbank")) {
+    $global{"accession"} = $seqObject->accession_number;
+    if (!(defined($options{title}))) {
+	$options{title} = $seqObject->description();
+    }    
+}
+if ($global{format} eq "fasta") {
+    if (!(defined($options{title}))) {
+	$options{title} = $seqObject->description();
+    }
+}
+
+#try to determine topology from genbank or embl record
+if (($global{format} eq "embl") || ($global{format} eq "genbank")) {
+    if ($seqObject->is_circular) {
+	$settings{isLinear} = "false";
+	$global{topology} = "circular";
+    }
+    else {
+	$settings{isLinear} = "true";
+	$global{topology} = "linear";
+    }
+}
+
+#user-supplied values take precedence
+if (_isTrue($options{linear})) {
+    $settings{isLinear} = "true";
+    $global{topology} = "linear";
+}
+elsif ((defined($options{linear})) && ($options{linear} =~ m/f/i)) {
+    $settings{isLinear} = "false";
+    $global{topology} = "circular";
+}
+
+#adjust settings based on size of map
+_adjustSettingsBasedOnSize($param{options}, $param{settings}, $param{global});
+
+#start building XML file
+_writeHeader(\%options, \%settings, \%global);
+
+#write title legend
+if ((defined($options{title})) && ($options{title} =~ m/\S/)) {
+    _writeTitleLegend(\%options, \%settings);
+}
+
+#write details legend
+if (_isTrue($options{details})) {
+    _writeDetailsLegend(\%param);
+}
+
+#write features legend
+if (_isTrue($options{legend})) {
+    _writeFeatureLegend(\%param, $seqObject);
+}
+
+
+#forward strand features drawn on outside of backbone circle. Those appearing first in the XML are drawn closest to the backbone.
+_message(\%options, "Creating XML for feature sets on the outside of the backbone circle.");
+_message(\%options, "Feature sets written first are drawn closest to the backbone circle.");
+
+#write starts and stops for three reading frames
+if (_isTrue($options{reading_frames})) {
+    _message(\%options, "Creating XML for starts and stops that are in reading frame +1.");    
+    _writeStopsAndStarts(\%options, \%settings, $seqObject, 1, 1);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+    _message(\%options, "Creating XML for starts and stops that are in reading frame +2.");  
+    _writeStopsAndStarts(\%options, \%settings, $seqObject, 1, 2);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+    _message(\%options, "Creating XML for starts and stops that are in reading frame +3.");  
+    _writeStopsAndStarts(\%options, \%settings, $seqObject, 1, 3);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+}
+
+#write ORFs for three reading frames
+if (_isTrue($options{orfs})) {
+    _message(\%options, "Creating XML for ORFs that are in reading frame +1.");   
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, 1, 1);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+    _message(\%options, "Creating XML for ORFs that are in reading frame +2."); 
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, 1, 2);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+    _message(\%options, "Creating XML for ORFs that are in reading frame +3."); 
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, 1, 3);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+}
+
+#write combined orfs
+if (_isTrue($options{combined_orfs})) {
+    _message(\%options, "Creating XML for ORFs that are on the plus strand.");
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, 1, "all");
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+    }
+}
+
+#write features in GenBank or EMBL file
+if (_isTrue($options{show_sequence_features})) {
+    if ((defined($global{format})) && ($global{format} eq "genbank")) {
+	_message(\%options, "Creating XML for features in the GenBank file that are on the plus strand.");
+	_writeGenBankGenes(\%options, \%settings, \%global, $seqObject, 1, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+        }
+    }
+    elsif ((defined($global{format})) && ($global{format} eq "embl")) {
+	_message(\%options, "Creating XML for features in the EMBL file that are on the plus strand.");
+	_writeEmblGenes(\%options, \%settings, \%global, $seqObject, 1, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+        }
+    }
+}
+
+#write features info from -genes files if available
+if (defined($options{genes})) {
+    foreach(reverse(@{$options{genes}})) {
+        _message(\%options, "Creating XML for features in the genes file $_ that are on the plus strand.");
+        _writeGenes(\%options, \%settings, \%global, $seqObject, 1, undef, undef, undef, $_, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+        }
+    }
+}
+
+#write info from analysis file if available
+#commented out on 2007-12-11 so that all analysis results shown on inside of backbone
+#if (defined($options{"analysis"})) {
+#    my @colors = @{$settings{'analysisColors'}};
+#    foreach(reverse(@{$options{"analysis"}})) {
+#        my $colorPos = shift(@colors);
+#        my $colorNeg = shift(@colors);
+#	push(@colors, $colorPos);
+#	push(@colors, $colorNeg);
+#        _message(\%options, "Creating XML for analysis values from the analysis file $_ that are on the plus strand.");
+#        _writeGenes(\%options, \%settings, \%global, $seqObject, 1, undef, $colorPos, $colorNeg, $_, 1);
+#        if (_isTrue($options{draw_divider_rings})) {
+#            _drawDivider(\%options, \%settings, \%global, $seqObject, 1, 0.25);
+#        }
+#    }
+#}
+
+
+#Reverse strand features drawn on inside of backbone circle. Those appearing first
+#in the XML are drawn closest to the backbone.
+_message(\%options, "Creating XML for feature sets on the inside of the backbone circle.");
+_message(\%options, "Feature sets written first are drawn closest to the backbone circle.");
+
+#write starts and stops for three reading frames
+if (_isTrue($options{reading_frames})) {
+    _message(\%options, "Creating XML for starts and stops that are in reading frame -1.");    
+    _writeStopsAndStarts(\%options, \%settings, $seqObject, -1, 1);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+    _message(\%options, "Creating XML for starts and stops that are in reading frame -2.");  
+    _writeStopsAndStarts(\%options, \%settings, $seqObject, -1, 2);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+    _message(\%options, "Creating XML for starts and stops that are in reading frame -3.");  
+    _writeStopsAndStarts(\%options, \%settings, $seqObject, -1, 3);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+
+#write ORFs for three reading frames
+if (_isTrue($options{orfs})) {
+    _message(\%options, "Creating XML for ORFs that are in reading frame -1.");   
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, -1, 1);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+    _message(\%options, "Creating XML for ORFs that are in reading frame -2."); 
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, -1, 2);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+    _message(\%options, "Creating XML for ORFs that are in reading frame -3."); 
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, -1, 3);
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+
+#write combined orfs
+if (_isTrue($options{combined_orfs})) {
+    _message(\%options, "Creating XML for ORFs that are on the reverse strand.");
+    _writeOrfs(\%options, \%settings, \%global, $seqObject, -1, "all");
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+
+#write features in GenBank or EMBL file
+if (_isTrue($options{show_sequence_features})) {
+    if ((defined($global{format})) && ($global{format} eq "genbank")) {
+	_message(\%options, "Creating XML for features in the GenBank file that are on the reverse strand.");
+	_writeGenBankGenes(\%options, \%settings, \%global, $seqObject, -1, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+        }
+    }
+    elsif ((defined($global{format})) && ($global{format} eq "embl")) {
+	_message(\%options, "Creating XML for features in the EMBL file that are on the reverse strand.");
+	_writeEmblGenes(\%options, \%settings, \%global, $seqObject, -1, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+        }
+    }
+}
+
+#write features info from -genes files if available
+if (defined($options{genes})) {   
+    foreach(reverse(@{$options{genes}})) {
+        _message(\%options, "Creating XML for features in the genes file $_ that are on the reverse strand.");
+        _writeGenes(\%options, \%settings, \%global, $seqObject, -1, undef, undef, undef, $_, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+        }
+    }
+}
+
+#write info from analysis file if available
+if (defined($options{"analysis"})) {
+    my @colors = @{$settings{'analysisColors'}};
+    foreach(reverse(@{$options{"analysis"}})) {
+        my $colorPos = shift(@colors);
+        my $colorNeg = shift(@colors);
+	push(@colors, $colorPos);
+	push(@colors, $colorNeg);
+        _message(\%options, "Creating XML for analysis values from the analysis file $_.");
+        _writeGenes(\%options, \%settings, \%global, $seqObject, -1, undef, $colorPos, $colorNeg, $_, 1);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+        }
+    }
+}
+
+#write blast results
+if (defined($options{"blast"})) {
+    my @colors = @{$settings{'blastColors'}};
+    foreach(@{$options{"blast"}}) {
+        my $color = shift(@colors);
+	push(@colors, $color);
+        _message(\%options, "Creating XML for BLAST hits from the BLAST file $_.");
+        _writeBlast(\%options, \%settings, \%global, $seqObject, -1, $_, $color, $settings{'featureThickness'}, undef);
+        if (_isTrue($options{draw_divider_rings})) {
+            _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+        }
+    }
+}
+
+#draw base content graphs.
+if (_isTrue($options{'at_content'})) {
+    _message(\%options, "Creating XML for AT content information.");
+    _writeBaseContent(\%options, \%settings, $seqObject, -1, 'at_content');
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+if (_isTrue($options{'at_skew'})) {
+    _message(\%options, "Creating XML for AT skew information.");
+    _writeBaseContent(\%options, \%settings, $seqObject, -1, 'at_skew');
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+if (_isTrue($options{'gc_content'})) {
+    _message(\%options, "Creating XML for GC content information.");
+    _writeBaseContent(\%options, \%settings, $seqObject, -1, 'gc_content');
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+if (_isTrue($options{'gc_skew'})) {
+    _message(\%options, "Creating XML for GC skew information.");
+    _writeBaseContent(\%options, \%settings, $seqObject, -1, 'gc_skew');
+    if (_isTrue($options{draw_divider_rings})) {
+        _drawDivider(\%options, \%settings, \%global, $seqObject, -1, 0.25);
+    }
+}
+
+
+#write footer
+_writeFooter(\%options);
+
+
+#give information about running CGView and improving XML
+_message(\%options, "CGView XML file complete.");
+_message(\%options, "The recommended CGView command is:");
+_message(\%options, "----------------------------------");
+_message(\%options, "java -jar -Xmx1500m ../cgview.jar -i $options{output} -o map.png -f png");
+_message(\%options, "Success!");
+
+##############################
+
+
+sub _createLog {
+    my $file = shift;
+    open(OUTFILE, ">" . $file) or die ("Cannot open file : $!");
+    print(OUTFILE "#Results of cgview_sml_builder.pl run started on " . _getTime() . ".\n");
+    close(OUTFILE) or die ("Cannot close file : $!");
+}
+
+sub _getTime {
+    my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time);
+    $year += 1900;
+
+    my @days = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday');
+    my @months = ('January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December');
+    my $time = $days[$wday] . " " . $months[$mon] . " " . sprintf("%02d", $mday) . " " . sprintf("%02d", $hour) . ":" . sprintf("%02d", $min) . ":" . sprintf("%02d", $sec) . " " . sprintf("%04d", $year);  
+    return $time;
+}
+
+sub _adjustSettingsBasedOnSize {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+ 
+    if ($options->{size} eq "small") {
+	$settings->{width} = "1000";
+	$settings->{height} = "1000";
+	$settings->{featureSlotSpacing} = "4";
+	$settings->{backboneRadius} = "300";
+	$settings->{backboneThickness} = "2";
+	$settings->{featureThickness} = "8";
+	$settings->{featureThicknessPlot} = "15";
+	$settings->{rulerFontSize} = "8";
+	$settings->{titleFontSize} = "30";
+	$settings->{labelFontSize} = "10";
+	$settings->{legendFontSize} = "8";
+	$settings->{maxTitleLength} = "50";
+	$settings->{maxLabelLength} = "20";
+	$settings->{maxLegendLength} = "20";
+	$settings->{plotLineThickness} = "0.02";
+	$settings->{labelLineLength} = "60";
+	$settings->{labelLineThickness} = "1";
+	$settings->{rulerPadding} = "14";
+	$settings->{tickThickness} = "1";
+	$settings->{arrowheadLength} = "4";
+	$settings->{minimumFeatureLength} = "0.2";
+	$settings->{tickLength} = "5";
+    }
+    elsif ($options->{size} eq "medium") {
+	$settings->{width} = "3000";
+	$settings->{height} = "3000";
+	$settings->{featureSlotSpacing} = "6";
+	$settings->{backboneRadius} = "1000";
+	$settings->{backboneThickness} = "8";
+	$settings->{featureThickness} = "30";
+	$settings->{featureThicknessPlot} = "80";
+	$settings->{rulerFontSize} = "30";
+	$settings->{titleFontSize} = "80";
+	$settings->{labelFontSize} = "15";
+	$settings->{legendFontSize} = "20";
+	$settings->{maxTitleLength} = "50";
+	$settings->{maxLabelLength} = "20";
+	$settings->{maxLegendLength} = "30";
+	$settings->{plotLineThickness} = "0.02";
+	$settings->{labelLineLength} = "200";
+	$settings->{labelLineThickness} = "4";
+	$settings->{rulerPadding} = "40";
+	$settings->{tickThickness} = "6";
+	$settings->{arrowheadLength} = "6";
+	$settings->{minimumFeatureLength} = "0.2";
+	$settings->{tickLength} = "15";	
+	$options->{tick_density} = $options->{tick_density} / 3.0;
+    }
+    #setting for the CGView server
+    elsif ($options->{size} eq "cgview_server_full") {
+	$settings->{width} = "3000";
+	$settings->{height} = "3000";
+	$settings->{featureSlotSpacing} = "1";
+	$settings->{backboneRadius} = "1000";
+	$settings->{backboneThickness} = "8";
+	$settings->{featureThickness} = "60";
+	$settings->{featureThicknessPlot} = "80";
+	$settings->{rulerFontSize} = "30";
+	$settings->{titleFontSize} = "80";
+	$settings->{labelFontSize} = "15";
+	$settings->{legendFontSize} = "20";
+	$settings->{maxTitleLength} = "90";
+	$settings->{maxLabelLength} = "20";
+	$settings->{maxLegendLength} = "30";
+	$settings->{plotLineThickness} = "0.02";
+	$settings->{labelLineLength} = "200";
+	$settings->{labelLineThickness} = "4";
+	$settings->{rulerPadding} = "40";
+	$settings->{tickThickness} = "6";
+	$settings->{arrowheadLength} = "10";
+	$settings->{minimumFeatureLength} = "0.5"; #was 0.2
+	$settings->{tickLength} = "15";	
+	$settings->{moveInnerLabelsToOuter} = "true";	
+	$options->{tick_density} = $options->{tick_density} / 3.0;
+
+	#if using labels, make rings thinner for more label space
+	#and don't allow plot slots to grow
+	if (_isTrue($options->{feature_labels})) {
+	    $settings->{backboneRadius} = "900";
+	    $settings->{featureThickness} = "50";
+	    $settings->{featureThicknessPlot} = "80";
+	    $settings->{autoPlotSlotIncrease} = 0;
+	}
+    }
+    #setting for the CGView server
+    elsif ($options->{size} eq "cgview_server_zoom") {
+	$settings->{width} = "3000";
+	$settings->{height} = "3000";
+	$settings->{featureSlotSpacing} = "1";
+	$settings->{backboneRadius} = "1000";
+	$settings->{backboneThickness} = "16";
+	$settings->{featureThickness} = "260";
+	$settings->{featureThicknessPlot} = "260";
+	$settings->{rulerFontSize} = "30";
+	$settings->{titleFontSize} = "80";
+	$settings->{labelFontSize} = "15";
+	$settings->{legendFontSize} = "20";
+	$settings->{maxTitleLength} = "90";
+	$settings->{maxLabelLength} = "20";
+	$settings->{maxLegendLength} = "30";
+	$settings->{plotLineThickness} = "0.02";
+	$settings->{labelLineLength} = "200";
+	$settings->{labelLineThickness} = "4";
+	$settings->{rulerPadding} = "40";
+	$settings->{tickThickness} = "6";
+	$settings->{arrowheadLength} = "10";
+	$settings->{minimumFeatureLength} = "0.5"; #was 0.2
+	$settings->{tickLength} = "15";	
+	$options->{tick_density} = $options->{tick_density} / 3.0;
+    }
+    elsif ($options->{size} eq "large") {
+	$settings->{width} = "9000";
+	$settings->{height} = "9000";
+	$settings->{featureSlotSpacing} = "6";
+	$settings->{backboneRadius} = "3500";
+	$settings->{backboneThickness} = "8";
+	$settings->{featureThickness} = "60";
+	$settings->{featureThicknessPlot} = "120";
+	$settings->{rulerFontSize} = "60";
+	$settings->{titleFontSize} = "100";
+	$settings->{labelFontSize} = "40";
+	$settings->{legendFontSize} = "50";
+	$settings->{maxTitleLength} = "90";
+	$settings->{maxLabelLength} = "20";
+	$settings->{maxLegendLength} = "30";
+	$settings->{plotLineThickness} = "0.02";
+	$settings->{labelLineLength} = "200";
+	$settings->{labelLineThickness} = "4";
+	$settings->{rulerPadding} = "100";
+	$settings->{tickThickness} = "10";
+	$settings->{arrowheadLength} = "12";
+	$settings->{minimumFeatureLength} = "0.2";
+	$settings->{tickLength} = "25";
+	$settings->{labelPlacementQuality} = "better";
+
+	$options->{tick_density} = $options->{tick_density} / 9.0;
+    }
+    elsif ($options->{size} eq "x-large") {
+	$settings->{width} = "12000";
+	$settings->{height} = "12000";
+	$settings->{featureSlotSpacing} = "2";
+	$settings->{backboneRadius} = "4000";
+	$settings->{featureThickness} = "100";
+	$settings->{featureThicknessPlot} = "150";
+	$settings->{rulerFontSize} = "60";
+	$settings->{titleFontSize} = "80";
+	$settings->{labelFontSize} = "15";
+	$settings->{legendFontSize} = "60";
+	$settings->{maxTitleLength} = "90";
+	$settings->{maxLabelLength} = "20";
+	$settings->{maxLegendLength} = "30";
+	$settings->{plotLineThickness} = "0.02";
+	$settings->{labelLineLength} = "200";
+	$settings->{labelLineThickness} = "4";
+	$settings->{rulerPadding} = "40";
+	$settings->{tickThickness} = "5";
+	$settings->{arrowheadLength} = "6";
+	$settings->{minimumFeatureLength} = "0.2";
+	$settings->{tickLength} = "20";
+	$settings->{labelPlacementQuality} = "better";
+
+	$options->{tick_density} = $options->{tick_density} / 12.0;
+    }
+    else {
+	_message($options, "-size setting $options->{size} not recognized.");
+	die("-size setting $options->{size} not recognized");
+    }
+
+    #override the fontsize settings if -font_size specified
+    #these are for the CGView server
+    if ((defined($options->{font_size})) && ($options->{size} eq "cgview_server_zoom")) {
+	if ($options->{font_size} eq 'xx-small') {
+	    $settings->{rulerFontSize} = '8';
+	    $settings->{titleFontSize} = '50';
+	    $settings->{labelFontSize} = '8';
+	    $settings->{legendFontSize} = '12';
+	    $settings->{labelLineLength} = "50";
+	    $settings->{labelLineThickness} = "1";
+	}
+	elsif ($options->{font_size} eq 'x-small') {
+	    $settings->{rulerFontSize} = '10';
+	    $settings->{titleFontSize} = '60';
+	    $settings->{labelFontSize} = '10';
+	    $settings->{legendFontSize} = '16';
+	    $settings->{labelLineLength} = "100";
+	    $settings->{labelLineThickness} = "2";
+	}
+	elsif ($options->{font_size} eq 'small') {
+	    $settings->{rulerFontSize} = '12';
+	    $settings->{titleFontSize} = '70';
+	    $settings->{labelFontSize} = '12';
+	    $settings->{legendFontSize} = '18';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "2";
+	}
+	elsif ($options->{font_size} eq 'medium') {
+	    $settings->{rulerFontSize} = '15';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '15';
+	    $settings->{legendFontSize} = '20';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "2";
+	}
+	elsif ($options->{font_size} eq 'large') {
+	    $settings->{rulerFontSize} = '20';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '20';
+	    $settings->{legendFontSize} = '22';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "4";
+	}
+	elsif ($options->{font_size} eq 'x-large') {
+	    $settings->{rulerFontSize} = '32';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '32';
+	    $settings->{legendFontSize} = '24';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "4";
+	}
+	elsif ($options->{font_size} eq 'xx-large') {
+	    $settings->{rulerFontSize} = '36';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '36';
+	    $settings->{legendFontSize} = '30';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "4";
+	}
+    }
+
+    #these are for the CGView server
+    if ((defined($options->{font_size})) && ($options->{size} eq "cgview_server_full")) {
+	if ($options->{font_size} eq 'xx-small') {
+	    $settings->{rulerFontSize} = '8';
+	    $settings->{titleFontSize} = '50';
+	    $settings->{labelFontSize} = '8';
+	    $settings->{legendFontSize} = '12';
+	    $settings->{labelLineLength} = "50";
+	    $settings->{labelLineThickness} = "1";
+	}
+	elsif ($options->{font_size} eq 'x-small') {
+	    $settings->{rulerFontSize} = '10';
+	    $settings->{titleFontSize} = '60';
+	    $settings->{labelFontSize} = '10';
+	    $settings->{legendFontSize} = '16';
+	    $settings->{labelLineLength} = "100";
+	    $settings->{labelLineThickness} = "2";
+	}
+	elsif ($options->{font_size} eq 'small') {
+	    $settings->{rulerFontSize} = '12';
+	    $settings->{titleFontSize} = '70';
+	    $settings->{labelFontSize} = '12';
+	    $settings->{legendFontSize} = '18';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "2";
+	}
+	elsif ($options->{font_size} eq 'medium') {
+	    $settings->{rulerFontSize} = '15';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '15';
+	    $settings->{legendFontSize} = '20';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "2";
+	}
+	elsif ($options->{font_size} eq 'large') {
+	    $settings->{rulerFontSize} = '16';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '20';
+	    $settings->{legendFontSize} = '22';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "4";
+	}
+	elsif ($options->{font_size} eq 'x-large') {
+	    $settings->{rulerFontSize} = '17';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '32';
+	    $settings->{legendFontSize} = '24';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "4";
+	}
+	elsif ($options->{font_size} eq 'xx-large') {
+	    $settings->{rulerFontSize} = '18';
+	    $settings->{titleFontSize} = '80';
+	    $settings->{labelFontSize} = '36';
+	    $settings->{legendFontSize} = '30';
+	    $settings->{labelLineLength} = "150";
+	    $settings->{labelLineThickness} = "4";
+	}
+
+    }
+
+    #count the number of featureSlots
+    my $plotSlotsOuter = 0;
+    my $plotSlotsInner = 0;
+    my $otherSlotsOuter = 0;
+    my $otherSlotsInner = 0;
+
+    #non plot slots such as genes
+    if (($global->{format} eq "embl") || ($global->{format} eq "genbank")) {
+	if ($options->{show_sequence_features}) {
+	    $otherSlotsOuter++;
+	    $otherSlotsInner++;
+	}
+    }
+    if (_isTrue($options->{reading_frames})) {
+	$otherSlotsOuter = $otherSlotsOuter + 3;
+	$otherSlotsInner = $otherSlotsInner + 3;
+    }   
+    if (_isTrue($options->{orfs})) {
+	$otherSlotsOuter = $otherSlotsOuter + 3;
+	$otherSlotsInner = $otherSlotsInner + 3;
+    } 
+    if (_isTrue($options->{combined_orfs})) {
+	$otherSlotsOuter = $otherSlotsOuter + 3;
+	$otherSlotsInner = $otherSlotsInner + 3;
+    } 
+    if (defined($options->{genes})) {
+	$otherSlotsOuter = $otherSlotsOuter + scalar(@{$options->{genes}});
+	$otherSlotsInner = $otherSlotsInner + scalar(@{$options->{genes}});
+    }
+    if (defined($options->{analysis})) {
+	#$plotSlotsOuter = $plotSlotsOuter + 2 * (scalar(@{$options->{analysis}}));
+	$plotSlotsInner = $plotSlotsInner + 2 * (scalar(@{$options->{analysis}}));
+    }
+
+    #This estimation could be improved, since maps can now show some blast results
+    #in a single track and others in six tracks, depending on whether reading
+    #frame information is read by _parseBLAST
+    if (defined($options->{blast})) {
+	if (_isTrue($options->{parse_reading_frame})) {
+	    foreach(@{$options->{blast}}) {
+		if (_containsReadingFrameInfo($settings, $global, $_)) {
+		    $otherSlotsInner = $otherSlotsInner + 6;
+		}
+		else {
+		    $otherSlotsInner = $otherSlotsInner + 1;
+		}
+	    }
+	}
+	else {
+	    $otherSlotsInner = $otherSlotsInner + scalar(@{$options->{blast}});
+	}
+    }
+
+    #plot slots such as gc skew
+    if (_isTrue($options->{at_content})) {
+	$plotSlotsInner++;
+    } 
+    if (_isTrue($options->{at_skew})) {
+	$plotSlotsInner++;
+    }
+    if (_isTrue($options->{gc_content})) {
+	$plotSlotsInner++;
+    } 
+    if (_isTrue($options->{gc_skew})) {
+	$plotSlotsInner++;
+    }
+
+    #adjust featureSlotThickness based on number of slots used
+    #want plotSlots to be six times wider than other slots
+    my $availableSpace = $settings->{backboneRadius} * 0.60 - $settings->{featureSlotSpacing} * ($plotSlotsInner + $plotSlotsOuter + $otherSlotsInner + $otherSlotsOuter - 1);
+    my $slotUnits = 6.0 * ($plotSlotsInner + $plotSlotsOuter) + $otherSlotsInner + $otherSlotsOuter;
+    
+    if ($slotUnits == 0) {
+	$slotUnits++;
+    }
+
+    my $slotWidths = $availableSpace / $slotUnits;
+
+    #changed 2007-01-14 so that feature widths don't get too big
+    #$settings->{featureThickness} = sprintf("%.2f", $slotWidths);
+    if (sprintf("%.2f", $slotWidths) < $settings->{featureThickness}) {
+	$settings->{featureThickness} = sprintf("%.2f", $slotWidths);	
+    }
+
+    if (sprintf("%.2f", $slotWidths * 6.0) < $settings->{featureThicknessPlot}) {
+	$settings->{featureThicknessPlot} = sprintf("%.2f", $slotWidths * 6.0);
+    }
+    else {
+	if ($settings->{autoPlotSlotIncrease}) {
+	    $settings->{featureThicknessPlot} = sprintf("%.2f", $slotWidths * 6.0);
+	}
+    }
+
+    #check condensed setting.
+    if (_isTrue($options->{condensed})) {
+	my $newWidth;
+	if ($options->{size} eq "small") {
+	    $newWidth = 8;
+	}
+	if ($options->{size} eq "medium") {
+	    $newWidth = 10;
+	}
+	if ($options->{size} eq "large") {
+	    $newWidth = 10;
+	}
+	if ($options->{size} eq "x-large") {
+	    $newWidth = 10;
+	}
+
+	if ($newWidth < $settings->{featureThickness}) {
+	    $settings->{featureThickness} = $newWidth;
+	    $settings->{backboneThickness} = "2";
+	}
+	if (($newWidth * 2) < $settings->{featureThicknessPlot}) {
+	    $settings->{featureThicknessPlot} = $newWidth * 2;
+	    $settings->{backboneThickness} = "2";
+	}
+    }
+}
+
+sub _message {
+    my $options = shift;
+    my $message = shift;
+ 
+    if (_isTrue($options->{verbose})) {
+	print "$message\n";
+    }
+    
+    if (defined($options->{log})) {
+	_writeLog($options->{log}, "$message\n");
+    }
+}
+
+sub _isTrue {
+    my $string = shift;
+    if ((defined($string)) && ($string =~ m/t/i)) {
+	return 1;
+    }
+    return 0;
+}
+
+sub _writeLog {
+    my $file = shift;
+    my $message = shift;
+    open(OUTFILE, "+>>" . $file) or die ("Cannot open file : $!");
+    print(OUTFILE $message);
+    close(OUTFILE) or die ("Cannot close file : $!");
+}
+
+sub _getSeqObject {
+    my $param = shift;
+    my $file = $param->{options}->{sequence};
+
+    open (INFILE, $file) or die( "Cannot open input file: $!" ); 
+  
+    while (my $line = <INFILE>) {
+	if (!($line =~ m/\S/)) {
+	    next;
+	}
+
+	#guess file format from first line
+	if ($line =~ m/^LOCUS\s+/) {
+	    $param->{global}->{format} = "genbank";
+	}
+	elsif ($line =~ m/^ID\s+/) {
+	    $param->{global}->{format} = "embl";
+	}
+	elsif ($line =~ m/^>/) {
+	    $param->{global}->{format} = "fasta";
+	}
+	else {
+	    $param->{global}->{format} = "raw";
+	}
+	last;
+    }
+
+    close (INFILE) or die ("Cannot close input file: $!");
+
+    #get seqobj
+    my $in = Bio::SeqIO->new(-format => $param->{global}->{format}, -file => $file);
+    my $seq = $in->next_seq();
+    
+    return $seq;
+    
+}
+
+
+sub _writeHeader {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    
+    my $header = "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n<cgview backboneRadius=\"$settings->{backboneRadius}\" backboneColor=\"$settings->{backboneColor}\" backboneThickness=\"$settings->{backboneThickness}\" featureSlotSpacing=\"$settings->{featureSlotSpacing}\" labelLineLength=\"$settings->{labelLineLength}\" labelPlacementQuality=\"$settings->{labelPlacementQuality}\" labelLineThickness=\"$settings->{labelLineThickness}\" rulerPadding=\"$settings->{rulerPadding}\" tickThick [...]
+
+    open (OUTFILE, ">$options->{output}") or die( "Cannot open file : $!" );
+    print (OUTFILE $header);
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+sub _writeTitleLegend {
+    my $options = shift;
+    my $settings = shift;
+    my $title = $options->{title};
+    $title =~ s/[\.\,]//g;
+    if (length($title) > $settings->{maxTitleLength} - 3) {
+	if ($options->{verbose}) {
+	    _message ($options, "The sequence title was shortened because it is longer than $settings->{maxTitleLength} characters.");
+	}
+	$title = substr($title, 0, $settings->{maxTitleLength} - 3) . "...";
+    }
+    $title = _escapeText($title);
+
+    my $legend = "<legend position=\"lower-center\" backgroundOpacity=\"0.8\">\n<legendItem textAlignment=\"center\" font=\"SansSerif, plain, $settings->{titleFontSize}\" text=\"$title\" />\n</legend>\n";
+    
+    open (OUTFILE, "+>>" . $options->{output}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- title -->\n");
+    print (OUTFILE $legend);
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+}
+
+sub _escapeText {
+    my $text = shift;
+    if (!defined($text)) {
+	return undef;
+    }
+    $text =~ s/&/&/g;
+    $text =~ s/\'/'/g;
+    $text =~ s/\"/"/g;
+    $text =~ s/</</g;
+    $text =~ s/>/>/g;
+    return $text;
+}
+
+sub _writeDetailsLegend {
+    my $param = shift;
+
+    my $accession = _escapeText($param->{global}->{accession});
+    my $length = _escapeText($param->{global}->{length});
+    my $topology = _escapeText($param->{global}->{topology});
+
+    my $legend = "<legend position=\"upper-left\" font=\"SansSerif, plain, $param->{settings}->{titleFontSize}\" backgroundOpacity=\"0.8\">\n";
+    if (defined($accession)) {
+	$legend = $legend . "<legendItem text=\"Accession: $accession\" />\n";
+    }
+
+    while ($length =~ s/^(-?\d+)(\d\d\d)/$1,$2/) {
+	1;
+    }
+    $length = $length . " bp";
+    $legend = $legend . "<legendItem text=\"Length: $length\" />\n";
+
+    if ($topology =~ m/linear/i) {
+	$legend = $legend . "<legendItem text=\"" . "Topology: $topology\" />\n";
+    }
+    
+    $legend = $legend . "</legend>\n";
+
+    open (OUTFILE, "+>>" . $param->{options}->{output}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- details legend -->\n");
+    print (OUTFILE $legend);
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+sub _writeFeatureLegend {
+    my $param = shift;
+    my $options = $param->{options};
+    my $settings = $param->{settings};
+    my $global = $param->{global};
+    my $seqObject = shift;
+
+
+    #check -genes files to see if they contain COG information, or features such as 'other' 'tRNA' 'rRNA'
+    my $hasCogs = 0;
+    my $hasOther = 0;
+    my $hastRNA = 0;
+    my $hasrRNA = 0;
+    my $hasCoding = 0;
+    if (defined($options->{genes})) {
+	foreach(@{$options->{genes}}) {
+	    my @features = @{_parseGFF($_, $options, $settings, $global, $seqObject)};
+
+	    foreach(@features) {
+		my $feat = $_;
+		my $type = lc($feat->{'feature'});
+
+		if ($type eq "cds") {
+		    $hasCoding = 1;
+		}
+		elsif ($type eq "rrna") {
+		    $hasrRNA = 1;
+		}
+		elsif ($type eq "trna") {
+		    $hastRNA = 1;
+		}
+		elsif ($type eq "other") {
+		    $hasOther = 1;
+		}
+		elsif (defined($settings->{'cogColors'}->{uc($type)})) {
+		    $hasCogs = 1;
+		}
+	    }
+	}	
+    }
+
+    my $legend = "<legend position=\"upper-right\" textAlignment=\"left\" backgroundOpacity=\"0.8\" font=\"SansSerif, plain, " . $settings->{'legendFontSize'} . "\">\n";
+
+    #legend for COGs if genes file supplied and COGs were found
+    if ($hasCogs) {
+	if (defined($options->{'genes'})) {
+	    my @cogs = keys(%{$settings->{'cogColors'}});
+	    @cogs = sort(@cogs);
+	    foreach(@cogs) {
+		$legend = $legend . "<legendItem text=\"" . $_ . " COG" . "\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'cogColors'}->{$_} . "\" />\n";
+	    }
+	}
+    }
+
+    #protein encoding genes legend
+    if (((($global->{'format'} eq "genbank") || ($global->{'format'} eq "embl"))) || ($hasCoding)) {
+	$legend = $legend . "<legendItem text=\"CDS\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'proteinColor'} . "\" />\n";
+    }
+
+    if (!(defined($global->{'format'}))) {
+	die ("_writeFeatureLegend requires that the sequence format be set by _getSeqObject.");
+    }    
+    
+    #legend for tRNA, rRNA and other genes if input file is GenBank or EMBL, or if these features were found in the -genes files
+    if ((((($global->{'format'} eq "genbank") || ($global->{'format'} eq "embl"))) && ($options->{show_sequence_features})) || ($hastRNA)) {
+        $legend = $legend . "<legendItem text=\"tRNA\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'tRNAColor'} . "\" />\n";
+    }
+    if ((((($global->{'format'} eq "genbank") || ($global->{'format'} eq "embl"))) && ($options->{show_sequence_features})) || ($hasrRNA)) {
+        $legend = $legend . "<legendItem text=\"rRNA\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'rRNAColor'} . "\" />\n";
+    }
+    if ((((($global->{'format'} eq "genbank") || ($global->{'format'} eq "embl"))) && ($options->{show_sequence_features})) || ($hasOther)) {
+        $legend = $legend . "<legendItem text=\"Other\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacityOther'} . "\" swatchColor=\"" . $settings->{'otherColor'} . "\" />\n";
+    }      
+
+    #orfs legend
+    if ((_isTrue($options->{'orfs'})) || (_isTrue($options->{'combined_orfs'}))) {
+	$legend = $legend . "<legendItem text=\"ORF\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'orfColor'} . "\" />\n";
+    }
+
+    #reading frames legend
+    if (_isTrue($options->{'reading_frames'})) {
+	$legend = $legend . "<legendItem text=\"Start\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'startColor'} . "\" />\n";
+	$legend = $legend . "<legendItem text=\"Stop\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'stopColor'} . "\" />\n";
+    }
+
+    #analysis legends
+    if (defined($options->{'analysis'})) {
+	my @colors = @{$settings->{'analysisColors'}};
+	my @color_set = ();
+	foreach(@{$options->{'analysis'}}) {
+	    my $colorPos = shift(@colors);
+	    my $colorNeg = shift(@colors);
+	    push (@color_set, $colorPos);
+	    push (@color_set, $colorNeg);
+	}
+	@color_set = reverse(@color_set);
+
+	foreach(@{$options->{'analysis'}}) {
+	    my $title = _createLegendName($_);
+	    my $colorNeg = shift(@color_set);
+	    my $colorPos = shift(@color_set);
+	    $legend = $legend . "<legendItem text=\"$title+\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $colorPos . "\" />\n";
+	    $legend = $legend . "<legendItem text=\"$title-\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $colorNeg . "\" />\n";
+	}
+    }
+
+    #blast legends
+    if (defined($options->{'blast'})) {
+	my @colors = @{$settings->{'blastColors'}};
+	foreach(@{$options->{'blast'}}) {
+	    my $title = "BLAST " . _createLegendName($_);
+	    my $color = shift(@colors);
+	    push(@colors, $color); 
+	    $legend = $legend . "<legendItem text=\"$title\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $color . "\" />\n";
+	}
+    }
+
+    #legend for various graphs
+    #at
+    if (_isTrue($options->{'at_content'})) {
+	if ($settings->{'atColorPos'} eq $settings->{'atColorNeg'}) {
+	    $legend = $legend . "<legendItem text=\"AT content\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'atColorPos'} . "\" />\n";
+	}
+	else {
+	    $legend = $legend . "<legendItem text=\"AT content+\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'atColorPos'} . "\" />\n";
+	    $legend = $legend . "<legendItem text=\"AT content-\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'atColorNeg'} . "\" />\n";
+	}
+    }
+    #at_skew
+    if (_isTrue($options->{'at_skew'})) {
+	if ($settings->{'atSkewColorPos'} eq $settings->{'atSkewColorNeg'}) {
+	    $legend = $legend . "<legendItem text=\"AT skew\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'atSkewColorPos'} . "\" />\n";
+	}
+	else {
+	    $legend = $legend . "<legendItem text=\"AT skew+\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'atSkewColorPos'} . "\" />\n";
+	    $legend = $legend . "<legendItem text=\"AT skew-\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'atSkewColorNeg'} . "\" />\n";
+	}
+    }
+    #gc
+    if (_isTrue($options->{'gc_content'})) {
+	if ($settings->{'gcColorPos'} eq $settings->{'gcColorNeg'}) {
+	    $legend = $legend . "<legendItem text=\"GC content\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'gcColorPos'} . "\" />\n";
+	}
+	else {
+	    $legend = $legend . "<legendItem text=\"GC content+\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'gcColorPos'} . "\" />\n";
+	    $legend = $legend . "<legendItem text=\"GC content-\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'gcColorNeg'} . "\" />\n";
+	}
+    }
+    #gc_skew
+    if (_isTrue($options->{'gc_skew'})) {
+	if ($settings->{'gcSkewColorPos'} eq $settings->{'gcSkewColorNeg'}) {
+	    $legend = $legend . "<legendItem text=\"GC skew\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'gcSkewColorPos'} . "\" />\n";
+	}
+	else {
+	    $legend = $legend . "<legendItem text=\"GC skew+\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'gcSkewColorPos'} . "\" />\n";
+	    $legend = $legend . "<legendItem text=\"GC skew-\" drawSwatch=\"true\" swatchOpacity=\"" . $settings->{'featureOpacity'} . "\" swatchColor=\"" . $settings->{'gcSkewColorNeg'} . "\" />\n";
+	}
+    }
+
+    $legend = $legend . "</legend>\n";
+
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- legend -->\n");
+    print (OUTFILE $legend);
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");  
+
+}
+
+sub _createLegendName {
+    my $file = shift;
+    my $name;
+    if ($file =~ m/\/([^\/]+)$/) {
+	$name = $1;
+	#remove extension
+	$name =~ s/\.[^\.]*$//;
+	$name =~ s/_/ /g;
+	#add underscores back to NCBI accession numbers (NM_181029 for example).
+	$name =~ s/([A-Z][A-Z])\s(\d{4,})/$1_$2/g;
+    }
+    if (defined($name)) {
+	return $name;
+    }
+    return $file;
+}
+
+sub _writeStopsAndStarts {
+    my $options = shift;
+    my $settings = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $rf = shift; #1,2, or 3
+
+    my $opacity = $settings->{'featureOpacity'};
+    my $startCodons = $options->{'starts'};
+    my $stopCodons = $options->{'stops'};
+   
+    my @outputArray = ();
+    if ($strand == 1) {
+	push (@outputArray, "<featureSlot showShading=\"false\" strand=\"direct\">\n");
+    }
+    else {
+	push (@outputArray, "<featureSlot showShading=\"false\" strand=\"reverse\">\n");
+    }
+
+    #add start and stop codons
+    my $dna;
+    if ($strand == 1) {
+ 
+	if ($rf == 1) {
+	    $dna = substr($seqObject->seq(), 0);
+	}
+	elsif ($rf == 2) {
+	    $dna = substr($seqObject->seq(), 1);
+	}
+	else {
+	    $dna = substr($seqObject->seq(), 2);
+	}
+
+
+	my $length = length($dna);
+	my $codon;
+	my $start;
+	my $stop;
+	my $feature;
+	my $featureRange;
+	#for start
+	for (my $i = 0; $i < $length - 2; $i = $i + 3) {
+	    $codon = substr($dna, $i, 3);
+	    if ($codon =~ m/$startCodons/i) {	  
+		$start = $i + $rf;
+		$stop = $start + 2;
+		$feature = "<feature color=\"" . $settings->{'startColor'} .  "\" decoration=\"arc\" opacity=\"$opacity\">\n";
+		$featureRange = "<featureRange start=\"$start\" stop=\"$stop\" proportionOfThickness=\"0.5\" />\n";
+		push (@outputArray, $feature . $featureRange . "</feature>\n");
+	    }
+	}
+
+	#for stop
+	for (my $i = 0; $i < $length - 2; $i = $i + 3) {
+	    $codon = substr($dna, $i, 3);
+	    if ($codon =~ m/$stopCodons/i) {	  
+		$start = $i + $rf;
+		$stop = $start + 2;
+		$feature = "<feature color=\"" . $settings->{'stopColor'} .  "\" decoration=\"arc\" opacity=\"$opacity\">\n";
+		$featureRange = "<featureRange start=\"$start\" stop=\"$stop\" proportionOfThickness=\"1.0\" />\n";
+		push (@outputArray, $feature . $featureRange . "</feature>\n");
+	    }
+	}	
+    }
+    elsif ($strand == -1) {
+	my $rev = $seqObject->revcom; 
+	$dna = $rev->seq();
+  
+	if ($rf == 1) {
+	    $dna = substr($dna, 0);
+	}
+	elsif ($rf == 2) {
+	    $dna = substr($dna, 1);
+	}
+	else {
+	    $dna = substr($dna, 2);
+	}
+
+	my $length = length($dna);
+	my $codon;
+	my $start;
+	my $stop;
+	my $feature;
+	my $featureRange;
+
+	#for start
+	for (my $i = 0; $i < $length - 2; $i = $i + 3) {
+	    $codon = substr($dna, $i, 3);
+	    if ($codon =~ m/$startCodons/i) {
+		#bug fix on 2009-09-01
+		#$start = $length - $i - 1 - $rf;
+		$start = $length - $i - 2;
+		$stop = $start + 2;
+		$feature = "<feature color=\"" . $settings->{'startColor'} .  "\" decoration=\"arc\" opacity=\"$opacity\">\n";
+		$featureRange = "<featureRange start=\"$start\" stop=\"$stop\" proportionOfThickness=\"0.5\" />\n";
+		push (@outputArray, $feature . $featureRange . "</feature>\n");
+	    }
+	}
+
+	#for stop
+	for (my $i = 0; $i < $length - 2; $i = $i + 3) {
+	    $codon = substr($dna, $i, 3);
+	    if ($codon =~ m/$stopCodons/i) {	  
+		#bug fix on 2009-09-01
+		#$start = $length - $i - 1 - $rf;
+		$start = $length - $i - 2;
+		$stop = $start + 2;
+		$feature = "<feature color=\"" . $settings->{'stopColor'} .  "\" decoration=\"arc\" opacity=\"$opacity\">\n";
+		$featureRange = "<featureRange start=\"$start\" stop=\"$stop\" proportionOfThickness=\"1.0\" />\n";
+		push (@outputArray, $feature . $featureRange . "</feature>\n");
+	    }
+	}
+    }
+
+    push (@outputArray, "</featureSlot>\n");  
+    my $strandTerm = undef;
+    if ($strand == 1) {
+	$strandTerm = "forward";
+    }
+    if ($strand == -1) {
+	$strandTerm = "reverse";
+    }
+
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- stops and starts in rf $rf on $strandTerm strand -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+
+sub _writeOrfs {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $rf = shift; #1,2, 3, or all
+
+    my $opacity = $settings->{'featureOpacity'};
+    my $startCodons = $options->{'starts'};
+    my $stopCodons = $options->{'stops'};
+    my $orfLength = $options->{'orf_size'};
+    my $color = $settings->{'orfColor'};
+    my $decoration;
+   
+    my @outputArray = ();
+
+    #for CGView server
+    my $shading = 'false';
+    if ((defined($options->{gene_decoration})) && ($options->{gene_decoration} eq 'arrow')) {
+	$shading = 'true';
+    }
+
+    if ($strand == 1) {
+	push (@outputArray, "<featureSlot showShading=\"$shading\" strand=\"direct\">\n");
+    }
+    else {
+	push (@outputArray, "<featureSlot showShading=\"$shading\" strand=\"reverse\">\n");
+    }
+
+    my @orfs = ();
+
+    if ($rf eq "all") {
+	push (@orfs, @{_getOrfs($options, $settings, $global, $seqObject, $strand, 1)});
+	push (@orfs, @{_getOrfs($options, $settings, $global, $seqObject, $strand, 2)});
+	push (@orfs, @{_getOrfs($options, $settings, $global, $seqObject, $strand, 3)});
+    }
+    else {
+	push (@orfs, @{_getOrfs($options, $settings, $global, $seqObject, $strand, $rf)});
+    }
+    
+    #sort orfs for visualization
+    if ($strand == 1) {
+	@orfs = @{_sortOrfs(\@orfs, 'start')};
+    }
+    elsif ($strand == -1) {
+	@orfs = @{_sortOrfs(\@orfs, 'stop')};
+    }
+
+    push (@outputArray, @orfs);
+
+    push (@outputArray, "</featureSlot>\n");  
+    my $strandTerm = undef;
+    if ($strand == 1) {
+	$strandTerm = "forward";
+    }
+    if ($strand == -1) {
+	$strandTerm = "reverse";
+    }
+
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- ORFs in rf $rf on $strandTerm strand -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+sub _sortOrfs {
+    my $orfs = shift;
+    my $field = shift;
+
+    @$orfs = map { $_->[1] }
+      sort { $b->[0] <=> $a->[0]}
+      map { [ _getSortValueOrfs($_, $field), $_] }
+      @$orfs;
+    
+    return $orfs;
+}
+
+sub _getSortValueOrfs {
+    my $orf = shift;
+    my $field = shift;
+
+    $orf =~ m/$field=\"(\d+)\"/;
+    return $1;
+}
+
+sub _getOrfs {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $rf = shift; #1,2, or 3
+    my $rfForLabel = $rf;
+
+    my $opacity = $settings->{'featureOpacity'};
+    my $startCodons = $options->{'starts'};
+    my $stopCodons = $options->{'stops'};
+    my $orfLength = $options->{'orf_size'};
+    my $color = $settings->{'orfColor'};
+    my $decoration;
+
+    if ($strand == 1) {
+	$decoration = "clockwise-arrow";
+    }
+    else {
+	$decoration = "counterclockwise-arrow";
+    }
+
+    #for CGView server
+    if ((defined($options->{gene_decoration})) && ($options->{gene_decoration} eq 'arc')) {
+	$decoration = "arc";
+    }
+   
+    my @orfs = ();
+
+    my $dna;
+    if ($strand == 1) {
+	$dna = $seqObject->seq();
+    }
+    else {
+ 	my $rev = $seqObject->revcom; 
+	$dna = $rev->seq();     
+    }
+    my $length = length($dna);
+    my $i = 0;
+    my $codon;
+    my $foundStart = 0;
+    my $proteinLength = 0;
+    my $foundStop = 0;
+    my $startPos = $rf - 1;
+    my $feature;
+    my $featureRange;
+    my $firstBase;
+    my $lastBase;
+    my $temp;
+
+    my @dna = ();
+
+    while ($i <= $length - 3)	{
+	for ($i = $startPos; $i <= $length - 3; $i = $i + 3)	{
+	    $codon = substr($dna,$i,3);
+	    if (($startCodons ne "any") && ($foundStart == 0) && (!($codon =~ m/$startCodons/i)))	{
+		last;
+	    }
+	    $foundStart = 1;
+	    
+	    if ($codon =~ m/$stopCodons/i) {
+		$foundStop = 1;
+	    }
+		
+	    $proteinLength++;
+	    push (@dna, $codon);
+
+	    if (($foundStop) && ($proteinLength < $orfLength))	{
+		last;
+	    }
+	    if ((($foundStop) && ($proteinLength >= $orfLength)) || (($i >= $length - 5) && ($proteinLength >= $orfLength)))	{
+		$firstBase = $startPos + 1;
+		$lastBase = $i + 3;
+
+		if ($strand == -1) {
+		    $temp = $length - $lastBase + 1;
+		    $lastBase = $length - $firstBase + 1;
+		    $firstBase = $temp;		    
+		}
+
+		$global->{orfCount}++;
+
+		$feature = "<feature color=\"$color\" decoration=\"$decoration\" opacity=\"$opacity\" ";
+
+		if (_isTrue($options->{orf_labels})) {
+		    $feature = $feature . "label=\"orf_$global->{orfCount}\" ";
+		    $feature = $feature . "mouseover=\"" . _escapeText("orf_$global->{orfCount}; $firstBase to $lastBase; strand=$strand; rf=$rfForLabel") . "\" ";
+		}
+		$feature = $feature . ">\n";
+
+		$featureRange = "<featureRange start=\"$firstBase\" stop=\"$lastBase\" />\n";
+		push (@orfs, $feature . $featureRange . "</feature>\n");
+       
+		last;
+	    }
+	}
+	$startPos = $i + 3;
+	$i = $startPos;
+	$foundStart = 0;
+	$foundStop = 0;
+	$proteinLength = 0;
+	@dna = ();
+    }
+
+    return \@orfs;
+
+}
+
+
+sub _expand_complex_features {
+    my $seq_object = shift ();
+    my @features = $seq_object->get_SeqFeatures();
+    for my $feature (@features) {
+
+	#check to see of the location is split (ie. complex feature)
+	if ($feature->location->isa('Bio::Location::SplitLocationI')) {
+	    for my $sub_location ($feature->location->sub_Location) {
+
+		#create a new split feature based on the original feature
+		my $split_feature = new Bio::SeqFeature::Generic (
+							      -display_name => $feature->display_name,
+							      -strand => $feature->strand,
+							      -primary_tag => $feature->primary_tag,
+							      -frame => $feature->frame,);
+		#copy all the tags
+		for my $tag ($feature->all_tags) {
+		    for my $value ($feature->each_tag_value($tag)) {
+		       $split_feature->set_attributes (-tag => {$tag => $value});
+		    }
+		}
+
+		#set the location of the split feature to the sub location
+		$split_feature->location($sub_location);
+		$seq_object->add_SeqFeature($split_feature);
+	    }
+	#change original feature type to 'del_feat' which will be excluded later
+	#therefore the original complex feature will be excluded from drawing
+       	$feature->primary_tag('del_feat');
+	}
+    }
+}
+
+
+sub _writeEmblGenes {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $rf = shift; #1,2,3, or undefined for all reading frames
+    _writeGenBankGenes($options, $settings, $global, $seqObject, $strand, $rf);
+}
+
+sub _writeGenBankGenes {
+ 
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $rf = shift; #1,2,3, or undefined for all reading frames
+
+    my $opacity;
+    
+    #make rf 
+    if ((defined($rf)) && ($rf == 3)) {
+	$rf = 0;
+    }
+
+    my @outputArray = ();
+
+    #for CGView server
+    my $shading = 'false';
+    if ((defined($options->{gene_decoration})) && ($options->{gene_decoration} eq 'arrow')) {
+	$shading = 'true';
+    }
+
+    my $decoration;
+    if ($strand == 1) {
+	push (@outputArray, "<featureSlot showShading=\"$shading\" strand=\"direct\">\n");
+	$decoration = "clockwise-arrow";
+    }
+    else {
+	push (@outputArray, "<featureSlot showShading=\"$shading\" strand=\"reverse\">\n");
+	$decoration = "counterclockwise-arrow";
+    }
+
+    #for CGView server
+    if ((defined($options->{gene_decoration})) && ($options->{gene_decoration} eq 'arc')) {
+	$decoration = "arc";
+    }
+   
+    #need to get the features from from the GenBank record.
+    my @features = $seqObject->get_SeqFeatures();
+    @features = @{_sortFeaturesByStart(\@features)};
+
+    if ($strand == 1) {
+	@features = reverse(@features);
+    }
+
+    foreach(@features) {
+	my $feat = $_;
+	my $type = lc($feat->primary_tag);
+	my $color;
+
+	if ($type eq "cds") {
+	    $color = $settings->{'proteinColor'};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+#	elsif ($type eq "exon") {
+#	    $color = $settings->{'proteinColor'};
+#	    $opacity = $settings->{'featureOpacity'};
+#	}
+
+	elsif ($type eq "rrna") {
+	    $color = $settings->{'rRNAColor'};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+	elsif ($type eq "trna") {
+	    $color = $settings->{'tRNAColor'};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+	else {
+	    $color = $settings->{'otherColor'};
+	    $opacity = $settings->{'featureOpacityOther'};
+#	    $decoration = "arc";
+	}
+
+	#skip certain feature types
+	if ($type eq "source") {
+	    next;
+	}
+	if ($type eq "gene") {
+	    next;
+	}
+	if ($type eq "exon") {
+	    next;
+	}
+	if ($type eq "del_feat") {
+	    next;
+	}
+#	if ($type eq "misc_feature") {
+#	    next;
+#	}
+	
+	my $st = $feat->strand;
+	unless($st == $strand) {
+	    next;
+	}
+
+	my $start = $feat->start;
+	my $stop = $feat->end;
+
+	#this handles feature that spans start/stop
+	#UPDATE: all features with more than 1 entry in @loc are skipped below
+
+	my $location = $feat->location;
+	my $locString = $location->to_FTstring;
+	my @loc = split(/,/, $locString);
+
+	if ($loc[0] =~ m/(\d+)\.\.(\d+)/) {
+	    $start = $1;
+	}
+
+	if ($loc[scalar(@loc) - 1] =~ m/(\d+)\.\.(\d+)/) {
+	    $stop = $2;
+	}
+	
+	if (defined($rf)) {
+	    if ($strand == 1) {
+		unless ($rf == $start % 3) {
+		    next;
+		}
+	    }
+	    elsif ($strand == -1) {
+		unless ($rf ==  ($seqObject->length() - $stop + 1)% 3) {
+		    next;
+		}
+	    }
+	}
+
+	my $label;
+	if ($feat->has_tag('gene')) {
+	    $label = join("",$feat->get_tag_values('gene'));
+	}
+	elsif ($feat->has_tag('locus_tag')) {
+	    $label = join("",$feat->get_tag_values('locus_tag'));
+	}
+	elsif ($feat->has_tag('note')) {
+	    $label = join("",$feat->get_tag_values('note'));	
+	}
+	else {
+	    $label = $feat->primary_tag;
+	}
+
+	if ($feat->primary_tag eq 'intron') {
+	    $label .= " (intron)";
+	}
+
+	if (length($label) > $settings->{'maxLabelLength'} - 3) {
+	    $label = substr($label, 0, $settings->{'maxLabelLength'} - 3) . "...";
+	}
+	$label = _escapeText($label);
+
+        #/db_xref="GI:11497049"
+	my $hyperlink;
+	if ($feat->has_tag('db_xref')) {
+	    my $dbXref = join("",$feat->get_tag_values('db_xref'));
+	    if ($dbXref =~ m/GI\:(\d+)/) {
+		$hyperlink = $global->{'ncbiGiLink'} . $1;
+	    }
+	    #/db_xref="GeneID:1132092"
+	    elsif ($dbXref =~ m/GeneID\:(\d+)/) {
+		$hyperlink = $global->{'ncbiGeneLink'} . $1;
+	    }
+	}
+
+	#/product="conserved hypothetical protein"
+	my $mouseover = $label . "; " . $start . " to " . $stop;
+	if ($feat->has_tag('product')) {
+	    my $product = join("",$feat->get_tag_values('product'));
+	    $mouseover = $mouseover . "; " . $product;
+	}
+	if ($feat->has_tag('db_xref')) {
+	    my $dbXref = join("",$feat->get_tag_values('db_xref'));
+	    if ($dbXref =~ m/(GI\:\d+)/) {
+		$mouseover = $mouseover .  "; " . $1;
+	    }
+	    #/db_xref="GeneID:1132092"
+	    elsif ($dbXref =~ m/(GeneID\:\d+)/) {
+		$mouseover = $mouseover .  "; " . $1;
+	    }	
+	}
+	$mouseover = _escapeText($mouseover);	    
+
+	#check length of feature
+	my $featLength = $stop - $start + 1;
+	if (scalar(@loc) > 1) {
+	    _message($options, "The following feature of type '$type' has a complex location string and will be ignored: label: $label");
+	    next;
+	}
+	if ($featLength == 0) {
+	    _message($options, "The following feature of type '$type' has length equal to zero and will be ignored: label: $label; start: $start; end: $stop");
+	    next;
+	}
+	if ($featLength < 0) {
+	    _message($options, "The following feature of type '$type' has 'start' less than 'end' and will be ignored: label: $label; start: $start; end: $stop");
+	    next;
+	}
+	if ($featLength > $settings->{maxFeatureSize}) {
+	    _message($options, "The following feature of type '$type' has length greater than $settings->{maxFeatureSize} and will be ignored: label: $label; start: $start; end: $stop");
+	    next;
+	}
+	if ($featLength == $seqObject->length()) {
+	    _message($options, "The following feature of type '$type' has length equal to the length of the entire sequence and will be ignored: label: $label; start: $start; end: $stop");
+	    next;
+	}
+
+	#now check entries and make tags
+	my $feature = "<feature color=\"$color\" decoration=\"$decoration\" opacity=\"$opacity\" ";
+
+	if (_isTrue($options->{feature_labels})) {
+	    if (_containsText($label)) {
+		$feature = $feature . "label=\"$label\" ";
+	    }
+	    if (_containsText($hyperlink)) {
+		$feature = $feature . "hyperlink=\"$hyperlink\" ";		
+	    }
+	    if (_containsText($mouseover)) {
+		$feature = $feature . "mouseover=\"$mouseover\" ";		
+	    }
+	}
+
+	$feature = $feature . ">\n";
+
+	my $featureRange = "<featureRange start=\"$start\" stop=\"$stop\" />\n";
+
+	#now add $feature and $featureRange to @outputArray
+	push (@outputArray, $feature . $featureRange . "</feature>\n");	
+
+
+    }
+
+
+    push (@outputArray, "</featureSlot>\n"); 
+    my $strandTerm = undef;
+    if ($strand == 1) {
+	$strandTerm = "forward";
+    }
+    if ($strand == -1) {
+	$strandTerm = "reverse";
+    }
+    
+    my $rfTerm = undef;
+    if (!(defined($rf))) {
+	$rfTerm = "1,2,3";
+    }
+    else {
+	$rfTerm = $rf;
+    }
+    
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- GenBank or EMBL genes on strand $strandTerm in rf $rfTerm -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+sub _sortFeaturesByStart {
+    my $features = shift;
+
+    @$features = map { $_->[1] }
+      sort { $a->[0] <=> $b->[0]}
+      map { [ _getSortValueFeature($_), $_] }
+      @$features;
+    
+    return $features;
+}
+
+sub _getSortValueFeature {
+    my $feature = shift;
+    return $feature->start;
+}
+
+sub _containsText {
+    my $text = shift;
+
+    if (!(defined($text))) {
+	return 0;
+    }
+    if ($text =~ m/[A-Za-z0-9]/g) {
+	return 1;
+    }
+    else {
+	return 0;
+    }
+}
+
+sub _writeGenes {
+
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $rf = shift; #1,2,3, or undefined for all reading frames
+    my $analysisColorPos = shift;
+    my $analysisColorNeg = shift;
+    my $file = shift;
+    my $useScore = shift;
+    my $standardBarGraph = 0;
+    
+    my $opacity = $settings->{'featureOpacity'};
+    
+ 
+    if ((defined($rf)) && ($rf == 3)) {
+	$rf = 0;
+    }
+
+    my @outputArray = ();
+
+    #for CGView server
+    my $shading = 'false';
+    if ((defined($options->{gene_decoration})) && ($options->{gene_decoration} eq 'arrow')) {
+	$shading = 'true';
+    }
+
+    my $decoration;
+    if (!($useScore)) {
+	if ($strand == 1) {
+	    push (@outputArray, "<featureSlot showShading=\"$shading\" strand=\"direct\">\n");
+	    $decoration = "clockwise-arrow";
+	}
+	else {
+	    push (@outputArray, "<featureSlot showShading=\"$shading\" strand=\"reverse\">\n");
+	    $decoration = "counterclockwise-arrow";
+	}
+    }
+    else {
+	if ($strand == 1) {
+	    push (@outputArray, "<featureSlot showShading=\"false\" strand=\"direct\" featureThickness=\"" . $settings->{'featureThicknessPlot'} . "\">\n");
+	}
+	else {
+	    push (@outputArray, "<featureSlot showShading=\"false\" strand=\"reverse\" featureThickness=\"" . $settings->{'featureThicknessPlot'} . "\">\n");
+	}
+	$decoration = "arc";
+    }
+
+    #for CGView server
+    if ((defined($options->{gene_decoration})) && ($options->{gene_decoration} eq 'arc')) {
+	$decoration = "arc";
+    }
+
+    #need to get the features from the file.
+    my @features = ();
+    @features = @{_parseGFF($file, $options, $settings, $global, $seqObject)};
+
+    @features = @{_sortGFFByStart(\@features)};
+
+    if ($strand == 1) {
+	@features = reverse(@features);
+    }
+
+    #This section was added 2007-05-30 to normalize score values for plotting
+    #
+    if (defined($useScore)) {
+	my $min = undef;
+	my $max = undef;
+	my $average = undef;
+	my $sum = 0;
+	my $count = 0;
+	foreach(@features) {
+	    my $score;
+	    if ($_->{score} =~ m/(\-?[\d\.e\-]+)/) {
+		$score = $1;
+		$sum = $sum + $score;
+		if ((!(defined($max))) || ($score > $max)) {
+		    $max = $score;
+		}
+		if ((!(defined($min))) || ($score < $min)) {
+		    $min = $score;
+		}
+		$count++;
+	    }
+	}
+
+	#Added 2009-02-22 to allow data sets consisting of all positive values to be plotted as a standard bar graph. 
+	if ((defined($min)) && ($min >= 0)) {
+	    $standardBarGraph = 1;
+	    $max = sprintf("%.4f", $max);
+	    $min = sprintf("%.4f", $min);
+
+	    _message($options, "Scaling score values in the file $file to between 0 and 1.");
+	    _message($options, "The maximum score value is $max.");
+	    _message($options, "The minimum score value is $min.");
+
+	    #adjust the score values so that the full width of the featureSlot is used.
+	    foreach(@features) {
+		my $score;
+		if ($_->{score} =~ m/(\-?[\d\.e\-]+)/) {
+		    $score = $1;
+		    $_->{score} = sprintf("%.4f", $score / $max);
+		}
+	    }
+	}
+
+	#If there are negative values, the x-axis is positioned in the middle of the featureSlot
+	elsif ((defined($min)) && ($min < 0)) {
+	    $average = $sum / $count;
+
+	    $average = sprintf("%.4f", $average);
+	    $max = sprintf("%.4f", $max);
+	    $min = sprintf("%.4f", $min);
+
+	    _message($options, "Scaling score values in the file $file to between 1 and -1.");
+	    _message($options, "The maximum score value is $max.");
+	    _message($options, "The minimum score value is $min.");
+	    _message($options, "The average score value is $average.");
+
+	    my $maxDeviation;
+	    if (($max - $average) > ($average - $min)) {
+		$maxDeviation = $max - $average;
+	    }
+	    else {
+		$maxDeviation = $average - $min;
+	    }
+
+	    #adjust the score values so that the full width of the featureSlot is used.
+	    foreach(@features) {
+		my $score;
+		if ($_->{score} =~ m/(\-?[\d\.e\-]+)/) {
+		    $score = $1;
+		    $_->{score} = sprintf("%.4f", ($score - $average) / $maxDeviation);
+		}
+	    }
+	}
+
+
+    }
+
+   
+    foreach(@features) {
+	my $feat = $_;
+	my $type = lc($feat->{'feature'});
+
+	#the genes in the GFF file can be coloured by the 'feature' column, based on the 
+	#type of gene (CDS, rRNA, tRNA, or other) or by COG (J, K, L etc).
+	#colour based on feature type first
+	my $color;
+	if ((defined($analysisColorPos)) && (defined($analysisColorNeg))) {
+	    $color = undef;
+	}
+	elsif ($type eq "cds") {
+	    $color = $settings->{'proteinColor'};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+	elsif ($type eq "rrna") {
+	    $color = $settings->{'rRNAColor'};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+	elsif ($type eq "trna") {
+	    $color = $settings->{'tRNAColor'};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+	elsif ($type eq "other") {
+	    $color = $settings->{'otherColor'};
+	    $opacity = $settings->{'featureOpacityOther'};
+	}
+	elsif (defined($settings->{'cogColors'}->{uc($type)})) {
+	    $color = $settings->{'cogColors'}->{uc($type)};
+	    $opacity = $settings->{'featureOpacity'};
+	}
+	else {
+	    $color = $settings->{'otherColor'};
+	    $opacity = $settings->{'featureOpacityOther'};
+	}
+	
+	my $st = $feat->{'strand'};
+	if ($st eq "+") {
+	    $st = 1;
+	}
+	elsif ($st eq "-") {
+	    $st = -1;	    
+	}
+
+	#when using score keep all features regardless of strand
+	if (($st ne $strand) && (!$useScore)) {
+	    next;
+	}
+
+	my $start = $feat->{'start'};
+	my $stop = $feat->{'end'};
+
+	if (defined($rf)) {
+	    if ($strand == 1) {
+		unless ($rf == $start % 3) {
+		    next;
+		}
+	    }
+	    elsif ($strand == -1) {
+		unless ($rf ==  ($seqObject->length() - $stop + 1)% 3) {
+		    next;
+		}
+	    }
+	}
+
+	my $label;
+	if (_containsText($feat->{'seqname'})) {
+	    $label = $feat->{'seqname'};
+	    if (length($label) > $settings->{'maxLabelLength'} - 3) {
+		$label = substr($label, 0, $settings->{'maxLabelLength'} - 3) . "...";
+	    }
+	    $label = _escapeText($label);
+	}
+
+	my $mouseover;
+	if (_containsText($label)) {
+	    $mouseover = $label . "; " . $start . " to " . $stop;
+	}
+	else {
+	    $mouseover = $start . " to " . $stop;
+	}
+	if (_containsText($feat->{'feature'})) {
+	    $mouseover = $mouseover . "; " . $feat->{'feature'};
+	    $mouseover = _escapeText($mouseover);
+	}
+
+	#now check entries and make tags
+	my $feature;
+	if (defined($color)) {
+	    $feature = "<feature color=\"$color\" decoration=\"$decoration\" opacity=\"$opacity\" ";
+	}
+	else {
+	    $feature = "<feature decoration=\"$decoration\" opacity=\"$opacity\" ";
+	}
+
+	#don't label genes when $useScore defined
+	if ((_isTrue($options->{gene_labels})) && (!$useScore)) {
+	    if (_containsText($label)) {
+		$feature = $feature . "label=\"$label\" ";
+	    }
+	    if (_containsText($mouseover)) {
+		$feature = $feature . "mouseover=\"$mouseover\" ";		
+	    }
+	}
+
+	$feature = $feature . ">\n";
+
+	my $featureRange;
+	if (defined($useScore)) {
+	    #score should be between -1 and 1 at this point
+	    my $score;
+	    if (defined($feat->{'score'})) {
+		if ($feat->{'score'} =~ m/(\-?[\d\.e\-]+)/) {
+		    $score = $1;
+		}
+	    }
+	    if (defined($score)) {
+		if ($score > 1) {
+		    $score = 1;
+		}
+		if ($score < -1) {
+		    $score = -1;
+		}
+	    }
+	    else {
+		$score = 0;
+	    }
+
+	    #Want to draw as bars with positive values extending outwards and negative values extending inwards.
+	    #If $standardBarGraph == 1, draw as bars with all values extending outwards.
+	    my $barHeight;
+	    my $radiusShift;
+
+	    if ($standardBarGraph) {
+		$barHeight = $score;
+		$radiusShift = $barHeight / 2.0;
+		$color = $analysisColorPos;
+	    }
+	    elsif ($score > 0) {
+		$barHeight = $score;
+		$barHeight = $barHeight * 0.5;
+		$radiusShift = 0.5 + $barHeight / 2.0;
+		$color = $analysisColorPos;
+	    }
+	    elsif ($score < 0) {
+		$barHeight = 0 - $score;
+		$barHeight = $barHeight * 0.5;
+		$radiusShift = 0.5 - $barHeight / 2;
+    		$color = $analysisColorNeg;
+	    }
+	    else {
+		$radiusShift = 0.5;
+		$barHeight = $settings->{'plotLineThickness'};
+        	$color = $analysisColorPos;
+	    }
+
+	    $featureRange = "<featureRange start=\"$start\" stop=\"$stop\" radiusAdjustment=\"$radiusShift\" proportionOfThickness=\"$barHeight\" color=\"$color\" />\n";
+	}
+	else {
+	    $featureRange = "<featureRange start=\"$start\" stop=\"$stop\" />\n";
+	}
+
+	#now add $feature and $featureRange to @outputArray
+	push (@outputArray, $feature . $featureRange . "</feature>\n");		
+    }
+
+    #Create dashed line to indicate zero
+    if (defined($useScore)) {
+	#here a dash is a dash and the space following it.
+#	if (_isTrue($options->{draw_divider_rings})) {
+	    my $length = $seqObject->length();
+	    my $number_of_dashes = 500;
+	    my $bases_per_dash = $length / $number_of_dashes;
+	    $bases_per_dash = sprintf("%.0f", $bases_per_dash);
+	    if ($bases_per_dash < 2) {
+		$bases_per_dash = 2;
+	    }
+	    my $i = 1;
+
+	    #make the dashed line the same thickness as the divider_ring
+	    my $dashed_line_proportion = ($settings->{backboneThickness} * 0.25) / $settings->{featureThicknessPlot};
+	    if ($dashed_line_proportion > 0.05) {
+		$dashed_line_proportion = 0.05;
+	    }
+	    my $dashed_line_shift = 0.5;
+
+	    push (@outputArray, "<feature radiusAdjustment=\"$dashed_line_shift\" proportionOfThickness=\"$dashed_line_proportion\" color=\"$settings->{backboneColor}\">\n");
+
+	    while ($i < $length) {
+		my $start = $i;
+		my $stop = $start + sprintf("%.0f", $bases_per_dash / 2);
+		if ($stop > $length) {
+		    $stop = $length;
+		}
+		push (@outputArray, "<featureRange start=\"$start\" stop=\"$stop\" />\n");
+		$i = $i + $bases_per_dash;
+	    }
+
+	    push (@outputArray, "</feature>\n");
+#	}
+    }
+
+    push (@outputArray, "</featureSlot>\n"); 
+    my $strandTerm = undef;
+    if ($strand == 1) {
+	$strandTerm = "forward";
+    }
+    if ($strand == -1) {
+	$strandTerm = "reverse";
+    }
+    
+    my $rfTerm = undef;
+    if (!(defined($rf))) {
+	$rfTerm = "1,2,3";
+    }
+    else {
+	$rfTerm = $rf;
+    }
+    
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- genes or analysis on $strandTerm strand in rf $rfTerm -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+sub _parseGFF {
+    my $file = shift;
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $lineCount = 0;
+    my @columnTitles = ();
+    my $columnsRead = 0;
+    open (INFILE, $file) or die ("Cannot open the GFF file $file");
+    
+    #check for column titles
+    while (my $line = <INFILE>) {
+	$line =~ s/\cM|\n//g;
+	$lineCount++;
+	if ($line =~ m/^\#/) {
+	    next;
+	}
+	if ($line =~ m/\S/) {
+	    $columnsRead = 1;
+	    @columnTitles = @{_split($line)};
+	    last;
+	}
+    }
+    #print Dumper(@columnTitles);
+    my @gffColumns = ("seqname", "source", "feature", "start", "end", "score", "strand", "frame");
+
+    for (my $i = 0; $i < scalar(@gffColumns); $i++) {
+	if (!(defined($columnTitles[$i]))) {
+	    _message($options, "Column $i in GFF file $file was not defined - must be titled \"$gffColumns[$i]\".");
+	    die ("Column $i in GFF file $file was not defined - must be titled \"$gffColumns[$i]\""); 	    
+	}
+	elsif ($gffColumns[$i] ne lc($columnTitles[$i])) {
+	    _message($options, "Column $i in GFF file $file was titled $columnTitles[$i] - must be titled \"$gffColumns[$i]\".");
+	   die ("Column $i in GFF file $file was titled $columnTitles[$i] - must be titled \"$gffColumns[$i]\""); 
+	}
+    }
+
+    #To allow for 'start', 'end', 'strand', and 'frame' values to be read from the '-sequence' file
+    #build a hash of genes.
+    my $sequenceGenes = _getFeatures($global, $seqObject);
+
+    #print (Dumper($sequenceGenes));
+
+    my @entries = ();
+    while (my $line = <INFILE>) {    
+	$line =~ s/\cM|\n//g;
+	$lineCount++;
+	if ($line =~ m/\S/) {
+	    my @values = @{_split($line)};
+	    my %entry = ();
+	    for (my $i = 0; $i < scalar(@gffColumns); $i++) {
+		$entry{$gffColumns[$i]} = $values[$i];
+	    }	    
+	    
+	    #try to add to entry if needed
+	    _addToEntry(\%entry, $sequenceGenes);
+
+	    if (!(defined($entry{'start'}))) {
+		if (defined($entry{'seqname'})) {
+		    _message($options, "Warning: unable to obtain 'start' value for seqname $entry{seqname} in $file line $lineCount.");	    
+		}
+		else {
+		    _message($options, "Warning: unable to obtain 'start' value for $file line $lineCount.");
+		}
+		next;
+	    }
+
+	    if (!(defined($entry{'end'}))) {
+		if (defined($entry{'seqname'})) {
+		    _message($options, "Warning: unable to obtain 'end' value for seqname $entry{seqname} in $file line $lineCount.");	    
+		}
+		else {
+		    _message($options, "Warning: unable to obtain 'end' value for $file line $lineCount.");
+		}
+		next;
+	    }
+
+	    if (!(defined($entry{'strand'}))) {
+		if (defined($entry{'seqname'})) {
+		    _message($options, "Warning: unable to obtain 'strand' value for seqname $entry{seqname} in $file line $lineCount.");	    
+		}
+		else {
+		    _message($options, "Warning: unable to obtain 'strand' value for $file line $lineCount.");
+		}
+		next;
+	    }
+
+	    if (!($entry{'start'} =~ m/^\d+$/)) {
+		_message($options, "Warning: value in 'start' column must be a positive integer in $file line $lineCount.");
+		next;
+		#die ("Value in 'start' column must be a positive integer in $file line $lineCount");
+	    }
+	    if (!($entry{'end'} =~ m/^\d+$/)) {
+		_message($options, "Warning: value in 'end' column must be a positive integer in $file line $lineCount.");
+		next;
+		#die ("Value in 'end' column must be a positive integer in $file line $lineCount");
+	    }
+	    if (!($entry{'strand'} =~ m/^(\+|\-|\.|\s)$/)) {
+		_message($options, "Warning: value in 'strand' column must be '+', '-', or '.' in $file line $lineCount.");
+		next;
+		#die ("Value in 'strand' column must be '+', '-', or '.' in $file line $lineCount");
+	    }
+
+	    #check start and end
+	    if ($entry{'start'} > $global->{length}) {
+		_message($options, "Warning: value in 'start' column must be less that the sequence length in $file line $lineCount.");
+		next;
+		#die ("Value in 'start' column must be less that the sequence length in $file line $lineCount");
+	    }
+	    if ($entry{'end'} > $global->{length}) {
+		_message($options, "Warning: value in 'end' column must be less that the sequence length in $file line $lineCount.");
+		next;
+		#die ("Value in 'end' column must be less that the sequence length in $file line $lineCount");
+	    }
+
+	    #Added 2008_07_31
+	    #users often swap the start and end values for features located on the negative strand. 
+	    #check for start > end and swap the values if it makes the feature shorter
+	    if ($entry{'start'} > $entry{'end'}) {
+		my $around_origin_length = ($entry{'end'} - 1 + 1) + ($global->{length} - $entry{'start'} + 1);
+		my $direct_length = $entry{'start'} - $entry{'end'} + 1;
+		if ($direct_length < $around_origin_length) {
+		    ($entry{'start'}, $entry{'end'}) = ($entry{'end'}, $entry{'start'});
+		    _message($options, "Warning: swapping values in 'start' and 'end' column so that 'start' is less than 'end' in $file line $lineCount.");
+		}
+	    }	    
+	    
+	    push (@entries, \%entry);
+	}
+    }
+    close (INFILE) or die( "Cannot close file : $!");
+    return \@entries;
+}
+
+sub _addToEntry {
+    my $entry = shift;
+    my $genBankFeatures = shift;
+    
+    if ((defined($entry->{'seqname'})) && (defined($genBankFeatures->{$entry->{'seqname'}})) && (!(defined($genBankFeatures->{$entry->{'seqname'}}->{multiples})))) {
+	#will try to determine start, end, strand
+	if ((!(defined($entry->{'start'}))) || (!($entry->{'start'} =~ m/^\d+$/))) {
+	    $entry->{'start'} = $genBankFeatures->{$entry->{'seqname'}}->{start};
+	}
+	if ((!(defined($entry->{'end'}))) || (!($entry->{'end'} =~ m/^\d+$/))) {
+	    $entry->{'end'} = $genBankFeatures->{$entry->{'seqname'}}->{end};
+	}
+	if ((!(defined($entry->{'strand'}))) || (!($entry->{'strand'} =~ m/^(\+|\-|\.)$/))) {
+	    $entry->{'strand'} = $genBankFeatures->{$entry->{'seqname'}}->{strand};
+	}
+    }
+}
+
+sub _getFeatures {
+    my $global = shift;
+    my $seqObject = shift;
+
+    if (($global->{format} ne "genbank") && ($global->{format} ne "embl")) {
+	return undef;
+    }
+
+    #need to get the features from from the GenBank record.
+    my @features = $seqObject->get_SeqFeatures();
+    @features = @{_sortFeaturesByStart(\@features)};
+
+    my %featureHash = ();
+    foreach(@features) {
+	my $feat = $_;
+
+	my $type = lc($feat->primary_tag);
+
+
+	################
+	#added 2007-10-10
+	#
+	#Some GenBank files may contain entries like the following:
+	#
+	#     gene            complement(1646..1774)
+        #                     /locus_tag="MM1_0006"
+        #     CDS             complement(1646..1774)
+        #                     /locus_tag="MM1_0006"
+	#
+	#These features share the same /locus_tag,
+	#which was causing this script to declare 
+	#the /locus_tag as having multiple positions.
+	#This new code block skips several feature types
+	#that are not drawn on the map anyway, and 
+	#this avoids the problem of having multiple
+	#positions in many cases.
+	if ($type eq "source") {
+	    next;
+	}
+	if ($type eq "gene") {
+	    next;
+	}
+	if ($type eq "exon") {
+	    next;
+	}
+	if ($type eq "del_feat") {
+	    next;
+	}
+	#################
+
+	my $strand = $feat->strand;
+	my $start = $feat->start;
+	my $stop = $feat->end;
+
+	#this handles feature that spans start/stop
+	my $location = $feat->location;
+	my $locString = $location->to_FTstring;
+	my @loc = split(/,/, $locString);
+
+	if ($loc[0] =~ m/(\d+)\.\.(\d+)/) {
+	    $start = $1;
+	}
+
+	if ($loc[scalar(@loc) - 1] =~ m/(\d+)\.\.(\d+)/) {
+	    $stop = $2;
+	}
+	
+	my $rf;
+	if ($strand == 1) {
+	    $rf = $start % 3;
+	}
+	elsif ($strand == -1) {
+	    $rf = ($seqObject->length() - $stop + 1) % 3;
+	}
+	
+	if ($rf == 0) {
+	    $rf = 3;
+	}
+
+	my $geneName;
+	if ($feat->has_tag('locus_tag')) {
+	    $geneName = join("",$feat->get_tag_values('locus_tag'));
+	}
+
+	if (!(defined($geneName))) {
+	    next;
+	}
+
+	#change some values
+	if ($strand == -1) {
+	    $strand = "-";
+	}
+	else {
+	    $strand = "+";
+	}
+
+	#add this info to the geneHash
+	my %geneHash = (start => undef,
+			end => undef,
+		        strand => undef,
+			rf => undef);
+
+	$geneHash{start} = $start;
+	$geneHash{end} = $stop;
+	$geneHash{rf} = $rf;
+	$geneHash{strand} = $strand;
+
+	if (defined($featureHash{$geneName})) {
+	    #if multiple genes have the same tag, mark this gene with the multiples key
+	    $featureHash{$geneName}->{multiples} = 1;
+	}
+	else {
+	    $featureHash{$geneName} = \%geneHash;
+	}
+    }
+    return \%featureHash;
+}
+
+sub _split {
+    my $line = shift;
+    my @values = ();
+    if ($line =~ m/\t/) {
+	@values = split(/\t/, $line);
+    }
+    elsif ($line =~ m/\,/) {
+	@values = split(/\,/, $line); 
+    }
+    else {
+	@values = split(/\s/, $line); 
+    }
+    foreach(@values) {
+	$_ = _cleanValue($_);
+    }
+    return \@values;
+}
+
+sub _sortGFFByStart {
+    my $features = shift;
+
+    @$features = map { $_->[1] }
+      sort { $a->[0] <=> $b->[0]}
+      map { [ _getSortValueGFF($_), $_] }
+      @$features;
+    
+    return $features;
+}
+
+sub _getSortValueGFF {
+    my $feature = shift;
+    return $feature->{'start'};
+}
+
+sub _cleanValue {
+    my $value = shift;
+    if (!defined($value)) {
+	return ".";
+    }
+    if ($value =~ m/^\s*$/) {
+	return ".";
+    }
+    $value =~ s/^\s+//g;
+    $value =~ s/\s+$//g;
+    $value =~ s/\"|\'//g;
+    return $value;
+}
+
+
+
+sub _writeFooter {
+    my $options = shift;
+    my $footer = "</cgview>\n";
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE $footer);
+    close (OUTFILE) or die( "Cannot close file : $!");
+}
+
+
+sub _writeBlast {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift;
+    my $file = shift;
+    my $color = shift;
+    my $thickness = shift;
+    my $rf = shift; #1,2,3, or undefined for all reading frames
+
+    if ((_isTrue($options->{parse_reading_frame})) && (_containsReadingFrameInfo($settings, $global, $file))) {
+	#The order needs to be 3, 2, 1 because BLAST results are always drawn on the inside
+	#of the backbone, and the slots are drawn closet to the backbone first.
+	_writeBlastResults($options, $settings, $global, $seqObject, 1, $file, $color, $thickness, 3);
+        if (_isTrue($options->{draw_divider_rings})) {
+            _drawDivider($options, $settings, $global, $seqObject, $strand, 0.25);
+        }
+	_writeBlastResults($options, $settings, $global, $seqObject, 1, $file, $color, $thickness, 2);
+        if (_isTrue($options->{draw_divider_rings})) {
+            _drawDivider($options, $settings, $global, $seqObject, $strand, 0.25);
+        }
+ 	_writeBlastResults($options, $settings, $global, $seqObject, 1, $file, $color, $thickness, 1);
+	_drawDivider($options, $settings, $global, $seqObject, $strand, 1);
+	_writeBlastResults($options, $settings, $global, $seqObject, -1, $file, $color, $thickness, 1);
+        if (_isTrue($options->{draw_divider_rings})) {
+            _drawDivider($options, $settings, $global, $seqObject, $strand, 0.25);
+        }
+	_writeBlastResults($options, $settings, $global, $seqObject, -1, $file, $color, $thickness, 2);
+        if (_isTrue($options->{draw_divider_rings})) {
+            _drawDivider($options, $settings, $global, $seqObject, $strand, 0.25);
+        }
+ 	_writeBlastResults($options, $settings, $global, $seqObject, -1, $file, $color, $thickness, 3);
+    }
+    else {
+	_writeBlastResults($options, $settings, $global, $seqObject, 1, $file, $color, $thickness, undef);
+    }
+}
+
+
+sub _drawDivider {
+
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift; #1 or -1
+    my $proportion_of_backbone = shift;
+    
+    my $opacity = $settings->{'featureOpacity'};
+    my @outputArray = ();
+
+    my $decoration = "arc";
+    if ($strand == 1) {
+	push (@outputArray, "<featureSlot featureThickness=\"" . $settings->{backboneThickness} * $proportion_of_backbone . "\" showShading=\"true\" strand=\"direct\">\n");
+    }
+    else {
+	push (@outputArray, "<featureSlot featureThickness=\"" . $settings->{backboneThickness} * $proportion_of_backbone . "\" showShading=\"true\" strand=\"reverse\">\n");
+    }
+    
+    push (@outputArray, "<feature color=\"$settings->{backboneColor}\" decoration=\"$decoration\">\n");
+    push (@outputArray, "<featureRange start=\"1\" stop=\"$global->{length}\">\n");
+    push (@outputArray, "</featureRange>\n");
+    push (@outputArray, "</feature>\n");
+
+    push (@outputArray, "</featureSlot>\n");
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- BLAST results divider -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+}
+
+sub _writeBlastResults {
+    my $options = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $seqObject = shift;
+    my $strand = shift;
+    my $file = shift;
+    my $color = shift;
+    my $thickness = shift;
+    my $rf = shift; #1,2,3, or undefined for all reading frames
+
+
+    my $opacity = $settings->{'featureOpacity'};
+    
+    my @outputArray = ();
+
+    #blast results are always drawn on the inside of the backbone. Strand is used when parse_reading_frame is specified
+    my $decoration = "arc";
+    if ($strand == 1) {
+	push (@outputArray, "<featureSlot strand=\"reverse\" showShading=\"false\" featureThickness=\"" . $thickness . "\">\n");
+    }
+    else {
+	push (@outputArray, "<featureSlot strand=\"reverse\" showShading=\"false\" featureThickness=\"" . $thickness . "\">\n");
+    }
+
+    #may want to mark query positions on the map, regardless of whether they 
+    #produced hits.
+    if (_isTrue($options->{'show_queries'})) {
+	my @queries = ();
+	@queries = @{_parseBlastQueries($file, $settings)};
+	@queries = @{_sortBLASTByStart(\@queries)};
+
+	if ($strand == 1) {
+	    @queries = reverse(@queries);
+	}   
+	#draw queries as faint features
+	push(@outputArray, "<feature>\n");
+	foreach(@queries) {
+	    #if a reading frame is specified, only want to draw
+	    #queries from this reading frame and strand
+	    if ((defined($rf)) && (defined($_->{q_rf}))) {
+		unless (($rf == $_->{q_rf}) && ($strand == $_->{q_strand})) {
+		    next;
+		}
+	    }
+	    push(@outputArray, "<featureRange start=\"$_->{q_start}\" stop=\"$_->{q_end}\" opacity=\"0.1\" radiusAdjustment=\"0.0\" proportionOfThickness=\"1.0\" color=\"$settings->{orfColor}\" />\n");
+	}
+	push(@outputArray, "</feature>\n");
+    }
+ 
+    my @features = ();
+    @features = @{_parseBLAST($file, $settings, $global)};
+    @features = @{_sortBLASTByStart(\@features)};
+
+    if ($strand == 1) {
+	@features = reverse(@features);
+    }
+
+   
+    foreach(@features) {
+	my $feat = $_;
+
+	my $start = $feat->{'q_start'};
+	my $stop = $feat->{'q_end'};
+
+	if ((defined($rf)) && (defined($feat->{'q_rf'}))) { 
+
+	    my $queryFrame = $feat->{'q_rf'};
+	    my $queryStrand = $feat->{'q_strand'};
+
+	    unless (($rf == $queryFrame) && ($strand == $queryStrand)) {
+		next;
+	    }
+	}
+
+	my $label;
+	if (_containsText($feat->{'match_id'})) {
+	    $label = $feat->{'match_id'};
+	    if (length($label) > $settings->{'maxLabelLength'} - 3) {
+		$label = substr($label, 0, $settings->{'maxLabelLength'} - 3) . "...";
+	    }
+		$label = _escapeText($label);
+	}
+
+        #gi|15678261
+	my $hyperlink;
+	if (_containsText($feat->{'match_id'})) {
+	    if ($feat->{'match_id'} =~ m/gi\|(\d+)/) {
+		$hyperlink = $global->{'ncbiGiLink'} . $1;
+	    }
+	    #GeneID:1132092"
+	    elsif ($feat->{'match_id'} =~ m/geneid\|(\d+)/) {
+		$hyperlink = $global->{'ncbiGeneLink'} . $1;
+	    }
+	}
+
+	my $mouseover;
+	if (_containsText($label)) {
+	    $mouseover = $label . "; " . $start . " to " . $stop;
+	}
+	else {
+	    $mouseover = $start . " to " . $stop;
+	}
+	if (_containsText($feat->{'match_description'})) {
+	    $mouseover = $mouseover . " " . $feat->{'match_description'};
+	}
+
+	$mouseover = $mouseover . "; percent identity=" . $feat->{'%_identity'} . "; alignment length=" . $feat->{alignment_length} . "; evalue=" . $feat->{'evalue'};
+	$mouseover = _escapeText($mouseover);
+
+	#now check entries and make tags
+	if (_isTrue($options->{use_opacity})) {
+	    $opacity = ".20";
+	}
+	else {
+	    $opacity = "1.0";
+	}
+
+	my $feature = "<feature color=\"$color\" decoration=\"$decoration\" opacity=\"$opacity\" ";
+
+	if (_isTrue($options->{hit_labels})) {
+	    if (_containsText($label)) {
+		$feature = $feature . "label=\"$label\" ";
+	    }
+	    if (_containsText($hyperlink)) {
+		$feature = $feature . "hyperlink=\"$hyperlink\" ";		
+	    }
+	    if (_containsText($mouseover)) {
+		$feature = $feature . "mouseover=\"$mouseover\" ";		
+	    }
+	}
+
+	$feature = $feature . ">\n";
+
+
+	#use %_identity to determine thickness of drawn feature
+	my $thickness = $feat->{'%_identity'} / 100.0;
+	$thickness = sprintf("%.10f", ($thickness)); 
+
+	my $featureRange = "<featureRange start=\"$start\" stop=\"$stop\" radiusAdjustment=\"0.0\" proportionOfThickness=\"$thickness\" />\n";
+	#now add $feature and $featureRange to @outputArray
+	push (@outputArray, $feature . $featureRange . "</feature>\n");		
+    }
+    
+    push (@outputArray, "</featureSlot>\n"); 
+    my $strandTerm = undef;
+    if ($strand == 1) {
+	$strandTerm = "forward";
+    }
+    if ($strand == -1) {
+	$strandTerm = "reverse";
+    }
+    
+    my $rfTerm = undef;
+    if (!(defined($rf))) {
+	$rfTerm = "1,2,3";
+    }
+    else {
+	$rfTerm = $rf;
+    }
+    
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+    print (OUTFILE "<!-- BLAST results on $strandTerm strand in rf $rfTerm -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+}
+
+sub _containsReadingFrameInfo {
+    my $settings = shift;
+    my $global = shift;
+    my $file = shift;
+
+    return _parseBLAST($file, $settings, $global, 1);
+}
+
+sub _parseBLAST {
+    my $file = shift;
+    my $settings = shift;
+    my $global = shift;
+    my $check_for_reading_frame_info = shift;
+
+    #The file can contain comments starting with'#'
+    #The file must have a line beginning with a 'query_id' and indicating the column names:
+    #query_id	match_id	match_description	%_identity	alignment_length	mismatches	gap_openings	q_start	q_end	s_start	s_end	evalue	bit_score
+    
+    my @required = ('query_id', '%_identity', 'q_start', 'q_end', 'alignment_length', 'evalue');
+
+    my $lineCount = 0;
+    my @columnTitles = ();
+    my $columnsRead = 0;
+    
+    #program will be used to store the value of #PROGRAM in the blast results header.
+    #if it is blastp or tblastn then q_start and q_end are in residues and need to
+    #be converted to bases.
+    my $program = undef;
+
+    open (INFILE, $file) or die ("Cannot open the BLAST results file $file");
+    
+    #check for column titles
+    while (my $line = <INFILE>) {
+	$line =~ s/\cM|\n//g;
+	$lineCount++;
+	if ($line =~ m/^\#PROGRAM\s*=\s*([^\s]+)/) {
+	    $program = $1;
+	}
+	if ($line =~ m/^\#/) {
+	    next;
+	}
+	if ($line =~ m/^query_id/) {
+	    $columnsRead = 1;
+	    @columnTitles = @{_split($line)};
+	    last;
+	}
+    }
+
+    if (!(defined($program))) {
+	die ("Cannot parse the #PROGRAM field in the BLAST results file $file");
+    }
+
+    #print Dumper(@columnTitles);
+
+    #now check for required columns  
+    foreach(@required) {
+	my $req = $_;
+	my $match = 0;
+	foreach(@columnTitles) {
+	    my $columnTitle = $_;
+	    if ($columnTitle eq $req) {
+		$match = 1;
+		last;
+	    }
+	}
+	if (!($match)) {
+	    die ("The BLAST results in $file do not contain a column labeled $req");
+	}
+    }
+
+    #factor to convert amino acid scales to base scales
+    my $scale;
+    if (($program =~ m/^blastp$/) || ($program =~ m/^tblastn$/)) {
+	$scale = 3;
+    }
+    else {
+	$scale = 1;
+    }
+
+    #read the remaining entries
+    my @entries = ();
+    while (my $line = <INFILE>) {    
+	$line =~ s/\cM|\n//g;
+	$lineCount++;
+	if ($line =~ m/^\#/) {
+	    next;
+	}
+	if ($line =~ m/\S/) {
+	    my @values = @{_split($line)};
+	    #skip lines with missing values
+	    if (scalar(@values) != scalar(@columnTitles)) {
+		next;
+	    }
+
+	    my %entry = ();
+	    for (my $i = 0; $i < scalar(@columnTitles); $i++) {
+		$entry{$columnTitles[$i]} = $values[$i]; 
+	    }
+	    
+	    #do some error checking of values
+	    #check query_id, %_identity, q_start, and q_end
+	    #skip if no identity value
+	    if (!($entry{'%_identity'} =~ m/\d/)) {
+		die ("No \%_identity value BLAST results $file line $lineCount");
+	    }
+
+	    if (!($entry{'q_start'} =~ m/\d/)) {
+		die ("No q_start value BLAST results $file line $lineCount");
+	    }
+	    if (!($entry{'q_end'} =~ m/\d/)) {
+		die ("No q_end value BLAST results $file line $lineCount");
+	    }
+
+	    #try to add reading frame and strand information using information
+	    #in the query_id:
+	    #orf3_start=3691;end=3858;strand=1;rf=1
+	    #orf16_start=8095;end=8178;strand=1;rf=1
+	    #
+	    #The q_start and q_end values are region of the query that matched
+	    #the hit. Depending on the search type, these can be in amino acids
+	    #or bases. The values in the query_id are always in bases. The
+	    #scale factor is used to convert the q_start and q_end values
+	    #so that they can be used to adjust the values in the query_id.
+	    #This allows hits to be mapped to the genomic sequence
+	    if ($entry{'query_id'} =~ m/start=(\d+);end=\d+;strand=(\-*\d+);rf=(\d+)\s*$/) {
+		$entry{'q_start'} = $entry{'q_start'} * $scale + $1 - 1 * $scale;
+		$entry{'q_end'} = $entry{'q_end'} * $scale + $1 - 1 * $scale;
+		$entry{'q_strand'} = $2;
+		$entry{'q_rf'} = $3;		
+	    }
+
+	    #try to determine reading frame of query even if not explicitly given in title,
+	    #by using the position of the hit relative to the source sequence.
+	    #sequence_start=286;end=385;length=100;source_length=1000
+	    #start and end refer to direct strand
+	    #
+	    if ($entry{'query_id'} =~ m/start=(\d+);end=\d+;length=\d+;source_length=(\d+)\s*$/) {
+		$entry{'q_start'} = $entry{'q_start'} * $scale + $1 - 1 * $scale;
+		$entry{'q_end'} = $entry{'q_end'} * $scale + $1 - 1 * $scale;
+		my $source_length = $2;
+
+		#for blastn results the s_start and s_end reversed to indicate reverse strand
+		if ($program =~ m/^blastn$/) {
+		    if ($entry{'s_start'} > $entry{'s_end'}) {
+			$entry{'q_strand'} = -1;
+		    }
+		    else {
+			$entry{'q_strand'} = 1;
+		    }
+		}
+		#for tblastx and blastx results the q_start and q_end are reversed to indicate reverse strand
+		elsif (($program =~ m/^tblastx$/) || ($program =~ m/^blastx$/)) {
+		    if ($entry{'q_start'} > $entry{'q_end'}) {
+			$entry{'q_strand'} = -1;
+		    }
+		    else {
+			$entry{'q_strand'} = 1;
+		    }
+		}
+
+		
+		if (($program =~ m/^blastx$/) || ($program =~ m/^tblastx$/)) {
+
+		    if ($entry{'q_strand'} == 1) {
+			$entry{'q_rf'} = $entry{'q_start'} % 3;
+		    }
+		    elsif ($entry{'q_strand'} == -1) {
+			my $end = $entry{'q_end'};
+			if ($entry{'q_start'} > $entry{'q_end'}) {
+			    $end = $entry{'q_start'};
+			}
+			$entry{'q_rf'} = ($source_length - $end + 1) % 3;	
+		    }
+
+		    if ($entry{'q_rf'} == 0) {
+			$entry{'q_rf'} = 3;
+		    }
+		}
+		else {
+		    $entry{'q_rf'} = undef;
+		}
+
+	    }
+	    
+	    #try to adjust q_start and q_end using information in title when rf and strand not specified
+	    #start=X;end=Y
+	    if ($entry{'query_id'} =~ m/start=(\d+);end=\d+\s*$/) {
+		$entry{'q_start'} = $entry{'q_start'} * $scale + $1 - 1 * $scale;
+		$entry{'q_end'} = $entry{'q_end'} * $scale + $1 - 1 * $scale;		 
+	    }
+
+	    #check q_start and q_end to make sure they are in range
+	    #depending on the blast search, the q_start may be larger than the q_end,
+	    #if this is the case, swap them
+	    if ($entry{'q_start'} > $entry{'q_end'}) {
+		my $temp = $entry{'q_start'};
+		$entry{'q_start'} = $entry{'q_end'};
+		$entry{'q_end'} = $temp;
+	    }
+
+	    if ($entry{'q_start'} < 1) {
+		die ("q_start value " . $entry{'q_start'} . " is less than 1 BLAST results $file line $lineCount");
+	    }
+	    if ($entry{'q_end'} < 1) {
+		die ("q_end value " . $entry{'q_end'} . " is less than 1 BLAST results $file line $lineCount");
+	    }
+	    if ($entry{'q_start'} > $global->{'length'}) {
+		die ("q_start value " . $entry{'q_start'} . " is greater than sequence length " . $global->{'length'} . " BLAST results $file line $lineCount");
+	    }
+	    if ($entry{'q_end'} > $global->{'length'}) {
+		die ("q_end value " . $entry{'q_end'} . " is greater than sequence length " . $global->{'length'} . " BLAST results $file line $lineCount");
+	    }
+	    if ($check_for_reading_frame_info) {
+		if (defined($entry{'q_rf'})) {
+		    return 1;
+		}
+		else {
+		    return 0;
+		}
+	    }
+	    push (@entries, \%entry);
+	}
+    }
+    close (INFILE) or die("Cannot close file : $!");
+    return \@entries;
+}
+
+
+sub _sortBLASTByStart {
+    my $features = shift;
+
+    @$features = map { $_->[1] }
+      sort { $a->[0] <=> $b->[0]}
+      map { [ _getSortValueBLAST($_), $_] }
+      @$features;
+    
+    return $features;
+}
+
+sub _getSortValueBLAST {
+    my $feature = shift;
+    return $feature->{'q_start'};
+}
+
+sub _parseBlastQueries {
+    my $file = shift;
+    my $lineCount = 0;
+
+    open (INFILE, $file) or die ("Cannot open the BLAST results file $file");
+    #won't bother checking columns.
+    my %entries = ();
+    while (my $line = <INFILE>) { 
+	$line =~ s/\cM|\n//g;
+	$lineCount++;
+	#orf1_start=142;end=255;strand=1;rf=1
+	#orf_900_start=142;end=255;strand=1;rf=1
+	#some gene_start=142;end=255;strand=1;rf=1 
+	if ($line =~ m/^([^\t]+)_start=(\d+);end=(\d+);strand=(\-*\d+);rf=(\d+)/) {
+	    my %entry = ();
+	    $entry{'q_start'} = $2;
+	    $entry{'q_end'} = $3;
+	    $entry{'q_strand'} = $4;
+	    $entry{'q_rf'} = $5;
+	    $entries{$1 . $2 . $3 . $4} = \%entry;		
+	}
+	#some gene_start=142;end=255
+	elsif ($line =~ m/^([^\t]+)_start=(\d+);end=(\d+)/) {
+	    my %entry = ();
+	    $entry{'q_start'} = $2;
+	    $entry{'q_end'} = $3;
+	    $entry{'q_strand'} = "1";
+	    $entry{'q_rf'} = undef;
+	    $entries{$1 . $2 . $3} = \%entry;	
+	}
+    }
+    close (INFILE) or die( "Cannot close file : $!");
+    my @values = values(%entries);
+    return \@values;
+}
+
+sub _writeBaseContent {
+    my $options = shift;
+    my $settings = shift;
+    my $seqObject = shift;
+
+    #1 or -1. Strand here only determines whether graph is drawn on outside or inside of backbone.
+    my $strand = shift;
+
+    #type should be gc_content, at_content, gc_skew, or at_skew.
+    my $type = shift;
+
+    my $plotTerm;
+    if ($type eq 'gc_content') {
+	$plotTerm = "GC content";
+    }
+    elsif ($type eq 'gc_skew') {
+	$plotTerm = "GC skew";
+    }
+    elsif ($type eq 'at_content') {
+	$plotTerm = "AT content";
+    }
+    elsif ($type eq 'at_skew') {
+	$plotTerm = "AT skew";
+    }
+    
+    my $globalBaseContentInfo = _getGlobalBaseContentInfo($options, $settings, $seqObject, $type);
+
+    #The max, min, and average have been scaled for some plot types to facilatate CGView plotting.
+    #When returning these to the user, adjust the values so that they are in the standard ranges.
+    my $actualMax;
+    my $actualMin;
+    my $actualAverage;
+
+    if (($type eq 'gc_content') || ($type eq 'at_content')) {
+	$actualMax = $globalBaseContentInfo->{'max'};
+	$actualMin = $globalBaseContentInfo->{'min'};
+	$actualAverage = $globalBaseContentInfo->{'average'};
+    }
+    elsif (($type eq 'gc_skew') || ($type eq 'at_skew')) {
+	$actualMax = _skewCorrect($globalBaseContentInfo->{'max'});
+	$actualMin = _skewCorrect($globalBaseContentInfo->{'min'});
+	$actualAverage = _skewCorrect($globalBaseContentInfo->{'average'});
+    }
+
+    $actualMax = sprintf("%.4f", $actualMax);
+    $actualMin = sprintf("%.4f", $actualMin);
+    $actualAverage = sprintf("%.4f", $actualAverage);
+
+    _message($options, "Plotting $plotTerm using a window size of $options->{window} and a step of $options->{step}.");
+    _message($options, "The maximum $plotTerm value is $actualMax.");
+    _message($options, "The minimum $plotTerm value is $actualMin.");
+    _message($options, "The average $plotTerm value is $actualAverage.");
+
+    if (_isTrue($options->{scale})) {
+	_message($options, "$plotTerm will be scaled based on the maximum and minimum values.");
+    }
+
+    if (_isTrue($options->{average})) {
+	_message($options, "$plotTerm will be plotted as the deviation from the average value.");
+    }
+
+    my $opacity = $settings->{'featureOpacity'};
+    my $decoration = 'arc';
+    my $positiveColor;
+    my $negativeColor;
+    if ($type eq 'gc_content') {
+	$positiveColor = $settings->{'gcColorPos'};
+	$negativeColor = $settings->{'gcColorNeg'};
+    }
+    elsif ($type eq 'at_content') {
+	$positiveColor = $settings->{'atColorPos'};
+	$negativeColor = $settings->{'atColorNeg'};
+    }
+    elsif ($type eq 'gc_skew') {
+	$positiveColor = $settings->{'gcSkewColorPos'};
+	$negativeColor = $settings->{'gcSkewColorNeg'};
+    }
+    elsif ($type eq 'at_skew') {
+	$positiveColor = $settings->{'atSkewColorPos'};
+	$negativeColor = $settings->{'atSkewColorNeg'};
+    }
+
+    my $upstreamLength = sprintf("%.f", $options->{'window'} / 2);
+    my $downstreamLength = $options->{'window'} - $upstreamLength;
+    my $step = $options->{'step'};
+    my $isLinear = undef;
+    if ($settings->{'isLinear'} eq "true") {
+	$isLinear = 1;
+    }
+    else {
+	$isLinear = 0;
+    }
+
+    my $dna = $seqObject->seq();
+    my $originalLength = length($dna);
+    my $subseq;
+    my $value;
+    my $positionCorrection = 0;
+    my $firstBase;
+    my $lastBase;
+
+    if (!($isLinear)) {
+	my $prefix = substr($dna, length($dna) - $upstreamLength, $upstreamLength);
+	my $suffix = substr($dna, 0, $downstreamLength);
+	$dna = $prefix . $dna . $suffix;
+	$positionCorrection = length($prefix);
+    }
+    
+    my $length = length($dna);
+    my $maxDeviationUp = $globalBaseContentInfo->{'max'} - $globalBaseContentInfo->{'average'};
+    my $maxDeviationDown = $globalBaseContentInfo->{'average'} - $globalBaseContentInfo->{'min'};
+    my $average = $globalBaseContentInfo->{'average'};
+    my $maxDeviation;
+    if ($maxDeviationUp > $maxDeviationDown) {
+	$maxDeviation = $maxDeviationUp;
+    }
+    else {
+	$maxDeviation = $maxDeviationDown;
+    }
+
+    my @outputArray = ();
+    if ($strand == 1) {
+	push (@outputArray, "<featureSlot showShading=\"false\" strand=\"direct\" featureThickness=\"" . $settings->{'featureThicknessPlot'} . "\">\n");
+    }
+    else {
+	push (@outputArray, "<featureSlot showShading=\"false\" strand=\"reverse\" featureThickness=\"" . $settings->{'featureThicknessPlot'} . "\">\n");
+    }
+
+    push (@outputArray, "<feature decoration=\"$decoration\" opacity=\"$opacity\">\n");
+
+    for (my $i = 1 + $upstreamLength; $i <= $length - $downstreamLength; $i = $i + $step) {
+
+	$subseq = substr($dna, $i - $upstreamLength - 1, ($i + $downstreamLength) - ($i - $upstreamLength - 1));
+
+	#These set the width and position of the "point" on the map. 
+	#They are not the actual first base and last base in the sliding window.
+	$firstBase = $i - $positionCorrection;
+	$lastBase = $firstBase + $step;
+
+	####2007-01-14
+	####This hack should prevent background from appearing in plots.
+	if (($originalLength > 10000) || ($settings->{backboneRadius} > 1000)) {
+	    $lastBase = $lastBase + sprintf("%.f", (2.0 * $step));
+	    $firstBase = $firstBase - sprintf("%.f", (2.0 * $step));
+	}
+        ###
+
+	if ($firstBase < 1) {
+	    $firstBase = 1;
+	}
+
+	if ($lastBase > $originalLength) {
+	    $lastBase = $originalLength;
+	}
+
+	$value = _calc($type, $subseq);
+        #want bars above middle line for values > 0.5 and below middle line for values < 0.5
+
+	my $barHeight;
+	my $radiusShift;
+	my $color;
+
+	if ($value > $average) {
+	    $color = $positiveColor;
+	    $barHeight = $value - $average;
+	    $barHeight = $barHeight * 0.5 / $maxDeviation;
+	    $radiusShift = 0.5 + $barHeight / 2.0;
+	}
+	elsif ($value < $average) {
+	    $color = $negativeColor;
+	    $barHeight = $average - $value;
+	    $barHeight = $barHeight * 0.5 / $maxDeviation;
+	    $radiusShift = 0.5 - $barHeight / 2;
+	}
+	else {
+	    $color = $positiveColor;
+	    $radiusShift = 0.5;
+	    $barHeight = $settings->{'plotLineThickness'};
+	}
+
+	push (@outputArray, "<featureRange color=\"" . $color . "\" start=\"$firstBase\" stop=\"$lastBase\" proportionOfThickness=\"" .  $barHeight  . "\" radiusAdjustment=\"$radiusShift\" />\n");
+    } 
+
+    push (@outputArray, "</feature>\n");
+
+    push (@outputArray, "</featureSlot>\n");  
+    my $strandTerm = undef;
+    if ($strand == 1) {
+	$strandTerm = "forward";
+    }
+    if ($strand == -1) {
+	$strandTerm = "reverse";
+    }
+
+    open (OUTFILE, "+>>" . $options->{"output"}) or die( "Cannot open file : $!" );
+    print (OUTFILE "\n\n\n\n");
+#    print (OUTFILE "<!-- $plotTerm for $strandTerm strand -->\n");
+    print (OUTFILE "<!-- $plotTerm -->\n");
+    print (OUTFILE join("", @outputArray));
+    print (OUTFILE "\n");
+    close (OUTFILE) or die( "Cannot close file : $!");
+
+}
+
+sub _getGlobalBaseContentInfo {
+    my $options = shift;
+    my $settings = shift;
+    my $seqObject = shift;
+
+    #type should be gc_content, at_content, gc_skew, or at_skew.
+    my $type = shift;
+
+    my %globalBaseContentInfo = (min => 1,
+				 max => 0,
+				 average => 0);
+
+    my $upstreamLength = sprintf("%.f", $options->{'window'} / 2);
+    my $downstreamLength = $options->{'window'} - $upstreamLength;
+    my $step = $options->{'step'};
+    my $isLinear = undef;
+    if ($settings->{'isLinear'} eq "true") {
+	$isLinear = 1;
+    }
+    else {
+	$isLinear = 0;
+    }
+
+    my $dna = $seqObject->seq();
+ 
+    if (_isTrue($options->{'average'})) {   
+	$globalBaseContentInfo{'average'} = _calc($type, $dna);
+    }
+    else {
+	$globalBaseContentInfo{'average'} = 0.5;
+    }
+
+    if (!(_isTrue($options->{'scale'}))) { 
+	$globalBaseContentInfo{'min'} = 0;
+	$globalBaseContentInfo{'max'} = 1;
+	return \%globalBaseContentInfo;	
+    }
+
+    my $subseq;
+    my $value;
+
+    if (!($isLinear)) {
+	my $prefix = substr($dna, length($dna) - $upstreamLength, $upstreamLength);
+	my $suffix = substr($dna, 0, $downstreamLength);
+	$dna = $prefix . $dna . $suffix;	
+    }
+    
+    my $length = length($dna);
+
+    for (my $i = 1 + $upstreamLength; $i <= $length - $downstreamLength; $i = $i + $step) {
+
+	$subseq = substr($dna, $i - $upstreamLength - 1, ($i + $downstreamLength) - ($i - $upstreamLength - 1));
+
+	$value = _calc($type, $subseq);
+
+	if ($value > $globalBaseContentInfo{'max'}) {
+	    $globalBaseContentInfo{'max'} = $value;
+	}
+		
+	if ($value < $globalBaseContentInfo{'min'}) {
+	    $globalBaseContentInfo{'min'} = $value;
+	}
+    } 
+
+    return \%globalBaseContentInfo;
+
+}   
+
+sub _calc {
+    my $type = shift;
+    my $dna = shift;
+
+    if ($type eq "gc_content") {
+	return _calcGCContent($dna);
+    }
+    elsif ($type eq "at_content") {
+	return _calcATContent($dna);
+    }
+    elsif ($type eq "gc_skew") {
+	return _calcGCSkew($dna);
+    }
+    elsif ($type eq "at_skew") {
+	return _calcATSkew($dna);
+    }
+    else {
+	die ("unknown calc type");
+    }
+}
+
+sub _calcGCContent {
+    my $dna = lc(shift);
+    my $total = length($dna);
+    my $g = ($dna =~ tr/g/G/);
+    my $c = ($dna =~ tr/c/C/);
+
+    if ($total == 0) {
+	return 0.5;
+    }
+
+    return sprintf("%.5f", (($g + $c) / $total));
+}
+
+sub _calcATContent {
+    my $dna = lc(shift);
+    my $total = length($dna);
+    my $a = ($dna =~ tr/a/A/);
+    my $t = ($dna =~ tr/t/T/);
+
+    if ($total == 0) {
+	return 0.5;
+    }
+    
+    return sprintf("%.5f", (($a + $t) / $total));
+}
+
+sub _calcGCSkew {
+    my $dna = lc(shift);
+    my $c = ($dna =~ tr/c/C/);
+    my $g = ($dna =~ tr/g/G/);
+    
+    if (($g + $c) == 0) {
+	return 0.5;
+    }    
+
+    #gives value between -1 and 1
+    my $value = ($g - $c) / ($g + $c);
+
+    #scale to a value between 0 and 1
+    $value = 0.5 + $value / 2.0; 
+
+    return sprintf("%.5f", ($value));
+}
+
+sub _calcATSkew {
+    my $dna = lc(shift);
+    my $a = ($dna =~ tr/a/A/);
+    my $t = ($dna =~ tr/t/T/);
+    
+    if (($a + $t) == 0) {
+	return 0.5;
+    }    
+
+    #gives value between -1 and 1
+    my $value = ($a - $t) / ($a + $t);
+
+    #scale to a value between 0 and 1
+    $value = 0.5 + $value / 2.0; 
+
+    return sprintf("%.5f", ($value));
+}
+
+#for reporting values to user
+sub _skewCorrect {
+    my $value = shift;
+    return (2*($value - 0.5));
+}
diff --git a/cgview/cgview_xml_builder/test.sh b/cgview/cgview_xml_builder/test.sh
new file mode 100644
index 0000000..d9ba9cf
--- /dev/null
+++ b/cgview/cgview_xml_builder/test.sh
@@ -0,0 +1,40 @@
+#!/bin/sh -x
+cgview=../cgview_comparison_tool/bin/cgview.jar
+
+if [ ! -d ./sample_output ]; then
+    mkdir ./sample_output
+fi
+
+for size in small medium large x-large
+do
+    #simple
+    perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -genes sample_input/R_denitrificans.cogs -output sample_output/${size}_simple.xml -gc_content T -gc_skew T -size $size -title 'Roseobacter denitrificans' -draw_divider_rings T
+
+    java -jar -Xmx2000m $cgview -i sample_output/${size}_simple.xml -o sample_output/${size}_simple.png -f png
+
+    #complex
+    perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -genes sample_input/R_denitrificans.cogs -output sample_output/${size}_complex.xml -reading_frames T -orfs T -combined_orfs T -gc_content T -gc_skew T -at_content T -at_skew T -size $size -title 'Roseobacter denitrificans' -draw_divider_rings T
+
+    java -jar -Xmx2000m $cgview -i sample_output/${size}_complex.xml -o sample_output/${size}_complex.png -f png
+done
+
+
+#create an x-large with feature labels
+size=x-large
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -genes sample_input/R_denitrificans.cogs -output sample_output/${size}_complex_labels.xml -reading_frames T -orfs T -combined_orfs T -gc_content T -gc_skew T -at_content T -at_skew T -size $size -title 'Roseobacter denitrificans' -feature_label T -draw_divider_rings T
+
+java -jar -Xmx2000m $cgview -i sample_output/${size}_complex_labels.xml -o sample_output/${size}_complex_labels.png -f png 
+
+#create zoomed with starts and stops
+size=large
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -genes sample_input/R_denitrificans.cogs -output sample_output/${size}_no_labels.xml -reading_frames T -combined_orfs T -gc_content F -gc_skew F -at_content F -at_skew F -size $size -title 'Roseobacter denitrificans' -draw_divider_rings T
+
+java -jar -Xmx1000m $cgview -i sample_output/${size}_no_labels.xml -o sample_output/${size}_no_labels_zoomed.png -f png -z 50 -c 10000
+
+#test ability to handle multiple 'genes' files
+size=medium
+perl cgview_xml_builder.pl -sequence sample_input/R_denitrificans.gbk -genes sample_input/R_denitrificans.cogs sample_input/R_denitrificans.cogs sample_input/R_denitrificans.cogs -output sample_output/${size}_multiple_genes_files.xml -reading_frames T -combined_orfs T -gc_content F -gc_skew F -at_content F -at_skew F -size $size -title 'Roseobacter denitrificans' -draw_divider_rings T
+
+java -jar -Xmx1000m $cgview -i sample_output/${size}_multiple_genes_files.xml -o sample_output/${size}_multiple_genes_files_zoomed.png -f png -z 50 -c 10000
+
+
diff --git a/cgview/includes/as_png.png b/cgview/includes/as_png.png
new file mode 100644
index 0000000..376f608
Binary files /dev/null and b/cgview/includes/as_png.png differ
diff --git a/cgview/includes/as_svg.png b/cgview/includes/as_svg.png
new file mode 100644
index 0000000..f2283f0
Binary files /dev/null and b/cgview/includes/as_svg.png differ
diff --git a/cgview/includes/expand_in.png b/cgview/includes/expand_in.png
new file mode 100644
index 0000000..a89e8f0
Binary files /dev/null and b/cgview/includes/expand_in.png differ
diff --git a/cgview/includes/expand_in_g.png b/cgview/includes/expand_in_g.png
new file mode 100644
index 0000000..387d289
Binary files /dev/null and b/cgview/includes/expand_in_g.png differ
diff --git a/cgview/includes/expand_out.png b/cgview/includes/expand_out.png
new file mode 100644
index 0000000..d47a2e9
Binary files /dev/null and b/cgview/includes/expand_out.png differ
diff --git a/cgview/includes/expand_out_g.png b/cgview/includes/expand_out_g.png
new file mode 100644
index 0000000..4aa0023
Binary files /dev/null and b/cgview/includes/expand_out_g.png differ
diff --git a/cgview/includes/full.png b/cgview/includes/full.png
new file mode 100644
index 0000000..536da90
Binary files /dev/null and b/cgview/includes/full.png differ
diff --git a/cgview/includes/full_g.png b/cgview/includes/full_g.png
new file mode 100644
index 0000000..d6c1ab7
Binary files /dev/null and b/cgview/includes/full_g.png differ
diff --git a/cgview/includes/help.html b/cgview/includes/help.html
new file mode 100644
index 0000000..cda90e2
--- /dev/null
+++ b/cgview/includes/help.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en">
+<head>
+<title>Map Navigation</title>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<link rel="stylesheet" href="stylesheet.css"  type="text/css" />
+</head>
+<body>
+
+<div class="title">
+Map Navigation
+</div>
+
+<table border="0" cellspacing="2" cellpadding="2" align="left">
+<tbody>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Buttons
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_out.png" alt="[Expand -]" />
+</td>
+<td class="left">
+View more of the map, at a reduced size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_in.png" alt="[Expand +]" />
+</td>
+<td class="left">
+View less of the map, at an expanded size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="full.png" alt="[Full view]" />
+</td>
+<td class="left">
+View the entire map.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_back.png" alt="[Rotate -]" />
+</td>
+<td class="left">
+Shift the current view in the counterclockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_forward.png" alt="[Rotate +]" />
+</td>
+<td class="left">
+Shift the current view in the clockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="as_png.png" alt="[View as PNG]" />
+</td>
+<td class="left">
+View the map in PNG (Portable Network Graphics) format. PNG raster images can be viewed in most current browsers.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="as_svg.png" alt="[View as SVG]" />
+</td>
+<td class="left">
+View the map in SVG (Scalable Vector Graphics) format. SVG is an XML grammar for defining vector-based 2D graphics. SVG images can be viewed in most current web browsers using the <a href="http://www.adobe.com/svg/viewer/install/main.html">Adobe SVG plugin</a>.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="comment">
+Note: The file size of the current view in SVG and PNG format is given in the lower right of the map window.
+</span>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Using Tick Marks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+A region of interest can be expanded by clicking on the nearest tick mark. 
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Hyperlinks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Some feature labels may be linked to other resources. To access a linked resource, click on the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Mouseover
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Additional information may be viewed for some features by pointing to the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="validInfo">
+Contact: Paul Stothard stothard at ualberta.ca
+</span><br />
+<span class="validInfo">
+<a href="http://validator.w3.org/check/referer">Valid XHTML 1.0;</a> <a href="http://jigsaw.w3.org/css-validator/check/referer">Valid CSS.</a>
+</span>
+</td>
+</tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/cgview/includes/help.png b/cgview/includes/help.png
new file mode 100644
index 0000000..4ca5189
Binary files /dev/null and b/cgview/includes/help.png differ
diff --git a/cgview/includes/help_png.html b/cgview/includes/help_png.html
new file mode 100644
index 0000000..f1410ba
--- /dev/null
+++ b/cgview/includes/help_png.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en">
+<head>
+<title>Map Navigation</title>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<link rel="stylesheet" href="stylesheet.css"  type="text/css" />
+</head>
+<body>
+
+<div class="title">
+Map Navigation
+</div>
+
+<table border="0" cellspacing="2" cellpadding="2" align="left">
+<tbody>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Buttons
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_out.png" alt="[Expand -]" />
+</td>
+<td class="left">
+View more of the map, at a reduced size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_in.png" alt="[Expand +]" />
+</td>
+<td class="left">
+View less of the map, at an expanded size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="full.png" alt="[Full view]" />
+</td>
+<td class="left">
+View the entire map.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_back.png" alt="[Rotate -]" />
+</td>
+<td class="left">
+Shift the current view in the counterclockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_forward.png" alt="[Rotate +]" />
+</td>
+<td class="left">
+Shift the current view in the clockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="comment">
+Note: The file size of the current view in PNG format is given in the lower right of the map window.
+</span>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Using Tick Marks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+A region of interest can be expanded by clicking on the nearest tick mark. 
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Hyperlinks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Some feature labels may be linked to other resources. To access a linked resource, click on the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Mouseover
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Additional information may be viewed for some features by pointing to the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="validInfo">
+Contact: Paul Stothard stothard at ualberta.ca
+</span><br />
+<span class="validInfo">
+<a href="http://validator.w3.org/check/referer">Valid XHTML 1.0;</a> <a href="http://jigsaw.w3.org/css-validator/check/referer">Valid CSS.</a>
+</span>
+</td>
+</tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/cgview/includes/info.js b/cgview/includes/info.js
new file mode 100644
index 0000000..0c69ea7
--- /dev/null
+++ b/cgview/includes/info.js
@@ -0,0 +1,73 @@
+//Written by Paul Stothard, University of Alberta, Canada 2004
+
+function showMouseover(evt, message) {
+
+	var PADDING = 8;
+	var X_SHIFT = 20;
+	var Y_SHIFT = 20;
+
+	var svgDoc = evt.target.ownerDocument; 
+
+	var translateX = svgDoc.rootElement.currentTranslate.x;
+	var translateY = svgDoc.rootElement.currentTranslate.y;
+	var scale = 1 / svgDoc.rootElement.currentScale;
+
+	var effectiveDocWidth = svgDoc.rootElement.getAttribute("width") - translateX;
+	var effectiveDocHeight = svgDoc.rootElement.getAttribute("height") - translateY;
+
+	var targetText = svgDoc.getElementById("mouseoverBox");
+	var x = evt.clientX - translateX + X_SHIFT;
+	var y = evt.clientY - translateY + Y_SHIFT;
+
+	var newText = svgDoc.createTextNode(message); 
+	targetText.replaceChild(newText, targetText.firstChild); 
+	var textBounds = targetText.getBBox(); 
+
+	y = y + textBounds.height;
+
+	if (x + textBounds.width + PADDING > effectiveDocWidth) {
+		x = x - (x + textBounds.width + PADDING - effectiveDocWidth); 
+		if (y > effectiveDocWidth / 2) {
+			y = y - Y_SHIFT - Y_SHIFT - textBounds.height;
+		}
+		else {
+
+		}
+	} 
+
+	if (y + textBounds.height + PADDING > effectiveDocHeight) {
+		y = y - (y + textBounds.height + PADDING - effectiveDocHeight); 
+	} 
+
+	if (x - PADDING < 0) {
+		x = 0 + PADDING;
+	} 
+	if (y - textBounds.height - PADDING < 0) {
+		y = 0 + textBounds.height + PADDING;
+	}
+
+	targetText.setAttribute("x", x);
+	targetText.setAttribute("y", y);
+	textBounds = targetText.getBBox();
+	targetTextBackground = svgDoc.getElementById("mouseoverBoxBackground");
+	targetTextBackground.setAttribute("transform", "scale(" + scale + "," + scale + ")");
+	targetTextBackground.setAttribute("x", textBounds.x - PADDING / 2);
+	targetTextBackground.setAttribute("y", textBounds.y - PADDING / 2);
+	targetTextBackground.setAttribute("width", textBounds.width + PADDING); 
+	targetTextBackground.setAttribute("height", textBounds.height + PADDING);
+	targetText.setAttribute("transform", "scale(" + scale + "," + scale + ")");
+} 
+
+function showMouseout(evt) {
+	var svgDoc = evt.target.ownerDocument;
+	var targetText = svgDoc.getElementById("mouseoverBox");
+	var newText = svgDoc.createTextNode("");
+	targetText.setAttribute("x", 0);
+	targetText.setAttribute("y", 0);
+	targetText.replaceChild(newText, targetText.firstChild);
+	targetTextBackground = svgDoc.getElementById("mouseoverBoxBackground");
+	targetTextBackground.setAttribute("x", 0);
+	targetTextBackground.setAttribute("y", 0);
+	targetTextBackground.setAttribute("width", 0);
+	targetTextBackground.setAttribute("height", 0);
+}
diff --git a/cgview/includes/move_back.png b/cgview/includes/move_back.png
new file mode 100644
index 0000000..b612959
Binary files /dev/null and b/cgview/includes/move_back.png differ
diff --git a/cgview/includes/move_back_g.png b/cgview/includes/move_back_g.png
new file mode 100644
index 0000000..89252a8
Binary files /dev/null and b/cgview/includes/move_back_g.png differ
diff --git a/cgview/includes/move_forward.png b/cgview/includes/move_forward.png
new file mode 100644
index 0000000..acbd440
Binary files /dev/null and b/cgview/includes/move_forward.png differ
diff --git a/cgview/includes/move_forward_g.png b/cgview/includes/move_forward_g.png
new file mode 100644
index 0000000..260d6b0
Binary files /dev/null and b/cgview/includes/move_forward_g.png differ
diff --git a/cgview/includes/overlib.js b/cgview/includes/overlib.js
new file mode 100644
index 0000000..3c6bfd6
--- /dev/null
+++ b/cgview/includes/overlib.js
@@ -0,0 +1,1491 @@
+//\/////
+//\  overLIB 4.21 - You may not remove or change this notice.
+//\  Copyright Erik Bosrup 1998-2004. All rights reserved.
+//\
+//\  Contributors are listed on the homepage.
+//\  This file might be old, always check for the latest version at:
+//\  http://www.bosrup.com/web/overlib/
+//\
+//\  Please read the license agreement (available through the link above)
+//\  before using overLIB. Direct any licensing questions to erik at bosrup.com.
+//\
+//\  Do not sell this as your own work or remove this copyright notice. 
+//\  For full details on copying or changing this script please read the
+//\  license agreement at the link above. Please give credit on sites that
+//\  use overLIB and submit changes of the script so other people can use
+//\  them as well.
+//   $Revision: 1.3 $                $Date: 2006/05/08 17:05:34 $
+//\/////
+//\mini
+
+////////
+// PRE-INIT
+// Ignore these lines, configuration is below.
+////////
+var olLoaded = 0;var pmStart = 10000000; var pmUpper = 10001000; var pmCount = pmStart+1; var pmt=''; var pms = new Array(); var olInfo = new Info('4.21', 1);
+var FREPLACE = 0; var FBEFORE = 1; var FAFTER = 2; var FALTERNATE = 3; var FCHAIN=4;
+var olHideForm=0;  // parameter for hiding SELECT and ActiveX elements in IE5.5+ 
+var olHautoFlag = 0;  // flags for over-riding VAUTO and HAUTO if corresponding
+var olVautoFlag = 0;  // positioning commands are used on the command line
+var hookPts = new Array(), postParse = new Array(), cmdLine = new Array(), runTime = new Array();
+// for plugins
+registerCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,css [...]
+
+////////
+// DEFAULT CONFIGURATION
+// Settings you want everywhere are set here. All of this can also be
+// changed on your html page or through an overLIB call.
+////////
+if (typeof ol_fgcolor=='undefined') var ol_fgcolor="#CCCCFF";
+if (typeof ol_bgcolor=='undefined') var ol_bgcolor="#333399";
+if (typeof ol_textcolor=='undefined') var ol_textcolor="#000000";
+if (typeof ol_capcolor=='undefined') var ol_capcolor="#FFFFFF";
+if (typeof ol_closecolor=='undefined') var ol_closecolor="#9999FF";
+if (typeof ol_textfont=='undefined') var ol_textfont="Verdana,Arial,Helvetica";
+if (typeof ol_captionfont=='undefined') var ol_captionfont="Verdana,Arial,Helvetica";
+if (typeof ol_closefont=='undefined') var ol_closefont="Verdana,Arial,Helvetica";
+if (typeof ol_textsize=='undefined') var ol_textsize="1";
+if (typeof ol_captionsize=='undefined') var ol_captionsize="1";
+if (typeof ol_closesize=='undefined') var ol_closesize="1";
+if (typeof ol_width=='undefined') var ol_width="200";
+if (typeof ol_border=='undefined') var ol_border="1";
+if (typeof ol_cellpad=='undefined') var ol_cellpad=2;
+if (typeof ol_offsetx=='undefined') var ol_offsetx=10;
+if (typeof ol_offsety=='undefined') var ol_offsety=10;
+if (typeof ol_text=='undefined') var ol_text="Default Text";
+if (typeof ol_cap=='undefined') var ol_cap="";
+if (typeof ol_sticky=='undefined') var ol_sticky=0;
+if (typeof ol_background=='undefined') var ol_background="";
+if (typeof ol_close=='undefined') var ol_close="Close";
+if (typeof ol_hpos=='undefined') var ol_hpos=RIGHT;
+if (typeof ol_status=='undefined') var ol_status="";
+if (typeof ol_autostatus=='undefined') var ol_autostatus=0;
+if (typeof ol_height=='undefined') var ol_height=-1;
+if (typeof ol_snapx=='undefined') var ol_snapx=0;
+if (typeof ol_snapy=='undefined') var ol_snapy=0;
+if (typeof ol_fixx=='undefined') var ol_fixx=-1;
+if (typeof ol_fixy=='undefined') var ol_fixy=-1;
+if (typeof ol_relx=='undefined') var ol_relx=null;
+if (typeof ol_rely=='undefined') var ol_rely=null;
+if (typeof ol_fgbackground=='undefined') var ol_fgbackground="";
+if (typeof ol_bgbackground=='undefined') var ol_bgbackground="";
+if (typeof ol_padxl=='undefined') var ol_padxl=1;
+if (typeof ol_padxr=='undefined') var ol_padxr=1;
+if (typeof ol_padyt=='undefined') var ol_padyt=1;
+if (typeof ol_padyb=='undefined') var ol_padyb=1;
+if (typeof ol_fullhtml=='undefined') var ol_fullhtml=0;
+if (typeof ol_vpos=='undefined') var ol_vpos=BELOW;
+if (typeof ol_aboveheight=='undefined') var ol_aboveheight=0;
+if (typeof ol_capicon=='undefined') var ol_capicon="";
+if (typeof ol_frame=='undefined') var ol_frame=self;
+if (typeof ol_timeout=='undefined') var ol_timeout=0;
+if (typeof ol_function=='undefined') var ol_function=null;
+if (typeof ol_delay=='undefined') var ol_delay=0;
+if (typeof ol_hauto=='undefined') var ol_hauto=0;
+if (typeof ol_vauto=='undefined') var ol_vauto=0;
+if (typeof ol_closeclick=='undefined') var ol_closeclick=0;
+if (typeof ol_wrap=='undefined') var ol_wrap=0;
+if (typeof ol_followmouse=='undefined') var ol_followmouse=1;
+if (typeof ol_mouseoff=='undefined') var ol_mouseoff=0;
+if (typeof ol_closetitle=='undefined') var ol_closetitle='Close';
+if (typeof ol_compatmode=='undefined') var ol_compatmode=0;
+if (typeof ol_css=='undefined') var ol_css=CSSOFF;
+if (typeof ol_fgclass=='undefined') var ol_fgclass="";
+if (typeof ol_bgclass=='undefined') var ol_bgclass="";
+if (typeof ol_textfontclass=='undefined') var ol_textfontclass="";
+if (typeof ol_captionfontclass=='undefined') var ol_captionfontclass="";
+if (typeof ol_closefontclass=='undefined') var ol_closefontclass="";
+
+////////
+// ARRAY CONFIGURATION
+////////
+
+// You can use these arrays to store popup text here instead of in the html.
+if (typeof ol_texts=='undefined') var ol_texts = new Array("Text 0", "Text 1");
+if (typeof ol_caps=='undefined') var ol_caps = new Array("Caption 0", "Caption 1");
+
+////////
+// END OF CONFIGURATION
+// Don't change anything below this line, all configuration is above.
+////////
+
+
+
+
+
+////////
+// INIT
+////////
+// Runtime variables init. Don't change for config!
+var o3_text="";
+var o3_cap="";
+var o3_sticky=0;
+var o3_background="";
+var o3_close="Close";
+var o3_hpos=RIGHT;
+var o3_offsetx=2;
+var o3_offsety=2;
+var o3_fgcolor="";
+var o3_bgcolor="";
+var o3_textcolor="";
+var o3_capcolor="";
+var o3_closecolor="";
+var o3_width=100;
+var o3_border=1;
+var o3_cellpad=2;
+var o3_status="";
+var o3_autostatus=0;
+var o3_height=-1;
+var o3_snapx=0;
+var o3_snapy=0;
+var o3_fixx=-1;
+var o3_fixy=-1;
+var o3_relx=null;
+var o3_rely=null;
+var o3_fgbackground="";
+var o3_bgbackground="";
+var o3_padxl=0;
+var o3_padxr=0;
+var o3_padyt=0;
+var o3_padyb=0;
+var o3_fullhtml=0;
+var o3_vpos=BELOW;
+var o3_aboveheight=0;
+var o3_capicon="";
+var o3_textfont="Verdana,Arial,Helvetica";
+var o3_captionfont="Verdana,Arial,Helvetica";
+var o3_closefont="Verdana,Arial,Helvetica";
+var o3_textsize="1";
+var o3_captionsize="1";
+var o3_closesize="1";
+var o3_frame=self;
+var o3_timeout=0;
+var o3_timerid=0;
+var o3_allowmove=0;
+var o3_function=null; 
+var o3_delay=0;
+var o3_delayid=0;
+var o3_hauto=0;
+var o3_vauto=0;
+var o3_closeclick=0;
+var o3_wrap=0;
+var o3_followmouse=1;
+var o3_mouseoff=0;
+var o3_closetitle='';
+var o3_compatmode=0;
+var o3_css=CSSOFF;
+var o3_fgclass="";
+var o3_bgclass="";
+var o3_textfontclass="";
+var o3_captionfontclass="";
+var o3_closefontclass="";
+
+// Display state variables
+var o3_x = 0;
+var o3_y = 0;
+var o3_showingsticky = 0;
+var o3_removecounter = 0;
+
+// Our layer
+var over = null;
+var fnRef, hoveringSwitch = false;
+var olHideDelay;
+
+// Decide browser version
+var isMac = (navigator.userAgent.indexOf("Mac") != -1);
+var olOp = (navigator.userAgent.toLowerCase().indexOf('opera') > -1 && document.createTextNode);  // Opera 7
+var olNs4 = (navigator.appName=='Netscape' && parseInt(navigator.appVersion) == 4);
+var olNs6 = (document.getElementById) ? true : false;
+var olKq = (olNs6 && /konqueror/i.test(navigator.userAgent));
+var olIe4 = (document.all) ? true : false;
+var olIe5 = false; 
+var olIe55 = false; // Added additional variable to identify IE5.5+
+var docRoot = 'document.body';
+
+// Resize fix for NS4.x to keep track of layer
+if (olNs4) {
+	var oW = window.innerWidth;
+	var oH = window.innerHeight;
+	window.onresize = function() { if (oW != window.innerWidth || oH != window.innerHeight) location.reload(); }
+}
+
+// Microsoft Stupidity Check(tm).
+if (olIe4) {
+	var agent = navigator.userAgent;
+	if (/MSIE/.test(agent)) {
+		var versNum = parseFloat(agent.match(/MSIE[ ](\d\.\d+)\.*/i)[1]);
+		if (versNum >= 5){
+			olIe5=true;
+			olIe55=(versNum>=5.5&&!olOp) ? true : false;
+			if (olNs6) olNs6=false;
+		}
+	}
+	if (olNs6) olIe4 = false;
+}
+
+// Check for compatability mode.
+if (document.compatMode && document.compatMode == 'CSS1Compat') {
+	docRoot= ((olIe4 && !olOp) ? 'document.documentElement' : docRoot);
+}
+
+// Add window onload handlers to indicate when all modules have been loaded
+// For Netscape 6+ and Mozilla, uses addEventListener method on the window object
+// For IE it uses the attachEvent method of the window object and for Netscape 4.x
+// it sets the window.onload handler to the OLonload_handler function for Bubbling
+if(window.addEventListener) window.addEventListener("load",OLonLoad_handler,false);
+else if (window.attachEvent) window.attachEvent("onload",OLonLoad_handler);
+
+var capExtent;
+
+////////
+// PUBLIC FUNCTIONS
+////////
+
+// overlib(arg0,...,argN)
+// Loads parameters into global runtime variables.
+function overlib() {
+	if (!olLoaded || isExclusive(overlib.arguments)) return true;
+	if (olCheckMouseCapture) olMouseCapture();
+	if (over) {
+		over = (typeof over.id != 'string') ? o3_frame.document.all['overDiv'] : over;
+		cClick();
+	}
+
+	// Load defaults to runtime.
+  olHideDelay=0;
+	o3_text=ol_text;
+	o3_cap=ol_cap;
+	o3_sticky=ol_sticky;
+	o3_background=ol_background;
+	o3_close=ol_close;
+	o3_hpos=ol_hpos;
+	o3_offsetx=ol_offsetx;
+	o3_offsety=ol_offsety;
+	o3_fgcolor=ol_fgcolor;
+	o3_bgcolor=ol_bgcolor;
+	o3_textcolor=ol_textcolor;
+	o3_capcolor=ol_capcolor;
+	o3_closecolor=ol_closecolor;
+	o3_width=ol_width;
+	o3_border=ol_border;
+	o3_cellpad=ol_cellpad;
+	o3_status=ol_status;
+	o3_autostatus=ol_autostatus;
+	o3_height=ol_height;
+	o3_snapx=ol_snapx;
+	o3_snapy=ol_snapy;
+	o3_fixx=ol_fixx;
+	o3_fixy=ol_fixy;
+	o3_relx=ol_relx;
+	o3_rely=ol_rely;
+	o3_fgbackground=ol_fgbackground;
+	o3_bgbackground=ol_bgbackground;
+	o3_padxl=ol_padxl;
+	o3_padxr=ol_padxr;
+	o3_padyt=ol_padyt;
+	o3_padyb=ol_padyb;
+	o3_fullhtml=ol_fullhtml;
+	o3_vpos=ol_vpos;
+	o3_aboveheight=ol_aboveheight;
+	o3_capicon=ol_capicon;
+	o3_textfont=ol_textfont;
+	o3_captionfont=ol_captionfont;
+	o3_closefont=ol_closefont;
+	o3_textsize=ol_textsize;
+	o3_captionsize=ol_captionsize;
+	o3_closesize=ol_closesize;
+	o3_timeout=ol_timeout;
+	o3_function=ol_function;
+	o3_delay=ol_delay;
+	o3_hauto=ol_hauto;
+	o3_vauto=ol_vauto;
+	o3_closeclick=ol_closeclick;
+	o3_wrap=ol_wrap;	
+	o3_followmouse=ol_followmouse;
+	o3_mouseoff=ol_mouseoff;
+	o3_closetitle=ol_closetitle;
+	o3_css=ol_css;
+	o3_compatmode=ol_compatmode;
+	o3_fgclass=ol_fgclass;
+	o3_bgclass=ol_bgclass;
+	o3_textfontclass=ol_textfontclass;
+	o3_captionfontclass=ol_captionfontclass;
+	o3_closefontclass=ol_closefontclass;
+	
+	setRunTimeVariables();
+	
+	fnRef = '';
+	
+	// Special for frame support, over must be reset...
+	o3_frame = ol_frame;
+	
+	if(!(over=createDivContainer())) return false;
+
+	parseTokens('o3_', overlib.arguments);
+	if (!postParseChecks()) return false;
+
+	if (o3_delay == 0) {
+		return runHook("olMain", FREPLACE);
+ 	} else {
+		o3_delayid = setTimeout("runHook('olMain', FREPLACE)", o3_delay);
+		return false;
+	}
+}
+
+// Clears popups if appropriate
+function nd(time) {
+	if (olLoaded && !isExclusive()) {
+		hideDelay(time);  // delay popup close if time specified
+
+		if (o3_removecounter >= 1) { o3_showingsticky = 0 };
+		
+		if (o3_showingsticky == 0) {
+			o3_allowmove = 0;
+			if (over != null && o3_timerid == 0) runHook("hideObject", FREPLACE, over);
+		} else {
+			o3_removecounter++;
+		}
+	}
+	
+	return true;
+}
+
+// The Close onMouseOver function for stickies
+function cClick() {
+	if (olLoaded) {
+		runHook("hideObject", FREPLACE, over);
+		o3_showingsticky = 0;	
+	}	
+	return false;
+}
+
+// Method for setting page specific defaults.
+function overlib_pagedefaults() {
+	parseTokens('ol_', overlib_pagedefaults.arguments);
+}
+
+
+////////
+// OVERLIB MAIN FUNCTION
+////////
+
+// This function decides what it is we want to display and how we want it done.
+function olMain() {
+	var layerhtml, styleType;
+ 	runHook("olMain", FBEFORE);
+ 	
+	if (o3_background!="" || o3_fullhtml) {
+		// Use background instead of box.
+		layerhtml = runHook('ol_content_background', FALTERNATE, o3_css, o3_text, o3_background, o3_fullhtml);
+	} else {
+		// They want a popup box.
+		styleType = (pms[o3_css-1-pmStart] == "cssoff" || pms[o3_css-1-pmStart] == "cssclass");
+
+		// Prepare popup background
+		if (o3_fgbackground != "") o3_fgbackground = "background=\""+o3_fgbackground+"\"";
+		if (o3_bgbackground != "") o3_bgbackground = (styleType ? "background=\""+o3_bgbackground+"\"" : o3_bgbackground);
+
+		// Prepare popup colors
+		if (o3_fgcolor != "") o3_fgcolor = (styleType ? "bgcolor=\""+o3_fgcolor+"\"" : o3_fgcolor);
+		if (o3_bgcolor != "") o3_bgcolor = (styleType ? "bgcolor=\""+o3_bgcolor+"\"" : o3_bgcolor);
+
+		// Prepare popup height
+		if (o3_height > 0) o3_height = (styleType ? "height=\""+o3_height+"\"" : o3_height);
+		else o3_height = "";
+
+		// Decide which kinda box.
+		if (o3_cap=="") {
+			// Plain
+			layerhtml = runHook('ol_content_simple', FALTERNATE, o3_css, o3_text);
+		} else {
+			// With caption
+			if (o3_sticky) {
+				// Show close text
+				layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, o3_close);
+			} else {
+				// No close text
+				layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, "");
+			}
+		}
+	}	
+
+	// We want it to stick!
+	if (o3_sticky) {
+		if (o3_timerid > 0) {
+			clearTimeout(o3_timerid);
+			o3_timerid = 0;
+		}
+		o3_showingsticky = 1;
+		o3_removecounter = 0;
+	}
+
+	// Created a separate routine to generate the popup to make it easier
+	// to implement a plugin capability
+	if (!runHook("createPopup", FREPLACE, layerhtml)) return false;
+
+	// Prepare status bar
+	if (o3_autostatus > 0) {
+		o3_status = o3_text;
+		if (o3_autostatus > 1) o3_status = o3_cap;
+	}
+
+	// When placing the layer the first time, even stickies may be moved.
+	o3_allowmove = 0;
+
+	// Initiate a timer for timeout
+	if (o3_timeout > 0) {          
+		if (o3_timerid > 0) clearTimeout(o3_timerid);
+		o3_timerid = setTimeout("cClick()", o3_timeout);
+	}
+
+	// Show layer
+	runHook("disp", FREPLACE, o3_status);
+	runHook("olMain", FAFTER);
+
+	return (olOp && event && event.type == 'mouseover' && !o3_status) ? '' : (o3_status != '');
+}
+
+////////
+// LAYER GENERATION FUNCTIONS
+////////
+// These functions just handle popup content with tags that should adhere to the W3C standards specification.
+
+// Makes simple table without caption
+function ol_content_simple(text) {
+	var cpIsMultiple = /,/.test(o3_cellpad);
+	var txt = '<table width="'+o3_width+ '" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass ? 'class="'+o3_bgclass+'"' : o3_bgcolor+' '+o3_height)+'><tr><td><table width="100%" border="0" '+((olNs4||!cpIsMultiple) ? 'cellpadding="'+o3_cellpad+'" ' : '')+'cellspacing="0" '+(o3_fgclass ? 'class="'+o3_fgclass+'"' : o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign="TOP"'+(o3_textfontclass ? ' class="'+o3_textfontclass+'">' : ((!olNs4&&cpIsMultiple) ? ' style=" [...]
+
+	set_background("");
+	return txt;
+}
+
+// Makes table with caption and optional close link
+function ol_content_caption(text,title,close) {
+	var nameId, txt, cpIsMultiple = /,/.test(o3_cellpad);
+	var closing, closeevent;
+
+	closing = "";
+	closeevent = "onmouseover";
+	if (o3_closeclick == 1) closeevent = (o3_closetitle ? "title='" + o3_closetitle +"'" : "") + " onclick";
+	if (o3_capicon != "") {
+	  nameId = ' hspace = \"5\"'+' align = \"middle\" alt = \"\"';
+	  if (typeof o3_dragimg != 'undefined' && o3_dragimg) nameId =' hspace=\"5\"'+' name=\"'+o3_dragimg+'\" id=\"'+o3_dragimg+'\" align=\"middle\" alt=\"Drag Enabled\" title=\"Drag Enabled\"';
+	  o3_capicon = '<img src=\"'+o3_capicon+'\"'+nameId+' />';
+	}
+
+	if (close != "")
+		closing = '<td '+(!o3_compatmode && o3_closefontclass ? 'class="'+o3_closefontclass : 'align="RIGHT')+'"><a href="javascript:return '+fnRef+'cClick();"'+((o3_compatmode && o3_closefontclass) ? ' class="' + o3_closefontclass + '" ' : ' ')+closeevent+'="return '+fnRef+'cClick();">'+(o3_closefontclass ? '' : wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass ? '' : wrapStr(1,o3_closesize,'close'))+'</a></td>';
+	txt = '<table width="'+o3_width+ '" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass ? 'class="'+o3_bgclass+'"' : o3_bgcolor+' '+o3_bgbackground+' '+o3_height)+'><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="0"><tr><td'+(o3_captionfontclass ? ' class="'+o3_captionfontclass+'">' : '>')+(o3_captionfontclass ? '' : '<b>'+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass ? '' : wrapStr(1,o3_captionsize)+'</b>')+'</td>'+closi [...]
+
+	set_background("");
+	return txt;
+}
+
+// Sets the background picture,padding and lots more. :)
+function ol_content_background(text,picture,hasfullhtml) {
+	if (hasfullhtml) {
+		txt=text;
+	} else {
+		txt='<table width="'+o3_width+'" border="0" cellpadding="0" cellspacing="0" height="'+o3_height+'"><tr><td colspan="3" height="'+o3_padyt+'"></td></tr><tr><td width="'+o3_padxl+'"></td><td valign="TOP" width="'+(o3_width-o3_padxl-o3_padxr)+(o3_textfontclass ? '" class="'+o3_textfontclass : '')+'">'+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'</td><td width="'+o3_padxr+'"></td></tr><tr><td colspan="3" height="'+o3_padyb+ [...]
+	}
+
+	set_background(picture);
+	return txt;
+}
+
+// Loads a picture into the div.
+function set_background(pic) {
+	if (pic == "") {
+		if (olNs4) {
+			over.background.src = null; 
+		} else if (over.style) {
+			over.style.backgroundImage = "none";
+		}
+	} else {
+		if (olNs4) {
+			over.background.src = pic;
+		} else if (over.style) {
+			over.style.width=o3_width + 'px';
+			over.style.backgroundImage = "url("+pic+")";
+		}
+	}
+}
+
+////////
+// HANDLING FUNCTIONS
+////////
+var olShowId=-1;
+
+// Displays the popup
+function disp(statustext) {
+	runHook("disp", FBEFORE);
+	
+	if (o3_allowmove == 0) {
+		runHook("placeLayer", FREPLACE);
+		(olNs6&&olShowId<0) ? olShowId=setTimeout("runHook('showObject', FREPLACE, over)", 1) : runHook("showObject", FREPLACE, over);
+		o3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1;
+	}
+	
+	runHook("disp", FAFTER);
+
+	if (statustext != "") self.status = statustext;
+}
+
+// Creates the actual popup structure
+function createPopup(lyrContent){
+	runHook("createPopup", FBEFORE);
+	
+	if (o3_wrap) {
+		var wd,ww,theObj = (olNs4 ? over : over.style);
+		theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);
+		layerWrite(lyrContent);
+		wd = (olNs4 ? over.clip.width : over.offsetWidth);
+		if (wd > (ww=windowWidth())) {
+			lyrContent=lyrContent.replace(/\ /g, ' ');
+			o3_width=ww;
+			o3_wrap=0;
+		} 
+	}
+
+	layerWrite(lyrContent);
+	
+	// Have to set o3_width for placeLayer() routine if o3_wrap is turned on
+	if (o3_wrap) o3_width=(olNs4 ? over.clip.width : over.offsetWidth);
+	
+	runHook("createPopup", FAFTER, lyrContent);
+
+	return true;
+}
+
+// Decides where we want the popup.
+function placeLayer() {
+	var placeX, placeY, widthFix = 0;
+	
+	// HORIZONTAL PLACEMENT, re-arranged to work in Safari
+	if (o3_frame.innerWidth) widthFix=18; 
+	iwidth = windowWidth();
+
+	// Horizontal scroll offset
+	winoffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollLeft') : o3_frame.pageXOffset;
+
+	placeX = runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix);
+
+	// VERTICAL PLACEMENT, re-arranged to work in Safari
+	if (o3_frame.innerHeight) {
+		iheight=o3_frame.innerHeight;
+	} else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientHeight=='number'")&&eval('o3_frame.'+docRoot+'.clientHeight')) { 
+		iheight=eval('o3_frame.'+docRoot+'.clientHeight');
+	}			
+
+	// Vertical scroll offset
+	scrolloffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollTop') : o3_frame.pageYOffset;
+	placeY = runHook('verticalPlacement',FCHAIN,iheight,scrolloffset);
+
+	// Actually move the object.
+	repositionTo(over, placeX, placeY);
+}
+
+// Moves the layer
+function olMouseMove(e) {
+	var e = (e) ? e : event;
+
+	if (e.pageX) {
+		o3_x = e.pageX;
+		o3_y = e.pageY;
+	} else if (e.clientX) {
+		o3_x = eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');
+		o3_y = eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');
+	}
+	
+	if (o3_allowmove == 1) runHook("placeLayer", FREPLACE);
+
+	// MouseOut handler
+	if (hoveringSwitch && !olNs4 && runHook("cursorOff", FREPLACE)) {
+		(olHideDelay ? hideDelay(olHideDelay) : cClick());
+		hoveringSwitch = !hoveringSwitch;
+	}
+}
+
+// Fake function for 3.0 users.
+function no_overlib() { return ver3fix; }
+
+// Capture the mouse and chain other scripts.
+function olMouseCapture() {
+	capExtent = document;
+	var fN, str = '', l, k, f, wMv, sS, mseHandler = olMouseMove;
+	var re = /function[ ]*(\w*)\(/;
+	
+	wMv = (!olIe4 && window.onmousemove);
+	if (document.onmousemove || wMv) {
+		if (wMv) capExtent = window;
+		f = capExtent.onmousemove.toString();
+		fN = f.match(re);
+		if (fN == null) {
+			str = f+'(e); ';
+		} else if (fN[1] == 'anonymous' || fN[1] == 'olMouseMove' || (wMv && fN[1] == 'onmousemove')) {
+			if (!olOp && wMv) {
+				l = f.indexOf('{')+1;
+				k = f.lastIndexOf('}');
+				sS = f.substring(l,k);
+				if ((l = sS.indexOf('(')) != -1) {
+					sS = sS.substring(0,l).replace(/^\s+/,'').replace(/\s+$/,'');
+					if (eval("typeof " + sS + " == 'undefined'")) window.onmousemove = null;
+					else str = sS + '(e);';
+				}
+			}
+			if (!str) {
+				olCheckMouseCapture = false;
+				return;
+			}
+		} else {
+			if (fN[1]) str = fN[1]+'(e); ';
+			else {
+				l = f.indexOf('{')+1;
+				k = f.lastIndexOf('}');
+				str = f.substring(l,k) + '\n';
+			}
+		}
+		str += 'olMouseMove(e); ';
+		mseHandler = new Function('e', str);
+	}
+
+	capExtent.onmousemove = mseHandler;
+	if (olNs4) capExtent.captureEvents(Event.MOUSEMOVE);
+}
+
+////////
+// PARSING FUNCTIONS
+////////
+
+// Does the actual command parsing.
+function parseTokens(pf, ar) {
+	// What the next argument is expected to be.
+	var v, i, mode=-1, par = (pf != 'ol_');	
+	var fnMark = (par && !ar.length ? 1 : 0);
+
+	for (i = 0; i < ar.length; i++) {
+		if (mode < 0) {
+			// Arg is maintext,unless its a number between pmStart and pmUpper
+			// then its a command.
+			if (typeof ar[i] == 'number' && ar[i] > pmStart && ar[i] < pmUpper) {
+				fnMark = (par ? 1 : 0);
+				i--;   // backup one so that the next block can parse it
+			} else {
+				switch(pf) {
+					case 'ol_':
+						ol_text = ar[i].toString();
+						break;
+					default:
+						o3_text=ar[i].toString();  
+				}
+			}
+			mode = 0;
+		} else {
+			// Note: NS4 doesn't like switch cases with vars.
+			if (ar[i] >= pmCount || ar[i]==DONOTHING) { continue; }
+			if (ar[i]==INARRAY) { fnMark = 0; eval(pf+'text=ol_texts['+ar[++i]+'].toString()'); continue; }
+			if (ar[i]==CAPARRAY) { eval(pf+'cap=ol_caps['+ar[++i]+'].toString()'); continue; }
+			if (ar[i]==STICKY) { if (pf!='ol_') eval(pf+'sticky=1'); continue; }
+			if (ar[i]==BACKGROUND) { eval(pf+'background="'+ar[++i]+'"'); continue; }
+			if (ar[i]==NOCLOSE) { if (pf!='ol_') opt_NOCLOSE(); continue; }
+			if (ar[i]==CAPTION) { eval(pf+"cap='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CENTER || ar[i]==LEFT || ar[i]==RIGHT) { eval(pf+'hpos='+ar[i]); if(pf!='ol_') olHautoFlag=1; continue; }
+			if (ar[i]==OFFSETX) { eval(pf+'offsetx='+ar[++i]); continue; }
+			if (ar[i]==OFFSETY) { eval(pf+'offsety='+ar[++i]); continue; }
+			if (ar[i]==FGCOLOR) { eval(pf+'fgcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==BGCOLOR) { eval(pf+'bgcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TEXTCOLOR) { eval(pf+'textcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CAPCOLOR) { eval(pf+'capcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CLOSECOLOR) { eval(pf+'closecolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==WIDTH) { eval(pf+'width='+ar[++i]); continue; }
+			if (ar[i]==BORDER) { eval(pf+'border='+ar[++i]); continue; }
+			if (ar[i]==CELLPAD) { i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad')); continue; }
+			if (ar[i]==STATUS) { eval(pf+"status='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==AUTOSTATUS) { eval(pf +'autostatus=('+pf+'autostatus == 1) ? 0 : 1'); continue; }
+			if (ar[i]==AUTOSTATUSCAP) { eval(pf +'autostatus=('+pf+'autostatus == 2) ? 0 : 2'); continue; }
+			if (ar[i]==HEIGHT) { eval(pf+'height='+pf+'aboveheight='+ar[++i]); continue; } // Same param again.
+			if (ar[i]==CLOSETEXT) { eval(pf+"close='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==SNAPX) { eval(pf+'snapx='+ar[++i]); continue; }
+			if (ar[i]==SNAPY) { eval(pf+'snapy='+ar[++i]); continue; }
+			if (ar[i]==FIXX) { eval(pf+'fixx='+ar[++i]); continue; }
+			if (ar[i]==FIXY) { eval(pf+'fixy='+ar[++i]); continue; }
+			if (ar[i]==RELX) { eval(pf+'relx='+ar[++i]); continue; }
+			if (ar[i]==RELY) { eval(pf+'rely='+ar[++i]); continue; }
+			if (ar[i]==FGBACKGROUND) { eval(pf+'fgbackground="'+ar[++i]+'"'); continue; }
+			if (ar[i]==BGBACKGROUND) { eval(pf+'bgbackground="'+ar[++i]+'"'); continue; }
+			if (ar[i]==PADX) { eval(pf+'padxl='+ar[++i]); eval(pf+'padxr='+ar[++i]); continue; }
+			if (ar[i]==PADY) { eval(pf+'padyt='+ar[++i]); eval(pf+'padyb='+ar[++i]); continue; }
+			if (ar[i]==FULLHTML) { if (pf!='ol_') eval(pf+'fullhtml=1'); continue; }
+			if (ar[i]==BELOW || ar[i]==ABOVE) { eval(pf+'vpos='+ar[i]); if (pf!='ol_') olVautoFlag=1; continue; }
+			if (ar[i]==CAPICON) { eval(pf+'capicon="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TEXTFONT) { eval(pf+"textfont='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CAPTIONFONT) { eval(pf+"captionfont='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CLOSEFONT) { eval(pf+"closefont='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==TEXTSIZE) { eval(pf+'textsize="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CAPTIONSIZE) { eval(pf+'captionsize="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CLOSESIZE) { eval(pf+'closesize="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TIMEOUT) { eval(pf+'timeout='+ar[++i]); continue; }
+			if (ar[i]==FUNCTION) { if (pf=='ol_') { if (typeof ar[i+1]!='number') { v=ar[++i]; ol_function=(typeof v=='function' ? v : null); }} else {fnMark = 0; v = null; if (typeof ar[i+1]!='number') v = ar[++i];  opt_FUNCTION(v); } continue; }
+			if (ar[i]==DELAY) { eval(pf+'delay='+ar[++i]); continue; }
+			if (ar[i]==HAUTO) { eval(pf+'hauto=('+pf+'hauto == 0) ? 1 : 0'); continue; }
+			if (ar[i]==VAUTO) { eval(pf+'vauto=('+pf+'vauto == 0) ? 1 : 0'); continue; }
+			if (ar[i]==CLOSECLICK) { eval(pf +'closeclick=('+pf+'closeclick == 0) ? 1 : 0'); continue; }
+			if (ar[i]==WRAP) { eval(pf +'wrap=('+pf+'wrap == 0) ? 1 : 0'); continue; }
+			if (ar[i]==FOLLOWMOUSE) { eval(pf +'followmouse=('+pf+'followmouse == 1) ? 0 : 1'); continue; }
+			if (ar[i]==MOUSEOFF) { eval(pf +'mouseoff=('+pf+'mouseoff==0) ? 1 : 0'); v=ar[i+1]; if (pf != 'ol_' && eval(pf+'mouseoff') && typeof v == 'number' && (v < pmStart || v > pmUpper)) olHideDelay=ar[++i]; continue; }
+			if (ar[i]==CLOSETITLE) { eval(pf+"closetitle='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CSSOFF||ar[i]==CSSCLASS) { eval(pf+'css='+ar[i]); continue; }
+			if (ar[i]==COMPATMODE) { eval(pf+'compatmode=('+pf+'compatmode==0) ? 1 : 0'); continue; }
+			if (ar[i]==FGCLASS) { eval(pf+'fgclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==BGCLASS) { eval(pf+'bgclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TEXTFONTCLASS) { eval(pf+'textfontclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CAPTIONFONTCLASS) { eval(pf+'captionfontclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CLOSEFONTCLASS) { eval(pf+'closefontclass="'+ar[++i]+'"'); continue; }
+			i = parseCmdLine(pf, i, ar);
+		}
+	}
+
+	if (fnMark && o3_function) o3_text = o3_function();
+	
+	if ((pf == 'o3_') && o3_wrap) {
+		o3_width = 0;
+		
+		var tReg=/<.*\n*>/ig;
+		if (!tReg.test(o3_text)) o3_text = o3_text.replace(/[ ]+/g, ' ');
+		if (!tReg.test(o3_cap))o3_cap = o3_cap.replace(/[ ]+/g, ' ');
+	}
+	if ((pf == 'o3_') && o3_sticky) {
+		if (!o3_close && (o3_frame != ol_frame)) o3_close = ol_close;
+		if (o3_mouseoff && (o3_frame == ol_frame)) opt_NOCLOSE(' ');
+	}
+}
+
+
+////////
+// LAYER FUNCTIONS
+////////
+
+// Writes to a layer
+function layerWrite(txt) {
+	txt += "\n";
+	if (olNs4) {
+		var lyr = o3_frame.document.layers['overDiv'].document
+		lyr.write(txt)
+		lyr.close()
+	} else if (typeof over.innerHTML != 'undefined') {
+		if (olIe5 && isMac) over.innerHTML = '';
+		over.innerHTML = txt;
+	} else {
+		range = o3_frame.document.createRange();
+		range.setStartAfter(over);
+		domfrag = range.createContextualFragment(txt);
+		
+		while (over.hasChildNodes()) {
+			over.removeChild(over.lastChild);
+		}
+		
+		over.appendChild(domfrag);
+	}
+}
+
+// Make an object visible
+function showObject(obj) {
+	runHook("showObject", FBEFORE);
+
+	var theObj=(olNs4 ? obj : obj.style);
+	theObj.visibility = 'visible';
+
+	runHook("showObject", FAFTER);
+}
+
+// Hides an object
+function hideObject(obj) {
+	runHook("hideObject", FBEFORE);
+
+	var theObj=(olNs4 ? obj : obj.style);
+	if (olNs6 && olShowId>0) { clearTimeout(olShowId); olShowId=0; }
+	theObj.visibility = 'hidden';
+	theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);
+
+	if (o3_timerid > 0) clearTimeout(o3_timerid);
+	if (o3_delayid > 0) clearTimeout(o3_delayid);
+
+	o3_timerid = 0;
+	o3_delayid = 0;
+	self.status = "";
+
+	if (obj.onmouseout||obj.onmouseover) {
+		if (olNs4) obj.releaseEvents(Event.MOUSEOUT || Event.MOUSEOVER);
+		obj.onmouseout = obj.onmouseover = null;
+	}
+
+	runHook("hideObject", FAFTER);
+}
+
+// Move a layer
+function repositionTo(obj, xL, yL) {
+	var theObj=(olNs4 ? obj : obj.style);
+	theObj.left = xL + (!olNs4 ? 'px' : 0);
+	theObj.top = yL + (!olNs4 ? 'px' : 0);
+}
+
+// Check position of cursor relative to overDiv DIVision; mouseOut function
+function cursorOff() {
+	var left = parseInt(over.style.left);
+	var top = parseInt(over.style.top);
+	var right = left + (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width));
+	var bottom = top + (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight);
+
+	if (o3_x < left || o3_x > right || o3_y < top || o3_y > bottom) return true;
+
+	return false;
+}
+
+
+////////
+// COMMAND FUNCTIONS
+////////
+
+// Calls callme or the default function.
+function opt_FUNCTION(callme) {
+	o3_text = (callme ? (typeof callme=='string' ? (/.+\(.*\)/.test(callme) ? eval(callme) : callme) : callme()) : (o3_function ? o3_function() : 'No Function'));
+
+	return 0;
+}
+
+// Handle hovering
+function opt_NOCLOSE(unused) {
+	if (!unused) o3_close = "";
+
+	if (olNs4) {
+		over.captureEvents(Event.MOUSEOUT || Event.MOUSEOVER);
+		over.onmouseover = function () { if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid = 0; } }
+		over.onmouseout = function (e) { if (olHideDelay) hideDelay(olHideDelay); else cClick(e); }
+	} else {
+		over.onmouseover = function () {hoveringSwitch = true; if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid =0; } }
+	}
+
+	return 0;
+}
+
+// Function to scan command line arguments for multiples
+function opt_MULTIPLEARGS(i, args, parameter) {
+  var k=i, re, pV, str='';
+
+  for(k=i; k<args.length; k++) {
+		if(typeof args[k] == 'number' && args[k]>pmStart) break;
+		str += args[k] + ',';
+	}
+	if (str) str = str.substring(0,--str.length);
+
+	k--;  // reduce by one so the for loop this is in works correctly
+	pV=(olNs4 && /cellpad/i.test(parameter)) ? str.split(',')[0] : str;
+	eval(parameter + '="' + pV + '"');
+
+	return k;
+}
+
+// Remove   in texts when done.
+function nbspCleanup() {
+	if (o3_wrap) {
+		o3_text = o3_text.replace(/\ /g, ' ');
+		o3_cap = o3_cap.replace(/\ /g, ' ');
+	}
+}
+
+// Escape embedded single quotes in text strings
+function escSglQuote(str) {
+  return str.toString().replace(/'/g,"\\'");
+}
+
+// Onload handler for window onload event
+function OLonLoad_handler(e) {
+	var re = /\w+\(.*\)[;\s]+/g, olre = /overlib\(|nd\(|cClick\(/, fn, l, i;
+
+	if(!olLoaded) olLoaded=1;
+
+  // Remove it for Gecko based browsers
+	if(window.removeEventListener && e.eventPhase == 3) window.removeEventListener("load",OLonLoad_handler,false);
+	else if(window.detachEvent) { // and for IE and Opera 4.x but execute calls to overlib, nd, or cClick()
+		window.detachEvent("onload",OLonLoad_handler);
+		var fN = document.body.getAttribute('onload');
+		if (fN) {
+			fN=fN.toString().match(re);
+			if (fN && fN.length) {
+				for (i=0; i<fN.length; i++) {
+					if (/anonymous/.test(fN[i])) continue;
+					while((l=fN[i].search(/\)[;\s]+/)) != -1) {
+						fn=fN[i].substring(0,l+1);
+						fN[i] = fN[i].substring(l+2);
+						if (olre.test(fn)) eval(fn);
+					}
+				}
+			}
+		}
+	}
+}
+
+// Wraps strings in Layer Generation Functions with the correct tags
+//    endWrap true(if end tag) or false if start tag
+//    fontSizeStr - font size string such as '1' or '10px'
+//    whichString is being wrapped -- 'text', 'caption', or 'close'
+function wrapStr(endWrap,fontSizeStr,whichString) {
+	var fontStr, fontColor, isClose=((whichString=='close') ? 1 : 0), hasDims=/[%\-a-z]+$/.test(fontSizeStr);
+	fontSizeStr = (olNs4) ? (!hasDims ? fontSizeStr : '1') : fontSizeStr;
+	if (endWrap) return (hasDims&&!olNs4) ? (isClose ? '</span>' : '</div>') : '</font>';
+	else {
+		fontStr='o3_'+whichString+'font';
+		fontColor='o3_'+((whichString=='caption')? 'cap' : whichString)+'color';
+		return (hasDims&&!olNs4) ? (isClose ? '<span style="font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';">' : '<div style="font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';">') : '<font face="'+eval(fontStr)+'" color="'+eval(fontColor)+'" size="'+(parseInt(fontSizeStr)>7 ? '7' : fontSizeStr)+'">';
+	}
+}
+
+// Quotes Multi word font names; needed for CSS Standards adherence in font-family
+function quoteMultiNameFonts(theFont) {
+	var v, pM=theFont.split(',');
+	for (var i=0; i<pM.length; i++) {
+		v=pM[i];
+		v=v.replace(/^\s+/,'').replace(/\s+$/,'');
+		if(/\s/.test(v) && !/['"]/.test(v)) {
+			v="\'"+v+"\'";
+			pM[i]=v;
+		}
+	}
+	return pM.join();
+}
+
+// dummy function which will be overridden 
+function isExclusive(args) {
+	return false;
+}
+
+// Sets cellpadding style string value
+function setCellPadStr(parameter) {
+	var Str='', j=0, ary = new Array(), top, bottom, left, right;
+
+	Str+='padding: ';
+	ary=parameter.replace(/\s+/g,'').split(',');
+
+	switch(ary.length) {
+		case 2:
+			top=bottom=ary[j];
+			left=right=ary[++j];
+			break;
+		case 3:
+			top=ary[j];
+			left=right=ary[++j];
+			bottom=ary[++j];
+			break;
+		case 4:
+			top=ary[j];
+			right=ary[++j];
+			bottom=ary[++j];
+			left=ary[++j];
+			break;
+	}
+
+	Str+= ((ary.length==1) ? ary[0] + 'px;' : top + 'px ' + right + 'px ' + bottom + 'px ' + left + 'px;');
+
+	return Str;
+}
+
+// function will delay close by time milliseconds
+function hideDelay(time) {
+	if (time&&!o3_delay) {
+		if (o3_timerid > 0) clearTimeout(o3_timerid);
+
+		o3_timerid=setTimeout("cClick()",(o3_timeout=time));
+	}
+}
+
+// Was originally in the placeLayer() routine; separated out for future ease
+function horizontalPlacement(browserWidth, horizontalScrollAmount, widthFix) {
+	var placeX, iwidth=browserWidth, winoffset=horizontalScrollAmount;
+	var parsedWidth = parseInt(o3_width);
+
+	if (o3_fixx > -1 || o3_relx != null) {
+		// Fixed position
+		placeX=(o3_relx != null ? ( o3_relx < 0 ? winoffset +o3_relx+ iwidth - parsedWidth - widthFix : winoffset+o3_relx) : o3_fixx);
+	} else {  
+		// If HAUTO, decide what to use.
+		if (o3_hauto == 1) {
+			if ((o3_x - winoffset) > (iwidth / 2)) {
+				o3_hpos = LEFT;
+			} else {
+				o3_hpos = RIGHT;
+			}
+		}  		
+
+		// From mouse
+		if (o3_hpos == CENTER) { // Center
+			placeX = o3_x+o3_offsetx-(parsedWidth/2);
+
+			if (placeX < winoffset) placeX = winoffset;
+		}
+
+		if (o3_hpos == RIGHT) { // Right
+			placeX = o3_x+o3_offsetx;
+
+			if ((placeX+parsedWidth) > (winoffset+iwidth - widthFix)) {
+				placeX = iwidth+winoffset - parsedWidth - widthFix;
+				if (placeX < 0) placeX = 0;
+			}
+		}
+		if (o3_hpos == LEFT) { // Left
+			placeX = o3_x-o3_offsetx-parsedWidth;
+			if (placeX < winoffset) placeX = winoffset;
+		}  	
+
+		// Snapping!
+		if (o3_snapx > 1) {
+			var snapping = placeX % o3_snapx;
+
+			if (o3_hpos == LEFT) {
+				placeX = placeX - (o3_snapx+snapping);
+			} else {
+				// CENTER and RIGHT
+				placeX = placeX+(o3_snapx - snapping);
+			}
+
+			if (placeX < winoffset) placeX = winoffset;
+		}
+	}	
+
+	return placeX;
+}
+
+// was originally in the placeLayer() routine; separated out for future ease
+function verticalPlacement(browserHeight,verticalScrollAmount) {
+	var placeY, iheight=browserHeight, scrolloffset=verticalScrollAmount;
+	var parsedHeight=(o3_aboveheight ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight));
+
+	if (o3_fixy > -1 || o3_rely != null) {
+		// Fixed position
+		placeY=(o3_rely != null ? (o3_rely < 0 ? scrolloffset+o3_rely+iheight - parsedHeight : scrolloffset+o3_rely) : o3_fixy);
+	} else {
+		// If VAUTO, decide what to use.
+		if (o3_vauto == 1) {
+			if ((o3_y - scrolloffset) > (iheight / 2) && o3_vpos == BELOW && (o3_y + parsedHeight + o3_offsety - (scrolloffset + iheight) > 0)) {
+				o3_vpos = ABOVE;
+			} else if (o3_vpos == ABOVE && (o3_y - (parsedHeight + o3_offsety) - scrolloffset < 0)) {
+				o3_vpos = BELOW;
+			}
+		}
+
+		// From mouse
+		if (o3_vpos == ABOVE) {
+			if (o3_aboveheight == 0) o3_aboveheight = parsedHeight; 
+
+			placeY = o3_y - (o3_aboveheight+o3_offsety);
+			if (placeY < scrolloffset) placeY = scrolloffset;
+		} else {
+			// BELOW
+			placeY = o3_y+o3_offsety;
+		} 
+
+		// Snapping!
+		if (o3_snapy > 1) {
+			var snapping = placeY % o3_snapy;  			
+
+			if (o3_aboveheight > 0 && o3_vpos == ABOVE) {
+				placeY = placeY - (o3_snapy+snapping);
+			} else {
+				placeY = placeY+(o3_snapy - snapping);
+			} 			
+
+			if (placeY < scrolloffset) placeY = scrolloffset;
+		}
+	}
+
+	return placeY;
+}
+
+// checks positioning flags
+function checkPositionFlags() {
+	if (olHautoFlag) olHautoFlag = o3_hauto=0;
+	if (olVautoFlag) olVautoFlag = o3_vauto=0;
+	return true;
+}
+
+// get Browser window width
+function windowWidth() {
+	var w;
+	if (o3_frame.innerWidth) w=o3_frame.innerWidth;
+	else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientWidth=='number'")&&eval('o3_frame.'+docRoot+'.clientWidth')) 
+		w=eval('o3_frame.'+docRoot+'.clientWidth');
+	return w;			
+}
+
+// create the div container for popup content if it doesn't exist
+function createDivContainer(id,frm,zValue) {
+	id = (id || 'overDiv'), frm = (frm || o3_frame), zValue = (zValue || 1000);
+	var objRef, divContainer = layerReference(id);
+
+	if (divContainer == null) {
+		if (olNs4) {
+			divContainer = frm.document.layers[id] = new Layer(window.innerWidth, frm);
+			objRef = divContainer;
+		} else {
+			var body = (olIe4 ? frm.document.all.tags('BODY')[0] : frm.document.getElementsByTagName("BODY")[0]);
+			if (olIe4&&!document.getElementById) {
+				body.insertAdjacentHTML("beforeEnd",'<div id="'+id+'"></div>');
+				divContainer=layerReference(id);
+			} else {
+				divContainer = frm.document.createElement("DIV");
+				divContainer.id = id;
+				body.appendChild(divContainer);
+			}
+			objRef = divContainer.style;
+		}
+
+		objRef.position = 'absolute';
+		objRef.visibility = 'hidden';
+		objRef.zIndex = zValue;
+		if (olIe4&&!olOp) objRef.left = objRef.top = '0px';
+		else objRef.left = objRef.top =  -10000 + (!olNs4 ? 'px' : 0);
+	}
+
+	return divContainer;
+}
+
+// get reference to a layer with ID=id
+function layerReference(id) {
+	return (olNs4 ? o3_frame.document.layers[id] : (document.all ? o3_frame.document.all[id] : o3_frame.document.getElementById(id)));
+}
+////////
+//  UTILITY FUNCTIONS
+////////
+
+// Checks if something is a function.
+function isFunction(fnRef) {
+	var rtn = true;
+
+	if (typeof fnRef == 'object') {
+		for (var i = 0; i < fnRef.length; i++) {
+			if (typeof fnRef[i]=='function') continue;
+			rtn = false;
+			break;
+		}
+	} else if (typeof fnRef != 'function') {
+		rtn = false;
+	}
+	
+	return rtn;
+}
+
+// Converts an array into an argument string for use in eval.
+function argToString(array, strtInd, argName) {
+	var jS = strtInd, aS = '', ar = array;
+	argName=(argName ? argName : 'ar');
+	
+	if (ar.length > jS) {
+		for (var k = jS; k < ar.length; k++) aS += argName+'['+k+'], ';
+		aS = aS.substring(0, aS.length-2);
+	}
+	
+	return aS;
+}
+
+// Places a hook in the correct position in a hook point.
+function reOrder(hookPt, fnRef, order) {
+	var newPt = new Array(), match, i, j;
+
+	if (!order || typeof order == 'undefined' || typeof order == 'number') return hookPt;
+	
+	if (typeof order=='function') {
+		if (typeof fnRef=='object') {
+			newPt = newPt.concat(fnRef);
+		} else {
+			newPt[newPt.length++]=fnRef;
+		}
+		
+		for (i = 0; i < hookPt.length; i++) {
+			match = false;
+			if (typeof fnRef == 'function' && hookPt[i] == fnRef) {
+				continue;
+			} else {
+				for(j = 0; j < fnRef.length; j++) if (hookPt[i] == fnRef[j]) {
+					match = true;
+					break;
+				}
+			}
+			if (!match) newPt[newPt.length++] = hookPt[i];
+		}
+
+		newPt[newPt.length++] = order;
+
+	} else if (typeof order == 'object') {
+		if (typeof fnRef == 'object') {
+			newPt = newPt.concat(fnRef);
+		} else {
+			newPt[newPt.length++] = fnRef;
+		}
+		
+		for (j = 0; j < hookPt.length; j++) {
+			match = false;
+			if (typeof fnRef == 'function' && hookPt[j] == fnRef) {
+				continue;
+			} else {
+				for (i = 0; i < fnRef.length; i++) if (hookPt[j] == fnRef[i]) {
+					match = true;
+					break;
+				}
+			}
+			if (!match) newPt[newPt.length++]=hookPt[j];
+		}
+
+		for (i = 0; i < newPt.length; i++) hookPt[i] = newPt[i];
+		newPt.length = 0;
+		
+		for (j = 0; j < hookPt.length; j++) {
+			match = false;
+			for (i = 0; i < order.length; i++) {
+				if (hookPt[j] == order[i]) {
+					match = true;
+					break;
+				}
+			}
+			if (!match) newPt[newPt.length++] = hookPt[j];
+		}
+		newPt = newPt.concat(order);
+	}
+
+	hookPt = newPt;
+
+	return hookPt;
+}
+
+////////
+//  PLUGIN ACTIVATION FUNCTIONS
+////////
+
+// Runs plugin functions to set runtime variables.
+function setRunTimeVariables(){
+	if (typeof runTime != 'undefined' && runTime.length) {
+		for (var k = 0; k < runTime.length; k++) {
+			runTime[k]();
+		}
+	}
+}
+
+// Runs plugin functions to parse commands.
+function parseCmdLine(pf, i, args) {
+	if (typeof cmdLine != 'undefined' && cmdLine.length) { 
+		for (var k = 0; k < cmdLine.length; k++) { 
+			var j = cmdLine[k](pf, i, args);
+			if (j >- 1) {
+				i = j;
+				break;
+			}
+		}
+	}
+
+	return i;
+}
+
+// Runs plugin functions to do things after parse.
+function postParseChecks(pf,args){
+	if (typeof postParse != 'undefined' && postParse.length) {
+		for (var k = 0; k < postParse.length; k++) {
+			if (postParse[k](pf,args)) continue;
+			return false;  // end now since have an error
+		}
+	}
+	return true;
+}
+
+
+////////
+//  PLUGIN REGISTRATION FUNCTIONS
+////////
+
+// Registers commands and creates constants.
+function registerCommands(cmdStr) {
+	if (typeof cmdStr!='string') return;
+
+	var pM = cmdStr.split(',');
+	pms = pms.concat(pM);
+
+	for (var i = 0; i< pM.length; i++) {
+		eval(pM[i].toUpperCase()+'='+pmCount++);
+	}
+}
+
+// Registers no-parameter commands
+function registerNoParameterCommands(cmdStr) {
+	if (!cmdStr && typeof cmdStr != 'string') return;
+	pmt=(!pmt) ? cmdStr : pmt + ',' + cmdStr;
+}
+
+// Register a function to hook at a certain point.
+function registerHook(fnHookTo, fnRef, hookType, optPm) {
+	var hookPt, last = typeof optPm;
+	
+	if (fnHookTo == 'plgIn'||fnHookTo == 'postParse') return;
+	if (typeof hookPts[fnHookTo] == 'undefined') hookPts[fnHookTo] = new FunctionReference();
+
+	hookPt = hookPts[fnHookTo];
+
+	if (hookType != null) {
+		if (hookType == FREPLACE) {
+			hookPt.ovload = fnRef;  // replace normal overlib routine
+			if (fnHookTo.indexOf('ol_content_') > -1) hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef; 
+
+		} else if (hookType == FBEFORE || hookType == FAFTER) {
+			var hookPt=(hookType == 1 ? hookPt.before : hookPt.after);
+
+			if (typeof fnRef == 'object') {
+				hookPt = hookPt.concat(fnRef);
+			} else {
+				hookPt[hookPt.length++] = fnRef;
+			}
+
+			if (optPm) hookPt = reOrder(hookPt, fnRef, optPm);
+
+		} else if (hookType == FALTERNATE) {
+			if (last=='number') hookPt.alt[pms[optPm-1-pmStart]] = fnRef;
+		} else if (hookType == FCHAIN) {
+			hookPt = hookPt.chain; 
+			if (typeof fnRef=='object') hookPt=hookPt.concat(fnRef); // add other functions 
+			else hookPt[hookPt.length++]=fnRef;
+		}
+
+		return;
+	}
+}
+
+// Register a function that will set runtime variables.
+function registerRunTimeFunction(fn) {
+	if (isFunction(fn)) {
+		if (typeof fn == 'object') {
+			runTime = runTime.concat(fn);
+		} else {
+			runTime[runTime.length++] = fn;
+		}
+	}
+}
+
+// Register a function that will handle command parsing.
+function registerCmdLineFunction(fn){
+	if (isFunction(fn)) {
+		if (typeof fn == 'object') {
+			cmdLine = cmdLine.concat(fn);
+		} else {
+			cmdLine[cmdLine.length++] = fn;
+		}
+	}
+}
+
+// Register a function that does things after command parsing. 
+function registerPostParseFunction(fn){
+	if (isFunction(fn)) {
+		if (typeof fn == 'object') {
+			postParse = postParse.concat(fn);
+		} else {
+			postParse[postParse.length++] = fn;
+		}
+	}
+}
+
+////////
+//  PLUGIN REGISTRATION FUNCTIONS
+////////
+
+// Runs any hooks registered.
+function runHook(fnHookTo, hookType) {
+	var l = hookPts[fnHookTo], k, rtnVal = null, optPm, arS, ar = runHook.arguments;
+
+	if (hookType == FREPLACE) {
+		arS = argToString(ar, 2);
+
+		if (typeof l == 'undefined' || !(l = l.ovload)) rtnVal = eval(fnHookTo+'('+arS+')');
+		else rtnVal = eval('l('+arS+')');
+
+	} else if (hookType == FBEFORE || hookType == FAFTER) {
+		if (typeof l != 'undefined') {
+			l=(hookType == 1 ? l.before : l.after);
+	
+			if (l.length) {
+				arS = argToString(ar, 2);
+				for (var k = 0; k < l.length; k++) eval('l[k]('+arS+')');
+			}
+		}
+	} else if (hookType == FALTERNATE) {
+		optPm = ar[2];
+		arS = argToString(ar, 3);
+
+		if (typeof l == 'undefined' || (l = l.alt[pms[optPm-1-pmStart]]) == 'undefined') {
+			rtnVal = eval(fnHookTo+'('+arS+')');
+		} else {
+			rtnVal = eval('l('+arS+')');
+		}
+	} else if (hookType == FCHAIN) {
+		arS=argToString(ar,2);
+		l=l.chain;
+
+		for (k=l.length; k > 0; k--) if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0)) break;
+	}
+
+	return rtnVal;
+}
+
+////////
+// OBJECT CONSTRUCTORS
+////////
+
+// Object for handling hooks.
+function FunctionReference() {
+	this.ovload = null;
+	this.before = new Array();
+	this.after = new Array();
+	this.alt = new Array();
+	this.chain = new Array();
+}
+
+// Object for simple access to the overLIB version used.
+// Examples: simpleversion:351 major:3 minor:5 revision:1
+function Info(version, prerelease) {
+	this.version = version;
+	this.prerelease = prerelease;
+
+	this.simpleversion = Math.round(this.version*100);
+	this.major = parseInt(this.simpleversion / 100);
+	this.minor = parseInt(this.simpleversion / 10) - this.major * 10;
+	this.revision = parseInt(this.simpleversion) - this.major * 100 - this.minor * 10;
+	this.meets = meets;
+}
+
+// checks for Core Version required
+function meets(reqdVersion) {
+	return (!reqdVersion) ? false : this.simpleversion >= Math.round(100*parseFloat(reqdVersion));
+}
+
+
+////////
+// STANDARD REGISTRATIONS
+////////
+registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSOFF);
+registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSOFF);
+registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSOFF);
+registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSCLASS);
+registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSCLASS);
+registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSCLASS);
+registerPostParseFunction(checkPositionFlags);
+registerHook("hideObject", nbspCleanup, FAFTER);
+registerHook("horizontalPlacement", horizontalPlacement, FCHAIN);
+registerHook("verticalPlacement", verticalPlacement, FCHAIN);
+if (olNs4||(olIe5&&isMac)||olKq) olLoaded=1;
+registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode');
+///////
+// ESTABLISH MOUSECAPTURING
+///////
+
+// Capture events, alt. diffuses the overlib function.
+var olCheckMouseCapture=true;
+if ((olNs4 || olNs6 || olIe4)) {
+	olMouseCapture();
+} else {
+	overlib = no_overlib;
+	nd = no_overlib;
+	ver3fix = true;
+}
diff --git a/cgview/includes/stylesheet.css b/cgview/includes/stylesheet.css
new file mode 100644
index 0000000..67304a8
--- /dev/null
+++ b/cgview/includes/stylesheet.css
@@ -0,0 +1,19 @@
+/* Paul Stothard, University of Alberta 2004 */
+
+body {background-color: #FFFFFF; font-family: arial, sans-serif; color: #000000;}
+span.note {font-size: medium; font-style: italic; font-weight: bold;}
+span.comment {font-size: small; font-style: italic;}
+span.validInfo {font-size: x-small;}
+span.fileSize {font-size: x-small;}
+span.warning {font-size: x-small; color: red;}
+div.heading {color: #FFFFFF; background-color: #6666FF; font-size: large; padding: 0.1cm;}
+div.title {font-size: x-large; text-align: center;}
+table.noBorder {border-style: none;}
+table.border {border-style: solid;}
+td.center {text-align: center; font-size: small;}
+td.left {text-align: left; font-size: small;}
+td.right {text-align: right; font-size: small;}	
+a:link {color: #000099; text-decoration: none;}
+a:visited {color: #000099; text-decoration: none;}
+a:active {color: #FF0000; text-decoration: underline;}
+a:hover {color: #FF0000; text-decoration: underline;}
diff --git a/cgview/manifestinfo b/cgview/manifestinfo
new file mode 100644
index 0000000..793ae54
--- /dev/null
+++ b/cgview/manifestinfo
@@ -0,0 +1,6 @@
+Main-Class: ca/ualberta/stothard/cgview/CgviewIO
+Class-Path: lib/batik-awt-util.jar lib/batik-dom.jar lib/batik-svggen.jar lib/batik-util.jar lib/batik-xml.jar lib/commons-lang-2.0.jar lib/jargs.jar lib/xercesImpl.jar
+
+
+
+
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Cgview.class b/cgview/src/ca/ualberta/stothard/cgview/Cgview.class
new file mode 100644
index 0000000..04bbce0
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/Cgview.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Cgview.java b/cgview/src/ca/ualberta/stothard/cgview/Cgview.java
new file mode 100644
index 0000000..9aa4d64
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/Cgview.java
@@ -0,0 +1,3693 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.awt.font.GlyphVector;
+import java.awt.geom.*;
+import java.util.*;
+import java.text.*;
+import java.util.regex.*;
+
+/**
+ * Represents a circular map of a DNA sequence. Numerous methods are available for controlling the overall appearance of
+ * the map (width, height, background color, etc). The contents of the map are described in terms of {@link
+ * FeatureSlot}, {@link Feature}, {@link FeatureRange}, {@link Legend}, and {@link LegendItem} objects.
+ *
+ * @author Paul Stothard
+ */
+
+public class Cgview implements CgviewConstants {
+
+    private Graphics2D gg;
+
+    private int sequenceLength;
+    private int width = 700;
+    private int height = 700;
+    private int smallestDimension = 700;
+    private Color backgroundColor = new Color(255, 255, 255); //white
+
+    private double backboneRadius = 190.0d;
+    private float backboneThickness = 5.0f;
+    private Color backboneColor = new Color(128, 128, 128);  //gray
+
+    private double origin = 90.0d;
+
+    private float featureThickness = 8.0f;
+    private double featureSlotSpacing = 4.0d;
+    private double arrowheadLength = 5.0d;
+    private boolean shiftSmallFeatures = true;
+    private double minimumFeatureLength = 0.02d;
+
+    private boolean showShading = true;
+    private float shadingProportion = 0.2f;
+    private float highlightOpacity = 0.3f;
+    private float shadowOpacity = 0.3f;
+
+    //private int desiredNumberOfTicks = 30;
+    private int desiredNumberOfTicks = 25;
+    private float tickThickness = 2.0f;
+    private Color longTickColor = new Color(0, 0, 0);  //black
+    private Color shortTickColor = new Color(0, 0, 0);  //black
+    private float shortTickThickness = 2.0f;
+    private Color zeroTickColor = new Color(0, 0, 0);  //black
+    private float tickLength = 7.0f;
+    private boolean drawTickMarks = true;
+    private double tickDensity = 1.0d;
+
+    private int rulerUnits = BASES;
+    private Font rulerFont = new Font("SansSerif", Font.PLAIN, 8);
+    private double rulerTextPadding = 10.0d;
+    private Color rulerFontColor = new Color(0, 0, 0);  //black
+
+    private String title = "";
+    private Font titleFont = new Font("SansSerif", Font.PLAIN, 12);
+    private Color titleFontColor = new Color(0, 0, 0);  //black
+
+    private boolean drawLegends = true;
+    private Font legendFont = new Font("SansSerif", Font.PLAIN, 8);
+    private Color legendTextColor = new Color(0, 0, 0);  //black
+
+    private Font labelFont = new Font("SansSerif", Font.PLAIN, 10);
+    private int globalLabel = LABEL;
+    private Color globalLabelColor;
+    private float labelLineThickness = 1.0f;
+    private double labelLineLength = 50.0d;
+    private double zoomShift = 1.01d;
+    private int useInnerLabels = INNER_LABELS_AUTO;
+    private boolean moveInnerLabelsToOuter = true;
+    private int giveFeaturePositions = POSITIONS_NO_SHOW;
+    private int labelsToKeep = 4000;
+    private boolean labelShuffle = true;
+    private boolean useColoredLabelBackgrounds = false;
+    private int clashSpan = 100;
+    private int spreadIterations = 100;
+    private double radiusShiftAmount = 10.0d;
+    private double radiansShiftConstant = 0.20d;
+    private int labelPlacementQuality = 8;
+    private boolean keepLastLabels = false;
+
+    private boolean isLinear = false;
+    private String linearBreakText = "3'   5'";
+    private double zigzagWidth = 0.0d;
+
+    private ArrayList featureSlots = new ArrayList();
+    private ArrayList outerLabels = new ArrayList();
+    private ArrayList innerLabels = new ArrayList();
+    private ArrayList legends = new ArrayList();
+    private Font warningFont = new Font("SansSerif", Font.PLAIN, 8);
+    private Color warningFontColor = new Color(0, 0, 0);  //black
+    private String warningText = "";
+    private boolean showWarning = false;
+
+    private Point2D centerPoint;
+
+    private int totalLabels = 0;
+    private int clashLabels = 0;
+    //these values are used for zooming and label placement
+    private boolean drawEntirePlasmid = true;
+    private int zoomRangeOneStart;
+    private int zoomRangeOneStop;
+    private int zoomRangeTwoStart;
+    private int zoomRangeTwoStop;
+    private int centerBase;
+    private double zoomMultiplier = 1.0d;
+    private double virtualZoomMultiplier = 1.0d;
+    private double virtualBackboneRadius = backboneRadius;
+    private Rectangle2D backgroundRectangle;
+    private Rectangle2D titleRectangle;
+    private Rectangle2D lengthRectangle;
+    private Arc2D outerArc;
+    private Arc2D innerArc;
+
+    private double desiredZoom = 1.0d;
+    private int desiredZoomCenter = 1;
+
+    private Color borderColor = new Color(0, 0, 0);  //black
+    private boolean showBorder = true;
+
+    private ArrayList labelBounds = new ArrayList();
+
+    private Legend infoLegend;
+
+    //some limits
+    private int MAX_DNA_LENGTH = 20000000;
+    //private double ZOOM_MULTIPLIER_MAX = 30000.0d;
+    private double ZOOM_MULTIPLIER_MAX = 30.0d;
+    private double VIRTUAL_ZOOM_MULTIPLIER_MAX = 500000.0d;
+
+    /**
+     * Constructs a new Cgview object.
+     *
+     * @param sequenceLength the length of the sequence to be mapped.
+     */
+    public Cgview(int sequenceLength) {
+        setSequenceLength(sequenceLength);
+    }
+
+    /**
+     * Sets the length of the sequence to be mapped.
+     *
+     * @param bases the sequence length.
+     */
+    public void setSequenceLength(int bases) {
+        if (bases < 0) {
+            bases = 0;
+        } else if (bases > MAX_DNA_LENGTH) {
+            //generate an error
+        }
+        sequenceLength = bases;
+    }
+
+    /**
+     * Returns the length of the sequence to be mapped.
+     *
+     * @return the length of the sequence.
+     */
+    public int getSequenceLength() {
+        return sequenceLength;
+    }
+
+    /**
+     * Returns the Graphics2D object for this Cgview.
+     *
+     * @return the Graphics2D object.
+     */
+    protected Graphics2D getGraphics() {
+        return gg;
+    }
+
+    /**
+     * Sets the height of the map.
+     *
+     * @param height the height of the map.
+     */
+    public void setHeight(int height) {
+        if (height < 0) {
+            height = 0;
+        }
+        this.height = height;
+    }
+
+    /**
+     * Returns the height of the map.
+     *
+     * @return the height of the map.
+     */
+    public int getHeight() {
+        return height;
+    }
+
+    /**
+     * Adjusts the tick density, with 0 being the minimum, 1 being the maximum.
+     *
+     * @param density a double between 0.0 and 1.0.
+     */
+    public void setTickDensity(double density) {
+        if (density < 0.0d) {
+            density = 0.0d;
+        }
+	else if (density > 1.0d) {
+	    density = 1.0d;
+	}
+        this.tickDensity = density;
+    }
+
+    /**
+     * Returns the tick density, with 0 being the minimum, 1 being the maximum.
+     *
+     * @return a double between 0.0 and 1.0 representing the tick density.
+     */
+    public double getTickDensity() {
+        return tickDensity;
+    }
+
+    /**
+     * Sets the width of the map.
+     *
+     * @param width the width of the map.
+     */
+    public void setWidth(int width) {
+        if (width < 0) {
+            width = 0;
+        }
+        this.width = width;
+    }
+
+    /**
+     * Returns the width of the map.
+     *
+     * @return the width of the map.
+     */
+    public int getWidth() {
+        return width;
+    }
+
+    /**
+     * Returns the width or the height of the map, whichever is smaller.
+     *
+     * @return the width or the height of the map, whichever is smaller.
+     */
+    public int getSmallestDimension() {
+        return Math.min(width, height);
+    }
+
+
+    /**
+     * Sets the background color of the map.
+     *
+     * @param color the background color.
+     */
+    public void setBackgroundColor(Color color) {
+        backgroundColor = color;
+    }
+
+    /**
+     * Returns the background color of the map.
+     *
+     * @return the background color.
+     */
+    public Color getBackgroundColor() {
+        return backgroundColor;
+    }
+
+    /**
+     * Sets the color of the map border.
+     *
+     * @param color the border color.
+     */
+    public void setBorderColor(Color color) {
+        borderColor = color;
+    }
+
+    /**
+     * Returns the color of the map border.
+     *
+     * @return the border color.
+     */
+    public Color getBorderColor() {
+        return borderColor;
+    }
+
+    /**
+     * Sets the radius of the circle that represents the DNA sequence.
+     *
+     * @param radius the backbone radius.
+     */
+    public void setBackboneRadius(double radius) {
+        if (radius < 0) {
+            radius = 0;
+        }
+        backboneRadius = radius;
+    }
+
+    /**
+     * Returns the radius of the circle that represents the DNA sequence.
+     *
+     * @return the backbone radius.
+     */
+    public double getBackboneRadius() {
+        return backboneRadius;
+    }
+
+    /**
+     * Sets the thickness of the line used to draw the circle that represents the DNA sequence.
+     *
+     * @param thickness the thickness of the line.
+     */
+    public void setBackboneThickness(float thickness) {
+        if (thickness < 0) {
+            thickness = 0.0f;
+        }
+        backboneThickness = thickness;
+    }
+
+    /**
+     * Returns the thickness of the line used to draw the circle that represents the DNA sequence.
+     *
+     * @return the thickness of the line.
+     */
+    public double getBackboneThickness() {
+        return backboneThickness;
+    }
+
+    /**
+     * Sets the color of the text used for the sequence ruler.
+     *
+     * @param color the font color.
+     */
+    public void setRulerFontColor(Color color) {
+        rulerFontColor = color;
+    }
+
+    /**
+     * Returns the color of the text used for the sequence ruler.
+     *
+     * @return the font color.
+     */
+    public Color getRulerFontColor() {
+        return rulerFontColor;
+    }
+
+    /**
+     * Sets the color of the text used for the sequence title.
+     *
+     * @param color the color of the font.
+     */
+    public void setTitleFontColor(Color color) {
+        titleFontColor = color;
+    }
+
+    /**
+     * Returns the color of the text used for the sequence title.
+     *
+     * @return the font color.
+     */
+    public Color getTitleFontColor() {
+        return titleFontColor;
+    }
+
+    /**
+     * Returns the default color of the text used for {@link Legend} objects.
+     *
+     * @return the font color.
+     */
+    public Color getLegendTextColor() {
+        return legendTextColor;
+    }
+
+    /**
+     * Sets the default color of the text used for {@link Legend} objects.
+     *
+     * @param color the font color.
+     */
+    public void setLegendTextColor(Color color) {
+        legendTextColor = color;
+    }
+
+
+    /**
+     * Sets the color of the text used for warnings that appear at the bottom of the figure.
+     *
+     * @param color the font color.
+     */
+    public void setWarningFontColor(Color color) {
+        warningFontColor = color;
+    }
+
+    /**
+     * Returns the color of the text used for warnings that appear at the bottom of the figure.
+     *
+     * @return the font color.
+     */
+    public Color getWarningFontColor() {
+        return warningFontColor;
+    }
+
+    /**
+     * By default, feature labels are colored to match the color of the feature they represent. The
+     * setGlobalLabelColor() method can be used to specify a single color for all labels.
+     *
+     * @param color the color of all labels.
+     */
+    public void setGlobalLabelColor(Color color) {
+        globalLabelColor = color;
+    }
+
+    /**
+     * Returns the color of all labels, or null if the labels are colored based on the feature they represent.
+     *
+     * @return the color of all labels.
+     */
+    public Color getGlobalLabelColor() {
+        return globalLabelColor;
+    }
+
+
+    /**
+     * Sets whether or not the message set using {@link #setWarningText(String) setWarningText()} should be drawn at the
+     * bottom of the figure.
+     *
+     * @param showWarning whether or not the message should be drawn.
+     */
+    public void setShowWarning(boolean showWarning) {
+        this.showWarning = showWarning;
+    }
+
+    /**
+     * Returns whether or not the message set using {@link #setWarningText(String) setWarningText()} should be drawn at
+     * the bottom of the figure.
+     *
+     * @return whether or not the message should be drawn.
+     */
+    public boolean getShowWarning() {
+        return showWarning;
+    }
+
+    /**
+     * Sets whether or not the map should be drawn with a broken backbone line to indicate a linear molecule.
+     *
+     * @param isLinear whether or not the map should be drawn with a broken backbone line.
+     */
+    public void setIsLinear(boolean isLinear) {
+        this.isLinear = isLinear;
+    }
+
+    /**
+     * Returns whether or not the map should be drawn with a broken backbone line to indicate a linear molecule.
+     *
+     * @return whether or not the map should be drawn with a broken backbone.
+     */
+    public boolean getIsLinear() {
+        return this.isLinear;
+    }
+
+    /**
+     * Sets the text to draw at the sequence start/end boundary if this is a linear molecule.
+     *
+     * @param text the text to draw at the start/end boundary.
+     */
+    public void setLinearBreakText(String text) {
+        linearBreakText = text;
+    }
+
+    /**
+     * Returns the text to draw at the sequence start/end boundary if this is a linear molecule.
+     *
+     * @return the text to draw at the start/end boundary.
+     */
+    public String getLinearBreakText() {
+        return linearBreakText;
+    }
+
+
+    /**
+     * Sets whether or not a border should be drawn around the map.
+     *
+     * @param showBorder whether or not a border should be drawn.
+     */
+    public void setShowBorder(boolean showBorder) {
+        this.showBorder = showBorder;
+    }
+
+    /**
+     * Returns whether or not a border should be drawn around the map.
+     *
+     * @return whether or not a border should be drawn.
+     */
+    public boolean getShowBorder() {
+        return showBorder;
+    }
+
+    /**
+     * Sets whether or not inner labels should be moved from the inside of the backbone circle to the outside of the
+     * backbone circle when there is insufficient room on the inside of the backbone circle.
+     *
+     * @param moveInnerLabelsToOuter whether or not labels should be moved from the inside to the outside.
+     */
+    public void setMoveInnerLabelsToOuter(boolean moveInnerLabelsToOuter) {
+        this.moveInnerLabelsToOuter = moveInnerLabelsToOuter;
+    }
+
+    /**
+     * Returns whether or not inner labels should be moved from the inside of the backbone circle to the outside of the
+     * backbone circle when there is insufficient room on the inside of the backbone circle.
+     *
+     * @return whether or not labels should be moved from the inside to the outside.
+     */
+    public boolean getMoveInnerLabelsToOuter() {
+        return moveInnerLabelsToOuter;
+    }
+
+    /**
+     * Sets whether or not items on the map should be drawn with shading. This setting can be overridden by individual
+     * {@link FeatureSlot} objects.
+     *
+     * @param showShading whether or not items on the map should be drawn with shading.
+     */
+    public void setShowShading(boolean showShading) {
+        this.showShading = showShading;
+    }
+
+    /**
+     * Returns whether or not items on the map should be drawn with shading.
+     *
+     * @return whether or not items on the map should be drawn with shading.
+     */
+    public boolean getShowShading() {
+        return showShading;
+    }
+
+    /**
+     * Sets the color of the circle that represents the DNA sequence.
+     *
+     * @param color the backbone color.
+     */
+    public void setBackboneColor(Color color) {
+        backboneColor = color;
+    }
+
+    /**
+     * Returns the color of the circle that represents the DNA sequence.
+     *
+     * @return the backbone color.
+     */
+    public Color getBackboneColor() {
+        return backboneColor;
+    }
+
+    /**
+     * Sets the default thickness of the line used to represent sequence features. This value can be changed for
+     * individual featureSlots using the {@link FeatureSlot#setFeatureThickness(float)
+     * FeatureSlot.setFeatureThickness()} method.
+     *
+     * @param thickness the default feature thickness.
+     */
+    public void setFeatureThickness(float thickness) {
+        if (thickness < 0) {
+            thickness = 0.0f;
+        }
+        featureThickness = thickness;
+    }
+
+    /**
+     * Returns the default thickness of the line used to represent sequence features. This value can be changed for
+     * individual featureSlots using the {@link FeatureSlot#setFeatureThickness(float)
+     * FeatureSlot.setFeatureThickness()} method.
+     *
+     * @return the default feature thickness.
+     */
+    public float getFeatureThickness() {
+        return featureThickness;
+    }
+
+    /**
+     * Sets the minimum feature length to use when drawing sequence features. Features smaller than this setting are
+     * artificially increased in length, to make them more visible.
+     *
+     * @param length the minimum feature length.
+     */
+    public void setMinimumFeatureLength(double length) {
+        if (length < 0) {
+            length = 0.0d;
+        }
+        minimumFeatureLength = length;
+    }
+
+    /**
+     * Returns the minimum feature length to use when drawing sequence features. Features smaller than this setting are
+     * artificially increased in length, to make them more visible.
+     *
+     * @return the minimum feature length.
+     */
+    public double getMinimumFeatureLength() {
+        return minimumFeatureLength;
+    }
+
+
+    /**
+     * Sets the amount of blank space placed between the concentric feature rings ({@link FeatureSlot} objects).
+     *
+     * @param spacing the spacing between FeatureSlot objects.
+     */
+    public void setFeatureSlotSpacing(double spacing) {
+        if (spacing < 0) {
+            spacing = 0.0d;
+        }
+        featureSlotSpacing = spacing;
+    }
+
+    /**
+     * Returns the amount of blank space placed between the concentric feature rings ({@link FeatureSlot} objects).
+     *
+     * @return the spacing between FeatureSlot objects.
+     */
+    public double getFeatureSlotSpacing() {
+        return featureSlotSpacing;
+    }
+
+    /**
+     * Sets the length of the arrowheads used for features that are drawn as arrows.
+     *
+     * @param length the arrowhead length.
+     */
+    public void setArrowheadLength(double length) {
+        if (length < 0) {
+            length = 0.0d;
+        }
+        arrowheadLength = length;
+    }
+
+    /**
+     * Returns the length of the arrowheads used for features that are drawn as arrows.
+     *
+     * @return the arrowhead length.
+     */
+    public double getArrowheadLength() {
+        return arrowheadLength;
+    }
+
+    /**
+     * Sets the alignment behavior of small features when they are drawn. Small features are those features drawn larger
+     * than they actually are, in order to make them visible on the map. If <code>shift</code> is set to
+     * <code>true</code>, the drawn representation of the feature is shifted so that its center coincides with the true
+     * center of the feature. If shift is set to false, the drawing begins at the true beginning of the feature, and
+     * extends the length specified using the {@link #setMinimumFeatureLength(double) setMinimumFeatureLength()}
+     * method.
+     *
+     * @param shift whether or not to shift small features so that their center coincides with the true center of the
+     *              feature.
+     * @see #setMinimumFeatureLength(double)
+     */
+    public void setShiftSmallFeatures(boolean shift) {
+        shiftSmallFeatures = shift;
+    }
+
+    /**
+     * Returns the alignment behavior of small features when they are drawn. Small features are those features drawn
+     * larger than they actually are, in order to make them visible on the map. If <code>shift</code> is set to
+     * <code>true</code>, the drawing of the feature is shifted so that its center coincides with the true center of the
+     * feature. If shift is set to false, the drawing begins at the true beginning of the feature, and extends the
+     * length specified using the {@link #setMinimumFeatureLength(double) setMinimumFeatureLength()}.
+     *
+     * @return whether or not to shift small features so that their center coincides with the true center of the
+     *         feature.
+     */
+    public boolean getShiftSmallFeatures() {
+        return shiftSmallFeatures;
+    }
+
+    /**
+     * Sets the proportion of the width of the features to be redrawn for highlighting and shadowing purposes.
+     *
+     * @param proportion the proportion (between <code>0</code> and <code>1</code>).
+     */
+    public void setShadingProportion(float proportion) {
+        if (proportion < 0) {
+            proportion = 0.0f;
+        }
+        if (proportion > 1) {
+            proportion = 1.0f;
+        }
+        //divide by 2.0f because half will be used for shadows and half for highlights.
+        shadingProportion = proportion / 2.0f;
+    }
+
+    /**
+     * Returns the proportion of the width of the features to be redrawn for highlighting and shadowing purposes.
+     *
+     * @return the proportion (between <code>0</code> and <code>1</code>).
+     */
+    public float getShadingProportion() {
+        return shadingProportion;
+    }
+
+    /**
+     * Sets the opacity of the highlighting added to map items. The higher the opacity, the more obvious the
+     * highlighting.
+     *
+     * @param opacity the opacity (between <code>0</code> and <code>1</code>).
+     */
+    public void setHighlightOpacity(float opacity) {
+        if (opacity < 0) {
+            opacity = 0.0f;
+        }
+        if (opacity > 1) {
+            opacity = 1.0f;
+        }
+        highlightOpacity = opacity;
+    }
+
+    /**
+     * Returns the opacity of the highlighting added to map items. The higher the opacity, the more obvious the
+     * highlighting.
+     *
+     * @return the opacity (between <code>0</code> and <code>1</code>).
+     */
+    public float getHighlightOpacity() {
+        return highlightOpacity;
+    }
+
+
+    /**
+     * Sets the opacity of the shadowing added to map items. The higher the opacity, the more obvious the shadowing.
+     *
+     * @param opacity the opacity (between <code>0</code> and <code>1</code>).
+     */
+    public void setShadowOpacity(float opacity) {
+        if (opacity < 0) {
+            opacity = 0.0f;
+        }
+        if (opacity > 1) {
+            opacity = 1.0f;
+        }
+        shadowOpacity = opacity;
+    }
+
+    /**
+     * Returns the opacity of the shadowing added to map items. The higher the opacity, the more obvious the shadowing.
+     *
+     * @return the opacity (between <code>0</code> and <code>1</code>).
+     */
+    public float getShadowOpacity() {
+        return shadowOpacity;
+    }
+
+
+    /**
+     * Sets the thickness of the tick marks in the sequence ruler.
+     *
+     * @param thickness the thickness of the tick marks.
+     */
+    public void setTickThickness(float thickness) {
+        if (thickness < 0) {
+            thickness = 0.0f;
+        }
+        tickThickness = thickness;
+    }
+
+    /**
+     * Returns the thickness of the tick marks in the sequence ruler.
+     *
+     * @return the thickness of the tick marks.
+     */
+    public float getTickThickness() {
+        return tickThickness;
+    }
+
+
+    /**
+     * Sets the length of the tick marks in the sequence ruler.
+     *
+     * @param length the length of the tick marks.
+     */
+    public void setTickLength(float length) {
+        if (length < 0) {
+            length = 0.0f;
+        }
+        tickLength = length;
+    }
+
+    /**
+     * Returns the length of the tick marks in the sequence ruler.
+     *
+     * @return the length of the tick marks.
+     */
+    public float getTickLength() {
+        return tickLength;
+    }
+
+    /**
+     * Sets the thickness of the short tick marks in the sequence ruler.
+     *
+     * @param thickness the thickness of the short tick marks.
+     */
+    public void setShortTickThickness(float thickness) {
+        if (thickness < 0) {
+            thickness = 0.0f;
+        }
+        shortTickThickness = thickness;
+    }
+
+    /**
+     * Returns the thickness of the short tick marks in the sequence ruler.
+     *
+     * @return the thickness of the short tick marks.
+     */
+    public float getShortTickThickness() {
+        return shortTickThickness;
+    }
+
+    /**
+     * Sets the color of the tick marks in the sequence ruler.
+     *
+     * @param color the color of the tick marks.
+     */
+    public void setLongTickColor(Color color) {
+        longTickColor = color;
+    }
+
+    /**
+     * Returns the color of the tick marks in the sequence ruler.
+     *
+     * @return the color of the tick marks.
+     */
+    public Color getLongTickColor() {
+        return longTickColor;
+    }
+
+    /**
+     * Sets the color of the short tick marks in the sequence ruler.
+     *
+     * @param color the color of the short tick marks.
+     */
+    public void setShortTickColor(Color color) {
+        shortTickColor = color;
+    }
+
+    /**
+     * Returns the color of the short tick marks in the sequence ruler.
+     *
+     * @return the color of the short tick marks.
+     */
+    public Color getShortTickColor() {
+        return shortTickColor;
+    }
+
+    /**
+     * Sets the color of the tick mark drawn at the boundary between the end and beginning of the sequence.
+     *
+     * @param color the color of the tick mark drawn at the boundary between the end and beginning of the sequence.
+     */
+    public void setZeroTickColor(Color color) {
+        zeroTickColor = color;
+    }
+
+    /**
+     * Returns the color of the tick mark drawn at the boundary between the end and beginning of the sequence.
+     *
+     * @return the color of the tick mark drawn at the boundary between the end and beginning of the sequence.
+     */
+    public Color getZeroTickColor() {
+        return zeroTickColor;
+    }
+
+    /**
+     * Sets the approximate number of long tick marks to be drawn in the sequence ruler.
+     *
+     * @param ticks the approximate number of tick marks.
+     */
+    public void setDesiredNumberOfTicks(int ticks) {
+        if (ticks < 0) {
+            ticks = 0;
+        }
+        desiredNumberOfTicks = ticks;
+    }
+
+    /**
+     * Returns the approximate number of long tick marks to be drawn in the sequence ruler.
+     *
+     * @return the approximate number of tick marks.
+     */
+    public int getDesiredNumberOfTicks() {
+        return desiredNumberOfTicks;
+    }
+
+    /**
+     * Can be used to store a zoom center value when a Cgview object is read from XML data. This value does not alter
+     * drawing directly.
+     *
+     * @param zoomCenter a base position to center the map on.
+     */
+    public void setDesiredZoomCenter(int zoomCenter) {
+        desiredZoomCenter = zoomCenter;
+    }
+
+    /**
+     * Returns the zoomCenter value stored using the setDesiredZoomCenter() method.
+     *
+     * @return a base position to center the map on.
+     */
+    public int getDesiredZoomCenter() {
+        return desiredZoomCenter;
+    }
+
+    /**
+     * Can be used to store a zoom value when a Cgview object is read from XML data. This value does not alter drawing
+     * directly.
+     *
+     * @param zoom a factor to zoom in by.
+     */
+    public void setDesiredZoom(double zoom) {
+        desiredZoom = zoom;
+    }
+
+    /**
+     * Returns the zoom value stored using the setDesiredZoom() method.
+     *
+     * @return a factor to zoom in by.
+     */
+    public double getDesiredZoom() {
+        return desiredZoom;
+    }
+
+    /**
+     * Sets the font of the number labels in the sequence ruler.
+     *
+     * @param font the font of the number labels.
+     */
+    public void setRulerFont(Font font) {
+        rulerFont = font;
+    }
+
+    /**
+     * Returns the font of the number labels in the sequence ruler.
+     *
+     * @return the font of the number labels.
+     */
+    public Font getRulerFont() {
+        return rulerFont;
+    }
+
+
+    /**
+     * Sets the default font used for text in {@link Legend} objects added to this Cgview.
+     *
+     * @param font the fault font for Legend objects.
+     */
+    public void setLegendFont(Font font) {
+        legendFont = font;
+    }
+
+    /**
+     * Returns the default font used for text in {@link Legend} objects added to this Cgview.
+     *
+     * @return the default font for Legend objects.
+     */
+    public Font getLegendFont() {
+        return legendFont;
+    }
+
+    /**
+     * Returns an arrayList of the Legend objects in this Cgview.
+     *
+     * @return the Legend objects in this Cgview.
+     */
+    protected ArrayList getLegends() {
+        return legends;
+    }
+
+
+    /**
+     * Sets the font used for any warnings that appear at the bottom of the map.
+     *
+     * @param font the font used for warning messages.
+     */
+    public void setWarningFont(Font font) {
+        warningFont = font;
+    }
+
+    /**
+     * Returns the font used for any warnings that appear at the bottom of the map.
+     *
+     * @return the font used for warning messages.
+     */
+    public Font getWarningFont() {
+        return warningFont;
+    }
+
+    /**
+     * Specifies a warning message to appear at the bottom of the map.
+     *
+     * @param message the contents of the message.
+     */
+    public void setWarningText(String message) {
+        warningText = message;
+    }
+
+    /**
+     * Returns a warning message to appear at the bottom of the map.
+     *
+     * @return the warning message.
+     */
+    public String getWarningText() {
+        return warningText;
+    }
+
+    /**
+     * Sets the units to be used for the sequence ruler.
+     *
+     * @param rulerUnits {@link CgviewConstants#BASES CgviewConstants.BASES} or {@link CgviewConstants#CENTISOMES
+     *                   CgviewConstants.CENTISOMES}.
+     */
+    public void setRulerUnits(int rulerUnits) {
+        this.rulerUnits = rulerUnits;
+    }
+
+    /**
+     * Returns the units to be used for the sequence ruler.
+     *
+     * @return {@link CgviewConstants#BASES CgviewConstants.BASES} or {@link CgviewConstants#CENTISOMES
+     *         CgviewConstants.CENTISOMES}.
+     */
+    public int getRulerUnits() {
+        return rulerUnits;
+    }
+
+    /**
+     * Sets whether or not feature labels should be shown on this map. This setting is not overridden by Feature and
+     * FeatureRange objects.
+     *
+     * @param labelType {@link CgviewConstants#LABEL_NONE CgviewConstants.LABEL_NONE}, {@link CgviewConstants#LABEL
+     *                  CgviewConstants.LABEL}, or {@link CgviewConstants#LABEL_ZOOMED CgviewConstants.LABEL_ZOOMED}.
+     */
+    public void setGlobalLabel(int labelType) {
+        this.globalLabel = labelType;
+    }
+
+    /**
+     * Returns whether or not feature labels should be shown on this map. This setting is not overridden by Feature and
+     * FeatureRange objects.
+     *
+     * @return {@link CgviewConstants#LABEL_NONE CgviewConstants.LABEL_NONE}, {@link CgviewConstants#LABEL
+     *         CgviewConstants.LABEL}, or {@link CgviewConstants#LABEL_ZOOMED CgviewConstants.LABEL_ZOOMED}.
+     */
+    public int getGlobalLabel() {
+        return globalLabel;
+    }
+
+    /**
+     * Sets whether or not legends should be drawn on this map.
+     *
+     * @param drawLegends whether or not to draw legends.
+     */
+    public void setDrawLegends(boolean drawLegends) {
+        this.drawLegends = drawLegends;
+    }
+
+
+    /**
+     * Returns boolean indicating whether or not legends should be drawn on this map.
+     *
+     * @return whether or not legends should be drawn on this map.
+     */
+    public boolean getDrawLegends() {
+        return this.drawLegends;
+    }
+
+    /**
+     * Sets the font of the map title.
+     *
+     * @param font the font of the map title.
+     */
+    public void setTitleFont(Font font) {
+        titleFont = font;
+    }
+
+    /**
+     * Returns the font of the map title.
+     *
+     * @return the font of the map title.
+     */
+    public Font getTitleFont() {
+        return titleFont;
+    }
+
+    /**
+     * Sets the default font of the feature labels. This font selection will be ignored if a new font is specified in
+     * the Feature or FeatureRange objects.
+     *
+     * @param font the font of the feature labels.
+     * @see Feature#setFont(Font) Feature.setFont()
+     * @see FeatureRange#setFont(Font) FeatureRange.setFont()
+     */
+    public void setLabelFont(Font font) {
+        labelFont = font;
+    }
+
+    /**
+     * Returns the font of the feature labels. This font selection will be ignored if a font is specified in the Feature
+     * or FeatureRange objects.
+     *
+     * @return the font of the feature labels.
+     */
+    public Font getLabelFont() {
+        return labelFont;
+    }
+
+    /**
+     * Sets the spacing between the ruler number labels and the tick marks.
+     *
+     * @param padding the spacing between the ruler number labels and the tick marks.
+     */
+    public void setRulerTextPadding(double padding) {
+        if (padding < 0) {
+            padding = 0.0d;
+        }
+        rulerTextPadding = padding;
+    }
+
+    /**
+     * Returns the spacing between the ruler number labels and the tick marks.
+     *
+     * @return the spacing between the ruler number labels and the tick marks.
+     */
+    public double getRulerTextPadding() {
+        return rulerTextPadding;
+    }
+
+
+    /**
+     * Sets the origin of the sequence in relation to the backbone drawing. By default the sequence begins at the twelve
+     * o'clock position.
+     *
+     * @param degrees the number of degrees (between <code>-360.0</code> and <code>360.0d</code>) to advance the
+     *                sequence origin in the counterclockwise direction from the three o'clock position.
+     */
+    public void setOrigin(double degrees) {
+        if (degrees < -360) {
+            degrees = -360.0d;
+        }
+        if (degrees > 360) {
+            degrees = 360.0d;
+        }
+        origin = degrees;
+    }
+
+    /**
+     * Returns the number of degrees that the origin is to be moved in the counterclockwise direction from the three
+     * o'clock position.
+     *
+     * @return the number of degrees.
+     */
+    public double getOrigin() {
+        return origin;
+    }
+
+    /**
+     * Sets the thickness of the line that extends from features to feature labels.
+     *
+     * @param thickness the thickness of the line.
+     */
+    public void setLabelLineThickness(float thickness) {
+        if (thickness < 0) {
+            thickness = 0.0f;
+        }
+        labelLineThickness = thickness;
+    }
+
+    /**
+     * Returns the thickness of the line that extends from features to feature labels.
+     *
+     * @return the thickness of the line.
+     */
+    public float getLabelLineThickness() {
+        return labelLineThickness;
+    }
+
+
+    /**
+     * Sets the length of the line that extends from the feature to the feature label. If feature labels clash with the
+     * number labels in the sequence ruler, the length of the label line should be increased using this method.
+     *
+     * @param length the length of the label line.
+     */
+    public void setLabelLineLength(double length) {
+        if (length < 10) {
+            length = 10.0d;
+        }
+        labelLineLength = length;
+    }
+
+    /**
+     * Returns the length of the line that extends from the feature to the feature label.
+     *
+     * @return the length of the label line.
+     */
+    public double getLabelLineLength() {
+        return labelLineLength;
+    }
+
+    /**
+     * Sets the minimum zoom value necessary for labels to be drawn below the backbone. When the map is drawn using a
+     * zoom value less than the value set using this method, all the labels are drawn on the outside of the backbone
+     * circle. When the map is drawn using a zoom value greater than the value set using this method, the labels for
+     * features on the reverse strand are drawn on the inside of the backbone circle. Also, when the zoom value is
+     * greater than the value set using this method, only the features in the visible portion of the map are drawn.
+     *
+     * @param zoom the minimum zoom value necessary for labels to be drawn below the backbone.
+     */
+    protected void setZoomShift(double zoom) {
+        if (zoom < 0) {
+            zoom = 0.0d;
+        }
+        zoomShift = zoom;
+    }
+
+    /**
+     * Returns the minimum zoom value necessary for labels to be drawn below the backbone. When the map is drawn using a
+     * zoom value less than the value set using this method, all the labels are drawn on the outside of the backbone
+     * circle. When the map is drawn using a zoom value greater than the value set using this method, the labels for
+     * features on the reverse strand are drawn on the inside of the backbone circle. Also, when the zoom value is
+     * greater than the value set using this method, only the features in the visible portion of the map are drawn.
+     *
+     * @return the minimum zoom value necessary for labels to be drawn below the backbone.
+     */
+    protected double getZoomShift() {
+        return zoomShift;
+    }
+
+    /**
+     * Sets the maximum number of labels to attempt to arrange for display. Additional labels are discarded prior to the
+     * arrangement process.
+     *
+     * @param number the maximum number of labels to attempt to arrange for display.
+     */
+    public void setLabelsToKeep(int number) {
+        if (number < 0) {
+            number = 0;
+        }
+        labelsToKeep = number;
+    }
+
+    /**
+     * Returns the maximum number of labels to attempt to arrange for display. Additional labels are discarded prior to
+     * the arrangement process.
+     *
+     * @return the maximum number of labels to attempt to arrange for display.
+     */
+    public int getLabelsToKeep() {
+        return labelsToKeep;
+    }
+
+    /**
+     * Sets whether or not labels should be randomly shuffled before removing excess labels.
+     *
+     * @param shuffle whether or not labels should be randomly shuffled before removing excess labels.
+     */
+    public void setLabelShuffle(boolean shuffle) {
+        labelShuffle = shuffle;
+    }
+
+    /**
+     * Returns true if labels are to be randomly shuffled before removing excess labels.
+     *
+     * @return whether or not labels should be randomly shuffled before removing excess labels.
+     */
+    public boolean getLabelShuffle() {
+        return labelShuffle;
+    }
+
+    /**
+     * Sets whether or not labels should be drawn with a colored background.
+     *
+     * @param coloredBackground whether or not labels should be drawn with a colored background.
+     */
+    public void setUseColoredLabelBackgrounds(boolean coloredBackground) {
+        useColoredLabelBackgrounds = coloredBackground;
+    }
+
+    /**
+     * Returns true if labels are to be drawn with a colored background.
+     *
+     * @return whether or not labels are to be drawn with a colored background.
+     */
+    public boolean getUseColoredLabelBackgrounds() {
+        return useColoredLabelBackgrounds;
+    }
+
+    /**
+     * Sets whether or not tick marks are drawn.
+     *
+     * @param draw whether or not tick marks are drawn.
+     */
+    public void setDrawTickMarks(boolean draw) {
+        drawTickMarks = draw;
+    }
+
+    /**
+     * Returns true if tick marks are to be drawn.
+     *
+     * @return whether or not tick marks are to be drawn.
+     */
+    public boolean getDrawTickMarks() {
+        return drawTickMarks;
+    }
+
+    /**
+     * Sets the title of of the map. This title is drawn in the center of the backbone circle when an unzoomed map is
+     * drawn.
+     *
+     * @param title the title of the map.
+     */
+    public void setTitle(String title) {
+        this.title = title.trim();
+    }
+
+    /**
+     * Returns the title of the map. This title is drawn in the center of the backbone circle when an unzoomed map is
+     * drawn.
+     *
+     * @return the title of the map.
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * Returns an arrayList containing the FeatureSlot objects associated with this Cgview.
+     *
+     * @return an arrayList of FeatureSlot objects.
+     */
+    protected ArrayList getFeatureSlots() {
+        return featureSlots;
+    }
+
+    /**
+     * Removes legends from this Cgview.
+     *
+     */
+    protected void removeLegends() {
+        this.legends.clear();
+    }
+
+    /**
+     * Removes labels from this Cgview.
+     *
+     */
+    protected void removeLabels() {
+        this.outerLabels.clear();
+        this.innerLabels.clear();
+    }
+
+    /**
+     * Returns an arrayList of OuterLabel objects associated with this Cgview.
+     *
+     * @return an arrayList of OuterLabel objects.
+     */
+    protected ArrayList getOuterLabels() {
+        return outerLabels;
+    }
+
+    /**
+     * Returns an arrayList of InnerLabel objects associated with this Cgview.
+     *
+     * @return an arrayList of InnerLabel objects.
+     */
+    protected ArrayList getInnerLabels() {
+        return innerLabels;
+    }
+
+    /**
+     * Returns an arrayList of LabelBounds objects associated with this Cgview.
+     *
+     * @return an arrayList of LabelBounds objects.
+     */
+    public ArrayList getLabelBounds() {
+        return labelBounds;
+    }
+
+    /**
+     * Returns the radius of the first (nearest to the backbone) direct strand FeatureSlot in this Cgview.
+     *
+     * @return the radius.
+     */
+    protected double getFirstOuterFeatureRadius() {
+        return backboneRadius + 0.5d * backboneThickness + featureSlotSpacing;
+    }
+
+    /**
+     * Returns the radius of the first (nearest to the backbone) reverse strand FeatureSlot in this Cgview.
+     *
+     * @return the radius.
+     */
+    protected double getFirstInnerFeatureRadius() {
+        return backboneRadius - 0.5d * backboneThickness - featureSlotSpacing;
+    }
+
+    /**
+     * Returns the radius of the last (furthest from the backbone) direct strand FeatureSlot in this Cgview.
+     *
+     * @return the radius.
+     */
+    protected double getLastOuterFeatureRadius() {
+        double radius = this.getFirstOuterFeatureRadius();
+        Iterator i = featureSlots.iterator();
+        while (i.hasNext()) {
+            FeatureSlot currentFeatureSlot = (FeatureSlot) i.next();
+            if (currentFeatureSlot.getStrand() == DIRECT_STRAND) {
+                radius = radius + featureSlotSpacing + currentFeatureSlot.getFeatureThickness();
+            }
+
+        }
+        return radius;
+    }
+
+    /**
+     * Returns the radius of the last (furthest from the backbone) reverse strand FeatureSlot in this Cgview.
+     *
+     * @return the radius.
+     */
+    protected double getLastInnerFeatureRadius() {
+        double radius = this.getFirstInnerFeatureRadius();
+        Iterator i = featureSlots.iterator();
+        while (i.hasNext()) {
+            FeatureSlot currentFeatureSlot = (FeatureSlot) i.next();
+            if (currentFeatureSlot.getStrand() == REVERSE_STRAND) {
+                radius = radius - featureSlotSpacing - currentFeatureSlot.getFeatureThickness();
+            }
+
+        }
+        return radius;
+    }
+
+    /**
+     * Returns a rectangle corresponding to the visible portion of the map.
+     *
+     * @return a rectangle.
+     */
+    protected Rectangle2D getBackgroundRectangle() {
+        return backgroundRectangle;
+    }
+
+    /**
+     * Returns a rectangle that covers the map title.
+     *
+     * @return a rectangle.
+     */
+    protected Rectangle2D getTitleRectangle() {
+        return titleRectangle;
+    }
+
+    /**
+     * Returns a rectangle that covers the length portion of the map title.
+     *
+     * @return a rectangle.
+     */
+    protected Rectangle2D getLengthRectangle() {
+        return lengthRectangle;
+    }
+
+    /**
+     * Returns a radians representation of the given base.
+     *
+     * @return a radians representation of the given base.
+     */
+    protected double getRadians(double base) {
+        if (virtualZoomMultiplier <= 1.0d) {
+            return (base * ((2.0d * Math.PI) / (double) (sequenceLength))) - ((Math.PI / 180.0d) * origin);
+        } else {
+            double centerRadians = (centerBase * ((2.0d * Math.PI) / (double) (sequenceLength))) - ((Math.PI / 180.0d) * origin);
+            double baseDiff;
+            double baseDiffRadians;
+
+            if ((inZoomRangeOne(centerBase)) && (inZoomRangeOne(base))) {
+                baseDiff = (double) centerBase - base;
+                baseDiffRadians = (baseDiff * ((2.0d * Math.PI) / (double) (sequenceLength)));
+                return centerRadians - baseDiffRadians * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+
+            } else if ((inZoomRangeTwo(centerBase)) && (inZoomRangeOne(base))) {
+                if (zoomRangeTwoStart != 0) {
+                    baseDiff = (double) centerBase - base;
+                    baseDiffRadians = (baseDiff * ((2.0d * Math.PI) / (double) (sequenceLength)));
+                    return centerRadians - baseDiffRadians * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                } else {
+                    baseDiff = (double) sequenceLength - base + (double) centerBase;
+                    baseDiffRadians = (baseDiff * ((2.0d * Math.PI) / (double) (sequenceLength)));
+                    return centerRadians - baseDiffRadians * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                }
+            } else if ((inZoomRangeOne(centerBase)) && (inZoomRangeTwo(base))) {
+                if (zoomRangeTwoStart != 0) {
+                    baseDiff = (double) centerBase - base;
+                    baseDiffRadians = (baseDiff * ((2.0d * Math.PI) / (double) (sequenceLength)));
+                    return centerRadians - baseDiffRadians * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                } else {
+                    baseDiff = (double) sequenceLength - (double) centerBase + base;
+                    baseDiffRadians = (baseDiff * ((2.0d * Math.PI) / (double) (sequenceLength)));
+                    return centerRadians + baseDiffRadians * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                }
+            } else { //if ((inZoomRangeTwo(centerBase)) && (inZoomRangeTwo(base))) {
+                baseDiff = (double) centerBase - base;
+                baseDiffRadians = (baseDiff * ((2.0d * Math.PI) / (double) (sequenceLength)));
+                return centerRadians - baseDiffRadians * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+            }
+        }
+    }
+
+
+    /**
+     * Returns a radians representation of the given base.
+     *
+     * @return a radians representation of the given base.
+     */
+    protected double getRadians(int base) {
+        if ((virtualZoomMultiplier <= 1.0f) || (base == centerBase)) {
+            return (base * ((2.0d * Math.PI) / (double) (sequenceLength))) - ((Math.PI / 180.0d) * origin);
+        } else {
+            return getRadians((double) base);
+        }
+    }
+
+    /**
+     * Returns a Point2D specifying the center of this cgview.
+     *
+     * @return the center of this cgview.
+     */
+    protected Point2D getCenter() {
+        return centerPoint;
+    }
+
+    /**
+     * Returns a degrees representation of the given base. The virtualZoomMultiplier stretches features.
+     *
+     * @return a degrees representation of the given base.
+     */
+    protected double getDegrees(int base) {
+        //System.out.print ("The base is " + base + " ");
+        //System.out.println ("the degrees was " + (((double)base / (double)sequenceLength) * 360.0d));
+        if ((virtualZoomMultiplier <= 1.0d) || (base == centerBase)) {
+            return ((double) base / (double) sequenceLength) * 360.0d;
+        } else {
+            double centerDegrees = ((double) centerBase / (double) sequenceLength) * 360.0d;
+            int baseDiff;
+            double baseDiffDegrees;
+
+            if ((inZoomRangeOne(centerBase)) && (almostInZoomRangeOne(base))) {
+                baseDiff = centerBase - base;
+                baseDiffDegrees = ((double) baseDiff / (double) sequenceLength) * 360.0d;
+                //System.out.println ("the degrees is A " + (centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier)));
+                return centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+
+            } else if ((inZoomRangeTwo(centerBase)) && (almostInZoomRangeOne(base))) {
+                if (zoomRangeTwoStart != 0) {
+                    baseDiff = centerBase - base;
+                    baseDiffDegrees = ((double) baseDiff / (double) sequenceLength) * 360.0d;
+                    //System.out.println ("the degrees is B " + (centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier)));
+                    return centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                } else {
+                    baseDiff = sequenceLength - base + centerBase;
+                    baseDiffDegrees = ((double) baseDiff / (double) sequenceLength) * 360.0d;
+                    //System.out.println ("the degrees is C " + (centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier)));
+                    return centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                }
+            } else if ((inZoomRangeOne(centerBase)) && (inZoomRangeTwo(base))) {
+                if (zoomRangeTwoStart != 0) {
+                    baseDiff = centerBase - base;
+                    baseDiffDegrees = ((double) baseDiff / (double) sequenceLength) * 360.0d;
+                    //System.out.println ("the degrees is D " + (centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier)));
+                    return centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                } else {
+                    baseDiff = sequenceLength - centerBase + base;
+                    baseDiffDegrees = ((double) baseDiff / (double) sequenceLength) * 360.0d;
+                    //System.out.println ("the degrees is E " + (centerDegrees + baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier)));
+                    return centerDegrees + baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+                }
+            } else { //if ((inZoomRangeTwo(centerBase)) && (inZoomRangeTwo(base))) {
+                baseDiff = centerBase - base;
+                baseDiffDegrees = ((double) baseDiff / (double) sequenceLength) * 360.0d;
+                //System.out.println ("the degrees is F " + (centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier)));
+                return centerDegrees - baseDiffDegrees * ((virtualZoomMultiplier + zoomMultiplier) / zoomMultiplier);
+            }
+        }
+    }
+
+
+    /**
+     * Specifies under what circumstances labels should be drawn on the inside of the backbone circle. When set to
+     * {@link CgviewConstants#INNER_LABELS_NO_SHOW  CgviewConstants.INNER_LABELS_NO_SHOW}, all the labels are drawn on
+     * the outside of the backbone circle.  When set to {@link CgviewConstants#INNER_LABELS_AUTO
+     * CgviewConstants.INNER_LABELS_AUTO}, all the labels are drawn on the outside of the backbone circle, unless a
+     * zoomed map is drawn. When set to {@link CgviewConstants#INNER_LABELS_SHOW  CgviewConstants.INNER_LABELS_SHOW},
+     * the labels for features on the reverse strand are drawn on the inside of the backbone circle.
+     *
+     * @param useInnerLabels
+     */
+    public void setUseInnerLabels(int useInnerLabels) {
+        this.useInnerLabels = useInnerLabels;
+    }
+
+    /**
+     * Returns the inner label behaviour of this Cgview.
+     *
+     * @return {@link CgviewConstants#INNER_LABELS_NO_SHOW  CgviewConstants.INNER_LABELS_NO_SHOW}, {@link
+     *         CgviewConstants#INNER_LABELS_AUTO  CgviewConstants.INNER_LABELS_AUTO}, or {@link
+     *         CgviewConstants#INNER_LABELS_SHOW  CgviewConstants.INNER_LABELS_SHOW}.
+     */
+    public int getUseInnerLabels() {
+        return useInnerLabels;
+    }
+
+    /**
+     * Specifies under what circumstances feature position information should be added to the label text. When set to
+     * {@link CgviewConstants#POSITIONS_NO_SHOW  CgviewConstants.POSITIONS_NO_SHOW}, position information is not added
+     * to the label.  When set to {@link CgviewConstants#POSITIONS_AUTO  CgviewConstants.POSITIONS_AUTO}, position
+     * information is added only when a zoomed map is drawn. When set to {@link CgviewConstants#POSITIONS_SHOW
+     * CgviewConstants.POSITIONS_SHOW}, position information is added to the labels.
+     *
+     * @param giveFeaturePositions
+     */
+    public void setGiveFeaturePositions(int giveFeaturePositions) {
+        this.giveFeaturePositions = giveFeaturePositions;
+    }
+
+    /**
+     * Returns the feature position labelling behaviour of this Cgview.
+     *
+     * @return {@link CgviewConstants#POSITIONS_NO_SHOW  CgviewConstants.POSITIONS_NO_SHOW}, {@link
+     *         CgviewConstants#POSITIONS_AUTO  CgviewConstants.POSITIONS_AUTO}, or {@link CgviewConstants#POSITIONS_SHOW
+     *         CgviewConstants.POSITIONS_SHOW}.
+     */
+    public int getGiveFeaturePositions() {
+        return giveFeaturePositions;
+    }
+
+    /**
+     * Returns the distance moved by the labels each time they are moved away from the map backbone during label
+     * repositioning.
+     *
+     * @return the distance moved by the labels.
+     */
+    protected double getRadiusShiftAmount() {
+        return radiusShiftAmount;
+    }
+
+    /**
+     * Controls label movement along the map backbone. When labels are moved along the backbone during label placement,
+     * the increment moved by labels is proportional to the <code>shiftValue</code> constant. If the lines extending to
+     * labels are crossing over one another the <code>shiftValue</code> constant should be set to a smaller value. The
+     * default value is <code>0.20</code>.
+     *
+     * @param shiftValue a value that controls label movement along the map backbone.
+     */
+    protected void setRadiansShiftConstant(double shiftValue) {
+        if (shiftValue < 0) {
+            radiansShiftConstant = 0.0f;
+        } else {
+            radiansShiftConstant = shiftValue;
+        }
+    }
+
+    /**
+     * Returns a constant that controls label movement along the map backbone. When labels are moved along the backbone
+     * during label placement, the increment moved by labels is proportional to the <code>RADIANS_SHIFT</code> constant.
+     * If the lines extending to labels are crossing over one another the <code>RADIANS_SHIFT</code> constant should be
+     * set to a smaller value. The default value is <code>0.20</code>.
+     *
+     * @return the <code>shiftValue</code>. It controls label movement along the map backbone.
+     */
+    protected double getRadiansShiftConstant() {
+        return radiansShiftConstant;
+    }
+
+    /**
+     * Specifies how carefully labels placed on the map. Higher values lead to more labels being placed without
+     * overlaps. Higher values also lead to slower program execution. Hight quality label placement can be used when
+     * there are fewer than 100 labels, but when there are more than 100 a low quality setting is recommended.
+     *
+     * @param labelPlacementQuality a value between <code>0</code> and <code>10</code> specifying how carefully labels
+     *                              are placed on the map. The default value is <code>5</code>.
+     * @see #setLabelsToKeep(int) setLabelsToKeep
+     */
+    public void setLabelPlacementQuality(int labelPlacementQuality) {
+        if (labelPlacementQuality < 1) {
+            this.labelPlacementQuality = 1;
+        } else if (labelPlacementQuality > 10) {
+            this.labelPlacementQuality = 10;
+        } else {
+            this.labelPlacementQuality = labelPlacementQuality;
+        }
+
+        if (this.labelPlacementQuality == 0) {
+            spreadIterations = 0;
+            clashSpan = 0;
+        } else if (this.labelPlacementQuality == 1) {
+            spreadIterations = 10;
+            clashSpan = 10;
+            radiusShiftAmount = 20.0d;
+        } else if (this.labelPlacementQuality == 2) {
+            spreadIterations = 20;
+            clashSpan = 40;
+            radiusShiftAmount = 15.0d;
+        } else if (this.labelPlacementQuality == 3) {
+            spreadIterations = 30;
+            clashSpan = 60;
+            radiusShiftAmount = 14.0d;
+        } else if (this.labelPlacementQuality == 4) {
+            spreadIterations = 40;
+            clashSpan = 80;
+            radiusShiftAmount = 12.0d;
+        } else if (this.labelPlacementQuality == 5) {
+            spreadIterations = 50;
+            clashSpan = 100;
+            radiusShiftAmount = 10.0d;
+        } else if (this.labelPlacementQuality == 6) {
+            spreadIterations = 60;
+            clashSpan = 120;
+            radiusShiftAmount = 8.0d;
+        } else if (this.labelPlacementQuality == 7) {
+            spreadIterations = 65;
+            clashSpan = 130;
+            radiusShiftAmount = 6.0d;
+        } else if (this.labelPlacementQuality == 8) {
+            spreadIterations = 70;
+            clashSpan = 140;
+            radiusShiftAmount = 4.0d;
+        } else if (this.labelPlacementQuality == 9) {
+            spreadIterations = 200;
+            clashSpan = 150;
+            radiusShiftAmount = 2.0d;
+        } else if (this.labelPlacementQuality == 10) {
+            spreadIterations = 500;
+            clashSpan = 1000;
+            radiusShiftAmount = 1.0d;
+        }
+    }
+
+    /**
+     * Returns the zoom multiplier for the map, as set using the {@link #drawZoomed(Graphics2D, double, int, boolean)
+     * drawZoomed()} method.
+     *
+     * @return the zoom multiplier.
+     */
+    protected double getZoomMultiplier() {
+        return zoomMultiplier;
+    }
+
+    /**
+     * Returns true if the entire plasmid should be drawn.
+     *
+     * @return true if the entire plasmid should be drawn.
+     */
+    protected boolean getDrawEntirePlasmid() {
+        return drawEntirePlasmid;
+    }
+
+    /**
+     * Returns the number of the first base inside the first zoom range. When drawing a zoomed map, two ranges are
+     * calculated. These ranges contain all the base positions that should be drawn.
+     *
+     * @return the number of the first base inside the first zoom range.
+     */
+    protected int getZoomRangeOneStart() {
+        return zoomRangeOneStart;
+    }
+
+    /**
+     * Returns the number of the last base inside the first zoom range. When drawing a zoomed map, two ranges are
+     * calculated. These ranges contain all the base positions that should be drawn.
+     *
+     * @return the number of the last base inside the first zoom range.
+     */
+    protected int getZoomRangeOneStop() {
+        return zoomRangeOneStop;
+    }
+
+    /**
+     * Returns the number of the first base inside the second zoom range. When drawing a zoomed map, two ranges are
+     * calculated. These ranges contain all the base positions that should be drawn.
+     *
+     * @return the number of the first base inside the second zoom range.
+     */
+    protected int getZoomRangeTwoStart() {
+        return zoomRangeTwoStart;
+    }
+
+    /**
+     * Returns the number of the last base inside the second zoom range. When drawing a zoomed map, two ranges are
+     * calculated. These ranges contain all the base positions that should be drawn.
+     *
+     * @return the number of the last base inside the second zoom range.
+     */
+    protected int getZoomRangeTwoStop() {
+        return zoomRangeTwoStop;
+    }
+
+    /**
+     * Returns true if the existing labels (those generated by the previous draw operation) are to be drawn. Returns
+     * false if a new set of labels is to be generated and positioned.
+     *
+     * @return whether or not the existing labels are to be drawn.
+     */
+    protected boolean getKeepLastLabels() {
+        return keepLastLabels;
+    }
+
+    /**
+     * Returns true if the base is located within the visible region of the map.
+     *
+     * @return whether or not the base is located within the visible region of the map.
+     */
+    protected boolean baseIsDrawable(int base) {
+        if (zoomMultiplier >= zoomShift) {
+            if ((base >= zoomRangeOneStart) && (base <= zoomRangeOneStop)) {
+                return true;
+            } else if ((base >= zoomRangeTwoStart) && (base <= zoomRangeTwoStop)) {
+                return true;
+            } else if (base < zoomRangeOneStart) {
+                return false;
+            } else if (base > zoomRangeTwoStop) {
+                return false;
+            } else {
+                return true;
+            }
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Returns true if the base is located within the first zoom range.
+     *
+     * @return whether or not the base is located within the first zoom range.
+     */
+    protected boolean inZoomRangeOne(int base) {
+        if ((base >= zoomRangeOneStart) && (base <= zoomRangeOneStop)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the base is located within the first zoom range.
+     *
+     * @return whether or not the base is located within the first zoom range.
+     */
+    protected boolean inZoomRangeOne(double base) {
+        if ((base >= zoomRangeOneStart) && (base <= zoomRangeOneStop)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the base is located within the first zoom range, or if it is one base less than the start.
+     *
+     * @return whether or not the base is located within the first zoom range, or if it is one base less than the
+     *         start.
+     */
+    protected boolean almostInZoomRangeOne(int base) {
+        if ((base >= zoomRangeOneStart) && (base <= zoomRangeOneStop)) {
+            return true;
+        } else if (((base + 1) >= zoomRangeOneStart) && ((base + 1) <= zoomRangeOneStop)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Returns true if the base is located within the second zoom range.
+     *
+     * @return whether or not the base is located within the first zoom range.
+     */
+    protected boolean inZoomRangeTwo(int base) {
+        if ((base >= zoomRangeTwoStart) && (base <= zoomRangeTwoStop)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the base is located within the second zoom range.
+     *
+     * @return whether or not the base is located within the first zoom range.
+     */
+    protected boolean inZoomRangeTwo(double base) {
+        if ((base >= zoomRangeTwoStart) && (base <= zoomRangeTwoStop)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Returns true if the base is located within the first zoom range or the second zoom range.
+     *
+     * @return whether or not the base is located within the first zoom range.
+     */
+    protected boolean inZoomRange(int base) {
+        if ((inZoomRangeOne(base)) || (inZoomRangeTwo(base))) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Returns true if the base is located within the first zoom range or the second zoom range.
+     *
+     * @return whether or not the base is located within the first zoom range.
+     */
+    protected boolean inZoomRange(double base) {
+        if ((inZoomRangeOne(base)) || (inZoomRangeTwo(base))) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+
+    /**
+     * Adds an outerLabel object to this cgview object.
+     *
+     * @param label an outerLabel object.
+     */
+    protected void addOuterLabel(Label label) {
+        outerLabels.add(label);
+    }
+
+    /**
+     * Adds an InnerLabel object to this cgview object.
+     *
+     * @param label an innerLabel object.
+     */
+    protected void addInnerLabel(Label label) {
+        innerLabels.add(label);
+    }
+
+    /**
+     * Returns an estimate of the maximum suitable zoom value for this map.
+     *
+     * @return an estimate of the maximum suitable zoom value for this map.
+     */
+    public double getZoomMax() {
+
+        smallestDimension = Math.min(width, height);
+
+        //this is an estimate of the viewing area
+        double viewDiagonal = Math.sqrt(smallestDimension * smallestDimension + smallestDimension * smallestDimension);
+        double basePerCircum = (double) (sequenceLength) / (2.0d * Math.PI * backboneRadius);
+
+        //this limits zoom to the point where 10 bases are shown on the map
+        double zoomMultiplierMaxForThisSequence = (viewDiagonal * basePerCircum) / 10;
+	return zoomMultiplierMaxForThisSequence;
+    }
+
+    /**
+     * Translates the canvas.
+     *
+     */
+    protected void translateCanvas() {
+	if (centerPoint != null) {
+
+	    AffineTransform at = new AffineTransform();
+	    at.setToTranslation((width / 2) - centerPoint.getX(), (height / 2) - centerPoint.getY());
+	    gg.transform(at);
+
+	    //create a rectangle for the background
+	    backgroundRectangle = new Rectangle2D.Double(centerPoint.getX() - (width / 2), centerPoint.getY() - (height / 2), width, height);
+	}
+    }
+
+    /**
+     * Undoes the canvas translation, so that point(0,0) is in upper left.
+     *
+     */
+    protected void untranslateCanvas() {
+	if (centerPoint != null) {
+
+	    AffineTransform at = new AffineTransform();
+
+	    at.setToTranslation((-width / 2) + centerPoint.getX(), (-height / 2) + centerPoint.getY());
+	    gg.transform(at);
+
+	    //create a rectangle for the background
+	    backgroundRectangle = new Rectangle2D.Double(0.0d, 0.0d, width, height);
+
+	}
+    }
+
+    /**
+     * Translates the canvas so that point (0,0) is in the center.
+     *
+     */
+    protected void translateZeroCenter() {
+
+	AffineTransform at = new AffineTransform();
+        at.setToTranslation((width / 2), (height / 2));
+        gg.transform(at);
+
+        backgroundRectangle = new Rectangle2D.Double(-(width / 2), -(height / 2), width, height);
+	
+    }
+
+    /**
+     * Undoes the translation of the canvas that was done to place point (0,0) at the center, so that point(0,0) becomes upper left.
+     *
+     */
+    protected void untranslateZeroCenter() {
+
+	AffineTransform at = new AffineTransform();
+        at.setToTranslation((-width / 2), (-height / 2));
+        gg.transform(at);
+
+        backgroundRectangle = new Rectangle2D.Double(0.0d, 0.0d, width, height);
+	
+    }
+
+    /**
+     * Checks the zoomMultiplier value and makes adjustments if necessary
+     *
+     * @param zoomMultiplier the factor to zoom in by.
+     */
+    protected double adjustZoom(double zoomMultiplier) {
+
+        //determine a suitable maximum zoomMultiplier for the sequence
+
+        smallestDimension = Math.min(width, height);
+
+        //this is an estimate of the viewing area
+        double viewDiagonal = Math.sqrt(smallestDimension * smallestDimension + smallestDimension * smallestDimension);
+        double basePerCircum = (double) (sequenceLength) / (2.0d * Math.PI * backboneRadius);
+
+        //this limits zoom to the point where 10 bases are shown on the map
+        double zoomMultiplierMaxForThisSequence = (viewDiagonal * basePerCircum) / 10;
+
+        //check the zoomMultiplier.
+        if (zoomMultiplier < 1.0d) {
+            zoomMultiplier = 1.0d;
+        }
+
+        if (zoomMultiplierMaxForThisSequence < 1.0d) {
+            zoomMultiplierMaxForThisSequence = 1.0d;
+        }
+
+        if (zoomMultiplier > zoomMultiplierMaxForThisSequence) {
+            zoomMultiplier = zoomMultiplierMaxForThisSequence;
+        }
+
+        if (zoomMultiplier > ZOOM_MULTIPLIER_MAX) {
+            virtualZoomMultiplier = zoomMultiplier - ZOOM_MULTIPLIER_MAX;
+            zoomMultiplier = ZOOM_MULTIPLIER_MAX;
+        }
+
+        if (virtualZoomMultiplier > VIRTUAL_ZOOM_MULTIPLIER_MAX) {
+            virtualZoomMultiplier = VIRTUAL_ZOOM_MULTIPLIER_MAX;
+        }
+        return zoomMultiplier;
+    }
+
+    /**
+     * Draws this Cgview map into the specified Graphics2D context. The map is drawn such that it is zoomed in by a
+     * factor of <code>zoom</code>, and centered on the base at position <code>centerBase</code>.
+     *
+     * @param gg             the <code>Graphics2D</code> context for rendering.
+     * @param zoom           the factor to zoom in by.
+     * @param center         the base position to center the map on.
+     * @param keepLastLabels <code>true</code> if the labels from the last draw operation should be redrawn without
+     *                       repositioning, or <code>false</code> if instead new labels should be generated and then
+     *                       positioned.
+     */
+    public void drawZoomed(Graphics2D gg, double zoom, int center, boolean keepLastLabels) {
+        this.keepLastLabels = keepLastLabels;
+        drawZoomed(gg, zoom, center);
+    }
+
+    /**
+     * Draws this Cgview map into the specified Graphics2D context. The map is drawn such that it is zoomed in by a
+     * factor of <code>zoom</code>, and centered on the base at position <code>centerBase</code>.
+     *
+     * @param gg     the <code>graphics2D</code> context for rendering.
+     * @param zoom   the factor to zoom in by.
+     * @param center the base position to center the map on.
+     */
+    public void drawZoomed(Graphics2D gg, double zoom, int center) {
+
+        this.gg = gg;
+        zoomMultiplier = adjustZoom(zoom);
+        centerBase = center;
+
+        smallestDimension = Math.min(width, height);
+        if (backboneRadius > 0.80d * smallestDimension / 2.0d) {
+            backboneRadius = 0.80d * smallestDimension / 2.0d;
+            System.err.println("[warning] backbone radius was adjusted to fit inside of canvas.");
+        }
+        if (backboneRadius < 10.0d) {
+            backboneRadius = 10.0d;
+            System.err.println("[warning] backbone radius was increased to 10.0.");
+        }
+
+        //use the zoomMultiplier to adjust the backboneRadius;
+        double originalBackboneRadius = backboneRadius;
+        backboneRadius = backboneRadius * zoomMultiplier;
+        virtualBackboneRadius = originalBackboneRadius * (zoomMultiplier + virtualZoomMultiplier - 1.0d);
+
+        if (centerBase < 0) {
+            centerBase = 0;
+        } else if (centerBase > sequenceLength) {
+            centerBase = sequenceLength;
+        }
+
+
+        //determine the radians for the centerBase
+        double radians = getRadians(centerBase);
+
+        //now determine the x and y coordinates on the backbone
+        double x = Math.cos(radians) * backboneRadius;
+        double y = Math.sin(radians) * backboneRadius;
+
+        //set centerPoint
+        centerPoint = new Point2D.Double(x, y);
+
+        //set render quality
+        setRenderQuality();
+
+        //now complete the translation
+	translateCanvas();
+
+        //fill the background
+        gg.setPaint(backgroundColor);
+        gg.fill(backgroundRectangle);
+
+        //change background rectangle to a square
+        //backgroundRectangle = new Rectangle2D.Double(x - (smallestDimension/2), y - (smallestDimension/2), smallestDimension, smallestDimension);
+
+        //now determine the length of the backbone arc that spans the viewing area by
+        //shifting radians down, and then up
+        //this is intended to determine which bases on the plasmid should be drawn. It doesn't have to be completely accurate because the graphics2d clipping region is set so that things are not drawn outside of the canvas.
+
+        if (zoomMultiplier >= zoomShift) {
+
+            double innerMostRadiusToDraw = this.getLastInnerFeatureRadius() - featureSlotSpacing - tickLength;
+            double outerMostRadiusToDraw = this.getLastOuterFeatureRadius() + featureSlotSpacing + tickLength;
+
+            double downshift = 0.0d;
+            double upshift = 0.0d;
+
+            double xInner = Math.cos(radians) * innerMostRadiusToDraw;
+            double yInner = Math.sin(radians) * innerMostRadiusToDraw;
+
+            double tempX1 = xInner;
+            double tempY1 = yInner;
+            double tempX2 = xInner;
+            double tempY2 = yInner;
+
+            double tempRadians = radians;
+            double shiftAmount = ((1.0d / 2.0d) * Math.PI) / (backboneRadius);
+            Point2D checkPointInner = new Point2D.Double(xInner, yInner);
+            Point2D checkPointOuter = new Point2D.Double(xInner, yInner);
+            drawEntirePlasmid = false;
+
+            while (((backgroundRectangle.contains(checkPointInner)) || (backgroundRectangle.contains(checkPointOuter))) && ((radians - tempRadians) < 2.0d * Math.PI)) {
+                tempRadians = tempRadians - shiftAmount;
+                tempX1 = Math.cos(tempRadians) * innerMostRadiusToDraw;
+                tempY1 = Math.sin(tempRadians) * innerMostRadiusToDraw;
+                tempX2 = Math.cos(tempRadians) * outerMostRadiusToDraw;
+                tempY2 = Math.sin(tempRadians) * outerMostRadiusToDraw;
+                checkPointInner.setLocation(tempX1, tempY1);
+                checkPointOuter.setLocation(tempX2, tempY2);
+            }
+
+            if ((radians - tempRadians) >= 2.0d * Math.PI) {
+                drawEntirePlasmid = true;
+            }
+
+            downshift = radians - tempRadians;
+            //System.out.println ("shiftamount is " + shiftAmount);
+
+            //System.out.println ("downshift is " + downshift);
+            checkPointInner.setLocation(xInner, yInner);
+            checkPointOuter.setLocation(xInner, yInner);
+
+            //new
+            tempRadians = radians;
+
+            while (((backgroundRectangle.contains(checkPointInner)) || (backgroundRectangle.contains(checkPointOuter))) && ((tempRadians - radians) < 2.0d * Math.PI)) {
+                tempRadians = tempRadians + shiftAmount;
+                tempX1 = Math.cos(tempRadians) * innerMostRadiusToDraw;
+                tempY1 = Math.sin(tempRadians) * innerMostRadiusToDraw;
+                tempX2 = Math.cos(tempRadians) * outerMostRadiusToDraw;
+                tempY2 = Math.sin(tempRadians) * outerMostRadiusToDraw;
+                checkPointInner.setLocation(tempX1, tempY1);
+                checkPointOuter.setLocation(tempX2, tempY2);
+            }
+
+            if ((tempRadians - radians) >= 2.0d * Math.PI) {
+                drawEntirePlasmid = true;
+            }
+
+            upshift = tempRadians - radians;
+            //System.out.println ("upshift is " + upshift);
+
+            double basePerCircum = (double) (sequenceLength) / (2.0d * Math.PI * backboneRadius);
+            double baseSpanUpd = upshift * basePerCircum * backboneRadius;
+            double baseSpanDownd = downshift * basePerCircum * backboneRadius;
+
+            baseSpanUpd = baseSpanUpd * (zoomMultiplier / (zoomMultiplier + virtualZoomMultiplier - 1));
+            baseSpanDownd = baseSpanDownd * (zoomMultiplier / (zoomMultiplier + virtualZoomMultiplier - 1));
+
+            //add 20% to each to make sure they extend off of the canvas
+            baseSpanUpd = baseSpanUpd + baseSpanUpd * 0.20d;
+            baseSpanDownd = baseSpanDownd + baseSpanDownd * 0.20d;
+
+            //System.out.println ("baseSpanUpd is " + baseSpanUpd);
+            int baseSpanUp = Math.round((float) (baseSpanUpd));
+            int baseSpanDown = Math.round((float) (baseSpanDownd));
+
+            if ((!drawEntirePlasmid) && ((centerBase + baseSpanUp) > sequenceLength)) {
+                zoomRangeOneStart = centerBase - baseSpanDown;
+                zoomRangeOneStop = sequenceLength;
+                zoomRangeTwoStart = 0;
+                zoomRangeTwoStop = baseSpanUp - (sequenceLength - centerBase);
+            } else if ((!drawEntirePlasmid) && ((centerBase - baseSpanDown) < 1)) {
+                zoomRangeOneStart = sequenceLength - (baseSpanDown - centerBase);
+                zoomRangeOneStop = sequenceLength;
+                zoomRangeTwoStart = 0;
+                zoomRangeTwoStop = centerBase + baseSpanUp;
+            } else if (!drawEntirePlasmid) {
+                zoomRangeOneStart = centerBase - baseSpanDown;
+                zoomRangeOneStop = centerBase;
+                zoomRangeTwoStart = centerBase;
+                zoomRangeTwoStop = centerBase + baseSpanUp;
+            }
+        }
+
+        //System.out.println ("zoomRangeOneStart is " + zoomRangeOneStart);
+        //System.out.println ("zoomRangeOneStop is " + zoomRangeOneStop);
+        //System.out.println ("zoomRangeTwoStart is " + zoomRangeTwoStart);
+        //System.out.println ("zoomRangeTwoStop is " + zoomRangeTwoStop);
+
+        drawMain();
+
+        //return the backboneRadius to its original value
+        backboneRadius = originalBackboneRadius;
+        virtualBackboneRadius = backboneRadius;
+        drawEntirePlasmid = true;
+
+        System.out.println("The map has been drawn.");
+
+    }
+
+    /**
+     * Draws this Cgview map into the specified Graphics2D context
+     *
+     * @param gg             the <code>graphics2D</code> context for rendering.
+     * @param keepLastLabels <code>true</code> if the labels from the last draw operation should be redrawn without
+     *                       repositioning, or <code>false</code> if instead new labels should be generated and then
+     *                       positioned.
+     */
+    public void draw(Graphics2D gg, boolean keepLastLabels) {
+        this.keepLastLabels = keepLastLabels;
+        draw(gg);
+    }
+
+    /**
+     * Draws this Cgview map into the specified Graphics2D context
+     *
+     * @param gg the Graphics2D context for rendering.
+     */
+    public void draw(Graphics2D gg) {
+
+        this.gg = gg;
+        zoomMultiplier = 1.0d;
+
+        smallestDimension = Math.min(width, height);
+        if (backboneRadius > 0.80d * smallestDimension / 2.0d) {
+            backboneRadius = 0.80d * smallestDimension / 2.0d;
+            System.err.println("[warning] backbone radius was adjusted to fit inside of canvas.");
+        }
+        if (backboneRadius < 10.0d) {
+            backboneRadius = 10.0d;
+            System.err.println("[warning] backbone radius was increased to 10.0.");
+        }
+
+        virtualBackboneRadius = backboneRadius;
+
+        setRenderQuality();
+
+        centerPoint = new Point2D.Double(0, 0);
+
+	translateCanvas();
+
+        //fill the background
+        gg.setPaint(backgroundColor);
+        gg.fill(backgroundRectangle);
+
+        //change background rectangle to a square
+        //backgroundRectangle = new Rectangle2D.Double(-(smallestDimension/2), -(smallestDimension/2), smallestDimension, smallestDimension);
+
+        drawMain();
+
+	System.out.println("The map has been drawn.");
+
+    }
+
+    /**
+     * Sets the render quality for the Graphics2D object.
+     */
+    private void setRenderQuality() {
+        gg.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        gg.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE);
+        gg.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
+        gg.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
+        gg.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);
+        gg.setRenderingHint(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
+        gg.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
+        gg.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
+
+	//gg.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
+    }
+
+    /**
+     * Calls more specialized drawing methods.
+     */
+    private void drawMain() {
+
+        Iterator i;
+
+        if (drawEntirePlasmid) {
+            placeTitle();
+        }
+
+        //remove labels from last draw if necessary
+        if (!keepLastLabels) {
+            innerLabels.clear();
+            outerLabels.clear();
+            labelBounds.clear();
+            clashLabels = 0;
+            totalLabels = 0;
+        }
+
+        //draw the contens of the FeatureSlots
+        System.out.print("Drawing features.");
+        i = featureSlots.iterator();
+        while (i.hasNext()) {
+            FeatureSlot currentFeatureSlot = (FeatureSlot) i.next();
+            currentFeatureSlot.draw();
+            System.out.print(".");
+        }
+        System.out.println(".");
+
+	drawBackbone();
+
+	if (isLinear) {
+	    drawLinearDividerLine();	    
+	}
+
+        if ((globalLabel == LABEL) || ((globalLabel == LABEL_ZOOMED) && (zoomMultiplier >= zoomShift))) {
+            totalLabels = outerLabels.size() + innerLabels.size();
+
+            System.out.print("Positioning and drawing " + totalLabels + " labels.");
+
+            //draw the new labels
+            if (!keepLastLabels) {
+                drawLabels(innerLabels);
+                drawLabels(outerLabels);
+            } else {
+                //or draw the labels from the last draw operation.
+                i = innerLabels.iterator();
+                while (i.hasNext()) {
+                    Label currentLabel = (Label) i.next();
+                    currentLabel.drawLabelLine();
+                }
+                i = outerLabels.iterator();
+                while (i.hasNext()) {
+                    Label currentLabel = (Label) i.next();
+                    currentLabel.drawLabelLine();
+                }
+
+		untranslateCanvas();
+                i = innerLabels.iterator();
+                while (i.hasNext()) {
+                    Label currentLabel = (Label) i.next();
+                    currentLabel.drawLabelText();
+                }
+                i = outerLabels.iterator();
+                while (i.hasNext()) {
+                    Label currentLabel = (Label) i.next();
+                    currentLabel.drawLabelText();
+                }
+		translateCanvas();
+            }
+
+            System.out.println(".");
+
+            System.out.println(clashLabels + " labels were removed.");
+        }
+
+        if (drawTickMarks) {
+
+            System.out.println("Drawing tick marks.");
+
+            drawTickMarks(DIRECT_STRAND, this.getLastOuterFeatureRadius() + 0.5d * tickThickness);
+
+            drawTickMarks(REVERSE_STRAND, this.getLastInnerFeatureRadius() - 0.5d * tickThickness);
+
+        }
+
+	//undo the translation here
+	untranslateCanvas();
+	translateZeroCenter();
+
+        drawWarningMessage();
+
+        if (drawEntirePlasmid) {
+            drawTitle();
+        }
+
+        //draw border
+        if (showBorder) {
+            double borderThickness = 2.0d;
+            Rectangle2D border = new Rectangle2D.Double(backgroundRectangle.getX() + 0.5d * borderThickness, backgroundRectangle.getY() + 0.5d * borderThickness, width - borderThickness, height - borderThickness);
+            gg.setPaint(borderColor);
+            gg.setStroke(new BasicStroke((float) borderThickness, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER));
+            gg.draw(border);
+        }
+
+	if (this.drawLegends) {
+	    System.out.println("Drawing legends.");
+	    //draw legends
+	    i = legends.iterator();
+	    while (i.hasNext()) {
+		Legend currentLegend = (Legend) i.next();
+		currentLegend.setBounds(0.0d, 0.0d);
+		currentLegend.draw();
+		//remove once drawn.
+		//i.remove();
+	    }
+	}
+ 
+	untranslateZeroCenter();	
+
+        keepLastLabels = false;
+        legends.remove(infoLegend);
+        zoomMultiplier = 1.0f;
+        virtualZoomMultiplier = 1.0f;
+    }
+
+    /**
+     * Draws the sequence backbone.
+     */
+    private void drawBackbone() {
+
+        double startOfArc;
+        double extentOfArc;
+
+        int startBase;
+        int stopBase;
+
+        if (!drawEntirePlasmid) {
+            startBase = zoomRangeOneStart;
+            stopBase = zoomRangeTwoStop;
+        } else {
+            startBase = 1;
+            stopBase = sequenceLength;
+        }
+
+        //typical case where start is less than stop
+        if (startBase <= stopBase) {
+            startOfArc = getDegrees(startBase - 1);
+            extentOfArc = getDegrees(stopBase) - startOfArc;
+        }
+        //case where feature spans start/stop boundary
+        else {
+            startOfArc = ((double) (startBase - 1.0d) / (double) (sequenceLength)) * 360.0d;
+            startOfArc = getDegrees(startBase - 1);
+            extentOfArc = getDegrees(sequenceLength) - startOfArc;
+
+            double startOfArcB = getDegrees(1 - 1);
+            double extentOfArcB = getDegrees(stopBase) - startOfArcB;
+
+            extentOfArc = extentOfArc + extentOfArcB;
+        }
+
+        //draw the plasmid backbone
+        BasicStroke arcStroke = new BasicStroke(backboneThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+        Area centralArc = new Area();
+        centralArc.add(new Area(arcStroke.createStrokedShape(new Arc2D.Double(-backboneRadius, -backboneRadius, (backboneRadius * 2.0d), (backboneRadius * 2.0d), -startOfArc - extentOfArc + origin, extentOfArc, Arc2D.OPEN))));
+
+	//create an Area to subtract from the backbone if this is a linear molecule
+	Area blockArc = null;
+	//restrict to case where origin is set to 90.0.
+	if ((this.isLinear) && (this.origin == 90.0d)) {
+	    if ((drawEntirePlasmid) || (zoomRangeTwoStart == 0)) {
+		//create a 3' 5' label to indicate molecule is linear
+		FontRenderContext frc = gg.getFontRenderContext();
+		TextLayout layout = new TextLayout(this.linearBreakText, rulerFont, frc);
+		Rectangle2D bounds = layout.getBounds();
+		double textHeight = bounds.getHeight();
+		double textWidth = bounds.getWidth();
+
+		double zeroLineRadians = getRadians(0);
+		double zeroStartX = (Math.cos(zeroLineRadians) * backboneRadius);
+		double zeroStartY = (Math.sin(zeroLineRadians) * backboneRadius);
+
+		double textPositionX = zeroStartX - textWidth / 2.0d - layout.getDescent() * 0.4d;
+		double textPositionY = zeroStartY + textHeight / 2.0d;
+
+		//adjust because all caps
+		textPositionY = textPositionY + layout.getDescent();
+
+		//draw bounds
+                gg.setPaint(backgroundColor);
+                bounds.setRect(bounds.getX() + textPositionX - 1.5d, bounds.getY() + textPositionY - layout.getDescent() - 1.5d, bounds.getWidth() + 3.0d, bounds.getHeight() + 3.0d);
+
+		//gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
+                //gg.fill(bounds);
+                //gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));		
+
+                gg.setPaint(rulerFontColor);
+
+		untranslateCanvas();
+
+		layout.draw(gg, (float) (textPositionX + width / 2 - centerPoint.getX()), (float) (textPositionY + height / 2 - centerPoint.getY()) - layout.getDescent());
+		translateCanvas();
+
+		//zero base is visible
+		//blockLength should be changed to the number of degrees needed to create an arc of length equals textWidth
+		double arcInDegrees = Math.toDegrees(textWidth / backboneRadius);
+		double blockLength = arcInDegrees;
+		//add extra white space
+		blockLength = blockLength + blockLength * 0.1d;
+		this.zigzagWidth = blockLength / 2.0d;
+		//double blockLength = 5.0d;
+		double startOfArcBlock = getDegrees(1 - 1) - blockLength / 2.0d;
+		double extentOfArcBlock = blockLength;
+
+		BasicStroke blockArcStroke = new BasicStroke(backboneThickness + 1.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+		blockArc = new Area(blockArcStroke.createStrokedShape(new Arc2D.Double(-backboneRadius, -backboneRadius, (backboneRadius * 2.0d), (backboneRadius * 2.0d), -startOfArcBlock - extentOfArcBlock + origin, extentOfArcBlock, Arc2D.OPEN)));	
+		
+	    }
+	}
+
+        //to prevent drawing off canvas
+	if (blockArc != null) {
+	    centralArc.subtract(blockArc);
+	}
+        centralArc.intersect(new Area(this.getBackgroundRectangle()));
+        gg.setPaint(backboneColor);
+        gg.fill(centralArc);
+
+
+        if (showShading) {
+
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity));
+            gg.setPaint(Color.white);
+
+            double radiusIncrease = 0.5d * backboneThickness - 0.5d * (backboneThickness * shadingProportion);
+
+            BasicStroke highlightArcStroke = new BasicStroke(backboneThickness * shadingProportion, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+            Area highlightArc = new Area();
+            highlightArc.add(new Area(highlightArcStroke.createStrokedShape(new Arc2D.Double(-backboneRadius - radiusIncrease, -backboneRadius - radiusIncrease, (backboneRadius + radiusIncrease) * 2.0d, (backboneRadius + radiusIncrease) * 2.0d, -startOfArc - extentOfArc + origin, extentOfArc, Arc2D.OPEN))));
+	    if (blockArc != null) {
+		highlightArc.subtract(blockArc);
+	    }
+            highlightArc.intersect(new Area(this.getBackgroundRectangle()));
+            gg.fill(highlightArc);
+
+
+            //draw a shadow arc on inner edge of backbone
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity));
+            gg.setPaint(Color.black);
+
+            double radiusDecrease = -0.5d * backboneThickness + 0.5d * (backboneThickness * shadingProportion);
+
+
+            BasicStroke shadowArcStroke = new BasicStroke(backboneThickness * shadingProportion, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+            Area shadowArc = new Area();
+            shadowArc.add(new Area(shadowArcStroke.createStrokedShape(new Arc2D.Double(-backboneRadius - radiusDecrease, -backboneRadius - radiusDecrease, (backboneRadius + radiusDecrease) * 2.0d, (backboneRadius + radiusDecrease) * 2.0d, -startOfArc - extentOfArc + origin, extentOfArc, Arc2D.OPEN))));
+	    if (blockArc != null) {
+		shadowArc.subtract(blockArc);
+	    }
+            shadowArc.intersect(new Area(this.getBackgroundRectangle()));
+            gg.fill(shadowArc);
+
+            //return to non transparent
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+        }
+
+        //set the values of innerArc and outerArc, which will be used for collision testing with labels
+        double outerArcRadius = this.getLastOuterFeatureRadius();
+
+        double innerArcRadius = this.getLastInnerFeatureRadius();
+
+        outerArc = new Arc2D.Double(-outerArcRadius, -outerArcRadius, (outerArcRadius * 2.0d), (outerArcRadius * 2.0d), -startOfArc - extentOfArc + origin, extentOfArc, Arc2D.OPEN);
+
+        innerArc = new Arc2D.Double(-innerArcRadius, -innerArcRadius, (innerArcRadius * 2.0d), (innerArcRadius * 2.0d), -startOfArc - extentOfArc + origin, extentOfArc, Arc2D.OPEN);
+    }
+
+    private void drawLinearDividerLine() {
+
+        //only draw divider line if it should be visible.
+        if (!((drawEntirePlasmid) || (zoomRangeTwoStart == 0))) {
+	    return;
+	}
+
+	double outerRadius = this.getLastOuterFeatureRadius() - featureSlotSpacing;
+        double innerRadius = this.getLastInnerFeatureRadius() + featureSlotSpacing;
+        double zeroLineRadians = getRadians(0);
+	int zigzagNum = featureSlots.size() * 4;
+
+	double zigzagRadiansShift = Math.toRadians(this.zigzagWidth / 8.0d);
+	boolean shiftLeft = true;
+	double zigzagRadius = innerRadius;
+	double zigzagLength = ((outerRadius - innerRadius) / (double)zigzagNum) / 2.0d;
+	double highlightArc = 0.5f * tickThickness - 0.5f * (shadingProportion * tickThickness);
+
+	ArrayList points = new ArrayList();
+	ArrayList highlightPoints = new ArrayList();
+	ArrayList shadowPoints = new ArrayList();
+
+	points.add(new Point2D.Double(Math.cos(zeroLineRadians) * innerRadius, Math.sin(zeroLineRadians) * innerRadius));
+	highlightPoints.add(new Point2D.Double(Math.cos(zeroLineRadians + highlightArc / innerRadius) * innerRadius, Math.sin(zeroLineRadians + highlightArc / innerRadius) * innerRadius));
+	shadowPoints.add(new Point2D.Double(Math.cos(zeroLineRadians - highlightArc / innerRadius) * innerRadius, Math.sin(zeroLineRadians - highlightArc / innerRadius) * innerRadius));
+
+	for (int i = 0; i < zigzagNum; i++) {
+	    if (shiftLeft) {
+		shiftLeft = false;
+		zigzagRadius = zigzagRadius + zigzagLength;
+		points.add(new Point2D.Double(Math.cos(zeroLineRadians + zigzagRadiansShift) * (zigzagRadius), Math.sin(zeroLineRadians + zigzagRadiansShift) * (zigzagRadius)));
+		highlightPoints.add(new Point2D.Double(Math.cos(zeroLineRadians + zigzagRadiansShift + highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians + zigzagRadiansShift + highlightArc / zigzagRadius) * (zigzagRadius)));
+		shadowPoints.add(new Point2D.Double(Math.cos(zeroLineRadians + zigzagRadiansShift - highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians + zigzagRadiansShift - highlightArc / zigzagRadius) * (zigzagRadius)));
+		zigzagRadius = zigzagRadius + zigzagLength;
+		points.add(new Point2D.Double(Math.cos(zeroLineRadians) * (zigzagRadius), Math.sin(zeroLineRadians) * (zigzagRadius)));
+		highlightPoints.add(new Point2D.Double(Math.cos(zeroLineRadians + highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians + highlightArc / zigzagRadius) * (zigzagRadius)));
+		shadowPoints.add(new Point2D.Double(Math.cos(zeroLineRadians - highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians - highlightArc / zigzagRadius) * (zigzagRadius)));
+
+	    }
+	    else {
+		shiftLeft = true;
+		zigzagRadius = zigzagRadius + zigzagLength;
+		points.add(new Point2D.Double(Math.cos(zeroLineRadians - zigzagRadiansShift) * (zigzagRadius), Math.sin(zeroLineRadians - zigzagRadiansShift) * (zigzagRadius)));
+		highlightPoints.add(new Point2D.Double(Math.cos(zeroLineRadians - zigzagRadiansShift + highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians - zigzagRadiansShift + highlightArc / zigzagRadius) * (zigzagRadius)));
+		shadowPoints.add(new Point2D.Double(Math.cos(zeroLineRadians - zigzagRadiansShift - highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians - zigzagRadiansShift - highlightArc / zigzagRadius) * (zigzagRadius)));
+		zigzagRadius = zigzagRadius + zigzagLength;
+		points.add(new Point2D.Double(Math.cos(zeroLineRadians) * (zigzagRadius), Math.sin(zeroLineRadians) * (zigzagRadius)));
+		highlightPoints.add(new Point2D.Double(Math.cos(zeroLineRadians + highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians + highlightArc / zigzagRadius) * (zigzagRadius)));
+		shadowPoints.add(new Point2D.Double(Math.cos(zeroLineRadians - highlightArc / zigzagRadius) * (zigzagRadius), Math.sin(zeroLineRadians - highlightArc / zigzagRadius) * (zigzagRadius)));
+	    }   
+	}
+
+	//add end points
+	points.add(new Point2D.Double(Math.cos(zeroLineRadians) * outerRadius, Math.sin(zeroLineRadians) * outerRadius));
+	highlightPoints.add(new Point2D.Double(Math.cos(zeroLineRadians + highlightArc / outerRadius) * outerRadius, Math.sin(zeroLineRadians + highlightArc / outerRadius) * outerRadius));
+	shadowPoints.add(new Point2D.Double(Math.cos(zeroLineRadians - highlightArc / outerRadius) * outerRadius, Math.sin(zeroLineRadians - highlightArc / outerRadius) * outerRadius));
+
+
+	//now draw points
+	Point2D previousPoint = null;
+	Point2D currentPoint = null;
+	Iterator i = points.iterator();
+	Area zigzagArea = new Area();
+	BasicStroke zigzagStroke = new BasicStroke(tickThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
+	if (i.hasNext()) {
+	    previousPoint = (Point2D) i.next();	    
+	}
+        while (i.hasNext()) {
+	    currentPoint = (Point2D) i.next();
+	    zigzagArea.add(new Area(zigzagStroke.createStrokedShape(new Line2D.Double(previousPoint.getX(), previousPoint.getY(), currentPoint.getX(), currentPoint.getY()))));
+	    previousPoint = currentPoint;
+	}
+	gg.setPaint(longTickColor);
+	zigzagArea.intersect(new Area(this.getBackgroundRectangle()));
+	gg.fill(zigzagArea);
+
+
+	if (showShading) {
+	    //now draw highlight points
+	    previousPoint = null;
+	    currentPoint = null;
+	    i = highlightPoints.iterator();
+	    zigzagArea = new Area();
+	    zigzagStroke = new BasicStroke(tickThickness * shadingProportion, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
+	    if (i.hasNext()) {
+		previousPoint = (Point2D) i.next();	    
+	    }
+	    while (i.hasNext()) {
+		currentPoint = (Point2D) i.next();
+		zigzagArea.add(new Area(zigzagStroke.createStrokedShape(new Line2D.Double(previousPoint.getX(), previousPoint.getY(), currentPoint.getX(), currentPoint.getY()))));
+		previousPoint = currentPoint;
+	    }
+	    gg.setPaint(Color.white);
+    	    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity));
+	    zigzagArea.intersect(new Area(this.getBackgroundRectangle()));
+	    gg.fill(zigzagArea);  
+    
+    
+	    //now draw shadow points
+	    previousPoint = null;
+	    currentPoint = null;
+	    i = shadowPoints.iterator();
+	    zigzagArea = new Area();
+	    zigzagStroke = new BasicStroke(tickThickness * shadingProportion, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL);
+	    if (i.hasNext()) {
+		previousPoint = (Point2D) i.next();	    
+	    }
+	    while (i.hasNext()) {
+		currentPoint = (Point2D) i.next();
+		zigzagArea.add(new Area(zigzagStroke.createStrokedShape(new Line2D.Double(previousPoint.getX(), previousPoint.getY(), currentPoint.getX(), currentPoint.getY()))));
+		previousPoint = currentPoint;
+	    }
+	    gg.setPaint(Color.black);
+    	    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity));
+	    zigzagArea.intersect(new Area(this.getBackgroundRectangle()));
+	    gg.fill(zigzagArea);   
+
+            //return to non transparent
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));   	
+	}
+    }	
+
+
+    /**
+     * Draws the tick marks.
+     */
+    private void drawTickMarks(int strand, double startRadius) {
+
+        NumberFormat format = NumberFormat.getInstance();
+        
+        double approxBasesPerTick;
+        double chosenBasesPerTick = 100000.0d;
+        double chosenIncrement = 10.0d;
+        double baseLabel = 0.0d;
+        String chosenUnits = "mbp";
+        int tickSig[];
+
+//         if ((strand == REVERSE_STRAND)) {
+//             tickSig = new int[5];
+//             tickSig[0] = 1;
+//             tickSig[1] = 5;
+//             tickSig[2] = 5;
+//             tickSig[3] = 5;
+//             tickSig[4] = 5;
+//         } else {
+//             tickSig = new int[4];
+//             tickSig[0] = 1;
+//             tickSig[1] = 4;
+//             tickSig[2] = 2;
+//             tickSig[3] = 4;
+//         }
+
+// 	tickSig = new int[8];
+// 	tickSig[0] = 1;
+// 	tickSig[1] = 6;
+// 	tickSig[2] = 4;
+// 	tickSig[3] = 6;
+// 	tickSig[4] = 2;
+// 	tickSig[5] = 6;
+// 	tickSig[6] = 4;
+// 	tickSig[7] = 6;
+
+        tickSig = new int[5];
+        tickSig[0] = 1;
+        tickSig[1] = 5;
+        tickSig[2] = 5;
+        tickSig[3] = 5;
+        tickSig[4] = 5;
+
+        int tickSigIndex = 0;
+        //goodTicks is the actual number of bases covered per major tick mark
+        int goodTicks[] = {1, 2, 5, 10, 20, 50, 100, 200, 500, 1000, 2000, 5000, 10000, 20000, 50000, 100000, 200000, 500000, 1000000, 2000000, 5000000, 10000000};
+        //goodIncrements is the amount added to the number label placed next to the tick mark.
+        double goodIncrements[] = {1.0d, 2.0d, 5.0d, 10.0d, 20.0d, 50.0d, 100.0d, 200.0d, 500.0d, 1.0d, 2.0d, 5.0d, 10.0d, 20.0d, 50.0d, 100.0d, 200.0d, 500.0d, 1.0d, 2.0d, 5.0d, 10.0d};
+        //goodUnits is the base pair units used for the corresponding goodIncrements.
+        String goodUnits[] = {" bp", " bp", " bp", " bp", " bp", " bp", " bp", " bp", " bp", " kbp", " kbp", " kbp", " kbp", " kbp", " kbp", " kbp", " kbp", " kbp", " mbp", " mbp", " mbp", " mbp"};
+        int strandDirection;
+
+        //goodCentisomeTickNumbers is an array of suitable numbers of ticks for marking centisome position.
+        double goodCentisomeTickNumbers[] = {1.0d, 2.0d, 5.0d, 10.0d, 20.0d, 50.0d, 100.0d, 200.0d, 500.0d, 1000.0d, 2000.0d, 5000.0d, 10000.0d, 20000.0d, 50000.0d, 100000.0d, 200000.0d, 500000.0d, 1000000.0d, 2000000.0d, 5000000.0d, 10000000.0d};
+        //these are the increments that correspond to the goodCentisomeTickNumbers
+        double goodCentisomeIncrements[] = {100.0d, 50.0d, 20.0d, 10.0d, 5.0d, 2.0d, 1.0d, 0.5d, 0.2d, 0.1d, 0.05d, 0.02d, 0.01d, 0.005d, 0.002d, 0.001d, 0.0005d, 0.0002d, 0.0001d, 0.00005d, 0.00002d, 0.00001d};
+        //these are the number of decimal places to round the number label to
+        int goodCentisomeRounds[] = {0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 2, 2, 2, 3, 3, 3, 4, 4, 4, 5, 5, 5};
+        int chosenCentisomeRound = 0;
+
+        if (strand == DIRECT_STRAND) {
+            strandDirection = 1;
+        } else {
+            strandDirection = -1;
+        }
+
+        //determine the base intervals for ticks.
+        //may need to be reduced if there are not enough ticks or increased if there are too many ticks
+        approxBasesPerTick = (double) (sequenceLength) / ((double) (desiredNumberOfTicks) * ((virtualBackboneRadius - (backboneRadius - this.getLastInnerFeatureRadius())) / 200.0d) * tickDensity);
+
+        if (rulerUnits == BASES) {
+            for (int i = 0; i < goodTicks.length; i++) {
+                if ((approxBasesPerTick < goodTicks[i]) || (i == (goodTicks.length - 1))) {
+                    chosenBasesPerTick = goodTicks[i];
+                    chosenIncrement = goodIncrements[i];
+                    chosenUnits = goodUnits[i];
+                    break;
+                }
+            }
+        } else if (rulerUnits == CENTISOMES) {
+            for (int i = 0; i < goodCentisomeTickNumbers.length; i++) {
+                //if ((((double) (desiredNumberOfTicks) * (virtualBackboneRadius / 200.0d)) < goodCentisomeTickNumbers[i]) || (i == (goodCentisomeTickNumbers.length - 1))) {
+		if ((((double) (desiredNumberOfTicks) *  ((virtualBackboneRadius - (backboneRadius - this.getLastInnerFeatureRadius())) / 200.0d) * tickDensity) < goodCentisomeTickNumbers[i]) || (i == (goodCentisomeTickNumbers.length - 1))) {
+                    if (i > 0) {
+                        chosenBasesPerTick = sequenceLength / goodCentisomeTickNumbers[i - 1];
+                        chosenIncrement = goodCentisomeIncrements[i - 1];
+                        chosenCentisomeRound = goodCentisomeRounds[i - 1];
+                        chosenUnits = "centisome";
+
+                        format.setMaximumFractionDigits(chosenCentisomeRound);
+                        format.setMinimumFractionDigits(chosenCentisomeRound);
+                        break;
+                    } else {
+                        chosenBasesPerTick = sequenceLength / goodCentisomeTickNumbers[i];
+                        chosenIncrement = goodCentisomeIncrements[i];
+                        chosenCentisomeRound = goodCentisomeRounds[i];
+                        chosenUnits = "centisome";
+
+                        format.setMaximumFractionDigits(chosenCentisomeRound);
+                        format.setMinimumFractionDigits(chosenCentisomeRound);
+                        break;
+                    }
+                }
+            }
+        }
+
+        chosenBasesPerTick = chosenBasesPerTick / (double) (tickSig.length);
+
+        double j = 0.0d;
+        int endBase = sequenceLength;
+
+        boolean finishedRanges = false;
+        boolean finishedFirstRange = false;
+
+
+        while (!(finishedRanges)) {  //outer while loop
+            if (drawEntirePlasmid) {
+                finishedRanges = true;
+            } else if (zoomRangeTwoStart != 0) {
+                j = zoomRangeOneStart;
+                //this next line makes j the nearest even multiple of chosenBasesPerTick
+                j = (chosenBasesPerTick - j % chosenBasesPerTick) + j;
+                endBase = zoomRangeTwoStop;
+                finishedRanges = true;
+            } else {
+                if (finishedFirstRange) {
+                    j = zoomRangeTwoStart;
+                    //this next line makes j the nearest even multiple of chosenBasesPerTick
+                    j = (chosenBasesPerTick - j % chosenBasesPerTick) + j;
+                    endBase = zoomRangeTwoStop;
+                    finishedRanges = true;
+                } else {
+                    j = zoomRangeOneStart;
+                    //this next line makes j the nearest even multiple of chosenBasesPerTick
+                    j = (chosenBasesPerTick - j % chosenBasesPerTick) + j;
+                    endBase = zoomRangeOneStop;
+                    finishedFirstRange = true;
+                }
+            }
+
+
+            //while (j < endBase) {  //inner while loop
+            while (j - 0.5d < endBase) {
+
+                //the second part is the radians per base.
+                double radians = getRadians(j);
+
+                int iterations = (int) Math.floor(j / chosenBasesPerTick + 0.5f);
+
+                tickSigIndex = iterations % tickSig.length;
+
+                baseLabel = (iterations / tickSig.length) * chosenIncrement;
+
+                double startX;
+                double startY;
+
+                double endX;
+                double endY;
+
+                double heightAdjust = (double) (tickSig[tickSigIndex]);
+                Color currentTickColor = longTickColor;
+                float currentTickThickness = tickThickness;
+
+                if (tickSig[tickSigIndex] != 1) {
+                    currentTickColor = shortTickColor;
+                    currentTickThickness = shortTickThickness;
+                }
+
+                startX = (Math.cos(radians) * startRadius);
+                startY = (Math.sin(radians) * startRadius);
+                endX = (Math.cos(radians) * (startRadius + strandDirection * tickLength / heightAdjust));
+                endY = (Math.sin(radians) * (startRadius + strandDirection * tickLength / heightAdjust));
+
+                //check if tick marks are inside of canvas. Important for some output formats.
+
+                if ((!backgroundRectangle.contains(startX, startY)) || (!backgroundRectangle.contains(endX, endY))) {
+                    j = j + chosenBasesPerTick;
+                    if ((strand == REVERSE_STRAND) && (tickSig[tickSigIndex] == 1)) {
+                        baseLabel = baseLabel + chosenIncrement;
+                    }
+                    continue;
+                }
+
+
+                gg.setPaint(currentTickColor);
+                gg.setStroke(new BasicStroke(currentTickThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
+                gg.draw(new Line2D.Double(startX, startY, endX, endY));
+
+
+                //below code creates labelBounds for every tick mark
+                //if ((strand == REVERSE_STRAND)) {
+
+                    int tickBase;
+                    double TICK_BOUNDS_PADDING = 1.5d;
+
+                    double tickBoundsX = Math.cos(radians) * (startRadius + strandDirection * tickLength * 0.5d) - 0.5d * (tickLength + currentTickThickness + TICK_BOUNDS_PADDING);
+                    double tickBoundsY = Math.sin(radians) * (startRadius + strandDirection * tickLength * 0.5d) - 0.5d * (tickLength + currentTickThickness + TICK_BOUNDS_PADDING);
+
+                    if ((int) Math.floor(j + 0.5d) <= 0) {
+                        tickBase = 1;
+                    } else {
+                        tickBase = (int) Math.floor(j + 0.5d);
+                    }
+
+                    Rectangle2D tickBounds = new Rectangle2D.Double(tickBoundsX + width / 2 - centerPoint.getX(), tickBoundsY + height / 2 - centerPoint.getY(), tickLength + currentTickThickness + TICK_BOUNDS_PADDING, tickLength + currentTickThickness + TICK_BOUNDS_PADDING);
+
+                    LabelBounds rulerLabelBounds = new LabelBounds(this);
+                    rulerLabelBounds.setBounds(tickBounds);
+                    rulerLabelBounds.setLabel(Integer.toString(tickBase));
+                    rulerLabelBounds.setType(BOUNDS_RULER);
+                    rulerLabelBounds.setUse(true);
+                    rulerLabelBounds.setBase(tickBase);
+
+                    //draw bounds
+                    //gg.setPaint(Color.blue);
+                    //gg.setStroke( new BasicStroke( 0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL ));
+                    //gg.draw(tickBounds);
+		    //}
+
+                if (showShading) {
+                    //for drawing highlights on ticks.
+                    double highlightArc = 0.5d * currentTickThickness - 0.5d * (shadingProportion * currentTickThickness);
+
+                    //now draw highlight line
+                    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity));
+                    gg.setPaint(Color.white);
+                    startX = (Math.cos(radians + highlightArc / startRadius) * startRadius);
+                    startY = (Math.sin(radians + highlightArc / startRadius) * startRadius);
+                    endX = (Math.cos(radians + highlightArc / (startRadius + strandDirection * tickLength / heightAdjust)) * (startRadius + strandDirection * tickLength / heightAdjust));
+                    endY = (Math.sin(radians + highlightArc / (startRadius + strandDirection * tickLength / heightAdjust)) * (startRadius + strandDirection * tickLength / heightAdjust));
+                    gg.setStroke(new BasicStroke(currentTickThickness * shadingProportion, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+                    gg.draw(new Line2D.Double(startX, startY, endX, endY));
+
+                    //draw shadow line
+                    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity));
+                    gg.setPaint(Color.black);
+                    startX = (Math.cos(radians - highlightArc / startRadius) * startRadius);
+                    startY = (Math.sin(radians - highlightArc / startRadius) * startRadius);
+                    endX = (Math.cos(radians - highlightArc / (startRadius + strandDirection * tickLength / heightAdjust)) * (startRadius + strandDirection * tickLength / heightAdjust));
+                    endY = (Math.sin(radians - highlightArc / (startRadius + strandDirection * tickLength / heightAdjust)) * (startRadius + strandDirection * tickLength / heightAdjust));
+                    gg.setStroke(new BasicStroke(currentTickThickness * shadingProportion, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+                    gg.draw(new Line2D.Double(startX, startY, endX, endY));
+
+                    //set the composite back to 1
+                    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+                }
+
+                if ((strand == REVERSE_STRAND) && (tickSig[tickSigIndex] == 1)) {
+                    //add numbering to the inside of the figure.
+                    if (baseLabel > 0) {
+                        //recalculate startX and startY using rulerTextPadding.
+                        startX = (Math.cos(radians) * (startRadius - rulerTextPadding - tickLength - 0.5d * tickThickness));
+                        startY = (Math.sin(radians) * (startRadius - rulerTextPadding - tickLength - 0.5d * tickThickness));
+
+                        FontRenderContext frc = gg.getFontRenderContext();
+                        TextLayout layout;
+
+                        String rulerLabel;
+
+                        if (rulerUnits == BASES) {
+                            rulerLabel = Integer.toString((int) baseLabel) + chosenUnits;
+                            //layout = new TextLayout(Integer.toString((int)baseLabel) + chosenUnits, rulerFont, frc);
+                        } else {
+                            rulerLabel = format.format(baseLabel);
+                            //String baseLabelString = format.format(baseLabel);
+                            //layout = new TextLayout(baseLabelString, rulerFont, frc);
+                        }
+
+                        layout = new TextLayout(rulerLabel, rulerFont, frc);
+                        Rectangle2D bounds = layout.getBounds();
+                        double textHeight = bounds.getHeight();
+                        double textWidth = bounds.getWidth();
+
+                        //double textHeight = layout.getAscent() + layout.getDescent();
+                        //double textWidth = layout.getAdvance();
+
+                        double textPositionX = startX;
+                        double textPositionY = startY;
+
+                        //adjust text position based on radians for label.
+                        if ((Math.sin(radians) <= 1.0d) && (Math.sin(radians) >= 0.0d) && (Math.cos(radians) >= 0.0d) && (Math.cos(radians) <= 1.0d)) { // 0 to 90 degrees
+                            textPositionX = textPositionX - textWidth + ((0.5d * textWidth) * (Math.sin(radians)));
+                            textPositionY = textPositionY + 0.5d * textHeight - ((0.5d * textHeight) * (Math.sin(radians)));
+                        } else if ((Math.sin(radians) <= 1.0d) && (Math.sin(radians) >= 0.0d) && (Math.cos(radians) <= 0.0d) && (Math.cos(radians) >= -1.0d)) { // 90 to 180 degrees
+                            textPositionX = textPositionX - ((0.5d * textWidth) * (Math.sin(radians)));
+                            textPositionY = textPositionY + 0.5d * textHeight - ((0.5d * textHeight) * (Math.sin(radians)));
+                        } else if ((Math.sin(radians) <= 0.0d) && (Math.sin(radians) >= -1.0d) && (Math.cos(radians) <= 0.0d) && (Math.cos(radians) >= -1.0d)) { // 180 to 270 degrees
+                            textPositionX = textPositionX + ((0.5d * textWidth) * (Math.sin(radians)));
+                            textPositionY = textPositionY + 0.5d * textHeight - ((0.5d * textHeight) * (Math.sin(radians)));
+                        } else {
+                            textPositionX = textPositionX - textWidth - ((0.5d * textWidth) * (Math.sin(radians)));
+                            textPositionY = textPositionY + 0.5d * textHeight - ((0.5d * textHeight) * (Math.sin(radians)));
+                        }
+
+                        //compensate is to correct for the way that java seems to shift the bound box down and to the right.
+                        //double compensate = 0.5d;
+                        double compensate = 0.0d;
+                        gg.setPaint(backgroundColor);
+                        bounds.setRect(bounds.getX() + textPositionX - 1.5d - compensate, bounds.getY() + textPositionY - layout.getDescent() - 1.5d - compensate, bounds.getWidth() + 3.0d, bounds.getHeight() + 3.0d);
+
+                        //check if label fits inside canvas
+
+                        if (backgroundRectangle.contains(bounds)) {
+                            //gg.setPaint(Color.blue);
+                            //gg.setStroke( new BasicStroke( 0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL ));
+                            //gg.draw(bounds);
+
+                            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
+                            gg.fill(bounds);
+                            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+
+                            gg.setPaint(rulerFontColor);
+                            //layout.draw(gg, (float) textPositionX, (float) textPositionY - layout.getDescent());
+
+			    //this is to avoid problem with imprecisely positioned text when using large coordinates
+			    untranslateCanvas();
+			    layout.draw(gg, (float) (textPositionX + width / 2 - centerPoint.getX()), (float) (textPositionY + height / 2 - centerPoint.getY()) - layout.getDescent());
+			    translateCanvas();
+			    /////
+
+                        }
+
+
+                    }
+                    baseLabel = baseLabel + chosenIncrement;
+                }
+
+                j = j + chosenBasesPerTick;
+
+            }// end of inner while loop
+
+
+        }// end of outer while loop
+
+        //draw a zero line if it should be visible.
+        if ((drawEntirePlasmid) || (zoomRangeTwoStart == 0)) {
+
+            //now draw a zero line
+            double zeroLineRadians = getRadians(0);
+            double zeroStartX = (Math.cos(zeroLineRadians) * startRadius);
+            double zeroStartY = (Math.sin(zeroLineRadians) * startRadius);
+            double zeroEndX = (Math.cos(zeroLineRadians) * (startRadius + strandDirection * tickLength));
+            double zeroEndY = (Math.sin(zeroLineRadians) * (startRadius + strandDirection * tickLength));
+
+	    //check whether zero line will fit in canvas
+            if ((backgroundRectangle.contains(zeroStartX, zeroStartY)) || (backgroundRectangle.contains(zeroEndX, zeroEndY))) {
+
+		gg.setPaint(zeroTickColor);
+		gg.setStroke(new BasicStroke(tickThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_BEVEL));
+		gg.draw(new Line2D.Double(zeroStartX, zeroStartY, zeroEndX, zeroEndY));
+
+
+
+		double TICK_BOUNDS_PADDING = 1.5d;
+
+		//double tickBoundsX = Math.cos(zeroLineRadians) * (startRadius + strandDirection * tickLength * 0.5d) - 0.5d * (tickLength + tickThickness + TICK_BOUNDS_PADDING);
+		//double tickBoundsY = Math.sin(zeroLineRadians) * (startRadius + strandDirection * tickLength * 0.5d) - 0.5d * (tickLength + tickThickness + TICK_BOUNDS_PADDING);
+		double heightAdjust = 1.0d;
+		double tickBoundsX = Math.cos(zeroLineRadians) * (startRadius + strandDirection * tickLength * 0.5d) - 0.5d * (tickLength + tickThickness + TICK_BOUNDS_PADDING);
+		double tickBoundsY = Math.sin(zeroLineRadians) * (startRadius + strandDirection * tickLength * 0.5d) - 0.5d * (tickLength + tickThickness + TICK_BOUNDS_PADDING);
+
+		Rectangle2D tickBounds = new Rectangle2D.Double(tickBoundsX + width / 2 - centerPoint.getX(), tickBoundsY + height / 2 - centerPoint.getY(), tickLength + tickThickness + TICK_BOUNDS_PADDING, tickLength + tickThickness + TICK_BOUNDS_PADDING);
+
+		//Rectangle2D tickBounds = new Rectangle2D.Double(tickBoundsX, tickBoundsY, tickLength + tickThickness + TICK_BOUNDS_PADDING, tickLength + tickThickness + TICK_BOUNDS_PADDING);
+
+		LabelBounds rulerLabelBounds = new LabelBounds(this);
+		rulerLabelBounds.setBounds(tickBounds);
+		rulerLabelBounds.setLabel(Integer.toString(1));
+		rulerLabelBounds.setType(BOUNDS_RULER);
+		rulerLabelBounds.setUse(true);
+		rulerLabelBounds.setBase(1);
+
+		gg.setPaint(Color.red);
+		////gg.setStroke( new BasicStroke( 0.1f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL ));
+		//gg.fill(tickBounds);
+
+
+		if (showShading) {
+		    //for drawing highlights on ticks.
+		    double highlightArc = 0.5f * tickThickness - 0.5f * (shadingProportion * tickThickness);
+
+		    //now draw highlight line
+		    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity));
+		    gg.setPaint(Color.white);
+		    zeroStartX = (Math.cos(zeroLineRadians + highlightArc / startRadius) * startRadius);
+		    zeroStartY = (Math.sin(zeroLineRadians + highlightArc / startRadius) * startRadius);
+		    zeroEndX = (Math.cos(zeroLineRadians + highlightArc / (startRadius + strandDirection * tickLength)) * (startRadius + strandDirection * tickLength));
+		    zeroEndY = (Math.sin(zeroLineRadians + highlightArc / (startRadius + strandDirection * tickLength)) * (startRadius + strandDirection * tickLength));
+		    gg.setStroke(new BasicStroke(tickThickness * shadingProportion, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+		    gg.draw(new Line2D.Double(zeroStartX, zeroStartY, zeroEndX, zeroEndY));
+
+		    //draw shadow line
+		    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity));
+		    gg.setPaint(Color.black);
+		    zeroStartX = (Math.cos(zeroLineRadians - highlightArc / startRadius) * startRadius);
+		    zeroStartY = (Math.sin(zeroLineRadians - highlightArc / startRadius) * startRadius);
+		    zeroEndX = (Math.cos(zeroLineRadians - highlightArc / (startRadius + strandDirection * tickLength)) * (startRadius + strandDirection * tickLength));
+		    zeroEndY = (Math.sin(zeroLineRadians - highlightArc / (startRadius + strandDirection * tickLength)) * (startRadius + strandDirection * tickLength));
+		    gg.setStroke(new BasicStroke(tickThickness * shadingProportion, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL));
+		    gg.draw(new Line2D.Double(zeroStartX, zeroStartY, zeroEndX, zeroEndY));
+
+		    //set the composite back to 1
+		    gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+		}
+
+	    }
+
+        }
+
+    }
+
+    /**
+     * Places the map title.
+     */
+    private void placeTitle() {
+
+        FontRenderContext frc;
+        TextLayout layout;
+        Rectangle2D bounds;
+        titleRectangle = new Rectangle2D.Double();
+        lengthRectangle = new Rectangle2D.Double();
+        double titleTextPositionX = 0.0d;
+        double titleTextPositionY = 0.0d;
+
+        double numberTextPositionX = 0.0d;
+        double numberTextPositionY = 0.0d;
+
+        //draw the title of the plasmid if there is one.
+        if (title == null) {
+            title = "";
+        }
+        Pattern p = Pattern.compile("\\S");
+        Matcher m = p.matcher(title);
+
+        if ((m.find())) {
+            frc = gg.getFontRenderContext();
+            layout = new TextLayout(title, titleFont, frc);
+            bounds = layout.getBounds();
+            titleTextPositionX = 0.0d - 0.5d * layout.getAdvance();
+            titleTextPositionY = 0.0d;
+            titleRectangle.setRect(bounds.getX() + titleTextPositionX - 1.5d, bounds.getY() + titleTextPositionY - layout.getDescent() - 1.5d, bounds.getWidth() + 3.0d, bounds.getHeight() + 3.0d);
+
+            //draw the length of the plasmid.
+            frc = gg.getFontRenderContext();
+            layout = new TextLayout(Integer.toString(sequenceLength) + " bp", titleFont, frc);
+            bounds = layout.getBounds();
+            numberTextPositionX = numberTextPositionX - 0.5d * layout.getAdvance();
+            numberTextPositionY = titleTextPositionY + layout.getDescent() + layout.getLeading() + layout.getDescent() + layout.getAscent();
+            lengthRectangle.setRect(bounds.getX() + numberTextPositionX - 1.5d, bounds.getY() + numberTextPositionY - layout.getDescent() - 1.5d, bounds.getWidth() + 3.0d, bounds.getHeight() + 3.0d);
+        }
+        //if no title, create a small titleRectangle to prevent innerLabels from crossing center
+        else {
+            titleRectangle.setRect(-5.0d, -5.0d, 10.0d, 10.0d);
+            //gg.setPaint(Color.red);
+            //gg.draw(titleRectangle);
+        }
+    }
+
+    /**
+     * Draws the map title.
+     */
+    private void drawTitle() {
+
+        FontRenderContext frc;
+        TextLayout layout;
+        Rectangle2D bounds;
+        titleRectangle = new Rectangle2D.Double();
+        lengthRectangle = new Rectangle2D.Double();
+        double titleTextPositionX = 0.0d;
+        double titleTextPositionY = 0.0d;
+
+        double numberTextPositionX = 0.0d;
+        double numberTextPositionY = 0.0d;
+
+        //draw the title of the plasmid if there is one.
+        if (title == null) {
+            title = "";
+        }
+        Pattern p = Pattern.compile("\\S");
+        Matcher m = p.matcher(title);
+
+        if ((m.find())) {
+            frc = gg.getFontRenderContext();
+            layout = new TextLayout(title, titleFont, frc);
+            bounds = layout.getBounds();
+            titleTextPositionX = 0.0d - 0.5d * layout.getAdvance();
+            titleTextPositionY = 0.0d;
+            gg.setPaint(titleFontColor);
+            titleRectangle.setRect(bounds.getX() + titleTextPositionX - 1.5d, bounds.getY() + titleTextPositionY - layout.getDescent() - 1.5d, bounds.getWidth() + 3.0d, bounds.getHeight() + 3.0d);
+            if (backgroundRectangle.contains(titleRectangle)) {
+                layout.draw(gg, (float) titleTextPositionX, (float) titleTextPositionY);
+            } else {
+                System.err.println("[warning] the plasmid title was too big for the canvas and was removed.");
+            }
+
+            //draw the length of the plasmid.
+            frc = gg.getFontRenderContext();
+            layout = new TextLayout(Integer.toString(sequenceLength) + " bp", titleFont, frc);
+            bounds = layout.getBounds();
+            numberTextPositionX = numberTextPositionX - 0.5d * layout.getAdvance();
+            numberTextPositionY = titleTextPositionY + layout.getDescent() + layout.getLeading() + layout.getDescent() + layout.getAscent();
+            lengthRectangle.setRect(bounds.getX() + numberTextPositionX - 1.5d, bounds.getY() + numberTextPositionY - layout.getDescent() - 1.5d, bounds.getWidth() + 3.0d, bounds.getHeight() + 3.0d);
+            gg.setPaint(titleFontColor);
+            if (backgroundRectangle.contains(lengthRectangle)) {
+                layout.draw(gg, (float) numberTextPositionX, (float) numberTextPositionY);
+            } else {
+                System.out.println("[warning] the plasmid length was too big for the canvas and was removed.");
+            }
+        }
+        //if no title, create a small titleRectangle to prevent innerLabels from crossing center
+        else {
+            titleRectangle.setRect(-5.0d, -5.0d, 10.0d, 10.0d);
+            //gg.setPaint(Color.red);
+            //gg.draw(titleRectangle);
+        }
+    }
+
+    /**
+     * Draws a warning message at the bottom of the map.
+     */
+    private void drawWarningMessage() {
+
+        if ((showWarning) && (totalLabels > 0)) {
+
+            String textToShow = "";
+            if (showWarning) {
+                textToShow = textToShow + warningText;
+            }
+
+            if ((zoomMultiplier == 1.0d) && (clashLabels != 0)) {
+                if (clashLabels == 1) {
+                    textToShow = textToShow + "Warning: " + clashLabels + " of the " + totalLabels + " labels is not shown. ";
+                } else {
+                    textToShow = textToShow + "Warning: " + clashLabels + " of the " + totalLabels + " labels are not shown. ";
+                }
+            } else if ((zoomMultiplier == 1.0d) && (clashLabels == 0)) {
+                textToShow = textToShow + totalLabels + " of the " + totalLabels + " labels are shown. ";
+            }
+
+            Pattern p = Pattern.compile("\\S");
+            Matcher m = p.matcher(textToShow);
+
+            if ((m.find())) {
+
+                infoLegend = new Legend(this);
+                infoLegend.setFont(warningFont);
+                infoLegend.setBackgroundColor(backgroundColor);
+                infoLegend.setBackgroundOpacity(0.2f);
+                infoLegend.setAllowLabelClash(false);
+                infoLegend.setPosition(LEGEND_LOWER_LEFT);
+                LegendItem infoContent = new LegendItem(infoLegend);
+                infoContent.setDrawSwatch(SWATCH_NO_SHOW);
+                infoContent.setLabel(textToShow);
+                infoContent.setFontColor(warningFontColor);
+
+            }
+        }
+    }
+
+    /**
+     * Draws the feature labels. Call this method for InnerLabel objects, and then OuterLabel objects.
+     *
+     * @param labels a collection of labels. The collection must consist of OuterLabel objects, or InnerLabel objects,
+     *               but not both.
+     */
+    private void drawLabels(ArrayList labels) {
+
+        Iterator i;
+        Comparator comparator;
+
+        double outerLabelStart;
+        double innerLabelStart;
+
+        if (drawTickMarks) {
+            outerLabelStart = this.getLastOuterFeatureRadius() + tickLength + tickThickness + featureSlotSpacing;
+
+            innerLabelStart = this.getLastInnerFeatureRadius() - tickLength - tickThickness - featureSlotSpacing;
+        } else {
+            outerLabelStart = this.getLastOuterFeatureRadius() + featureSlotSpacing;
+
+            innerLabelStart = this.getLastInnerFeatureRadius() - featureSlotSpacing;
+        }
+
+        int adjustedClashSpan = clashSpan;
+
+	//the below code will keep labels in a square with width = min(canvas length, canvas width)
+	//this will be undone automatically at the end of this method
+	//because of a call to untranslateCanvas()
+	//if (drawEntirePlasmid) {
+	//    backgroundRectangle = new Rectangle2D.Double(backgroundRectangle.getX(), backgroundRectangle.getY(), smallestDimension, smallestDimension);
+	//}
+
+        //System.out.println ("Set radius");
+        System.out.print(".");
+        i = labels.iterator();
+        while (i.hasNext()) {
+            Label currentLabel = (Label) i.next();
+            if (currentLabel instanceof OuterLabel) {
+                currentLabel.setLineStartRadius(outerLabelStart);
+            } else {
+                currentLabel.setLineStartRadius(innerLabelStart);
+            }
+        }
+
+        //System.out.println ("Shuffle");
+        System.out.print(".");
+        if ((labelShuffle) && (labels.size() > 50)) {
+            Collections.shuffle(labels);
+        }
+
+        //System.out.println ("Trim");
+        //Remove labels until labelsToKeep labels remain. If a label does not clash with any labels, do not remove it.
+        System.out.print(".");
+        if (labels.size() > labelsToKeep) {
+            for (int j = 0; j < labels.size() - labelsToKeep; j++) {
+                if (((Label) labels.get(j)).getForceLabel()) {
+                    continue;
+                }
+                for (int k = j; k < labels.size(); k++) {
+                    if ((((Label) labels.get(j)).getBounds()).intersects(((Label) labels.get(k)).getBounds())) {
+                        labels.remove(j);
+                        j--;
+                        clashLabels++;
+                        break;
+                    }
+                }
+            }
+        }
+
+        //System.out.println ("Sort by radians");
+        System.out.print(".");
+        comparator = new SortLabelsByRadians();
+        Collections.sort(labels, comparator);
+
+	//set bounds with padding set to 3
+        i = labels.iterator();
+        while (i.hasNext()) {
+            ((Label) i.next()).updateBounds(3.0d);	    
+        }	
+
+        //System.out.println ("Radians shifting");
+        System.out.print(".");
+        if (labels.size() > 1) {
+            boolean noClash;
+            int upper;
+            int lower;
+            for (int outer = 0; outer < spreadIterations; outer++) {
+                noClash = true;
+                for (int inner = 0; inner < labels.size(); inner++) {
+                    if (inner == 0) {
+                        if (((Label) labels.get(1)).getLineStartRadians() - ((Label) labels.get(0)).getLineStartRadians() > Math.PI) {
+                            continue;
+                        } else {
+                            upper = 1;
+                            lower = 0;
+                        }
+                    }
+
+                    if (inner == (labels.size() - 1)) {
+                        if (((Label) labels.get(inner)).getLineStartRadians() - ((Label) labels.get(0)).getLineStartRadians() < Math.PI) {
+                            continue;
+                        } else {
+                            upper = inner;
+                            lower = 0;
+                        }
+                    } else {
+                        upper = inner;
+                        lower = inner + 1;
+                    }
+
+                    if ((((Label) labels.get(upper)).getBounds()).intersects(((Label) labels.get(lower)).getBounds())) {
+                        noClash = false;
+                        ((Label) labels.get(upper)).shiftRadiansLower();
+                        ((Label) labels.get(lower)).shiftRadiansHigher();
+                    }
+                }//inner loop
+                if (noClash) {
+                    break;
+                }
+            }//outer loop
+        }
+
+	//set bounds with padding set to 2
+        i = labels.iterator();
+        while (i.hasNext()) {
+            ((Label) i.next()).updateBounds(2.0d);	    
+        }
+
+        //System.out.println ("Radius shifting and removing");
+        System.out.print(".");
+        if (labels.size() > 1) {
+            int j;
+            int checked;
+
+            for (int outer = 0; outer < labels.size(); outer++) {
+                if (((Label) labels.get(outer)).getForceLabel()) {
+                    continue;
+                }
+
+                if ((adjustedClashSpan) > (labels.size() / 2)) {
+                    adjustedClashSpan = labels.size() / 2;
+                }
+
+                j = outer - adjustedClashSpan;
+                checked = 0;
+                while (checked < (adjustedClashSpan * 2)) {
+
+                    if (j == labels.size()) {
+                        j = 0;
+                    } else if (j < 0) {
+                        j = labels.size() + j;
+                    }
+
+                    if (j == outer) {
+                        j++;
+                        continue;
+                    }
+
+                    if ((((Label) labels.get(outer)).getBounds()).intersects(((Label) labels.get(j)).getBounds())) {
+
+                        if (((Label) labels.get(outer)).extendRadius()) {
+
+                            j = outer - adjustedClashSpan;
+                            checked = 0;
+
+                            continue;
+                        } else {
+                            if ((!moveInnerLabelsToOuter) || (((Label) labels.get(outer)) instanceof OuterLabel)) {
+                                labels.remove(outer);
+                                clashLabels++;
+                                outer = outer - 1;
+                                break;
+                            } else {
+                                //convert innerLabel to an outerLabel
+                                new OuterLabel((InnerLabel) labels.get(outer));
+                                labels.remove(outer);
+                                outer = outer - 1;
+                                break;
+                            }
+                        }
+                    }
+                    checked++;
+                    j++;
+                }
+            }
+        }
+
+	//set bounds with padding set to 1.5
+        i = labels.iterator();
+        while (i.hasNext()) {
+            ((Label) i.next()).updateBounds(1.5d);	    
+        }
+
+        //System.out.println ("Remove labels that clash with other labels");
+        System.out.print(".");
+        Collections.shuffle(labels);
+        if (labels.size() > 1) {
+            for (int outer = 0; outer < labels.size(); outer++) {
+
+                if (((Label) labels.get(outer)).getForceLabel()) {
+                    continue;
+                }
+                for (int inner = outer + 1; inner < labels.size(); inner++) {
+                    if ((((Label) labels.get(outer)).getBounds()).intersects(((Label) labels.get(inner)).getBounds())) {
+
+                        if ((!moveInnerLabelsToOuter) || (((Label) labels.get(outer)) instanceof OuterLabel)) {
+                            //((Label)labels.get(outer)).draw();
+                            labels.remove(outer);
+                            clashLabels++;
+                            outer = outer - 1;
+                            break;
+                        } else {
+                            //convert innerLabel to an outerLabel
+                            new OuterLabel((InnerLabel) labels.get(outer));
+                            labels.remove(outer);
+                            outer = outer - 1;
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+
+        //System.out.println ("Sort by radians");
+        //sort labels by radius
+        //System.out.print(".");
+        //comparator = new SortLabelsByRadians();
+        //Collections.sort(labels, comparator);
+
+        //System.out.println ("Sort by radius");
+        //sort labels by radius
+        //System.out.print(".");
+        //comparator = new SortLabelsByRadius();
+        //Collections.sort(labels, comparator);
+
+
+        //System.out.println ("Remove labels that still clash with map elements");
+        //go through the labels again and remove those that clash with the map title, map length, inner FeatureSlot, or outer FeatureSlot.
+        System.out.print(".");
+        if (labels.size() > 0) {
+            Label currentLabel;
+            for (int j = 0; j < labels.size(); j++) {
+                currentLabel = (Label) (labels.get(j));
+                if (currentLabel instanceof OuterLabel) {
+                    if ((outerArc.intersects(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getLineStart()))) {
+                        if (!currentLabel.getForceLabel()) {
+
+                            if ((!moveInnerLabelsToOuter) || (currentLabel instanceof OuterLabel)) {
+                                labels.remove(j);
+                                clashLabels++;
+                                j = j - 1;
+                            } else {
+                                //convert innerLabel to an outerLabel
+                                new OuterLabel((InnerLabel) currentLabel);
+                                labels.remove(j);
+                                j = j - 1;
+                            }
+                        }
+                    }
+                } else {
+                    if (drawEntirePlasmid) {
+
+                        if ((titleRectangle.intersects(currentLabel.getBounds())) || (lengthRectangle.intersects(currentLabel.getBounds())) || !(innerArc.contains(currentLabel.getBounds())) || (titleRectangle.contains(currentLabel.getBounds())) || (lengthRectangle.contains(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getLineStart()))) {
+                            if (!currentLabel.getForceLabel()) {
+                                if ((!moveInnerLabelsToOuter) || (currentLabel instanceof OuterLabel)) {
+                                    labels.remove(j);
+                                    clashLabels++;
+                                    j = j - 1;
+                                } else {
+                                    //convert innerLabel to an outerLabel
+                                    new OuterLabel((InnerLabel) currentLabel);
+                                    labels.remove(j);
+                                    j = j - 1;
+                                }
+                            }
+                        }
+                    } else {
+
+ //this may need fixing if labels on the inside of the backbone circle are being drawn when the shouldn't
+                        if (!(backgroundRectangle.contains(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getLineStart()))) {
+                            if (!currentLabel.getForceLabel()) {
+                                if ((!moveInnerLabelsToOuter) || (currentLabel instanceof OuterLabel)) {
+                                    labels.remove(j);
+                                    clashLabels++;
+                                    j = j - 1;
+                                } else {
+                                    //convert innerLabel to an outerLabel
+                                    new OuterLabel((InnerLabel) currentLabel);
+                                    labels.remove(j);
+                                    j = j - 1;
+                                }
+                            }
+                        }
+
+
+			//this wass a bug. with the code below lots of inner labels were not being drawn. new code above
+//                         if (!(innerArc.contains(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getBounds())) || !(backgroundRectangle.contains(currentLabel.getLineStart()))) {
+//                             if (!currentLabel.getForceLabel()) {
+//                                 if ((!moveInnerLabelsToOuter) || (currentLabel instanceof OuterLabel)) {
+//                                     labels.remove(j);
+//                                     clashLabels++;
+//                                     j = j - 1;
+//                                 } else {
+//                                     //convert innerLabel to an outerLabel
+//                                     new OuterLabel((InnerLabel) currentLabel);
+//                                     labels.remove(j);
+//                                     j = j - 1;
+//                                 }
+//                             }
+//                         }
+
+                    }
+                }
+            }
+        }
+
+        //System.out.println ("Remove labels that clash with legends");
+        //go through the labels again and remove those that clash with legends.
+        System.out.print(".");
+        if (labels.size() > 0) {
+            i = legends.iterator();
+            Rectangle2D legendBounds;
+            Label currentLabel;
+            Legend currentLegend;
+            while (i.hasNext()) {
+                currentLegend = (Legend) i.next();
+                if (!(currentLegend.getAllowLabelClash())) {
+                    legendBounds = currentLegend.getBounds();
+
+                    for (int j = 0; j < labels.size(); j++) {
+                        currentLabel = (Label) (labels.get(j));
+                        if ((!currentLabel.getForceLabel()) && ((legendBounds.contains(currentLabel.getBounds())) || (legendBounds.intersects(currentLabel.getBounds())))) {
+                            if ((!moveInnerLabelsToOuter) || (currentLabel instanceof OuterLabel)) {
+                                labels.remove(j);
+                                clashLabels++;
+                                j = j - 1;
+                            } else {
+                                //convert innerLabel to an outerLabel
+                                new OuterLabel((InnerLabel) currentLabel);
+                                labels.remove(j);
+                                j = j - 1;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        //System.out.println ("Sort by forceLabel");
+        //sort labels by forceLabel so that those that have forceLabel = true are drawn last.
+        System.out.print(".");
+        comparator = new SortLabelsByForceLabel();
+        Collections.sort(labels, comparator);
+
+        //System.out.println ("Draw label lines");
+        //draw label lines
+        System.out.print(".");
+        i = labels.iterator();
+        while (i.hasNext()) {
+            Label currentLabel = (Label) i.next();
+            currentLabel.drawLabelLine();
+        }
+
+        //System.out.println ("Draw label text");
+        //draw label text
+	untranslateCanvas();
+        System.out.print(".");
+        i = labels.iterator();
+        while (i.hasNext()) {
+            Label currentLabel = (Label) i.next();
+            currentLabel.drawLabelText();
+
+            //now create a labelBounds object
+            if ((currentLabel.getHyperlink() != null) || (currentLabel.getMouseover() != null)) {
+                LabelBounds labelBounds = new LabelBounds(this);
+                labelBounds.setBounds(currentLabel.getBounds());
+                labelBounds.setLabel(currentLabel.getLabelText());
+                labelBounds.setType(BOUNDS_FEATURE);
+                labelBounds.setHyperlink(currentLabel.getHyperlink());
+                labelBounds.setMouseover(currentLabel.getMouseover());
+                labelBounds.setUse(true);
+            }
+
+            //remove once drawn
+            //i.remove();
+        }
+	translateCanvas();
+    }
+
+    public static void main(String ars[]) {
+
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewConstants.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewConstants.class
new file mode 100644
index 0000000..ed6d60b
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewConstants.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewConstants.java b/cgview/src/ca/ualberta/stothard/cgview/CgviewConstants.java
new file mode 100644
index 0000000..8a2da75
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/CgviewConstants.java
@@ -0,0 +1,208 @@
+package ca.ualberta.stothard.cgview;
+
+/**
+ * The <code>CgviewConstants</code> interface provides constants for use in the ca.ualberta.stothard.cgview package.
+ *
+ * @author Paul Stothard
+ */
+
+
+public interface CgviewConstants {
+    /**
+     * Represents the direct strand.
+     */
+    public static final int DIRECT_STRAND = 1;
+
+    /**
+     * Represents the reverse strand.
+     */
+    public static final int REVERSE_STRAND = 2;
+
+    /**
+     * Indicates that no labels are to be created.
+     */
+    public static final int LABEL_NONE = 1;
+
+    /**
+     * Indicates that labels are to be created.
+     */
+    public static final int LABEL = 2;
+
+    /**
+     * Indicates that a label is to be drawn even if there is insufficient space.
+     */
+    public static final int LABEL_FORCE = 3;
+
+    /**
+     * Indicates that labels are to be drawn only when a zoomed map is generated.
+     */
+    public static final int LABEL_ZOOMED = 4;
+
+    /**
+     * Indicates that labels should be shown with position information.
+     */
+    public static final int POSITIONS_SHOW = 1;
+
+    /**
+     * Indicates that labels should not be shown with position information.
+     */
+    public static final int POSITIONS_NO_SHOW = 2;
+
+    /**
+     * Indicates that labels should be shown with position information only when a zoomed map is generated.
+     */
+    public static final int POSITIONS_AUTO = 3;
+
+    /**
+     * Indicates that labels should be drawn on the inside of the backbone if they are in a reverse-strand FeatureSlot.
+     */
+    public static final int INNER_LABELS_SHOW = 1;
+
+    /**
+     * Indicates that all labels should be drawn on the outside of the backbone.
+     */
+    public static final int INNER_LABELS_NO_SHOW = 2;
+
+    /**
+     * Indicates that labels should be shown be drawn on the inside of the backbone if they are in a reverse-strand
+     * FeatureSlot and a zoomed map is generated.
+     */
+    public static final int INNER_LABELS_AUTO = 3;
+
+    /**
+     * Indicates that the Cgview sequence ruler should be shown in base pair units.
+     */
+    public static final int BASES = 1;
+
+    /**
+     * Indicates that the Cgview sequence ruler should be shown in centisome units.
+     */
+    public static final int CENTISOMES = 2;
+
+    /**
+     * Indicates that the Feature or FeatureRange should be drawn as a simple arc.
+     */
+    public static final int DECORATION_STANDARD = 1;
+
+    /**
+     * Indicates that the Feature or FeatureRange should be drawn as an arc with an arrowhead at the beginning.
+     */
+    public static final int DECORATION_COUNTERCLOCKWISE_ARROW = 2;
+
+    /**
+     * Indicates that the Feature or FeatureRange should be drawn as an arc with an arrowhead at the end.
+     */
+    public static final int DECORATION_CLOCKWISE_ARROW = 3;
+
+    /**
+     * Indicates that the Feature or FeatureRange should not be drawn. This setting is typically used when only a label
+     * is needed (a restriction site for example).
+     */
+    public static final int DECORATION_HIDDEN = 4;
+
+    /**
+     * Indicates that the LegendItem should be drawn with a color swatch.
+     */
+    public static final int SWATCH_SHOW = 1;
+
+    /**
+     * Indicates that the LegendItem should be drawn without a color swatch.
+     */
+    public static final int SWATCH_NO_SHOW = 2;
+
+    /**
+     * Indicates that the Legend should be drawn in the upper left portion of the map.
+     */
+    public static final int LEGEND_UPPER_LEFT = 1;
+
+    /**
+     * Indicates that the Legend should be drawn in the upper center portion of the map.
+     */
+    public static final int LEGEND_UPPER_CENTER = 2;
+
+    /**
+     * Indicates that the Legend should be drawn in the upper right portion of the map.
+     */
+    public static final int LEGEND_UPPER_RIGHT = 3;
+
+    /**
+     * Indicates that the Legend should be drawn in the middle left portion of the map.
+     */
+    public static final int LEGEND_MIDDLE_LEFT = 4;
+
+    /**
+     * Indicates that the Legend should be drawn left of the middle left portion of the map.
+     */
+    public static final int LEGEND_MIDDLE_LEFT_OF_CENTER = 5;
+
+    /**
+     * Indicates that the Legend should be drawn in the middle center portion of the map.
+     */
+    public static final int LEGEND_MIDDLE_CENTER = 6;
+
+    /**
+     * Indicates that the Legend should be drawn right of the middle right portion of the map.
+     */
+    public static final int LEGEND_MIDDLE_RIGHT_OF_CENTER = 7;
+
+    /**
+     * Indicates that the Legend should be drawn in the middle right portion of the map.
+     */
+    public static final int LEGEND_MIDDLE_RIGHT = 8;
+
+    /**
+     * Indicates that the Legend should be drawn in the lower left portion of the map.
+     */
+    public static final int LEGEND_LOWER_LEFT = 9;
+
+    /**
+     * Indicates that the Legend should be drawn in the lower center portion of the map.
+     */
+    public static final int LEGEND_LOWER_CENTER = 10;
+
+    /**
+     * Indicates that the Legend should be drawn in the lower right portion of the map.
+     */
+    public static final int LEGEND_LOWER_RIGHT = 11;
+
+    /**
+     * Indicates that the Legend should be drawn when zoomed.
+     */
+    public static final int LEGEND_DRAW_ZOOMED = 1;
+
+    /**
+     * Indicates that the Legend should not be drawn when zoomed.
+     */
+    public static final int LEGEND_NO_DRAW_ZOOMED = 2;
+
+    /**
+     * Indicates that the LegendItem text should be aligned to the left.
+     */
+    public static final int LEGEND_ITEM_ALIGN_LEFT = 1;
+
+    /**
+     * Indicates that the LegendItem text should be aligned to the center.
+     */
+    public static final int LEGEND_ITEM_ALIGN_CENTER = 2;
+
+    /**
+     * Indicates that the LegendItem text should be aligned to the right.
+     */
+    public static final int LEGEND_ITEM_ALIGN_RIGHT = 3;
+
+    /**
+     * Indicates that the LabelBounds encloses a tick mark.
+     */
+    public static final int BOUNDS_RULER = 1;
+
+    /**
+     * Indicates that the labelBounds encloses a feature label.
+     */
+    public static final int BOUNDS_FEATURE = 2;
+
+    /**
+     * Indicates that the labelBounds encloses a button.
+     */
+    public static final int BOUNDS_BUTTON = 3;
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$1.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$1.class
new file mode 100644
index 0000000..5cd8b2e
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$1.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$2.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$2.class
new file mode 100644
index 0000000..4a00b0e
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$2.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$3.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$3.class
new file mode 100644
index 0000000..0820cb8
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$3.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$4.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$4.class
new file mode 100644
index 0000000..c0c99a9
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$4.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$ElementDetails.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$ElementDetails.class
new file mode 100644
index 0000000..af6e2f6
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory$ElementDetails.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory.class
new file mode 100644
index 0000000..f12055a
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory.java b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory.java
new file mode 100644
index 0000000..2d98de2
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactory.java
@@ -0,0 +1,2847 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.Stack;
+import java.io.*;
+import java.lang.Integer;
+import java.awt.*;
+import java.util.*;
+import java.util.regex.*;
+
+//xml
+//import org.apache.xerces.parsers.SAXParser;
+import org.xml.sax.*;
+import org.xml.sax.helpers.*;
+
+/**
+ * This class reads an XML document and creates a Cgview object. The various elements and attributes in the file are
+ * used to describe sequence features (position, type, name, color, label font, and opacity). Optional XML attributes
+ * can be included, to control global map characteristics, and to add legends, a title, and footnotes.
+ *
+ * @author Paul Stothard
+ */
+
+public class CgviewFactory extends DefaultHandler implements CgviewConstants {
+
+    private final static Hashtable COLORS = new Hashtable();
+    private final static Hashtable LABEL_TYPES = new Hashtable();
+    private final static Hashtable GLOBAL_LABEL_TYPES = new Hashtable();
+    private final static Hashtable DECORATIONS = new Hashtable();
+    private final static Hashtable RULER_UNITS = new Hashtable();
+    private final static Hashtable USE_INNER_LABELS = new Hashtable();
+    private final static Hashtable GIVE_FEATURE_POSITIONS = new Hashtable();
+    private final static Hashtable FEATURE_THICKNESSES = new Hashtable();
+    private final static Hashtable FEATURESLOT_SPACINGS = new Hashtable();
+    private final static Hashtable BACKBONE_THICKNESSES = new Hashtable();
+    private final static Hashtable ARROWHEAD_LENGTHS = new Hashtable();
+    private final static Hashtable MINIMUM_FEATURE_LENGTHS = new Hashtable();
+    private final static Hashtable ORIGINS = new Hashtable();
+    private final static Hashtable TICK_THICKNESSES = new Hashtable();
+    private final static Hashtable TICK_LENGTHS = new Hashtable();
+    private final static Hashtable LABEL_LINE_THICKNESSES = new Hashtable();
+    private final static Hashtable LABEL_LINE_LENGTHS = new Hashtable();
+    private final static Hashtable LABEL_PLACEMENT_QUALITIES = new Hashtable();
+    private final static Hashtable BOOLEANS = new Hashtable();
+    private final static Hashtable SWATCH_TYPES = new Hashtable();
+    private final static Hashtable LEGEND_POSITIONS = new Hashtable();
+    private final static Hashtable LEGEND_ALIGNMENTS = new Hashtable();
+    private final static Hashtable LEGEND_SHOW_ZOOM = new Hashtable();
+
+    private final static int MAX_BASES = 20000000;
+    private final static int MIN_BASES = 10;
+    private final static double MIN_BACKBONE_RADIUS = 10.0d;
+    private final static double MAX_BACKBONE_RADIUS = 12000.0d;  //default is 190.0d
+    private final static int MAX_IMAGE_WIDTH = 30000; //default is 700.0d
+    private final static int MIN_IMAGE_WIDTH = 100;
+
+    private final static int MAX_IMAGE_HEIGHT = 30000; //default is 700.0d
+    private final static int MIN_IMAGE_HEIGHT = 100;
+
+    private Pattern fontDescriptionPattern = Pattern.compile("\\s*(\\S+)\\s*,\\s*(\\S+)\\s*,\\s*(\\d+)\\s*,*\\s*");
+    private Pattern colorDescriptionPattern = Pattern.compile("\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,*\\s*");
+    private Matcher m;
+
+    private int cgviewLength;
+    private int imageWidth;
+    private int imageHeight;
+
+    //set to true if combining data
+    private boolean ignoreCgviewTag = false;
+    private boolean ignoreLegendTag = false;
+    private boolean ignoreLegendItemTag = false;
+
+    private Cgview currentCgview;
+    private FeatureSlot currentFeatureSlot;
+    private Feature currentFeature;
+    private FeatureRange currentFeatureRange;
+    private Legend currentLegend;
+    private LegendItem currentLegendItem;
+
+    private int labelFontSize = -1;
+    private int rulerFontSize = -1;
+    private int legendFontSize = -1;
+
+    private StringBuffer content = new StringBuffer();
+    private Locator locator;
+    private Stack context = new Stack();
+
+    /**
+     * Constructs a new CgviewFactory object.
+     */
+    public CgviewFactory() {
+        super();
+
+        COLORS.put("black", new Color(0, 0, 0));   //longTickColor default //rulerFontColor default //titleFontColor default // shortTickColor default //zeroTickColor default
+        COLORS.put("silver", new Color(192, 192, 192));
+        COLORS.put("gray", new Color(128, 128, 128));   //backbone default
+        COLORS.put("grey", new Color(128, 128, 128));
+        COLORS.put("white", new Color(255, 255, 255));  //background default
+        COLORS.put("maroon", new Color(128, 0, 0));
+        COLORS.put("red", new Color(255, 0, 0));
+        COLORS.put("purple", new Color(128, 0, 128));
+        COLORS.put("fuchsia", new Color(255, 0, 255));
+        COLORS.put("green", new Color(0, 128, 0));
+        COLORS.put("lime", new Color(0, 255, 0));
+        COLORS.put("olive", new Color(128, 128, 0));
+        COLORS.put("yellow", new Color(255, 255, 0));
+        COLORS.put("orange", new Color(255, 153, 0));
+        COLORS.put("navy", new Color(0, 0, 128));
+        COLORS.put("blue", new Color(0, 0, 255));  //feature and featureRange default
+        COLORS.put("teal", new Color(0, 128, 128));
+        COLORS.put("aqua", new Color(0, 255, 255));
+
+        LABEL_TYPES.put("true", new Integer(LABEL));
+        LABEL_TYPES.put("false", new Integer(LABEL_NONE));  //default for feature and featureRange
+        LABEL_TYPES.put("force", new Integer(LABEL_FORCE));
+
+        GLOBAL_LABEL_TYPES.put("true", new Integer(LABEL));  //default for Cgview
+        GLOBAL_LABEL_TYPES.put("false", new Integer(LABEL_NONE));
+        GLOBAL_LABEL_TYPES.put("auto", new Integer(LABEL_ZOOMED));
+
+        DECORATIONS.put("arc", new Integer(DECORATION_STANDARD));  //default for feature and featureRange
+        DECORATIONS.put("hidden", new Integer(DECORATION_HIDDEN));
+        DECORATIONS.put("counterclockwise-arrow", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        DECORATIONS.put("clockwise-arrow", new Integer(DECORATION_CLOCKWISE_ARROW));
+
+        RULER_UNITS.put("bases", new Integer(BASES));   //default for rulerUnits
+        RULER_UNITS.put("centisomes", new Integer(CENTISOMES));
+
+        USE_INNER_LABELS.put("true", new Integer(INNER_LABELS_SHOW));   //should have true, false, auto
+        USE_INNER_LABELS.put("false", new Integer(INNER_LABELS_NO_SHOW));
+        USE_INNER_LABELS.put("auto", new Integer(INNER_LABELS_AUTO));
+
+        GIVE_FEATURE_POSITIONS.put("true", new Integer(POSITIONS_SHOW));
+        GIVE_FEATURE_POSITIONS.put("false", new Integer(POSITIONS_NO_SHOW));  //default
+        GIVE_FEATURE_POSITIONS.put("auto", new Integer(POSITIONS_AUTO));
+
+        FEATURE_THICKNESSES.put("xxx-small", new Float(1.0f));
+        FEATURE_THICKNESSES.put("xx-small", new Float(2.0f));
+        FEATURE_THICKNESSES.put("x-small", new Float(4.0f));
+        FEATURE_THICKNESSES.put("small", new Float(6.0f));
+        FEATURE_THICKNESSES.put("medium", new Float(8.0f)); //default for featureThickness
+        FEATURE_THICKNESSES.put("large", new Float(10.0f));
+        FEATURE_THICKNESSES.put("x-large", new Float(12.0f));
+        FEATURE_THICKNESSES.put("xx-large", new Float(14.0f));
+        FEATURE_THICKNESSES.put("xxx-large", new Float(16.0f));
+
+        FEATURESLOT_SPACINGS.put("xxx-small", new Float(0.0f));
+        FEATURESLOT_SPACINGS.put("xx-small", new Float(1.0f));
+        FEATURESLOT_SPACINGS.put("x-small", new Float(2.0f));
+        FEATURESLOT_SPACINGS.put("small", new Float(3.0f));
+        FEATURESLOT_SPACINGS.put("medium", new Float(4.0f)); //default for featureSlotSpacing
+        FEATURESLOT_SPACINGS.put("large", new Float(5.0f));
+        FEATURESLOT_SPACINGS.put("x-large", new Float(6.0f));
+        FEATURESLOT_SPACINGS.put("xx-large", new Float(7.0f));
+        FEATURESLOT_SPACINGS.put("xxx-large", new Float(8.0f));
+
+        BACKBONE_THICKNESSES.put("xxx-small", new Float(1.0f));
+        BACKBONE_THICKNESSES.put("xx-small", new Float(2.0f));
+        BACKBONE_THICKNESSES.put("x-small", new Float(3.0f));
+        BACKBONE_THICKNESSES.put("small", new Float(4.0f));
+        BACKBONE_THICKNESSES.put("medium", new Float(5.0f)); //default for backboneThickness
+        BACKBONE_THICKNESSES.put("large", new Float(6.0f));
+        BACKBONE_THICKNESSES.put("x-large", new Float(7.0f));
+        BACKBONE_THICKNESSES.put("xx-large", new Float(8.0f));
+        BACKBONE_THICKNESSES.put("xxx-large", new Float(9.0f));
+
+        ARROWHEAD_LENGTHS.put("xxx-small", new Double(1.0d));
+        ARROWHEAD_LENGTHS.put("xx-small", new Double(2.0d));
+        ARROWHEAD_LENGTHS.put("x-small", new Double(3.0d));
+        ARROWHEAD_LENGTHS.put("small", new Double(4.0d));
+        ARROWHEAD_LENGTHS.put("medium", new Double(5.0d)); //default for arrowheadLength
+        ARROWHEAD_LENGTHS.put("large", new Double(6.0d));
+        ARROWHEAD_LENGTHS.put("x-large", new Double(7.0d));
+        ARROWHEAD_LENGTHS.put("xx-large", new Double(8.0d));
+        ARROWHEAD_LENGTHS.put("xxx-large", new Double(9.0d));
+
+        TICK_LENGTHS.put("xxx-small", new Float(3.0f));
+        TICK_LENGTHS.put("xx-small", new Float(4.0f));
+        TICK_LENGTHS.put("x-small", new Float(5.0f));
+        TICK_LENGTHS.put("small", new Float(6.0f));
+        TICK_LENGTHS.put("medium", new Float(7.0f)); //default for ticks
+        TICK_LENGTHS.put("large", new Float(8.0f));
+        TICK_LENGTHS.put("x-large", new Float(9.0f));
+        TICK_LENGTHS.put("xx-large", new Float(10.0f));
+        TICK_LENGTHS.put("xxx-large", new Float(11.0f));
+
+        MINIMUM_FEATURE_LENGTHS.put("xxx-small", new Double(0.02d)); //default for minimumFeatureLength
+        MINIMUM_FEATURE_LENGTHS.put("xx-small", new Double(0.05d));
+        MINIMUM_FEATURE_LENGTHS.put("x-small", new Double(0.1d));
+        MINIMUM_FEATURE_LENGTHS.put("small", new Double(0.5d));
+        MINIMUM_FEATURE_LENGTHS.put("medium", new Double(1.0d));
+        MINIMUM_FEATURE_LENGTHS.put("large", new Double(1.5d));
+        MINIMUM_FEATURE_LENGTHS.put("x-large", new Double(2.0d));
+        MINIMUM_FEATURE_LENGTHS.put("xx-large", new Double(2.5d));
+        MINIMUM_FEATURE_LENGTHS.put("xxx-large", new Double(3.0d));
+
+        ORIGINS.put("1", new Double(60.0d));
+        ORIGINS.put("2", new Double(30.0d));
+        ORIGINS.put("3", new Double(0.0d));
+        ORIGINS.put("4", new Double(-30.0d));
+        ORIGINS.put("5", new Double(-60.0d));
+        ORIGINS.put("6", new Double(-90.0d));
+        ORIGINS.put("7", new Double(-120.0d));
+        ORIGINS.put("8", new Double(-150.0d));
+        ORIGINS.put("9", new Double(-180.0d));
+        ORIGINS.put("10", new Double(-210.0d));
+        ORIGINS.put("11", new Double(-240.0d));
+        ORIGINS.put("12", new Double(90.0d));  //default for origin
+
+        TICK_THICKNESSES.put("xxx-small", new Float(0.02f));
+        TICK_THICKNESSES.put("xx-small", new Float(0.5f));
+        TICK_THICKNESSES.put("x-small", new Float(1.0f));
+        TICK_THICKNESSES.put("small", new Float(1.5f));
+        TICK_THICKNESSES.put("medium", new Float(2.0f)); //default for tickThickness
+        TICK_THICKNESSES.put("large", new Float(2.5f));
+        TICK_THICKNESSES.put("x-large", new Float(3.0f));
+        TICK_THICKNESSES.put("xx-large", new Float(3.5f));
+        TICK_THICKNESSES.put("xxx-large", new Float(4.0f));
+
+        LABEL_LINE_THICKNESSES.put("xxx-small", new Float(0.02f));
+        LABEL_LINE_THICKNESSES.put("xx-small", new Float(0.25f));
+        LABEL_LINE_THICKNESSES.put("x-small", new Float(0.50f));
+        LABEL_LINE_THICKNESSES.put("small", new Float(0.75f));
+        LABEL_LINE_THICKNESSES.put("medium", new Float(1.0f)); //default for labelLineThickness
+        LABEL_LINE_THICKNESSES.put("large", new Float(1.25f));
+        LABEL_LINE_THICKNESSES.put("x-large", new Float(1.5f));
+        LABEL_LINE_THICKNESSES.put("xx-large", new Float(1.75f));
+        LABEL_LINE_THICKNESSES.put("xxx-large", new Float(2.0f));
+
+        LABEL_LINE_LENGTHS.put("xxx-small", new Double(10.0d));
+        LABEL_LINE_LENGTHS.put("xx-small", new Double(20.0d));
+        LABEL_LINE_LENGTHS.put("x-small", new Double(30.0d));
+        LABEL_LINE_LENGTHS.put("small", new Double(40.0d));
+        LABEL_LINE_LENGTHS.put("medium", new Double(50.0d)); //default for labelLineLength
+        LABEL_LINE_LENGTHS.put("large", new Double(60.0d));
+        LABEL_LINE_LENGTHS.put("x-large", new Double(70.0d));
+        LABEL_LINE_LENGTHS.put("xx-large", new Double(80.0d));
+        LABEL_LINE_LENGTHS.put("xxx-large", new Double(90.0d));
+
+        LABEL_PLACEMENT_QUALITIES.put("good", new Integer(5));
+        LABEL_PLACEMENT_QUALITIES.put("better", new Integer(8));  //default for labelPlacementQuality
+        LABEL_PLACEMENT_QUALITIES.put("best", new Integer(10));
+
+        BOOLEANS.put("true", new Boolean(true)); //default for showShading //default for moveInnerLabelsToOuter
+        BOOLEANS.put("false", new Boolean(false)); //default for allowLabelClash //default for showWarning
+
+        LEGEND_POSITIONS.put("upper-left", new Integer(LEGEND_UPPER_LEFT));
+        LEGEND_POSITIONS.put("upper-center", new Integer(LEGEND_UPPER_CENTER));
+        LEGEND_POSITIONS.put("upper-right", new Integer(LEGEND_UPPER_RIGHT));
+        LEGEND_POSITIONS.put("middle-left", new Integer(LEGEND_MIDDLE_LEFT));
+        LEGEND_POSITIONS.put("middle-left-of-center", new Integer(LEGEND_MIDDLE_LEFT_OF_CENTER));
+        LEGEND_POSITIONS.put("middle-center", new Integer(LEGEND_MIDDLE_CENTER));
+        LEGEND_POSITIONS.put("middle-right-of-center", new Integer(LEGEND_MIDDLE_RIGHT_OF_CENTER));
+        LEGEND_POSITIONS.put("middle-right", new Integer(LEGEND_MIDDLE_RIGHT));	//default for legend
+        LEGEND_POSITIONS.put("lower-left", new Integer(LEGEND_LOWER_LEFT));
+        LEGEND_POSITIONS.put("lower-center", new Integer(LEGEND_LOWER_CENTER));
+        LEGEND_POSITIONS.put("lower-right", new Integer(LEGEND_LOWER_RIGHT));
+
+        LEGEND_SHOW_ZOOM.put("true", new Integer(LEGEND_DRAW_ZOOMED));  //default for legend
+        LEGEND_SHOW_ZOOM.put("false", new Integer(LEGEND_NO_DRAW_ZOOMED));
+
+        LEGEND_ALIGNMENTS.put("left", new Integer(LEGEND_ITEM_ALIGN_LEFT)); //default for legend //default for legendItem
+        LEGEND_ALIGNMENTS.put("center", new Integer(LEGEND_ITEM_ALIGN_CENTER));
+        LEGEND_ALIGNMENTS.put("right", new Integer(LEGEND_ITEM_ALIGN_RIGHT));
+
+        SWATCH_TYPES.put("true", new Integer(SWATCH_SHOW));
+        SWATCH_TYPES.put("false", new Integer(SWATCH_NO_SHOW)); //default for legendItem
+
+    }
+
+    /**
+     * Generates a Cgview object from an XML file.
+     *
+     * @param filename the XML file to read.
+     * @return the newly created Cgview object.
+     * @throws SAXException
+     * @throws IOException
+     */
+    public Cgview createCgviewFromFile(String filename) throws SAXException, IOException {
+
+        XMLReader xr = new org.apache.xerces.parsers.SAXParser();
+        xr.setContentHandler(this);
+
+        ErrorHandler handler = new ErrorHandler() {
+            public void warning(SAXParseException e) throws SAXException {
+                System.err.println("[warning] " + e.getMessage());
+            }
+
+            public void error(SAXParseException e) throws SAXException {
+                System.err.println("[error] " + e.getMessage());
+            }
+
+            public void fatalError(SAXParseException e) throws SAXException {
+                System.err.println("[fatal error] " + e.getMessage());
+                throw e;
+            }
+        };
+
+        xr.setErrorHandler(handler);
+        FileReader r = new FileReader(filename);
+        xr.parse(new InputSource(r));
+
+        if (currentCgview == null) {
+            String error = "no cgview tags were encountered";
+            throw new SAXException(error);
+        }
+
+        return currentCgview;
+    }
+
+    /**
+     * Generates a Cgview object from a String of XML content.
+     *
+     * @param xml the XML content to read.
+     * @return the newly created Cgview object.
+     * @throws SAXException
+     * @throws IOException
+     */
+    public Cgview createCgviewFromString(String xml) throws SAXException, IOException {
+
+        XMLReader xr = new org.apache.xerces.parsers.SAXParser();
+        xr.setContentHandler(this);
+
+        ErrorHandler handler = new ErrorHandler() {
+            public void warning(SAXParseException e) throws SAXException {
+                System.err.println("[warning] " + e.getMessage());
+            }
+
+            public void error(SAXParseException e) throws SAXException {
+                System.err.println("[error] " + e.getMessage());
+            }
+
+            public void fatalError(SAXParseException e) throws SAXException {
+                System.err.println("[fatal error] " + e.getMessage());
+                throw e;
+            }
+        };
+
+        xr.setErrorHandler(handler);
+
+        byte[] xml_bytes = xml.getBytes();
+        ByteArrayInputStream b = new ByteArrayInputStream(xml_bytes);
+        xr.parse(new InputSource(b));
+
+        if (currentCgview == null) {
+            String error = "no cgview tags were encountered";
+            throw new SAXException(error);
+        }
+
+        return currentCgview;
+    }
+
+    /**
+     * Adds FeatureSlot, Feature, and FeatureRange objects described in an XML file to an existing Cgview object. Any
+     * Legend and LegendItem objects in the XML are ignored, as are attributes in the cgview element.
+     *
+     * @param cgview   the Cgview object to modify.
+     * @param filename the XML file to supply the additional map content.
+     * @throws SAXException
+     * @throws IOException
+     */
+    public void addToCgviewFromFile(Cgview cgview, String filename) throws SAXException, IOException {
+
+        ignoreCgviewTag = true;
+        ignoreLegendTag = true;
+        ignoreLegendItemTag = true;
+
+        currentCgview = cgview;
+
+        XMLReader xr = new org.apache.xerces.parsers.SAXParser();
+        xr.setContentHandler(this);
+
+        ErrorHandler handler = new ErrorHandler() {
+            public void warning(SAXParseException e) throws SAXException {
+                System.err.println("[warning] " + e.getMessage());
+            }
+
+            public void error(SAXParseException e) throws SAXException {
+                System.err.println("[error] " + e.getMessage());
+            }
+
+            public void fatalError(SAXParseException e) throws SAXException {
+                System.err.println("[fatal error] " + e.getMessage());
+                throw e;
+            }
+        };
+
+        xr.setErrorHandler(handler);
+        FileReader r = new FileReader(filename);
+        xr.parse(new InputSource(r));
+        ignoreCgviewTag = false;
+        ignoreLegendTag = false;
+        ignoreLegendItemTag = false;
+    }
+
+    /**
+     * Adds FeatureSlot, Feature, and FeatureRange objects described in a String of XML to an existing Cgview object.
+     * Any Legend and LegendItem objects in the XML are ignored, as are attributes in the cgview element.
+     *
+     * @param cgview the Cgview object to modify.
+     * @param xml    the XML content to read.
+     * @throws SAXException
+     * @throws IOException
+     */
+    public void addToCgviewFromString(Cgview cgview, String xml) throws SAXException, IOException {
+
+        ignoreCgviewTag = true;
+        ignoreLegendTag = true;
+        ignoreLegendItemTag = true;
+
+        currentCgview = cgview;
+
+        XMLReader xr = new org.apache.xerces.parsers.SAXParser();
+        xr.setContentHandler(this);
+
+        ErrorHandler handler = new ErrorHandler() {
+            public void warning(SAXParseException e) throws SAXException {
+                System.err.println("[warning] " + e.getMessage());
+            }
+
+            public void error(SAXParseException e) throws SAXException {
+                System.err.println("[error] " + e.getMessage());
+            }
+
+            public void fatalError(SAXParseException e) throws SAXException {
+                System.err.println("[fatal error] " + e.getMessage());
+                throw e;
+            }
+        };
+
+        xr.setErrorHandler(handler);
+
+        byte[] xml_bytes = xml.getBytes();
+        ByteArrayInputStream b = new ByteArrayInputStream(xml_bytes);
+        xr.parse(new InputSource(b));
+
+        ignoreCgviewTag = false;
+        ignoreLegendTag = false;
+        ignoreLegendItemTag = false;
+    }
+
+
+    /**
+     * Sets the font size of feature labels. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of feature labels.
+     */
+    public void setLabelFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	labelFontSize = size;
+    }
+
+    /**
+     * Sets the font size of the sequence ruler. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of the sequence ruler.
+     */
+    public void setRulerFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	rulerFontSize = size;
+    }
+
+    /**
+     * Sets the font size of legends. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of legends.
+     */
+    public void setLegendFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	legendFontSize = size;
+    }
+
+    public void setDocumentLocator(Locator loc) {
+        locator = loc;
+    }
+
+
+    public void startDocument() {
+        System.out.println("Parsing XML input.");
+    }
+
+
+    public void endDocument() {
+        //System.out.println("End document");
+    }
+
+    public void startElement(String uri, String name, String qName, Attributes atts) throws SAXException {
+        //System.out.println("Start element: " + name);
+        ElementDetails details = new ElementDetails(name, atts);
+        context.push(details);
+
+        if ((name.equalsIgnoreCase("cgview")) && (!(ignoreCgviewTag))) {
+            handleCgview();
+        } else if (name.equalsIgnoreCase("featureSlot")) {
+            handleFeatureSlot();
+        } else if (name.equalsIgnoreCase("feature")) {
+            handleFeature();
+        } else if (name.equalsIgnoreCase("featureRange")) {
+            handleFeatureRange();
+        } else if ((name.equalsIgnoreCase("legend")) && (!(ignoreLegendTag))) {
+            handleLegend();
+        } else if ((name.equalsIgnoreCase("legendItem")) && (!(ignoreLegendItemTag))) {
+            handleLegendItem();
+        }
+
+        content.setLength(0);
+    }
+
+    public void characters(char[] ch, int start, int length) {
+        content.append(ch, start, length);
+    }
+
+    public void endElement(String uri, String name, String qName) throws SAXException {
+        //System.out.println("End element: " + name);
+        content.setLength(0);
+        context.pop();
+
+        if (name.equalsIgnoreCase("cgview")) {
+            //currentCgview = null;
+        } else if (name.equalsIgnoreCase("featureSlot")) {
+            currentFeatureSlot = null;
+        } else if (name.equalsIgnoreCase("feature")) {
+            currentFeature = null;
+        } else if (name.equalsIgnoreCase("featureRange")) {
+            currentFeatureRange = null;
+        } else if (name.equalsIgnoreCase("legend")) {
+            currentLegend = null;
+        } else if (name.equalsIgnoreCase("legendItem")) {
+            currentLegendItem = null;
+        }
+    }
+
+    /**
+     * Handles the cgview element and its attributes.
+     *
+     * @throws SAXException
+     */
+    //required attributes: sequenceLength.
+    //optional attributes: title, rulerUnits, rulerFont, rulerPadding, labelFont, useInnerLabels, featureThickness, featureSlotSpacing, backboneThickness, arrowheadLength, minimumFeatureLength, titleFont, titleFontColor, rulerFontColor, origin, tickThickness, tickLength, labelLineThickness, labelLineLength, backboneColor, backgroundColor, longTickColor, giveFeaturePositions, shortTickColor, zeroTickColor, width, height, backboneRadius, labelPlacementQuality, useColoredLabelBackgrounds, s [...]
+    private void handleCgview() throws SAXException {
+
+        for (int p = context.size() - 1; p >= 0; p--) {
+            ElementDetails elem = (ElementDetails) context.elementAt(p);
+            if (elem.name.equalsIgnoreCase("cgview")) {
+                if (currentCgview != null) {
+                    //an error because already in a cgview tag
+                    String error = "cgview element encountered inside of another cgview element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                }
+                if (elem.attributes.getValue("sequenceLength") == null) {
+                    //an error because no length
+                    String error = "cgview element is missing 'sequenceLength' attribute";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else {
+                    try {
+                        cgviewLength = Integer.parseInt(elem.attributes.getValue("sequenceLength"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'sequenceLength' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (cgviewLength > MAX_BASES) {
+                        String error = "value for 'sequenceLength' attribute in cgview element must be less than " + MAX_BASES;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (cgviewLength < MIN_BASES) {
+                        String error = "value for 'sequenceLength' attribute in cgview element must be greater than " + MIN_BASES;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentCgview = new Cgview(cgviewLength);
+                }
+
+                //optional tags
+
+                //title
+                if (elem.attributes.getValue("title") != null) {
+                    currentCgview.setTitle(elem.attributes.getValue("title"));
+                }
+
+                //info
+                if (elem.attributes.getValue("info") != null) {
+                    currentCgview.setWarningText(elem.attributes.getValue("info"));
+                }
+
+                //rulerUnits
+                if (elem.attributes.getValue("rulerUnits") != null) {
+                    if (RULER_UNITS.get(((elem.attributes.getValue("rulerUnits"))).toLowerCase()) != null) {
+                        currentCgview.setRulerUnits(((Integer) RULER_UNITS.get(((elem.attributes.getValue("rulerUnits"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'rulerUnits' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //showWarning
+                if (elem.attributes.getValue("showWarning") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("showWarning"))).toLowerCase()) != null) {
+                        currentCgview.setShowWarning(((Boolean) BOOLEANS.get(((elem.attributes.getValue("showWarning"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'showWarning' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+
+                //isLinear
+                if (elem.attributes.getValue("isLinear") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("isLinear"))).toLowerCase()) != null) {
+                        currentCgview.setIsLinear(((Boolean) BOOLEANS.get(((elem.attributes.getValue("isLinear"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'isLinear' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //showBorder
+                if (elem.attributes.getValue("showBorder") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("showBorder"))).toLowerCase()) != null) {
+                        currentCgview.setShowBorder(((Boolean) BOOLEANS.get(((elem.attributes.getValue("showBorder"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'showBorder' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //moveInnerLabelsToOuter
+                if (elem.attributes.getValue("moveInnerLabelsToOuter") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("moveInnerLabelsToOuter"))).toLowerCase()) != null) {
+                        currentCgview.setMoveInnerLabelsToOuter(((Boolean) BOOLEANS.get(((elem.attributes.getValue("moveInnerLabelsToOuter"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'moveInnerLabelsToOuter' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //showShading
+                if (elem.attributes.getValue("showShading") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase()) != null) {
+                        currentCgview.setShowShading(((Boolean) BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'showShading' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //useColoredLabelBackgrounds
+                if (elem.attributes.getValue("useColoredLabelBackgrounds") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("useColoredLabelBackgrounds"))).toLowerCase()) != null) {
+                        currentCgview.setUseColoredLabelBackgrounds(((Boolean) BOOLEANS.get(((elem.attributes.getValue("useColoredLabelBackgrounds"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'useColoredLabelBackgrounds' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //labelPlacementQuality
+                if (elem.attributes.getValue("labelPlacementQuality") != null) {
+                    if (LABEL_PLACEMENT_QUALITIES.get(((elem.attributes.getValue("labelPlacementQuality"))).toLowerCase()) != null) {
+                        currentCgview.setLabelPlacementQuality(((Integer) LABEL_PLACEMENT_QUALITIES.get(((elem.attributes.getValue("labelPlacementQuality"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'labelPlacementQuality' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //useInnerLabels
+                if (elem.attributes.getValue("useInnerLabels") != null) {
+                    if (USE_INNER_LABELS.get(((elem.attributes.getValue("useInnerLabels"))).toLowerCase()) != null) {
+                        currentCgview.setUseInnerLabels(((Integer) USE_INNER_LABELS.get(((elem.attributes.getValue("useInnerLabels"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'useInnerLabels' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //giveFeaturePositions
+                if (elem.attributes.getValue("giveFeaturePositions") != null) {
+                    if (GIVE_FEATURE_POSITIONS.get(((elem.attributes.getValue("giveFeaturePositions"))).toLowerCase()) != null) {
+                        currentCgview.setGiveFeaturePositions(((Integer) GIVE_FEATURE_POSITIONS.get(((elem.attributes.getValue("giveFeaturePositions"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'giveFeaturePositions' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //titleFont
+                if (elem.attributes.getValue("titleFont") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("titleFont"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentCgview.setTitleFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'titleFont' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'titleFont' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+
+                //warningFont
+                if (elem.attributes.getValue("warningFont") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("warningFont"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentCgview.setWarningFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'warningFont' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'warningFont' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+
+                //rulerFont
+                if (elem.attributes.getValue("rulerFont") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("rulerFont"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentCgview.setRulerFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'rulerFont' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'rulerFont' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+
+                //labelFont
+                if (elem.attributes.getValue("labelFont") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("labelFont"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentCgview.setLabelFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'labelFont' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'labelFont' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+
+                //titleFontColor
+                if (elem.attributes.getValue("titleFontColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("titleFontColor"))).toLowerCase()) != null) {
+                        currentCgview.setTitleFontColor((Color) COLORS.get(((elem.attributes.getValue("titleFontColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("titleFontColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setTitleFontColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'titleFontColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'titleFontColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //globalLabelColor
+                if (elem.attributes.getValue("globalLabelColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("globalLabelColor"))).toLowerCase()) != null) {
+                        currentCgview.setGlobalLabelColor((Color) COLORS.get(((elem.attributes.getValue("globalLabelColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("globalLabelColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setGlobalLabelColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'globalLabelColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'globalLabelColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //warningFontColor
+                if (elem.attributes.getValue("warningFontColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("warningFontColor"))).toLowerCase()) != null) {
+                        currentCgview.setWarningFontColor((Color) COLORS.get(((elem.attributes.getValue("warningFontColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("warningFontColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setWarningFontColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'warningFontColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'warningFontColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //borderColor
+                if (elem.attributes.getValue("borderColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("borderColor"))).toLowerCase()) != null) {
+                        currentCgview.setBorderColor((Color) COLORS.get(((elem.attributes.getValue("borderColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("borderColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setBorderColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'borderColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'borderColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+
+                //rulerFontColor
+                if (elem.attributes.getValue("rulerFontColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("rulerFontColor"))).toLowerCase()) != null) {
+                        currentCgview.setRulerFontColor((Color) COLORS.get(((elem.attributes.getValue("rulerFontColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("rulerFontColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setRulerFontColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'rulerFontColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'rulerFontColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //backboneColor
+                if (elem.attributes.getValue("backboneColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("backboneColor"))).toLowerCase()) != null) {
+                        currentCgview.setBackboneColor((Color) COLORS.get(((elem.attributes.getValue("backboneColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("backboneColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setBackboneColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'backboneColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'backboneColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //backgroundColor
+                if (elem.attributes.getValue("backgroundColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("backgroundColor"))).toLowerCase()) != null) {
+                        currentCgview.setBackgroundColor((Color) COLORS.get(((elem.attributes.getValue("backgroundColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("backgroundColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setBackgroundColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'backgroundColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'backgroundColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //longTickColor
+                if (elem.attributes.getValue("longTickColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("longTickColor"))).toLowerCase()) != null) {
+                        currentCgview.setLongTickColor((Color) COLORS.get(((elem.attributes.getValue("longTickColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("longTickColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setLongTickColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'longTickColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'longTickColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //shortTickColor
+                if (elem.attributes.getValue("shortTickColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("shortTickColor"))).toLowerCase()) != null) {
+                        currentCgview.setShortTickColor((Color) COLORS.get(((elem.attributes.getValue("shortTickColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("shortTickColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setShortTickColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'shortTickColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'shortTickColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //zeroTickColor
+                if (elem.attributes.getValue("zeroTickColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("zeroTickColor"))).toLowerCase()) != null) {
+                        currentCgview.setZeroTickColor((Color) COLORS.get(((elem.attributes.getValue("zeroTickColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("zeroTickColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentCgview.setZeroTickColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'zeroTickColor' attribute in cgview element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'zeroTickColor' attribute in cgview element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //featureThickness
+                if (elem.attributes.getValue("featureThickness") != null) {
+                    if (FEATURE_THICKNESSES.get(((elem.attributes.getValue("featureThickness"))).toLowerCase()) != null) {
+                        currentCgview.setFeatureThickness(((Float) FEATURE_THICKNESSES.get(((elem.attributes.getValue("featureThickness"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("featureThickness"));
+			    currentCgview.setFeatureThickness(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'featureThickness' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    }
+                }
+
+
+
+                //featureSlotSpacing
+                if (elem.attributes.getValue("featureSlotSpacing") != null) {
+                    if (FEATURESLOT_SPACINGS.get(((elem.attributes.getValue("featureSlotSpacing"))).toLowerCase()) != null) {
+                        currentCgview.setFeatureSlotSpacing(((Float) FEATURESLOT_SPACINGS.get(((elem.attributes.getValue("featureSlotSpacing"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("featureSlotSpacing"));
+			    currentCgview.setFeatureSlotSpacing(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'featureSlotSpacing' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    }            
+                }
+
+                //backboneThickness
+                if (elem.attributes.getValue("backboneThickness") != null) {
+                    if (BACKBONE_THICKNESSES.get(((elem.attributes.getValue("backboneThickness"))).toLowerCase()) != null) {
+                        currentCgview.setBackboneThickness(((Float) BACKBONE_THICKNESSES.get(((elem.attributes.getValue("backboneThickness"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("backboneThickness"));
+			    currentCgview.setBackboneThickness(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'backboneThickness' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    }   
+                }
+
+                //rulerPadding
+                if (elem.attributes.getValue("rulerPadding") != null) {
+
+		    try {
+			double s = Double.parseDouble(elem.attributes.getValue("rulerPadding"));
+			currentCgview.setRulerTextPadding(s);
+		    }
+		    catch (Exception e) {
+
+			String error = "value for 'rulerPadding' attribute in cgview element not understood";
+			if (locator != null) {
+			    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			}
+			//throw new SAXException (error);
+			System.err.println("[warning] " + error);
+		    }
+
+                }
+
+                //arrowheadLength
+                if (elem.attributes.getValue("arrowheadLength") != null) {
+                    if (ARROWHEAD_LENGTHS.get(((elem.attributes.getValue("arrowheadLength"))).toLowerCase()) != null) {
+                        currentCgview.setArrowheadLength(((Double) ARROWHEAD_LENGTHS.get(((elem.attributes.getValue("arrowheadLength"))).toLowerCase())).doubleValue());
+                    } else {
+			try {
+			    double s = Double.parseDouble(elem.attributes.getValue("arrowheadLength"));
+			    currentCgview.setArrowheadLength(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'arrowheadLength' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    }  
+                }
+
+                //tickDensity
+                if (elem.attributes.getValue("tickDensity") != null) {
+
+		    try {
+			double s = Double.parseDouble(elem.attributes.getValue("tickDensity"));
+			currentCgview.setTickDensity(s);
+		    }
+		    catch (Exception e) {
+
+			String error = "value for 'tickDensity' attribute in cgview element not understood";
+			if (locator != null) {
+			    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			}
+			//throw new SAXException (error);
+			System.err.println("[warning] " + error);
+		    }
+
+                }
+
+
+                //tickLength
+                if (elem.attributes.getValue("tickLength") != null) {
+                    if (TICK_LENGTHS.get(((elem.attributes.getValue("tickLength"))).toLowerCase()) != null) {
+                        currentCgview.setTickLength(((Float) TICK_LENGTHS.get(((elem.attributes.getValue("tickLength"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("tickLength"));
+			    currentCgview.setTickLength(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'tickLength' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    } 
+                }
+
+                //minimumFeatureLength
+                if (elem.attributes.getValue("minimumFeatureLength") != null) {
+                    if (MINIMUM_FEATURE_LENGTHS.get(((elem.attributes.getValue("minimumFeatureLength"))).toLowerCase()) != null) {
+                        currentCgview.setMinimumFeatureLength(((Double) MINIMUM_FEATURE_LENGTHS.get(((elem.attributes.getValue("minimumFeatureLength"))).toLowerCase())).doubleValue());
+                    } else {
+			try {
+			    double s = Double.parseDouble(elem.attributes.getValue("minimumFeatureLength"));
+			    currentCgview.setMinimumFeatureLength(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'minimumFeatureLength' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    } 
+                }
+
+                //tickThickness
+                if (elem.attributes.getValue("tickThickness") != null) {
+                    if (TICK_THICKNESSES.get(((elem.attributes.getValue("tickThickness"))).toLowerCase()) != null) {
+                        currentCgview.setTickThickness(((Float) TICK_THICKNESSES.get(((elem.attributes.getValue("tickThickness"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("tickThickness"));
+			    currentCgview.setTickThickness(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'tickThickness' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    } 
+                }
+
+                //shortTickThickness
+                if (elem.attributes.getValue("shortTickThickness") != null) {
+                    if (TICK_THICKNESSES.get(((elem.attributes.getValue("shortTickThickness"))).toLowerCase()) != null) {
+                        currentCgview.setShortTickThickness(((Float) TICK_THICKNESSES.get(((elem.attributes.getValue("shortTickThickness"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("shortTickThickness"));
+			    currentCgview.setShortTickThickness(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'shortTickThickness' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    } 
+                }
+
+                //labelLineThickness
+                if (elem.attributes.getValue("labelLineThickness") != null) {
+                    if (LABEL_LINE_THICKNESSES.get(((elem.attributes.getValue("labelLineThickness"))).toLowerCase()) != null) {
+                        currentCgview.setLabelLineThickness(((Float) LABEL_LINE_THICKNESSES.get(((elem.attributes.getValue("labelLineThickness"))).toLowerCase())).floatValue());
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("labelLineThickness"));
+			    currentCgview.setLabelLineThickness(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'labelLineThickness' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    } 
+                }
+
+                //labelLineLength
+                if (elem.attributes.getValue("labelLineLength") != null) {
+                    if (LABEL_LINE_LENGTHS.get(((elem.attributes.getValue("labelLineLength"))).toLowerCase()) != null) {
+                        currentCgview.setLabelLineLength(((Double) LABEL_LINE_LENGTHS.get(((elem.attributes.getValue("labelLineLength"))).toLowerCase())).doubleValue());
+                    } else {
+			try {
+			    double s = Double.parseDouble(elem.attributes.getValue("labelLineLength"));
+			    currentCgview.setLabelLineLength(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'labelLineLength' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    } 
+                }
+
+                //origin
+                if (elem.attributes.getValue("origin") != null) {
+                    if (ORIGINS.get(((elem.attributes.getValue("origin"))).toLowerCase()) != null) {
+                        currentCgview.setOrigin(((Double) ORIGINS.get(((elem.attributes.getValue("origin"))).toLowerCase())).doubleValue());
+                    } else {
+                        String error = "value for 'origin' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //width
+                if (elem.attributes.getValue("width") != null) {
+                    try {
+                        imageWidth = Integer.parseInt(elem.attributes.getValue("width"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'width' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (imageWidth < MIN_IMAGE_WIDTH) {
+                        String error = "value for 'width' attribute in cgview element must be greater than or equal to " + MIN_IMAGE_WIDTH;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (imageWidth > MAX_IMAGE_WIDTH) {
+                        String error = "value for 'width' attribute in cgview element must be less than or equal to " + MAX_IMAGE_WIDTH;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+                    currentCgview.setWidth(imageWidth);
+                }
+
+                //height
+                if (elem.attributes.getValue("height") != null) {
+                    try {
+                        imageHeight = Integer.parseInt(elem.attributes.getValue("height"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'height' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (imageHeight < MIN_IMAGE_HEIGHT) {
+                        String error = "value for 'height' attribute in cgview element must be greater than or equal to " + MIN_IMAGE_HEIGHT;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (imageHeight > MAX_IMAGE_HEIGHT) {
+                        String error = "value for 'height' attribute in cgview element must be less than or equal to " + MAX_IMAGE_HEIGHT;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentCgview.setHeight(imageHeight);
+                }
+
+                //backboneRadius
+                if (elem.attributes.getValue("backboneRadius") != null) {
+                    double radius;
+                    try {
+                        radius = Double.parseDouble(elem.attributes.getValue("backboneRadius"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'backboneRadius' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (radius < MIN_BACKBONE_RADIUS) {
+                        String error = "value for 'backboneRadius' attribute in cgview element must be greater than or equal to " + MIN_BACKBONE_RADIUS;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (radius > MAX_BACKBONE_RADIUS) {
+                        String error = "value for 'backboneRadius' attribute in cgview element must be less than or equal to " + MAX_BACKBONE_RADIUS;
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentCgview.setBackboneRadius(radius);
+                }
+
+                //globalLabel
+                if (elem.attributes.getValue("globalLabel") != null) {
+                    if (GLOBAL_LABEL_TYPES.get(((elem.attributes.getValue("globalLabel"))).toLowerCase()) != null) {
+                        currentCgview.setGlobalLabel(((Integer) GLOBAL_LABEL_TYPES.get(((elem.attributes.getValue("globalLabel"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'globalLabel' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //labelsToKeep
+                if (elem.attributes.getValue("labelsToKeep") != null) {
+                    int labelsToKeep;
+                    try {
+                        labelsToKeep = Integer.parseInt(elem.attributes.getValue("labelsToKeep"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'labelsToKeep' attribute in cgview element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (labelsToKeep < 0) {
+                        String error = "value for 'labelsToKeep' attribute in cgview element must be greater than or equal to 0";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentCgview.setLabelsToKeep(labelsToKeep);
+                }
+		
+		if (this.rulerFontSize != -1) {
+		    //rulerFont = new Font("SansSerif", Font.PLAIN, this.rulerFontSize);
+		    currentCgview.setRulerFont(new Font(currentCgview.getRulerFont().getName(), currentCgview.getRulerFont().getStyle(), this.rulerFontSize));
+		}
+            }
+        }
+    }
+
+    /**
+     * Handles the featureSlot element and its attributes.
+     *
+     * @throws SAXException
+     */
+    //required attributes: strand.
+    //optional attributes featureThickness, showShading:
+    private void handleFeatureSlot() throws SAXException {
+
+        for (int p = context.size() - 1; p >= 0; p--) {
+            ElementDetails elem = (ElementDetails) context.elementAt(p);
+            if (elem.name.equalsIgnoreCase("featureSlot")) {
+                if (currentFeatureSlot != null) {
+                    //an error because already in a FeatureSlot tag
+                    String error = "featureSlot element encountered inside of another featureSlot element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentCgview == null) {
+                    //an error because no currentCgview
+                    String error = "featureSlot element encountered outside of a cgview element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (elem.attributes.getValue("strand") == null) {
+                    //an error because no strand given
+                    String error = "featureSlot element is missing 'strand' attribute";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else {
+                    if ((elem.attributes.getValue("strand")).equalsIgnoreCase("direct")) {
+                        currentFeatureSlot = new FeatureSlot(currentCgview, DIRECT_STRAND);
+                    } else if ((elem.attributes.getValue("strand")).equalsIgnoreCase("reverse")) {
+                        currentFeatureSlot = new FeatureSlot(currentCgview, REVERSE_STRAND);
+                    } else {
+                        //an error because strand could not be understood
+                        String error = "value for 'strand' attribute in featureSlot element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+                }
+                //optional tags
+                //featureThickness
+                if (elem.attributes.getValue("featureThickness") != null) {
+                    if (FEATURE_THICKNESSES.get(((elem.attributes.getValue("featureThickness"))).toLowerCase()) != null) {
+                        currentFeatureSlot.setFeatureThickness(((Float) FEATURE_THICKNESSES.get(((elem.attributes.getValue("featureThickness"))).toLowerCase())).floatValue());
+
+                    } else {
+			try {
+			    float s = Float.parseFloat(elem.attributes.getValue("featureThickness"));
+			    currentFeatureSlot.setFeatureThickness(s);
+			}
+			catch (Exception e) {
+
+			    String error = "value for 'featureThickness' attribute in cgview element not understood";
+			    if (locator != null) {
+				error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+			    }
+			    //throw new SAXException (error);
+			    System.err.println("[warning] " + error);
+			}
+                    }
+                }
+                //showShading
+                if (elem.attributes.getValue("showShading") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase()) != null) {
+                        currentFeatureSlot.setShowShading(((Boolean) BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'showShading' attribute in featureSlot element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Handles the feature element and its attributes.
+     *
+     * @throws SAXException
+     */
+    //required attributes:
+    //optional attributes: color, opacity, proportionOfThickness, radiusAdjustment, decoration, showLabel, font, label, showShading, hyperlink, mouseover 
+    private void handleFeature() throws SAXException {
+
+        for (int p = context.size() - 1; p >= 0; p--) {
+            ElementDetails elem = (ElementDetails) context.elementAt(p);
+            if (elem.name.equalsIgnoreCase("feature")) {
+                if (currentFeature != null) {
+                    //an error because already in a Feature tag
+                    String error = "feature element encountered inside of another feature element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentCgview == null) {
+                    //an error because no currentCgview
+                    String error = "feature element encountered outside of a cgview element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentFeatureSlot == null) {
+                    //an error because no currentFeatureSlot
+                    String error = "feature element encountered outside of a featureSlot element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else {
+                    currentFeature = new Feature(currentFeatureSlot);
+                }
+
+                //optional tags
+                //color
+                if (elem.attributes.getValue("color") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("color"))).toLowerCase()) != null) {
+                        currentFeature.setColor((Color) COLORS.get(((elem.attributes.getValue("color"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("color"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentFeature.setColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'color' attribute in feature element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'color' attribute in feature element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+                //opacity
+                if (elem.attributes.getValue("opacity") != null) {
+                    float opacity;
+                    try {
+                        opacity = Float.parseFloat(elem.attributes.getValue("opacity"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'opacity' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity > 1.0f) {
+                        String error = "value for 'opacity' attribute in feature element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity < 0.0f) {
+                        String error = "value for 'opacity' attribute in feature element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeature.setOpacity(opacity);
+                }
+                //proportionOfThickness
+                if (elem.attributes.getValue("proportionOfThickness") != null) {
+                    float thickness;
+                    try {
+                        thickness = Float.parseFloat(elem.attributes.getValue("proportionOfThickness"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'proportionOfThickness' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (thickness > 1.0f) {
+                        String error = "value for 'proportionOfThickness' attribute in feature element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (thickness < 0.0f) {
+                        String error = "value for 'proportionOfThickness' attribute in feature element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeature.setProportionOfThickness(thickness);
+                }
+                //radiusAdjustment
+                if (elem.attributes.getValue("radiusAdjustment") != null) {
+                    float height;
+                    try {
+                        height = Float.parseFloat(elem.attributes.getValue("radiusAdjustment"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'radiusAdjustment' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (height > 1.0f) {
+                        String error = "value for 'radiusAdjustment' attribute in feature element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (height < 0.0f) {
+                        String error = "value for 'radiusAdjustment' attribute in feature element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeature.setRadiusAdjustment(height);
+                }
+                //decoration
+                if (elem.attributes.getValue("decoration") != null) {
+
+                    if (DECORATIONS.get(((elem.attributes.getValue("decoration"))).toLowerCase()) != null) {
+                        currentFeature.setDecoration(((Integer) DECORATIONS.get(((elem.attributes.getValue("decoration"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'decoration' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+                //showLabel
+                if (elem.attributes.getValue("showLabel") != null) {
+                    if (LABEL_TYPES.get(((elem.attributes.getValue("showLabel"))).toLowerCase()) != null) {
+                        currentFeature.setShowLabel(((Integer) LABEL_TYPES.get(((elem.attributes.getValue("showLabel"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'showLabel' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+                //font
+                if (elem.attributes.getValue("font") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("font"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentFeature.setFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'font' attribute in feature element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'font' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+                //label
+                if (elem.attributes.getValue("label") != null) {
+                    currentFeature.setLabel(elem.attributes.getValue("label"));
+                }
+                //showShading
+                if (elem.attributes.getValue("showShading") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase()) != null) {
+                        currentFeature.setShowShading(((Boolean) BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'showShading' attribute in feature element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+                //hyperlink
+                if (elem.attributes.getValue("hyperlink") != null) {
+                    currentFeature.setHyperlink(elem.attributes.getValue("hyperlink"));
+                }
+                //mouseover
+                if (elem.attributes.getValue("mouseover") != null) {
+                    currentFeature.setMouseover(elem.attributes.getValue("mouseover"));
+                }
+
+		if (this.labelFontSize != -1) {
+		    if (currentFeature.getFont() != null) {
+			currentFeature.setFont(new Font(currentFeature.getFont().getName(), currentFeature.getFont().getStyle(), this.labelFontSize));
+		    }
+		    else {
+			currentFeature.setFont(new Font(currentCgview.getLabelFont().getName(), currentCgview.getLabelFont().getStyle(), this.labelFontSize));
+		    }
+		}
+
+            }
+        }
+    }
+
+    /**
+     * Handles the featureRange element and its attributes.
+     *
+     * @throws SAXException
+     */
+    //required attributes: start, stop
+    //optional attributes: color, opacity, proportionOfThickness, radiusAdjustment, decoration, showLabel, font, label, showShading, hyperlink, mouseover
+    private void handleFeatureRange() throws SAXException {
+
+        for (int p = context.size() - 1; p >= 0; p--) {
+            ElementDetails elem = (ElementDetails) context.elementAt(p);
+            if (elem.name.equalsIgnoreCase("featureRange")) {
+                if (currentFeatureRange != null) {
+                    //an error because already in a FeatureRange
+                    String error = "featureRange element encountered inside of another featureRange element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentFeature == null) {
+                    //an error because no current Feature
+                    String error = "featureRange element encountered outside of a feature element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentCgview == null) {
+                    //an error because no currentCgview
+                    String error = "featureRange element encountered outside of a cgview element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentFeatureSlot == null) {
+                    //an error because no currentFeatureSlot
+                    String error = "featureRange element encountered outside of a featureSlot element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (elem.attributes.getValue("start") == null) {
+                    //an error because no length
+                    String error = "featureRange element is missing 'start' attribute";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (elem.attributes.getValue("stop") == null) {
+                    //an error because no length
+                    String error = "featureRange element is missing 'stop' attribute";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else {
+                    int start;
+                    try {
+                        start = Integer.parseInt(elem.attributes.getValue("start"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'start' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (start > cgviewLength) {
+                        String error = "value for 'start' attribute in featureRange element must be less than or equal to the length of the plasmid";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (start < 1) {
+                        String error = "value for 'start' attribute in featureRange element must be greater than or equal to 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    int stop;
+                    try {
+                        stop = Integer.parseInt(elem.attributes.getValue("stop"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'stop' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (stop > cgviewLength) {
+                        String error = "value for 'stop' attribute in featureRange element must be less than or equal to the length of the plasmid";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (stop < 1) {
+                        String error = "value for 'stop' attribute in featureRange element must be greater than or equal to 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeatureRange = new FeatureRange(currentFeature, start, stop);
+                }
+                //optional tags
+                //color
+                if (elem.attributes.getValue("color") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("color"))).toLowerCase()) != null) {
+                        currentFeatureRange.setColor((Color) COLORS.get(((elem.attributes.getValue("color"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("color"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentFeatureRange.setColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'color' attribute in featureRange element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'color' attribute in featureRange element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //opacity
+                if (elem.attributes.getValue("opacity") != null) {
+                    float opacity;
+                    try {
+                        opacity = Float.parseFloat(elem.attributes.getValue("opacity"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'opacity' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity > 1.0f) {
+                        String error = "value for 'opacity' attribute in featureRange element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity < 0.0f) {
+                        String error = "value for 'opacity' attribute in featureRange element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeatureRange.setOpacity(opacity);
+                }
+                //proportionOfThickness
+                if (elem.attributes.getValue("proportionOfThickness") != null) {
+                    float thickness;
+                    try {
+                        thickness = Float.parseFloat(elem.attributes.getValue("proportionOfThickness"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'proportionOfThickness' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (thickness > 1.0f) {
+                        String error = "value for 'proportionOfThickness' attribute in featureRange element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (thickness < 0.0f) {
+                        String error = "value for 'proportionOfThickness' attribute in featureRange element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeatureRange.setProportionOfThickness(thickness);
+                }
+                //radiusAdjustment
+                if (elem.attributes.getValue("radiusAdjustment") != null) {
+                    float height;
+                    try {
+                        height = Float.parseFloat(elem.attributes.getValue("radiusAdjustment"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'radiusAdjustment' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (height > 1.0f) {
+                        String error = "value for 'radiusAdjustment' attribute in featureRange element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (height < 0.0f) {
+                        String error = "value for 'radiusAdjustment' attribute in featureRange element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentFeatureRange.setRadiusAdjustment(height);
+                }
+                //decoration
+                if (elem.attributes.getValue("decoration") != null) {
+
+                    if (DECORATIONS.get(((elem.attributes.getValue("decoration"))).toLowerCase()) != null) {
+                        currentFeatureRange.setDecoration(((Integer) DECORATIONS.get(((elem.attributes.getValue("decoration"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'decoration' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+                //showLabel
+                if (elem.attributes.getValue("showLabel") != null) {
+                    if (LABEL_TYPES.get(((elem.attributes.getValue("showLabel"))).toLowerCase()) != null) {
+                        currentFeatureRange.setShowLabel(((Integer) LABEL_TYPES.get(((elem.attributes.getValue("showLabel"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'showLabel' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+                //font
+                if (elem.attributes.getValue("font") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("font"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentFeatureRange.setFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'font' attribute in featureRange element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'font' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+                //label
+                if (elem.attributes.getValue("label") != null) {
+                    currentFeatureRange.setLabel(elem.attributes.getValue("label"));
+                }
+                //showShading
+                if (elem.attributes.getValue("showShading") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase()) != null) {
+                        currentFeatureRange.setShowShading(((Boolean) BOOLEANS.get(((elem.attributes.getValue("showShading"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'showShading' attribute in featureRange element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+                //hyperlink
+                if (elem.attributes.getValue("hyperlink") != null) {
+                    currentFeatureRange.setHyperlink(elem.attributes.getValue("hyperlink"));
+                }
+                //mouseover
+                if (elem.attributes.getValue("mouseover") != null) {
+                    currentFeatureRange.setMouseover(elem.attributes.getValue("mouseover"));
+                }
+
+		if (this.labelFontSize != -1) {
+		    if (currentFeatureRange.getFont() != null) {
+			currentFeatureRange.setFont(new Font(currentFeatureRange.getFont().getName(), currentFeatureRange.getFont().getStyle(), this.labelFontSize));
+		    }
+		    else if (currentFeature.getFont() != null) {
+			currentFeatureRange.setFont(new Font(currentFeature.getFont().getName(), currentFeature.getFont().getStyle(), this.labelFontSize));
+		    }
+		    else {
+			currentFeatureRange.setFont(new Font(currentCgview.getLabelFont().getName(), currentCgview.getLabelFont().getStyle(), this.labelFontSize));
+		    }
+		}
+            }
+        }
+    }
+
+    /**
+     * Handles the legend element and its attributes.
+     *
+     * @throws SAXException
+     */
+    //required attributes: none.
+    //optional attributes: font, fontColor, position, drawWhenZoomed, textAlignment, backgroundColor, backgroundOpacity, allowLabelClash.
+    private void handleLegend() throws SAXException {
+
+        for (int p = context.size() - 1; p >= 0; p--) {
+            ElementDetails elem = (ElementDetails) context.elementAt(p);
+            if (elem.name.equalsIgnoreCase("legend")) {
+                if (currentLegend != null) {
+                    //an error because already in a legend tag
+                    String error = "legend element encountered inside of another legend element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentCgview == null) {
+                    //an error because no currentCgview
+                    String error = "legend element encountered outside of a cgview element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                }
+
+                currentLegend = new Legend(currentCgview);
+
+                //optional tags
+                //fontColor
+                if (elem.attributes.getValue("fontColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("fontColor"))).toLowerCase()) != null) {
+                        currentLegend.setFontColor((Color) COLORS.get(((elem.attributes.getValue("fontColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("fontColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentLegend.setFontColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'fontColor' attribute in legend element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'fontColor' attribute in legend element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //font
+                if (elem.attributes.getValue("font") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("font"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentLegend.setFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'font' attribute in legend element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'font' attribute in legend element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+
+                //position
+                if (elem.attributes.getValue("position") != null) {
+                    if (LEGEND_POSITIONS.get(((elem.attributes.getValue("position"))).toLowerCase()) != null) {
+                        currentLegend.setPosition(((Integer) LEGEND_POSITIONS.get(((elem.attributes.getValue("position"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'position' attribute in legend element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //textAlignment
+                if (elem.attributes.getValue("textAlignment") != null) {
+                    if (LEGEND_ALIGNMENTS.get(((elem.attributes.getValue("textAlignment"))).toLowerCase()) != null) {
+                        currentLegend.setAlignment(((Integer) LEGEND_ALIGNMENTS.get(((elem.attributes.getValue("textAlignment"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'textAlignment' attribute in legend element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //drawWhenZoomed
+                if (elem.attributes.getValue("drawWhenZoomed") != null) {
+                    if (LEGEND_SHOW_ZOOM.get(((elem.attributes.getValue("drawWhenZoomed"))).toLowerCase()) != null) {
+                        currentLegend.setPosition(((Integer) LEGEND_POSITIONS.get(((elem.attributes.getValue("drawWhenZoomed"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'drawWhenZoomed' attribute in legend element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //backgroundOpacity
+                if (elem.attributes.getValue("backgroundOpacity") != null) {
+                    float opacity;
+                    try {
+                        opacity = Float.parseFloat(elem.attributes.getValue("backgroundOpacity"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'backgroundOpacity' attribute in legend element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity > 1.0f) {
+                        String error = "value for 'backgroundOpacity' attribute in legend element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity < 0.0f) {
+                        String error = "value for 'backgroundOpacity' attribute in legend element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentLegend.setBackgroundOpacity(opacity);
+                }
+
+                //backgroundColor
+                if (elem.attributes.getValue("backgroundColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("backgroundColor"))).toLowerCase()) != null) {
+                        currentLegend.setBackgroundColor((Color) COLORS.get(((elem.attributes.getValue("backgroundColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("backgroundColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentLegend.setBackgroundColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'backgroundColor' attribute in legend element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'backgroundColor' attribute in legend element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //allowLabelClash
+                if (elem.attributes.getValue("allowLabelClash") != null) {
+                    if (BOOLEANS.get(((elem.attributes.getValue("allowLabelClash"))).toLowerCase()) != null) {
+                        currentLegend.setAllowLabelClash(((Boolean) BOOLEANS.get(((elem.attributes.getValue("allowLabelClash"))).toLowerCase())).booleanValue());
+                    } else {
+                        String error = "value for 'allowLabelClash' attribute in legend element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+		if (this.legendFontSize != -1) {
+		    if (currentLegend.getFont() != null) {
+			currentLegend.setFont(new Font(currentLegend.getFont().getName(), currentLegend.getFont().getStyle(), this.legendFontSize));
+		    }
+		    else {
+			currentLegend.setFont(new Font(currentCgview.getLegendFont().getName(), currentCgview.getLegendFont().getStyle(), this.legendFontSize));
+		    }
+		}
+
+            }
+        }
+    }
+
+    /**
+     * Handles the legendItem element and its attributes.
+     *
+     * @throws SAXException
+     */
+    //required attributes: text.
+    //optional attributes: fontColor, swatchOpacity, drawSwatch, swatchColor, font, textAlignment.
+    private void handleLegendItem() throws SAXException {
+
+        for (int p = context.size() - 1; p >= 0; p--) {
+            ElementDetails elem = (ElementDetails) context.elementAt(p);
+            if (elem.name.equalsIgnoreCase("legendItem")) {
+                if (currentLegend == null) {
+                    //an error because no current legend
+                    String error = "legendItem element encountered inside of legend element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentCgview == null) {
+                    //an error because no currentCgview
+                    String error = "legendItem element encountered outside of a cgview element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (currentLegendItem != null) {
+                    //an error because already inside legendItem tag
+                    String error = "legendItem element encountered inside of another legendItem element";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                } else if (elem.attributes.getValue("text") == null) {
+                    //an error because no length
+                    String error = "legendItem element is missing 'text' attribute";
+                    if (locator != null) {
+                        error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                    }
+                    throw new SAXException(error);
+                }
+
+                currentLegendItem = new LegendItem(currentLegend);
+
+                currentLegendItem.setLabel(elem.attributes.getValue("text"));
+
+                //optional tags
+                //swatchOpacity
+                if (elem.attributes.getValue("swatchOpacity") != null) {
+                    float opacity;
+                    try {
+                        opacity = Float.parseFloat(elem.attributes.getValue("swatchOpacity"));
+                    } catch (NumberFormatException nfe) {
+                        String error = "value for 'swatchOpacity' attribute in legendItem element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity > 1.0f) {
+                        String error = "value for 'swatchOpacity' attribute in legendItem element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    if (opacity < 0.0f) {
+                        String error = "value for 'swatchOpacity' attribute in legendItem element must be between 0 and 1";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        throw new SAXException(error);
+                    }
+
+                    currentLegendItem.setSwatchOpacity(opacity);
+                }
+                //fontColor
+                if (elem.attributes.getValue("fontColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("fontColor"))).toLowerCase()) != null) {
+                        currentLegendItem.setFontColor((Color) COLORS.get(((elem.attributes.getValue("fontColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("fontColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentLegendItem.setFontColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'fontColor' attribute in legendItem element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'fontColor' attribute in legendItem element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //swatchColor
+                if (elem.attributes.getValue("swatchColor") != null) {
+                    if (COLORS.get(((elem.attributes.getValue("swatchColor"))).toLowerCase()) != null) {
+                        currentLegendItem.setSwatchColor((Color) COLORS.get(((elem.attributes.getValue("swatchColor"))).toLowerCase()));
+                    } else {
+                        m = colorDescriptionPattern.matcher(elem.attributes.getValue("swatchColor"));
+                        if (m.find()) {
+                            try {
+
+                                int r = Integer.parseInt(m.group(1));
+                                int g = Integer.parseInt(m.group(2));
+                                int b = Integer.parseInt(m.group(3));
+
+                                currentLegendItem.setSwatchColor(new Color(r, g, b));
+
+                            } catch (Exception e) {
+                                String error = "value for 'swatchColor' attribute in legendItem element not understood";
+                                if (locator != null) {
+                                    error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                                }
+                                //throw new SAXException (error);
+                                System.err.println("[warning] " + error);
+                            }
+                        } else {
+                            String error = "value for 'swatchColor' attribute in legendItem element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    }
+                }
+
+                //drawSwatch
+                if (elem.attributes.getValue("drawSwatch") != null) {
+                    if (SWATCH_TYPES.get(((elem.attributes.getValue("drawSwatch"))).toLowerCase()) != null) {
+                        currentLegendItem.setDrawSwatch(((Integer) SWATCH_TYPES.get(((elem.attributes.getValue("drawSwatch"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'drawSwatch' attribute in legendItem element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //textAlignment
+                if (elem.attributes.getValue("textAlignment") != null) {
+                    if (LEGEND_ALIGNMENTS.get(((elem.attributes.getValue("textAlignment"))).toLowerCase()) != null) {
+                        currentLegendItem.setTextAlignment(((Integer) LEGEND_ALIGNMENTS.get(((elem.attributes.getValue("textAlignment"))).toLowerCase())).intValue());
+                    } else {
+                        String error = "value for 'textAlignment' attribute in legendItem element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+                }
+
+                //font
+                if (elem.attributes.getValue("font") != null) {
+
+                    m = fontDescriptionPattern.matcher(elem.attributes.getValue("font"));
+                    if (m.find()) {
+                        try {
+
+                            String name = m.group(1);
+                            String style = m.group(2);
+                            int size = Integer.parseInt(m.group(3));
+                            int intStyle = Font.PLAIN;
+
+                            if (style.equalsIgnoreCase("bold")) {
+                                intStyle = Font.BOLD;
+                            } else if ((style.equalsIgnoreCase("italic")) || (style.equalsIgnoreCase("italics"))) {
+                                intStyle = Font.ITALIC;
+                            } else if ((style.equalsIgnoreCase("bold-italic")) || (style.equalsIgnoreCase("italic-bold"))) {
+                                intStyle = Font.ITALIC + Font.BOLD;
+                            }
+                            currentLegendItem.setFont(new Font(name, intStyle, size));
+
+                        } catch (Exception e) {
+                            String error = "value for 'font' attribute in legendItem element not understood";
+                            if (locator != null) {
+                                error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                            }
+                            //throw new SAXException (error);
+                            System.err.println("[warning] " + error);
+                        }
+                    } else {
+                        String error = "value for 'font' attribute in legendItem element not understood";
+                        if (locator != null) {
+                            error = error + " in " + locator.getSystemId() + " at line " + locator.getLineNumber() + " column " + locator.getColumnNumber();
+                        }
+                        //throw new SAXException (error);
+                        System.err.println("[warning] " + error);
+                    }
+
+                }
+
+		if (this.legendFontSize != -1) {
+		    if (currentLegendItem.getFont() != null) {
+			currentLegendItem.setFont(new Font(currentLegendItem.getFont().getName(), currentLegendItem.getFont().getStyle(), this.legendFontSize));
+		    }
+		    else if (currentLegend.getFont() != null) {
+			currentLegendItem.setFont(new Font(currentLegend.getFont().getName(), currentLegend.getFont().getStyle(), this.legendFontSize));
+		    }
+		    else {
+			currentLegendItem.setFont(new Font(currentCgview.getLegendFont().getName(), currentCgview.getLegendFont().getStyle(), this.legendFontSize));
+		    }
+
+		}
+
+            }
+        }
+    }
+
+    private class ElementDetails {
+
+        public String name;
+        public Attributes attributes;
+
+        public ElementDetails(String name, Attributes atts) {
+            this.name = name;
+            this.attributes = new AttributesImpl(atts);
+        }
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryPtt.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryPtt.class
new file mode 100644
index 0000000..e42f55a
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryPtt.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryPtt.java b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryPtt.java
new file mode 100644
index 0000000..53dceb0
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryPtt.java
@@ -0,0 +1,1534 @@
+package ca.ualberta.stothard.cgview;
+
+
+import java.io.*;
+import java.awt.*;
+import java.util.*;
+import java.lang.Integer;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.ArrayList;
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import java.text.NumberFormat;
+import java.util.regex.*;
+
+/**
+ * This class reads a tab delimited feature file and creates a Cgview object.
+ *
+ * @author Paul Stothard
+ */
+
+public class CgviewFactoryPtt implements CgviewConstants {
+
+    private Cgview cgview;
+
+    private Hashtable COLORS = new Hashtable();
+    private Hashtable MAP_ITEM_COLORS = new Hashtable();
+    private Hashtable FEATURE_COLORS = new Hashtable();
+    private Hashtable FEATURE_DECORATIONS_DIRECT = new Hashtable();
+    private Hashtable FEATURE_DECORATIONS_REVERSE = new Hashtable();
+    private Hashtable LEGEND_ITEM_NAMES_LONG = new Hashtable();
+    private Hashtable LEGEND_ITEM_NAMES_SHORT = new Hashtable();
+    private Hashtable DRAW_LEGEND_ITEMS = new Hashtable();
+
+    private Hashtable DEFAULT_MAP_SIZES = new Hashtable();
+    private Hashtable MIN_MAP_SIZES = new Hashtable();
+    private Hashtable MAX_MAP_SIZES = new Hashtable();
+
+    private Hashtable DEFAULT_MAP_MODES = new Hashtable();
+    private Hashtable SMALL_MAP_MODES = new Hashtable();
+    private Hashtable LARGE_MAP_MODES = new Hashtable();
+
+    private int LARGE_MAP_MODE_DIMENSION = 2000;
+    private int SMALL_MAP_MODE_DIMENSION = 800;
+
+    private FeatureSlot forwardSlot1;
+    private FeatureSlot forwardSlot2;
+    private FeatureSlot forwardSlot3;
+    private FeatureSlot forwardSlot4;
+    private FeatureSlot forwardSlot5;
+    private FeatureSlot forwardSlot6;
+
+    private FeatureSlot reverseSlot1;
+    private FeatureSlot reverseSlot2;
+    private FeatureSlot reverseSlot3;
+    private FeatureSlot reverseSlot4;
+    private FeatureSlot reverseSlot5;
+    private FeatureSlot reverseSlot6;
+
+    private Legend legend;
+
+    private int zoomCenter = 1;
+    private int length = 0;
+    private String title = "";
+
+    private int mapWidth = 900;
+    private int mapHeight = 600;
+    private int mapSmallest = 0;
+
+    private float mapItemSizeAdjustment = 0.0f;
+
+
+    private int labelFontSize = -1;
+    private int rulerFontSize = -1;
+    private int legendFontSize = -1;
+
+    private double tickDensity = 1.0d;
+
+    private boolean readDimension = true;
+
+    private NumberFormat nf = NumberFormat.getInstance();
+
+    private int MAX_MOUSEOVER_LENGTH = 100;
+    private int MAX_LABEL_LENGTH = 50;
+    private int MAX_TITLE_LENGTH = 80;
+    private int MAX_SEQUENCE_LENGTH = 20000000;
+
+    private int MAX_IMAGE_WIDTH;
+    private int MIN_IMAGE_WIDTH;
+
+    private int MAX_IMAGE_HEIGHT;
+    private int MIN_IMAGE_HEIGHT;
+
+    private float opacity = 1.0f;
+    private boolean useColoredLabelBackground = false;
+    private boolean showTitle = true;
+    private boolean showShading = true;
+    private boolean showBorder = false;
+    private boolean allowLabelClashLegend = false;
+    private boolean moveInnerLabelsToOuter = true;
+    private int labelPlacementQuality = 9;
+    private int legendPosition = LEGEND_UPPER_RIGHT;
+    private boolean useColoredLabels = true;
+    private boolean drawTickMarks = true;
+    private boolean showLegend = true;
+    private boolean showLabels = true;
+    private float shadingProportion = 0.4f;
+    private float shadingOpacity = 0.5f;
+
+    private boolean containsCogs = false;
+
+    private String ncbiLink = "http://www.ncbi.nlm.nih.gov/entrez/query.fcgi?cmd=Text&db=Protein&dopt=genpept&dispmax=20&uid=";
+
+    /**
+     * Constructs a new CgviewFactoryPtt object.
+     */
+    public CgviewFactoryPtt() {
+	cgview = new Cgview(1);
+    }
+
+    /**
+     * Generates a Cgview object from an tab delimited feature file.
+     *
+     * @param filename the file to read.
+     * @return the newly created Cgview object.
+     * @throws Exception
+     * @throws IOException
+     */
+    public Cgview createCgviewFromFile(String filename) throws Exception, IOException {
+	File file = new File(filename);
+	URL url = null;
+	url = file.toURL();
+	return createCgviewFromURL(url);
+    }
+
+    /**
+     * Generates a Cgview object from an tab delimited feature file.
+     *
+     * @param url the URL of the tab delimited file to read.
+     * @return the newly created Cgview object.
+     * @throws Exception
+     * @throws IOException
+     */
+    public Cgview createCgviewFromURL(URL url) throws Exception, IOException {
+
+        COLORS.put("black", new Color(0, 0, 0));
+        COLORS.put("silver", new Color(192, 192, 192));
+        COLORS.put("gray", new Color(128, 128, 128));
+        COLORS.put("white", new Color(255, 255, 255));
+        COLORS.put("maroon", new Color(128, 0, 0));
+        COLORS.put("red", new Color(255, 0, 0));
+        COLORS.put("pink", new Color(255, 153, 204));
+        COLORS.put("purple", new Color(128, 0, 128));
+        COLORS.put("fuchsia", new Color(255, 0, 255));
+        COLORS.put("orange", new Color(255, 153, 0));
+        COLORS.put("green", new Color(0, 128, 0));
+        COLORS.put("spring", new Color(204, 255, 204));
+        COLORS.put("lime", new Color(0, 255, 0));
+        COLORS.put("olive", new Color(128, 128, 0));
+        COLORS.put("yellow", new Color(255, 255, 0));
+        COLORS.put("navy", new Color(0, 0, 128));
+        COLORS.put("blue", new Color(0, 0, 255));
+        COLORS.put("azure", new Color(51, 153, 255));
+        COLORS.put("lightBlue", new Color(102, 204, 255));
+        COLORS.put("teal", new Color(153, 255, 204));
+        COLORS.put("aqua", new Color(0, 255, 255));
+
+        MAP_ITEM_COLORS.put("tick", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("rulerFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("titleFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("messageFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("backbone", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("partialTick", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("zeroLine", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("background", COLORS.get("white"));
+
+        FEATURE_COLORS.put("forward_gene", new Color(249,0,0));
+        FEATURE_COLORS.put("reverse_gene", new Color(19,19,255));
+        FEATURE_COLORS.put("J", new Color(152,0,0));
+        FEATURE_COLORS.put("K", new Color(255,175,100));
+        FEATURE_COLORS.put("L", new Color(245,222,188));
+        FEATURE_COLORS.put("D", new Color(51,255,153));
+        FEATURE_COLORS.put("O", new Color(150,199,35));
+        FEATURE_COLORS.put("M", new Color(240,245,60));
+	FEATURE_COLORS.put("N", new Color(62,217,157));
+        FEATURE_COLORS.put("P", new Color(185,255,134));
+        FEATURE_COLORS.put("T", new Color(0,128,0));
+        FEATURE_COLORS.put("C", new Color(185,74,125));	
+        FEATURE_COLORS.put("G", new Color(152,26,206));
+        FEATURE_COLORS.put("E", new Color(255,79,255));
+        FEATURE_COLORS.put("F", new Color(255,204,204));
+        FEATURE_COLORS.put("H", new Color(179,225,234));	
+        FEATURE_COLORS.put("I", new Color(100,255,250));
+        FEATURE_COLORS.put("Q", new Color(0,0,139));
+        FEATURE_COLORS.put("R", new Color(179,179,179));
+        FEATURE_COLORS.put("S", new Color(240,240,240));
+        FEATURE_COLORS.put("no_cog", new Color(96,96,96));
+
+        FEATURE_DECORATIONS_DIRECT.put("forward_gene", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("J", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("K", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("L", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("D", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("O", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("M", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("N", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("P", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("T", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("C", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("G", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("E", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("F", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("H", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("I", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("Q", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("R", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("S", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("no_cog", new Integer(DECORATION_STANDARD));
+
+        FEATURE_DECORATIONS_REVERSE.put("reverse_gene", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("J", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("K", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("L", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("D", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("O", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("M", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("N", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("P", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("T", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("C", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("G", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("E", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("F", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("H", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("I", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("Q", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("R", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("S", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("no_cog", new Integer(DECORATION_STANDARD));
+
+        LEGEND_ITEM_NAMES_LONG.put("forward_gene", "Forward strand gene");
+        LEGEND_ITEM_NAMES_LONG.put("reverse_gene", "Reverse strand gene");
+        LEGEND_ITEM_NAMES_LONG.put("J", "Translation, ribosomal structure and biogenesis");
+        LEGEND_ITEM_NAMES_LONG.put("K", "Transcription");
+        LEGEND_ITEM_NAMES_LONG.put("L", "DNA replication, recombination and repair");
+        LEGEND_ITEM_NAMES_LONG.put("D", "Cell division and chromosome partitioning");
+        LEGEND_ITEM_NAMES_LONG.put("O", "Posttranslational modification, protein turnover, chaperones");
+        LEGEND_ITEM_NAMES_LONG.put("M", "Cell envelope biogenesis, outer membrane");
+        LEGEND_ITEM_NAMES_LONG.put("N", "Cell motility and secretion");
+        LEGEND_ITEM_NAMES_LONG.put("P", "Inorganic ion transport and metabolism");
+        LEGEND_ITEM_NAMES_LONG.put("T", "Signal transduction mechanisms");
+        LEGEND_ITEM_NAMES_LONG.put("C", "Energy production and conversion");
+        LEGEND_ITEM_NAMES_LONG.put("G", "Carbohydrate transport and metabolism");
+        LEGEND_ITEM_NAMES_LONG.put("E", "Amino acid transport and metabolism");
+        LEGEND_ITEM_NAMES_LONG.put("F", "Nucleotide transport and metabolism");
+        LEGEND_ITEM_NAMES_LONG.put("H", "Coenzyme metabolism");
+        LEGEND_ITEM_NAMES_LONG.put("I", "Lipid metabolism");
+        LEGEND_ITEM_NAMES_LONG.put("Q", "Secondary metabolites biosynthesis, transport and catabolism");
+        LEGEND_ITEM_NAMES_LONG.put("R", "General function prediction only");
+        LEGEND_ITEM_NAMES_LONG.put("S", "Function unknown");
+        LEGEND_ITEM_NAMES_LONG.put("no_cog", "No COG information");
+
+        LEGEND_ITEM_NAMES_SHORT.put("forward_gene", "Forward");
+        LEGEND_ITEM_NAMES_SHORT.put("reverse_gene", "Reverse");
+        LEGEND_ITEM_NAMES_SHORT.put("J", "COG J");
+        LEGEND_ITEM_NAMES_SHORT.put("K", "COG K");
+        LEGEND_ITEM_NAMES_SHORT.put("L", "COG L");
+        LEGEND_ITEM_NAMES_SHORT.put("D", "COG D");
+        LEGEND_ITEM_NAMES_SHORT.put("O", "COG O");
+        LEGEND_ITEM_NAMES_SHORT.put("M", "COG M");
+        LEGEND_ITEM_NAMES_SHORT.put("N", "COG N");
+        LEGEND_ITEM_NAMES_SHORT.put("P", "COG P");
+        LEGEND_ITEM_NAMES_SHORT.put("T", "COG T");
+        LEGEND_ITEM_NAMES_SHORT.put("C", "COG C");
+        LEGEND_ITEM_NAMES_SHORT.put("G", "COG G");
+        LEGEND_ITEM_NAMES_SHORT.put("E", "COG E");
+        LEGEND_ITEM_NAMES_SHORT.put("F", "COG F");
+        LEGEND_ITEM_NAMES_SHORT.put("H", "COG H");
+        LEGEND_ITEM_NAMES_SHORT.put("I", "COG I");
+        LEGEND_ITEM_NAMES_SHORT.put("Q", "COG Q");
+        LEGEND_ITEM_NAMES_SHORT.put("R", "COG R");
+        LEGEND_ITEM_NAMES_SHORT.put("S", "COG S");
+        LEGEND_ITEM_NAMES_SHORT.put("no_cog", "No COG");
+   
+        DEFAULT_MAP_SIZES.put("mapWidth", new Integer(900));
+        DEFAULT_MAP_SIZES.put("mapHeight", new Integer(900));
+        DEFAULT_MAP_SIZES.put("labelFontSize", new Integer(10));
+        DEFAULT_MAP_SIZES.put("titleFontSize", new Integer(15));
+        DEFAULT_MAP_SIZES.put("legendFontSize", new Integer(13));
+        DEFAULT_MAP_SIZES.put("rulerFontSize", new Integer(8));
+        DEFAULT_MAP_SIZES.put("messageFontSize", new Integer(12));
+        DEFAULT_MAP_SIZES.put("featureThickness", new Float(12.0f));
+        DEFAULT_MAP_SIZES.put("backboneThickness", new Float(4.0f));
+        DEFAULT_MAP_SIZES.put("featureSlotSpacing", new Float(2.0f));
+        DEFAULT_MAP_SIZES.put("tickLength", new Float(6.0f));
+        DEFAULT_MAP_SIZES.put("tickThickness", new Float(2.0f));
+        DEFAULT_MAP_SIZES.put("shortTickThickness", new Float(2.0f));
+        DEFAULT_MAP_SIZES.put("labelLineLength", new Double(50.0d));
+        DEFAULT_MAP_SIZES.put("labelLineThickness", new Float(1.0f));
+        DEFAULT_MAP_SIZES.put("arrowheadLength", new Double(5.0d));
+        DEFAULT_MAP_SIZES.put("maxLabels", new Integer(5000));
+
+        MIN_MAP_SIZES.put("mapWidth", new Integer(500));
+        MIN_MAP_SIZES.put("mapHeight", new Integer(500));
+        MIN_MAP_SIZES.put("labelFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("titleFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("legendFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("rulerFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("messageFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("featureThickness", new Float(0.5f));
+        MIN_MAP_SIZES.put("backboneThickness", new Float(0.1f));
+        MIN_MAP_SIZES.put("featureSlotSpacing", new Float(0.1f));
+        MIN_MAP_SIZES.put("tickLength", new Float(1.0f));
+        MIN_MAP_SIZES.put("tickThickness", new Float(0.5f));
+        MIN_MAP_SIZES.put("shortTickThickness", new Float(0.5));
+        MIN_MAP_SIZES.put("labelLineLength", new Double(2.0f));
+        MIN_MAP_SIZES.put("labelLineThickness", new Float(0.5));
+        MIN_MAP_SIZES.put("arrowheadLength", new Double(0.5d));
+        MIN_MAP_SIZES.put("maxLabels", new Integer(10));
+
+        MAX_MAP_SIZES.put("mapWidth", new Integer(30000));
+        MAX_MAP_SIZES.put("mapHeight", new Integer(30000));
+        MAX_MAP_SIZES.put("labelFontSize", new Integer(10));
+        MAX_MAP_SIZES.put("titleFontSize", new Integer(100));
+        MAX_MAP_SIZES.put("legendFontSize", new Integer(100));
+        MAX_MAP_SIZES.put("rulerFontSize", new Integer(8));
+        MAX_MAP_SIZES.put("messageFontSize", new Integer(100));
+        MAX_MAP_SIZES.put("featureThickness", new Float(80.0f));
+        MAX_MAP_SIZES.put("backboneThickness", new Float(5.0f));
+        MAX_MAP_SIZES.put("featureSlotSpacing", new Float(5.0f));
+        MAX_MAP_SIZES.put("tickLength", new Float(6.0f));
+        MAX_MAP_SIZES.put("tickThickness", new Float(2.0f));
+        MAX_MAP_SIZES.put("shortTickThickness", new Float(2.0f));
+        MAX_MAP_SIZES.put("labelLineLength", new Double(80.0f));
+        MAX_MAP_SIZES.put("labelLineThickness", new Float(1.0f));
+        MAX_MAP_SIZES.put("arrowheadLength", new Double(18.0d));
+        MAX_MAP_SIZES.put("maxLabels", new Integer(50000));
+
+	DEFAULT_MAP_MODES.put("giveFeaturePositions", new Integer(POSITIONS_NO_SHOW));
+	DEFAULT_MAP_MODES.put("useInnerLabels", new Integer(INNER_LABELS_AUTO));
+
+	SMALL_MAP_MODES.put("giveFeaturePositions", new Integer(POSITIONS_NO_SHOW));
+	SMALL_MAP_MODES.put("useInnerLabels", new Integer(INNER_LABELS_AUTO));
+
+	LARGE_MAP_MODES.put("giveFeaturePositions", new Integer(POSITIONS_NO_SHOW));
+	LARGE_MAP_MODES.put("useInnerLabels", new Integer(INNER_LABELS_SHOW));	
+
+	MAX_IMAGE_WIDTH = ((Integer)MAX_MAP_SIZES.get("mapWidth")).intValue();
+	MIN_IMAGE_WIDTH = ((Integer)MIN_MAP_SIZES.get("mapWidth")).intValue();
+
+	MAX_IMAGE_HEIGHT = ((Integer)MAX_MAP_SIZES.get("mapHeight")).intValue();
+	MIN_IMAGE_HEIGHT = ((Integer)MIN_MAP_SIZES.get("mapHeight")).intValue();
+
+	InputStream in;
+	BufferedReader buf;
+	int lineCount = 0;
+	String line;
+	String lineItems[];
+
+	int columnNumber = 0;
+
+	//intermediate values
+	String location;
+	String strand;
+	String length;
+	String pid;
+	String gene;
+	String synonym;
+	String code;
+	String cog;
+	String product;
+
+	String strandB;
+	int slot = 0; 
+	int start = 0; 
+	int stop = 0; 
+	float opacity = 1.0f;
+	float thickness = 1.0f;
+	float radius = 0.0f;
+	String type = "";
+	String label = "";
+	String mouseover = "";
+	String hyperlink = "";
+
+	boolean hasLocationColumn = false;
+	boolean hasStrandColumn = false;
+	boolean hasLengthColumn = false;
+	boolean hasPIDColumn = false;
+	boolean hasGeneColumn = false;
+	boolean hasSynonymColumn = false;
+	boolean hasCodeColumn = false;
+	boolean hasCOGColumn = false;
+	boolean hasProductColumn = false;
+
+	int locationColumnIndex = -1;
+	int strandColumnIndex = -1;
+	int lengthColumnIndex = -1;
+	int pidColumnIndex = -1;
+	int geneColumnIndex = -1;
+	int synonymColumnIndex = -1;
+	int codeColumnIndex = -1;
+	int cogColumnIndex = -1;
+	int productColumnIndex = -1;
+	
+	//pattern to find line with length value
+        Pattern pLength = Pattern.compile("[01]\\.\\.(\\d+)\\s*$");
+        Matcher m;
+
+	//pattern to find column names
+	Pattern pColumn = Pattern.compile("Location\\s*\\t+\\s*Strand");
+
+	//pattern to find start and stop
+	Pattern pStart = Pattern.compile("(\\d+)\\.\\.(\\d+)");
+	
+		
+	in = url.openStream();
+
+        System.out.println("Parsing ptt input.");
+
+	buf = new BufferedReader(new InputStreamReader(in));
+	while((line = buf.readLine()) != null) {
+	    lineCount++;
+	    //System.out.println ("doing line " + line);
+	    //try to read length and title from first few lines of ptt file.
+	    //usually first line, sometimes second line or third line
+	    //usually looks something like:
+	    //Acinetobacter sp. ADP1, complete geneome - 0..3598621
+
+	    //look for title and DNA length
+	    if (lineCount <= 5) {
+		m = pLength.matcher(line);
+		if (m.find()) {
+		    title = line;
+		    try {
+			this.length = Integer.parseInt(m.group(1));
+		    }
+		    catch (Exception e) {
+			throw new Exception("There is a problem with the length value on line " + lineCount + " in the data file.");
+		    }
+		    
+		    
+		}
+	    }
+
+	    //look for column names
+	    if ((lineCount <= 8) && (!hasLocationColumn)) {
+		m = pColumn.matcher(line);
+		if (m.find()) {
+      		    lineItems = line.split("(?:\\s*\\t+\\s*)|(?:\\s{2,})");
+		    //lineItems = line.split("\\s*\\t+\\s*");
+		    columnNumber = lineItems.length;
+		    for (int i = 0; i < lineItems.length; i = i + 1) {
+			String lineItem = lineItems[i].trim();
+			if (lineItem.equalsIgnoreCase("Location")) {
+			    hasLocationColumn = true;
+			    locationColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("Strand")) {
+			    hasStrandColumn = true;
+			    strandColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("Length")) {
+			    hasLengthColumn = true;
+			    lengthColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("PID")) {
+			    hasPIDColumn = true;
+			    pidColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("Gene")) {
+			    hasGeneColumn = true;
+			    geneColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("Synonym")) {
+			    hasSynonymColumn = true;
+			    synonymColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("Code")) {
+			    hasCodeColumn = true;
+			    codeColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("COG")) {
+			    hasCOGColumn = true;
+			    cogColumnIndex = i;
+			}
+			else if (lineItem.equalsIgnoreCase("Product")) {
+			    hasProductColumn = true;
+			    productColumnIndex = i;
+			}
+		    }
+		}
+		continue;
+	    }
+
+	    if (columnNumber > 0) {
+		//some text editors may use spaces instead of tabs.
+		//try to handle this.
+		lineItems = line.split("\\s*\\t+\\s*");
+		if (lineItems.length != columnNumber) {
+		    lineItems = line.split("(?:\\s*\\t+\\s*)|(?:\\s{2,})");
+		}
+
+		if (lineItems.length >= 5) {
+
+		    if (hasLocationColumn == false) {
+			throw new Exception("A \"Location\" column has not been defined in the data file.");			
+		    }
+		    if (hasStrandColumn == false) {
+			throw new Exception("A \"Strand\" column has not been defined in the data file.");			
+		    }
+		    if (hasPIDColumn == false) {
+			throw new Exception("A \"PID\" column has not been defined in the data file.");			
+		    }
+
+		    //location
+		    try {
+			location = lineItems[locationColumnIndex];
+			location = location.trim();
+		    }
+		    catch (Exception e) {
+			continue;
+			//throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    //strand	    
+		    try {
+			strand = lineItems[strandColumnIndex];
+			strand = strand.trim();
+		    }
+		    catch (Exception e) {
+			continue;
+			//throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    //pid
+		    try {
+			pid = lineItems[pidColumnIndex];
+			pid = pid.trim();
+		    }
+		    catch (Exception e) {
+			continue;
+			//throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    //length
+		    if (hasLengthColumn) {
+			try {
+			    length = lineItems[lengthColumnIndex];
+			    length = length.trim();
+			}
+			catch (Exception e) {
+			    continue;
+			    //throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			length = "";
+		    }
+
+		    //gene
+		    if (hasGeneColumn) {
+			try {
+			    gene = lineItems[geneColumnIndex];
+			    gene = gene.trim();
+			}
+			catch (Exception e) {
+			    continue;
+			    //throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			gene = "";
+		    }
+
+		    //synonym
+		    if (hasSynonymColumn) {		    
+			try {
+			    synonym = lineItems[synonymColumnIndex];
+			    synonym = synonym.trim();
+			}
+			catch (Exception e) {
+			    continue;
+			    //throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			synonym = "";
+		    }
+
+		    //code
+		    if (hasCodeColumn) {
+			try {
+			    code = lineItems[codeColumnIndex];
+			    code = code.trim();
+			}
+			catch (Exception e) {
+			    continue;
+			    //throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			code = "";
+		    }
+
+		    //cog
+		    if (hasCOGColumn) {		    
+			try {
+			    cog = lineItems[cogColumnIndex];
+			    cog = cog.trim();
+			}
+			catch (Exception e) {
+			    continue;
+			    //throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			cog = "";
+		    }
+
+		    //product
+		    if (hasProductColumn) {			    
+			try {
+			    product = lineItems[productColumnIndex];
+			    product = product.trim();
+			}
+			catch (Exception e) {
+			    continue;
+			    //throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			product = "";
+		    }
+
+		    //build start and stop
+		    m = pStart.matcher(location);
+		    if (m.find()) {
+			start = Integer.parseInt(m.group(1));
+			stop = Integer.parseInt(m.group(2));
+		    }
+		    else {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+		    
+		    //build slot, strandB,  and type
+		    if (strand.equalsIgnoreCase("+")) {
+			slot = 1;
+			type = "forward_gene";
+			strandB = "forward";
+		    }
+		    else if (strand.equalsIgnoreCase("-")) {
+			slot = 1;
+			type = "reverse_gene";
+			strandB = "reverse";
+		    }
+		    else {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    //build label
+		    if ((!(gene.matches("^\\s*$"))) && (!(gene.equals("-")))) {
+			label = gene;
+		    }
+		    else if ((!(synonym.matches("^\\s*$"))) && (!(synonym.equals("-")))) {
+			label = synonym;
+		    }
+		    else if ((!(pid.matches("^\\s*$"))) && (!(pid.equals("-")))) {
+			label = pid;
+		    }
+
+		    //build mouseover
+		    mouseover = location + ";";
+		    
+		    if ((!(cog.matches("^\\s*$"))) && (!(cog.equals("-")))) {
+			mouseover = mouseover + " " + cog + ";";
+		    }
+
+		    if ((!(code.matches("^\\s*$"))) && (!(code.equals("-")))) {
+			mouseover = mouseover + " (code=" + code + ");";
+		    }
+
+		    if ((!(product.matches("^\\s*$"))) && (!(product.equals("-")))) {
+			mouseover = mouseover + " " + product + ";";
+		    }
+
+		    //build hyperlink
+		    if ((!(pid.matches("^\\s*$"))) && (!(pid.equals("-")))) {
+			hyperlink = ncbiLink + pid;
+		    }		    
+
+		    //add the gene feature
+		    try {
+			addFeature(strandB, slot, start, stop, opacity, thickness, radius, type, label, mouseover, hyperlink);
+		    }
+		    catch (Exception e) {
+			throw new Exception("Line " + lineCount + ": " + e.toString() + ".");
+		    }
+
+		    //create COG feature
+		    if ((!(code.matches("^\\s*$"))) && (!(code.equals("-")))) {
+			slot = 2;
+			label = "";
+			mouseover = "";
+			hyperlink = "";
+			type = code;
+			containsCogs = true;
+			try {
+			    addFeature(strandB, slot, start, stop, opacity, thickness, radius, type, label, mouseover, hyperlink);
+			}
+			catch (Exception e) {
+			    throw new Exception("Line " + lineCount + ": " + e.toString() + ".");
+			}			
+		    }
+		}
+		else if (lineItems.length > 2) {
+		    throw new Exception ("The contents of line " + lineCount + " could not be parsed in the data file.");
+		}
+	    }
+	}
+
+	if (this.length > MAX_SEQUENCE_LENGTH) {
+	    throw new Exception ("Maximum sequence length is " + MAX_SEQUENCE_LENGTH + ".");
+	}
+	else if (this.length < 1) {
+	    throw new Exception ("Minimum sequence length is 1 base.");
+	}
+
+	if (mapWidth > MAX_IMAGE_WIDTH) {
+	    throw new Exception ("Maximum image width is " + MAX_IMAGE_WIDTH + ".");
+	}
+	else if (mapWidth < MIN_IMAGE_WIDTH) {
+	    throw new Exception ("Minimum image width is " + MIN_IMAGE_WIDTH + ".");
+	}
+
+	if (mapHeight > MAX_IMAGE_HEIGHT) {
+	    throw new Exception ("Maximum image height is " + MAX_IMAGE_HEIGHT + ".");
+	}
+	else if (mapHeight < MIN_IMAGE_HEIGHT) {
+	    throw new Exception ("Minimum image height is " + MIN_IMAGE_HEIGHT + ".");
+	}
+
+	prepareToDraw();
+        return cgview;
+    }
+
+    /**
+     * Add a feature to this map. Note that the start of the feature should be a smaller number than the stop of the
+     * feature, regardless of the strand. The only case where start is larger than the stop is when the feature runs
+     * across the start/stop boundary, for example 6899-10 on a 7000bp plasmid.
+     *
+     * @param strand    one of the following: forward, reverse.
+     * @param slot      one of the following: 1, 2, 3, 4, 5, 6.
+     * @param start     the start position of the feature. Must be between 1 and the length of the plasmid.
+     * @param stop      the end position of the feature. Must be between 1 and the length of the plasmid.
+     * @param opacity   the opacity of the feature.
+     * @param thickness the thickness of the feature.
+     * @param radius    the radius of the feature.
+     * @param type      one of the following: origin_of_replication, promoter, terminator, regulatory_sequence, 
+     *                  unique_restriction_site, restriction_site, open_reading_frame, gene, predicted_gene, 
+     *                  sequence_similarity, score, primer.
+     * @param label     the label to show or empty String.
+     * @param mouseover the mouseover to show or empty String.
+     * @param hyperlink the label hyperlink or empty String.
+     * @return whether or not the feature was added to the map. If there is a problem the feature is not added.
+     */
+    public void addFeature(String strand, int slot, int start, int stop, float opacity, float thickness, float radius, String type, String label, String mouseover, String hyperlink) throws Exception {
+ 
+        int decoration;
+        Color color;
+	int intStrand;
+	String problem;
+
+	//look for feature position problems
+        if (start > length) {
+	    throw new Exception ("The start value " + start + " is greater than the sequence length.");
+        }
+        if (start < 1) {
+	    throw new Exception ("The start value " + start + " is less than 1.");
+        }
+
+        if (stop > length) {
+	    throw new Exception ("The stop value " + stop + " is greater than the sequence length.");
+        }
+        if (stop < 1) {
+	    throw new Exception ("The stop value " + stop + " is less than 1.");
+        }
+
+	//convert the strand
+	if (strand.equalsIgnoreCase("forward")) {
+	    intStrand = DIRECT_STRAND;
+	}
+	else if (strand.equalsIgnoreCase("reverse")) {
+	    intStrand = REVERSE_STRAND;
+	}
+	else {
+	    throw new Exception ("The strand value must be \"forward\" or \"reverse\".");
+	}
+
+	//obtain the color
+        try {
+            color = getFeatureColor(type);
+        } catch (NullPointerException e) {
+	    System.err.println("Warning: feature type \"" + type + "\" was not recognized. Feature skipped.");
+	    return;
+	    //throw new Exception ("The feature type \"" + type + "\" was not recognized.");
+        }
+
+	//obtain the decoration
+        try {
+            decoration = getFeatureDecoration(type, intStrand);
+        } catch (NullPointerException e) {
+	    System.err.println("Warning: feature type \"" + type + "\" was not recognized. Feature skipped.");
+	    return;
+	    //throw new Exception ("The feature type \"" + type + "\" was not recognized.");
+        }
+
+	//add item to the legend
+        try {
+            addItemToLegend(type);	    
+        } catch (NullPointerException e) {
+	    System.err.println("Warning: feature type \"" + type + "\" was not recognized. Feature skipped.");
+	    return;
+	    //throw new Exception ("The feature type \"" + type + "\" was not recognized.");
+        }
+
+        //create a feature and a feature range
+        //then figure out which feature slot to put the feature in.
+        Feature feature = new Feature(showShading);
+        FeatureRange featureRange = new FeatureRange(feature, start, stop);
+        featureRange.setDecoration(decoration);
+        featureRange.setColor(color);
+
+        featureRange.setOpacity(opacity);
+	featureRange.setProportionOfThickness(thickness);
+	featureRange.setRadiusAdjustment(radius);
+	
+	//if in slot 5 or 6 don't use shading
+	if ((slot == 5) || (slot == 6)) {
+	    feature.setShowShading(false);
+	}
+
+	if (!(label.matches("^\\s*$"))) {
+	    //shorten long label
+	    if (label.length() > MAX_LABEL_LENGTH) {
+		label = label.substring(0, MAX_LABEL_LENGTH) + "...";
+	    }
+	    featureRange.setLabel(label);
+	}
+	
+	if (!(mouseover.matches("^\\s*$"))) {	    
+	    //shorten long mouseover
+	    if (mouseover.length() > MAX_MOUSEOVER_LENGTH) {
+		mouseover = mouseover.substring(0, MAX_MOUSEOVER_LENGTH) + "...";
+	    }
+	    featureRange.setMouseover(mouseover);
+	}
+
+	if (!(hyperlink.matches("^\\s*$"))) {	    
+	    featureRange.setHyperlink(hyperlink);
+	}
+
+	if (intStrand == DIRECT_STRAND) {
+	    if (slot == 1) {
+		if (forwardSlot1 == null) {
+		    forwardSlot1 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot1);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot1);
+		}
+	    }
+	    else if (slot == 2) {
+		if (forwardSlot2 == null) {
+		    forwardSlot2 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot2);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot2);
+		}	   
+	    }
+	    else if (slot == 3) {
+		if (forwardSlot3 == null) {
+		    forwardSlot3 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot3);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot3);
+		}	   
+	    }	
+	    else if (slot == 4) {
+		if (forwardSlot4 == null) {
+		    forwardSlot4 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot4);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot4);
+		}	   
+	    }
+	    else if (slot == 5) {
+		if (forwardSlot5 == null) {
+		    forwardSlot5 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot5);
+
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot5);
+		}	   
+	    }
+	    else if (slot == 6) {
+		if (forwardSlot6 == null) {
+		    forwardSlot6 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot6);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot6);
+		}	   
+	    }
+	    else {
+	        throw new Exception ("The slot value must be between 1 and 6");
+	    }
+        }
+	else {
+	    if (slot == 1) {
+		if (reverseSlot1 == null) {
+		    reverseSlot1 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot1);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot1);
+		}
+	    }
+	    else if (slot == 2) {
+		if (reverseSlot2 == null) {
+		    reverseSlot2 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot2);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot2);
+		}	   
+	    }
+	    else if (slot == 3) {
+		if (reverseSlot3 == null) {
+		    reverseSlot3 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot3);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot3);
+		}	   
+	    }	
+	    else if (slot == 4) {
+		if (reverseSlot4 == null) {
+		    reverseSlot4 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot4);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot4);
+		}	   
+	    }
+	    else if (slot == 5) {
+		if (reverseSlot5 == null) {
+		    reverseSlot5 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot5);
+
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot5);
+		}	   
+	    }
+	    else if (slot == 6) {
+		if (reverseSlot6 == null) {
+		    reverseSlot6 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot6);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot6);
+		}	   
+	    }
+	    else {
+	        throw new Exception ("The slot value must be between 1 and 6");
+	    }
+	}
+    }
+
+    private Color getFeatureColor(String type) throws NullPointerException {
+
+        Color colorToReturn = (Color) FEATURE_COLORS.get(type);
+        return colorToReturn;
+    }
+
+    private int getFeatureDecoration(String type, int strand) throws NullPointerException {
+
+        int decoration = DECORATION_STANDARD;
+ 
+	if (strand == DIRECT_STRAND) {
+	    decoration = ((Integer) FEATURE_DECORATIONS_DIRECT.get(type)).intValue();
+	} else {
+	    decoration = ((Integer) FEATURE_DECORATIONS_REVERSE.get(type)).intValue();
+	}
+
+        return decoration;
+
+    }
+
+    private void addItemToLegend(String type) throws NullPointerException {
+	if (!((type.equalsIgnoreCase("forward_gene")) || (type.equalsIgnoreCase("reverse_gene")))) {
+	    DRAW_LEGEND_ITEMS.put(type, new Boolean(true));
+	}
+    }
+
+    /**
+     * Sets whether or not canvas dimension information should be read from the input file.
+     *
+     * @param readDimension whether or not to read the canvas dimension from the input file.
+     */
+    public void setReadDimension(boolean readDimension) {
+	this.readDimension = readDimension;
+    }
+
+    /**
+     * Sets the width of the map. Use this method before calling createCgviewFromURL() or createCgviewFromFile() to specify the default image width.
+     *
+     * @param width the width of the map.
+     */
+    public void setWidth(int width) {
+	mapWidth = width;
+    }
+
+    /**
+     * Sets the height of the map. Use this method before calling createCgviewFromURL() or createCgviewFromFile() to specify the default image height.
+     *
+     * @param height the height of the map.
+     */
+    public void setHeight(int height) {
+	mapHeight = height;
+    }
+
+    public void setMapItemSizeAdjustment(float adjustment) {
+	mapItemSizeAdjustment = adjustment;
+    }
+
+    /**
+     * Sets the font size of feature labels. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of feature labels.
+     */
+    public void setLabelFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	labelFontSize = size;
+    }
+
+
+
+    /**
+     * Sets the font size of the sequence ruler. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of the sequence ruler.
+     */
+    public void setRulerFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	rulerFontSize = size;
+    }
+
+    /**
+     * Sets the font size of legends. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of legends.
+     */
+    public void setLegendFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	legendFontSize = size;
+    }
+
+    /**
+     * Sets the tick density.
+     *
+     * @param density a double between 0.0 and 1.0, with 1.0 being more dense.
+     */
+    public void setTickDensity(double density) {
+	if (density < 0.0d) {
+	    density = 0.0d;
+	}
+	else if (density > 1.0d) {
+	    density = 1.0d;
+	}
+
+	this.tickDensity = density;
+    }
+
+    private void prepareToDraw() {
+
+
+	Font labelFont;
+	Font titleFont;
+	Font legendFont;
+	Font rulerFont;
+	Font messageFont;
+
+	float featureThickness;
+	float maxFeatureThickness;
+	float backboneThickness;
+	float featureSlotSpacing;
+	float tickLength;
+	float tickThickness;
+	float shortTickThickness;   
+	float labelLineThickness;
+	double labelLineLength;
+	double minimumFeatureLength = 1.0d;
+	double arrowheadLength;
+
+	int giveFeaturePositions;
+	int useInnerLabels;
+	int maxLabels;
+
+	//make changes to the sizes of map items based on the map size
+	//determine size of map compared to default map
+	mapSmallest = Math.min(mapWidth, mapHeight);
+
+	int defaultSmallest = Math.min(((Integer)DEFAULT_MAP_SIZES.get("mapWidth")).intValue(), ((Integer)DEFAULT_MAP_SIZES.get("mapHeight")).intValue());
+
+	float sizeRatio = (float)mapSmallest / (float)defaultSmallest;
+
+	//do fonts
+	int labelFontSize = (int) Math.floor((sizeRatio + mapItemSizeAdjustment)* (float)((Integer)DEFAULT_MAP_SIZES.get("labelFontSize")).intValue() + 0.5f);
+	int titleFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("titleFontSize")).intValue() + 0.5f);
+	int legendFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("legendFontSize")).intValue() + 0.5f);
+	int rulerFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("rulerFontSize")).intValue() + 0.5f);
+	int messageFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("messageFontSize")).intValue() + 0.5f);
+
+	if (labelFontSize < ((Integer)MIN_MAP_SIZES.get("labelFontSize")).intValue()) {
+	    labelFontSize = ((Integer)MIN_MAP_SIZES.get("labelFontSize")).intValue();
+	}
+	else if (labelFontSize > ((Integer)MAX_MAP_SIZES.get("labelFontSize")).intValue()) {
+	    labelFontSize = ((Integer)MAX_MAP_SIZES.get("labelFontSize")).intValue();
+	}
+
+	if (titleFontSize < ((Integer)MIN_MAP_SIZES.get("titleFontSize")).intValue()) {
+	    titleFontSize = ((Integer)MIN_MAP_SIZES.get("titleFontSize")).intValue();
+	}
+	else if (titleFontSize > ((Integer)MAX_MAP_SIZES.get("titleFontSize")).intValue()) {
+	    titleFontSize = ((Integer)MAX_MAP_SIZES.get("titleFontSize")).intValue();
+	}
+
+	if (legendFontSize < ((Integer)MIN_MAP_SIZES.get("legendFontSize")).intValue()) {
+	    legendFontSize = ((Integer)MIN_MAP_SIZES.get("legendFontSize")).intValue();
+	}
+	else if (legendFontSize > ((Integer)MAX_MAP_SIZES.get("legendFontSize")).intValue()) {
+	    legendFontSize = ((Integer)MAX_MAP_SIZES.get("legendFontSize")).intValue();
+	}
+
+	if (rulerFontSize < ((Integer)MIN_MAP_SIZES.get("rulerFontSize")).intValue()) {
+	    rulerFontSize = ((Integer)MIN_MAP_SIZES.get("rulerFontSize")).intValue();
+	}
+	else if (rulerFontSize > ((Integer)MAX_MAP_SIZES.get("rulerFontSize")).intValue()) {
+	    rulerFontSize = ((Integer)MAX_MAP_SIZES.get("rulerFontSize")).intValue();
+	}
+
+	if (messageFontSize < ((Integer)MIN_MAP_SIZES.get("messageFontSize")).intValue()) {
+	    messageFontSize = ((Integer)MIN_MAP_SIZES.get("messageFontSize")).intValue();
+	}
+	else if (messageFontSize > ((Integer)MAX_MAP_SIZES.get("messageFontSize")).intValue()) {
+	    messageFontSize = ((Integer)MAX_MAP_SIZES.get("messageFontSize")).intValue();
+	}
+
+
+	labelFont = new Font("SansSerif", Font.PLAIN, labelFontSize);
+	titleFont = new Font("SansSerif", Font.PLAIN, titleFontSize);
+	legendFont = new Font("SansSerif", Font.PLAIN, legendFontSize);
+	rulerFont = new Font("SansSerif", Font.PLAIN, rulerFontSize);
+	messageFont = new Font("SansSerif", Font.PLAIN, messageFontSize);
+
+	//check for overriding values
+	if (this.labelFontSize != -1) {
+	    labelFont = new Font("SansSerif", Font.PLAIN, this.labelFontSize);
+	}
+	if (this.rulerFontSize != -1) {
+	    rulerFont = new Font("SansSerif", Font.PLAIN, this.rulerFontSize);
+	}
+	if (this.legendFontSize != -1) {
+	    legendFont = new Font("SansSerif", Font.PLAIN, this.legendFontSize);
+	}
+
+	//do int
+	maxLabels = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("maxLabels")).intValue() + 0.5f);
+	if (maxLabels < ((Integer)MIN_MAP_SIZES.get("maxLabels")).intValue()) {
+	    maxLabels = ((Integer)MIN_MAP_SIZES.get("maxLabels")).intValue();
+	}
+	else if (maxLabels > ((Integer)MAX_MAP_SIZES.get("maxLabels")).intValue()) {
+	    maxLabels = ((Integer)MAX_MAP_SIZES.get("maxLabels")).intValue();
+	}
+
+	//do float
+	featureThickness = (sizeRatio + mapItemSizeAdjustment) * ((Float)DEFAULT_MAP_SIZES.get("featureThickness")).floatValue();
+
+	//done later
+// 	if (featureThickness < ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue()) {
+// 	    featureThickness = ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue();
+// 	}
+// 	else if (featureThickness > ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue()) {
+// 	    featureThickness = ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue();
+// 	}
+
+	backboneThickness = (sizeRatio + mapItemSizeAdjustment) * ((Float)DEFAULT_MAP_SIZES.get("backboneThickness")).floatValue();
+	if (backboneThickness < ((Float)MIN_MAP_SIZES.get("backboneThickness")).floatValue()) {
+	    backboneThickness = ((Float)MIN_MAP_SIZES.get("backboneThickness")).floatValue();
+	}
+	else if (backboneThickness > ((Float)MAX_MAP_SIZES.get("backboneThickness")).floatValue()) {
+	    backboneThickness = ((Float)MAX_MAP_SIZES.get("backboneThickness")).floatValue();
+	}
+
+	featureSlotSpacing = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("featureSlotSpacing")).floatValue();
+	if (featureSlotSpacing < ((Float)MIN_MAP_SIZES.get("featureSlotSpacing")).floatValue()) {
+	    featureSlotSpacing = ((Float)MIN_MAP_SIZES.get("featureSlotSpacing")).floatValue();
+	}
+	else if (featureSlotSpacing > ((Float)MAX_MAP_SIZES.get("featureSlotSpacing")).floatValue()) {
+	    featureSlotSpacing = ((Float)MAX_MAP_SIZES.get("featureSlotSpacing")).floatValue();
+	}
+
+	tickLength = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("tickLength")).floatValue();
+	if (tickLength < ((Float)MIN_MAP_SIZES.get("tickLength")).floatValue()) {
+	    tickLength = ((Float)MIN_MAP_SIZES.get("tickLength")).floatValue();
+	}
+	else if (tickLength > ((Float)MAX_MAP_SIZES.get("tickLength")).floatValue()) {
+	    tickLength = ((Float)MAX_MAP_SIZES.get("tickLength")).floatValue();
+	}
+
+	tickThickness = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("tickThickness")).floatValue();
+	if (tickThickness < ((Float)MIN_MAP_SIZES.get("tickThickness")).floatValue()) {
+	    tickThickness = ((Float)MIN_MAP_SIZES.get("tickThickness")).floatValue();
+	}
+	else if (tickThickness > ((Float)MAX_MAP_SIZES.get("tickThickness")).floatValue()) {
+	    tickThickness = ((Float)MAX_MAP_SIZES.get("tickThickness")).floatValue();
+	}
+
+	shortTickThickness = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("shortTickThickness")).floatValue();
+	if (shortTickThickness < ((Float)MIN_MAP_SIZES.get("shortTickThickness")).floatValue()) {
+	    shortTickThickness = ((Float)MIN_MAP_SIZES.get("shortTickThickness")).floatValue();
+	}
+	else if (shortTickThickness > ((Float)MAX_MAP_SIZES.get("shortTickThickness")).floatValue()) {
+	    shortTickThickness = ((Float)MAX_MAP_SIZES.get("shortTickThickness")).floatValue();
+	}
+
+	labelLineThickness = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("labelLineThickness")).floatValue();
+	if (labelLineThickness < ((Float)MIN_MAP_SIZES.get("labelLineThickness")).floatValue()) {
+	    labelLineThickness = ((Float)MIN_MAP_SIZES.get("labelLineThickness")).floatValue();
+	}
+	else if (labelLineThickness > ((Float)MAX_MAP_SIZES.get("labelLineThickness")).floatValue()) {
+	    labelLineThickness = ((Float)MAX_MAP_SIZES.get("labelLineThickness")).floatValue();
+	}
+
+	//do doubles
+	labelLineLength = sizeRatio * ((Double)DEFAULT_MAP_SIZES.get("labelLineLength")).doubleValue();
+	if (labelLineLength < ((Double)MIN_MAP_SIZES.get("labelLineLength")).doubleValue()) {
+	    labelLineLength = ((Double)MIN_MAP_SIZES.get("labelLineLength")).doubleValue();
+	}
+	else if (labelLineLength > ((Double)MAX_MAP_SIZES.get("labelLineLength")).doubleValue()) {
+	    labelLineLength = ((Double)MAX_MAP_SIZES.get("labelLineLength")).doubleValue();
+	}
+
+	arrowheadLength = (sizeRatio + mapItemSizeAdjustment) * ((Double)DEFAULT_MAP_SIZES.get("arrowheadLength")).doubleValue();
+	if (arrowheadLength < ((Double)MIN_MAP_SIZES.get("arrowheadLength")).doubleValue()) {
+	    arrowheadLength = ((Double)MIN_MAP_SIZES.get("arrowheadLength")).doubleValue();
+	}
+	else if (arrowheadLength > ((Double)MAX_MAP_SIZES.get("arrowheadLength")).doubleValue()) {
+	    arrowheadLength = ((Double)MAX_MAP_SIZES.get("arrowheadLength")).doubleValue();
+	}
+   
+
+	//do modal changes
+	if (mapSmallest <= SMALL_MAP_MODE_DIMENSION) {
+	    giveFeaturePositions = ((Integer)SMALL_MAP_MODES.get("giveFeaturePositions")).intValue();
+	    useInnerLabels = ((Integer)SMALL_MAP_MODES.get("useInnerLabels")).intValue();	
+	}
+	else if (mapSmallest >= LARGE_MAP_MODE_DIMENSION) {
+	    giveFeaturePositions = ((Integer)LARGE_MAP_MODES.get("giveFeaturePositions")).intValue();
+	    useInnerLabels = ((Integer)LARGE_MAP_MODES.get("useInnerLabels")).intValue();
+	}
+	else {
+	    giveFeaturePositions = ((Integer)DEFAULT_MAP_MODES.get("giveFeaturePositions")).intValue();
+	    useInnerLabels = ((Integer)DEFAULT_MAP_MODES.get("useInnerLabels")).intValue();
+	}
+
+	//adjust feature thickness based on how many slots are used
+	float growthIncrement = 0.083f * featureThickness;  // 1/12 = 0.083
+	int emptySlots = 0;
+
+        if (forwardSlot1 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot2 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot3 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot4 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot5 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot6 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot1 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot2 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot3 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot4 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot5 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot6 == null) {
+	    emptySlots++;
+	}
+
+	featureThickness = featureThickness + (float)emptySlots * growthIncrement;
+
+	if (featureThickness < ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue()) {
+	    featureThickness = ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue();
+	}
+	else if (featureThickness > ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue()) {
+	    featureThickness = ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue();
+	}
+
+        if (forwardSlot1 != null) {
+	    forwardSlot1.sortFeaturesByStart();
+            forwardSlot1.setCgview(cgview);
+            forwardSlot1.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot2 != null) {
+	    forwardSlot2.sortFeaturesByStart();
+            forwardSlot2.setCgview(cgview);
+            forwardSlot2.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot3 != null) {
+	    forwardSlot3.sortFeaturesByStart();
+            forwardSlot3.setCgview(cgview);
+            forwardSlot3.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot4 != null) {
+	    forwardSlot4.sortFeaturesByStart();
+            forwardSlot4.setCgview(cgview);
+            forwardSlot4.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot5 != null) {
+	    forwardSlot5.sortFeaturesByStart();
+            forwardSlot5.setCgview(cgview);
+            forwardSlot5.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot6 != null) {
+	    forwardSlot6.sortFeaturesByStart();
+            forwardSlot6.setCgview(cgview);
+            forwardSlot6.setFeatureThickness(featureThickness);
+        }
+
+        if (reverseSlot1 != null) {
+	    reverseSlot1.sortFeaturesByStart();
+            reverseSlot1.setCgview(cgview);
+            reverseSlot1.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot2 != null) {
+	    reverseSlot2.sortFeaturesByStart();
+            reverseSlot2.setCgview(cgview);
+            reverseSlot2.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot3 != null) {
+	    reverseSlot3.sortFeaturesByStart();
+            reverseSlot3.setCgview(cgview);
+            reverseSlot3.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot4 != null) {
+	    reverseSlot4.sortFeaturesByStart();
+            reverseSlot4.setCgview(cgview);
+            reverseSlot4.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot5 != null) {
+	    reverseSlot5.sortFeaturesByStart();
+            reverseSlot5.setCgview(cgview);
+            reverseSlot5.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot6 != null) {
+	    reverseSlot6.sortFeaturesByStart();
+            reverseSlot6.setCgview(cgview);
+            reverseSlot6.setFeatureThickness(featureThickness);
+        }
+
+	cgview.setWidth(mapWidth);
+	cgview.setHeight(mapHeight);
+        cgview.setLabelsToKeep(maxLabels);
+        cgview.setDrawTickMarks(drawTickMarks);
+        cgview.setTitleFont(titleFont);
+        cgview.setLabelFont(labelFont);
+        cgview.setFeatureThickness(featureThickness);
+        cgview.setBackboneThickness(backboneThickness);
+        cgview.setFeatureSlotSpacing(featureSlotSpacing);
+	cgview.setMinimumFeatureLength(minimumFeatureLength);
+        cgview.setLegendFont(legendFont);
+        cgview.setTickLength(tickLength);
+	cgview.setTickThickness(tickThickness);
+	cgview.setShortTickThickness(shortTickThickness);
+	cgview.setLabelLineThickness(labelLineThickness);
+        cgview.setLabelLineLength(labelLineLength);
+        cgview.setLabelPlacementQuality(labelPlacementQuality);
+        cgview.setUseColoredLabelBackgrounds(useColoredLabelBackground);
+        cgview.setShowBorder(showBorder);
+        cgview.setShowShading(showShading);
+	cgview.setGiveFeaturePositions(giveFeaturePositions);
+        cgview.setShadingProportion(shadingProportion);
+        cgview.setUseInnerLabels(useInnerLabels);
+        cgview.setMoveInnerLabelsToOuter(moveInnerLabelsToOuter);
+        cgview.setWarningFont(rulerFont);
+        cgview.setRulerFont(rulerFont);
+	cgview.setArrowheadLength(arrowheadLength);
+	cgview.setHighlightOpacity(shadingOpacity);
+	cgview.setShadowOpacity(shadingOpacity);
+
+	cgview.setTickDensity(tickDensity);
+
+        //if not drawing labels, don't show message.
+        if (!(showLabels)) {
+            cgview.setShowWarning(false);
+        }
+
+        //set backboneRadius based on smallest image dimension
+	cgview.setSequenceLength(length);
+	mapSmallest = Math.min(mapWidth, mapHeight);
+	cgview.setBackboneRadius(0.50d * (double) mapSmallest / 1.9d);	
+
+        //check coloredLabels
+        if (!(useColoredLabels)) {
+	    cgview.setGlobalLabelColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+        }
+
+        //set map item colors
+	cgview.setLongTickColor((Color) MAP_ITEM_COLORS.get("tick"));
+	cgview.setShortTickColor((Color) MAP_ITEM_COLORS.get("partialTick"));
+	cgview.setZeroTickColor((Color) MAP_ITEM_COLORS.get("zeroLine"));
+	cgview.setRulerFontColor((Color) MAP_ITEM_COLORS.get("rulerFont"));
+	cgview.setBackboneColor((Color) MAP_ITEM_COLORS.get("backbone"));
+	cgview.setTitleFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+	cgview.setWarningFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+	cgview.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+ 
+
+        //build legend
+        if (showLegend) {
+            //create legend
+            legend = new Legend(cgview);
+            legend.setAllowLabelClash(allowLabelClashLegend);
+            legend.setBackgroundOpacity(0.5f);
+
+	    //legend.setFont(labelFont);
+
+	    legend.setFont(legendFont);
+
+            legend.setPosition(legendPosition);
+
+            legend.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+            legend.setFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+
+            LegendItem legendItem;
+       
+	    //legendItem = new LegendItem(legend);
+	    //legendItem.setLabel("Feature legend");
+	    //legendItem.setDrawSwatch(SWATCH_NO_SHOW);
+
+            Enumeration legendEntries = DRAW_LEGEND_ITEMS.keys();
+            ArrayList list = new ArrayList();
+            while (legendEntries.hasMoreElements()) {
+                list.add(legendEntries.nextElement());
+            }
+            Collections.sort(list);
+
+	    list.add(0, "reverse_gene");
+	    list.add(0, "forward_gene");
+
+            Iterator i = list.iterator();
+
+            while (i.hasNext()) {
+                String key = (String) i.next();
+                legendItem = new LegendItem(legend);
+		if (mapSmallest >= LARGE_MAP_MODE_DIMENSION) {
+		    legendItem.setLabel((String) LEGEND_ITEM_NAMES_LONG.get(key));
+		}
+		else {
+		    legendItem.setLabel((String) LEGEND_ITEM_NAMES_SHORT.get(key));
+		}
+                legendItem.setSwatchColor((Color) FEATURE_COLORS.get(key));
+		legendItem.setDrawSwatch(SWATCH_SHOW);
+            }
+        }
+
+	//add title legend
+	if (showTitle) {
+	    if (title.length() > MAX_TITLE_LENGTH) {
+		title = title.substring(0, MAX_TITLE_LENGTH) + "...";
+	    }
+	    legend = new Legend(cgview);
+	    legend.setAllowLabelClash(allowLabelClashLegend);
+	    legend.setBackgroundOpacity(0.5f);
+	    legend.setFont(legendFont);
+	    legend.setPosition(LEGEND_LOWER_CENTER);
+	    LegendItem legendItem = new LegendItem(legend);
+	    legendItem.setLabel(title);
+	    legendItem.setDrawSwatch(SWATCH_NO_SHOW);
+	}
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryTab.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryTab.class
new file mode 100644
index 0000000..a9389ea
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryTab.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryTab.java b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryTab.java
new file mode 100644
index 0000000..e87e5e3
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/CgviewFactoryTab.java
@@ -0,0 +1,1407 @@
+package ca.ualberta.stothard.cgview;
+
+
+import java.io.*;
+import java.awt.*;
+import java.util.*;
+import java.lang.Integer;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.ArrayList;
+import java.net.*;
+import java.util.*;
+import java.io.*;
+import java.text.NumberFormat;
+
+/**
+ * This class reads a tab delimited feature file and creates a Cgview object.
+ *
+ * @author Paul Stothard
+ */
+
+public class CgviewFactoryTab implements CgviewConstants {
+
+    private Cgview cgview;
+
+    private Hashtable COLORS = new Hashtable();
+    private Hashtable MAP_ITEM_COLORS = new Hashtable();
+    private Hashtable FEATURE_COLORS = new Hashtable();
+    private Hashtable FEATURE_DECORATIONS_DIRECT = new Hashtable();
+    private Hashtable FEATURE_DECORATIONS_REVERSE = new Hashtable();
+    private Hashtable LEGEND_ITEM_NAMES = new Hashtable();
+    private Hashtable DRAW_LEGEND_ITEMS = new Hashtable();
+
+    private Hashtable DEFAULT_MAP_SIZES = new Hashtable();
+    private Hashtable MIN_MAP_SIZES = new Hashtable();
+    private Hashtable MAX_MAP_SIZES = new Hashtable();
+
+    private Hashtable DEFAULT_MAP_MODES = new Hashtable();
+    private Hashtable SMALL_MAP_MODES = new Hashtable();
+    private Hashtable LARGE_MAP_MODES = new Hashtable();
+
+    private int LARGE_MAP_MODE_DIMENSION = 2000;
+    private int SMALL_MAP_MODE_DIMENSION = 800;
+
+    private FeatureSlot forwardSlot1;
+    private FeatureSlot forwardSlot2;
+    private FeatureSlot forwardSlot3;
+    private FeatureSlot forwardSlot4;
+    private FeatureSlot forwardSlot5;
+    private FeatureSlot forwardSlot6;
+
+    private FeatureSlot reverseSlot1;
+    private FeatureSlot reverseSlot2;
+    private FeatureSlot reverseSlot3;
+    private FeatureSlot reverseSlot4;
+    private FeatureSlot reverseSlot5;
+    private FeatureSlot reverseSlot6;
+
+    private Legend legend;
+
+    private int zoomCenter = 1;
+    private int length = 0;
+    private String title = "";
+
+    private int mapWidth = 900;
+    private int mapHeight = 600;
+    private int mapSmallest = 0;
+
+    private float mapItemSizeAdjustment = 0.0f;
+
+    private int labelFontSize = -1;
+    private int rulerFontSize = -1;
+    private int legendFontSize = -1;
+
+    private double tickDensity = 1.0d;
+
+    private boolean readDimension = true;
+
+    private NumberFormat nf = NumberFormat.getInstance();
+
+    private int MAX_MOUSEOVER_LENGTH = 100;
+    private int MAX_LABEL_LENGTH = 50;
+    private int MAX_TITLE_LENGTH = 50;
+    private int MAX_SEQUENCE_LENGTH = 20000000;
+
+    private int MAX_IMAGE_WIDTH;
+    private int MIN_IMAGE_WIDTH;
+
+    private int MAX_IMAGE_HEIGHT;
+    private int MIN_IMAGE_HEIGHT;
+
+    private float opacity = 1.0f;
+    private boolean useColoredLabelBackground = false;
+    private boolean showTitle = true;
+    private boolean showShading = true;
+    private boolean showBorder = false;
+    private boolean allowLabelClashLegend = false;
+    private boolean moveInnerLabelsToOuter = true;
+    private int labelPlacementQuality = 9;
+    private int legendPosition = LEGEND_UPPER_RIGHT;
+    private boolean useColoredLabels = true;
+    private boolean drawTickMarks = true;
+    private boolean showLegend = true;
+    private boolean showWarning = false;
+    private boolean showLabels = true;
+    private float shadingProportion = 0.4f;
+    private float shadingOpacity = 0.5f;
+
+    /**
+     * Constructs a new CgviewFactoryTab object.
+     */
+    public CgviewFactoryTab() {
+	cgview = new Cgview(1);
+    }
+
+    /**
+     * Generates a Cgview object from an tab delimited feature file.
+     *
+     * @param filename the file to read.
+     * @return the newly created Cgview object.
+     * @throws Exception
+     * @throws IOException
+     */
+    public Cgview createCgviewFromFile(String filename) throws Exception, IOException {
+	File file = new File(filename);
+	URL url = null;
+	url = file.toURL();
+	return createCgviewFromURL(url);
+    }
+
+    /**
+     * Generates a Cgview object from an tab delimited feature file.
+     *
+     * @param url the URL of the tab delimited file to read.
+     * @return the newly created Cgview object.
+     * @throws Exception
+     * @throws IOException
+     */
+    public Cgview createCgviewFromURL(URL url) throws Exception, IOException {
+
+        COLORS.put("black", new Color(0, 0, 0));
+        COLORS.put("silver", new Color(192, 192, 192));
+        COLORS.put("gray", new Color(128, 128, 128));
+        COLORS.put("white", new Color(255, 255, 255));
+        COLORS.put("maroon", new Color(128, 0, 0));
+        COLORS.put("red", new Color(255, 0, 0));
+        COLORS.put("pink", new Color(255, 153, 204));
+        COLORS.put("purple", new Color(128, 0, 128));
+        COLORS.put("fuchsia", new Color(255, 0, 255));
+        COLORS.put("orange", new Color(255, 153, 0));
+        COLORS.put("green", new Color(0, 128, 0));
+        COLORS.put("spring", new Color(204, 255, 204));
+        COLORS.put("lime", new Color(0, 255, 0));
+        COLORS.put("olive", new Color(128, 128, 0));
+        COLORS.put("yellow", new Color(255, 255, 0));
+        COLORS.put("navy", new Color(0, 0, 128));
+        COLORS.put("blue", new Color(0, 0, 255));
+        COLORS.put("azure", new Color(51, 153, 255));
+        COLORS.put("lightBlue", new Color(102, 204, 255));
+        COLORS.put("teal", new Color(153, 255, 204));
+        COLORS.put("aqua", new Color(0, 255, 255));
+
+        MAP_ITEM_COLORS.put("tick", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("rulerFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("titleFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("messageFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("backbone", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("partialTick", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("zeroLine", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("background", COLORS.get("white"));
+
+        FEATURE_COLORS.put("forward_gene", COLORS.get("red"));
+        FEATURE_COLORS.put("reverse_gene", COLORS.get("blue"));
+        FEATURE_COLORS.put("origin_of_replication", COLORS.get("black"));
+        FEATURE_COLORS.put("promoter", COLORS.get("green"));
+        FEATURE_COLORS.put("terminator", COLORS.get("maroon"));
+        FEATURE_COLORS.put("regulatory_sequence", COLORS.get("olive"));
+        FEATURE_COLORS.put("unique_restriction_site", COLORS.get("purple"));
+        FEATURE_COLORS.put("restriction_site", COLORS.get("azure"));
+        FEATURE_COLORS.put("open_reading_frame", COLORS.get("pink"));
+        //FEATURE_COLORS.put("gene", COLORS.get("blue"));
+	FEATURE_COLORS.put("predicted_gene", COLORS.get("orange"));
+        FEATURE_COLORS.put("sequence_similarity", COLORS.get("silver"));
+        FEATURE_COLORS.put("score", COLORS.get("fuchsia"));
+        FEATURE_COLORS.put("score_II", COLORS.get("gray"));	
+        FEATURE_COLORS.put("primer", COLORS.get("teal"));
+
+        FEATURE_DECORATIONS_DIRECT.put("forward_gene", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("origin_of_replication", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("promoter", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("terminator", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("regulatory_sequence", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("unique_restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("open_reading_frame", new Integer(DECORATION_CLOCKWISE_ARROW));
+        //FEATURE_DECORATIONS_DIRECT.put("gene", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("predicted_gene", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("sequence_similarity", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("score", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("score_II", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("primer", new Integer(DECORATION_CLOCKWISE_ARROW));
+
+        FEATURE_DECORATIONS_REVERSE.put("reverse_gene", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("origin_of_replication", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("promoter", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("terminator", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("regulatory_sequence", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("unique_restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("open_reading_frame", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        //FEATURE_DECORATIONS_REVERSE.put("gene", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("predicted_gene", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("sequence_similarity", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("score", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("score_II", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("primer", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+
+        LEGEND_ITEM_NAMES.put("forward_gene", "Forward gene");
+        LEGEND_ITEM_NAMES.put("reverse_gene", "Reverse gene");
+        LEGEND_ITEM_NAMES.put("origin_of_replication", "Origin of replication");
+        LEGEND_ITEM_NAMES.put("promoter", "Promoter");
+        LEGEND_ITEM_NAMES.put("terminator", "Terminator");
+        LEGEND_ITEM_NAMES.put("regulatory_sequence", "Regulatory sequence");
+        LEGEND_ITEM_NAMES.put("unique_restriction_site", "Unique restriction site");
+        LEGEND_ITEM_NAMES.put("restriction_site", "Restriction site");
+        LEGEND_ITEM_NAMES.put("open_reading_frame", "Open reading frame");
+        //LEGEND_ITEM_NAMES.put("gene", "Gene");
+        LEGEND_ITEM_NAMES.put("predicted_gene", "Predicted gene");
+        LEGEND_ITEM_NAMES.put("sequence_similarity", "Sequence similarity");
+        LEGEND_ITEM_NAMES.put("score", "Score");
+        LEGEND_ITEM_NAMES.put("score_II", "Score II");
+        LEGEND_ITEM_NAMES.put("primer", "Primer");
+
+        DEFAULT_MAP_SIZES.put("mapWidth", new Integer(900));
+        DEFAULT_MAP_SIZES.put("mapHeight", new Integer(900));
+        DEFAULT_MAP_SIZES.put("labelFontSize", new Integer(10));
+        DEFAULT_MAP_SIZES.put("titleFontSize", new Integer(15));
+        DEFAULT_MAP_SIZES.put("legendFontSize", new Integer(13));
+        DEFAULT_MAP_SIZES.put("rulerFontSize", new Integer(8));
+        DEFAULT_MAP_SIZES.put("messageFontSize", new Integer(12));
+        DEFAULT_MAP_SIZES.put("featureThickness", new Float(12.0f));
+        DEFAULT_MAP_SIZES.put("backboneThickness", new Float(4.0f));
+        DEFAULT_MAP_SIZES.put("featureSlotSpacing", new Float(2.0f));
+        DEFAULT_MAP_SIZES.put("tickLength", new Float(6.0f));
+        DEFAULT_MAP_SIZES.put("tickThickness", new Float(2.0f));
+        DEFAULT_MAP_SIZES.put("shortTickThickness", new Float(2.0f));
+        DEFAULT_MAP_SIZES.put("labelLineLength", new Double(50.0d));
+        DEFAULT_MAP_SIZES.put("labelLineThickness", new Float(1.0f));
+        DEFAULT_MAP_SIZES.put("arrowheadLength", new Double(5.0d));
+        DEFAULT_MAP_SIZES.put("maxLabels", new Integer(5000));
+
+        MIN_MAP_SIZES.put("mapWidth", new Integer(500));
+        MIN_MAP_SIZES.put("mapHeight", new Integer(500));
+        MIN_MAP_SIZES.put("labelFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("titleFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("legendFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("rulerFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("messageFontSize", new Integer(1));
+        MIN_MAP_SIZES.put("featureThickness", new Float(0.5f));
+        MIN_MAP_SIZES.put("backboneThickness", new Float(0.1f));
+        MIN_MAP_SIZES.put("featureSlotSpacing", new Float(0.1f));
+        MIN_MAP_SIZES.put("tickLength", new Float(1.0f));
+        MIN_MAP_SIZES.put("tickThickness", new Float(0.5f));
+        MIN_MAP_SIZES.put("shortTickThickness", new Float(0.5));
+        MIN_MAP_SIZES.put("labelLineLength", new Double(2.0f));
+        MIN_MAP_SIZES.put("labelLineThickness", new Float(0.5));
+        MIN_MAP_SIZES.put("arrowheadLength", new Double(0.5d));
+        MIN_MAP_SIZES.put("maxLabels", new Integer(10));
+
+        MAX_MAP_SIZES.put("mapWidth", new Integer(30000));
+        MAX_MAP_SIZES.put("mapHeight", new Integer(30000));
+        MAX_MAP_SIZES.put("labelFontSize", new Integer(10));
+        MAX_MAP_SIZES.put("titleFontSize", new Integer(100));
+        MAX_MAP_SIZES.put("legendFontSize", new Integer(100));
+        MAX_MAP_SIZES.put("rulerFontSize", new Integer(8));
+        MAX_MAP_SIZES.put("messageFontSize", new Integer(100));
+        MAX_MAP_SIZES.put("featureThickness", new Float(80.0f));
+        MAX_MAP_SIZES.put("backboneThickness", new Float(5.0f));
+        MAX_MAP_SIZES.put("featureSlotSpacing", new Float(5.0f));
+        MAX_MAP_SIZES.put("tickLength", new Float(6.0f));
+        MAX_MAP_SIZES.put("tickThickness", new Float(2.0f));
+        MAX_MAP_SIZES.put("shortTickThickness", new Float(2.0f));
+        MAX_MAP_SIZES.put("labelLineLength", new Double(80.0f));
+        MAX_MAP_SIZES.put("labelLineThickness", new Float(1.0f));
+        MAX_MAP_SIZES.put("arrowheadLength", new Double(18.0d));
+        MAX_MAP_SIZES.put("maxLabels", new Integer(50000));
+
+	DEFAULT_MAP_MODES.put("giveFeaturePositions", new Integer(POSITIONS_NO_SHOW));
+	DEFAULT_MAP_MODES.put("useInnerLabels", new Integer(INNER_LABELS_AUTO));
+
+	SMALL_MAP_MODES.put("giveFeaturePositions", new Integer(POSITIONS_NO_SHOW));
+	SMALL_MAP_MODES.put("useInnerLabels", new Integer(INNER_LABELS_AUTO));
+
+	LARGE_MAP_MODES.put("giveFeaturePositions", new Integer(POSITIONS_NO_SHOW));
+	LARGE_MAP_MODES.put("useInnerLabels", new Integer(INNER_LABELS_SHOW));	
+
+	MAX_IMAGE_WIDTH = ((Integer)MAX_MAP_SIZES.get("mapWidth")).intValue();
+	MIN_IMAGE_WIDTH = ((Integer)MIN_MAP_SIZES.get("mapWidth")).intValue();
+
+	MAX_IMAGE_HEIGHT = ((Integer)MAX_MAP_SIZES.get("mapHeight")).intValue();
+	MIN_IMAGE_HEIGHT = ((Integer)MIN_MAP_SIZES.get("mapHeight")).intValue();
+
+	InputStream in;
+	BufferedReader buf;
+	int lineCount = 0;
+	String line;
+	String lineItems[];
+
+	int columnNumber = 0;
+
+	String strand;
+	int slot = 0; 
+	int start = 0; 
+	int stop = 0; 
+	float opacity = 1.0f;
+	float thickness = 1.0f;
+	float radius = 0.0f;
+	String type = "";
+	String label = "";
+	String mouseover = "";
+	String hyperlink = "";
+
+	boolean hasStrandColumn = false;
+	boolean hasSlotColumn = false;
+	boolean hasStartColumn = false;
+	boolean hasStopColumn = false;
+	boolean hasOpacityColumn = false;
+	boolean hasThicknessColumn = false;
+	boolean hasRadiusColumn = false;
+	boolean hasTypeColumn = false;
+	boolean hasLabelColumn = false;
+	boolean hasMouseoverColumn = false;
+	boolean hasHyperlinkColumn = false;
+
+	int strandColumnIndex = -1;
+	int slotColumnIndex = -1;
+	int startColumnIndex = -1;
+	int stopColumnIndex = -1;
+	int opacityColumnIndex = -1;
+	int thicknessColumnIndex = -1;
+	int radiusColumnIndex = -1;
+	int typeColumnIndex = -1;
+	int labelColumnIndex = -1;
+	int mouseoverColumnIndex = -1;
+	int hyperlinkColumnIndex = -1;
+		
+	in = url.openStream();
+
+        System.out.println("Parsing tab delimited input.");
+
+	buf = new BufferedReader(new InputStreamReader(in));
+	while((line = buf.readLine()) != null) {
+	    lineCount++;
+	    if (line.startsWith("#")) {
+		title = line.substring(1);
+	    }
+
+	    else if (line.startsWith("%")) {
+		try {
+		    length = Integer.parseInt(line.substring(1));
+		}
+		catch (Exception e) {
+		    throw new Exception("There is a problem with the length value on line " + lineCount + " in the data file.");
+		}				
+	    }
+	    else if (line.startsWith("!")) {
+		line = line.substring(1);
+		lineItems = line.split("(?:\\s*\\t+\\s*)|(?:\\s{2,})");
+		//lineItems = line.split("\\s*\\t+\\s*");
+		columnNumber = lineItems.length;
+		for (int i = 0; i < lineItems.length; i = i + 1) {
+		    String lineItem = lineItems[i].trim();
+		    if (lineItem.equalsIgnoreCase("strand")) {
+			hasStrandColumn = true;
+			strandColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("slot")) {
+			hasSlotColumn = true;
+			slotColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("start")) {
+			hasStartColumn = true;
+			startColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("stop")) {
+			hasStopColumn = true;
+			stopColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("type")) {
+			hasTypeColumn = true;
+			typeColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("opacity")) {
+			hasOpacityColumn = true;
+			opacityColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("thickness")) {
+			hasThicknessColumn = true;
+			thicknessColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("radius")) {
+			hasRadiusColumn = true;
+			radiusColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("label")) {
+			hasLabelColumn = true;
+			labelColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("mouseover")) {
+			hasMouseoverColumn = true;
+			mouseoverColumnIndex = i;
+		    }
+		    else if (lineItem.equalsIgnoreCase("hyperlink")) {
+			hasHyperlinkColumn = true;
+			hyperlinkColumnIndex = i;
+		    }
+		}
+	    }
+	    else {
+		//some text editors may use spaces instead of tabs.
+		//try to handle this.
+		lineItems = line.split("\\s*\\t+\\s*");
+		if (lineItems.length != columnNumber) {
+		    lineItems = line.split("(?:\\s*\\t+\\s*)|(?:\\s{2,})");
+		}
+
+		if (lineItems.length >= 5) {
+
+		    if (hasStrandColumn == false) {
+			throw new Exception("A \"strand\" column has not been defined in the data file.");			
+		    }
+		    if (hasSlotColumn == false) {
+			throw new Exception("A \"slot\" column has not been defined in the data file.");			
+		    }
+		    if (hasStartColumn == false) {
+			throw new Exception("A \"start\" column has not been defined in the data file.");		
+		    }
+		    if (hasStopColumn == false) {
+			throw new Exception("A \"stop\" column has not been defined in the data file.");			
+		    }
+		    if (hasTypeColumn == false) {
+			throw new Exception("A \"type\" column has not been defined in the data file.");			
+		    }
+
+		    try {
+			strand = lineItems[strandColumnIndex];
+		    }
+		    catch (Exception e) {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    try {
+			slot = Integer.parseInt(lineItems[slotColumnIndex]);
+		    }
+		    catch (Exception e) {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    try {
+			start = Integer.parseInt(lineItems[startColumnIndex]);
+		    }
+		    catch (Exception e) {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    try {
+			stop = Integer.parseInt(lineItems[stopColumnIndex]);
+		    }
+		    catch (Exception e) {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    try {
+			type = lineItems[typeColumnIndex];
+		    }
+		    catch (Exception e) {
+			throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+		    }
+
+		    if (hasOpacityColumn) {
+			try {
+			    if ((!(lineItems[opacityColumnIndex].matches("^\\s*$"))) && (!(lineItems[opacityColumnIndex].equals("-")))) {
+				opacity = Float.parseFloat(lineItems[opacityColumnIndex]);
+			    }
+			    else {
+				opacity = 1.0f;
+			    }
+			}
+			catch (Exception e) {
+			    throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			opacity = 1.0f;
+		    }
+
+		    if (hasThicknessColumn) {
+			try {
+			    if ((!(lineItems[thicknessColumnIndex].matches("^\\s*$"))) && (!(lineItems[thicknessColumnIndex].equals("-")))) {			   
+				thickness = Float.parseFloat(lineItems[thicknessColumnIndex]);
+			    }
+			    else {
+				thickness = 1.0f;
+			    }
+			}
+			catch (Exception e) {
+			    throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			thickness = 1.0f;
+		    }
+
+		    if (hasRadiusColumn) {
+			try {
+			    if ((!(lineItems[radiusColumnIndex].matches("^\\s*$"))) && (!(lineItems[radiusColumnIndex].equals("-")))) {			    
+				radius = Float.parseFloat(lineItems[radiusColumnIndex]);
+			    }
+			    else {
+				radius = 0.0f;
+			    }
+			}
+			catch (Exception e) {
+			    throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			radius = 0.0f;
+		    }
+
+		    if (hasLabelColumn) {
+			try {
+			    if ((!(lineItems[labelColumnIndex].matches("^\\s*$"))) && (!(lineItems[labelColumnIndex].equals("-")))) {				    
+				label = lineItems[labelColumnIndex];
+			    }
+			    else {
+				label = "";
+			    }
+			}
+			catch (Exception e) {
+			    throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			label = "";
+		    }
+
+		    if (hasMouseoverColumn) {
+			try {
+			    if ((!(lineItems[mouseoverColumnIndex].matches("^\\s*$"))) && (!(lineItems[mouseoverColumnIndex].equals("-")))) {			    
+				mouseover = lineItems[mouseoverColumnIndex];
+			    }
+			    else {
+				mouseover = "";
+			    }
+			}
+			catch (Exception e) {
+ 			    throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			mouseover = "";
+		    }
+
+		    if (hasHyperlinkColumn) {
+			try {
+			    if ((!(lineItems[hyperlinkColumnIndex].matches("^\\s*$"))) && (!(lineItems[hyperlinkColumnIndex].equals("-")))) {
+				hyperlink = lineItems[hyperlinkColumnIndex];
+			    }
+			    else {
+				hyperlink = "";
+			    }
+			}
+			catch (Exception e) {
+			    throw new Exception("There is a problem with line " + lineCount + " in the data file.");
+			}
+		    }
+		    else {
+			hyperlink = "";
+		    }
+		    
+		    try {
+			//change type 'gene' to 'forward_gene' or 'reverse_gene' depending on strand
+			if (type.equalsIgnoreCase("gene")) {
+			    if ((strand.equalsIgnoreCase("forward")) || (strand.equalsIgnoreCase("+"))) {
+				type = "forward_gene";
+			    }
+			    else if ((strand.equalsIgnoreCase("reverse")) || (strand.equalsIgnoreCase("-"))) {
+				type = "reverse_gene";
+			    }	
+			}
+	
+			addFeature(strand, slot, start, stop, opacity, thickness, radius, type, label, mouseover, hyperlink);
+		    }
+		    catch (Exception e) {
+			throw new Exception("Line " + lineCount + ": " + e.toString() + ".");
+		    }
+		}
+		else if (lineItems.length > 2) {
+		    throw new Exception ("The contents of line " + lineCount + " could not be parsed in the data file.");
+		}
+	    }
+	}
+
+	if (length > MAX_SEQUENCE_LENGTH) {
+	    throw new Exception ("Maximum sequence length is " + MAX_SEQUENCE_LENGTH + ".");
+	}
+	else if (length < 1) {
+	    throw new Exception ("Minimum sequence length is 1 base.");
+	}
+
+	if (mapWidth > MAX_IMAGE_WIDTH) {
+	    throw new Exception ("Maximum image width is " + MAX_IMAGE_WIDTH + ".");
+	}
+	else if (mapWidth < MIN_IMAGE_WIDTH) {
+	    throw new Exception ("Minimum image width is " + MIN_IMAGE_WIDTH + ".");
+	}
+
+	if (mapHeight > MAX_IMAGE_HEIGHT) {
+	    throw new Exception ("Maximum image height is " + MAX_IMAGE_HEIGHT + ".");
+	}
+	else if (mapHeight < MIN_IMAGE_HEIGHT) {
+	    throw new Exception ("Minimum image height is " + MIN_IMAGE_HEIGHT + ".");
+	}
+
+	prepareToDraw();
+        return cgview;
+    }
+
+    /**
+     * Add a feature to this map. Note that the start of the feature should be a smaller number than the stop of the
+     * feature, regardless of the strand. The only case where start is larger than the stop is when the feature runs
+     * across the start/stop boundary, for example 6899-10 on a 7000bp plasmid.
+     *
+     * @param strand    one of the following: forward, reverse.
+     * @param slot      one of the following: 1, 2, 3, 4, 5, 6.
+     * @param start     the start position of the feature. Must be between 1 and the length of the plasmid.
+     * @param stop      the end position of the feature. Must be between 1 and the length of the plasmid.
+     * @param opacity   the opacity of the feature.
+     * @param thickness the thickness of the feature.
+     * @param radius    the radius of the feature.
+     * @param type      one of the following: origin_of_replication, promoter, terminator, regulatory_sequence, 
+     *                  unique_restriction_site, restriction_site, open_reading_frame, gene, predicted_gene, 
+     *                  sequence_similarity, score, primer.
+     * @param label     the label to show or empty String.
+     * @param mouseover the mouseover to show or empty String.
+     * @param hyperlink the label hyperlink or empty String.
+     * @return whether or not the feature was added to the map. If there is a problem the feature is not added.
+     */
+    public void addFeature(String strand, int slot, int start, int stop, float opacity, float thickness, float radius, String type, String label, String mouseover, String hyperlink) throws Exception {
+ 
+        int decoration;
+        Color color;
+	int intStrand;
+	String problem;
+
+	//look for feature position problems
+        if (start > length) {
+	    throw new Exception ("The start value " + start + " is greater than the sequence length.");
+        }
+        if (start < 1) {
+	    throw new Exception ("The start value " + start + " is less than 1.");
+        }
+
+        if (stop > length) {
+	    throw new Exception ("The stop value " + stop + " is greater than the sequence length.");
+        }
+        if (stop < 1) {
+	    throw new Exception ("The stop value " + stop + " is less than 1.");
+        }
+
+	//convert the strand
+	if ((strand.equalsIgnoreCase("forward")) || (strand.equalsIgnoreCase("+"))) {
+	    intStrand = DIRECT_STRAND;
+	}
+	else if ((strand.equalsIgnoreCase("reverse")) || (strand.equalsIgnoreCase("-"))) {
+	    intStrand = REVERSE_STRAND;
+	}
+	else {
+	    throw new Exception ("The strand value must be \"forward\" or \"reverse\".");
+	}
+
+	//obtain the color
+        try {
+            color = getFeatureColor(type);
+        } catch (NullPointerException e) {
+	    throw new Exception ("The feature type \"" + type + "\" was not recognized.");
+        }
+
+	//obtain the decoration
+        try {
+            decoration = getFeatureDecoration(type, intStrand);
+        } catch (NullPointerException e) {
+	    throw new Exception ("The feature type \"" + type + "\" was not recognized.");
+        }
+
+	//add item to the legend
+        try {
+            addItemToLegend(type);	    
+        } catch (NullPointerException e) {
+	    throw new Exception ("The feature type \"" + type + "\" was not recognized.");
+        }
+
+        //create a feature and a feature range
+        //then figure out which feature slot to put the feature in.
+        Feature feature = new Feature(showShading);
+        FeatureRange featureRange = new FeatureRange(feature, start, stop);
+        featureRange.setDecoration(decoration);
+        featureRange.setColor(color);
+
+        featureRange.setOpacity(opacity);
+	featureRange.setProportionOfThickness(thickness);
+	featureRange.setRadiusAdjustment(radius);
+	
+	//if in slot 5 or 6 don't use shading
+	if ((slot == 5) || (slot == 6)) {
+	    feature.setShowShading(false);
+	}
+
+	if (!(label.matches("^\\s*$"))) {
+	    //shorten long label
+	    if (label.length() > MAX_LABEL_LENGTH) {
+		label = label.substring(0, MAX_LABEL_LENGTH) + "...";
+	    }
+	    featureRange.setLabel(label);
+	}
+	
+	if (!(mouseover.matches("^\\s*$"))) {	    
+	    //shorten long mouseover
+	    if (mouseover.length() > MAX_MOUSEOVER_LENGTH) {
+		mouseover = mouseover.substring(0, MAX_MOUSEOVER_LENGTH) + "...";
+	    }
+	    featureRange.setMouseover(mouseover);
+	}
+
+	if (!(hyperlink.matches("^\\s*$"))) {	    
+	    featureRange.setHyperlink(hyperlink);
+	}
+
+	if (intStrand == DIRECT_STRAND) {
+	    if (slot == 1) {
+		if (forwardSlot1 == null) {
+		    forwardSlot1 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot1);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot1);
+		}
+	    }
+	    else if (slot == 2) {
+		if (forwardSlot2 == null) {
+		    forwardSlot2 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot2);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot2);
+		}	   
+	    }
+	    else if (slot == 3) {
+		if (forwardSlot3 == null) {
+		    forwardSlot3 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot3);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot3);
+		}	   
+	    }	
+	    else if (slot == 4) {
+		if (forwardSlot4 == null) {
+		    forwardSlot4 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot4);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot4);
+		}	   
+	    }
+	    else if (slot == 5) {
+		if (forwardSlot5 == null) {
+		    forwardSlot5 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot5);
+
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot5);
+		}	   
+	    }
+	    else if (slot == 6) {
+		if (forwardSlot6 == null) {
+		    forwardSlot6 = new FeatureSlot(DIRECT_STRAND, showShading);
+		    feature.setFeatureSlot(forwardSlot6);
+		}
+		else {
+		    feature.setFeatureSlot(forwardSlot6);
+		}	   
+	    }
+	    else {
+	        throw new Exception ("The slot value must be between 1 and 6");
+	    }
+        }
+	else {
+	    if (slot == 1) {
+		if (reverseSlot1 == null) {
+		    reverseSlot1 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot1);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot1);
+		}
+	    }
+	    else if (slot == 2) {
+		if (reverseSlot2 == null) {
+		    reverseSlot2 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot2);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot2);
+		}	   
+	    }
+	    else if (slot == 3) {
+		if (reverseSlot3 == null) {
+		    reverseSlot3 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot3);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot3);
+		}	   
+	    }	
+	    else if (slot == 4) {
+		if (reverseSlot4 == null) {
+		    reverseSlot4 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot4);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot4);
+		}	   
+	    }
+	    else if (slot == 5) {
+		if (reverseSlot5 == null) {
+		    reverseSlot5 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot5);
+
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot5);
+		}	   
+	    }
+	    else if (slot == 6) {
+		if (reverseSlot6 == null) {
+		    reverseSlot6 = new FeatureSlot(REVERSE_STRAND, showShading);
+		    feature.setFeatureSlot(reverseSlot6);
+		}
+		else {
+		    feature.setFeatureSlot(reverseSlot6);
+		}	   
+	    }
+	    else {
+	        throw new Exception ("The slot value must be between 1 and 6");
+	    }
+	}
+    }
+
+    private Color getFeatureColor(String type) throws NullPointerException {
+
+        Color colorToReturn = (Color) FEATURE_COLORS.get(type);
+        return colorToReturn;
+    }
+
+    private int getFeatureDecoration(String type, int strand) throws NullPointerException {
+
+        int decoration = DECORATION_STANDARD;
+ 
+	if (strand == DIRECT_STRAND) {
+	    decoration = ((Integer) FEATURE_DECORATIONS_DIRECT.get(type)).intValue();
+	} else {
+	    decoration = ((Integer) FEATURE_DECORATIONS_REVERSE.get(type)).intValue();
+	}
+
+        return decoration;
+
+    }
+
+    private void addItemToLegend(String type) throws NullPointerException {
+	if (!((type.equalsIgnoreCase("forward_gene")) || (type.equalsIgnoreCase("reverse_gene")))) {
+	    DRAW_LEGEND_ITEMS.put(type, new Boolean(true));
+	}
+    }
+
+    /**
+     * Sets whether or not canvas dimension information should be read from the input file.
+     *
+     * @param readDimension whether or not to read the canvas dimension from the input file.
+     */
+    public void setReadDimension(boolean readDimension) {
+	this.readDimension = readDimension;
+    }
+
+    /**
+     * Sets whether or not a warning is shown.
+     *
+     * @param showWarning whether or not a warning is shown.
+     */
+    public void setShowWarning(boolean showWarning) {
+        this.showWarning = showWarning;
+    }
+
+    /**
+     * Sets the width of the map. Use this method before calling createCgviewFromURL() or createCgviewFromFile() to specify the default image width.
+     *
+     * @param width the width of the map.
+     */
+    public void setWidth(int width) {
+	mapWidth = width;
+    }
+
+    /**
+     * Sets the height of the map. Use this method before calling createCgviewFromURL() or createCgviewFromFile() to specify the default image height.
+     *
+     * @param height the height of the map.
+     */
+    public void setHeight(int height) {
+	mapHeight = height;
+    }
+
+    public void setMapItemSizeAdjustment(float adjustment) {
+	mapItemSizeAdjustment = adjustment;
+    }
+
+    /**
+     * Sets the font size of feature labels. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of feature labels.
+     */
+    public void setLabelFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	labelFontSize = size;
+    }
+
+    /**
+     * Sets the font size of the sequence ruler. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of the sequence ruler.
+     */
+    public void setRulerFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	rulerFontSize = size;
+    }
+
+    /**
+     * Sets the font size of legends. Use this method before calling createCgviewFromURL() or createCgviewFromFile().
+     *
+     * @param size the font size of legends.
+     */
+    public void setLegendFontSize(int size) {
+	if (size < 0) {
+	    size = 0;
+	}
+	else if (size > 100) {
+	    size = 100;
+	}
+
+	legendFontSize = size;
+    }
+
+    /**
+     * Sets the tick density.
+     *
+     * @param density a double between 0.0 and 1.0, with 1.0 being more dense.
+     */
+    public void setTickDensity(double density) {
+	if (density < 0.0d) {
+	    density = 0.0d;
+	}
+	else if (density > 1.0d) {
+	    density = 1.0d;
+	}
+
+	this.tickDensity = density;
+    }
+
+
+    private void prepareToDraw() {
+
+
+	Font labelFont;
+	Font titleFont;
+	Font legendFont;
+	Font rulerFont;
+	Font messageFont;
+
+	float featureThickness;
+	float maxFeatureThickness;
+	float backboneThickness;
+	float featureSlotSpacing;
+	float tickLength;
+	float tickThickness;
+	float shortTickThickness;   
+	float labelLineThickness;
+	double labelLineLength;
+	double minimumFeatureLength = 1.0d;
+	double arrowheadLength;
+
+	int giveFeaturePositions;
+	int useInnerLabels;
+	int maxLabels;
+
+	//make changes to the sizes of map items based on the map size
+	//determine size of map compared to default map
+	mapSmallest = Math.min(mapWidth, mapHeight);
+
+	int defaultSmallest = Math.min(((Integer)DEFAULT_MAP_SIZES.get("mapWidth")).intValue(), ((Integer)DEFAULT_MAP_SIZES.get("mapHeight")).intValue());
+
+	float sizeRatio = (float)mapSmallest / (float)defaultSmallest;
+
+	//do fonts
+	int labelFontSize = (int) Math.floor((sizeRatio + mapItemSizeAdjustment)* (float)((Integer)DEFAULT_MAP_SIZES.get("labelFontSize")).intValue() + 0.5f);
+	int titleFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("titleFontSize")).intValue() + 0.5f);
+	int legendFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("legendFontSize")).intValue() + 0.5f);
+	int rulerFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("rulerFontSize")).intValue() + 0.5f);
+	int messageFontSize = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("messageFontSize")).intValue() + 0.5f);
+
+	if (labelFontSize < ((Integer)MIN_MAP_SIZES.get("labelFontSize")).intValue()) {
+	    labelFontSize = ((Integer)MIN_MAP_SIZES.get("labelFontSize")).intValue();
+	}
+	else if (labelFontSize > ((Integer)MAX_MAP_SIZES.get("labelFontSize")).intValue()) {
+	    labelFontSize = ((Integer)MAX_MAP_SIZES.get("labelFontSize")).intValue();
+	}
+
+	if (titleFontSize < ((Integer)MIN_MAP_SIZES.get("titleFontSize")).intValue()) {
+	    titleFontSize = ((Integer)MIN_MAP_SIZES.get("titleFontSize")).intValue();
+	}
+	else if (titleFontSize > ((Integer)MAX_MAP_SIZES.get("titleFontSize")).intValue()) {
+	    titleFontSize = ((Integer)MAX_MAP_SIZES.get("titleFontSize")).intValue();
+	}
+
+	if (legendFontSize < ((Integer)MIN_MAP_SIZES.get("legendFontSize")).intValue()) {
+	    legendFontSize = ((Integer)MIN_MAP_SIZES.get("legendFontSize")).intValue();
+	}
+	else if (legendFontSize > ((Integer)MAX_MAP_SIZES.get("legendFontSize")).intValue()) {
+	    legendFontSize = ((Integer)MAX_MAP_SIZES.get("legendFontSize")).intValue();
+	}
+
+	if (rulerFontSize < ((Integer)MIN_MAP_SIZES.get("rulerFontSize")).intValue()) {
+	    rulerFontSize = ((Integer)MIN_MAP_SIZES.get("rulerFontSize")).intValue();
+	}
+	else if (rulerFontSize > ((Integer)MAX_MAP_SIZES.get("rulerFontSize")).intValue()) {
+	    rulerFontSize = ((Integer)MAX_MAP_SIZES.get("rulerFontSize")).intValue();
+	}
+
+	if (messageFontSize < ((Integer)MIN_MAP_SIZES.get("messageFontSize")).intValue()) {
+	    messageFontSize = ((Integer)MIN_MAP_SIZES.get("messageFontSize")).intValue();
+	}
+	else if (messageFontSize > ((Integer)MAX_MAP_SIZES.get("messageFontSize")).intValue()) {
+	    messageFontSize = ((Integer)MAX_MAP_SIZES.get("messageFontSize")).intValue();
+	}
+
+
+	labelFont = new Font("SansSerif", Font.PLAIN, labelFontSize);
+	titleFont = new Font("SansSerif", Font.PLAIN, titleFontSize);
+	legendFont = new Font("SansSerif", Font.PLAIN, legendFontSize);
+	rulerFont = new Font("SansSerif", Font.PLAIN, rulerFontSize);
+	messageFont = new Font("SansSerif", Font.PLAIN, messageFontSize);
+
+	//check for overriding values
+	if (this.labelFontSize != -1) {
+	    labelFont = new Font("SansSerif", Font.PLAIN, this.labelFontSize);
+	}
+	if (this.rulerFontSize != -1) {
+	    rulerFont = new Font("SansSerif", Font.PLAIN, this.rulerFontSize);
+	}
+	if (this.legendFontSize != -1) {
+	    legendFont = new Font("SansSerif", Font.PLAIN, this.legendFontSize);
+	}
+
+	//do int
+	maxLabels = (int) Math.floor(sizeRatio * (float)((Integer)DEFAULT_MAP_SIZES.get("maxLabels")).intValue() + 0.5f);
+	if (maxLabels < ((Integer)MIN_MAP_SIZES.get("maxLabels")).intValue()) {
+	    maxLabels = ((Integer)MIN_MAP_SIZES.get("maxLabels")).intValue();
+	}
+	else if (maxLabels > ((Integer)MAX_MAP_SIZES.get("maxLabels")).intValue()) {
+	    maxLabels = ((Integer)MAX_MAP_SIZES.get("maxLabels")).intValue();
+	}
+
+	//do float
+	featureThickness = (sizeRatio + mapItemSizeAdjustment) * ((Float)DEFAULT_MAP_SIZES.get("featureThickness")).floatValue();
+
+	//done later
+// 	if (featureThickness < ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue()) {
+// 	    featureThickness = ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue();
+// 	}
+// 	else if (featureThickness > ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue()) {
+// 	    featureThickness = ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue();
+// 	}
+
+	backboneThickness = (sizeRatio + mapItemSizeAdjustment) * ((Float)DEFAULT_MAP_SIZES.get("backboneThickness")).floatValue();
+	if (backboneThickness < ((Float)MIN_MAP_SIZES.get("backboneThickness")).floatValue()) {
+	    backboneThickness = ((Float)MIN_MAP_SIZES.get("backboneThickness")).floatValue();
+	}
+	else if (backboneThickness > ((Float)MAX_MAP_SIZES.get("backboneThickness")).floatValue()) {
+	    backboneThickness = ((Float)MAX_MAP_SIZES.get("backboneThickness")).floatValue();
+	}
+
+	featureSlotSpacing = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("featureSlotSpacing")).floatValue();
+	if (featureSlotSpacing < ((Float)MIN_MAP_SIZES.get("featureSlotSpacing")).floatValue()) {
+	    featureSlotSpacing = ((Float)MIN_MAP_SIZES.get("featureSlotSpacing")).floatValue();
+	}
+	else if (featureSlotSpacing > ((Float)MAX_MAP_SIZES.get("featureSlotSpacing")).floatValue()) {
+	    featureSlotSpacing = ((Float)MAX_MAP_SIZES.get("featureSlotSpacing")).floatValue();
+	}
+
+	tickLength = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("tickLength")).floatValue();
+	if (tickLength < ((Float)MIN_MAP_SIZES.get("tickLength")).floatValue()) {
+	    tickLength = ((Float)MIN_MAP_SIZES.get("tickLength")).floatValue();
+	}
+	else if (tickLength > ((Float)MAX_MAP_SIZES.get("tickLength")).floatValue()) {
+	    tickLength = ((Float)MAX_MAP_SIZES.get("tickLength")).floatValue();
+	}
+
+	tickThickness = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("tickThickness")).floatValue();
+	if (tickThickness < ((Float)MIN_MAP_SIZES.get("tickThickness")).floatValue()) {
+	    tickThickness = ((Float)MIN_MAP_SIZES.get("tickThickness")).floatValue();
+	}
+	else if (tickThickness > ((Float)MAX_MAP_SIZES.get("tickThickness")).floatValue()) {
+	    tickThickness = ((Float)MAX_MAP_SIZES.get("tickThickness")).floatValue();
+	}
+
+	shortTickThickness = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("shortTickThickness")).floatValue();
+	if (shortTickThickness < ((Float)MIN_MAP_SIZES.get("shortTickThickness")).floatValue()) {
+	    shortTickThickness = ((Float)MIN_MAP_SIZES.get("shortTickThickness")).floatValue();
+	}
+	else if (shortTickThickness > ((Float)MAX_MAP_SIZES.get("shortTickThickness")).floatValue()) {
+	    shortTickThickness = ((Float)MAX_MAP_SIZES.get("shortTickThickness")).floatValue();
+	}
+
+	labelLineThickness = sizeRatio * ((Float)DEFAULT_MAP_SIZES.get("labelLineThickness")).floatValue();
+	if (labelLineThickness < ((Float)MIN_MAP_SIZES.get("labelLineThickness")).floatValue()) {
+	    labelLineThickness = ((Float)MIN_MAP_SIZES.get("labelLineThickness")).floatValue();
+	}
+	else if (labelLineThickness > ((Float)MAX_MAP_SIZES.get("labelLineThickness")).floatValue()) {
+	    labelLineThickness = ((Float)MAX_MAP_SIZES.get("labelLineThickness")).floatValue();
+	}
+
+	//do doubles
+	labelLineLength = sizeRatio * ((Double)DEFAULT_MAP_SIZES.get("labelLineLength")).doubleValue();
+	if (labelLineLength < ((Double)MIN_MAP_SIZES.get("labelLineLength")).doubleValue()) {
+	    labelLineLength = ((Double)MIN_MAP_SIZES.get("labelLineLength")).doubleValue();
+	}
+	else if (labelLineLength > ((Double)MAX_MAP_SIZES.get("labelLineLength")).doubleValue()) {
+	    labelLineLength = ((Double)MAX_MAP_SIZES.get("labelLineLength")).doubleValue();
+	}
+
+	arrowheadLength = (sizeRatio + mapItemSizeAdjustment) * ((Double)DEFAULT_MAP_SIZES.get("arrowheadLength")).doubleValue();
+	if (arrowheadLength < ((Double)MIN_MAP_SIZES.get("arrowheadLength")).doubleValue()) {
+	    arrowheadLength = ((Double)MIN_MAP_SIZES.get("arrowheadLength")).doubleValue();
+	}
+	else if (arrowheadLength > ((Double)MAX_MAP_SIZES.get("arrowheadLength")).doubleValue()) {
+	    arrowheadLength = ((Double)MAX_MAP_SIZES.get("arrowheadLength")).doubleValue();
+	}
+   
+
+	//do modal changes
+	if (mapSmallest <= SMALL_MAP_MODE_DIMENSION) {
+	    giveFeaturePositions = ((Integer)SMALL_MAP_MODES.get("giveFeaturePositions")).intValue();
+	    useInnerLabels = ((Integer)SMALL_MAP_MODES.get("useInnerLabels")).intValue();	
+	}
+	else if (mapSmallest >= LARGE_MAP_MODE_DIMENSION) {
+	    giveFeaturePositions = ((Integer)LARGE_MAP_MODES.get("giveFeaturePositions")).intValue();
+	    useInnerLabels = ((Integer)LARGE_MAP_MODES.get("useInnerLabels")).intValue();
+	}
+	else {
+	    giveFeaturePositions = ((Integer)DEFAULT_MAP_MODES.get("giveFeaturePositions")).intValue();
+	    useInnerLabels = ((Integer)DEFAULT_MAP_MODES.get("useInnerLabels")).intValue();
+	}
+
+	//adjust feature thickness based on how many slots are used
+	float growthIncrement = 0.083f * featureThickness;  // 1/12 = 0.083
+	int emptySlots = 0;
+
+        if (forwardSlot1 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot2 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot3 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot4 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot5 == null) {
+	    emptySlots++;
+	}
+        if (forwardSlot6 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot1 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot2 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot3 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot4 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot5 == null) {
+	    emptySlots++;
+	}
+        if (reverseSlot6 == null) {
+	    emptySlots++;
+	}
+
+	featureThickness = featureThickness + (float)emptySlots * growthIncrement;
+
+	if (featureThickness < ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue()) {
+	    featureThickness = ((Float)MIN_MAP_SIZES.get("featureThickness")).floatValue();
+	}
+	else if (featureThickness > ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue()) {
+	    featureThickness = ((Float)MAX_MAP_SIZES.get("featureThickness")).floatValue();
+	}
+
+        if (forwardSlot1 != null) {
+	    forwardSlot1.sortFeaturesByStart();
+            forwardSlot1.setCgview(cgview);
+            forwardSlot1.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot2 != null) {
+	    forwardSlot2.sortFeaturesByStart();
+            forwardSlot2.setCgview(cgview);
+            forwardSlot2.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot3 != null) {
+	    forwardSlot3.sortFeaturesByStart();
+            forwardSlot3.setCgview(cgview);
+            forwardSlot3.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot4 != null) {
+	    forwardSlot4.sortFeaturesByStart();
+            forwardSlot4.setCgview(cgview);
+            forwardSlot4.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot5 != null) {
+	    forwardSlot5.sortFeaturesByStart();
+            forwardSlot5.setCgview(cgview);
+            forwardSlot5.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot6 != null) {
+	    forwardSlot6.sortFeaturesByStart();
+            forwardSlot6.setCgview(cgview);
+            forwardSlot6.setFeatureThickness(featureThickness);
+        }
+
+        if (reverseSlot1 != null) {
+	    reverseSlot1.sortFeaturesByStart();
+            reverseSlot1.setCgview(cgview);
+            reverseSlot1.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot2 != null) {
+	    reverseSlot2.sortFeaturesByStart();
+            reverseSlot2.setCgview(cgview);
+            reverseSlot2.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot3 != null) {
+	    reverseSlot3.sortFeaturesByStart();
+            reverseSlot3.setCgview(cgview);
+            reverseSlot3.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot4 != null) {
+	    reverseSlot4.sortFeaturesByStart();
+            reverseSlot4.setCgview(cgview);
+            reverseSlot4.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot5 != null) {
+	    reverseSlot5.sortFeaturesByStart();
+            reverseSlot5.setCgview(cgview);
+            reverseSlot5.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot6 != null) {
+	    reverseSlot6.sortFeaturesByStart();
+            reverseSlot6.setCgview(cgview);
+            reverseSlot6.setFeatureThickness(featureThickness);
+        }
+
+	cgview.setWidth(mapWidth);
+	cgview.setHeight(mapHeight);
+        cgview.setLabelsToKeep(maxLabels);
+        cgview.setDrawTickMarks(drawTickMarks);
+        cgview.setTitleFont(titleFont);
+        cgview.setLabelFont(labelFont);
+        cgview.setFeatureThickness(featureThickness);
+        cgview.setBackboneThickness(backboneThickness);
+        cgview.setFeatureSlotSpacing(featureSlotSpacing);
+	cgview.setMinimumFeatureLength(minimumFeatureLength);
+        cgview.setLegendFont(legendFont);
+        cgview.setTickLength(tickLength);
+	cgview.setTickThickness(tickThickness);
+	cgview.setShortTickThickness(shortTickThickness);
+	cgview.setLabelLineThickness(labelLineThickness);
+        cgview.setLabelLineLength(labelLineLength);
+        cgview.setLabelPlacementQuality(labelPlacementQuality);
+        cgview.setUseColoredLabelBackgrounds(useColoredLabelBackground);
+        cgview.setShowBorder(showBorder);
+        cgview.setShowShading(showShading);
+	cgview.setGiveFeaturePositions(giveFeaturePositions);
+        cgview.setShadingProportion(shadingProportion);
+        cgview.setUseInnerLabels(useInnerLabels);
+        cgview.setMoveInnerLabelsToOuter(moveInnerLabelsToOuter);
+        cgview.setWarningFont(rulerFont);
+        cgview.setRulerFont(rulerFont);
+	cgview.setArrowheadLength(arrowheadLength);
+	cgview.setHighlightOpacity(shadingOpacity);
+	cgview.setShadowOpacity(shadingOpacity);
+
+	cgview.setTickDensity(tickDensity);
+
+        //if not drawing labels, don't show message.
+        if (!(showLabels)) {
+            cgview.setShowWarning(false);
+        }
+
+        //set backboneRadius based on smallest image dimension
+	cgview.setSequenceLength(length);
+	mapSmallest = Math.min(mapWidth, mapHeight);
+	cgview.setBackboneRadius(0.50d * (double) mapSmallest / 1.9d);	
+
+        //check coloredLabels
+        if (!(useColoredLabels)) {
+	    cgview.setGlobalLabelColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+        }
+
+        //set map item colors
+	cgview.setLongTickColor((Color) MAP_ITEM_COLORS.get("tick"));
+	cgview.setShortTickColor((Color) MAP_ITEM_COLORS.get("partialTick"));
+	cgview.setZeroTickColor((Color) MAP_ITEM_COLORS.get("zeroLine"));
+	cgview.setRulerFontColor((Color) MAP_ITEM_COLORS.get("rulerFont"));
+	cgview.setBackboneColor((Color) MAP_ITEM_COLORS.get("backbone"));
+	cgview.setTitleFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+	cgview.setWarningFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+	cgview.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+ 
+
+        //build legend
+        if (showLegend) {
+            //create legend
+            legend = new Legend(cgview);
+            legend.setAllowLabelClash(allowLabelClashLegend);
+            legend.setBackgroundOpacity(0.5f);
+            legend.setFont(legendFont);
+	    //legend.setFont(labelFont);
+            legend.setPosition(legendPosition);
+
+            legend.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+            legend.setFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+
+            LegendItem legendItem;
+
+            Enumeration legendEntries = DRAW_LEGEND_ITEMS.keys();
+            ArrayList list = new ArrayList();
+            while (legendEntries.hasMoreElements()) {
+                list.add(legendEntries.nextElement());
+            }
+            Collections.sort(list);
+
+	    list.add(0, "reverse_gene");
+	    list.add(0, "forward_gene");
+
+            Iterator i = list.iterator();
+
+            while (i.hasNext()) {
+                String key = (String) i.next();
+                legendItem = new LegendItem(legend);
+                legendItem.setLabel((String) LEGEND_ITEM_NAMES.get(key));
+                legendItem.setSwatchColor((Color) FEATURE_COLORS.get(key));
+		legendItem.setDrawSwatch(SWATCH_SHOW);
+            }
+        }
+
+        //send settings to cgview
+        if (showTitle) {
+	    if (title.length() > MAX_TITLE_LENGTH) {
+		title = title.substring(0, MAX_TITLE_LENGTH) + "...";
+	    }
+	    legend = new Legend(cgview);
+	    legend.setAllowLabelClash(allowLabelClashLegend);
+	    legend.setBackgroundOpacity(0.5f);
+	    legend.setFont(legendFont);
+	    legend.setPosition(LEGEND_LOWER_CENTER);
+	    LegendItem legendItem = new LegendItem(legend);
+	    legendItem.setLabel(title);
+	    legendItem.setDrawSwatch(SWATCH_NO_SHOW);
+        }
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewHTMLDocument.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewHTMLDocument.class
new file mode 100644
index 0000000..4d86ddf
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewHTMLDocument.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewHTMLDocument.java b/cgview/src/ca/ualberta/stothard/cgview/CgviewHTMLDocument.java
new file mode 100644
index 0000000..a7b284a
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/CgviewHTMLDocument.java
@@ -0,0 +1,370 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.geom.*;
+import java.util.*;
+
+import org.apache.commons.lang.StringEscapeUtils;
+
+
+/**
+ * This class contains methods for constructing HTML pages that contain Cgview maps. Tags are added to the document in
+ * the order that the various tag adding methods are called. The methods in this class escape all supplied text to make
+ * it suitable for inclusion in an HTML document.
+ *
+ * @author Paul Stothard
+ */
+
+public class CgviewHTMLDocument implements CgviewConstants {
+
+    private ArrayList contents;
+    private String newline;
+
+    /**
+     * Constructs a new CgviewHTMLDocument object.
+     */
+    public CgviewHTMLDocument() {
+        contents = new ArrayList();   
+	newline = System.getProperty("line.separator");     
+    }
+
+    /**
+     * Adds header information to this CgviewHTMLDocument, including an html opening tag. This method should be the
+     * first method called after a CgviewHTMLDocument is created.
+     *
+     * @param title       the title in the header.
+     * @param zoom        the value to appear in the 'zoom' meta tag.
+     * @param zoomCenter  the value to appear in the 'zoomCenter' meta tag.
+     * @param imageFormat the format of the image to which this CgviewHTMLDocument refers.
+     * @param useOverlib  whether or not to use the overlib.js JavaScript library for PNG and JPG image maps.
+     * @param useExternalStyleSheet  whether or not to use an external stylesheet.
+     */
+    public void addHeader(String title, String zoom, String zoomCenter, String imageFormat, Boolean useOverlib, Boolean useExternalStyleSheet) {
+        contents.add("<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">" + newline);
+        contents.add("<html lang=\"en\">" + newline);
+        contents.add("<head>" + newline);
+        contents.add("<title>" + StringEscapeUtils.escapeHtml(title) + "</title>" + newline);
+        //contents.add("<meta name=\"mapInfo\" zoom=\"" + StringEscapeUtils.escapeHtml(zoom) + "\" />" + newline);
+        //contents.add("<meta name=\"mapInfo\" zoomCenter=\"" + StringEscapeUtils.escapeHtml(zoomCenter) + "\" />" + newline);
+        //contents.add("<meta name=\"mapInfo\" format=\"" + StringEscapeUtils.escapeHtml(imageFormat) + "\" />" + newline);
+        contents.add("<meta http-equiv=\"Content-Type\" content=\"text/html; charset=ISO-8859-1\" />" + newline);
+        if ((useExternalStyleSheet != null) && (useExternalStyleSheet.booleanValue())) {
+            contents.add("<link rel=\"stylesheet\" href=\"includes/stylesheet.css\" type=\"text/css\" />" + newline);
+        } else {
+            contents.add("<style type=\"text/css\">" + newline);
+            contents.add("body {background-color: #FFFFFF; font-family: arial, sans-serif; color: #000000}" + newline);
+            contents.add("span.note {font-size: small; font-style: italic}" + newline);
+            contents.add("span.validInfo {font-size: x-small}" + newline);
+            contents.add("span.fileSize {font-size: x-small}" + newline);
+            contents.add("span.warning {font-size: x-small; color: red}" + newline);
+            contents.add("div.heading {color: #FFFFFF; background-color: #6666FF; font-size: large; padding: 0.1cm}" + newline);
+            contents.add("div.title {font-size: x-large; text-align: center}" + newline);
+            contents.add("table.noBorder {border-style: none}" + newline);
+            contents.add("table.border {border-style: solid}" + newline);
+            contents.add("td.center {text-align: center; font-size: small}" + newline);
+            contents.add("td.left {text-align: left; font-size: small}" + newline);
+            contents.add("td.right {text-align: right; font-size: small}" + newline);
+            contents.add("a:link {color: #000099; text-decoration: none}" + newline);
+            contents.add("a:visited {color: #000099; text-decoration: none}" + newline);
+            contents.add("a:active {color: #FF0000; text-decoration: underline}" + newline);
+            contents.add("a:hover {color: #FF0000; text-decoration: underline}" + newline);
+            contents.add("</style>" + newline);
+        }      
+
+	if ((useOverlib != null) && ((useOverlib.booleanValue()) && ((imageFormat.equalsIgnoreCase("png")) || (imageFormat.equalsIgnoreCase("jpg"))))) {
+            contents.add("<script type=\"text/javascript\" src=\"includes/overlib.js\"><!-- overLIB (c) Erik Bosrup --></script>" + newline);	    
+	}
+        contents.add("</head>" + newline);
+        contents.add("<body>" + newline);
+	if ((useOverlib != null) && ((useOverlib.booleanValue()) && ((imageFormat.equalsIgnoreCase("png")) || (imageFormat.equalsIgnoreCase("jpg"))))) {
+            contents.add("<div id=\"overDiv\" style=\"position:absolute; visibility:hidden; z-index:1000;\"></div>" + newline);  
+	}
+
+    }
+
+    /**
+     * Adds table and tbody opening tags to this CgviewHTMLDocument.
+     *
+     * @param width the width of the table in pixels.
+     */
+    public void addTableStart(int width) {
+	addTableStart(width, 0);
+    }
+
+    /**
+     * Adds table and tbody opening tags to this CgviewHTMLDocument.
+     *
+     * @param width the width of the table in pixels.
+     * @param border the width of the border in pixels.
+     */
+    public void addTableStart(int width, int border) {
+	if (border == 0) {
+	    contents.add("<table class=\"noBorder\" width=\"" + Integer.toString(width) + "\" cellspacing=\"0\" cellpadding=\"1\" align=\"left\">" + newline);
+	}
+	else {
+	    contents.add("<table class=\"border\" width=\"" + Integer.toString(width) + "\" border=\"" + border + "\" cellspacing=\"0\" cellpadding=\"1\" align=\"left\">" + newline);
+	}
+        contents.add("<tbody>" + newline);
+    }
+
+    /**
+     * Adds table and tbody closing tags to this CgviewHTMLDocument.
+     */
+    public void addTableEnd() {
+        contents.add("</tbody>" + newline);
+        contents.add("</table>" + newline);
+    }
+
+    /**
+     * Adds tr opening tag to this CgviewHTMLDocument.
+     */
+    public void addTableRowStart() {
+        contents.add("<tr>" + newline);
+    }
+
+    /**
+     * Adds tr closing tag to this CgviewHTMLDocument.
+     */
+    public void addTableRowEnd() {
+        contents.add("</tr>" + newline);
+    }
+
+    /**
+     * Adds td opening tag to this CgviewHTMLDocument.
+     */
+    public void addTableColumnStart() {
+        contents.add("<td>" + newline);
+    }
+
+    /**
+     * Adds td opening tag with center alignment to this CgviewHTMLDocument.
+     */
+    public void addTableColumnCenterStart() {
+        contents.add("<td class=\"center\">" + newline);
+    }
+
+    /**
+     * Adds td opening tag with left alignment to this CgviewHTMLDocument.
+     */
+    public void addTableColumnLeftStart() {
+        contents.add("<td class=\"left\">" + newline);
+    }
+
+    /**
+     * Adds td opening tag with right alignment to this CgviewHTMLDocument.
+     */
+    public void addTableColumnRightStart() {
+        contents.add("<td class=\"right\">" + newline);
+    }
+
+    /**
+     * Adds td closing tag to this CgviewHTMLDocument.
+     */
+    public void addTableColumnEnd() {
+        contents.add("</td>" + newline);
+    }
+
+    /**
+     * Adds text to this CgviewHTMLDocument stating that the document is valid XHTML 1.0 and valid CSS.
+     */
+    public void addValidationInfo() {
+        contents.add("Valid XHTML 1.0;");
+        contents.add(" ");
+        contents.add("Valid CSS.");
+    }
+
+    /**
+     * Adds body and html closing tags to this CgviewHTMLDocument. This method should be the last method called before
+     * the contents of this document are retrieved using {@link #getContents()}.
+     */
+    public void addFooter() {
+        contents.add("</body>" + newline);
+        contents.add("</html>" + newline);
+    }
+
+    /**
+     * Adds a span opening tag with the 'note' style to this CgviewHTMLDocument.
+     */
+    public void addSpanNoteStart() {
+        contents.add("<span class=\"note\">" + newline);
+    }
+
+    /**
+     * Adds a span opening tag with the 'fileSize' style to this CgviewHTMLDocument.
+     */
+    public void addSpanFileSizeStart() {
+        contents.add("<span class=\"fileSize\">" + newline);
+    }
+
+    /**
+     * Adds a span opening tag with the 'validInfo' style to this CgviewHTMLDocument.
+     */
+    public void addSpanValidStart() {
+        contents.add("<span class=\"validInfo\">" + newline);
+    }
+
+    /**
+     * Adds a span opening tag with the 'warning' style to this CgviewHTMLDocument.
+     */
+    public void addSpanWarningStart() {
+        contents.add("<span class=\"warning\">" + newline);
+    }
+
+    /**
+     * Adds a span closing tag to this CgviewHTMLDocument.
+     */
+    public void addSpanEnd() {
+        contents.add("</span>" + newline);
+    }
+
+    /**
+     * Adds an image with an image map to this CgviewHTMLDocument, to implement mouseovers and hyperlinks associated
+     * with Cgview Feature objects and FeatureRange objects. Image maps are used for PNG and JPG maps. SVG maps contain
+     * the mouseover and hyperlink information internally.
+     *
+     * @param imageFile   the image URL that the image map refers to.
+     * @param width       the width of the image.
+     * @param height      the height of the image.
+     * @param labelBounds an ArrayList of LabelBounds objects, obtained from a previously drawn Cgview object using the
+     *                    {@link Cgview#getLabelBounds()} method.
+     * @param useOverlib whether or not to use the overlib.js JavaScript library for PNG and JPG image maps.
+     */
+    public void addImageMap(String imageFile, int width, int height, ArrayList labelBounds, Boolean useOverlib) {
+        contents.add("<img style=\"border:0\" src=\"" + StringEscapeUtils.escapeHtml(imageFile) + "\" width=\"" + Integer.toString(width) + "\" height=\"" + Integer.toString(height) + "\" usemap=\"#cgviewmap\" />" + newline);
+        contents.add("<map id=\"cgviewmap\" name=\"cgviewmap\">" + newline);
+
+        //add areas
+        Iterator i;
+        i = labelBounds.iterator();
+        while (i.hasNext()) {
+
+            LabelBounds currentLabelBounds = (LabelBounds) i.next();
+            Rectangle2D bounds = currentLabelBounds.getBounds();
+            if ((currentLabelBounds.getUse() == true) && ((currentLabelBounds.getMouseover() != null) || (currentLabelBounds.getHyperlink() != null))) {
+
+                contents.add("<area shape=\"rect\" coords=\"" + Integer.toString((int) Math.floor(bounds.getX() + 0.5d)) + "," + Integer.toString((int) Math.floor(bounds.getY() + 0.5d)) + "," + Integer.toString((int) Math.floor(bounds.getX() + 0.5d) + (int) Math.floor(bounds.getWidth() + 0.5d)) + "," + Integer.toString((int) Math.floor(bounds.getY() + 0.5d) + (int) Math.floor(bounds.getHeight() + 0.5d)) + "\" ");
+
+                if (currentLabelBounds.getHyperlink() != null) {
+                    contents.add("href=\"" + currentLabelBounds.getHyperlink() + "\" ");
+                }
+
+                if ((currentLabelBounds.getMouseover() != null) && (!(currentLabelBounds.getMouseover().matches("\\S*")))) {
+		    if ((useOverlib != null) && (useOverlib.booleanValue())) {
+			contents.add("onmouseover=\"return overlib('" + StringEscapeUtils.escapeJavaScript(currentLabelBounds.getMouseover()) + "');\" ");
+			contents.add("onmouseout=\"return nd();\" ");
+		    }
+		    else {
+			contents.add("onmouseover=\"self.status='" + StringEscapeUtils.escapeJavaScript(currentLabelBounds.getMouseover()) + "'; return true;\" ");
+			contents.add("onmouseout=\"self.status=' '; return true;\" ");
+		    }
+                }
+                contents.add("/>" + newline);
+            }
+
+        }
+        contents.add("</map>" + newline);
+    }
+
+    /**
+     * Adds an image to this CgviewHTMLDocument. Use this method for adding a JPG or PNG image to a CgviewHTMLDocument.
+     * To add an SVG image use {@link #addSVG}.
+     *
+     * @param imageFile the image URL.
+     * @param width     the width of the image.
+     * @param height    the height of the image.
+     */
+    public void addImage(String imageFile, int width, int height) {
+        addImage(imageFile, width, height, "map");
+    }
+
+    /**
+     * Adds an image to this CgviewHTMLDocument. Use this method for adding a JPG or PNG image to a CgviewHTMLDocument.
+     * To add an SVG image use {@link #addSVG}.
+     *
+     * @param imageFile the image URL.
+     * @param width     the width of the image.
+     * @param height    the height of the image.
+     * @param alt       alternate text for the image
+     */
+    public void addImage(String imageFile, int width, int height, String alt) {
+        contents.add("<img style=\"border:0\" src=\"" + StringEscapeUtils.escapeHtml(imageFile) + "\" width=\"" + Integer.toString(width) + "\" height=\"" + Integer.toString(height) + "\" alt=\"" + StringEscapeUtils.escapeHtml(alt) + "\" />" + newline);
+    }
+
+    /**
+     * Adds an image of a button to this CgviewHTMLDocument and links the button to another file.
+     *
+     * @param imageFile the button image URL.
+     * @param linkFile  the URL to be linked to the button.
+     * @param altText   a short description of the image.
+     */
+    public void addButton(String imageFile, String linkFile, String altText) {
+        contents.add("<a href=\"" + StringEscapeUtils.escapeHtml(linkFile) + "\">");
+        contents.add("<img style=\"border:0\" src=\"" + StringEscapeUtils.escapeHtml(imageFile) + "\" alt=\"" + StringEscapeUtils.escapeHtml(altText) + "\" />");
+        contents.add("</a>" + newline);
+    }
+
+    /**
+     * Adds an image of a button to this CgviewHTMLDocument.
+     *
+     * @param imageFile the button image URL.
+     * @param altText   a short description of the image.
+     */
+    public void addButtonNoLink(String imageFile, String altText) {
+        contents.add("<img style=\"border:0\" src=\"" + StringEscapeUtils.escapeHtml(imageFile) + "\" alt=\"" + StringEscapeUtils.escapeHtml(altText) + "\" />" + newline);
+    }
+
+    /**
+     * Adds an SVG image to this CgviewHTMLDocument.
+     *
+     * @param imageFile the SVG image URL.
+     * @param width     the width of the SVG image.
+     * @param height    the height of the SVG image.
+     */
+    public void addSVG(String imageFile, int width, int height) {
+	//contents.add("<embed src=\"" + StringEscapeUtils.escapeHtml(imageFile) + "\" type=\"image/svg+xml\" pluginspage=\"http://www.adobe.com/svg/viewer/install/\" width=\"" + Integer.toString(width) + "\" height=\"" + Integer.toString(height) + "\" />" + newline);
+
+	contents.add("<object data=\"" + StringEscapeUtils.escapeHtml(imageFile) + "\" type=\"image/svg+xml\" width=\"" + Integer.toString(width) + "\" height=\"" + Integer.toString(height) + "\" />" + newline);
+    }
+
+    /**
+     * Adds a br tag to this CgviewHTMLDocument.
+     */
+    public void addBreak() {
+        contents.add("<br />" + newline);
+    }
+
+    /**
+     * Adds a non-breaking space to this CgviewHTMLDocument.
+     */
+    public void addSpace() {
+        contents.add(" ");
+    }
+
+    /**
+     * Adds a hyperlink to this CgviewHTMLDocument.
+     *
+     * @param name the text to appear in the link.
+     * @param link the link URL.
+     */
+    public void addLink(String name, String link) {
+        contents.add("<a href=\"" + StringEscapeUtils.escapeHtml(link) + "\">" + StringEscapeUtils.escapeHtml(name) + "</a>" + newline);
+    }
+
+    /**
+     * Adds text to this CgviewHTMLDocument.
+     *
+     * @param text
+     */
+    public void addText(String text) {
+        contents.add(StringEscapeUtils.escapeHtml(text) + "" + newline);
+    }
+
+    /**
+     * Returns the contents of this CgviewHTMLDocument.
+     *
+     * @return an ArrayList of the entries in this CgviewHTMLDocument.
+     */
+    public ArrayList getContents() {
+        return contents;
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewIO.class b/cgview/src/ca/ualberta/stothard/cgview/CgviewIO.class
new file mode 100644
index 0000000..87d8b77
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/CgviewIO.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/CgviewIO.java b/cgview/src/ca/ualberta/stothard/cgview/CgviewIO.java
new file mode 100644
index 0000000..c06d6ee
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/CgviewIO.java
@@ -0,0 +1,1713 @@
+package ca.ualberta.stothard.cgview;
+
+import java.io.*;
+import java.lang.Integer;
+import javax.imageio.*;
+import java.awt.image.*;
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.*;
+import java.text.NumberFormat;
+
+//string escape
+import org.apache.commons.lang.StringEscapeUtils;
+
+//command line processing
+import jargs.gnu.CmdLineParser;
+
+//xml
+//import org.apache.xerces.parsers.SAXParser;
+import org.xml.sax.*;
+//import org.xml.sax.helpers.*;
+
+//svg
+import org.apache.batik.svggen.SVGGeneratorContext;
+import org.apache.batik.svggen.SVGGraphics2D;
+import org.apache.batik.svggen.SVGGraphics2DIOException;
+import org.apache.batik.dom.GenericDOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+//import org.w3c.dom.NodeList;
+import org.w3c.dom.CDATASection;
+import org.w3c.dom.Text;
+import org.w3c.dom.DOMImplementation;
+//import org.apache.batik.ext.awt.g2d.*;
+
+//gzip
+import java.util.zip.*;
+
+/**
+ * This class contains static methods for converting Cgview objects to image files. Images can be generated in PNG, JPG,
+ * SVG, and SVGZ (gzipped SVG) formats.
+ *
+ * @author Paul Stothard
+ */
+
+public class CgviewIO implements CgviewConstants {
+
+    private static String outputDirectory;
+    
+    private static Integer legendValue;
+    private static Boolean useOverlibValue;
+    private static Integer heightValue;
+    private static Integer widthValue;
+    private static Boolean excludeSVGValue;
+    private static Boolean useExternalStylesheetValue;
+    private static Integer useInnerLabelsValue;
+    private static Boolean removeLabelsValue;
+    private static Boolean removeLegendsValue;
+    private static String seriesValue;
+    private static String seriesNumbersValue;
+
+    private static Boolean embedFontsValue;
+
+    private static Integer legendFontValue;
+    private static Integer rulerFontValue;
+    private static Integer labelFontValue;
+
+    private static Double tickDensityValue;
+
+    private final static String PROBLEM_MESSAGE = "The following error occurred: ";
+
+    private final static String INCLUDES_PATH = "includes";
+
+    private final static String INCLUDES_OUT_PATH = "includes";
+    private final static String PNG_OUT_PATH = "png";
+    private final static String SVG_OUT_PATH = "svg";
+
+    private final static String ZOOM_IN_BUTTON = "expand_in.png";
+    private final static String ZOOM_IN_BUTTON_OFF = "expand_in_g.png";
+
+    private final static String ZOOM_OUT_BUTTON = "expand_out.png";
+    private final static String ZOOM_OUT_BUTTON_OFF = "expand_out_g.png";
+
+    private final static String INDEX_BUTTON = "full.png";
+    private final static String INDEX_BUTTON_OFF = "full_g.png";
+
+    private final static String MOVE_FORWARD_BUTTON = "move_forward.png";
+    private final static String MOVE_FORWARD_BUTTON_OFF = "move_forward_g.png";
+
+    private final static String MOVE_BACK_BUTTON = "move_back.png";
+    private final static String MOVE_BACK_BUTTON_OFF = "move_back_g.png";
+
+    private final static String TO_SVG_BUTTON = "as_svg.png";
+    private final static String TO_PNG_BUTTON = "as_png.png";
+
+    private final static String HELP_BUTTON = "help.png";
+
+    private final static String HELP_FILE = "help.html";
+    private final static String HELP_FILE_PNG = "help_png.html";
+    private final static String STYLE_FILE = "stylesheet.css";
+    private final static String SVG_JAVASCRIPT = "info.js";
+
+    private final static String OVERLIB_JAVASCRIPT = "overlib.js";
+
+    private final static String EXTERNAL_LEGEND = "legend.png";
+
+    private static void printUsage() {
+        System.err.println("usage: java -jar cgview.jar [OPTION]...");
+        System.err.println("-A <integer> Specifies a label font size.");
+        System.err.println("-c <integer> Specifies the base to center on when zooming.");
+        System.err.println("-D <integer> Specifies a legend font size.");
+        System.err.println("-d <real> Specifies tick density, between 0 and 1.0. Default is 1.0.");
+        System.err.println("-E <boolean> Whether or not to embed vector-based text in SVG output.");	
+        System.err.println("-e <boolean> Whether or not to exclude SVG output from image series.");
+        System.err.println("-f <format> The format of the output: PNG, JPG, SVG, or SVGZ.");
+        System.err.println("-h <file> HTML file to create.");
+        System.err.println("-H <integer> The height of the map.");
+        System.err.println("-i <file> The input file to parse.");
+	System.err.println("-I <boolean> Whether or not to draw labels on the inside of the backbone circle.");
+        System.err.println("-L <integer> The width of an external legend.");
+        System.err.println("-o <file> The image file to create.");
+        System.err.println("-p <path> The path to the image file in the HTML file created using the -h option.");
+        System.err.println("-r <boolean> Whether or not to remove legends.");
+        System.err.println("-R <boolean> Whether or not to remove labels.");
+        System.err.println("-s <directory> Directory to receive an image series.");
+        System.err.println("-S <boolean> Whether or not to reference external stylesheet in HTML output.");
+        System.err.println("-u <boolean> Whether or not to reference overlib.js in HTML output.");
+        System.err.println("-U <integer> Specifies a sequence ruler font size.");
+        System.err.println("-W <integer> The width of the map.");
+        System.err.println("-x <string> Comma separated zoom values for image series.");
+        System.err.println("-z <real> The factor to zoom in by.");
+        System.err.println("Example usage: java -jar cgview.jar -f png -i cybercell.xml -o my_picture.png -h view_image.html.");
+        System.err.println("Example usage: java -jar cgview.jar -i cybercell.xml -s directory_for_series -e true.");
+    }
+
+    /**
+     * Writes a Cgview object to a SVG or a SVGZ file. Any mouseover or hyperlink information associated with the Cgview
+     * object is embedded directly in the SVG.
+     *
+     * @param cgview         the Cgview object.
+     * @param filename       the file to create.
+     * @param embedFonts     whether or not to embed fonts in the SVG. Embedded fonts produce a much nicer map but yield
+     *                       a larger file.
+     * @param useCompression whether or not to generate compressed SVG (SVGZ).
+     * @param nextZoomValue  the zoom value of the next Cgview map to draw in the series, or <code>0</code> if there is
+     *                       not another Cgview in the series.
+     * @param keepLastLabels whether or not to use labels generated by a previous call to one of the Cgview objects
+     *                       draw() or drawZoomed() methods.
+     * @throws FileNotFoundException
+     * @throws IOException
+     * @throws UnsupportedEncodingException
+     * @throws SVGGraphics2DIOException
+     */
+    private static void writeToSVGFile(Cgview cgview, String filename, boolean embedFonts, boolean useCompression, int nextZoomValue, boolean keepLastLabels) throws FileNotFoundException, IOException, UnsupportedEncodingException, SVGGraphics2DIOException {
+
+        DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
+
+        // Create an instance of org.w3c.dom.Document
+        Document document = domImpl.createDocument(null, "svg", null);
+        //String svgNS = "http://www.w3.org/2000/svg";
+
+        SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
+        ctx.setComment("Generated by CGView (written by Paul Stothard, University of Alberta) using the Batik SVG Generator");
+        ctx.setPrecision(12);
+
+        SVGGraphics2D graphics2D;
+
+        if (embedFonts) {
+            graphics2D = new SVGGraphics2D(ctx, true);
+        } else {
+            graphics2D = new SVGGraphics2D(ctx, false);
+        }
+
+        try {
+            if (cgview.getDesiredZoom() > 1.0d) {
+                cgview.drawZoomed(graphics2D, cgview.getDesiredZoom(), cgview.getDesiredZoomCenter(), keepLastLabels);
+            } else {
+                cgview.draw(graphics2D, keepLastLabels);
+            }
+
+            //try adding some custom tags to the document
+            //get the root element
+
+            Element root = graphics2D.getRoot();
+            //set width and height attributes
+            root.setAttributeNS(null, "width", Integer.toString(cgview.getWidth()));
+            root.setAttributeNS(null, "height", Integer.toString(cgview.getHeight()));
+
+            Document factory = graphics2D.getDOMFactory();
+
+            ArrayList labelBounds = cgview.getLabelBounds();
+            Iterator i;
+
+            boolean hasMouseover = false;
+            //if hasMouseover add javascript
+            i = labelBounds.iterator();
+            while (i.hasNext()) {
+                LabelBounds currentLabelBounds = (LabelBounds) i.next();
+                if ((currentLabelBounds.getUse() == true) && ((currentLabelBounds.getMouseover() != null) || ((currentLabelBounds.getType() == BOUNDS_RULER) && (nextZoomValue > 0)))) {
+                    hasMouseover = true;
+                }
+            }
+
+            if (hasMouseover) {
+
+		
+		Element script = factory.createElementNS(null, "script");
+		//-1 indicates that image is not part of an image series and thus javascript should
+		//be embedded in the svg rather than linked to an includes directory
+
+
+		if (nextZoomValue == -1) {
+		    String javascript = "//Written by Paul Stothard, University of Alberta, Canada 2004\nfunction showMouseover(evt, message) {var PADDING = 8; var X_SHIFT = 20; var Y_SHIFT = 20; var svgDoc = evt.target.ownerDocument; var translateX = svgDoc.rootElement.currentTranslate.x; var translateY = svgDoc.rootElement.currentTranslate.y; var scale = 1 / svgDoc.rootElement.currentScale; var effectiveDocWidth = svgDoc.rootElement.getAttribute(\"width\") - translateX; var effectiveDocHeight = svgD [...]
+		    //create CDATA section
+		    script.setAttributeNS(null, "type", "text/javascript");
+		    CDATASection cdata = factory.createCDATASection(javascript);
+		    script.appendChild(cdata); 
+		}
+		else {
+		    script.setAttributeNS(null, "type", "text/javascript");
+		    script.setAttributeNS(null, "xlink:href", "../" + INCLUDES_PATH + "/" + SVG_JAVASCRIPT);
+		}
+
+                //add javascript element to root
+                root.appendChild(script);
+
+                //create a background for the mouseoverBox
+                Element mouseoverBoxBackground = factory.createElementNS(null, "rect");
+                mouseoverBoxBackground.setAttributeNS(null, "id", "mouseoverBoxBackground");
+                mouseoverBoxBackground.setAttributeNS(null, "x", "0");
+                mouseoverBoxBackground.setAttributeNS(null, "y", "0");
+                mouseoverBoxBackground.setAttributeNS(null, "width", "0");
+                mouseoverBoxBackground.setAttributeNS(null, "height", "0");
+                mouseoverBoxBackground.setAttributeNS(null, "style", "fill: rgb(204,204,255); stroke: rgb(51,51,153); stroke-width:1");
+
+                //add background element to root
+                root.appendChild(mouseoverBoxBackground);
+
+                //add a text element to show the mouseover text
+                Element mouseoverBox = factory.createElementNS(null, "text");
+                mouseoverBox.setAttributeNS(null, "id", "mouseoverBox");
+                mouseoverBox.setAttributeNS(null, "x", "0");
+                mouseoverBox.setAttributeNS(null, "y", "0");
+                mouseoverBox.setAttributeNS(null, "style", "fill:black; stroke:none; font-family:Arial; font-size:12");
+
+                //add a text node to the element
+                Text text = factory.createTextNode(" ");
+                mouseoverBox.appendChild(text);
+
+                //add mouseoverBox element to root
+                root.appendChild(mouseoverBox);
+            }
+
+            i = labelBounds.iterator();
+
+            NumberFormat nf = NumberFormat.getInstance();
+
+            while (i.hasNext()) {
+                LabelBounds currentLabelBounds = (LabelBounds) i.next();
+                Rectangle2D bounds = currentLabelBounds.getBounds();
+
+                if ((nextZoomValue > 0) && (currentLabelBounds.getType() == BOUNDS_RULER)) {
+                    currentLabelBounds.setHyperlink("../" + Integer.toString(nextZoomValue) + "_" + Integer.toString(currentLabelBounds.getBase()) + ".html");
+                    currentLabelBounds.setMouseover("expand " + nf.format((long) currentLabelBounds.getBase()) + " bp region");
+                }
+
+                if ((currentLabelBounds.getUse() == true) && ((currentLabelBounds.getMouseover() != null) || (currentLabelBounds.getHyperlink() != null))) {
+
+                    Element rectangle = factory.createElementNS(null, "rect");
+                    rectangle.setAttributeNS(null, "x", Double.toString(bounds.getX()));
+                    rectangle.setAttributeNS(null, "y", Double.toString(bounds.getY()));
+                    rectangle.setAttributeNS(null, "width", Double.toString(bounds.getWidth()));
+                    rectangle.setAttributeNS(null, "height", Double.toString(bounds.getHeight()));
+                    rectangle.setAttributeNS(null, "style", "fill:none; stroke:none");
+                    rectangle.setAttributeNS(null, "pointer-events", "fill");
+
+                    if ((currentLabelBounds.getMouseover() != null) && (!(currentLabelBounds.getMouseover().matches("\\S*")))) {
+                        rectangle.setAttributeNS(null, "onmouseover", "showMouseover(evt, \"" + StringEscapeUtils.escapeXml(currentLabelBounds.getMouseover()) + "\")");
+                        rectangle.setAttributeNS(null, "onmouseout", "showMouseout(evt)");
+                    }
+
+                    if (currentLabelBounds.getHyperlink() != null) {
+                        //create hyperlink element
+                        Element hyperlink = factory.createElementNS(null, "a");
+                        hyperlink.setAttributeNS(null, "xlink:href", StringEscapeUtils.escapeXml(currentLabelBounds.getHyperlink()));
+                        hyperlink.appendChild(rectangle);
+                        root.appendChild(hyperlink);
+                    } else {
+                        root.appendChild(rectangle);
+                    }
+
+                }
+            }
+
+            System.out.println("Writing picture to " + filename);
+            boolean useCSS = true;
+
+            FileOutputStream fileOutputStream = new FileOutputStream(new File(filename));
+
+            if (useCompression) {
+                GZIPOutputStream gzipOut = new GZIPOutputStream(fileOutputStream);
+                Writer out = new OutputStreamWriter(gzipOut, "UTF-8");
+                //graphics2D.stream(out, useCSS);
+                graphics2D.stream(root, out, useCSS);
+                out.flush();
+                gzipOut.flush();
+                out.close();
+                gzipOut.close();
+            } else {
+                Writer out = new OutputStreamWriter(fileOutputStream, "UTF-8");
+                //graphics2D.stream(out, useCSS);
+                graphics2D.stream(root, out, useCSS);
+                out.flush();
+                out.close();
+            }
+        } finally {
+            graphics2D.dispose();
+        }
+    }
+
+    /**
+     * Writes a Cgview object to a SVG or a SVGZ file. Any mouseover or hyperlink information associated with the Cgview
+     * object is embedded directly in the SVG.
+     *
+     * @param cgview         the Cgview object.
+     * @param filename       the file to create.
+     * @param embedFonts     whether or not to embed fonts in the SVG. Embedded fonts produce a much nicer map but yield
+     *                       a larger file.
+     * @param useCompression whether or not to generate compressed SVG (SVGZ).
+     * @throws FileNotFoundException
+     * @throws IOException
+     * @throws UnsupportedEncodingException
+     * @throws SVGGraphics2DIOException
+     */
+    public static void writeToSVGFile(Cgview cgview, String filename, boolean embedFonts, boolean useCompression) throws FileNotFoundException, IOException, UnsupportedEncodingException, SVGGraphics2DIOException {
+        writeToSVGFile(cgview, filename, embedFonts, useCompression, -1, false);
+    }
+
+    /**
+     * Writes a Cgview object to a SVG or a SVGZ file. Any mouseover or hyperlink information associated with the Cgview
+     * object is embedded directly in the SVG.
+     *
+     * @param cgview         the Cgview object.
+     * @param filename       the file to create.
+     * @param embedFonts     whether or not to embed fonts in the SVG. Embedded fonts produce a much nicer map but yield
+     *                       a larger file.
+     * @param useCompression whether or not to generate compressed SVG (SVGZ).
+     * @param keepLastLabels whether or not to use labels generated by a previous call to one of the Cgview objects
+     *                       draw() or drawZoomed() methods.
+     * @throws FileNotFoundException
+     * @throws IOException
+     * @throws UnsupportedEncodingException
+     * @throws SVGGraphics2DIOException
+     */
+    public static void writeToSVGFile(Cgview cgview, String filename, boolean embedFonts, boolean useCompression, boolean keepLastLabels) throws FileNotFoundException, IOException, UnsupportedEncodingException, SVGGraphics2DIOException {
+        writeToSVGFile(cgview, filename, embedFonts, useCompression, -1, keepLastLabels);
+    }
+
+    /**
+     * Writes a Cgview object to a PNG file.
+     *
+     * @param cgview         the Cgview object.
+     * @param filename       the file to create.
+     * @param keepLastLabels whether or not to use labels generated by a previous call to one of the Cgview objects
+     *                       draw() or drawZoomed() methods.
+     * @throws IOException
+     */
+    public static void writeToPNGFile(Cgview cgview, String filename, boolean keepLastLabels) throws IOException {
+
+        BufferedImage buffImage = new BufferedImage(cgview.getWidth(), cgview.getHeight(), BufferedImage.TYPE_INT_RGB);
+
+        Graphics2D graphics2D = buffImage.createGraphics();
+        try {
+            if (cgview.getDesiredZoom() > 1.0d) {
+                cgview.drawZoomed(graphics2D, cgview.getDesiredZoom(), cgview.getDesiredZoomCenter(), keepLastLabels);
+            } else {
+                cgview.draw(graphics2D, keepLastLabels);
+            }
+            System.out.println("Writing picture to " + filename);
+            ImageIO.write(buffImage, "PNG", new File(filename));
+        } finally {
+            graphics2D.dispose();
+        }
+    }
+
+    /**
+     * Writes a Cgview object to a PNG file.
+     *
+     * @param cgview   the Cgview object.
+     * @param filename the file to create.
+     * @throws IOException
+     */
+    public static void writeToPNGFile(Cgview cgview, String filename) throws IOException {
+        writeToPNGFile(cgview, filename, false);
+    }
+
+    /**
+     * Writes a Cgview object to a JPG file.
+     *
+     * @param cgview         the Cgview object.
+     * @param filename       the file to create.
+     * @param keepLastLabels whether or not to use labels generated by a previous call to one of the Cgview objects
+     *                       draw() or drawZoomed() methods.
+     * @throws IOException
+     */
+    public static void writeToJPGFile(Cgview cgview, String filename, boolean keepLastLabels) throws IOException {
+
+        BufferedImage buffImage = new BufferedImage(cgview.getWidth(), cgview.getHeight(), BufferedImage.TYPE_INT_RGB);
+
+        Graphics2D graphics2D = buffImage.createGraphics();
+        try {
+            if (cgview.getDesiredZoom() > 1.0d) {
+                cgview.drawZoomed(graphics2D, cgview.getDesiredZoom(), cgview.getDesiredZoomCenter(), keepLastLabels);
+            } else {
+                cgview.draw(graphics2D, keepLastLabels);
+            }
+            System.out.println("Writing picture to " + filename);
+            ImageIO.write(buffImage, "JPG", new File(filename));
+        } finally {
+            graphics2D.dispose();
+        }
+    }
+
+    /**
+     * Writes a Cgview object to a JPG file.
+     *
+     * @param cgview   the Cgview object.
+     * @param filename the file to create.
+     * @throws IOException
+     */
+    public static void writeToJPGFile(Cgview cgview, String filename) throws IOException {
+        writeToJPGFile(cgview, filename, false);
+    }
+
+    /**
+     * Creates an HTML file that links to a Cgview map. Any hyperlink or mouseover information associated with the
+     * Cgview object is included in an image map in the HTML file (in the case of PNG and JPG maps). In the case of SVG
+     * and SVGZ maps, the mouseover and hyperlink information is embedded directly in the SVG.
+     *
+     * @param cgview               the Cgview object embedded in the HTML.
+     * @param imageFilename        the name of the image file containing the Cgview image.
+     * @param imageFormat          the format of the image file.
+     * @param htmlFilename         the HTML file to generate.
+     * @param zoomOutFile          the HTML file to link the 'zoom out' button to, or <code>null</code> if no button
+     *                             should be included.
+     * @param zoomInFile           the HTML file to link the 'zoom in' button to, or <code>null</code> if no button
+     *                             should be included.
+     * @param clockwiseFile        the HTML file to link the 'move clockwise' button to, or <code>null</code> if no
+     *                             button should be included.
+     * @param counterclockwiseFile the HTML file to link the 'move counterclockwise' button to, or <code>null</code> if
+     *                             no button should be included.
+     * @throws FileNotFoundException
+     * @throws IOException
+     */
+    private static void writeHTMLFile(Cgview cgview, String imageFilename, String imageFormat, String htmlFilename, String zoomOutFile, String zoomInFile, String clockwiseFile, String counterclockwiseFile) throws FileNotFoundException, IOException {
+
+        String title;
+	int tableWidth;
+
+	if (legendValue == null) {
+	    tableWidth = cgview.getWidth();
+	}
+	else {
+	    tableWidth = cgview.getWidth() + legendValue.intValue();
+	}
+
+        if ((cgview.getTitle() == null) || (cgview.getTitle().equals(""))) {
+            //title = "zoom = " + Double.toString(cgview.getDesiredZoom()) + ", center = " + Integer.toString(cgview.getDesiredZoomCenter());
+            title = "CGView map";
+        } else {
+            //title = cgview.getTitle() + ", zoom = " + Double.toString(cgview.getDesiredZoom()) + ", center = " + Integer.toString(cgview.getDesiredZoomCenter());
+            title = cgview.getTitle();
+        }
+
+        CgviewHTMLDocument htmlDocument = new CgviewHTMLDocument();	
+
+        htmlDocument.addHeader(title, Double.toString(cgview.getDesiredZoom()), Integer.toString(cgview.getDesiredZoomCenter()), imageFormat, useOverlibValue, useExternalStylesheetValue);
+
+        //start master table
+        htmlDocument.addTableStart(tableWidth);
+        //first table row
+        htmlDocument.addTableRowStart();
+        if (seriesValue != null) {
+            htmlDocument.addTableColumnCenterStart();
+        } else {
+            htmlDocument.addTableColumnStart();
+        }
+
+
+	//start image table
+        htmlDocument.addTableStart(tableWidth, 1);	
+        htmlDocument.addTableRowStart();
+
+        if (seriesValue != null) {
+            htmlDocument.addTableColumnCenterStart();
+        } else {
+            htmlDocument.addTableColumnStart();
+        }
+
+        if ((imageFormat.equalsIgnoreCase("png")) || (imageFormat.equalsIgnoreCase("jpg"))) {
+            ArrayList labelBounds = cgview.getLabelBounds();
+            boolean makeImageMap = false;
+            Iterator i;
+            i = labelBounds.iterator();
+
+            while (i.hasNext()) {
+                LabelBounds currentLabelBounds = (LabelBounds) i.next();
+                if ((currentLabelBounds.getUse() == true) && ((currentLabelBounds.getMouseover() != null) || (currentLabelBounds.getHyperlink() != null))) {
+                    makeImageMap = true;
+                    break;
+                }
+            }
+
+            if (makeImageMap) {
+		htmlDocument.addImageMap(imageFilename, cgview.getWidth(), cgview.getHeight(), labelBounds, useOverlibValue);
+            } else {
+                htmlDocument.addImage(imageFilename, cgview.getWidth(), cgview.getHeight());
+            }
+
+        } else if ((imageFormat.equalsIgnoreCase("svg")) || (imageFormat.equalsIgnoreCase("svgz"))) {
+            htmlDocument.addSVG(imageFilename, cgview.getWidth(), cgview.getHeight());
+        }
+
+        htmlDocument.addTableColumnEnd();
+
+	//if space needs to be reserved for an external legend, add the space here.
+	if (legendValue != null) {
+	    if (seriesValue != null) {
+		htmlDocument.addTableColumnCenterStart();
+		//add image tag
+		htmlDocument.addImage(INCLUDES_OUT_PATH + "/" + EXTERNAL_LEGEND, legendValue.intValue(), cgview.getHeight(), "Legend Image");    
+	    } else {
+		htmlDocument.addTableColumnStart();
+		htmlDocument.addImage(EXTERNAL_LEGEND, legendValue.intValue(), cgview.getHeight(), "Legend Image");       
+	    }
+
+	    htmlDocument.addTableColumnEnd();	    
+	}
+
+        htmlDocument.addTableRowEnd();
+	htmlDocument.addTableEnd();
+
+        htmlDocument.addTableColumnEnd();	
+        htmlDocument.addTableRowEnd();	
+	
+
+        if (seriesValue != null) {
+
+            //add table row
+            htmlDocument.addTableRowStart();
+            htmlDocument.addTableColumnCenterStart();
+
+            if (zoomOutFile != null) {
+                htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + ZOOM_OUT_BUTTON, zoomOutFile, "[Expand -]");
+            } else {
+                htmlDocument.addButtonNoLink(INCLUDES_OUT_PATH + "/" + ZOOM_OUT_BUTTON_OFF, "[Expand -]");
+            }
+
+            if (zoomInFile != null) {
+                htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + ZOOM_IN_BUTTON, zoomInFile, "[Expand +]");
+            } else {
+                htmlDocument.addButtonNoLink(INCLUDES_OUT_PATH + "/" + ZOOM_IN_BUTTON_OFF, "[Expand +]");
+            }
+
+            if (zoomOutFile != null) {
+                if (imageFormat.equalsIgnoreCase("svgz")) {
+                    //htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + INDEX_BUTTON, "index_svg.html", "[Full view]");
+                    htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + INDEX_BUTTON, "index.html", "[Full view]");
+                } else if (imageFormat.equalsIgnoreCase("png")) {
+                    htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + INDEX_BUTTON, "index.html", "[Full view]");
+                }
+
+            } else {
+                htmlDocument.addButtonNoLink(INCLUDES_OUT_PATH + "/" + INDEX_BUTTON_OFF, "[Full view]");
+            }
+
+            if (counterclockwiseFile != null) {
+                htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + MOVE_BACK_BUTTON, counterclockwiseFile, "[Rotate -]");
+            } else {
+                htmlDocument.addButtonNoLink(INCLUDES_OUT_PATH + "/" + MOVE_BACK_BUTTON_OFF, "[Rotate -]");
+            }
+
+            if (clockwiseFile != null) {
+                htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + MOVE_FORWARD_BUTTON, clockwiseFile, "[Rotate +]");
+            } else {
+                htmlDocument.addButtonNoLink(INCLUDES_OUT_PATH + "/" + MOVE_FORWARD_BUTTON_OFF, "[Rotate +]");
+            }
+
+	    if (!excludeSVGValue.booleanValue()) {
+		if (imageFormat.equalsIgnoreCase("svgz")) {
+		    htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + TO_PNG_BUTTON, Integer.toString((int) cgview.getDesiredZoom()) + "_" + Integer.toString(cgview.getDesiredZoomCenter()) + "." + "html", "[View as PNG]");
+		} else if (imageFormat.equalsIgnoreCase("png")) {
+		    htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + TO_SVG_BUTTON, Integer.toString((int) cgview.getDesiredZoom()) + "_" + Integer.toString(cgview.getDesiredZoomCenter()) + "_svg." + "html", "[View as SVG]");
+		}
+	    }
+
+	    if (!excludeSVGValue.booleanValue()) {
+		htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + HELP_BUTTON, INCLUDES_OUT_PATH + "/" + HELP_FILE, "[Help]");
+	    }
+	    else {
+		htmlDocument.addButton(INCLUDES_OUT_PATH + "/" + HELP_BUTTON, INCLUDES_OUT_PATH + "/" + HELP_FILE_PNG, "[Help]");
+	    }
+
+            //end table row
+            htmlDocument.addTableColumnEnd();
+
+            htmlDocument.addTableRowEnd();
+
+            //add row for format information
+            htmlDocument.addTableRowStart();
+            htmlDocument.addTableColumnCenterStart();
+
+            htmlDocument.addTableStart(tableWidth);
+
+            htmlDocument.addTableRowStart();
+            htmlDocument.addTableColumnLeftStart();
+
+            htmlDocument.addSpanNoteStart();
+
+            if (zoomInFile != null) {
+                htmlDocument.addText("Click tick marks to expand the view.");
+            }
+
+            if ((zoomInFile == null) && (zoomOutFile != null)) {
+                htmlDocument.addText("This is a fully expanded view.");
+            }
+
+            htmlDocument.addSpanEnd();
+
+            htmlDocument.addTableColumnEnd();
+
+            htmlDocument.addTableColumnRightStart();
+
+            htmlDocument.addSpanFileSizeStart();
+
+            NumberFormat nf = NumberFormat.getInstance();
+
+	    File svgFile = null;
+	    long svgLength = 0;
+
+	    if (!excludeSVGValue.booleanValue()) {
+		svgFile = new File(outputDirectory + File.separator + SVG_OUT_PATH + File.separator + Integer.toString((int) cgview.getDesiredZoom()) + "_" + Integer.toString(cgview.getDesiredZoomCenter()) + ".svgz");
+		svgLength = svgFile.length();
+		svgLength = (long) Math.floor((float) svgLength / 1000.0f + 0.5f);		
+	    }
+
+            File pngFile = new File(outputDirectory + File.separator + PNG_OUT_PATH + File.separator + Integer.toString((int) cgview.getDesiredZoom()) + "_" + Integer.toString(cgview.getDesiredZoomCenter()) + ".png");
+
+            long pngLength = pngFile.length();
+
+            pngLength = (long) Math.floor((float) pngLength / 1000.0f + 0.5f);
+
+	    if (!excludeSVGValue.booleanValue()) {
+		if (imageFormat.equalsIgnoreCase("svgz")) {
+		    htmlDocument.addText("Displayed SVG file size: ");
+		    if (svgLength > 1000) {
+			htmlDocument.addSpanWarningStart();
+			htmlDocument.addText(nf.format(svgLength) + " kb; ");
+			htmlDocument.addSpanEnd();
+		    } else {
+			htmlDocument.addText(nf.format(svgLength) + " kb; ");
+		    }
+		    htmlDocument.addText("PNG file size: ");
+		    if (pngLength > 1000) {
+			htmlDocument.addSpanWarningStart();
+			htmlDocument.addText(nf.format(pngLength) + " kb.");
+			htmlDocument.addSpanEnd();
+		    } else {
+			htmlDocument.addText(nf.format(pngLength) + " kb.");
+		    }
+
+		} else if (imageFormat.equalsIgnoreCase("png")) {
+		    htmlDocument.addText("Displayed PNG file size: ");
+		    if (pngLength > 1000) {
+			htmlDocument.addSpanWarningStart();
+			htmlDocument.addText(nf.format(pngLength) + " kb; ");
+			htmlDocument.addSpanEnd();
+		    } else {
+			htmlDocument.addText(nf.format(pngLength) + " kb; ");
+		    }
+		    htmlDocument.addText("SVG file size: ");
+		    if (svgLength > 1000) {
+			htmlDocument.addSpanWarningStart();
+			htmlDocument.addText(nf.format(svgLength) + " kb.");
+			htmlDocument.addSpanEnd();
+		    } else {
+			htmlDocument.addText(nf.format(svgLength) + " kb.");
+		    }
+		}
+	    }
+	    else {
+		htmlDocument.addText("Displayed PNG file size: ");
+		if (pngLength > 1000) {
+		    htmlDocument.addSpanWarningStart();
+		    htmlDocument.addText(nf.format(pngLength) + " kb.");
+		    htmlDocument.addSpanEnd();
+		} else {
+		    htmlDocument.addText(nf.format(pngLength) + " kb.");
+		}
+	    }
+
+            htmlDocument.addSpanEnd();
+
+            htmlDocument.addTableColumnEnd();
+            htmlDocument.addTableRowEnd();
+
+            htmlDocument.addTableRowStart();
+
+            htmlDocument.addTableColumnLeftStart();
+            htmlDocument.addSpanValidStart();
+            htmlDocument.addValidationInfo();
+            htmlDocument.addSpanEnd();
+            htmlDocument.addTableColumnEnd();
+
+	    long centerBase = (long) Math.floor((float)cgview.getDesiredZoomCenter() + 0.5f);
+
+            htmlDocument.addTableColumnRightStart();
+            htmlDocument.addSpanFileSizeStart();
+            htmlDocument.addText("Centered on base " + nf.format(centerBase) + "; Zoom = " + Integer.toString((int) cgview.getDesiredZoom()) + ".");
+            htmlDocument.addSpanEnd();
+            htmlDocument.addTableColumnEnd();
+
+            htmlDocument.addTableRowEnd();
+
+            htmlDocument.addTableEnd();
+
+            htmlDocument.addTableColumnEnd();
+
+            htmlDocument.addTableRowEnd();
+
+        }
+
+        //end table
+        htmlDocument.addTableEnd();
+
+        htmlDocument.addFooter();
+
+        try {
+            System.out.println("Writing HTML to " + htmlFilename);
+            BufferedWriter out = new BufferedWriter(new FileWriter(htmlFilename));
+            ArrayList contents = htmlDocument.getContents();
+            Iterator i;
+            i = contents.iterator();
+            while (i.hasNext()) {
+                out.write((String) i.next());
+            }
+            out.close();
+        } finally {
+
+        }
+    }
+
+    /**
+     * Creates an HTML file that links to a Cgview map. Any hyperlink or mouseover information associated with the
+     * Cgview object is included in an image map in the HTML file (in the case of PNG and JPG maps). In the case of SVG
+     * and SVGZ maps, the mouseover and hyperlink information is embedded directly in the SVG.
+     *
+     * @param cgview        the Cgview object embedded in the HTML.
+     * @param imageFilename the name of the image file containing the Cgview image.
+     * @param imageFormat   the format of the image file.
+     * @param htmlFilename  the HTML file to generate.
+     */
+    public static void writeHTMLFile(Cgview cgview, String imageFilename, String imageFormat, String htmlFilename) throws FileNotFoundException, IOException {
+        writeHTMLFile(cgview, imageFilename, imageFormat, htmlFilename, null, null, null, null);
+
+    }
+
+    /**
+     * Creates an HTML file that links to a Cgview map. Any hyperlink or mouseover information associated with the
+     * Cgview object is included in an image map in the HTML file (in the case of PNG and JPG maps). In the case of SVG
+     * and SVGZ maps, the mouseover and hyperlink information is embedded directly in the SVG.
+     *
+     * @param cgview        the Cgview object embedded in the HTML.
+     * @param imageFilename the name of the image file containing the Cgview image.
+     * @param imageFormat   the format of the image file.
+     * @param htmlFilename  the HTML file to generate.
+     * @param useOverlib    whether to use the overlib javascript library for mouseovers (recommended)
+     */
+    public static void writeHTMLFile(Cgview cgview, String imageFilename, String imageFormat, String htmlFilename, boolean useOverlib) throws FileNotFoundException, IOException {
+	useOverlibValue = new Boolean(useOverlib);
+        writeHTMLFile(cgview, imageFilename, imageFormat, htmlFilename, null, null, null, null);
+
+    }
+
+
+    /**
+     * Writes a Cgview object to an image file.
+     *
+     * @param cgview        the Cgview object.
+     * @param filename      the file to create.
+     * @param imageFormat   the image format to create ("svg", "svgz", "png", or "jpg").
+     * @param embedFonts    whether or not to embed fonts in the SVG. Embedded fonts produce a much nicer map but yield
+     *                      a larger file.
+     * @param nextZoomValue the zoom value of the next Cgview map to draw in the series, or <code>0</code> if there is
+     *                      not another Cgview in the series.
+     */
+    private static void writeImageToFile(Cgview cgview, String filename, String imageFormat, boolean embedFonts, int nextZoomValue) {
+        writeImageToFile(cgview, filename, imageFormat, embedFonts, nextZoomValue, false);
+    }
+
+    /**
+     * Writes a Cgview object to an image file.
+     *
+     * @param cgview        the Cgview object.
+     * @param filename      the file to create.
+     * @param imageFormat   the image format to create ("svg", "svgz", "png", or "jpg").
+     * @param embedFonts    whether or not to embed fonts in the SVG. Embedded fonts produce a much nicer map but yield
+     *                      a larger file.
+     * @param nextZoomValue the zoom value of the next Cgview map to draw in the series, or <code>0</code> if there is
+     *                      not another Cgview in the series.
+     */
+    private static void writeImageToFile(Cgview cgview, String filename, String imageFormat, boolean embedFonts, int nextZoomValue, boolean keepLastLabels) {
+        try {
+            if (imageFormat.equalsIgnoreCase("svg")) {
+                writeToSVGFile(cgview, filename, embedFonts, false, nextZoomValue, keepLastLabels);
+            } else if (imageFormat.equalsIgnoreCase("svgz")) {
+                writeToSVGFile(cgview, filename, embedFonts, true, nextZoomValue, keepLastLabels);
+            } else if (imageFormat.equalsIgnoreCase("png")) {
+                writeToPNGFile(cgview, filename, keepLastLabels);
+            } else if (imageFormat.equalsIgnoreCase("jpg")) {
+                writeToJPGFile(cgview, filename, keepLastLabels);
+            } else {
+                System.err.println("The output format was not recognized.");
+                System.exit(1);
+            }
+
+        } catch (SVGGraphics2DIOException e) {
+	    e.printStackTrace(System.err);
+            System.err.println(PROBLEM_MESSAGE + e.toString());
+            System.exit(1);
+        } catch (UnsupportedEncodingException e) {
+	    e.printStackTrace(System.err);
+            System.err.println(PROBLEM_MESSAGE + e.toString());
+            System.exit(1);
+        } catch (IOException e) {
+	    e.printStackTrace(System.err);
+            System.err.println(PROBLEM_MESSAGE + e.toString());
+            System.exit(1);
+        }
+    }
+
+    /**
+     * Creates an HTML file that links to a Cgview map. Any hyperlink or mouseover information associated with the
+     * Cgview object is included in an image map in the HTML file (in the case of PNG and JPG maps). In the case of SVG
+     * and SVGZ maps, the mouseover and hyperlink information is embedded directly in the SVG.
+     *
+     * @param cgview               the Cgview object embedded in the HTML.
+     * @param imageFilename        the name of the image file containing the Cgview image.
+     * @param imageFormat          the format of the image file.
+     * @param htmlFilename         the HTML file to generate.
+     * @param zoomOutFile          the HTML file to link the 'zoom out' button to, or <code>null</code> if no button
+     *                             should be included.
+     * @param zoomInFile           the HTML file to link the 'zoom in' button to, or <code>null</code> if no button
+     *                             should be included.
+     * @param clockwiseFile        the HTML file to link the 'move clockwise' button to, or <code>null</code> if no
+     *                             button should be included.
+     * @param counterclockwiseFile the HTML file to link the 'move counterclockwise' button to, or <code>null</code> if
+     *                             no button should be included.
+     */
+    private static void writeHTMLToFile(Cgview cgview, String imageFilename, String imageFormat, String htmlFilename, String zoomOutFile, String zoomInFile, String clockwiseFile, String counterclockwiseFile) {
+
+        try {
+            writeHTMLFile(cgview, imageFilename, imageFormat, htmlFilename, zoomOutFile, zoomInFile, clockwiseFile, counterclockwiseFile);
+        } catch (IOException e) {
+	    e.printStackTrace(System.err);
+            System.err.println(PROBLEM_MESSAGE + e.toString());
+            System.exit(1);
+        }
+
+    }
+
+
+    public static void main(String args[]) {
+
+        CmdLineParser parser = new CmdLineParser();
+        CmdLineParser.Option labelFont = parser.addIntegerOption('A', "labelFont");
+        CmdLineParser.Option centerBase = parser.addIntegerOption('c', "centerBase");
+        CmdLineParser.Option legendFont = parser.addIntegerOption('D', "legendFont");
+        CmdLineParser.Option tickDensity = parser.addDoubleOption('d', "tickDensity");
+        CmdLineParser.Option embedFonts = parser.addStringOption('E', "embedFonts");	
+        CmdLineParser.Option excludeSVG = parser.addStringOption('e', "excludeSVG");
+        CmdLineParser.Option format = parser.addStringOption('f', "formatOfOutput");
+        CmdLineParser.Option html = parser.addStringOption('h', "htmlFile");
+        CmdLineParser.Option height = parser.addIntegerOption('H', "heightOfMap");
+        CmdLineParser.Option input = parser.addStringOption('i', "inputFile");
+        CmdLineParser.Option innerLabels = parser.addStringOption('I', "innerLabels");	
+        CmdLineParser.Option legend = parser.addIntegerOption('L', "legendSpace");
+        CmdLineParser.Option output = parser.addStringOption('o', "outputFile");
+        CmdLineParser.Option path = parser.addStringOption('p', "pathToImage");
+
+        CmdLineParser.Option removeLegends = parser.addStringOption('r', "removeLegends");
+        CmdLineParser.Option removeLabels = parser.addStringOption('R', "removeLabels");
+
+        CmdLineParser.Option series = parser.addStringOption('s', "seriesDirectory");
+        CmdLineParser.Option stylesheet = parser.addStringOption('S', "stylesheet");
+        CmdLineParser.Option useOverlib = parser.addStringOption('u', "useOverlib");
+        CmdLineParser.Option rulerFont = parser.addIntegerOption('U', "rulerFont");
+        CmdLineParser.Option width = parser.addIntegerOption('W', "widthOfMap");
+        CmdLineParser.Option seriesNumbers = parser.addStringOption('x', "seriesNumbers");	
+        CmdLineParser.Option zoom = parser.addDoubleOption('z', "zoomAmount");	
+
+        try {
+            parser.parse(args);
+        } catch (CmdLineParser.OptionException e) {
+            System.err.println(e.getMessage());
+            printUsage();
+            System.exit(1);
+        }
+
+        // Extract the values entered for the various options -- if the
+        // options were not specified, the corresponding values will be
+        // null.
+        Integer centerBaseValue = (Integer) parser.getOptionValue(centerBase);
+	String embedFontsValueString = (String) parser.getOptionValue(embedFonts);
+        String excludeSVGValueString = (String)parser.getOptionValue(excludeSVG);
+        String formatValue = (String) parser.getOptionValue(format);
+        String htmlValue = (String) parser.getOptionValue(html);
+        String inputValue = (String) parser.getOptionValue(input);
+	String useInnerLabelsValueString = (String) parser.getOptionValue(innerLabels);
+	legendValue = (Integer) parser.getOptionValue(legend);
+        String outputValue = (String) parser.getOptionValue(output);
+        String pathValue = (String) parser.getOptionValue(path);
+        seriesValue = (String) parser.getOptionValue(series);
+	String useExternalStylesheetValueString = (String) parser.getOptionValue(stylesheet);
+        String useOverlibValueString = (String)parser.getOptionValue(useOverlib);
+        Double zoomValue = (Double) parser.getOptionValue(zoom);
+
+	heightValue = (Integer) parser.getOptionValue(height);
+	widthValue = (Integer) parser.getOptionValue(width);
+
+	String removeLabelsValueString = (String) parser.getOptionValue(removeLabels);
+	String removeLegendsValueString = (String) parser.getOptionValue(removeLegends);
+
+	legendFontValue = (Integer) parser.getOptionValue(legendFont);
+	rulerFontValue = (Integer) parser.getOptionValue(rulerFont);
+	labelFontValue = (Integer) parser.getOptionValue(labelFont);
+
+	tickDensityValue = (Double) parser.getOptionValue(tickDensity);
+
+	seriesNumbersValue = (String) parser.getOptionValue(seriesNumbers);
+
+        if (formatValue == null) {
+            formatValue = "png";
+        }
+        if (inputValue == null) {
+            System.err.println("Please specify an input file name");
+            printUsage();
+            System.exit(1);
+        }
+        if ((outputValue == null) && (seriesValue == null)) {
+            System.err.println("Please specify an output file name");
+            printUsage();
+            System.exit(1);
+        }
+        if (centerBaseValue == null) {
+            centerBaseValue = new Integer(1);
+        }
+        if (zoomValue == null) {
+            zoomValue = new Double(1.0d);
+        }
+
+	if (useOverlibValueString == null) {
+	    useOverlibValue = new Boolean(true);
+	}
+	else if ((useOverlibValueString.equalsIgnoreCase("t")) || (useOverlibValueString.equalsIgnoreCase("true"))) {
+	    useOverlibValue = new Boolean(true);
+	}
+	else {
+	    useOverlibValue = new Boolean(false);
+	}
+
+	if (useInnerLabelsValueString == null) {
+	    useInnerLabelsValue = null;
+	}
+	else if ((useInnerLabelsValueString.equalsIgnoreCase("t")) || (useInnerLabelsValueString.equalsIgnoreCase("true"))) {
+	    useInnerLabelsValue = (Integer) INNER_LABELS_SHOW;
+	}
+	else {
+	    useInnerLabelsValue = (Integer) INNER_LABELS_NO_SHOW;
+	}	
+
+	if (excludeSVGValueString == null) {
+	    excludeSVGValue = new Boolean(false);
+	}
+	else if ((excludeSVGValueString.equalsIgnoreCase("t")) || (excludeSVGValueString.equalsIgnoreCase("true"))) {
+	    excludeSVGValue = new Boolean(true);
+	}
+	else {
+	    excludeSVGValue = new Boolean(false);
+	}
+
+	if (embedFontsValueString == null) {
+	    embedFontsValue = new Boolean(true);
+	}
+	else if ((embedFontsValueString.equalsIgnoreCase("t")) || (embedFontsValueString.equalsIgnoreCase("true"))) {
+	    embedFontsValue = new Boolean(true);
+	}
+	else {
+	    embedFontsValue = new Boolean(true);
+	}
+
+	if (useExternalStylesheetValueString == null) {
+	    useExternalStylesheetValue = new Boolean(false);
+	}
+	else if ((useExternalStylesheetValueString.equalsIgnoreCase("t")) || (useExternalStylesheetValueString.equalsIgnoreCase("true"))) {
+	    useExternalStylesheetValue = new Boolean(true);
+	}
+	else {
+	    useExternalStylesheetValue = new Boolean(false);
+	}
+
+	if (removeLabelsValueString == null) {
+	    removeLabelsValue = new Boolean(false);
+	}
+	else if ((removeLabelsValueString.equalsIgnoreCase("t")) || (removeLabelsValueString.equalsIgnoreCase("true"))) {
+	    removeLabelsValue = new Boolean(true);
+	}
+	else {
+	    removeLabelsValue = new Boolean(false);
+	}
+
+	if (removeLegendsValueString == null) {
+	    removeLegendsValue = new Boolean(false);
+	}
+	else if ((removeLegendsValueString.equalsIgnoreCase("t")) || (removeLegendsValueString.equalsIgnoreCase("true"))) {
+	    removeLegendsValue = new Boolean(true);
+	}
+	else {
+	    removeLegendsValue = new Boolean(false);
+	}
+
+
+	//determine input format type
+	String inputFormat = "xml";
+	if (inputValue.length() >= 3) {
+	    inputFormat = inputValue.substring(inputValue.length() - 3);
+	}
+
+        //if not generating an image series, generate the single image
+        if (seriesValue == null) {
+            Cgview cgview = new Cgview(1);
+	    if (inputFormat.equalsIgnoreCase("xml")) {
+		try {
+		    CgviewFactory cgviewFactory = new CgviewFactory();
+
+		    if (legendFontValue != null) {
+			cgviewFactory.setLegendFontSize(legendFontValue.intValue());
+		    }
+		    if (labelFontValue != null) {
+			cgviewFactory.setLabelFontSize(labelFontValue.intValue());
+		    }
+		    if (rulerFontValue != null) {
+			cgviewFactory.setRulerFontSize(rulerFontValue.intValue());
+		    }
+
+		    cgview = cgviewFactory.createCgviewFromFile(inputValue);
+
+		    if (heightValue != null) {
+			cgview.setHeight(heightValue.intValue());
+		    }
+
+		    if (widthValue != null) {
+			cgview.setWidth(widthValue.intValue());
+		    }
+
+		    if (removeLabelsValue.booleanValue()) {
+			cgview.setGlobalLabel(LABEL_NONE);
+		    }
+
+		    if (removeLegendsValue.booleanValue()) {
+			cgview.setDrawLegends(false);
+		    }
+
+		    if (useInnerLabelsValue != null) {
+			cgview.setUseInnerLabels(useInnerLabelsValue.intValue());
+		    }
+
+		    if (tickDensityValue != null) {
+			cgview.setTickDensity(tickDensityValue.doubleValue());
+		    }
+
+		    cgview.setDesiredZoomCenter(centerBaseValue.intValue());
+		    cgview.setDesiredZoom(zoomValue.doubleValue());
+		} catch (SAXException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		} catch (IOException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		}
+	    }
+	    else if (inputFormat.equalsIgnoreCase("tab")) {
+		try {
+		    CgviewFactoryTab cgviewFactory = new CgviewFactoryTab();
+
+		    if (legendFontValue != null) {
+			cgviewFactory.setLegendFontSize(legendFontValue.intValue());
+		    }
+		    if (labelFontValue != null) {
+			cgviewFactory.setLabelFontSize(labelFontValue.intValue());
+		    }
+		    if (rulerFontValue != null) {
+			cgviewFactory.setRulerFontSize(rulerFontValue.intValue());
+		    }
+
+		    if (heightValue != null) {
+			cgviewFactory.setHeight(heightValue.intValue());
+		    }
+
+		    if (widthValue != null) {
+			cgviewFactory.setWidth(widthValue.intValue());
+		    }
+
+		    if (tickDensityValue != null) {
+			cgviewFactory.setTickDensity(tickDensityValue.doubleValue());
+		    }
+
+		    cgview = cgviewFactory.createCgviewFromFile(inputValue);
+		    cgview.setDesiredZoomCenter(centerBaseValue.intValue());
+		    cgview.setDesiredZoom(zoomValue.doubleValue());
+
+		    if (removeLabelsValue.booleanValue()) {
+			cgview.setGlobalLabel(LABEL_NONE);
+		    }
+
+		    if (removeLegendsValue.booleanValue()) {
+			cgview.setDrawLegends(false);
+		    }
+
+		    if (useInnerLabelsValue != null) {
+			cgview.setUseInnerLabels(useInnerLabelsValue.intValue());
+		    }
+
+		} catch (IOException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		} catch (Exception e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		}
+	    }
+	    else if (inputFormat.equalsIgnoreCase("ptt")) {
+		try {
+		    CgviewFactoryPtt cgviewFactory = new CgviewFactoryPtt();
+
+		    if (legendFontValue != null) {
+			cgviewFactory.setLegendFontSize(legendFontValue.intValue());
+		    }
+		    if (labelFontValue != null) {
+			cgviewFactory.setLabelFontSize(labelFontValue.intValue());
+		    }
+		    if (rulerFontValue != null) {
+			cgviewFactory.setRulerFontSize(rulerFontValue.intValue());
+		    }
+
+		    if (heightValue != null) {
+			cgviewFactory.setHeight(heightValue.intValue());
+		    }
+
+		    if (widthValue != null) {
+			cgviewFactory.setWidth(widthValue.intValue());
+		    }
+
+		    if (tickDensityValue != null) {
+			cgviewFactory.setTickDensity(tickDensityValue.doubleValue());
+		    }
+
+		    cgview = cgviewFactory.createCgviewFromFile(inputValue);
+		    cgview.setDesiredZoomCenter(centerBaseValue.intValue());
+		    cgview.setDesiredZoom(zoomValue.doubleValue());
+
+		    if (removeLabelsValue.booleanValue()) {
+			cgview.setGlobalLabel(LABEL_NONE);
+		    }
+
+		    if (removeLegendsValue.booleanValue()) {
+			cgview.setDrawLegends(false);
+		    }
+
+		    if (useInnerLabelsValue != null) {
+			cgview.setUseInnerLabels(useInnerLabelsValue.intValue());
+		    }
+
+		} catch (IOException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		} catch (Exception e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		}
+	    }
+	    else {
+		System.err.println("Input file extension was not recognized.");
+		System.exit(1);		
+	    }
+
+            if (formatValue.equalsIgnoreCase("svg")) {
+
+                try {
+                    if (embedFontsValue.booleanValue() == false) {
+                        writeToSVGFile(cgview, outputValue, false, false);
+                    } else {
+                        writeToSVGFile(cgview, outputValue, true, false);
+                    }
+                } catch (SVGGraphics2DIOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                } catch (UnsupportedEncodingException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                } catch (IOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                }
+
+            } else if (formatValue.equalsIgnoreCase("svgz")) {
+                try {
+                    if (embedFontsValue.booleanValue() == false) {
+                        writeToSVGFile(cgview, outputValue, false, true);
+                    } else {
+                        writeToSVGFile(cgview, outputValue, true, true);
+                    }
+                } catch (SVGGraphics2DIOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                } catch (UnsupportedEncodingException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                } catch (IOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                }
+            } else if (formatValue.equalsIgnoreCase("png")) {
+                try {
+                    writeToPNGFile(cgview, outputValue);
+                } catch (IOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                }
+            } else if (formatValue.equalsIgnoreCase("jpg")) {
+                try {
+                    writeToJPGFile(cgview, outputValue);
+                } catch (IOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                }
+            } else {
+                System.err.println("The output format was not recognized.");
+                System.exit(1);
+            }
+
+
+            if (htmlValue != null) {
+                //write HTML file
+                try {
+		    if (pathValue == null) {
+			writeHTMLFile(cgview, outputValue, formatValue, htmlValue);
+		    }
+		    else {
+			writeHTMLFile(cgview, pathValue, formatValue, htmlValue);			
+		    }
+                } catch (IOException e) {
+		    e.printStackTrace(System.err);
+                    System.err.println(PROBLEM_MESSAGE + e.toString());
+                    System.exit(1);
+                }
+            }
+        }
+        //seriesValue is defined.
+        else {
+
+	    useExternalStylesheetValue = new Boolean(true);
+
+            File seriesDirectory = new File(seriesValue);
+            if (!(seriesDirectory.isDirectory())) {
+                if (!(seriesDirectory.mkdirs())) {
+                    System.err.println("The directory " + seriesValue + " could not be created.");
+                    System.exit(1);
+                }
+            }
+
+            File includesDirectory = new File(seriesValue + File.separator + INCLUDES_OUT_PATH);
+            if (!(includesDirectory.isDirectory())) {
+                if (!(includesDirectory.mkdirs())) {
+                    System.err.println("The directory " + seriesValue + File.separator + INCLUDES_OUT_PATH + " could not be created.");
+                    System.exit(1);
+                }
+            }
+
+            File pngDirectory = new File(seriesValue + File.separator + PNG_OUT_PATH);
+            if (!(pngDirectory.isDirectory())) {
+                if (!(pngDirectory.mkdirs())) {
+                    System.err.println("The directory " + seriesValue + File.separator + PNG_OUT_PATH + " could not be created.");
+                    System.exit(1);
+                }
+            }
+
+	    File svgDirectory = null;
+	    if (!excludeSVGValue.booleanValue()) {
+		svgDirectory = new File(seriesValue + File.separator + SVG_OUT_PATH);
+		if (!(svgDirectory.isDirectory())) {
+		    if (!(svgDirectory.mkdirs())) {
+			System.err.println("The directory " + seriesValue + File.separator + SVG_OUT_PATH + " could not be created.");
+			System.exit(1);
+		    }
+		}
+	    }
+
+            outputDirectory = seriesValue;
+
+            //now create a cgview
+            Cgview cgview = new Cgview(1);
+	    if (inputFormat.equalsIgnoreCase("xml")) {
+		try {
+		    CgviewFactory cgviewFactory = new CgviewFactory();
+
+		    if (legendFontValue != null) {
+			cgviewFactory.setLegendFontSize(legendFontValue.intValue());
+		    }
+		    if (labelFontValue != null) {
+			cgviewFactory.setLabelFontSize(labelFontValue.intValue());
+		    }
+		    if (rulerFontValue != null) {
+			cgviewFactory.setRulerFontSize(rulerFontValue.intValue());
+		    }
+
+
+		    cgview = cgviewFactory.createCgviewFromFile(inputValue);
+
+		    if (heightValue != null) {
+			cgview.setHeight(heightValue.intValue());
+		    }
+
+		    if (widthValue != null) {
+			cgview.setWidth(widthValue.intValue());
+		    }
+
+		    if (removeLabelsValue.booleanValue()) {
+			cgview.setGlobalLabel(LABEL_NONE);
+		    }
+
+		    if (removeLegendsValue.booleanValue()) {
+			cgview.setDrawLegends(false);
+		    }
+
+		    if (useInnerLabelsValue != null) {
+			cgview.setUseInnerLabels(useInnerLabelsValue.intValue());
+		    }
+
+		    if (tickDensityValue != null) {
+			cgview.setTickDensity(tickDensityValue.doubleValue());
+		    }
+
+		    //cgview.setDesiredZoomCenter(centerBaseValue.intValue());
+		    //cgview.setDesiredZoom(zoomValue.doubleValue());
+		} catch (SAXException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		} catch (IOException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		}
+	    }
+	    else if (inputFormat.equalsIgnoreCase("tab")) {
+		try {
+		    CgviewFactoryTab cgviewFactory = new CgviewFactoryTab();
+
+
+		    if (legendFontValue != null) {
+			cgviewFactory.setLegendFontSize(legendFontValue.intValue());
+		    }
+		    if (labelFontValue != null) {
+			cgviewFactory.setLabelFontSize(labelFontValue.intValue());
+		    }
+		    if (rulerFontValue != null) {
+			cgviewFactory.setRulerFontSize(rulerFontValue.intValue());
+		    }
+
+		    if (heightValue != null) {
+			cgviewFactory.setHeight(heightValue.intValue());
+		    }
+
+		    if (widthValue != null) {
+			cgviewFactory.setWidth(widthValue.intValue());
+		    }
+		    if (tickDensityValue != null) {
+			cgviewFactory.setTickDensity(tickDensityValue.doubleValue());
+		    }
+
+		    cgview = cgviewFactory.createCgviewFromFile(inputValue);
+		    //cgview.setDesiredZoomCenter(centerBaseValue.intValue());
+		    //cgview.setDesiredZoom(zoomValue.doubleValue());
+
+		    if (removeLabelsValue.booleanValue()) {
+			cgview.setGlobalLabel(LABEL_NONE);
+		    }
+
+		    if (removeLegendsValue.booleanValue()) {
+			cgview.setDrawLegends(false);
+		    }
+
+		    if (useInnerLabelsValue != null) {
+			cgview.setUseInnerLabels(useInnerLabelsValue.intValue());
+		    }
+
+		} catch (IOException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		} catch (Exception e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		}
+	    }
+	    else if (inputFormat.equalsIgnoreCase("ptt")) {
+		try {
+		    CgviewFactoryPtt cgviewFactory = new CgviewFactoryPtt();
+
+		    if (legendFontValue != null) {
+			cgviewFactory.setLegendFontSize(legendFontValue.intValue());
+		    }
+		    if (labelFontValue != null) {
+			cgviewFactory.setLabelFontSize(labelFontValue.intValue());
+		    }
+		    if (rulerFontValue != null) {
+			cgviewFactory.setRulerFontSize(rulerFontValue.intValue());
+		    }
+
+
+		    if (heightValue != null) {
+			cgviewFactory.setHeight(heightValue.intValue());
+		    }
+
+		    if (widthValue != null) {
+			cgviewFactory.setWidth(widthValue.intValue());
+		    }
+
+		    if (tickDensityValue != null) {
+			cgviewFactory.setTickDensity(tickDensityValue.doubleValue());
+		    }
+
+		    cgview = cgviewFactory.createCgviewFromFile(inputValue);
+		    //cgview.setDesiredZoomCenter(centerBaseValue.intValue());
+		    //cgview.setDesiredZoom(zoomValue.doubleValue());
+
+		    if (removeLabelsValue.booleanValue()) {
+			cgview.setGlobalLabel(LABEL_NONE);
+		    }
+
+		    if (removeLegendsValue.booleanValue()) {
+			cgview.setDrawLegends(false);
+		    }
+
+		    if (useInnerLabelsValue != null) {
+			cgview.setUseInnerLabels(useInnerLabelsValue.intValue());
+		    }
+
+		} catch (IOException e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		} catch (Exception e) {
+		    e.printStackTrace(System.err);
+		    System.err.println(PROBLEM_MESSAGE + e.toString());
+		    System.exit(1);
+		}
+	    }
+	    else {
+		System.err.println("Input file extension was not recognized.");
+		System.exit(1);		
+	    }
+
+            //now try to copy button images to the output directory
+            FileMover fileMover = new FileMover();
+	    if (excludeSVGValue.booleanValue()) {
+		if (!(fileMover.moveFile(INCLUDES_PATH, ZOOM_IN_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, ZOOM_OUT_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_FORWARD_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_BACK_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, INDEX_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, ZOOM_IN_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, ZOOM_OUT_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_FORWARD_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_BACK_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, INDEX_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, HELP_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, HELP_FILE_PNG, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, STYLE_FILE, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, OVERLIB_JAVASCRIPT, seriesValue + File.separator + INCLUDES_OUT_PATH))) {
+		    System.err.println("Include files could not be copied to the " + seriesValue + File.separator + INCLUDES_OUT_PATH + " directory");
+		    System.exit(1);
+		}
+	    }
+            else {
+		if (!(fileMover.moveFile(INCLUDES_PATH, ZOOM_IN_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, ZOOM_OUT_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_FORWARD_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_BACK_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, INDEX_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, ZOOM_IN_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, ZOOM_OUT_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_FORWARD_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, MOVE_BACK_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, INDEX_BUTTON_OFF, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, TO_SVG_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, TO_PNG_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, HELP_BUTTON, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, HELP_FILE, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, STYLE_FILE, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, SVG_JAVASCRIPT, seriesValue + File.separator + INCLUDES_OUT_PATH) && 
+		      fileMover.moveFile(INCLUDES_PATH, OVERLIB_JAVASCRIPT, seriesValue + File.separator + INCLUDES_OUT_PATH))) {
+		    System.err.println("Include files could not be copied to the " + seriesValue + File.separator + INCLUDES_OUT_PATH + " directory");
+		    System.exit(1);
+		}
+            }
+
+	    //use a default zoom scheme
+	    int[] zoomValues = {1, 6, 36};
+	    //zoom values must start with 1, and must be in ascending order.
+	    //there must be no spaces between numbers.
+	    if (seriesNumbersValue != null) {
+		try {
+		    String values[] = seriesNumbersValue.split(","); 
+		    zoomValues = new int[values.length];
+		    int previousValue = 0;
+		    for (int k = 0; k < values.length; k++) {
+			zoomValues[k] = Integer.parseInt(values[k]);
+			if (k == 0) {
+			    if (zoomValues[k] != 1) {
+				System.err.println("There is a problem with the supplied zoom values: " + seriesNumbersValue);
+				System.err.println("The first value in the zoom values must be 1.");
+				System.exit(1);
+			    }
+			}
+			else {
+			    if (zoomValues[k] <= previousValue) {
+				System.err.println("There is a problem with the supplied zoom values: " + seriesNumbersValue);
+				System.err.println("The zoom values must be given in ascending order.");
+				System.exit(1);
+			    }
+		        }
+			previousValue = zoomValues[k];
+		    }
+		}
+		catch (Exception e) {
+		    System.err.println("There is a problem with the supplied zoom values: " + seriesNumbersValue);  
+		    System.err.println("Please enter comma separated values, for example: 1, 6, 36");		  
+		}
+	    }
+
+            ArrayList toDrawPreviousZoom = new ArrayList();
+            ArrayList toDrawCurrentZoom = new ArrayList();
+            ArrayList toDrawNextZoom = new ArrayList();
+
+            ArrayList labelBounds;
+            Iterator i;
+            Iterator j;
+            Iterator m;
+
+            NumberFormat nf = NumberFormat.getInstance();
+
+            for (int k = 0; k < zoomValues.length; k++) {
+
+                //add first SeriesImage if k is 0
+                if (k == 0) {
+                    toDrawCurrentZoom.add(new SeriesImage(1, 1));
+                }
+                //need to sort toDrawCurrentZoom by zoomCenter
+                Comparator comparator = new SortSeriesImageByZoomCenter();
+                Collections.sort(toDrawCurrentZoom, comparator);
+
+                m = toDrawCurrentZoom.iterator();
+
+                while (m.hasNext()) {
+                    SeriesImage imageToDraw = (SeriesImage) m.next();
+                    cgview.setDesiredZoomCenter(imageToDraw.getZoomCenter());
+                    cgview.setDesiredZoom(imageToDraw.getZoomValue());
+
+                    //draw to file. The zoomValues value is needed for svg and svgz output, to modify the BOUNDS_RULER type labelBounds.
+                    if (k < zoomValues.length - 1) {
+                        //png
+                        writeImageToFile(cgview, seriesValue + File.separator + PNG_OUT_PATH + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", embedFontsValue.booleanValue(), zoomValues[k + 1]);
+                        //svgz
+			if (!excludeSVGValue.booleanValue()) {
+			    writeImageToFile(cgview, seriesValue + File.separator + SVG_OUT_PATH + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", embedFontsValue.booleanValue(), zoomValues[k + 1], true);
+			}
+                    } else {
+                        //png
+                        writeImageToFile(cgview, seriesValue + File.separator + PNG_OUT_PATH + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", embedFontsValue.booleanValue(), 0);
+                        //svgz
+			if (!excludeSVGValue.booleanValue()) {
+			    writeImageToFile(cgview, seriesValue + File.separator + SVG_OUT_PATH + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", embedFontsValue.booleanValue(), 0, true);
+			}
+                    }
+
+                    labelBounds = cgview.getLabelBounds();
+
+                    //now modify the BOUNDS_RULER type labelBounds for png output.
+                    if (k < zoomValues.length - 1) {
+                        i = labelBounds.iterator();
+                        while (i.hasNext()) {
+                            LabelBounds currentLabelBounds = (LabelBounds) i.next();
+                            if (currentLabelBounds.getType() == BOUNDS_RULER) {
+                                currentLabelBounds.setHyperlink(Integer.toString(zoomValues[k + 1]) + "_" + Integer.toString(currentLabelBounds.getBase()) + ".html");
+                                currentLabelBounds.setMouseover("expand " + nf.format((long) currentLabelBounds.getBase()) + " bp region");
+                            }
+                        }
+                    }
+
+                    //now examine the BOUNDS_RULER type labelBounds and add seriesImage objects to the toDrawNextZoom arrayList
+
+                    i = labelBounds.iterator();
+                    while (i.hasNext()) {
+                        LabelBounds currentLabelBounds = (LabelBounds) i.next();
+                        if (currentLabelBounds.getType() == BOUNDS_RULER) {
+                            if (k < zoomValues.length - 1) {
+
+                                //if this particular labelBounds is new, add it to the stack
+                                SeriesImage newSeriesImage = new SeriesImage(zoomValues[k + 1], currentLabelBounds.getBase());
+                                boolean isNew = true;
+                                j = toDrawNextZoom.iterator();
+                                while (j.hasNext()) {
+                                    SeriesImage existingSeriesImage = (SeriesImage) j.next();
+                                    if (existingSeriesImage.isEqual(newSeriesImage)) {
+                                        isNew = false;
+                                        break;
+                                    }
+                                }
+                                if (isNew) {
+                                    toDrawNextZoom.add(newSeriesImage);
+                                }
+                            }
+                        }
+                    }
+
+
+                    //now create html file for the image file that was written
+                    if (k == 0) {
+                        //there are more than one items in the list of zoom values
+                        if (k < zoomValues.length - 1) {
+                            //png
+                            writeHTMLToFile(cgview, PNG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", seriesValue + File.separator + "index.html", null, imageToDraw.getZoomInFilePrefix(labelBounds, zoomValues[k + 1]) + "." + "html", null, null);
+                            writeHTMLToFile(cgview, PNG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", seriesValue + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "html", null, imageToDraw.getZoomInFilePrefix(labelBounds, zoomValues[k + 1]) + "." + "html", null, null);
+
+                            //svgz
+			    if (!excludeSVGValue.booleanValue()) {
+				writeHTMLToFile(cgview, SVG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", seriesValue + File.separator + "index_svg.html", null, imageToDraw.getZoomInFilePrefix(labelBounds, zoomValues[k + 1]) + "." + "html", null, null);
+				writeHTMLToFile(cgview, SVG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", seriesValue + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "_svg." + "html", null, imageToDraw.getZoomInFilePrefix(labelBounds, zoomValues[k + 1]) + "." + "html", null, null);
+			    }
+
+                        }
+                        //there is only one item in the list of zoom values
+                        else {
+                            //png
+                            writeHTMLToFile(cgview, PNG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", seriesValue + File.separator + "index.html", null, null, null, null);
+
+                            //svgz
+			    if (!excludeSVGValue.booleanValue()) {
+				writeHTMLToFile(cgview, SVG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", seriesValue + File.separator + "index_svg.html", null, null, null, null);
+			    }
+                        }
+                    } else {
+                        //this is not the most zoomed in level
+                        if (k < zoomValues.length - 1) {
+                            //png
+                            writeHTMLToFile(cgview, PNG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", seriesValue + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "html", imageToDraw.getZoomOutFilePrefix(toDrawPreviousZoom, zoomValues[k - 1]) + "." + "html", imageToDraw.getZoomInFilePrefix(labelBounds, zoomValues[k + 1])  [...]
+
+                            //svgz
+			    if (!excludeSVGValue.booleanValue()) {
+				writeHTMLToFile(cgview, SVG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", seriesValue + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "_svg." + "html", imageToDraw.getZoomOutFilePrefix(toDrawPreviousZoom, zoomValues[k - 1]) + "." + "html", imageToDraw.getZoomInFilePrefix(labelBounds, zoomValues[k + 1]) + "." + "html", im [...]
+			    }
+
+                        }
+                        //this is the most zoomed in level
+                        else {
+                            //png
+                            writeHTMLToFile(cgview, PNG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "png", "png", seriesValue + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "html", imageToDraw.getZoomOutFilePrefix(toDrawPreviousZoom, zoomValues[k - 1]) + "." + "html", null, imageToDraw.getClockwiseFilePrefix(toDrawCurrentZoom) + ". [...]
+
+                            //svgz
+			    if (!excludeSVGValue.booleanValue()) {
+				writeHTMLToFile(cgview, SVG_OUT_PATH + "/" + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "." + "svgz", "svgz", seriesValue + File.separator + Integer.toString(imageToDraw.getZoomValue()) + "_" + Integer.toString(imageToDraw.getZoomCenter()) + "_svg." + "html", imageToDraw.getZoomOutFilePrefix(toDrawPreviousZoom, zoomValues[k - 1]) + "." + "html", null, imageToDraw.getClockwiseFilePrefix(toDrawCurrentZoom) + "." + "html", imageT [...]
+			    }
+                        }
+                    }
+                }
+                //now need to move toDrawNextZoom items into toDrawCurrentZoom
+                toDrawPreviousZoom.clear();
+                toDrawPreviousZoom = (ArrayList) toDrawCurrentZoom.clone();
+                toDrawCurrentZoom.clear();
+                toDrawCurrentZoom = (ArrayList) toDrawNextZoom.clone();
+                toDrawNextZoom.clear();
+            }
+        }
+        System.exit(0);
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Feature$SortFeatureRangesByStart.class b/cgview/src/ca/ualberta/stothard/cgview/Feature$SortFeatureRangesByStart.class
new file mode 100644
index 0000000..cc62b35
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/Feature$SortFeatureRangesByStart.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Feature.class b/cgview/src/ca/ualberta/stothard/cgview/Feature.class
new file mode 100644
index 0000000..f123759
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/Feature.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Feature.java b/cgview/src/ca/ualberta/stothard/cgview/Feature.java
new file mode 100644
index 0000000..9dfa65a
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/Feature.java
@@ -0,0 +1,461 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.util.*;
+
+/**
+ * This class represents a sequence feature.  Feature objects (along with the FeatureRange objects) are used to describe
+ * individual sequence features. Feature objects can specify, for example, the color, opacity, and thickness of a
+ * sequence feature. They can also be used to provide a text label. The Feature object does not dictate which bases
+ * contain the sequence feature. The position information is instead provided by FeatureRange objects contained by the
+ * Feature objects.
+ *
+ * @author Paul Stothard
+ */
+
+public class Feature implements CgviewConstants {
+
+    private String label;
+    private String hyperlink;
+    private String mouseover;
+    private ArrayList ranges = new ArrayList();
+    private Color color = new Color(0, 0, 255); //blue
+    private int strand;
+    private Font font;
+    private boolean forceLabel = false;
+    private int showLabel = LABEL;
+
+    private int decoration = DECORATION_STANDARD;
+    private float radiusAdjustment = 0.0f;
+    private float proportionOfThickness = 1.0f;
+    private float opacity = 1.0f;
+
+    private boolean showShading;
+
+    /**
+     * Constructs a new Feature object.
+     *
+     * @param featureSlot the FeatureSlot object to contain this Feature.
+     * @param label       the text label for this Feature. This label will be used in any labels generated for the
+     *                    Feature when it is drawn.
+     */
+    public Feature(FeatureSlot featureSlot, String label) {
+        this.label = label;
+        this.strand = featureSlot.getStrand();
+        this.showShading = featureSlot.getShowShading();
+        //add this feature to the FeatureSlot.
+        featureSlot.addFeature(this);
+    }
+
+    /**
+     * Constructs a new Feature object.
+     *
+     * @param featureSlot the FeatureSlot object to contain this Feature.
+     */
+    public Feature(FeatureSlot featureSlot) {
+        this.strand = featureSlot.getStrand();
+        this.showShading = featureSlot.getShowShading();
+        //add this feature to the FeatureSlot.
+        featureSlot.addFeature(this);
+    }
+
+    /**
+     * Constructs a new Feature object. The Feature object must be added to a FeatureSlot using the {@link
+     * #setFeatureSlot(FeatureSlot) setFeatureSlot()} method. method.
+     */
+    public Feature() {
+
+    }
+
+    /**
+     * Constructs a new Feature object. The Feature object must be added to a FeatureSlot using the {@link
+     * #setFeatureSlot(FeatureSlot) setFeatureSlot()} method. method.
+     *
+     * @param showShading whether or not this Feature should be drawn with shading.
+     */
+    public Feature(boolean showShading) {
+        this.showShading = showShading;
+    }
+
+    /**
+     * Places this Feature into a FeatureSlot.
+     *
+     * @param featureSlot the FeatureSlot to contain this Feature.
+     */
+    public void setFeatureSlot(FeatureSlot featureSlot) {
+        this.strand = featureSlot.getStrand();
+        featureSlot.addFeature(this);
+    }
+
+    /**
+     * Adds a FeatureRange to this Feature.
+     *
+     * @param featureRange the FeatureRange object to add to this Feature.
+     */
+    protected void addRange(FeatureRange featureRange) {
+        ranges.add(featureRange);
+    }
+
+    /**
+     * Returns an ArrayList of FeatureRange objects contained by this Feature.
+     *
+     * @return an ArrayList of FeatureRange objects.
+     */
+    protected ArrayList getRanges() {
+        return ranges;
+    }
+
+    /**
+     * Sets the default color that will be assigned to FeatureRange objects added to this Feature. This color can be
+     * changed for individual FeatureRange objects using {@link FeatureRange#setColor(Color) FeatureRange.setColor()}.
+     *
+     * @param color the default FeatureRange color.
+     */
+    public void setColor(Color color) {
+        this.color = color;
+    }
+
+    /**
+     * Returns the default color that will be assigned to FeatureRange objects added to this Feature.
+     *
+     * @return the default FeatureRange color.
+     */
+    public Color getColor() {
+        return color;
+    }
+
+    /**
+     * Specifies whether or not labels created for this Feature should be drawn even if they cannot be placed such that
+     * they do not clash with other labels. This behaviour can be set for individual FeatureRange objects using {@link
+     * FeatureRange#setForceLabel(boolean) FeatureRange.setForceLabel()}.
+     *
+     * @param forceLabel a boolean specifying whether or not to draw labels for this Feature even if they cannot be
+     *                   placed such that they do not clash with other labels.
+     */
+    public void setForceLabel(boolean forceLabel) {
+        this.forceLabel = forceLabel;
+        if (this.forceLabel == true) {
+            showLabel = LABEL_FORCE;
+        }
+    }
+
+    /**
+     * Returns a boolean specifying whether or not labels created for this Feature should be drawn even if they cannot
+     * be placed such that they do not clash with other labels.
+     *
+     * @return whether or not to draw labels for this Feature even if they cannot be placed such that they do not clash
+     *         with other labels.
+     */
+    public boolean getForceLabel() {
+        return forceLabel;
+    }
+
+    /**
+     * Sets the label text for this Feature. This label will be used in any labels generated for this Feature. This
+     * label can be changed for individual FeatureRange objects using {@link FeatureRange#setLabel(String)
+     * FeatureRange.setLabel()}.
+     *
+     * @param label the label for this Feature.
+     */
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    /**
+     * Returns the label text for this Feature. This label will be used in any labels generated for this Feature. This
+     * label can be changed for individual featureRanges using {@link FeatureRange#setLabel(String)
+     * FeatureRange.setLabel()}.
+     *
+     * @return the label for this Feature.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Specifies a hyperlink to be associated with this Feature. Hyperlinks are included in SVG output generated using
+     * {@link CgviewIO#writeToSVGFile(ca.ualberta.stothard.cgview.Cgview, java.lang.String, boolean, boolean)} or in
+     * image maps for PNG and JPG images generated using {@link CgviewIO#writeHTMLFile(ca.ualberta.stothard.cgview.Cgview,
+            * java.lang.String, java.lang.String, java.lang.String)}.
+     *
+     * @param hyperlink a hyperlink for this Feature.
+     */
+    public void setHyperlink(String hyperlink) {
+        this.hyperlink = hyperlink;
+    }
+
+    /**
+     * Returns the hyperlink to be associated with this Feature.
+     *
+     * @return the hyperlink for this Feature.
+     */
+    public String getHyperlink() {
+        return hyperlink;
+    }
+
+    /**
+     * Specifies a mouseover to be associated with this Feature. Mouseovers are included in SVG output generated using
+     * {@link CgviewIO#writeToSVGFile(ca.ualberta.stothard.cgview.Cgview, java.lang.String, boolean, boolean)} or in
+     * image maps for PNG and JPG images generated using {@link CgviewIO#writeHTMLFile(ca.ualberta.stothard.cgview.Cgview,
+            * java.lang.String, java.lang.String, java.lang.String)}.
+     *
+     * @param mouseover the mouseover for this feature.
+     */
+    public void setMouseover(String mouseover) {
+        this.mouseover = mouseover;
+    }
+
+    /**
+     * Returns the mouseover to be associated with this Feature.
+     *
+     * @return the mouseover for this Feature.
+     */
+    public String getMouseover() {
+        return mouseover;
+    }
+
+    /**
+     * Sets the font used for labels generated for this Feature. This font can be changed for individual FeatureRange
+     * objects using {@link FeatureRange#setFont(Font) FeatureRange.setFont()}.
+     *
+     * @param font the font used for labels generated for this Feature.
+     */
+    public void setFont(Font font) {
+        this.font = font;
+    }
+
+    /**
+     * Returns the font used for labels generated for this Feature. This font can be changed for individual
+     * FeatureRanges using {@link FeatureRange#setFont(Font) FeatureRange.setFont()}.
+     *
+     * @return the font used for labels generated for this Feature.
+     */
+    public Font getFont() {
+        return font;
+    }
+
+    /**
+     * Returns the strand of this Feature, which is determined by the FeatureSlot that contains this Feature.
+     *
+     * @return an <code>int</code> representing the strand of this feature.
+     */
+    protected int getStrand() {
+        return strand;
+    }
+
+    /**
+     * Sets whether or not a label should be drawn for this Feature. This setting can be changed for individual
+     * FeatureRange objects using {@link FeatureRange#setShowLabel(int) FeatureRange.setShowLabel()}.
+     *
+     * @param showLabel {@link CgviewConstants#LABEL CgviewConstants.LABEL}, {@link CgviewConstants#LABEL_NONE
+     *                  CgviewConstants.NO_LABEL}, or {@link CgviewConstants#LABEL_FORCE CgviewConstants.LABEL_FORCE}.
+     */
+    public void setShowLabel(int showLabel) {
+        this.showLabel = showLabel;
+        if (this.showLabel == LABEL_FORCE) {
+            forceLabel = true;
+        } else {
+            forceLabel = false;
+        }
+    }
+
+    /**
+     * Returns whether or not a label should be generated for this Feature when drawn. This setting can be changed for
+     * individual FeatureRange objects using {@link FeatureRange#setShowLabel(int) FeatureRange.setShowLabel()}.
+     *
+     * @return {@link CgviewConstants#LABEL CgviewConstants.LABEL}, {@link CgviewConstants#LABEL_NONE
+     *         CgviewConstants.NO_LABEL}, or {@link CgviewConstants#LABEL_FORCE CgviewConstants.LABEL_FORCE}.
+     */
+    public int getShowLabel() {
+        return showLabel;
+    }
+
+    /**
+     * Sets the type of decoration added to this Feature when drawn. This decoration can be changed for individual
+     * FeatureRange objects using {@link FeatureRange#setDecoration(int) FeatureRange.setDecoration()}.
+     *
+     * @param decoration {@link CgviewConstants#DECORATION_STANDARD CgviewConstants.DECORATION_STANDARD}, {@link
+     *                   CgviewConstants#DECORATION_COUNTERCLOCKWISE_ARROW CgviewConstants.DECORATION_COUNTERCLOCKWISE_ARROW},
+     *                   {@link CgviewConstants#DECORATION_CLOCKWISE_ARROW CgviewConstants.DECORATION_CLOCKWISE_ARROW},
+     *                   {@link CgviewConstants#DECORATION_HIDDEN CgviewConstants.DECORATION_HIDDEN}.
+     */
+    public void setDecoration(int decoration) {
+        this.decoration = decoration;
+    }
+
+    /**
+     * Returns an integer indicating what type of decoration will be added to this Feature when drawn. This decoration
+     * can be changed for individual FeatureRange objects using {@link FeatureRange#setDecoration(int)
+     * FeatureRange.setDecoration()}.
+     *
+     * @return {@link CgviewConstants#DECORATION_STANDARD CgviewConstants.DECORATION_STANDARD}, {@link
+     *         CgviewConstants#DECORATION_COUNTERCLOCKWISE_ARROW CgviewConstants.DECORATION_COUNTERCLOCKWISE_ARROW},
+     *         {@link CgviewConstants#DECORATION_CLOCKWISE_ARROW CgviewConstants.DECORATION_CLOCKWISE_ARROW}, {@link
+     *         CgviewConstants#DECORATION_HIDDEN CgviewConstants.DECORATION_HIDDEN}.
+     */
+    public int getDecoration() {
+        return decoration;
+    }
+
+    /**
+     * Sets the position of this Feature relative to the FeatureSlot object that contains it. This value is only applied
+     * when the thickness of this Feature is adjusted using {@link #setProportionOfThickness(float)} so that it is less
+     * than 1.0. This setting can be changed for individual FeatureRange objects using {@link
+     * FeatureRange#setRadiusAdjustment(float) FeatureRange.setProportionOfThickness()}.
+     *
+     * @param radiusAdjustment between <code>0</code> and <code>1</code>, with <code>1</code> being near the edge
+     *                         furthest from the map center.
+     */
+    public void setRadiusAdjustment(float radiusAdjustment) {
+        if (radiusAdjustment < 0) {
+            radiusAdjustment = 0.0f;
+        } else if (radiusAdjustment > 1) {
+            radiusAdjustment = 1.0f;
+        }
+        this.radiusAdjustment = radiusAdjustment;
+    }
+
+    /**
+     * Returns the position of this Feature relative to the FeatureSlot object that contains it. This value is only
+     * applied when the thickness of this Feature is adjusted using {@link #setProportionOfThickness(float)} so that it
+     * is less than 1.0. This setting can be changed for individual FeatureRange objects using {@link
+     * FeatureRange#setRadiusAdjustment(float) FeatureRange.setProportionOfThickness()}.
+     *
+     * @return a <code>float</code> between <code>0</code> and <code>1</code>, with <code>1</code> being near the edge
+     *         furthest from the map center.
+     * @see #setProportionOfThickness(float)
+     */
+    public float getRadiusAdjustment() {
+        return radiusAdjustment;
+    }
+
+    /**
+     * Sets the thickness of this Feature when drawn, as a proportion of the thickness of the FeatureSlot containing
+     * this Feature. This setting can be changed for individual FeatureRange objects using {@link
+     * FeatureRange#setProportionOfThickness(float) FeatureRange.setProportionOfThickness()}.
+     *
+     * @param proportionOfThickness between <code>0</code> and <code>1</code>, with <code>1</code> being full
+     *                              thickness.
+     */
+    public void setProportionOfThickness(float proportionOfThickness) {
+        if (proportionOfThickness < 0) {
+            proportionOfThickness = 0.0f;
+        } else if (proportionOfThickness > 1) {
+            proportionOfThickness = 1.0f;
+        }
+        this.proportionOfThickness = proportionOfThickness;
+    }
+
+    /**
+     * Returns the thickness of this Feature when drawn, as a proportion of the thickness of the FeatureSlot containing
+     * this Feature. This setting can be changed for individual FeatureRange objects using {@link
+     * FeatureRange#setProportionOfThickness(float) FeatureRange.setProportionOfThickness()}.
+     *
+     * @return a <code>float</code> between <code>0</code> and <code>1</code>, with <code>1</code> being full
+     *         thickness.
+     */
+    public float getProportionOfThickness() {
+        return proportionOfThickness;
+    }
+
+    /**
+     * Sets the opacity of this Feature when drawn. This setting can be changed for individual FeatureRange objects
+     * using {@link FeatureRange#setOpacity(float) FeatureRange.setSwatchOpacity()}.
+     *
+     * @param opacity the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public void setOpacity(float opacity) {
+        if (opacity < 0) {
+            opacity = 0.0f;
+        } else if (opacity > 1) {
+            opacity = 1.0f;
+        }
+        this.opacity = opacity;
+    }
+
+    /**
+     * Returns the opacity of this Feature when drawn. This setting can be changed for individual FeatureRange objects
+     * using {@link FeatureRange#setOpacity(float) FeatureRange.setSwatchOpacity()}.
+     *
+     * @return the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public float getOpacity() {
+        return opacity;
+    }
+
+    /**
+     * Sets whether or not this Feature should be drawn with shading.
+     *
+     * @param showShading whether or not this Feature should be drawn with shading.
+     */
+    public void setShowShading(boolean showShading) {
+        this.showShading = showShading;
+    }
+
+    /**
+     * Returns whether or not this Feature should be drawn with shading.
+     *
+     * @return whether or not this Feature should be drawn with shading.
+     */
+    public boolean getShowShading() {
+        return showShading;
+    }
+
+    /**
+     * Draws this Feature and creates labels if necessary.
+     *
+     * @param cgview    the Cgview object containing this Feature.
+     * @param radius    the radius of the FeatureSlot containing this Feature.
+     * @param thickness the thickness of the FeatureSlot containing this Feature.
+     */
+    protected void draw(Cgview cgview, double radius, float thickness) {
+        Iterator i = ranges.iterator();
+        while (i.hasNext()) {
+            FeatureRange currentFeatureRange = (FeatureRange) i.next();
+            currentFeatureRange.draw(cgview, radius, thickness);
+            //remove once drawn
+            //i.remove();
+        }
+    }
+
+    /**
+     * Returns the smallest start value from the featureRanges in this Feature, or -1 if there are no featureRanges.
+     *
+     * @return the smallest featureRange start in this featureRange or -1.
+     */
+    protected int getStart () {
+
+	if (ranges.size() == 0) {
+	    return -1;
+	}
+
+	Comparator comparator = new SortFeatureRangesByStart();
+        Collections.sort(ranges, comparator);
+
+	FeatureRange first = (FeatureRange) ranges.get(0);
+	return first.getStart();
+	
+    }
+
+    //sort so that smallest start is first.
+    public class SortFeatureRangesByStart implements Comparator {
+
+	public int compare(Object o1, Object o2) {
+	    FeatureRange feature1 = (FeatureRange) o1;
+	    FeatureRange feature2 = (FeatureRange) o2;
+
+	    if (feature1.getStart() == feature2.getStart()) {
+		return 0;
+	    } else if (feature2.getStart() < feature1.getStart()) {
+		return 1;
+	    } else {
+		return -1;
+	    }
+	}
+
+	public boolean equals(Object obj) {
+	    return obj.equals(this);
+	}
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FeatureRange.class b/cgview/src/ca/ualberta/stothard/cgview/FeatureRange.class
new file mode 100644
index 0000000..47bbd76
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/FeatureRange.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FeatureRange.java b/cgview/src/ca/ualberta/stothard/cgview/FeatureRange.java
new file mode 100644
index 0000000..8cb71ec
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/FeatureRange.java
@@ -0,0 +1,1205 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.awt.geom.*;
+import java.util.regex.*;
+
+/**
+ * This class is used to assign sequence features, which are described using the Feature object, to specific bases of a
+ * DNA sequence. FeatureRange objects inherit most of their attributes from the parent Feature object.
+ *
+ * @author Paul Stothard
+ */
+
+public class FeatureRange implements CgviewConstants {
+    private int start;
+    private int stop;
+
+    private int decoration;
+    private int showLabel;
+
+    private String hyperlink;
+    private String mouseover;
+
+    private Color color;
+    private Feature feature;
+
+    private String label;
+    private Font font;
+    private boolean forceLabel;
+
+    private float radiusAdjustment;
+    private float proportionOfThickness;
+    private float opacity;
+
+    private boolean showShading;
+
+    /**
+     * Constructs a new <code>FeatureRange</code> object. The <code>start</code> and <code>stop</code> positions refer
+     * to the direct strand. If the <code>start</code> is greater than the <code>stop</code>, the feature is assumed to
+     * extend from the start, across the end of the sequence, to the stop. If <code>start</code> equals
+     * <code>stop</code>, the FeatureRange is assumed to refer to a single base.
+     *
+     * @param feature the Feature object to contain this FeatureRange.
+     * @param start   the first base in this FeatureRange.
+     * @param stop    the last base in this FeatureRange.
+     */
+    public FeatureRange(Feature feature, int start, int stop) {
+        this.start = start;
+        this.stop = stop;
+        feature.addRange(this);
+
+        decoration = feature.getDecoration();
+        showLabel = feature.getShowLabel();
+
+        color = feature.getColor();
+        this.feature = feature;
+
+        this.hyperlink = feature.getHyperlink();
+        this.mouseover = feature.getMouseover();
+
+        label = feature.getLabel();
+        font = feature.getFont();
+        forceLabel = feature.getForceLabel();
+
+        radiusAdjustment = feature.getRadiusAdjustment();
+        proportionOfThickness = feature.getProportionOfThickness();
+        opacity = feature.getOpacity();
+
+        showShading = feature.getShowShading();
+
+    }
+
+    /**
+     * Returns the position of the first base in this FeatureRange.
+     *
+     * @return the position of the first base in this FeatureRange.
+     */
+    public int getStart() {
+        return start;
+    }
+
+    /**
+     * Returns the position of the last base in this FeatureRange.
+     *
+     * @return the position of the last base in this FeatureRange.
+     */
+    public int getStop() {
+        return stop;
+    }
+
+    /**
+     * Specifies whether or not labels created for this FeatureRange should be drawn even if they cannot be placed such
+     * that they do not clash with other labels.
+     *
+     * @param forceLabel a boolean specifying whether or not to draw labels for this FeatureRange even if they cannot be
+     *                   placed such that they do not clash with other labels.
+     */
+    public void setForceLabel(boolean forceLabel) {
+        this.forceLabel = forceLabel;
+        if (this.forceLabel == true) {
+            showLabel = LABEL_FORCE;
+        }
+    }
+
+    /**
+     * Returns a boolean specifying whether or not labels created for this FeatureRange should be drawn even if they
+     * cannot be placed such that they do not clash with other labels.
+     *
+     * @return whether or not to draw labels for this FeatureRange even if they cannot be placed such that they do not
+     *         clash with other labels.
+     */
+    public boolean getForceLabel() {
+        return forceLabel;
+    }
+
+    /**
+     * Draws this FeatureRange and creates a label if necessary.
+     *
+     * @param cgview    the Cgview object that contains this FeatureRange.
+     * @param radius    the radius of the FeatureSlot that contains this FeatureRange.
+     * @param thickness the thickness of the FeatureSlot that contains this FeatureRange.
+     */
+    protected void draw(Cgview cgview, double radius, float thickness) {
+
+        boolean keepLastLabels = cgview.getKeepLastLabels();
+
+        //case -1: if start or stop are < 1 or greater than the length of the plasmid, do not draw
+        if ((start < 1) || (stop < 1) || (start > cgview.getSequenceLength()) || (stop > cgview.getSequenceLength())) {
+            System.err.println("[warning] Invalid feature position encountered: start = " + start + ", stop = " + stop + ".");
+        }
+
+        //case 0: if drawing the entire plasmid just draw the feature
+        else if (cgview.getDrawEntirePlasmid()) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, stop, thickness);
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawClockwiseArrow(cgview, radius, start, stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, stop);
+            }
+
+            //System.out.println ("case0");
+        }
+
+        //case 1: both bases are equal and they are in one of the zoomRanges
+        else if ((start == stop) && (cgview.inZoomRange(start))) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, stop, thickness);
+
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawClockwiseArrow(cgview, radius, start, stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, stop);
+            }
+            //System.out.println ("case1");
+        }
+
+        //case 2: start is in zoomRangeOne and stop is in zoomRangeTwo
+        else if ((cgview.inZoomRangeOne(start)) && (cgview.inZoomRangeTwo(stop))) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, stop, thickness);
+
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawClockwiseArrow(cgview, radius, start, stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, stop);
+            }
+            //System.out.println ("case2");
+        }
+
+        //case 3: start and stop are in zoomRangeOne and start is less than stop
+        else if ((cgview.inZoomRangeOne(start)) && (cgview.inZoomRangeOne(stop)) && (start < stop)) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, stop, thickness);
+
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawClockwiseArrow(cgview, radius, start, stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, stop);
+            }
+            //System.out.println ("case3");
+        }
+
+        //case 4: start and stop are in zoomRangeTwo and start is less than stop
+        else if ((cgview.inZoomRangeTwo(start)) && (cgview.inZoomRangeTwo(stop)) && (start < stop)) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, stop, thickness);
+
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawClockwiseArrow(cgview, radius, start, stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, stop);
+            }
+            // System.out.println ("case4");
+        }
+
+
+        //case 5: start is in zoomRangeTwo and stop is in zoomRangeOne
+        else if ((cgview.inZoomRangeTwo(start)) && (cgview.inZoomRangeOne(stop))) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawClockwiseArrow(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, cgview.getZoomRangeTwoStop());
+                labelStandard(cgview, cgview.getZoomRangeOneStart(), stop);
+            }
+            //System.out.println ("case5");
+        }
+
+        //case 6: start is in zoomRangeOne and stop is in zoomRangeOne and start > stop
+        else if ((cgview.inZoomRangeOne(start)) && (cgview.inZoomRangeOne(stop)) && (start > stop)) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawClockwiseArrow(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, cgview.getZoomRangeTwoStop());
+                labelStandard(cgview, cgview.getZoomRangeOneStart(), stop);
+            }
+            //System.out.println ("case6");
+        }
+
+        //case 7: start is in zoomRangeTwo and stop is in zoomRangeTwo and start > stop
+        else if ((cgview.inZoomRangeTwo(start)) && (cgview.inZoomRangeTwo(stop)) && (start > stop)) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawClockwiseArrow(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, cgview.getZoomRangeTwoStop());
+                labelStandard(cgview, cgview.getZoomRangeOneStart(), stop);
+            }
+            //System.out.println ("case7");
+        }
+
+        //case 8: stop is in zoomRange
+        else if (cgview.inZoomRange(stop)) {
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawClockwiseArrow(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), stop, thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, cgview.getZoomRangeOneStart(), stop);
+            }
+            //System.out.println ("case8");
+        }
+
+        //case 9: start is in zoomRange
+        else if (cgview.inZoomRange(start)) {
+
+            if (decoration == DECORATION_STANDARD) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+            } else if (decoration == DECORATION_CLOCKWISE_ARROW) {
+                drawStandard(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+            } else if (decoration == DECORATION_COUNTERCLOCKWISE_ARROW) {
+                drawCounterclockwiseArrow(cgview, radius, start, cgview.getZoomRangeTwoStop(), thickness);
+            }
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, start, cgview.getZoomRangeTwoStop());
+            }
+
+            //System.out.println ("case9");
+        }
+
+        //case 10: range spans zoomRange
+        else if ((start < cgview.getZoomRangeOneStart()) && (stop > cgview.getZoomRangeTwoStop()) && (start != stop)) {
+            if (cgview.getZoomRangeTwoStart() == 0) {
+                if (start > stop) {
+                    drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop(), thickness);
+
+                    if ((showLabel == LABEL) && (!keepLastLabels)) {
+                        labelStandard(cgview, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop());
+                    }
+                    //System.out.println ("case10");
+                }
+            } else {
+                drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop(), thickness);
+                if ((showLabel == LABEL) && (!keepLastLabels)) {
+                    labelStandard(cgview, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop());
+                }
+                //System.out.println ("case10.5");
+            }
+        }
+
+        //case 11: range spans zoomRange
+        else if ((stop > cgview.getZoomRangeTwoStop()) && (start > stop)) {
+            drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop(), thickness);
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop());
+            }
+            //System.out.println ("case11");
+        }
+
+        //case 12: range spans zoomRange
+        else if ((start < cgview.getZoomRangeOneStart()) && (start > stop)) {
+            drawStandard(cgview, radius, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop(), thickness);
+
+            if ((showLabel == LABEL) && (!keepLastLabels)) {
+                labelStandard(cgview, cgview.getZoomRangeOneStart(), cgview.getZoomRangeTwoStop());
+            }
+            //System.out.println ("case12");
+        } else {
+            //don't draw anything
+            //System.out.println ("no label");
+        }
+    }
+
+    /**
+     * Draws this FeatureRange as a simple arc.
+     *
+     * @param cgview    the Cgview object that contains this FeatureRange.
+     * @param radius    the radius of the FeatureSlot that contains this FeatureRange.
+     * @param startBase the adjusted position of the first base in this FeatureRange.
+     * @param stopBase  the adjusted position of the last base in this FeatureRange.
+     * @param thickness the thickness of the FeatureSlot that contains this FeatureRange.
+     */
+    private void drawStandard(Cgview cgview, double radius, int startBase, int stopBase, float thickness) {
+
+        float featureThickness = thickness;
+        double shadingProportion = cgview.getShadingProportion();
+        double minimumFeatureLength = cgview.getMinimumFeatureLength();
+        float highlightOpacity = cgview.getHighlightOpacity();
+        float shadowOpacity = cgview.getShadowOpacity();
+        double originOffset = cgview.getOrigin();
+        Graphics2D gg = cgview.getGraphics();
+        int totalBases = cgview.getSequenceLength();
+        boolean shiftSmallFeatures = cgview.getShiftSmallFeatures();
+	
+
+        //adjust radius to take into account proportionOfThickness and radiusAdjustment values;
+        //radius = radius - 0.5d * featureThickness + 0.5d * (proportionOfThickness * featureThickness) + radiusAdjustment * (featureThickness - (proportionOfThickness * featureThickness));
+	double newRadius = radius;
+	if (proportionOfThickness < 1.0f) {
+	    newRadius = radius - 0.5d * featureThickness;
+	    newRadius = newRadius + featureThickness * radiusAdjustment;
+	}
+	//prevent drawing outside of feature slot for this feature
+	double maxRadiusForThisFeature = radius + featureThickness * 0.5d - (0.5d * featureThickness * proportionOfThickness);
+	double minRadiusForThisFeature = radius - featureThickness * 0.5d + (0.5d * featureThickness * proportionOfThickness);
+
+	if (newRadius > maxRadiusForThisFeature) {
+	    newRadius = maxRadiusForThisFeature;
+	}
+	if (newRadius < minRadiusForThisFeature) {
+	    newRadius = minRadiusForThisFeature;
+	}
+	radius = newRadius;
+
+        featureThickness = proportionOfThickness * featureThickness;
+
+        double startOfArc;
+        double extentOfArc;
+
+        //typical case where start is less than stop
+        if (startBase <= stopBase) {
+
+            startOfArc = cgview.getDegrees(startBase - 1);
+            extentOfArc = cgview.getDegrees(stopBase) - startOfArc;
+        }
+        //case where feature spans junction
+        else {
+
+            startOfArc = cgview.getDegrees(startBase - 1);
+            extentOfArc = cgview.getDegrees(totalBases) - startOfArc;
+
+            double startOfArcB = cgview.getDegrees(1 - 1);
+            double extentOfArcB = cgview.getDegrees(stopBase) - startOfArcB;
+
+            extentOfArc = extentOfArc + extentOfArcB;
+
+        }
+
+        //check to see if the arc is below cgview.getMinimunFeatureLength() and if it is make adjustments
+        if ((extentOfArc * (Math.PI / 180.0d) * radius) < minimumFeatureLength) {
+            extentOfArc = (minimumFeatureLength / radius) * (180.0d / Math.PI);
+            if (shiftSmallFeatures) {
+                startOfArc = startOfArc - 0.5d * extentOfArc;
+            }
+        }
+
+        gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+        gg.setPaint(color);
+        BasicStroke arcStroke = new BasicStroke(featureThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+        Area centralArc = new Area();
+        centralArc.add(new Area(arcStroke.createStrokedShape(new Arc2D.Double(-radius, -radius, radius * 2.0d, radius * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+
+        //to prevent drawing off canvas
+        centralArc.intersect(new Area(cgview.getBackgroundRectangle()));
+        gg.fill(centralArc);
+
+
+        //if (cgview.getShowShading()) {
+        if (this.feature.getShowShading()) {
+            //draw highlight
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity * opacity));
+            gg.setPaint(Color.white);
+
+            double radiusIncrease = 0.5d * featureThickness - 0.5d * (featureThickness * shadingProportion);
+            BasicStroke highlightArcStroke = new BasicStroke(featureThickness * (float) (shadingProportion), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+            Area highlightArc = new Area();
+            highlightArc.add(new Area(highlightArcStroke.createStrokedShape(new Arc2D.Double(-radius - radiusIncrease, -radius - radiusIncrease, (radius + radiusIncrease) * 2.0d, (radius + radiusIncrease) * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+            highlightArc.intersect(new Area(cgview.getBackgroundRectangle()));
+            gg.fill(highlightArc);
+
+
+            //draw shadow
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity * opacity));
+            gg.setPaint(Color.black);
+            double radiusDecrease = -0.5d * featureThickness + 0.5d * (featureThickness * shadingProportion);
+            BasicStroke shadowArcStroke = new BasicStroke(featureThickness * (float) (shadingProportion), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+            Area shadowArc = new Area();
+            shadowArc.add(new Area(shadowArcStroke.createStrokedShape(new Arc2D.Double(-radius - radiusDecrease, -radius - radiusDecrease, (radius + radiusDecrease) * 2.0d, (radius + radiusDecrease) * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+            shadowArc.intersect(new Area(cgview.getBackgroundRectangle()));
+            gg.fill(shadowArc);
+
+        }
+
+        //set back to 1.0f
+        gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+
+    }
+
+
+    /**
+     * Draws this FeatureRange as an arrow pointing in the clockwise direction.
+     *
+     * @param cgview    the Cgview object that contains this FeatureRange.
+     * @param radius    the radius of the FeatureSlot that contains this FeatureRange.
+     * @param startBase the adjusted position of the first base in this FeatureRange.
+     * @param stopBase  the adjusted position of the last base in this FeatureRange.
+     * @param thickness the thickness of the FeatureSlot that contains this FeatureRange.
+     */
+    private void drawClockwiseArrow(Cgview cgview, double radius, int startBase, int stopBase, float thickness) {
+
+        float featureThickness = thickness;
+        double shadingProportion = cgview.getShadingProportion();
+        float highlightOpacity = cgview.getHighlightOpacity();
+        float shadowOpacity = cgview.getShadowOpacity();
+        double originOffset = cgview.getOrigin();
+        Graphics2D gg = cgview.getGraphics();
+        int totalBases = cgview.getSequenceLength();
+        boolean shiftSmallFeatures = cgview.getShiftSmallFeatures();
+        double arrowLength = cgview.getArrowheadLength();
+
+        //adjust radius to take into account proportionOfThickness and radiusAdjustment values;
+        //radius = radius - 0.5d * featureThickness + 0.5d * (proportionOfThickness * featureThickness) + radiusAdjustment * (featureThickness - (proportionOfThickness * featureThickness));
+	double newRadius = radius;
+	if (proportionOfThickness < 1.0f) {
+	    newRadius = radius - 0.5d * featureThickness;
+	    newRadius = newRadius + featureThickness * radiusAdjustment;
+	}
+	//prevent drawing outside of feature slot for this feature
+	double maxRadiusForThisFeature = radius + featureThickness * 0.5d - (0.5d * featureThickness * proportionOfThickness);
+	double minRadiusForThisFeature = radius - featureThickness * 0.5d + (0.5d * featureThickness * proportionOfThickness);
+
+	if (newRadius > maxRadiusForThisFeature) {
+	    newRadius = maxRadiusForThisFeature;
+	}
+	if (newRadius < minRadiusForThisFeature) {
+	    newRadius = minRadiusForThisFeature;
+	}
+	radius = newRadius;
+
+
+        featureThickness = proportionOfThickness * featureThickness;
+
+        double startOfArc;
+        double extentOfArc;
+
+        //typical case where start is less than stop
+        if (startBase <= stopBase) {
+
+            startOfArc = cgview.getDegrees(startBase - 1);
+            extentOfArc = cgview.getDegrees(stopBase) - startOfArc;
+        }
+        //case where feature spans junction
+        else {
+            startOfArc = cgview.getDegrees(startBase - 1);
+            extentOfArc = cgview.getDegrees(totalBases) - startOfArc;
+
+            double startOfArcB = cgview.getDegrees(1 - 1);
+            double extentOfArcB = cgview.getDegrees(stopBase) - startOfArcB;
+
+            extentOfArc = extentOfArc + extentOfArcB;
+        }
+
+        int arrowBase;
+        double extentOfArcShift;
+        double arrowPointRadians;
+        double arrowBaseRadians;
+
+        arrowBase = stopBase;
+        extentOfArcShift = (arrowLength / radius) * (180.0d / Math.PI);
+
+	if (((extentOfArc * (Math.PI / 180.0d) * radius) < (arrowLength)) && (shiftSmallFeatures)) {
+
+            ///extentOfArc = extentOfArc - 0.5d * extentOfArcShift;
+
+            //now determine the position in radians of the arrow head base
+            //arrowPointRadians = -(-cgview.getDegrees(arrowBase) + originOffset - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+	    arrowPointRadians = -(-cgview.getDegrees(arrowBase) + originOffset + 0.5d * extentOfArc - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+
+            //now determine the position in radians of the arrow head point
+            //arrowBaseRadians = -(-cgview.getDegrees(arrowBase) + originOffset + ((arrowLength / radius) * (180.0d / Math.PI)) - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+	    arrowBaseRadians = -(-cgview.getDegrees(arrowBase) + originOffset + ((arrowLength / radius) * (180.0d / Math.PI)) + 0.5d * extentOfArc - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+	    
+	    extentOfArc = 0.0d;
+	    
+        } else {
+
+            extentOfArc = extentOfArc - extentOfArcShift;
+
+            //now determine the position in radians of the arrow head base
+            arrowPointRadians = -(-cgview.getDegrees(arrowBase) + originOffset) * (Math.PI / 180.0d);
+
+            //now determine the position in radians of the arrow head point
+            arrowBaseRadians = -(-cgview.getDegrees(arrowBase) + originOffset + ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+        }
+
+        //determine the radius of the outer edge of the arrow
+        double outerEdgeRadius = radius + 0.5d * featureThickness;
+
+        //determine the radius of the inner edge of the arrow
+        double innerEdgeRadius = radius - 0.5d * featureThickness;
+
+        //create areas for drawing the arc
+        Area centralArrow = new Area();
+        Area highlightArrow = new Area();
+        Area shadowArrow = new Area();
+
+        //create a GeneralPath to describe the arrow head
+        GeneralPath arrow = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+        arrow.moveTo((float) (Math.cos(arrowBaseRadians) * outerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * outerEdgeRadius));
+        arrow.lineTo((float) (Math.cos(arrowBaseRadians) * innerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * innerEdgeRadius));
+        arrow.lineTo((float) (Math.cos(arrowPointRadians) * radius), (float) (Math.sin(arrowPointRadians) * radius));
+        arrow.closePath();
+        centralArrow.add(new Area(arrow));
+
+        if (showShading) {
+            //create a GeneralPath to draw a highlight on the arrow
+            GeneralPath arrowHighlight = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+            arrowHighlight.moveTo((float) (Math.cos(arrowBaseRadians) * outerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * outerEdgeRadius));
+            arrowHighlight.lineTo((float) (Math.cos(arrowPointRadians) * radius), (float) (Math.sin(arrowPointRadians) * radius));
+            arrowHighlight.lineTo((float) (Math.cos(arrowBaseRadians) * (outerEdgeRadius - featureThickness * shadingProportion)), (float) (Math.sin(arrowBaseRadians) * (outerEdgeRadius - featureThickness * shadingProportion)));
+            highlightArrow.add(new Area(arrowHighlight));
+
+            //create a GeneralPath to draw a shadow on the arrow
+            GeneralPath arrowShadow = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+            arrowShadow.moveTo((float) (Math.cos(arrowBaseRadians) * innerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * innerEdgeRadius));
+            arrowShadow.lineTo((float) (Math.cos(arrowPointRadians) * radius), (float) (Math.sin(arrowPointRadians) * radius));
+            arrowShadow.lineTo((float) (Math.cos(arrowBaseRadians) * (innerEdgeRadius + featureThickness * shadingProportion)), (float) (Math.sin(arrowBaseRadians) * (innerEdgeRadius + featureThickness * shadingProportion)));
+            shadowArrow.add(new Area(arrowShadow));
+
+        }
+
+        //now draw the arc
+        if (extentOfArc > 0.0d) {
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+            gg.setPaint(color);
+            BasicStroke arcStroke = new BasicStroke(featureThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+            centralArrow.add(new Area(arcStroke.createStrokedShape(new Arc2D.Double(-radius, -radius, radius * 2.0d, radius * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+
+            //to prevent drawing off canvas
+            centralArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+            gg.fill(centralArrow);
+
+            if (showShading) {
+                //draw highlight
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity * opacity));
+                gg.setPaint(Color.white);
+                double radiusIncrease = 0.5d * featureThickness - 0.5d * (featureThickness * shadingProportion);
+                BasicStroke highlightArcStroke = new BasicStroke(featureThickness * (float) (shadingProportion), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+                highlightArrow.add(new Area(highlightArcStroke.createStrokedShape(new Arc2D.Double(-radius - radiusIncrease, -radius - radiusIncrease, (radius + radiusIncrease) * 2.0d, (radius + radiusIncrease) * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+                highlightArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(highlightArrow);
+
+                //draw shadow
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity * opacity));
+                gg.setPaint(Color.black);
+                double radiusDecrease = -0.5d * featureThickness + 0.5d * (featureThickness * shadingProportion);
+                BasicStroke shadowArcStroke = new BasicStroke(featureThickness * (float) (shadingProportion), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+                shadowArrow.add(new Area(shadowArcStroke.createStrokedShape(new Arc2D.Double(-radius - radiusDecrease, -radius - radiusDecrease, (radius + radiusDecrease) * 2.0d, (radius + radiusDecrease) * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+                shadowArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(shadowArrow);
+
+                //set back to 1.0f
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+
+            }
+        } else {
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+            gg.setPaint(color);
+            centralArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+            gg.fill(centralArrow);
+
+            if (showShading) {
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity * opacity));
+                gg.setPaint(Color.white);
+                highlightArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(highlightArrow);
+
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity * opacity));
+                gg.setPaint(Color.black);
+                shadowArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(shadowArrow);
+
+                //set back to 1.0f
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+            }
+        }
+    }
+
+    /**
+     * Draws this FeatureRange as an arrow pointing in the counterclockwise direction.
+     *
+     * @param cgview    the Cgview object that contains this FeatureRange.
+     * @param radius    the radius of the FeatureSlot that contains this FeatureRange.
+     * @param startBase the adjusted position of the first base in this FeatureRange.
+     * @param stopBase  the adjusted position of the last base in this FeatureRange.
+     * @param thickness the thickness of the FeatureSlot that contains this FeatureRange.
+     */
+    private void drawCounterclockwiseArrow(Cgview cgview, double radius, int startBase, int stopBase, float thickness) {
+
+        float featureThickness = thickness;
+        double shadingProportion = cgview.getShadingProportion();
+        float highlightOpacity = cgview.getHighlightOpacity();
+        float shadowOpacity = cgview.getShadowOpacity();
+        double originOffset = cgview.getOrigin();
+        Graphics2D gg = cgview.getGraphics();
+        int totalBases = cgview.getSequenceLength();
+        boolean shiftSmallFeatures = cgview.getShiftSmallFeatures();
+        double arrowLength = cgview.getArrowheadLength();
+
+        //adjust radius to take into account proportionOfThickness and radiusAdjustment values;
+        //radius = radius - 0.5d * featureThickness + 0.5d * (proportionOfThickness * featureThickness) + radiusAdjustment * (featureThickness - (proportionOfThickness * featureThickness));
+	double newRadius = radius;
+	if (proportionOfThickness < 1.0f) {
+	    newRadius = radius - 0.5d * featureThickness;
+	    newRadius = newRadius + featureThickness * radiusAdjustment;
+	}
+	//prevent drawing outside of feature slot for this feature
+	double maxRadiusForThisFeature = radius + featureThickness * 0.5d - (0.5d * featureThickness * proportionOfThickness);
+	double minRadiusForThisFeature = radius - featureThickness * 0.5d + (0.5d * featureThickness * proportionOfThickness);
+
+	if (newRadius > maxRadiusForThisFeature) {
+	    newRadius = maxRadiusForThisFeature;
+	}
+	if (newRadius < minRadiusForThisFeature) {
+	    newRadius = minRadiusForThisFeature;
+	}
+	radius = newRadius;
+
+
+        featureThickness = proportionOfThickness * featureThickness;
+
+        double startOfArc;
+        double extentOfArc;
+
+        //typical case where start is less than stop
+        if (startBase <= stopBase) {
+
+            startOfArc = cgview.getDegrees(startBase - 1);
+            extentOfArc = cgview.getDegrees(stopBase) - startOfArc;
+        }
+        //case where feature spans junction
+        else {
+
+            startOfArc = cgview.getDegrees(startBase - 1);
+            extentOfArc = cgview.getDegrees(totalBases) - startOfArc;
+
+            double startOfArcB = cgview.getDegrees(1 - 1);
+            double extentOfArcB = cgview.getDegrees(stopBase) - startOfArcB;
+
+            extentOfArc = extentOfArc + extentOfArcB;
+        }
+
+        int arrowBase;
+        double extentOfArcShift;
+        double arrowPointRadians;
+        double arrowBaseRadians;
+
+        arrowBase = startBase - 1;
+        extentOfArcShift = (arrowLength / radius) * (180.0d / Math.PI);
+
+        //this centers the arrow head when there is no arc
+        if (((extentOfArc * (Math.PI / 180.0d) * radius) < (arrowLength)) && (shiftSmallFeatures)) {
+
+            //extentOfArc = extentOfArc - 0.5d * extentOfArcShift;
+            //startOfArc = startOfArc + 0.5d * extentOfArcShift;
+
+
+            //now determine the position in radians of the arrow head base
+            //arrowBaseRadians = -(-cgview.getDegrees(arrowBase) + originOffset - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+	    arrowBaseRadians = -(-cgview.getDegrees(arrowBase) + originOffset - 0.5d * extentOfArc - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+
+            //now determine the position in radians of the arrow head point
+            //arrowPointRadians = -(-cgview.getDegrees(arrowBase) + originOffset + ((arrowLength / radius) * (180.0d / Math.PI)) - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+	    arrowPointRadians = -(-cgview.getDegrees(arrowBase) + originOffset - 0.5d * extentOfArc + ((arrowLength / radius) * (180.0d / Math.PI)) - 0.5d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+	    
+	    extentOfArc = 0.0d;
+
+
+        } else {
+            //startOfArc = startOfArc;
+            extentOfArc = extentOfArc - extentOfArcShift;
+            startOfArc = startOfArc + extentOfArcShift;
+
+            //now determine the position in radians of the arrow head base
+            arrowBaseRadians = -(-cgview.getDegrees(arrowBase) + originOffset - 1.0d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+
+            //now determine the position in radians of the arrow head point
+            arrowPointRadians = -(-cgview.getDegrees(arrowBase) + originOffset + ((arrowLength / radius) * (180.0d / Math.PI)) - 1.0d * ((arrowLength / radius) * (180.0d / Math.PI))) * (Math.PI / 180.0d);
+
+        }
+
+        //create areas for drawing the arc
+        Area centralArrow = new Area();
+        Area highlightArrow = new Area();
+        Area shadowArrow = new Area();
+
+        //determine the radius of the outer edge of the arrow
+        double outerEdgeRadius = radius + 0.5d * featureThickness;
+
+        //determine the radius of the inner edge of the arrow
+        double innerEdgeRadius = radius - 0.5d * featureThickness;
+
+        //create a GeneralPath to describe the arrow head
+        GeneralPath arrow = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+        arrow.moveTo((float) (Math.cos(arrowBaseRadians) * outerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * outerEdgeRadius));
+        arrow.lineTo((float) (Math.cos(arrowBaseRadians) * innerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * innerEdgeRadius));
+        arrow.lineTo((float) (Math.cos(arrowPointRadians) * radius), (float) (Math.sin(arrowPointRadians) * radius));
+        arrow.closePath();
+        centralArrow.add(new Area(arrow));
+
+
+        if (showShading) {
+            //create a GeneralPath to draw a highlight on the arrow
+            GeneralPath arrowHighlight = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+            arrowHighlight.moveTo((float) (Math.cos(arrowBaseRadians) * outerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * outerEdgeRadius));
+            arrowHighlight.lineTo((float) (Math.cos(arrowPointRadians) * radius), (float) (Math.sin(arrowPointRadians) * radius));
+            arrowHighlight.lineTo((float) (Math.cos(arrowBaseRadians) * (outerEdgeRadius - featureThickness * shadingProportion)), (float) (Math.sin(arrowBaseRadians) * (outerEdgeRadius - featureThickness * shadingProportion)));
+            highlightArrow.add(new Area(arrowHighlight));
+
+
+            //create a GeneralPath to draw a shadow on the arrow
+            GeneralPath arrowShadow = new GeneralPath(GeneralPath.WIND_NON_ZERO);
+            arrowShadow.moveTo((float) (Math.cos(arrowBaseRadians) * innerEdgeRadius), (float) (Math.sin(arrowBaseRadians) * innerEdgeRadius));
+            arrowShadow.lineTo((float) (Math.cos(arrowPointRadians) * radius), (float) (Math.sin(arrowPointRadians) * radius));
+            arrowShadow.lineTo((float) (Math.cos(arrowBaseRadians) * (innerEdgeRadius + featureThickness * shadingProportion)), (float) (Math.sin(arrowBaseRadians) * (innerEdgeRadius + featureThickness * shadingProportion)));
+            shadowArrow.add(new Area(arrowShadow));
+
+        }
+
+        //now draw the arc
+
+        if (extentOfArc > 0.0d) {
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+            gg.setPaint(color);
+            BasicStroke arcStroke = new BasicStroke(featureThickness, BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+            centralArrow.add(new Area(arcStroke.createStrokedShape(new Arc2D.Double(-radius, -radius, radius * 2.0d, radius * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+            //to prevent drawing off canvas
+            centralArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+            gg.fill(centralArrow);
+
+            if (showShading) {
+                //draw highlight
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity * opacity));
+                gg.setPaint(Color.white);
+                double radiusIncrease = 0.5d * featureThickness - 0.5d * (featureThickness * shadingProportion);
+                BasicStroke highlightArcStroke = new BasicStroke(featureThickness * (float) (shadingProportion), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+                highlightArrow.add(new Area(highlightArcStroke.createStrokedShape(new Arc2D.Double(-radius - radiusIncrease, -radius - radiusIncrease, (radius + radiusIncrease) * 2.0d, (radius + radiusIncrease) * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+                highlightArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(highlightArrow);
+
+                //draw shadow
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity * opacity));
+                gg.setPaint(Color.black);
+                double radiusDecrease = -0.5d * featureThickness + 0.5d * (featureThickness * shadingProportion);
+                BasicStroke shadowArcStroke = new BasicStroke(featureThickness * (float) (shadingProportion), BasicStroke.CAP_BUTT, BasicStroke.JOIN_BEVEL);
+                shadowArrow.add(new Area(shadowArcStroke.createStrokedShape(new Arc2D.Double(-radius - radiusDecrease, -radius - radiusDecrease, (radius + radiusDecrease) * 2.0d, (radius + radiusDecrease) * 2.0d, -startOfArc - extentOfArc + originOffset, extentOfArc, Arc2D.OPEN))));
+                shadowArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(shadowArrow);
+
+
+                //set back to 1.0f
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+            }
+        } else {
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
+            gg.setPaint(color);
+            centralArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+            gg.fill(centralArrow);
+
+            if (showShading) {
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, highlightOpacity * opacity));
+                gg.setPaint(Color.white);
+                highlightArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(highlightArrow);
+
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, shadowOpacity * opacity));
+                gg.setPaint(Color.black);
+                shadowArrow.intersect(new Area(cgview.getBackgroundRectangle()));
+                gg.fill(shadowArrow);
+
+                //set back to 1.0f
+                gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+            }
+        }
+
+    }
+
+    /**
+     * Creates a Label object for this FeatureRange.
+     *
+     * @param cgview    the Cgview object that contains this FeatureRange.
+     * @param startBase the adjusted position of the first base in this FeatureRange.
+     * @param stopBase  the adjusted position of the last base in this FeatureRange.
+     */
+    private void labelStandard(Cgview cgview, int startBase, int stopBase) {
+        double originOffset = cgview.getOrigin();
+        int totalBases = cgview.getSequenceLength();
+        double startOfArc;
+        double extentOfArc;
+
+        boolean drawLabel = true;
+
+        //decide whether to create a label
+        if (this.label == null) {
+            drawLabel = false;
+        } else {
+            Pattern p = Pattern.compile("\\S");
+            Matcher m = p.matcher(this.label);
+
+            if (!(m.find())) {
+                drawLabel = false;
+            }
+        }
+
+        if ((this.mouseover != null) || (this.hyperlink != null)) {
+            drawLabel = true;
+        }
+
+        if (drawLabel) {
+
+            //typical case where start is less than stop
+            if (startBase <= stopBase) {
+
+                startOfArc = cgview.getDegrees(startBase - 1);
+                extentOfArc = cgview.getDegrees(stopBase) - startOfArc;
+            }
+            //case where feature spans junction
+            else {
+
+                startOfArc = cgview.getDegrees(startBase - 1);
+                extentOfArc = cgview.getDegrees(totalBases) - startOfArc;
+
+                double startOfArcB = cgview.getDegrees(1 - 1);
+                double extentOfArcB = cgview.getDegrees(stopBase) - startOfArcB;
+
+                extentOfArc = extentOfArc + extentOfArcB;
+            }
+
+            //create the label
+            double arcMidPoint = -((-startOfArc - extentOfArc + originOffset) + (extentOfArc / 2.0d)) * Math.PI / 180.0d;
+            if (arcMidPoint < 0.0d) {
+                arcMidPoint = 2.0d * Math.PI + arcMidPoint;
+            }
+
+            String theLabel;
+            Label createdLabel;
+
+            //first decide what text to use in the label
+            //if not zoomed in just show the label name
+            if ((cgview.getGiveFeaturePositions() == POSITIONS_NO_SHOW) || ((cgview.getZoomMultiplier() < cgview.getZoomShift()) && (cgview.getGiveFeaturePositions() == POSITIONS_AUTO))) {
+                theLabel = label;
+
+            }
+            //if zoomed in add position information
+            else {
+                if (startBase == stopBase) {
+                    theLabel = label + " " + Integer.toString(this.start);
+                } else if (feature.getStrand() == REVERSE_STRAND) {
+                    if ((decoration == DECORATION_STANDARD) || (decoration == DECORATION_CLOCKWISE_ARROW)) {
+                        //theLabel = label + " " + Integer.toString(this.start) + "-" + Integer.toString(this.stop);
+                        theLabel = label + " " + Integer.toString(this.start) + "-" + Integer.toString(this.stop);
+                    } else {
+                        //theLabel = label + " " + Integer.toString(this.stop) + "-" + Integer.toString(this.start);
+                        theLabel = label + " " + Integer.toString(this.start) + "-" + Integer.toString(this.stop);
+                    }
+                } else {
+                    if ((decoration == DECORATION_STANDARD) || (decoration == DECORATION_CLOCKWISE_ARROW)) {
+                        theLabel = label + " " + Integer.toString(this.start) + "-" + Integer.toString(this.stop);
+                    } else {
+                        theLabel = label + " " + Integer.toString(this.stop) + "-" + Integer.toString(this.start);
+                    }
+                }
+            }
+
+            //now decide whether to make the label outside of the backbone or inside
+            //if not zoomed, make OuterLabels only
+            if ((cgview.getUseInnerLabels() == INNER_LABELS_NO_SHOW) || ((cgview.getZoomMultiplier() < cgview.getZoomShift()) && (cgview.getUseInnerLabels() == INNER_LABELS_AUTO))) {
+                createdLabel = new OuterLabel(cgview, theLabel, hyperlink, mouseover, font, color, forceLabel, arcMidPoint, feature.getStrand());
+            } else {
+                if (feature.getStrand() == DIRECT_STRAND) {
+                    createdLabel = new OuterLabel(cgview, theLabel, hyperlink, mouseover, font, color, forceLabel, arcMidPoint, feature.getStrand());
+                } else {
+                    createdLabel = new InnerLabel(cgview, theLabel, hyperlink, mouseover, font, color, forceLabel, arcMidPoint, feature.getStrand());
+                }
+            }
+        }
+    }
+
+    /**
+     * Sets whether or not a label a should be drawn for this FeatureRange.
+     *
+     * @param showLabel {@link CgviewConstants#LABEL CgviewConstants.LABEL}, {@link CgviewConstants#LABEL_NONE
+     *                  CgviewConstants.NO_LABEL}, or {@link CgviewConstants#LABEL_FORCE CgviewConstants.LABEL_FORCE}.
+     */
+    public void setShowLabel(int showLabel) {
+        this.showLabel = showLabel;
+        if (this.showLabel == LABEL_FORCE) {
+            forceLabel = true;
+        } else {
+            forceLabel = false;
+        }
+    }
+
+    /**
+     * Returns whether or not a label should be generated for this FeatureRange when drawn.
+     *
+     * @return {@link CgviewConstants#LABEL CgviewConstants.LABEL}, {@link CgviewConstants#LABEL_NONE
+     *         CgviewConstants.NO_LABEL}, or {@link CgviewConstants#LABEL_FORCE CgviewConstants.LABEL_FORCE}.
+     */
+    public int getShowLabel() {
+        return showLabel;
+    }
+
+    /**
+     * Sets the type of decoration added to this FeatureRange when drawn.
+     *
+     * @param decoration {@link CgviewConstants#DECORATION_STANDARD CgviewConstants.DECORATION_STANDARD}, {@link
+     *                   CgviewConstants#DECORATION_COUNTERCLOCKWISE_ARROW CgviewConstants.DECORATION_COUNTERCLOCKWISE_ARROW},
+     *                   {@link CgviewConstants#DECORATION_CLOCKWISE_ARROW CgviewConstants.DECORATION_CLOCKWISE_ARROW},
+     *                   {@link CgviewConstants#DECORATION_HIDDEN CgviewConstants.DECORATION_HIDDEN}.
+     */
+    public void setDecoration(int decoration) {
+        this.decoration = decoration;
+    }
+
+    /**
+     * Returns an integer indicating what type of decoration will be added to this FeatureRange when drawn.
+     *
+     * @return {@link CgviewConstants#DECORATION_STANDARD CgviewConstants.DECORATION_STANDARD}, {@link
+     *         CgviewConstants#DECORATION_COUNTERCLOCKWISE_ARROW CgviewConstants.DECORATION_COUNTERCLOCKWISE_ARROW},
+     *         {@link CgviewConstants#DECORATION_CLOCKWISE_ARROW CgviewConstants.DECORATION_CLOCKWISE_ARROW}, {@link
+     *         CgviewConstants#DECORATION_HIDDEN CgviewConstants.DECORATION_HIDDEN}.
+     */
+    public int getDecoration() {
+        return decoration;
+    }
+
+
+    /**
+     * Sets the label text for this FeatureRange.
+     *
+     * @param label the label for this FeatureRange.
+     */
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    /**
+     * Returns the label text for this FeatureRange.
+     *
+     * @return the label for this FeatureRange.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Sets the position of this FeatureRange relative to the FeatureSlot object that contains it. This value is only
+     * applied when the thickness of this FeatureRange is adjusted using {@link #setProportionOfThickness(float)} or
+     * {@link Feature#setProportionOfThickness(float)}.
+     *
+     * @param radiusAdjustment between <code>0</code> and <code>1</code>, with <code>1</code> being near the edge
+     *                         furthest from the map center.
+     */
+    public void setRadiusAdjustment(float radiusAdjustment) {
+        if (radiusAdjustment < 0) {
+            radiusAdjustment = 0.0f;
+        } else if (radiusAdjustment > 1) {
+            radiusAdjustment = 1.0f;
+        }
+        this.radiusAdjustment = radiusAdjustment;
+    }
+
+    /**
+     * Returns the position of this FeatureRange relative to the FeatureSlot object that contains it. This value is only
+     * applied when the thickness of this FeatureRange is adjusted using {@link #setProportionOfThickness(float)} or
+     * {@link Feature#setProportionOfThickness(float)}.
+     *
+     * @return a <code>float</code> between <code>0</code> and <code>1</code>, with <code>1</code> being near the edge
+     *         furthest from the map center.
+     * @see #setProportionOfThickness(float)
+     */
+    public float getRadiusAdjustment() {
+        return radiusAdjustment;
+    }
+
+    /**
+     * Sets the thickness of this FeatureRange when drawn, as a proportion of the thickness of the FeatureSlot
+     * containing this Feature.
+     *
+     * @param proportionOfThickness between <code>0</code> and <code>1</code>, with <code>1</code> being full
+     *                              thickness.
+     */
+    public void setProportionOfThickness(float proportionOfThickness) {
+        if (proportionOfThickness < 0) {
+            proportionOfThickness = 0.0f;
+        } else if (proportionOfThickness > 1) {
+            proportionOfThickness = 1.0f;
+        }
+        this.proportionOfThickness = proportionOfThickness;
+    }
+
+    /**
+     * Returns the thickness of this FeatureRange when drawn, as a proportion of the thickness of the FeatureSlot
+     * containing this FeatureRange.
+     *
+     * @return a <code>float</code> between <code>0</code> and <code>1</code>, with <code>1</code> being full
+     *         thickness.
+     */
+    public float getProportionOfThickness() {
+        return proportionOfThickness;
+    }
+
+    /**
+     * Sets the opacity of this FeatureRange when drawn.
+     *
+     * @param opacity the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public void setOpacity(float opacity) {
+        if (opacity < 0) {
+            opacity = 0.0f;
+        } else if (opacity > 1) {
+            opacity = 1.0f;
+        }
+        this.opacity = opacity;
+    }
+
+    /**
+     * Returns the opacity of this FeatureRange when drawn.
+     *
+     * @return the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public float getOpacity() {
+        return opacity;
+    }
+
+    /**
+     * Sets the color of this FeatureRange when drawn.
+     *
+     * @param color the color of this FeatureRange when drawn.
+     */
+    public void setColor(Color color) {
+        this.color = color;
+    }
+
+    /**
+     * Returns the color of this FeatureRange when drawn.
+     *
+     * @return the color of this FeatureRange when drawn.
+     */
+    public Color getColor() {
+        return color;
+    }
+
+    /**
+     * Sets the font used for the label generated for this FeatureRange.
+     *
+     * @param font the font used for the label generated for this FeatureRange.
+     */
+    public void setFont(Font font) {
+        this.font = font;
+    }
+
+    /**
+     * Returns the font used for the label generated for this FeatureRange.
+     *
+     * @return the font used for the label generated for this FeatureRange.
+     */
+    public Font getFont() {
+        return font;
+    }
+
+    /**
+     * Sets whether or not this FeatureRange should be drawn with shading.
+     *
+     * @param showShading whether or not this FeatureRange should be drawn with shading.
+     */
+    public void setShowShading(boolean showShading) {
+        this.showShading = showShading;
+    }
+
+    /**
+     * Returns whether or not this FeatureRange should be drawn with shading.
+     *
+     * @return whether or not this FeatureRange should be drawn with shading.
+     */
+    public boolean getShowShading() {
+        return showShading;
+    }
+
+    /**
+     * Specifies a hyperlink to be associated with this FeatureRange. Hyperlinks are included in SVG output generated
+     * using {@link CgviewIO#writeToSVGFile(ca.ualberta.stothard.cgview.Cgview, java.lang.String, boolean, boolean)} or
+     * in image maps for PNG and JPG images generated using {@link CgviewIO#writeHTMLFile(ca.ualberta.stothard.cgview.Cgview,
+            * java.lang.String, java.lang.String, java.lang.String)}.
+     *
+     * @param hyperlink a hyperlink for this FeatureRange.
+     */
+    public void setHyperlink(String hyperlink) {
+        this.hyperlink = hyperlink;
+    }
+
+    /**
+     * Returns the hyperlink to be associated with this Feature.
+     *
+     * @return the hyperlink for this Feature.
+     */
+    public String getHyperlink() {
+        return hyperlink;
+    }
+
+    /**
+     * Specifies a mouseover to be associated with this FeatureRange. Mouseovers are included in SVG output generated
+     * using {@link CgviewIO#writeToSVGFile(ca.ualberta.stothard.cgview.Cgview, java.lang.String, boolean, boolean)} or
+     * in image maps for PNG and JPG images generated using {@link CgviewIO#writeHTMLFile(ca.ualberta.stothard.cgview.Cgview,
+            * java.lang.String, java.lang.String, java.lang.String)}.
+     *
+     * @param mouseover the mouseover for this featureRange.
+     */
+    public void setMouseover(String mouseover) {
+        this.mouseover = mouseover;
+    }
+
+    /**
+     * Returns the mouseover to be associated with this FeatureRange.
+     *
+     * @return the mouseover for this FeatureRange.
+     */
+    public String getMouseover() {
+        return mouseover;
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot$SortFeaturesByStart.class b/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot$SortFeaturesByStart.class
new file mode 100644
index 0000000..5a85408
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot$SortFeaturesByStart.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot.class b/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot.class
new file mode 100644
index 0000000..666b29c
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot.java b/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot.java
new file mode 100644
index 0000000..51f3818
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/FeatureSlot.java
@@ -0,0 +1,322 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+/**
+ * Represents a slot of space on the Cgview map. When the map is drawn, the FeatureSlot objects form concentric rings
+ * around the backbone circle. Individual features, which are described using {@link Feature} objects, are drawn in the
+ * FeatureSlot objects. FeatureSlot objects are allocated space in the order that they are added to the Cgview object,
+ * such that those added first receive space closest to the backbone circle.
+ *
+ * @author Paul Stothard
+ */
+public class FeatureSlot implements CgviewConstants {
+
+    private int strand;
+    private ArrayList featuresInSlot = new ArrayList();
+    private double radius = 0.0d;
+    private Cgview cgview;
+    private float featureThickness;
+    private boolean showShading;
+
+
+    /**
+     * Constructs a new FeatureSlot object.
+     *
+     * @param cgview the Cgview object to contain this FeatureSlot.
+     * @param strand the strand of this FeatureSlot, {@link CgviewConstants#DIRECT_STRAND CgviewConstants.DIRECT_STRAND}
+     *               or {@link CgviewConstants#REVERSE_STRAND CgviewConstants.REVERSE_STRAND}. If strand is set to
+     *               DIRECT_STRAND this FeatureSlot is placed on the outside of the backbone circle. If strand is set to
+     *               REVERSE_STRAND this FeatureSlot is placed on the inside of the backbone circle.
+     */
+    public FeatureSlot(Cgview cgview, int strand) {
+        this.strand = strand;
+        this.cgview = cgview;
+        this.featureThickness = cgview.getFeatureThickness();
+        this.showShading = cgview.getShowShading();
+
+        //go through the existing FeatureSlots to determine which position this one will occupy.
+        ArrayList featureSlots = cgview.getFeatureSlots();
+
+        //add this FeatureSlot to the Cgview featureSlots.
+        featureSlots.add(this);
+
+    }
+
+
+    /**
+     * Constructs a new <code>FeatureSlot</code> object. It can be added to a Cgview object using the setCgview()
+     * method.
+     *
+     * @param strand the strand of this FeatureSlot, {@link CgviewConstants#DIRECT_STRAND CgviewConstants.DIRECT_STRAND}
+     *               or {@link CgviewConstants#REVERSE_STRAND CgviewConstants.REVERSE_STRAND}. If strand is set to
+     *               DIRECT_STRAND this FeatureSlot is placed on the outside of the backbone circle. If strand is set to
+     *               REVERSE_STRAND this FeatureSlot is placed on the inside of the backbone circle.
+     */
+    public FeatureSlot(int strand) {
+        this.strand = strand;
+    }
+
+    /**
+     * Constructs a new <code>FeatureSlot</code> object. It can be added to a cgview object using the setCgview()
+     * method.
+     *
+     * @param strand      the strand of this featureSlot, {@link CgviewConstants#DIRECT_STRAND
+     *                    CgviewConstants.DIRECT_STRAND} or {@link CgviewConstants#REVERSE_STRAND
+     *                    CgviewConstants.REVERSE_STRAND}. If strand is set to DIRECT_STRAND this FeatureSlot is placed
+     *                    on the outside of the backbone circle. If strand is set to REVERSE_STRAND this FeatureSlot is
+     *                    placed on the inside of the backbone circle.
+     * @param showShading whether or not items this FeatureSlot should be drawn with shading.
+     */
+    public FeatureSlot(int strand, boolean showShading) {
+        this.strand = strand;
+        this.showShading = showShading;
+    }
+
+    /**
+     * Adds this FeatureSlot to a Cgview object.
+     *
+     * @param cgview the Cgview object to contain this FeatureSlot.
+     */
+    public void setCgview(Cgview cgview) {
+
+        this.cgview = cgview;
+        this.featureThickness = cgview.getFeatureThickness();
+        this.showShading = cgview.getShowShading();
+
+        //go through the existing FeatureSlots to determine which position this one will occupy.
+        ArrayList featureSlots = cgview.getFeatureSlots();
+
+        //add this FeatureSlot to the Cgview featureSlots.
+        featureSlots.add(this);
+
+    }
+
+    /**
+     * Adds a Feature object to this FeatureSlot.
+     *
+     * @param feature the Feature to add to this FeatureSlot.
+     */
+    protected void addFeature(Feature feature) {
+        featuresInSlot.add(feature);
+    }
+
+    /**
+     * Returns the strand of this FeatureSlot.
+     *
+     * @return an <code>int</code> representing the strand of this FeatureSlot.
+     */
+    public int getStrand() {
+        return strand;
+    }
+
+    /**
+     * Sets the thickness of the arc used to represent sequence features in this FeatureSlot.
+     *
+     * @param featureThickness the feature thickness.
+     */
+    public void setFeatureThickness(float featureThickness) {
+        if (featureThickness < 0) {
+            featureThickness = 0.0f;
+        }
+        this.featureThickness = featureThickness;
+    }
+
+    /**
+     * Sets whether or not items in this FeatureSlot should be drawn with shading.
+     *
+     * @param showShading whether or not items this FeatureSlot should be drawn with shading.
+     */
+    public void setShowShading(boolean showShading) {
+        this.showShading = showShading;
+    }
+
+    /**
+     * Returns whether or not items in this FeatureSlot should be drawn with shading.
+     *
+     * @return whether or not items in this featureSlot should be drawn with shading.
+     */
+    public boolean getShowShading() {
+        return showShading;
+    }
+
+    /**
+     * Returns the thickness of the arc used to represent sequence features in this FeatureSlot.
+     *
+     * @return the feature thickness.
+     */
+    public float getFeatureThickness() {
+        return featureThickness;
+    }
+
+    /**
+     * Sets the radius of this FeatureSlot.
+     */
+    protected void setRadius() {
+        if (strand == DIRECT_STRAND) {
+            radius = cgview.getFirstOuterFeatureRadius();
+            ArrayList featureSlots = cgview.getFeatureSlots();
+            Iterator i = featureSlots.iterator();
+            while (i.hasNext()) {
+                FeatureSlot currentFeatureSlot = (FeatureSlot) i.next();
+                if (currentFeatureSlot.getStrand() == DIRECT_STRAND) {
+                    if (currentFeatureSlot.equals(this)) {
+                        radius = radius + 0.5d * featureThickness;
+                        break;
+                    } else {
+                        radius = radius + currentFeatureSlot.getFeatureThickness() + cgview.getFeatureSlotSpacing();
+                    }
+                }
+            }
+        } else {
+            radius = cgview.getFirstInnerFeatureRadius();
+            ArrayList featureSlots = cgview.getFeatureSlots();
+            Iterator i = featureSlots.iterator();
+            while (i.hasNext()) {
+                FeatureSlot currentFeatureSlot = (FeatureSlot) i.next();
+                if (currentFeatureSlot.getStrand() == REVERSE_STRAND) {
+                    if (currentFeatureSlot.equals(this)) {
+                        radius = radius - 0.5d * featureThickness;
+                        break;
+                    } else {
+                        radius = radius - currentFeatureSlot.getFeatureThickness() - cgview.getFeatureSlotSpacing();
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Returns the minimum feature length in bases that can be drawn accurately in this FeatureSlot, at the given zoom
+     * value. Feature lengths smaller than this length are automatically drawn larger so that they are visible. This
+     * method should be used when deciding on the appropriate window size (length of bases) to use when calculating a
+     * value to present on the map. For example, if you plan to display percent GC content on the map, and this method
+     * returns <code>98.0003</code>, you should choose a window size of 99 or greater when calculating percent GC. In
+     * other words, you would create a Feature object containing a FeatureRange object spanning bases 1 to 99, a second
+     * FeatureRange spanning bases 100 to 199, and so on. Each FeatureRange would be decorated in some way to convey the
+     * %GC value calculated for the segment of bases it contains (using {@link FeatureRange#setProportionOfThickness(float)}
+     * for example).
+     *
+     * @param zoom the zoom value to be used when drawing the Cgview map.
+     */
+    public double getBasesPerMinFeature(double zoom) {
+        this.setRadius();
+        double adjustedZoom = cgview.adjustZoom(zoom);
+        double minimumFeatureLength = cgview.getMinimumFeatureLength();
+        double basePerCircum = (double) (cgview.getSequenceLength()) / (2.0d * Math.PI * radius * adjustedZoom);
+        return minimumFeatureLength * basePerCircum;
+    }
+
+    /**
+     * Draws the contents of this FeatureSlot.
+     */
+    protected void draw() {
+        this.setRadius();
+        Iterator i = featuresInSlot.iterator();
+        while (i.hasNext()) {
+            Feature currentFeature = (Feature) i.next();
+            currentFeature.draw(cgview, radius, featureThickness);
+            //remove once drawn
+            //i.remove();
+        }
+    }
+
+    /**
+     * Returns a boolean specifying whether or not the supplied Feature object can fit in this FeatureSlot without
+     * overlapping with Feature objects already present in this FeatureSlot.
+     *
+     * @param feature the Feature to check.
+     * @return whether or not the Feature object can fit without overlapping with other Feature objects.
+     */
+    public boolean isRoom(Feature feature) {
+        //go through each feature and each featureRange.
+        Iterator i = featuresInSlot.iterator();
+        while (i.hasNext()) {
+            Feature currentFeature = (Feature) i.next();
+            Iterator j = currentFeature.getRanges().iterator();
+
+            while (j.hasNext()) {
+                FeatureRange currentFeatureRange = (FeatureRange) j.next();
+                if (currentFeatureRange.getDecoration() == DECORATION_HIDDEN) {
+                    continue;
+                }
+
+                int startOne = currentFeatureRange.getStart();
+                int stopOne = currentFeatureRange.getStop();
+
+                //now examine the featureRanges in the submitted feature.
+                Iterator k = feature.getRanges().iterator();
+
+                while (k.hasNext()) {
+                    FeatureRange innerFeatureRange = (FeatureRange) k.next();
+
+                    if (innerFeatureRange.getDecoration() == DECORATION_HIDDEN) {
+                        continue;
+                    }
+
+                    int startTwo = innerFeatureRange.getStart();
+                    int stopTwo = innerFeatureRange.getStop();
+
+                    if ((startOne < stopOne) && (startTwo < stopTwo)) {
+                        if ((startTwo > stopOne) || (stopTwo < startOne)) {
+                            continue;
+                        } else {
+                            //System.out.println ("label overlap 1: " + startOne + "-" + stopOne + ", " + startTwo + "-" + stopTwo + ".");
+                            return false;
+                        }
+                    } else if ((startOne > stopOne) && (startTwo > stopTwo)) {
+                        //System.out.println ("label overlap 2: " + startOne + "-" + stopOne + ", " + startTwo + "-" + stopTwo + ".");
+                        return false;
+                    } else if ((startOne < stopOne) && (startTwo > stopOne) && (stopTwo < startOne)) {
+                        continue;
+                    } else if ((startTwo < stopTwo) && (startOne > stopTwo) && (stopOne < startTwo)) {
+                        continue;
+                    } else {
+                        //System.out.println ("label overlap 3: " + startOne + "-" + stopOne + ", " + startTwo + "-" + stopTwo + ".");
+                        return false;
+                    }
+                }
+            }// end of while
+
+        }
+        return true;
+    }
+
+    /**
+     * Sorts the features in this FeatureSlot by start base. If this is a DIRECT_STRAND slot the features
+     * are sorted in ascending order. If this is a REVERSE_STRAND slot the features are sorted in 
+     * descending order. This sorting produces a more visually pleasing feature appearance when arrows are
+     * used.
+     */
+    public void sortFeaturesByStart() {
+
+	Comparator comparator = new SortFeaturesByStart();
+        Collections.sort(featuresInSlot, comparator);
+
+	if (this.strand == DIRECT_STRAND) {
+	    Collections.reverse(featuresInSlot);
+	}
+    }
+
+    //sort so that smallest start is first.
+    public class SortFeaturesByStart implements Comparator {
+
+	public int compare(Object o1, Object o2) {
+	    Feature feature1 = (Feature) o1;
+	    Feature feature2 = (Feature) o2;
+
+	    if (feature1.getStart() == feature2.getStart()) {
+		return 0;
+	    } else if (feature2.getStart() < feature1.getStart()) {
+		return 1;
+	    } else {
+		return -1;
+	    }
+	}
+
+	public boolean equals(Object obj) {
+	    return obj.equals(this);
+	}
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FileMover.class b/cgview/src/ca/ualberta/stothard/cgview/FileMover.class
new file mode 100644
index 0000000..ae80500
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/FileMover.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/FileMover.java b/cgview/src/ca/ualberta/stothard/cgview/FileMover.java
new file mode 100644
index 0000000..cf0b08f
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/FileMover.java
@@ -0,0 +1,61 @@
+package ca.ualberta.stothard.cgview;
+
+import java.io.*;
+import java.net.*;
+
+
+/**
+ * This class contains methods for moving jar resources to the output directory.
+ *
+ * @author Paul Stothard
+ */
+
+public class FileMover {
+
+    protected boolean moveFile(String filePath, String fileName, String destinationPath) {
+
+        try {
+	    //text files
+	    if ((fileName.endsWith("html")) || (fileName.endsWith("js")) || (fileName.endsWith("css"))) {
+		URL includeURL = this.getClass().getClassLoader().getResource(filePath + "/" + fileName);
+		
+		BufferedReader br = new BufferedReader(new InputStreamReader(includeURL.openStream()));
+
+		Writer output = new BufferedWriter( new FileWriter(destinationPath + File.separator + fileName));
+		
+		String line;
+		while ((line = br.readLine()) != null) {
+		    output.write(line + System.getProperty("line.separator"));
+		}	       
+		br.close();
+		output.flush();
+		output.close();
+	       
+	    }
+	    //binary files or text files
+	    else {
+		URL includeURL = this.getClass().getClassLoader().getResource(filePath + "/" + fileName);
+		URLConnection connection = includeURL.openConnection();
+		InputStream stream = connection.getInputStream();
+		BufferedInputStream in = new BufferedInputStream(stream);
+		FileOutputStream file = new FileOutputStream(destinationPath + File.separator + fileName);
+		BufferedOutputStream out = new BufferedOutputStream(file);
+		int i;
+		while ((i = in.read()) != -1) {
+		    out.write(i);
+		}
+		out.flush();
+		in.close();
+		out.close();	       
+
+	    }
+
+	    return true;
+
+        } catch (Exception e) {
+	    System.out.println(e.toString());
+            return false;
+        }
+
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/InnerLabel.class b/cgview/src/ca/ualberta/stothard/cgview/InnerLabel.class
new file mode 100644
index 0000000..43414c3
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/InnerLabel.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/InnerLabel.java b/cgview/src/ca/ualberta/stothard/cgview/InnerLabel.java
new file mode 100644
index 0000000..410f518
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/InnerLabel.java
@@ -0,0 +1,462 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.*;
+import java.util.*;
+
+/**
+ * This class is used by Cgview objects to facilitate label layout and drawing. The labels represented by this class are
+ * drawn on the inside of the sequence backbone.
+ *
+ * @author Paul Stothard
+ */
+public class InnerLabel extends Label implements CgviewConstants {
+
+    /**
+     * Constructs a new InnerLabel object.
+     *
+     * @param cgview           the Cgview object to contain this Label.
+     * @param labelText        the text that is to be drawn.
+     * @param hyperlink        a hyperlink to be associated with this Label.
+     * @param mouseover        mouseover information to be associated with this Label.
+     * @param font             the font to use when drawing this Label.
+     * @param color            the color to use when drawing the Label.
+     * @param forceLabel       whether or not this Label should be drawn even if it cannot be placed such that it does
+     *                         not clash with other labels.
+     * @param lineStartRadians the angle in radians of the line extending from the feature to the label.
+     * @param strand           the strand of this Label ({@link CgviewConstants#DIRECT_STRAND} or {@link
+     *                         CgviewConstants#REVERSE_STRAND}).
+     */
+    protected InnerLabel(Cgview cgview, String labelText, String hyperlink, String mouseover, Font font, Color color, boolean forceLabel, double lineStartRadians, int strand) {
+        super(cgview, labelText, hyperlink, mouseover, font, color, forceLabel, lineStartRadians, strand);
+        cgview.addInnerLabel(this);
+    }
+
+    /**
+     * Returns a boolean specifying whether or not this Label currently clashes with other Label objects in the Cgview
+     * object containing this Label.
+     *
+     * @return a <code>boolean</code> specifying whether or not this Label clashes with other Labels.
+     */
+    protected boolean clashesWithAny() {
+        //need to restrict comparison to Labels of the same class.
+        ArrayList labels = cgview.getInnerLabels();
+        if (labels.size() < 2) {
+            return false;
+        }
+        for (int outer = 0; outer < labels.size(); outer++) {
+            Label outerLabel = (Label) (labels.get(outer));
+            if (labels.indexOf(this) == outer) {
+                continue;
+            } else if (this.clashes(outerLabel)) {
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    /**
+     * Draws a line joining the feature to this Label.
+     */
+    protected void drawLabelLine() {
+
+        double extension = descent;
+        double lineShiftAmount = 0.01d;
+        double tempRadius;
+
+        double lineX2;
+        double lineY2;
+        Point2D checkPoint = new Point2D.Double(0.0d, 0.0d);
+
+        double textPositionX;
+        double textPositionY;
+
+        //Graphics2D gg = cgview.getGraphics();
+
+        //FontRenderContext frc = gg.getFontRenderContext();
+        //TextLayout layout = new TextLayout(labelText, font, frc);
+
+        double textHeight = unplacedBounds.getHeight();
+        double textWidth = unplacedBounds.getWidth();
+
+        if (extendedRadius) {
+            textPositionX = (Math.cos(lineEndRadians) * (extendedLineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (extendedLineEndRadius));
+        } else {
+            textPositionX = (Math.cos(lineEndRadians) * (lineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (lineEndRadius));
+        }
+
+
+        //double textHeight = bounds.getHeight();
+        //double textWidth = bounds.getWidth();
+        //adjust text position based on radians for label.
+        if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 1)) { // 0 to 90 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - textWidth + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 90 to 180 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 0) && (Math.sin(lineEndRadians) >= -1) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 180 to 270 degrees
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5 * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else { // 270 to 360
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        }
+
+        double compensate = 0.0d;
+
+        if (cgview.getDrawEntirePlasmid()) {
+            compensate = 0.0d;
+        }
+
+        placedBounds.setRect(unplacedBounds.getX() + textPositionX - 1.5d - compensate, unplacedBounds.getY() + textPositionY - descent - 1.5d - compensate, unplacedBounds.getWidth() + 3.0d, unplacedBounds.getHeight() + 3.0d);
+
+        //gg.setColor(Color.red);
+        //gg.draw(placedBounds);
+
+        //now move label line end until it no longer intersects placedBounds
+        if (cgview.getUseColoredLabelBackgrounds()) {
+            if (extendedRadius) {
+                //draw first line
+                Area area = this.getLineAsArea(lineStartRadius, lineStartRadians, lineEndRadius, lineEndRadians);
+                //draw second line
+                this.drawLine(lineEndRadius, lineEndRadians, extendedLineEndRadius + extension, lineEndRadians, area);
+            } else {
+                this.drawLine(lineStartRadius, lineStartRadians, lineEndRadius + extension, lineEndRadians);
+            }
+        } else {
+
+            if (extendedRadius) {
+                //draw first line
+                Area area = this.getLineAsArea(lineStartRadius, lineStartRadians, lineEndRadius, lineEndRadians);
+
+                tempRadius = extendedLineEndRadius - extension;
+                lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                checkPoint.setLocation(lineX2, lineY2);
+
+                while (placedBounds.contains(checkPoint)) {
+                    tempRadius = tempRadius + lineShiftAmount;
+                    lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                    lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                    checkPoint.setLocation(lineX2, lineY2);
+                }
+
+                //now remove some radius for the line end cap
+                tempRadius = tempRadius + cgview.getLabelLineThickness();
+
+                //draw second line
+                this.drawLine(lineEndRadius, lineEndRadians, tempRadius, lineEndRadians, area);
+            } else {
+
+                tempRadius = lineEndRadius - extension;
+                lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                checkPoint.setLocation(lineX2, lineY2);
+
+                while (placedBounds.contains(checkPoint)) {
+                    tempRadius = tempRadius + lineShiftAmount;
+                    lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                    lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                    checkPoint.setLocation(lineX2, lineY2);
+                }
+
+                //now remove some radius for the line end cap
+                tempRadius = tempRadius + cgview.getLabelLineThickness();
+                this.drawLine(lineStartRadius, lineStartRadians, tempRadius, lineEndRadians);
+            }
+        }
+
+
+// 	if (extendedRadius) {
+// 	    this.drawLine(lineStartRadius, lineStartRadians, lineEndRadius, lineEndRadians);
+// 	}
+// 	else {
+// 	    this.drawLine(lineStartRadius, lineStartRadians, lineEndRadius - extension, lineEndRadians);
+// 	}
+
+// 	//now check to see if there is an extended line for this label and if there is one draw it.
+// 	if (extendedRadius) {
+
+// 	    this.drawLine(lineEndRadius, lineEndRadians, extendedLineEndRadius - extension, lineEndRadians);
+		
+// 	}
+    }
+
+    /**
+     * Draws the text portion of this Label.
+     */
+    protected void drawLabelText() {
+
+        double textPositionX;
+        double textPositionY;
+
+        Graphics2D gg = cgview.getGraphics();
+        Color backgroundColor = cgview.getBackgroundColor();
+
+        FontRenderContext frc = gg.getFontRenderContext();
+        TextLayout layout = new TextLayout(labelText, font, frc);
+
+        double textHeight = unplacedBounds.getHeight();
+        double textWidth = unplacedBounds.getWidth();
+
+        if (extendedRadius) {
+            textPositionX = (Math.cos(lineEndRadians) * (extendedLineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (extendedLineEndRadius));
+        } else {
+            textPositionX = (Math.cos(lineEndRadians) * (lineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (lineEndRadius));
+        }
+
+
+        //double textHeight = bounds.getHeight();
+        //double textWidth = bounds.getWidth();
+        //adjust text position based on radians for label.
+        if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 1)) { // 0 to 90 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - textWidth + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 90 to 180 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 0) && (Math.sin(lineEndRadians) >= -1) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 180 to 270 degrees
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5 * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else { // 270 to 360
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        }
+
+	//adjust text position for (0,0) in upper left
+
+	textPositionX = textPositionX + cgview.getWidth() / 2 - cgview.getCenter().getX();
+	textPositionY = textPositionY + cgview.getHeight() / 2 - cgview.getCenter().getY();
+
+        double compensate = 0.0d;
+
+        if (cgview.getDrawEntirePlasmid()) {
+            compensate = 0.0d;
+        }
+
+        placedBounds.setRect(unplacedBounds.getX() + textPositionX - 1.5d - compensate, unplacedBounds.getY() + textPositionY - descent - 1.5d - compensate, unplacedBounds.getWidth() + 3.0d, unplacedBounds.getHeight() + 3.0d);
+
+        //placedBounds.setRect(unplacedBounds.getX()+textPositionX, unplacedBounds.getY() + textPositionY - descent, unplacedBounds.getWidth(), unplacedBounds.getHeight());
+
+        if (cgview.getUseColoredLabelBackgrounds()) {
+            if (cgview.getGlobalLabelColor() != null) {
+                gg.setPaint(cgview.getGlobalLabelColor());
+            } else {
+                gg.setPaint(color);
+            }
+            gg.fill(placedBounds);
+
+            //gg.setPaint(Color.blue);
+            //gg.draw(placedBounds);
+
+            gg.setPaint(backgroundColor);
+            layout.draw(gg, (float) textPositionX, (float) textPositionY - descent);
+        } else {
+            gg.setPaint(backgroundColor);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
+            gg.fill(placedBounds);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+            if (cgview.getGlobalLabelColor() != null) {
+                gg.setPaint(cgview.getGlobalLabelColor());
+            } else {
+                gg.setPaint(color);
+            }
+            layout.draw(gg, (float) textPositionX, (float) textPositionY - descent);
+        }
+
+    }
+
+    /**
+     * Recalculates the rectangle that represents the bounds of this Label.
+     */
+    protected void updateBounds() {
+	this.updateBounds(2.0d);
+    }
+
+    /**
+     * Recalculates the rectangle that represents the bounds of this Label.
+     *
+     * @param padding the amount of padding to add to the bounds box.
+     */
+    protected void updateBounds(double padding) {
+        double textPositionX;
+        double textPositionY;
+
+        float labelLineThickness = cgview.getLabelLineThickness();
+
+        //now check to see if there is an extended line for this label and if there is adjust the bounds.
+        if (extendedRadius) {
+            textPositionX = (Math.cos(lineEndRadians) * (extendedLineEndRadius + labelLineThickness));
+            textPositionY = (Math.sin(lineEndRadians) * (extendedLineEndRadius + labelLineThickness));
+        } else {
+            textPositionX = (Math.cos(lineEndRadians) * (lineEndRadius + labelLineThickness));
+            textPositionY = (Math.sin(lineEndRadians) * (lineEndRadius + labelLineThickness));
+        }
+
+        double textHeight = unplacedBounds.getHeight();
+        double textWidth = unplacedBounds.getWidth();
+
+        if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 1)) { // 0 to 90 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - textWidth + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 90 to 180 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 0) && (Math.sin(lineEndRadians) >= -1) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 180 to 270 degrees
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5 * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else { // 270 to 360
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        }
+
+        double compensate = 0.0d;
+
+        if (cgview.getDrawEntirePlasmid()) {
+            compensate = 0.0d;
+        }
+
+        placedBounds.setRect(unplacedBounds.getX() + textPositionX - padding - compensate, unplacedBounds.getY() + textPositionY - descent - padding - compensate, unplacedBounds.getWidth() + 2.0d * padding, unplacedBounds.getHeight() + 2.0d * padding);
+
+
+        //placedBounds.setRect(unplacedBounds.getX()+textPositionX, unplacedBounds.getY() + textPositionY - descent, unplacedBounds.getWidth(), unplacedBounds.getHeight());
+
+    }
+
+    /**
+     * Attempts to move this Label by increasing its radius value. If this Label cannot be moved without introducing a
+     * new conflict for space, it is not moved.
+     *
+     * @return a <code>boolean</code> specifing whether or not this Label was moved.
+     */
+    protected boolean extendRadius() {
+        if (extendedRadius) {
+            extendedLineEndRadius = extendedLineEndRadius - radiusShiftAmount;
+            placedBounds.setRect(placedBounds.getX() - Math.cos(lineEndRadians) * radiusShiftAmount, placedBounds.getY() - Math.sin(lineEndRadians) * radiusShiftAmount, placedBounds.getWidth(), placedBounds.getHeight());
+            if (fitsInBackground()) {
+                return true;
+            } else {
+                extendedLineEndRadius = extendedLineEndRadius + radiusShiftAmount;
+                updateBounds();
+                return false;
+            }
+        } else {
+            extendedRadius = true;
+            extendedLineStartRadius = lineEndRadius;
+            extendedLineEndRadius = lineEndRadius - radiusShiftAmount;
+            placedBounds.setRect(placedBounds.getX() - Math.cos(lineEndRadians) * radiusShiftAmount, placedBounds.getY() - Math.sin(lineEndRadians) * radiusShiftAmount, placedBounds.getWidth(), placedBounds.getHeight());
+            return true;
+        }
+    }
+
+    /**
+     * Specifies radius of the innermost point in the line extending from the feature to this Label.
+     *
+     * @param lineStartRadius the radius of the innermost point in the line extending from the feature to this Label.
+     */
+    protected void setLineStartRadius(double lineStartRadius) {
+        this.lineStartRadius = lineStartRadius;
+        lineEndRadius = lineStartRadius - cgview.getLabelLineLength();
+        updateBounds();
+    }
+
+    /**
+     * Returns a boolean specifying whether or not this Label can fit inside of the map canvas.
+     *
+     * @return a <code>boolean</code> specifying whether or not this Label can fit inside of the map canvas.
+     */
+    protected boolean fitsInBackground() {
+        if (cgview.getDrawEntirePlasmid()) {
+            return ((cgview.getBackgroundRectangle().contains(this.getBounds())) && !(cgview.getTitleRectangle().intersects(this.getBounds())) && !(cgview.getLengthRectangle().intersects(this.getBounds())));
+        } else {
+            return cgview.getBackgroundRectangle().contains(this.getBounds());
+        }
+    }
+}
+    
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Label.class b/cgview/src/ca/ualberta/stothard/cgview/Label.class
new file mode 100644
index 0000000..0e4fdb1
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/Label.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Label.java b/cgview/src/ca/ualberta/stothard/cgview/Label.java
new file mode 100644
index 0000000..4ad88c6
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/Label.java
@@ -0,0 +1,498 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.*;
+import java.util.*;
+import java.util.regex.*;
+
+/**
+ * This class is used by Cgview objects to facilitate label layout and drawing.
+ *
+ * @author Paul Stothard
+ */
+
+public abstract class Label implements CgviewConstants {
+
+    protected String labelText;
+    protected Color color;
+    protected int strand;
+
+    protected String hyperlink;
+    protected String mouseover;
+
+    protected double lineStartRadians;
+    protected double lineStartRadius;
+    protected double lineEndRadians;
+    protected double lineEndRadius;
+
+    protected boolean extendedRadius;
+    protected double extendedLineStartRadius;
+    protected double extendedLineEndRadius;
+
+    protected boolean fixedInPlace;
+    protected double allowedRadiansDelta;
+
+    protected static double radiusShiftAmount;
+    protected static double radiansShiftAmount;
+
+    protected Rectangle2D unplacedBounds;
+    protected Rectangle2D placedBounds;
+
+    protected Font font;
+    protected float descent;
+    protected float ascent;
+
+    protected boolean forceLabel;
+
+    protected Cgview cgview;
+
+    protected static double smallestDimension = 0;
+
+    protected static double RADIAN_SHIFT_PADDING = 3.0d;
+
+    /**
+     * Constructs a new Label object.
+     *
+     * @param cgview           the Cgview object to contain this Label.
+     * @param labelText        the text that is to be drawn.
+     * @param hyperlink        a hyperlink to be associated with this Label.
+     * @param mouseover        mouseover information to be associated with this Label.
+     * @param font             the font to use when drawing this Label.
+     * @param color            the color to use when drawing this Label.
+     * @param forceLabel       whether or not this Label should be drawn even if it cannot be placed such that it does
+     *                         not clash with other labels.
+     * @param lineStartRadians the angle in radians of the line extending from the feature to this Label.
+     * @param strand           the strand of this Label ({@link CgviewConstants#DIRECT_STRAND} or {@link
+     *                         CgviewConstants#REVERSE_STRAND}).
+     */
+    protected Label(Cgview cgview, String labelText, String hyperlink, String mouseover, Font font, Color color, boolean forceLabel, double lineStartRadians, int strand) {
+        this.cgview = cgview;
+        this.labelText = labelText;
+        this.hyperlink = hyperlink;
+        this.mouseover = mouseover;
+        this.color = color;
+        this.forceLabel = forceLabel;
+        this.lineStartRadians = lineStartRadians;
+        this.strand = strand;
+
+        if (this.labelText == null) {
+            this.labelText = "Untitled";
+        }
+
+        Pattern p = Pattern.compile("\\S");
+        Matcher m = p.matcher(this.labelText);
+
+        if (!(m.find())) {
+            this.labelText = "Untitled";
+        }
+
+        if (font != null) {
+            this.font = font;
+        } else {
+            this.font = cgview.getLabelFont();
+        }
+
+        lineEndRadians = lineStartRadians;
+
+        //if close to vertical
+        if (Math.abs(Math.sin(lineStartRadians)) > 0.70d) {
+            allowedRadiansDelta = (1.0d / 16.0d) * (2.0d * Math.PI);
+        } else {
+            allowedRadiansDelta = (1.0d / 10.0d) * (2.0d * Math.PI);
+        }
+        extendedRadius = false;
+        fixedInPlace = false;
+
+        //create bounds
+        Graphics2D gg = cgview.getGraphics();
+        FontRenderContext frc = gg.getFontRenderContext();
+        TextLayout layout = new TextLayout(this.labelText, this.font, frc);
+
+        unplacedBounds = layout.getBounds();
+        placedBounds = layout.getBounds();
+        descent = layout.getDescent();
+        ascent = layout.getAscent();
+
+        if (smallestDimension == 0) {
+            if (unplacedBounds.getWidth() > unplacedBounds.getHeight()) {
+                smallestDimension = unplacedBounds.getHeight();
+            } else {
+                smallestDimension = unplacedBounds.getWidth();
+            }
+        } else {
+            if (unplacedBounds.getWidth() < smallestDimension) {
+                smallestDimension = unplacedBounds.getWidth();
+            }
+            if (unplacedBounds.getHeight() < smallestDimension) {
+                smallestDimension = unplacedBounds.getHeight();
+            }
+        }
+
+
+        radiusShiftAmount = cgview.getRadiusShiftAmount();
+
+        //radiansShiftConstant may need to be made smaller if label lines are crossing
+        //radiansShiftAmount = cgview.getRadiansShiftConstant() / cgview.getLastOuterFeatureRadius();
+        radiansShiftAmount = ((smallestDimension / 2) / (cgview.getLastOuterFeatureRadius()));
+
+
+        //need to adjust some values for zooming
+        //radiansShiftAmount = radiansShiftAmount / cgview.getZoomMultiplier();
+        //allowedRadiansDelta = allowedRadiansDelta / cgview.getZoomMultiplier();
+    }
+
+    protected abstract void drawLabelText();
+
+    protected abstract void drawLabelLine();
+
+    /**
+     * Draws a line between two points described by radius and radian values.
+     *
+     * @param startRadius  the radius of the first point.
+     * @param startRadians the radians of the first point.
+     * @param endRadius    the radius of the second point.
+     * @param endRadians   the radians of the second point.
+     */
+    protected void drawLine(double startRadius, double startRadians, double endRadius, double endRadians) {
+
+        Graphics2D gg = cgview.getGraphics();
+
+        float labelLineThickness = cgview.getLabelLineThickness();
+
+        double lineX1 = Math.cos(startRadians) * startRadius;
+        double lineY1 = Math.sin(startRadians) * startRadius;
+        double lineX2 = Math.cos(endRadians) * endRadius;
+        double lineY2 = Math.sin(endRadians) * endRadius;
+
+        if (cgview.getGlobalLabelColor() != null) {
+            gg.setPaint(cgview.getGlobalLabelColor());
+        } else {
+            gg.setPaint(color);
+        }
+
+        gg.setStroke(new BasicStroke(labelLineThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER));
+        gg.draw(new Line2D.Double(lineX1, lineY1, lineX2, lineY2));
+
+    }
+
+    /**
+     * Draws a line between two points described by radius and radian values.
+     *
+     * @param startRadius  the radius of the first point.
+     * @param startRadians the radians of the first point.
+     * @param endRadius    the radius of the second point.
+     * @param endRadians   the radians of the second point.
+     * @param area         an area to add to the line.
+     */
+    protected void drawLine(double startRadius, double startRadians, double endRadius, double endRadians, Area area) {
+
+        Graphics2D gg = cgview.getGraphics();
+
+        float labelLineThickness = cgview.getLabelLineThickness();
+
+        double lineX1 = Math.cos(startRadians) * startRadius;
+        double lineY1 = Math.sin(startRadians) * startRadius;
+        double lineX2 = Math.cos(endRadians) * endRadius;
+        double lineY2 = Math.sin(endRadians) * endRadius;
+
+        if (cgview.getGlobalLabelColor() != null) {
+            gg.setPaint(cgview.getGlobalLabelColor());
+        } else {
+            gg.setPaint(color);
+        }
+
+	BasicStroke lineStroke = new BasicStroke(labelLineThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
+	area.add(new Area(lineStroke.createStrokedShape(new Line2D.Double(lineX1, lineY1, lineX2, lineY2))));
+	
+        gg.fill(area);
+
+    }
+
+    /**
+     * Returns an Area representing a line between two points described by radius and radian values.
+     *
+     * @param startRadius  the radius of the first point.
+     * @param startRadians the radians of the first point.
+     * @param endRadius    the radius of the second point.
+     * @param endRadians   the radians of the second point.
+     * @return an Area to add to the line.
+     */
+    protected Area getLineAsArea(double startRadius, double startRadians, double endRadius, double endRadians) {
+
+        Graphics2D gg = cgview.getGraphics();
+
+        float labelLineThickness = cgview.getLabelLineThickness();
+
+        double lineX1 = Math.cos(startRadians) * startRadius;
+        double lineY1 = Math.sin(startRadians) * startRadius;
+        double lineX2 = Math.cos(endRadians) * endRadius;
+        double lineY2 = Math.sin(endRadians) * endRadius;
+
+	Area area = new Area();
+
+	BasicStroke lineStroke = new BasicStroke(labelLineThickness, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER);
+	area.add(new Area(lineStroke.createStrokedShape(new Line2D.Double(lineX1, lineY1, lineX2, lineY2))));
+	
+        return area;
+
+    }
+
+    /**
+     * Returns the starting point of the line drawn to this Label.
+     *
+     * @return the starting point of the line drawn to this Label.
+     */
+    protected Point2D getLineStart() {
+        return new Point2D.Double(Math.cos(this.lineStartRadians) * this.lineStartRadius, Math.sin(this.lineStartRadians) * this.lineStartRadius);
+    }
+
+    /**
+     * Returns the radians of the innermost point in the line extending from the feature to this Label.
+     *
+     * @return the radians of the innermost point in the label line.
+     */
+    protected double getLineStartRadians() {
+        return lineStartRadians;
+    }
+
+    /**
+     * Returns the radians of the outermost point in the line extending from the feature to this Label.
+     *
+     * @return the radians of the outermost point in the label line.
+     */
+    protected double getLineEndRadians() {
+        return lineEndRadians;
+    }
+
+    /**
+     * Returns a boolean specifying whether or not the line between the feature and this Label has been extended to
+     * prevent label clashes.
+     *
+     * @return a <code>boolean</code> representing whether or not the line between the feature and this Label has been
+     *         extended to prevent label clashes.
+     */
+    protected boolean isExtendedRadius() {
+        return extendedRadius;
+    }
+
+    /**
+     * Returns the radius of the innermost point in the line extending from the feature to this Label.
+     *
+     * @return the radius of the innermost point in the label line.
+     */
+    protected double getLineStartRadius() {
+        return lineStartRadius;
+    }
+
+    /**
+     * Returns the radius of the outermost point in the line extending from the feature to this Label.
+     *
+     * @return the radius of the outermost point in the label line.
+     */
+    protected double getLineEndRadius() {
+        return lineEndRadius;
+    }
+
+    /**
+     * Returns the radius of the outermost point in the second line (the extended line) extending from the feature to
+     * this Label.
+     *
+     * @return the radius of the outermost point in the second label line.
+     */
+    protected double getExtendedLineEndRadius() {
+        return extendedLineEndRadius;
+    }
+
+    /**
+     * Returns a boolean specifying whether or not this label should be drawn even if it cannot be placed such that it
+     * does not clash with other labels.
+     *
+     * @return a <code>boolean</code> specifying whether or not this Label should be drawn even if it cannot be placed
+     *         such that it does not clash with other labels.
+     */
+    protected boolean getForceLabel() {
+        return forceLabel;
+    }
+
+    protected abstract void updateBounds();
+
+    protected abstract void updateBounds(double padding);
+
+    /**
+     * Returns a rectangle that represents the bounds of this Label. {@link #updateBounds()} should be used to calculate
+     * the bounds if the Label has been moved since the last call to {@link #updateBounds()}.
+     *
+     * @return the bounds of this Label.
+     */
+    protected Rectangle2D getBounds() {
+        return placedBounds;
+    }
+
+    /**
+     * Returns a boolean specifying whether or not this Label clashes with the supplied Label.
+     *
+     * @param testLabel a Label object.
+     * @return a <code>boolean</code> specifying whether this label clashes with the supplied label.
+     */
+    protected boolean clashes(Label testLabel) {
+        return this.getBounds().intersects(testLabel.getBounds());
+    }
+
+    protected abstract boolean clashesWithAny();
+
+    /**
+     * Attempts to move this Label by decreasing its radians value. If the angle between the the start of the label line
+     * and the label text is at the maximum acceptable value the label is not moved.
+     *
+     * @return a <code>boolean</code> specifing whether or not this Label was moved.
+     */
+    protected final boolean shiftRadiansLower() {
+        if (Math.abs(lineStartRadians - (lineEndRadians - radiansShiftAmount)) < (allowedRadiansDelta)) {
+            lineEndRadians = lineEndRadians - radiansShiftAmount;
+            updateBounds(3.0d);
+            return true;
+        } else {
+            //System.out.println("failed to shift radians lower");
+            return false;
+        }
+    }
+
+    /**
+     * Attempts to move this Label by increasing its radians value. If the angle between the the start of the label line
+     * and the label text is at the maximum acceptable value the label is not moved.
+     *
+     * @return a <code>boolean</code> specifing whether or not this Label was moved.
+     */
+    protected final boolean shiftRadiansHigher() {
+        if (Math.abs(lineStartRadians - (lineEndRadians + radiansShiftAmount)) < (allowedRadiansDelta)) {
+            lineEndRadians = lineEndRadians + radiansShiftAmount;
+            updateBounds(3.0d);
+            return true;
+        } else {
+            //System.out.println("failed to shift radians higher");
+            return false;
+        }
+
+    }
+
+    /**
+     * Attempts to move this Label by adjusting its radians value such that it is closer to its original radians value.
+     * If the adjustment introduces a conflict for space with other labels, this Label is not moved.
+     *
+     * @return a <code>boolean</code> specifing whether or not this Label was moved.
+     */
+    protected boolean shiftRadiansToOriginal(ArrayList labels) {
+
+        if (lineEndRadians == lineStartRadians) {
+            //they are already the same
+            return false;
+        } else if (Math.abs(lineStartRadians - lineEndRadians) <= (radiansShiftAmount)) {
+            //already close enough, make them the same if possible
+            double tempRadians = lineEndRadians;
+            lineEndRadians = lineStartRadians;
+            updateBounds(3.0d);
+            if (clashesWithAny(labels)) {
+                lineEndRadians = tempRadians;
+                updateBounds(3.0d);
+                return false;
+            } else {
+                return false;
+            }
+        } else if (lineStartRadians < lineEndRadians) {
+            shiftRadiansLower();
+            if (clashesWithAny(labels)) {
+                shiftRadiansHigher();
+                return false;
+            } else {
+                return true;
+            }
+        } else if (lineStartRadians > lineEndRadians) {
+            this.shiftRadiansHigher();
+            if (clashesWithAny(labels)) {
+                shiftRadiansLower();
+                return false;
+            } else {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    protected abstract boolean extendRadius();
+
+    protected abstract void setLineStartRadius(double lineStartRadius);
+
+    /**
+     * Returns a boolean specifying whether or not this Label clashes with any of the labels in the supplied ArrayList.
+     *
+     * @param labels a list of Label objects.
+     * @return a <code>boolean</code> specifying whether or not this Label clashes with any of the Label objects in the
+     *         supplied list.
+     */
+    protected boolean clashesWithAny(ArrayList labels) {
+
+        if (labels.size() < 2) {
+            return false;
+        }
+        for (int outer = 0; outer < labels.size(); outer++) {
+            Label outerLabel = (Label) (labels.get(outer));
+            if (labels.indexOf(this) == outer) {
+                continue;
+            } else if (this.clashes(outerLabel)) {
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    protected abstract boolean fitsInBackground();
+
+    /**
+     * Specifies the hyperlink to be associated with this Label.
+     *
+     * @param hyperlink the hyperlink to be associated with this Label.
+     */
+    protected void setHyperlink(String hyperlink) {
+        this.hyperlink = hyperlink;
+    }
+
+    /**
+     * Returns the hyperlink to be associated with this Label.
+     *
+     * @return the hyperlink to be associated with this Label.
+     */
+    protected String getHyperlink() {
+        return hyperlink;
+    }
+
+    /**
+     * Returns the text of this Label.
+     *
+     * @return the text of this Label.
+     */
+    protected String getLabelText() {
+        return labelText;
+    }
+
+    /**
+     * The mouseover to be associated with this Label.
+     *
+     * @param mouseover the mouseover to be associated with this Label.
+     */
+    protected void setMouseover(String mouseover) {
+        this.mouseover = mouseover;
+    }
+
+    /**
+     * Returns the mouseover to be associated with this Label.
+     *
+     * @return the mouseover to be associated with this Label.
+     */
+    protected String getMouseover() {
+        return mouseover;
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/LabelBounds.class b/cgview/src/ca/ualberta/stothard/cgview/LabelBounds.class
new file mode 100644
index 0000000..47b8073
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/LabelBounds.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/LabelBounds.java b/cgview/src/ca/ualberta/stothard/cgview/LabelBounds.java
new file mode 100644
index 0000000..54145d2
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/LabelBounds.java
@@ -0,0 +1,161 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.geom.*;
+
+/**
+ * This class is used to store bounds information about text already drawn on a Cgview map. The information stored in
+ * this class can be used to implement label mouseovers and hyperlinks.
+ *
+ * @author Paul Stothard
+ */
+
+public class LabelBounds implements CgviewConstants {
+
+    private String labelText;
+    private String hyperlink;
+    private String mouseover;
+    private Rectangle2D bounds;
+    private int type;
+    private boolean use;
+    private int base;
+    private Cgview cgview;
+
+    /**
+     * Constructs a new LabelBounds object.
+     *
+     * @param cgview the Cgview object to contain this LabelBounds.
+     */
+    protected LabelBounds(Cgview cgview) {
+        this.cgview = cgview;
+        cgview.getLabelBounds().add(this);
+    }
+
+    /**
+     * Specifies the bounds of this LabelBounds.
+     *
+     * @param bounds the bounds of the label.
+     */
+    protected void setBounds(Rectangle2D bounds) {
+        this.bounds = bounds;
+    }
+
+    /**
+     * Returns a rectangle that represents the bounds of this LabelBounds.
+     *
+     * @return the bounds of the label.
+     */
+    public Rectangle2D getBounds() {
+        return bounds;
+    }
+
+    /**
+     * Specifies the text that gave rise to this LabelBounds.
+     *
+     * @param label the text that gave rise to this LabelBounds.
+     */
+    protected void setLabel(String label) {
+        this.labelText = label;
+    }
+
+    /**
+     * Returns the text that gave rise to this LabelBounds.
+     *
+     * @return the text gave rise to this LabelBounds.
+     */
+    public String getLabel() {
+        return labelText;
+    }
+
+    /**
+     * Specifies a hyperlink to be associated with this LabelBounds.
+     *
+     * @param hyperlink a hyperlink to be associated with this LabelBounds.
+     */
+    protected void setHyperlink(String hyperlink) {
+        this.hyperlink = hyperlink;
+    }
+
+    /**
+     * Returns the hyperlink associated with this LabelBounds.
+     *
+     * @return the hyperlink associated with this LabelBounds.
+     */
+    public String getHyperlink() {
+        return hyperlink;
+    }
+
+    /**
+     * Specifies a mouseover to be associated with this LabelBounds.
+     *
+     * @param mouseover a mouseover to be associated with this LabelBounds.
+     */
+    protected void setMouseover(String mouseover) {
+        this.mouseover = mouseover;
+    }
+
+    /**
+     * Returns the mouseover associated with this LabelBounds.
+     *
+     * @return the mouseover associated with this LabelBounds.
+     */
+    public String getMouseover() {
+        return mouseover;
+    }
+
+    /**
+     * Sets whether or not this LabelBounds should be used.
+     *
+     * @param use whether or not this LabelBounds should be used.
+     */
+    public void setUse(boolean use) {
+        this.use = use;
+    }
+
+    /**
+     * Returns whether or not this LabelBounds should be used.
+     *
+     * @return whether or not this LabelBounds should be used.
+     */
+    public boolean getUse() {
+        return use;
+    }
+
+    /**
+     * Specifies what map object this LabelBounds represents.
+     *
+     * @param type {@link CgviewConstants#BOUNDS_RULER CgviewConstants.BOUNDS_RULER}, {@link
+     *             CgviewConstants#BOUNDS_FEATURE CgviewConstants.BOUNDS_FEATURE}, of {@link
+     *             CgviewConstants#BOUNDS_BUTTON CgviewConstants.BOUNDS_BUTTON}.
+     */
+    protected void setType(int type) {
+        this.type = type;
+    }
+
+    /**
+     * Returns the type of this LabelBounds.
+     *
+     * @return {@link CgviewConstants#BOUNDS_RULER CgviewConstants.BOUNDS_RULER}, {@link CgviewConstants#BOUNDS_FEATURE
+     *         CgviewConstants.BOUNDS_FEATURE}, of {@link CgviewConstants#BOUNDS_BUTTON CgviewConstants.BOUNDS_BUTTON}.
+     */
+    public int getType() {
+        return type;
+    }
+
+    /**
+     * Specifies which sequence position this LabelBounds is closest to.
+     *
+     * @param base the sequence position.
+     */
+    protected void setBase(int base) {
+        this.base = base;
+    }
+
+    /**
+     * Returns the sequence position closest to this LabelBounds.
+     *
+     * @return the sequence position closest to this LabelBounds.
+     */
+    public int getBase() {
+        return base;
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Legend.class b/cgview/src/ca/ualberta/stothard/cgview/Legend.class
new file mode 100644
index 0000000..8bc84f4
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/Legend.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Legend.java b/cgview/src/ca/ualberta/stothard/cgview/Legend.java
new file mode 100644
index 0000000..c366f78
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/Legend.java
@@ -0,0 +1,447 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.util.*;
+import java.awt.geom.*;
+
+/**
+ * This class is used add legends to a Cgview map. Individual legend entries are represented using the {@link
+ * LegendItem} class.
+ *
+ * @author Paul Stothard
+ */
+public class Legend implements CgviewConstants {
+
+    private Font font;
+    private Color fontColor;
+    private Color backgroundColor;
+    private float backgroundOpacity = 1.0f;
+    private ArrayList legendItems = new ArrayList();
+    private Cgview cgview;
+    private int drawWhenZoomed = LEGEND_DRAW_ZOOMED;
+    private int position = LEGEND_UPPER_RIGHT;
+    private Rectangle2D bounds;
+    private double swatchHeight;
+    private int textAlignment = LEGEND_ITEM_ALIGN_LEFT;
+    private boolean allowLabelClash = false;
+
+    //gives padding to legend
+    protected final static double PADDING = 5.0d;
+
+
+    /**
+     * Constructs a new Legend object.
+     *
+     * @param cgview the Cgview object to contain this Legend.
+     */
+    public Legend(Cgview cgview) {
+
+        this.cgview = cgview;
+        font = cgview.getLegendFont();
+        fontColor = cgview.getLegendTextColor();
+        ArrayList legends = cgview.getLegends();
+        legends.add(this);
+    }
+
+    /**
+     * Adds a LegendItem object to this Legend.
+     *
+     * @param legendItem the LegendItem object to add to this Legend.
+     */
+    protected void addLegendItem(LegendItem legendItem) {
+        legendItems.add(legendItem);
+    }
+
+    /**
+     * Draws the contents of this Legend.
+     */
+    protected void draw() {
+
+        if (bounds == null) {
+            this.setBounds();
+        }
+
+        if (((cgview.getZoomMultiplier() == 1.0d) || (drawWhenZoomed == LEGEND_DRAW_ZOOMED)) && (legendItems.size() > 0) && (bounds.getHeight() <= cgview.getHeight()) && (bounds.getWidth() <= cgview.getWidth())) {
+
+            Graphics2D gg = cgview.getGraphics();
+
+            if (this.backgroundColor == null) {
+                gg.setPaint(cgview.getBackgroundColor());
+            } else {
+                gg.setPaint(this.backgroundColor);
+            }
+
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, this.backgroundOpacity));
+
+            gg.fill(bounds);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+
+            //go through legendItems and draw them.
+            //space items with swatches according to swatch height
+            Collections.reverse(legendItems);
+            double startX = bounds.getX() + PADDING;
+            double startY = bounds.getY() + bounds.getHeight() - PADDING;
+
+            Iterator i;
+            i = legendItems.iterator();
+            double height;
+            while (i.hasNext()) {
+                LegendItem currentLegendItem = (LegendItem) i.next();
+                height = currentLegendItem.getHeight(cgview);
+
+                if (currentLegendItem.getDrawSwatch() == SWATCH_SHOW) {
+                    currentLegendItem.draw(cgview, startX, startY, swatchHeight);
+                    startY = startY - swatchHeight - swatchHeight / 2.0d;
+                } else {
+                    currentLegendItem.draw(cgview, startX, startY, 0.0d);
+                    startY = startY - height - height / 2.0d;
+                }
+            }
+
+            Collections.reverse(legendItems);
+
+        } else if ((bounds.getHeight() > cgview.getHeight()) || (bounds.getWidth() > cgview.getWidth())) {
+            System.err.println("[warning] a legend was removed because it is too large for the canvas.");
+            this.allowLabelClash = true;
+        }
+
+        bounds = null;
+    }
+
+    /**
+     * Returns the bounds of this Legend.
+     */
+    protected Rectangle2D getBounds() {
+        if (bounds == null) {
+            this.setBounds();
+        }
+        return bounds;
+    }
+
+    /**
+     * Calculates the bounds of this Legend.
+     */
+    protected void setBounds() {
+	setBounds(cgview.getCenter().getX(), cgview.getCenter().getY());
+    }
+
+
+    /**
+     * Calculates the bounds of this Legend.
+     */
+    protected void setBounds(double cgviewCenterX, double cgviewCenterY) {
+
+        double cgviewWidth = cgview.getWidth();
+        double cgviewHeight = cgview.getHeight();
+
+        //if (cgviewWidth > cgviewHeight) {
+        //    cgviewCenterX = cgviewCenterX + (cgviewWidth - cgviewHeight) / 2.0d;
+	//
+        //} else if (cgviewHeight > cgviewWidth) {
+        //    cgviewCenterY = cgviewCenterY + (cgviewHeight - cgviewWidth) / 2.0d;
+        //}
+
+        swatchHeight = this.getSwatchHeight();
+        double widestItem = this.getWidestLegendItem(swatchHeight);
+
+        double legendWidth = widestItem;
+        double legendHeight = 0.0d;
+
+        Iterator i;
+        double height = 0;
+        i = legendItems.iterator();
+        boolean first = true;
+        while (i.hasNext()) {
+            LegendItem currentLegendItem = (LegendItem) i.next();
+            height = currentLegendItem.getHeight(cgview);
+            if (currentLegendItem.getDrawSwatch() == SWATCH_SHOW) {
+                legendHeight = legendHeight + swatchHeight;
+                if (!(first)) {
+                    legendHeight = legendHeight + swatchHeight / 2.0d;
+                }
+            } else {
+                legendHeight = legendHeight + height;
+                if (!(first)) {
+                    legendHeight = legendHeight + height / 2.0d;
+                }
+            }
+            first = false;
+        }
+
+        legendHeight = legendHeight + 2.0d * PADDING;
+
+        double upperX = 0.0d;
+        double upperY = 0.0d;
+
+        //adjust x and y using PADDING
+
+        if (position == LEGEND_UPPER_LEFT) {
+            upperX = cgviewCenterX - cgviewWidth / 2 + PADDING;
+            upperY = cgviewCenterY - cgviewHeight / 2 + PADDING;
+        } else if (position == LEGEND_UPPER_CENTER) {
+            upperX = cgviewCenterX - legendWidth / 2;
+            upperY = cgviewCenterY - cgviewHeight / 2 + PADDING;
+        } else if (position == LEGEND_UPPER_RIGHT) {
+            upperX = cgviewCenterX + cgviewWidth / 2 - legendWidth - PADDING;
+            upperY = cgviewCenterY - cgviewHeight / 2 + PADDING;
+        } else if (position == LEGEND_MIDDLE_LEFT) {
+            upperX = cgviewCenterX - cgviewWidth / 2 + PADDING;
+            upperY = cgviewCenterY - legendHeight / 2;
+        } else if (position == LEGEND_MIDDLE_LEFT_OF_CENTER) {
+            upperX = cgviewCenterX - legendWidth;
+            upperY = cgviewCenterY - legendHeight / 2;
+        } else if (position == LEGEND_MIDDLE_CENTER) {
+            upperX = cgviewCenterX - legendWidth / 2;
+            upperY = cgviewCenterY - legendHeight / 2;
+        } else if (position == LEGEND_MIDDLE_RIGHT_OF_CENTER) {
+            upperX = cgviewCenterX;
+            upperY = cgviewCenterY - legendHeight / 2;
+        } else if (position == LEGEND_MIDDLE_RIGHT) {
+            upperX = cgviewCenterX + cgviewWidth / 2 - legendWidth - PADDING;
+            upperY = cgviewCenterY - legendHeight / 2;
+        } else if (position == LEGEND_LOWER_LEFT) {
+            upperX = cgviewCenterX - cgviewWidth / 2 + PADDING;
+            upperY = cgviewCenterY + cgviewHeight / 2 - legendHeight - PADDING;
+        } else if (position == LEGEND_LOWER_CENTER) {
+            upperX = cgviewCenterX - legendWidth / 2;
+            upperY = cgviewCenterY + cgviewHeight / 2 - legendHeight - PADDING;
+        } else if (position == LEGEND_LOWER_RIGHT) {
+            upperX = cgviewCenterX + cgviewWidth / 2 - legendWidth - PADDING;
+            upperY = cgviewCenterY + cgviewHeight / 2 - legendHeight - PADDING;
+        } else { //(position == LEGEND_MIDDLE_RIGHT) {
+            upperX = cgviewCenterX + cgviewWidth / 2 - legendWidth - PADDING;
+            upperY = cgviewCenterY - legendHeight / 2;
+        }
+
+        bounds = new Rectangle2D.Double(upperX, upperY, legendWidth, legendHeight);
+    }
+
+    /**
+     * Returns the width of the widest LegendItem in this Legend.
+     */
+    protected double getWidestLegendItem(double swatchWidth) {
+        Iterator i;
+        double widest = 0.0d;
+        double width;
+
+        i = legendItems.iterator();
+        while (i.hasNext()) {
+            LegendItem currentLegendItem = (LegendItem) i.next();
+            if (currentLegendItem.getDrawSwatch() == SWATCH_SHOW) {
+                width = currentLegendItem.getWidth(cgview, swatchWidth);
+            } else {
+                width = currentLegendItem.getWidth(cgview, 0.0d);
+            }
+            if (width > widest) {
+                widest = width;
+            }
+        }
+        return widest + 2.0d * PADDING;
+    }
+
+    /**
+     * Returns the height that is suitable for any LegendItem swatches drawn in this Legend.
+     */
+    protected double getSwatchHeight() {
+        Iterator i;
+        double swatchHeight = 0.0d;
+        double height = 0.0d;
+        i = legendItems.iterator();
+        while (i.hasNext()) {
+            LegendItem currentLegendItem = (LegendItem) i.next();
+            height = currentLegendItem.getHeight(cgview);
+            if (currentLegendItem.getDrawSwatch() == SWATCH_SHOW) {
+                if (height > swatchHeight) {
+                    swatchHeight = height;
+                }
+            }
+        }
+        return swatchHeight;
+    }
+
+    /**
+     * Sets the default color that will be used for the text in this Legend. This color can be changed for individual
+     * LegendItem objects using {@link LegendItem#setFontColor(Color) LegendItem.setFontColor()}.
+     *
+     * @param fontColor the default text color for the text in this Legend.
+     */
+    public void setFontColor(Color fontColor) {
+        this.fontColor = fontColor;
+    }
+
+    /**
+     * Returns the default color that will be used for the text in this Legend. This color can be changed for individual
+     * LegendItem objects using {@link LegendItem#setFontColor(Color)}.
+     *
+     * @return the default text color for the text in this Legend.
+     */
+    public Color getFontColor() {
+        return fontColor;
+    }
+
+    /**
+     * Sets the font used for text in this Legend. This font can be changed for individual LegendItem objects using
+     * {@link LegendItem#setFont(Font)}.
+     *
+     * @param font the font used for text in this legend.
+     */
+    public void setFont(Font font) {
+        this.font = font;
+    }
+
+    /**
+     * Returns the font used for text in this Legend. This font can be changed for individual LegendItem objects using
+     * {@link LegendItem#setFont(Font)}.
+     *
+     * @return the font used for text in this Legend.
+     */
+    public Font getFont() {
+        return font;
+    }
+
+    /**
+     * Sets whether or not this Legend is drawn when a zoomed Cgview map is generated.
+     *
+     * @param drawWhenZoomed {@link CgviewConstants#LEGEND_DRAW_ZOOMED CgviewConstants.LEGEND_DRAW_ZOOMED} or {@link
+     *                       CgviewConstants#LEGEND_NO_DRAW_ZOOMED CgviewConstants.LEGEND_NO_DRAW_ZOOMED}.
+     */
+    public void setDrawWhenZoomed(int drawWhenZoomed) {
+        this.drawWhenZoomed = drawWhenZoomed;
+    }
+
+    /**
+     * Returns whether or not this Legend is drawn when a zoomed Cgview map is generated.
+     *
+     * @return {@link CgviewConstants#LEGEND_DRAW_ZOOMED CgviewConstants.LEGEND_DRAW_ZOOMED} or {@link
+     *         CgviewConstants#LEGEND_NO_DRAW_ZOOMED CgviewConstants.LEGEND_NO_DRAW_ZOOMED}.
+     */
+    public int getDrawWhenZoomed() {
+        return drawWhenZoomed;
+    }
+
+    /**
+     * Sets the position of this Legend relative to the Cgview map canvas.
+     *
+     * @param position {@link CgviewConstants#LEGEND_UPPER_LEFT CgviewConstants.LEGEND_UPPER_LEFT}, {@link
+     *                 CgviewConstants#LEGEND_UPPER_CENTER CgviewConstants.LEGEND_UPPER_CENTER}, {@link
+     *                 CgviewConstants#LEGEND_UPPER_RIGHT CgviewConstants.LEGEND_UPPER_RIGHT}, {@link
+     *                 CgviewConstants#LEGEND_MIDDLE_LEFT CgviewConstants.LEGEND_MIDDLE_LEFT}, {@link
+     *                 CgviewConstants#LEGEND_MIDDLE_LEFT_OF_CENTER CgviewConstants.LEGEND_MIDDLE_LEFT_OF_CENTER},
+     *                 {@link CgviewConstants#LEGEND_MIDDLE_CENTER CgviewConstants.LEGEND_MIDDLE_CENTER}, {@link
+     *                 CgviewConstants#LEGEND_MIDDLE_RIGHT CgviewConstants.LEGEND_MIDDLE_RIGHT}, {@link
+     *                 CgviewConstants#LEGEND_MIDDLE_RIGHT_OF_CENTER CgviewConstants.LEGEND_MIDDLE_RIGHT_OF_CENTER},
+     *                 {@link CgviewConstants#LEGEND_LOWER_LEFT CgviewConstants.LEGEND_LOWER_LEFT}, {@link
+     *                 CgviewConstants#LEGEND_LOWER_CENTER CgviewConstants.LEGEND_LOWER_CENTER}, or {@link
+     *                 CgviewConstants#LEGEND_LOWER_RIGHT CgviewConstants.LEGEND_LOWER_RIGHT}.
+     */
+    public void setPosition(int position) {
+        this.position = position;
+    }
+
+    /**
+     * Returns the position of this Legend relative to the Cgview map canvas.
+     *
+     * @return {@link CgviewConstants#LEGEND_UPPER_LEFT CgviewConstants.LEGEND_UPPER_LEFT}, {@link
+     *         CgviewConstants#LEGEND_UPPER_CENTER CgviewConstants.LEGEND_UPPER_CENTER}, {@link
+     *         CgviewConstants#LEGEND_UPPER_RIGHT CgviewConstants.LEGEND_UPPER_RIGHT}, {@link
+     *         CgviewConstants#LEGEND_MIDDLE_LEFT CgviewConstants.LEGEND_MIDDLE_LEFT}, {@link
+     *         CgviewConstants#LEGEND_MIDDLE_LEFT_OF_CENTER CgviewConstants.LEGEND_MIDDLE_LEFT_OF_CENTER}, {@link
+     *         CgviewConstants#LEGEND_MIDDLE_CENTER CgviewConstants.LEGEND_MIDDLE_CENTER}, {@link
+     *         CgviewConstants#LEGEND_MIDDLE_RIGHT CgviewConstants.LEGEND_MIDDLE_RIGHT}, {@link
+     *         CgviewConstants#LEGEND_MIDDLE_RIGHT_OF_CENTER CgviewConstants.LEGEND_MIDDLE_RIGHT_OF_CENTER}, {@link
+     *         CgviewConstants#LEGEND_LOWER_LEFT CgviewConstants.LEGEND_LOWER_LEFT}, {@link
+     *         CgviewConstants#LEGEND_LOWER_CENTER CgviewConstants.LEGEND_LOWER_CENTER}, or {@link
+     *         CgviewConstants#LEGEND_LOWER_RIGHT CgviewConstants.LEGEND_LOWER_RIGHT}.
+     */
+    public int getPosition() {
+        return position;
+    }
+
+    /**
+     * Sets the alignment of the LegendItems in this Legend.
+     *
+     * @param textAlignment {@link CgviewConstants#LEGEND_ITEM_ALIGN_LEFT CgviewConstants.LEGEND_ITEM_ALIGN_LEFT},
+     *                      {@link CgviewConstants#LEGEND_ITEM_ALIGN_CENTER CgviewConstants.LEGEND_ITEM_ALIGN_CENTER},
+     *                      or {@link CgviewConstants#LEGEND_ITEM_ALIGN_RIGHT CgviewConstants.LEGEND_ITEM_ALIGN_RIGHT}.
+     *                      This setting can be changed for individual legendItems using {@link
+     *                      LegendItem#setTextAlignment(int) LegendItem.setTextAlignment()}.
+     */
+    public void setAlignment(int textAlignment) {
+        this.textAlignment = textAlignment;
+    }
+
+    /**
+     * Returns the alignment of legendItems in this Legend.
+     *
+     * @return {@link CgviewConstants#LEGEND_ITEM_ALIGN_LEFT CgviewConstants.LEGEND_ITEM_ALIGN_LEFT}, {@link
+     *         CgviewConstants#LEGEND_ITEM_ALIGN_CENTER CgviewConstants.LEGEND_ITEM_ALIGN_CENTER}, or {@link
+     *         CgviewConstants#LEGEND_ITEM_ALIGN_RIGHT CgviewConstants.LEGEND_ITEM_ALIGN_RIGHT}. The alignment of
+     *         legendItems can be changed for individual legendItems using {@link LegendItem#setTextAlignment(int)
+     *         LegendItem.setTextAlignment()}.
+     */
+    public int getAlignment() {
+        return textAlignment;
+    }
+
+    /**
+     * Sets the opacity of the background of this Legend when drawn.
+     *
+     * @param opacity the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public void setBackgroundOpacity(float opacity) {
+        if (opacity < 0) {
+            opacity = 0.0f;
+        } else if (opacity > 1) {
+            opacity = 1.0f;
+        }
+        backgroundOpacity = opacity;
+    }
+
+    /**
+     * Returns the opacity of the background of this Legend when drawn.
+     *
+     * @return the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public float getBackgroundOpacity() {
+        return backgroundOpacity;
+    }
+
+    /**
+     * Sets the color of the background of this Legend when drawn.
+     *
+     * @param color the color of the background.
+     */
+    public void setBackgroundColor(Color color) {
+        backgroundColor = color;
+    }
+
+    /**
+     * Returns the color of the background of this Legend when drawn.
+     *
+     * @return the color of the background.
+     */
+    public Color getBackgroundColor() {
+        return backgroundColor;
+    }
+
+    /**
+     * Sets whether or not feature labels are allowed to clash with this Legend. If false, feature labels are removed if
+     * they clash with this Legend.
+     *
+     * @param allowClash whether or not feature labels are allowed to clash with this Legend.
+     */
+    public void setAllowLabelClash(boolean allowClash) {
+        allowLabelClash = allowClash;
+    }
+
+    /**
+     * Returns whether or not feature labels are allowed to clash with this Legend. If false, labels are removed if they
+     * clash with this Legend.
+     *
+     * @return whether or not labels are allowed to clash with this Legend.
+     */
+    public boolean getAllowLabelClash() {
+        return allowLabelClash;
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/LegendItem.class b/cgview/src/ca/ualberta/stothard/cgview/LegendItem.class
new file mode 100644
index 0000000..c793d4c
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/LegendItem.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/LegendItem.java b/cgview/src/ca/ualberta/stothard/cgview/LegendItem.java
new file mode 100644
index 0000000..27bfd18
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/LegendItem.java
@@ -0,0 +1,290 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.util.regex.*;
+import java.awt.geom.*;
+
+/**
+ * This class is used to add text entries to Legend objects.
+ *
+ * @author Paul Stothard
+ */
+public class LegendItem implements CgviewConstants {
+
+    private Color fontColor;
+    private Color swatchColor = new Color(0, 0, 0);  //black
+    private String label;
+    private Legend legend;
+    private float swatchOpacity = 1.0f;
+    private int drawSwatch = SWATCH_NO_SHOW;
+    private Font font;
+    private int textAlignment;
+
+    /**
+     * Constructs a new LegendItem object.
+     *
+     * @param legend the Legend object to contain this LegendItem.
+     */
+    public LegendItem(Legend legend) {
+
+        this.legend = legend;
+        fontColor = legend.getFontColor();
+        textAlignment = legend.getAlignment();
+        font = legend.getFont();
+        legend.addLegendItem(this);
+    }
+
+    /**
+     * Draws the contents of this LegendItem.
+     *
+     * @param cgview       the Cgview object that contains this LegendItem.
+     * @param x            the x-coordinate for the upper left corner of this LegendItem.
+     * @param y            the y-coordinate for the upper left corner of this LegendItem.
+     * @param swatchHeight the swatch height for this LegendItem.
+     */
+    protected void draw(Cgview cgview, double x, double y, double swatchHeight) {
+
+        if (this.label == null) {
+            this.label = "Untitled";
+        }
+
+        Pattern p = Pattern.compile("\\S");
+        Matcher m = p.matcher(this.label);
+
+        if (!(m.find())) {
+            this.label = "Untitled";
+        }
+
+        Graphics2D gg = cgview.getGraphics();
+        FontRenderContext frc = gg.getFontRenderContext();
+        TextLayout layout = new TextLayout(this.label, this.font, frc);
+        Rectangle2D bounds = layout.getBounds();
+        double textWidth = bounds.getWidth();
+        double textHeight = bounds.getHeight();
+
+        double textPositionX = x;
+        //the below adjustment accounts for text starting slightly right of draw point. Amount is proportional to fontsize
+        textPositionX = textPositionX - textHeight / 12.0d;
+
+        double textPositionY = y;
+        double internalLegendWidth = legend.getBounds().getWidth() - 2.0d * Legend.PADDING;
+
+        if (swatchHeight > 0.0d) {
+            //Rectangle2D swatchRectangle = new Rectangle2D.Double(x, y - height / 7.0d, height, height);
+            Rectangle2D swatchRectangle = new Rectangle2D.Double(x, y - swatchHeight, swatchHeight, swatchHeight);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, swatchOpacity));
+            gg.setPaint(swatchColor);
+            gg.fill(swatchRectangle);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+
+            internalLegendWidth = internalLegendWidth - swatchHeight - swatchHeight / 2.0d;
+            textPositionX = x + swatchHeight + swatchHeight / 2.0d;
+        }
+
+        //adjust textAlignment of text within the legend
+        if (this.textAlignment == LEGEND_ITEM_ALIGN_RIGHT) {
+            textPositionX = textPositionX + internalLegendWidth - textWidth - textHeight / 12.0d;
+        } else if (this.textAlignment == LEGEND_ITEM_ALIGN_CENTER) {
+            textPositionX = textPositionX + internalLegendWidth / 2.0d - textWidth / 2.0d;
+        }
+
+        gg.setPaint(fontColor);
+        layout.draw(gg, (float) textPositionX, (float) textPositionY - layout.getDescent());
+        //layout.draw(gg, (float)textPositionX, (float)textPositionY);
+
+    }
+
+    /**
+     * Returns the width of the text in this LegendItem.
+     *
+     * @param cgview the Cgview object that contains this LegendItem.
+     */
+    protected double getWidth(Cgview cgview, double swatchWidth) {
+
+        double width = 0.0d;
+
+        Pattern p = Pattern.compile("\\S");
+        Matcher m = p.matcher(this.label);
+
+        if (!(m.find())) {
+            this.label = "Untitled";
+        }
+
+        Graphics2D gg = cgview.getGraphics();
+        FontRenderContext frc = gg.getFontRenderContext();
+        TextLayout layout = new TextLayout(this.label, this.font, frc);
+        Rectangle2D bounds = layout.getBounds();
+
+        width = bounds.getWidth();
+
+        width = width + swatchWidth + swatchWidth / 2.0d;
+
+        return width;
+    }
+
+    /**
+     * Returns the height of the text in this LegendItem.
+     *
+     * @param cgview the cgview object to draw on.
+     */
+    protected double getHeight(Cgview cgview) {
+
+        Pattern p = Pattern.compile("\\S");
+        Matcher m = p.matcher(this.label);
+
+        if (!(m.find())) {
+            this.label = "Untitled";
+        }
+
+        Graphics2D gg = cgview.getGraphics();
+        FontRenderContext frc = gg.getFontRenderContext();
+        TextLayout layout = new TextLayout(this.label, this.font, frc);
+        //Rectangle2D bounds = layout.getBounds();
+
+        //return bounds.getHeight();
+        return layout.getDescent() + layout.getAscent();
+    }
+
+
+    /**
+     * Sets the color that will be used for the text in this LegendItem.
+     *
+     * @param fontColor the color of the text in this LegendItem.
+     */
+    public void setFontColor(Color fontColor) {
+        this.fontColor = fontColor;
+    }
+
+    /**
+     * Returns the color that will be used for the text in this LegendItem.
+     *
+     * @return the color of the text in this LegendItem.
+     */
+    public Color getFontColor() {
+        return fontColor;
+    }
+
+
+    /**
+     * Sets the swatch color that will be used for this LegendItem.
+     *
+     * @param swatchColor the swatch color for this LegendItem.
+     */
+    public void setSwatchColor(Color swatchColor) {
+        this.swatchColor = swatchColor;
+    }
+
+    /**
+     * Returns the swatch color that will be used for this LegendItem.
+     *
+     * @return the swatch color for this LegendItem.
+     */
+    public Color getSwatchColor() {
+        return swatchColor;
+    }
+
+    /**
+     * Sets whether or not a color swatch should be drawn for this LegendItem.
+     *
+     * @param drawSwatch {@link CgviewConstants#SWATCH_SHOW CgviewConstants.SWATCH_SHOW} or {@link
+     *                   CgviewConstants#SWATCH_NO_SHOW CgviewConstants.SWATCH_NO_SHOW}.
+     */
+    public void setDrawSwatch(int drawSwatch) {
+        this.drawSwatch = drawSwatch;
+    }
+
+    /**
+     * Returns whether or not a color swatch should be drawn for this LegendItem.
+     *
+     * @return {@link CgviewConstants#SWATCH_SHOW CgviewConstants.SWATCH_SHOW} or {@link CgviewConstants#SWATCH_NO_SHOW
+     *         CgviewConstants.SWATCH_NO_SHOW}.
+     */
+    public int getDrawSwatch() {
+        return drawSwatch;
+    }
+
+    /**
+     * Sets the text to be used for this LegendItem.
+     *
+     * @param label the text for this LegendItem.
+     */
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    /**
+     * Returns the text to be used for this LegendItem.
+     *
+     * @return the text for this LegendItem.
+     */
+    public String getLabel() {
+        return label;
+    }
+
+    /**
+     * Sets the opacity of the swatch drawn for this LegendItem.
+     *
+     * @param swatchOpacity the opacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most
+     *                      opaque.
+     */
+    public void setSwatchOpacity(float swatchOpacity) {
+        if (swatchOpacity < 0) {
+            swatchOpacity = 0.0f;
+        } else if (swatchOpacity > 1) {
+            swatchOpacity = 1.0f;
+        }
+        this.swatchOpacity = swatchOpacity;
+    }
+
+    /**
+     * Returns the opacity of the swatch drawn for this LegendItem.
+     *
+     * @return the swatchOpacity between <code>0</code> and <code>1</code>, with <code>1</code> being the most opaque.
+     */
+    public float getSwatchOpacity() {
+        return swatchOpacity;
+    }
+
+    /**
+     * Sets the font used for this LegendItem.
+     *
+     * @param font the font used for this LegendItem.
+     */
+    public void setFont(Font font) {
+        this.font = font;
+    }
+
+    /**
+     * Returns the font used for this LegendItem.
+     *
+     * @return the font used for this legendItem.
+     */
+    public Font getFont() {
+        return font;
+    }
+
+    /**
+     * Sets the alignment of this LegendItem, relative to the Legend object that contains it.
+     *
+     * @param textAlignment {@link CgviewConstants#LEGEND_ITEM_ALIGN_LEFT CgviewConstants.LEGEND_ITEM_ALIGN_LEFT},
+     *                      {@link CgviewConstants#LEGEND_ITEM_ALIGN_CENTER CgviewConstants.LEGEND_ITEM_ALIGN_CENTER},
+     *                      or {@link CgviewConstants#LEGEND_ITEM_ALIGN_RIGHT CgviewConstants.LEGEND_ITEM_ALIGN_RIGHT}.
+     */
+    public void setTextAlignment(int textAlignment) {
+        this.textAlignment = textAlignment;
+    }
+
+    /**
+     * Returns the alignment of this legendItem, relative to the Legend object that contains it.
+     *
+     * @return {@link CgviewConstants#LEGEND_ITEM_ALIGN_LEFT CgviewConstants.LEGEND_ITEM_ALIGN_LEFT}, {@link
+     *         CgviewConstants#LEGEND_ITEM_ALIGN_CENTER CgviewConstants.LEGEND_ITEM_ALIGN_CENTER}, or {@link
+     *         CgviewConstants#LEGEND_ITEM_ALIGN_RIGHT CgviewConstants.LEGEND_ITEM_ALIGN_RIGHT}.
+     */
+    public int getTextAlignment() {
+        return textAlignment;
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/OuterLabel.class b/cgview/src/ca/ualberta/stothard/cgview/OuterLabel.class
new file mode 100644
index 0000000..56980a5
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/OuterLabel.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/OuterLabel.java b/cgview/src/ca/ualberta/stothard/cgview/OuterLabel.java
new file mode 100644
index 0000000..49a9d1e
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/OuterLabel.java
@@ -0,0 +1,455 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.awt.font.TextLayout;
+import java.awt.font.FontRenderContext;
+import java.awt.geom.*;
+import java.util.*;
+
+/**
+ * This class is used by Cgview objects to facilitate label layout and drawing. The labels represented by this class are
+ * drawn on the outside of the sequence backbone.
+ *
+ * @author Paul Stothard
+ */
+
+public class OuterLabel extends Label implements CgviewConstants {
+
+
+    /**
+     * Constructs a new OuterLabel object.
+     *
+     * @param cgview           the Cgview object to contain this Label.
+     * @param labelText        the text that is to be drawn.
+     * @param hyperlink        a hyperlink to be associated with this Label.
+     * @param mouseover        mouseover information to be associated with this Label.
+     * @param font             the font to use when drawing this Label.
+     * @param color            the color to use when drawing this Label.
+     * @param forceLabel       whether or not this Label should be drawn even if it cannot be placed such that it does
+     *                         not clash with other labels.
+     * @param lineStartRadians the angle in radians of the line extending from the feature to this Label.
+     * @param strand           the strand of this Label ({@link CgviewConstants#DIRECT_STRAND} or {@link
+     *                         CgviewConstants#REVERSE_STRAND}).
+     */
+    protected OuterLabel(Cgview cgview, String labelText, String hyperlink, String mouseover, Font font, Color color, boolean forceLabel, double lineStartRadians, int strand) {
+        super(cgview, labelText, hyperlink, mouseover, font, color, forceLabel, lineStartRadians, strand);
+        cgview.addOuterLabel(this);
+    }
+
+
+    /**
+     * Constructs a new OuterLabel object from an InnerLabel object, and adds the new OuterLabel to the parent Cgview
+     * object. This method is used to convert an InnerLabel to an OuterLabel.
+     *
+     * @param innerLabel the innerLabel object to convert to an outerLabel.
+     */
+    protected OuterLabel(InnerLabel innerLabel) {
+        super(innerLabel.cgview, innerLabel.labelText, innerLabel.hyperlink, innerLabel.mouseover, innerLabel.font, innerLabel.color, innerLabel.forceLabel, innerLabel.lineStartRadians, innerLabel.strand);
+        cgview.addOuterLabel(this);
+    }
+
+
+    /**
+     * Returns a boolean specifying whether or not this Label clashes with other Label objects in the Cgview object
+     * containing this Label.
+     *
+     * @return a <code>boolean</code> specifying whether or not this Label clashes with other Labels.
+     */
+    protected boolean clashesWithAny() {
+        //need to restrict comparison to Labels of the same class.
+        ArrayList labels = cgview.getOuterLabels();
+        if (labels.size() < 2) {
+            return false;
+        }
+        for (int outer = 0; outer < labels.size(); outer++) {
+            Label outerLabel = (Label) (labels.get(outer));
+            if (labels.indexOf(this) == outer) {
+                continue;
+            } else if (this.clashes(outerLabel)) {
+                return true;
+            }
+
+        }
+        return false;
+    }
+
+    /**
+     * Draws a line joining the feature to this Label.
+     */
+    protected void drawLabelLine() {
+
+        //the extension may be omitted.
+        double extension = descent;
+        double lineShiftAmount = 0.01d;
+        double tempRadius;
+
+        double lineX2;
+        double lineY2;
+        Point2D checkPoint = new Point2D.Double(0.0d, 0.0d);
+
+        double textPositionX;
+        double textPositionY;
+
+        double textHeight = unplacedBounds.getHeight();
+        //double textHeight = ascent + descent;
+        double textWidth = unplacedBounds.getWidth();
+
+        if (extendedRadius) {
+            textPositionX = (Math.cos(lineEndRadians) * (extendedLineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (extendedLineEndRadius));
+        } else {
+            textPositionX = (Math.cos(lineEndRadians) * (lineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (lineEndRadius));
+        }
+
+        //adjust text position based on radians for label.
+        if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 1)) { // 0 to 90 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 90 to 180 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - textWidth + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 0) && (Math.sin(lineEndRadians) >= -1) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 180 to 270 degrees
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5 * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else { // 270 to 360
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        }
+
+        double compensate = 0.0d;
+
+        if (cgview.getDrawEntirePlasmid()) {
+            compensate = 0.0d;
+        }
+
+        placedBounds.setRect(unplacedBounds.getX() + textPositionX - 1.5d - compensate, unplacedBounds.getY() + textPositionY - descent - 1.5d - compensate, unplacedBounds.getWidth() + 3.0d, unplacedBounds.getHeight() + 3.0d);
+
+        //gg.setColor(Color.red);
+        //gg.draw(placedBounds);
+
+        //now move label line end until it no longer intersects placedBounds
+        if (cgview.getUseColoredLabelBackgrounds()) {
+            if (extendedRadius) {
+                //draw first line
+                Area area = this.getLineAsArea(lineStartRadius, lineStartRadians, lineEndRadius, lineEndRadians);
+                //draw second line
+                this.drawLine(lineEndRadius, lineEndRadians, extendedLineEndRadius + extension, lineEndRadians, area);
+            } else {
+                this.drawLine(lineStartRadius, lineStartRadians, lineEndRadius + extension, lineEndRadians);
+            }
+        } else {
+
+            if (extendedRadius) {
+                //draw first line
+                Area area = this.getLineAsArea(lineStartRadius, lineStartRadians, lineEndRadius, lineEndRadians);
+
+                tempRadius = extendedLineEndRadius + extension;
+                lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                checkPoint.setLocation(lineX2, lineY2);
+
+                while (placedBounds.contains(checkPoint)) {
+                    tempRadius = tempRadius - lineShiftAmount;
+                    lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                    lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                    checkPoint.setLocation(lineX2, lineY2);
+                }
+
+                //now remove some radius for the line end cap
+                tempRadius = tempRadius - cgview.getLabelLineThickness();
+
+                //draw second line
+                this.drawLine(lineEndRadius, lineEndRadians, tempRadius, lineEndRadians, area);
+            } else {
+
+                tempRadius = lineEndRadius + extension;
+                lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                checkPoint.setLocation(lineX2, lineY2);
+
+                while (placedBounds.contains(checkPoint)) {
+                    tempRadius = tempRadius - lineShiftAmount;
+                    lineX2 = Math.cos(lineEndRadians) * (tempRadius);
+                    lineY2 = Math.sin(lineEndRadians) * (tempRadius);
+                    checkPoint.setLocation(lineX2, lineY2);
+                }
+
+                //now remove some radius for the line end cap
+                tempRadius = tempRadius - cgview.getLabelLineThickness();
+                this.drawLine(lineStartRadius, lineStartRadians, tempRadius, lineEndRadians);
+            }
+        }
+
+    }
+
+    /**
+     * Draws the text portion of this Label.
+     */
+    protected void drawLabelText() {
+
+        double textPositionX;
+        double textPositionY;
+
+        Graphics2D gg = cgview.getGraphics();
+        Color backgroundColor = cgview.getBackgroundColor();
+
+        FontRenderContext frc = gg.getFontRenderContext();
+        TextLayout layout = new TextLayout(labelText, font, frc);
+
+        double textHeight = unplacedBounds.getHeight();
+        //double textHeight = ascent + descent;
+        double textWidth = unplacedBounds.getWidth();
+
+        if (extendedRadius) {
+            textPositionX = (Math.cos(lineEndRadians) * (extendedLineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (extendedLineEndRadius));
+        } else {
+            textPositionX = (Math.cos(lineEndRadians) * (lineEndRadius));
+            textPositionY = (Math.sin(lineEndRadians) * (lineEndRadius));
+        }
+
+        //adjust text position based on radians for label.
+        if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 1)) { // 0 to 90 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 90 to 180 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - textWidth + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 0) && (Math.sin(lineEndRadians) >= -1) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 180 to 270 degrees
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5 * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else { // 270 to 360
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        }
+
+	//adjust text position for (0,0) in upper left
+
+	textPositionX = textPositionX + cgview.getWidth() / 2 - cgview.getCenter().getX();
+	textPositionY = textPositionY + cgview.getHeight() / 2 - cgview.getCenter().getY();
+
+        double compensate = 0.0d;
+
+        if (cgview.getDrawEntirePlasmid()) {
+            compensate = 0.0d;
+        }
+
+        placedBounds.setRect(unplacedBounds.getX() + textPositionX - 1.5d - compensate, unplacedBounds.getY() + textPositionY - descent - 1.5d - compensate, unplacedBounds.getWidth() + 3.0d, unplacedBounds.getHeight() + 3.0d);
+
+        //placedBounds.setRect(unplacedBounds.getX()+textPositionX, unplacedBounds.getY() + textPositionY - descent, unplacedBounds.getWidth(), unplacedBounds.getHeight());
+
+        if (cgview.getUseColoredLabelBackgrounds()) {
+            //cover area behind text
+            if (cgview.getGlobalLabelColor() != null) {
+                gg.setPaint(cgview.getGlobalLabelColor());
+            } else {
+                gg.setPaint(color);
+            }
+            gg.fill(placedBounds);
+
+            //gg.setPaint(Color.blue);
+            //gg.draw(placedBounds);
+
+            gg.setPaint(backgroundColor);
+            layout.draw(gg, (float) textPositionX, (float) textPositionY - descent);
+        } else {
+            gg.setPaint(backgroundColor);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.6f));
+            gg.fill(placedBounds);
+            gg.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1.0f));
+            if (cgview.getGlobalLabelColor() != null) {
+                gg.setPaint(cgview.getGlobalLabelColor());
+            } else {
+                gg.setPaint(color);
+            }
+            layout.draw(gg, (float) textPositionX, (float) textPositionY - descent);
+        }
+    }
+
+    /**
+     * Recalculates the rectangle that represents the bounds of this Label.
+     */
+    protected void updateBounds() {
+	this.updateBounds(2.0d);
+    }
+
+    /**
+     * Recalculates the rectangle that represents the bounds of this Label.
+     *
+     * @param padding the amount of padding to add to the bounds box.
+     */
+    protected void updateBounds(double padding) {
+        double textPositionX;
+        double textPositionY;
+
+        float labelLineThickness = cgview.getLabelLineThickness();
+
+        //now check to see if there is an extended line for this label and if there is adjust the bounds.
+        if (extendedRadius) {
+            textPositionX = (Math.cos(lineEndRadians) * (extendedLineEndRadius + labelLineThickness));
+            textPositionY = (Math.sin(lineEndRadians) * (extendedLineEndRadius + labelLineThickness));
+        } else {
+            textPositionX = (Math.cos(lineEndRadians) * (lineEndRadius + labelLineThickness));
+            textPositionY = (Math.sin(lineEndRadians) * (lineEndRadius + labelLineThickness));
+        }
+
+        //double textHeight = descent + ascent;
+        //double textWidth = advance;
+
+
+        double textHeight = unplacedBounds.getHeight();
+
+        double textWidth = unplacedBounds.getWidth();
+        //adjust text position based on radians for label.
+        if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 1)) { // 0 to 90 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 1) && (Math.sin(lineEndRadians) >= 0) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 90 to 180 degrees
+            //if close to 90 degrees
+            if (Math.sin(lineEndRadians) > 0.90d) {
+                textPositionX = textPositionX - textWidth + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                textPositionY = textPositionY + textHeight;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else if ((Math.sin(lineEndRadians) <= 0) && (Math.sin(lineEndRadians) >= -1) && (Math.cos(lineEndRadians) <= 0) && (Math.cos(lineEndRadians) >= -1)) { // 180 to 270 degrees
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX - textWidth - Math.sin(lineEndRadians) * 0.5 * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                textPositionX = textPositionX - textWidth;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        } else { // 270 to 360
+
+            //if close to 270 degrees
+            if (Math.sin(lineEndRadians) < -0.90d) {
+                textPositionX = textPositionX + Math.sin(lineEndRadians) * 0.5d * textWidth;
+                //textPositionY = textPositionY;
+            } else {
+                //textPositionX = textPositionX;
+                textPositionY = textPositionY + 0.5d * textHeight;
+            }
+        }
+
+        double compensate = 0.0d;
+
+        if (cgview.getDrawEntirePlasmid()) {
+            compensate = 0.0d;
+        }
+
+        placedBounds.setRect(unplacedBounds.getX() + textPositionX - padding - compensate, unplacedBounds.getY() + textPositionY - descent - padding - compensate, unplacedBounds.getWidth() + 2.0d * padding, unplacedBounds.getHeight() + 2.0d * padding);
+
+        //placedBounds.setRect(unplacedBounds.getX()+textPositionX, unplacedBounds.getY() + textPositionY - descent, unplacedBounds.getWidth(), unplacedBounds.getHeight());
+
+    }
+
+    /**
+     * Attempts to move this Label by extending its radius value. If this Label is already at the edge of the canvas it
+     * is not moved.
+     *
+     * @return a <code>boolean</code> specifing whether or not this Label was moved.
+     */
+    protected final boolean extendRadius() {
+        if (extendedRadius) {
+            extendedLineEndRadius = extendedLineEndRadius + radiusShiftAmount;
+            placedBounds.setRect(placedBounds.getX() + Math.cos(lineEndRadians) * radiusShiftAmount, placedBounds.getY() + Math.sin(lineEndRadians) * radiusShiftAmount, placedBounds.getWidth(), placedBounds.getHeight());
+            if (fitsInBackground()) {
+                return true;
+            } else {
+                extendedLineEndRadius = extendedLineEndRadius - radiusShiftAmount;
+                return false;
+            }
+        } else {
+            extendedRadius = true;
+            extendedLineStartRadius = lineEndRadius;
+            extendedLineEndRadius = lineEndRadius + radiusShiftAmount;
+            placedBounds.setRect(placedBounds.getX() + Math.cos(lineEndRadians) * radiusShiftAmount, placedBounds.getY() + Math.sin(lineEndRadians) * radiusShiftAmount, placedBounds.getWidth(), placedBounds.getHeight());
+            return true;
+        }
+    }
+
+    /**
+     * Specifies radius of the innermost point in the line extending from the feature to this Label.
+     *
+     * @param lineStartRadius the radius of the innermost point in the line extending from the feature to this Label.
+     */
+    protected void setLineStartRadius(double lineStartRadius) {
+        this.lineStartRadius = lineStartRadius;
+        lineEndRadius = lineStartRadius + cgview.getLabelLineLength();
+        updateBounds();
+    }
+
+    /**
+     * Returns a boolean specifying whether or not this Label can completely fit inside of the map canvas.
+     *
+     * @return a <code>boolean</code> specifying whether this label can completely fit inside of the map canvas.
+     */
+    protected boolean fitsInBackground() {
+        return cgview.getBackgroundRectangle().contains(this.getBounds());
+    }
+
+}
+    
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Plasmid.class b/cgview/src/ca/ualberta/stothard/cgview/Plasmid.class
new file mode 100644
index 0000000..eaa3ff2
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/Plasmid.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/Plasmid.java b/cgview/src/ca/ualberta/stothard/cgview/Plasmid.java
new file mode 100644
index 0000000..3629dde
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/Plasmid.java
@@ -0,0 +1,1237 @@
+package ca.ualberta.stothard.cgview;
+
+import java.awt.*;
+import java.util.*;
+import javax.imageio.*;
+import java.io.*;
+import java.awt.image.BufferedImage;
+//import javax.servlet.*;
+//import javax.servlet.http.*;
+
+//svg
+import org.apache.batik.svggen.SVGGeneratorContext;
+import org.apache.batik.svggen.SVGGraphics2D;
+import org.apache.batik.svggen.SVGGraphics2DIOException;
+import org.apache.batik.dom.GenericDOMImplementation;
+import org.w3c.dom.Document;
+import org.w3c.dom.DOMImplementation;
+
+//gzip
+import java.util.zip.*;
+
+//note you can only call the draw methods once after the features are added. If you want to call the draw methods
+//more than once you will need to add a method to store the features, and then add code to the prepareToDraw
+//method, to draw the features. Currently features are drawn directly from the addFeature method.
+
+
+public class Plasmid implements CgviewConstants {
+
+
+    private Cgview p;
+    private Legend legend;
+
+    private FeatureSlot forwardSlot0;
+    private FeatureSlot forwardSlot1;
+    private FeatureSlot forwardSlot2;
+    private FeatureSlot forwardSlot3;
+    private FeatureSlot forwardSlot4;
+
+    private FeatureSlot forwardSlot5;
+    private FeatureSlot forwardSlot6;
+    private FeatureSlot forwardSlot7;
+
+    private FeatureSlot restrictionSlot;
+
+    private FeatureSlot reverseSlot0;
+    private FeatureSlot reverseSlot1;
+    private FeatureSlot reverseSlot2;
+    private FeatureSlot reverseSlot3;
+    private FeatureSlot reverseSlot4;
+
+    private FeatureSlot reverseSlot5;
+    private FeatureSlot reverseSlot6;
+    private FeatureSlot reverseSlot7;
+
+    //static
+    final static int NO_DIRECTION = 0;
+    final static int FORWARD = 1;
+    final static int REVERSE = 2;
+
+    final static int REGULAR = 1;
+    final static int INVERSE = 0;
+
+
+    private Hashtable COLORS;
+
+    private Hashtable MAP_ITEM_COLORS;
+    private Hashtable MAP_ITEM_COLORS_INVERSE;
+
+    private Hashtable FEATURE_COLORS;
+    private Hashtable FEATURE_COLORS_INVERSE;
+
+    private Hashtable FEATURE_DECORATIONS_DIRECT;
+    private Hashtable FEATURE_DECORATIONS_REVERSE;
+
+    private Hashtable FEATURE_CATEGORIES;
+
+    private Hashtable FEATURE_THICKNESSES;
+    private Hashtable BACKBONE_THICKNESSES;
+
+    private Hashtable DRAW_LEGEND_ITEMS;
+    private Hashtable LEGEND_ITEM_NAMES;
+
+    //use these to adjust appearance of figure
+    private float opacity = 1.0f;
+    private int imageWidth = 800;
+    private int imageHeight = 800;
+    private int size;
+    private Font labelFont = new Font("SansSerif", Font.PLAIN, 12);
+    private Font titleFont = new Font("SansSerif", Font.PLAIN, 13);
+    private Font legendFont = new Font("SansSerif", Font.PLAIN, 12);
+    private Font rulerFont = new Font("SansSerif", Font.PLAIN, 8);
+    private Font messageFont = new Font("SansSerif", Font.PLAIN, 13);
+    private float featureThickness = 8.0f;
+    private float backboneThickness = 8.0f;
+    private float featureSpacing = 2.0f;
+    private float tickLength = 7.0f;
+    private double labelLineLength = 40.0d;
+    private boolean useColoredLabelBackground = false;
+    private boolean showTitle = true;
+    private boolean showShading = true;
+    private boolean showPositions = true;
+    private boolean showBorder = true;
+    private boolean allowLabelClashLegend = false;
+    private float shadingProportion = 0.4f;
+    private int useInnerLabels = INNER_LABELS_SHOW;
+    private String message = "";
+    private boolean moveInnerLabelsToOuter = true;
+    private int colorScheme = REGULAR; //or INVERSE
+    private String title = "";
+    private int labelPlacementQuality = 9;
+    private int legendPosition = LEGEND_UPPER_RIGHT;
+    private boolean showMessage = true;
+    private boolean showLabels = true;
+    private boolean showLegend = true;
+    private boolean useArrows = true;
+    private boolean useColoredLabels = true;
+    private boolean drawTickMarks = true;
+    private boolean addCategoryInfo = false;
+
+    private int MAXLABELS = 400;
+
+
+    /**
+     * Create a new Plasmid. Note that a constructor accepting a title and length is also available.
+     *
+     * @param size the size of the plasmid in base pairs.
+     */
+    public Plasmid(int size) {
+        this.size = size;
+
+        COLORS = new Hashtable();
+
+        MAP_ITEM_COLORS = new Hashtable();
+        MAP_ITEM_COLORS_INVERSE = new Hashtable();
+
+        FEATURE_COLORS = new Hashtable();
+        FEATURE_COLORS_INVERSE = new Hashtable();
+
+        FEATURE_DECORATIONS_DIRECT = new Hashtable();
+        FEATURE_DECORATIONS_REVERSE = new Hashtable();
+
+        FEATURE_CATEGORIES = new Hashtable();
+
+        FEATURE_THICKNESSES = new Hashtable();
+        BACKBONE_THICKNESSES = new Hashtable();
+
+        DRAW_LEGEND_ITEMS = new Hashtable();
+        LEGEND_ITEM_NAMES = new Hashtable();
+
+        COLORS.put("black", new Color(0, 0, 0));   //tickmark defaults //rulerFontColor default //titleFontColor default
+        COLORS.put("silver", new Color(192, 192, 192));
+        COLORS.put("gray", new Color(128, 128, 128));   //backbone default //partial tickmark default //zeroline default
+        COLORS.put("white", new Color(255, 255, 255));  //background default
+        COLORS.put("maroon", new Color(128, 0, 0));
+        COLORS.put("red", new Color(255, 0, 0));
+        COLORS.put("pink", new Color(255, 153, 204));
+        COLORS.put("purple", new Color(128, 0, 128));
+        COLORS.put("fuchsia", new Color(255, 0, 255));
+        COLORS.put("orange", new Color(255, 153, 0));
+        COLORS.put("green", new Color(0, 128, 0));
+        COLORS.put("spring", new Color(204, 255, 204));
+        COLORS.put("lime", new Color(0, 255, 0));
+        COLORS.put("olive", new Color(128, 128, 0));
+        COLORS.put("yellow", new Color(255, 255, 0));
+        COLORS.put("navy", new Color(0, 0, 128));
+        COLORS.put("blue", new Color(0, 0, 255));
+        COLORS.put("azure", new Color(51, 153, 255));
+        COLORS.put("lightBlue", new Color(102, 204, 255));
+        COLORS.put("teal", new Color(153, 255, 204));
+        COLORS.put("aqua", new Color(0, 255, 255));
+
+        MAP_ITEM_COLORS.put("tick", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("rulerFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("titleFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("messageFont", COLORS.get("black"));
+        MAP_ITEM_COLORS.put("backbone", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("partialTick", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("zeroLine", COLORS.get("gray"));
+        MAP_ITEM_COLORS.put("background", COLORS.get("white"));
+
+        MAP_ITEM_COLORS_INVERSE.put("tick", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("rulerFont", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("titleFont", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("messageFont", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("backbone", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("partialTick", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("zeroLine", COLORS.get("white"));
+        MAP_ITEM_COLORS_INVERSE.put("background", COLORS.get("black"));
+
+        FEATURE_COLORS.put("origin_of_replication", COLORS.get("black"));
+        FEATURE_COLORS.put("promoter", COLORS.get("green"));
+        FEATURE_COLORS.put("terminator", COLORS.get("maroon"));
+        FEATURE_COLORS.put("selectable_marker", COLORS.get("orange"));
+        FEATURE_COLORS.put("regulatory_sequence", COLORS.get("olive"));
+        FEATURE_COLORS.put("tag", COLORS.get("silver"));
+        FEATURE_COLORS.put("other_gene", COLORS.get("fuchsia"));
+        FEATURE_COLORS.put("reporter_gene", COLORS.get("purple"));
+        FEATURE_COLORS.put("unique_restriction_site", COLORS.get("blue"));
+        FEATURE_COLORS.put("restriction_site", COLORS.get("red"));
+        FEATURE_COLORS.put("open_reading_frame", COLORS.get("pink"));
+
+
+        FEATURE_COLORS_INVERSE.put("origin_of_replication", COLORS.get("white"));
+        FEATURE_COLORS_INVERSE.put("promoter", COLORS.get("lime"));
+        FEATURE_COLORS_INVERSE.put("terminator", COLORS.get("yellow"));
+        FEATURE_COLORS_INVERSE.put("selectable_marker", COLORS.get("orange"));
+        FEATURE_COLORS_INVERSE.put("regulatory_sequence", COLORS.get("azure"));
+        FEATURE_COLORS_INVERSE.put("tag", COLORS.get("silver"));
+        FEATURE_COLORS_INVERSE.put("other_gene", COLORS.get("fuchsia"));
+        FEATURE_COLORS_INVERSE.put("reporter_gene", COLORS.get("teal"));
+        FEATURE_COLORS_INVERSE.put("unique_restriction_site", COLORS.get("lightBlue"));
+        FEATURE_COLORS_INVERSE.put("restriction_site", COLORS.get("pink"));
+        FEATURE_COLORS_INVERSE.put("open_reading_frame", COLORS.get("red"));
+
+        FEATURE_DECORATIONS_DIRECT.put("origin_of_replication", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("promoter", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("terminator", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("selectable_marker", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("regulatory_sequence", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("tag", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("other_gene", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("reporter_gene", new Integer(DECORATION_CLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_DIRECT.put("unique_restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_DIRECT.put("open_reading_frame", new Integer(DECORATION_CLOCKWISE_ARROW));
+
+        FEATURE_DECORATIONS_REVERSE.put("origin_of_replication", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("promoter", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("terminator", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("selectable_marker", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("regulatory_sequence", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("tag", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("other_gene", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("reporter_gene", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+        FEATURE_DECORATIONS_REVERSE.put("unique_restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("restriction_site", new Integer(DECORATION_STANDARD));
+        FEATURE_DECORATIONS_REVERSE.put("open_reading_frame", new Integer(DECORATION_COUNTERCLOCKWISE_ARROW));
+
+        FEATURE_CATEGORIES.put("origin_of_replication", new String(" origin"));
+        FEATURE_CATEGORIES.put("promoter", new String(" prom"));
+        FEATURE_CATEGORIES.put("terminator", new String(" term"));
+        FEATURE_CATEGORIES.put("selectable_marker", new String(" marker"));
+        FEATURE_CATEGORIES.put("regulatory_sequence", new String(" reg"));
+        FEATURE_CATEGORIES.put("tag", new String(" tag"));
+        FEATURE_CATEGORIES.put("other_gene", new String(" gene"));
+        FEATURE_CATEGORIES.put("reporter_gene", new String(" gene"));
+        FEATURE_CATEGORIES.put("unique_restriction_site", new String(""));
+        FEATURE_CATEGORIES.put("restriction_site", new String(""));
+        FEATURE_CATEGORIES.put("open_reading_frame", new String(""));
+
+        LEGEND_ITEM_NAMES.put("origin_of_replication", "Origin of replication");
+        LEGEND_ITEM_NAMES.put("promoter", "Promoter");
+        LEGEND_ITEM_NAMES.put("terminator", "Terminator");
+        LEGEND_ITEM_NAMES.put("selectable_marker", "Selectable marker");
+        LEGEND_ITEM_NAMES.put("regulatory_sequence", "Regulatory sequence");
+        LEGEND_ITEM_NAMES.put("tag", "Tag");
+        LEGEND_ITEM_NAMES.put("other_gene", "Other gene");
+        LEGEND_ITEM_NAMES.put("reporter_gene", "Reporter gene");
+        LEGEND_ITEM_NAMES.put("unique_restriction_site", "Unique restriction site");
+        LEGEND_ITEM_NAMES.put("restriction_site", "Restriction site");
+        LEGEND_ITEM_NAMES.put("open_reading_frame", "Open reading frame");
+
+        FEATURE_THICKNESSES.put("xxx-small", new Float(4.0f));
+        FEATURE_THICKNESSES.put("xx-small", new Float(5.0f));
+        FEATURE_THICKNESSES.put("x-small", new Float(6.0f));
+        FEATURE_THICKNESSES.put("small", new Float(7.0f));
+        FEATURE_THICKNESSES.put("medium", new Float(8.0f)); //default for featureThickness
+        FEATURE_THICKNESSES.put("large", new Float(9.0f));
+        FEATURE_THICKNESSES.put("x-large", new Float(10.0f));
+        FEATURE_THICKNESSES.put("xx-large", new Float(11.0f));
+        FEATURE_THICKNESSES.put("xxx-large", new Float(12.0f));
+
+        BACKBONE_THICKNESSES.put("xxx-small", new Float(4.0f));
+        BACKBONE_THICKNESSES.put("xx-small", new Float(5.0f));
+        BACKBONE_THICKNESSES.put("x-small", new Float(6.0f));
+        BACKBONE_THICKNESSES.put("small", new Float(7.0f));
+        BACKBONE_THICKNESSES.put("medium", new Float(8.0f)); //default for backboneThickness
+        BACKBONE_THICKNESSES.put("large", new Float(9.0f));
+        BACKBONE_THICKNESSES.put("x-large", new Float(10.0f));
+        BACKBONE_THICKNESSES.put("xx-large", new Float(11.0f));
+        BACKBONE_THICKNESSES.put("xxx-large", new Float(12.0f));
+
+        p = new Cgview(size);
+    }
+
+    /**
+     * Create a new Plasmid. Note that supplying a title does not ensure that the title will be shown. Use the
+     * setShowTitle() method to force the title to be drawn.
+     *
+     * @param title the title of the plasmid.
+     * @param size  the size of the plasmid in base pairs.
+     */
+    public Plasmid(String title, int size) {
+        this(size);
+        this.title = title;
+
+    }
+
+    /**
+     * Add a feature to this map. Note that the start of the feature should be a smaller number than the stop of the
+     * feature, regardless of the strand. The only case where start is larger than the stop is when the feature runs
+     * across the start/stop boundary, for example 6899-10 on a 7000bp plasmid.
+     *
+     * @param type   one of the following: origin_of_replication, promoter, terminator, selectable_marker,
+     *               regulatory_sequence, tag, other_gene, reporter_gene, unique_restriction_site, restriction_site.
+     * @param name   the name of the feature, such as EcoRI.
+     * @param start  the start position of the feature. Must be between 1 and the length of the plasmid.
+     * @param stop   the end position of the feature. Must be between 1 and the length of the plasmid.
+     * @param strand the strand of the feature. Can be Plasmid.FORWARD, Plasmid.REVERSE, or Plasmid.NO_DIRECTION.
+     */
+    public void addFeature(String type, String name, int start, int stop, int strand) {
+        //add the feature to the plasmid.
+        int decoration;
+        int label;
+        Color color;
+        //String slot;
+
+        if (start > size) {
+            start = size;
+        }
+        if (start < 1) {
+            start = 1;
+        }
+
+        if (stop > size) {
+            stop = size;
+        }
+        if (stop < 1) {
+            stop = 1;
+        }
+
+        try {
+            color = getFeatureColor(type);
+            decoration = getFeatureDecoration(type, strand);
+            label = getLabelType();
+            addItemToLegend(type, strand);
+        } catch (NullPointerException e) {
+            color = new Color(0, 0, 128); //navy
+            if (colorScheme == REGULAR) {
+                color = new Color(0, 0, 128); //navy
+            } else if (colorScheme == INVERSE) {
+                color = new Color(0, 128, 128); //teal
+            }
+            decoration = DECORATION_STANDARD;
+            label = LABEL;
+
+        }
+
+        //create a feature and a feature range
+        //then figure out which feature slot to put the feature in.
+        Feature feature = new Feature(showShading);
+        FeatureRange featureRange = new FeatureRange(feature, start, stop);
+        featureRange.setDecoration(decoration);
+        featureRange.setColor(color);
+        featureRange.setOpacity(opacity);
+        featureRange.setShowLabel(label);
+        if ((showPositions) && ((type.equalsIgnoreCase("restriction_site")) || (type.equalsIgnoreCase("unique_restriction_site")))) {
+            featureRange.setLabel(name + " " + start);
+        } else {
+            if (addCategoryInfo) {
+                try {
+                    featureRange.setLabel(name + (String) FEATURE_CATEGORIES.get(type));
+                } catch (NullPointerException e) {
+                    featureRange.setLabel(name);
+                }
+            } else {
+                featureRange.setLabel(name);
+            }
+        }
+
+        if ((type.equalsIgnoreCase("restriction_site")) || (type.equalsIgnoreCase("unique_restriction_site"))) {
+            if (restrictionSlot == null) {
+                restrictionSlot = new FeatureSlot(DIRECT_STRAND, showShading);
+                restrictionSlot.setFeatureThickness(1f);
+            }
+            feature.setFeatureSlot(restrictionSlot);
+        } else if ((strand == NO_DIRECTION) || (strand == FORWARD)) {
+            if (forwardSlot0 == null) {
+                forwardSlot0 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot0);
+            } else if (forwardSlot0.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot0);
+            } else if (forwardSlot1 == null) {
+                forwardSlot1 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot1);
+            } else if (forwardSlot1.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot1);
+            } else if (forwardSlot2 == null) {
+                forwardSlot2 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot2);
+            } else if (forwardSlot2.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot2);
+            } else if (forwardSlot3 == null) {
+                forwardSlot3 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot3);
+            } else if (forwardSlot3.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot3);
+            } else if (forwardSlot4 == null) {
+                forwardSlot4 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot4);
+            } else if (forwardSlot4.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot4);
+            } else if (forwardSlot5 == null) {
+                forwardSlot5 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot5);
+            } else if (forwardSlot5.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot5);
+            } else if (forwardSlot6 == null) {
+                forwardSlot6 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot6);
+            } else if (forwardSlot6.isRoom(feature)) {
+                feature.setFeatureSlot(forwardSlot6);
+            } else if (forwardSlot7 == null) {
+                forwardSlot7 = new FeatureSlot(DIRECT_STRAND, showShading);
+                feature.setFeatureSlot(forwardSlot7);
+            } else {
+                feature.setFeatureSlot(forwardSlot7);
+            }
+
+
+        } else if (strand == REVERSE) {
+            if (reverseSlot0 == null) {
+                reverseSlot0 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot0);
+            } else if (reverseSlot0.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot0);
+            } else if (reverseSlot1 == null) {
+                reverseSlot1 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot1);
+            } else if (reverseSlot1.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot1);
+            } else if (reverseSlot2 == null) {
+                reverseSlot2 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot2);
+            } else if (reverseSlot2.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot2);
+            } else if (reverseSlot3 == null) {
+                reverseSlot3 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot3);
+            } else if (reverseSlot3.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot3);
+            } else if (reverseSlot4 == null) {
+                reverseSlot4 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot4);
+            } else if (reverseSlot4.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot4);
+            } else if (reverseSlot5 == null) {
+                reverseSlot5 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot5);
+            } else if (reverseSlot5.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot5);
+            } else if (reverseSlot6 == null) {
+                reverseSlot6 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot6);
+            } else if (reverseSlot6.isRoom(feature)) {
+                feature.setFeatureSlot(reverseSlot6);
+            } else if (reverseSlot7 == null) {
+                reverseSlot7 = new FeatureSlot(REVERSE_STRAND, showShading);
+                feature.setFeatureSlot(reverseSlot7);
+            } else {
+                feature.setFeatureSlot(reverseSlot7);
+            }
+        }
+    }
+
+    private Color getFeatureColor(String type) throws NullPointerException {
+
+        Color colorToReturn = (Color) FEATURE_COLORS.get(type);
+
+        if (colorScheme == REGULAR) {
+            colorToReturn = (Color) FEATURE_COLORS.get(type);
+        } else if (colorScheme == INVERSE) {
+            colorToReturn = (Color) FEATURE_COLORS_INVERSE.get(type);
+        }
+        return colorToReturn;
+    }
+
+    private int getFeatureDecoration(String type, int strand) throws NullPointerException {
+
+        int decoration = DECORATION_STANDARD;
+        if (!(useArrows)) {
+            decoration = DECORATION_STANDARD;
+        } else {
+            if (strand == FORWARD) {
+                decoration = ((Integer) FEATURE_DECORATIONS_DIRECT.get(type)).intValue();
+            } else if (strand == NO_DIRECTION) {
+                decoration = ((Integer) FEATURE_DECORATIONS_DIRECT.get(type)).intValue();
+            } else {
+                decoration = ((Integer) FEATURE_DECORATIONS_REVERSE.get(type)).intValue();
+            }
+        }
+
+        return decoration;
+
+    }
+
+    private int getLabelType() throws NullPointerException {
+        int labelType = LABEL;
+        if (showLabels) {
+            labelType = LABEL;
+        } else {
+            labelType = LABEL_NONE;
+
+        }
+        return labelType;
+    }
+
+    private void addItemToLegend(String type, int strand) throws NullPointerException {
+        if ((strand == NO_DIRECTION) || (strand == FORWARD) || (strand == REVERSE)) {
+            DRAW_LEGEND_ITEMS.put(type, new Boolean(true));
+        }
+    }
+
+    /**
+     * Sets the title of of the map. This title is drawn in the center of the backbone circle. Use setShowTitle() to set
+     * whether the title is shown.
+     *
+     * @param title the title of the map.
+     */
+    public void setTitle(String title) {
+        this.title = title.trim();
+    }
+
+    /**
+     * Sets the map message. This message is drawn in the lower right of the map. Use setShowMessage() to set whether
+     * the message is shown.
+     *
+     * @param message the map message.
+     */
+    public void setMessage(String message) {
+        this.message = message.trim();
+    }
+
+    /**
+     * Sets whether a legend is drawn on this map.
+     *
+     * @param show whether a legend is drawn on this map.
+     */
+    public void setShowLegend(boolean show) {
+        showLegend = show;
+    }
+
+    /**
+     * Sets whether a title is drawn on this map. Use the setTitle method to specify the title, or use the Plasmid
+     * constructor that accepts a title.
+     *
+     * @param show whether to draw a title on this map.
+     */
+    public void setShowTitle(boolean show) {
+        showTitle = show;
+    }
+
+    /**
+     * Sets whether a message is drawn on this map. Use the setMessage method to specify the message.
+     *
+     * @param show whether to draw a title on this map.
+     */
+    public void setShowMessage(boolean show) {
+        showMessage = show;
+    }
+
+    /**
+     * Sets whether labels are drawn on this map.
+     *
+     * @param show whether labels are drawn on this map.
+     */
+    public void setShowLabels(boolean show) {
+        showLabels = show;
+    }
+
+    /**
+     * Sets whether a category is added to certain labels to provide more information. For example, a label like "T7"
+     * might become "T7 prom" if this is set to true.
+     *
+     * @param show whether extra info is added to certain labels to provide more information.
+     */
+    public void setAddCategoryInfo(boolean show) {
+        addCategoryInfo = show;
+    }
+
+    /**
+     * Sets whether arrows are drawn on this map (true) or just arcs (false).
+     *
+     * @param show whether labels are drawn in color, or just black and white.
+     */
+    public void setUseArrows(boolean show) {
+        useArrows = show;
+    }
+
+    /**
+     * Sets whether labels are drawn using color (true), or just black and white (false).
+     *
+     * @param show whether labels are drawn in color, or just black and white.
+     */
+    public void setUseColoredLabels(boolean show) {
+        useColoredLabels = show;
+    }
+
+    /**
+     * Sets whether labels are drawn with a colored box surrounding them.
+     *
+     * @param show whether labels are drawn with a colored box surrounding them.
+     */
+    public void setUseColoredLabelBackground(boolean show) {
+        useColoredLabelBackground = show;
+    }
+
+    /**
+     * Sets whether the overall color scheme. Plasmid.REGULAR is a white background with dark labels, while
+     * Plasmid.INVERSE is a black background with light labels.
+     *
+     * @param colorScheme Plasmid.REGULAR or Plasmid.INVERSE.
+     */
+    public void setColorScheme(int colorScheme) {
+        if (colorScheme == INVERSE) {
+            this.colorScheme = INVERSE;
+        } else {
+            this.colorScheme = REGULAR;
+        }
+    }
+
+    /**
+     * Sets whether tick marks are drawn.
+     *
+     * @param draw whether tick marks are drawn.
+     */
+    public void setDrawTickMarks(boolean draw) {
+        drawTickMarks = draw;
+    }
+
+    /**
+     * Sets whether items on the map are drawn with shading.
+     *
+     * @param showShading whether items on the map are draw with shading.
+     */
+    public void setShowShading(boolean showShading) {
+        this.showShading = showShading;
+    }
+
+    /**
+     * Sets whether this map is drawn with a border.
+     *
+     * @param showBorder whether this map is surrounded with a border.
+     */
+    public void setShowBorder(boolean showBorder) {
+        this.showBorder = showBorder;
+    }
+
+    /**
+     * Sets the legend position.
+     *
+     * @param position the position: "upper_right", "upper_left", or "none". Specifying "none" calls the showLegend()
+     *                 method automatically.
+     */
+    public void setLegendPosition(String position) {
+
+        this.legendPosition = LEGEND_UPPER_RIGHT;
+
+        if (position.equalsIgnoreCase("upper_right")) {
+            this.legendPosition = LEGEND_UPPER_RIGHT;
+        } else if (position.equalsIgnoreCase("upper_left")) {
+            this.legendPosition = LEGEND_UPPER_LEFT;
+        } else if (position.equalsIgnoreCase("none")) {
+            this.setShowLegend(false);
+        }
+    }
+
+    /**
+     * Sets whether labels are allowed to be drawn on the inside of the plasmid.
+     *
+     * @param useInnerLabels whether labels are allowed to be drawn on the inside of the plasmid.
+     */
+    public void setShowInnerLabels(boolean useInnerLabels) {
+        if (useInnerLabels) {
+            this.useInnerLabels = INNER_LABELS_SHOW;
+        } else {
+            this.useInnerLabels = INNER_LABELS_NO_SHOW;
+        }
+    }
+
+    /**
+     * Sets the thickness of the arc used to draw the backbone.
+     *
+     * @param width "xxx-small", "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large".
+     */
+    public void setBackboneThickness(String width) {
+        try {
+            backboneThickness = ((Float) BACKBONE_THICKNESSES.get(width)).floatValue();
+        } catch (NullPointerException e) {
+            backboneThickness = ((Float) BACKBONE_THICKNESSES.get("medium")).floatValue();
+        }
+    }
+
+    /**
+     * Sets the thickness of the arc used to draw features.
+     *
+     * @param width "xxx-small", "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "xxx-large".
+     */
+    public void setFeatureThickness(String width) {
+        try {
+            featureThickness = ((Float) FEATURE_THICKNESSES.get(width)).floatValue();
+        } catch (NullPointerException e) {
+            featureThickness = ((Float) FEATURE_THICKNESSES.get("medium")).floatValue();
+        }
+    }
+
+    /**
+     * Sets the width of this map.
+     *
+     * @param width the width of the map.
+     */
+    public void setImageWidth(int width) {
+        if (width < 0) {
+            width = 0;
+        }
+        this.imageWidth = width;
+    }
+
+    /**
+     * Returns the width of this map.
+     *
+     * @return the width of the map.
+     */
+    public int getImageWidth() {
+        return imageWidth;
+    }
+
+    /**
+     * Sets the height of this map.
+     *
+     * @param height the height of the map.
+     */
+    public void setImageHeight(int height) {
+        if (height < 0) {
+            height = 0;
+        }
+        this.imageHeight = height;
+    }
+
+    /**
+     * Returns the height of this map.
+     *
+     * @return the height of the map.
+     */
+    public int getImageHeight() {
+        return imageHeight;
+    }
+
+    private void prepareToDraw() {
+
+        if (forwardSlot0 != null) {
+            forwardSlot0.setCgview(p);
+            forwardSlot0.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot1 != null) {
+            forwardSlot1.setCgview(p);
+            forwardSlot1.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot2 != null) {
+            forwardSlot2.setCgview(p);
+            forwardSlot2.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot3 != null) {
+            forwardSlot3.setCgview(p);
+            forwardSlot3.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot4 != null) {
+            forwardSlot4.setCgview(p);
+            forwardSlot4.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot5 != null) {
+            forwardSlot5.setCgview(p);
+            forwardSlot5.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot6 != null) {
+            forwardSlot6.setCgview(p);
+            forwardSlot6.setFeatureThickness(featureThickness);
+        }
+        if (forwardSlot7 != null) {
+            forwardSlot7.setCgview(p);
+            forwardSlot7.setFeatureThickness(featureThickness);
+        }
+
+
+        if (reverseSlot0 != null) {
+            reverseSlot0.setCgview(p);
+            reverseSlot0.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot1 != null) {
+            reverseSlot1.setCgview(p);
+            reverseSlot1.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot2 != null) {
+            reverseSlot2.setCgview(p);
+            reverseSlot2.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot3 != null) {
+            reverseSlot3.setCgview(p);
+            reverseSlot3.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot4 != null) {
+            reverseSlot4.setCgview(p);
+            reverseSlot4.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot5 != null) {
+            reverseSlot5.setCgview(p);
+            reverseSlot5.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot6 != null) {
+            reverseSlot6.setCgview(p);
+            reverseSlot6.setFeatureThickness(featureThickness);
+        }
+        if (reverseSlot7 != null) {
+            reverseSlot7.setCgview(p);
+            reverseSlot7.setFeatureThickness(featureThickness);
+        }
+
+        if (restrictionSlot != null) {
+            restrictionSlot.setCgview(p);
+            restrictionSlot.setFeatureThickness(featureThickness);
+        }
+
+        //send settings to p
+        if (showTitle) {
+            p.setTitle(title);
+        }
+        p.setWidth(imageWidth);
+        p.setHeight(imageHeight);
+        p.setLabelsToKeep(MAXLABELS);
+        p.setDrawTickMarks(drawTickMarks);
+        p.setTitleFont(titleFont);
+        p.setLabelFont(labelFont);
+        p.setFeatureThickness(featureThickness);
+        p.setBackboneThickness(backboneThickness);
+        p.setFeatureSlotSpacing(featureSpacing);
+        p.setLegendFont(legendFont);
+        p.setTickLength(tickLength);
+        p.setLabelLineLength(labelLineLength);
+        p.setLabelPlacementQuality(labelPlacementQuality);
+        p.setUseColoredLabelBackgrounds(useColoredLabelBackground);
+        p.setShowBorder(showBorder);
+        p.setShowShading(showShading);
+        p.setShadingProportion(shadingProportion);
+        p.setUseInnerLabels(useInnerLabels);
+        p.setMoveInnerLabelsToOuter(moveInnerLabelsToOuter);
+        p.setWarningFont(rulerFont);
+        p.setRulerFont(rulerFont);
+
+        //if not drawing labels, don't show message.
+        if (!(showLabels)) {
+            p.setShowWarning(false);
+        }
+
+        //set backboneRadius based on smallest image dimension
+        int smallestDimension = Math.min(imageWidth, imageHeight);
+        if (smallestDimension <= 750) {
+            p.setBackboneRadius(0.50d * (double) smallestDimension / 2.0d);
+        } else {
+            p.setBackboneRadius(0.50d * 750.0d / 2.0d);
+        }
+
+
+        //check coloredLabels
+        if (!(useColoredLabels)) {
+            if (colorScheme == REGULAR) {
+                p.setGlobalLabelColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+            } else if (colorScheme == INVERSE) {
+                p.setGlobalLabelColor((Color) MAP_ITEM_COLORS_INVERSE.get("titleFont"));
+            }
+        }
+
+        //set map item colors
+        if (colorScheme == REGULAR) {
+            p.setLongTickColor((Color) MAP_ITEM_COLORS.get("tick"));
+            p.setShortTickColor((Color) MAP_ITEM_COLORS.get("partialTick"));
+            p.setZeroTickColor((Color) MAP_ITEM_COLORS.get("zeroLine"));
+            p.setRulerFontColor((Color) MAP_ITEM_COLORS.get("rulerFont"));
+            p.setBackboneColor((Color) MAP_ITEM_COLORS.get("backbone"));
+            p.setTitleFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+            p.setWarningFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+            p.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+        } else if (colorScheme == INVERSE) {
+            p.setLongTickColor((Color) MAP_ITEM_COLORS_INVERSE.get("tick"));
+            p.setShortTickColor((Color) MAP_ITEM_COLORS_INVERSE.get("partialTick"));
+            p.setZeroTickColor((Color) MAP_ITEM_COLORS_INVERSE.get("zeroLine"));
+            p.setRulerFontColor((Color) MAP_ITEM_COLORS_INVERSE.get("rulerFont"));
+            p.setBackboneColor((Color) MAP_ITEM_COLORS_INVERSE.get("backbone"));
+            p.setTitleFontColor((Color) MAP_ITEM_COLORS_INVERSE.get("titleFont"));
+            p.setWarningFontColor((Color) MAP_ITEM_COLORS_INVERSE.get("titleFont"));
+            p.setBackgroundColor((Color) MAP_ITEM_COLORS_INVERSE.get("background"));
+        }
+
+        //build legend
+        if ((showLegend) && (DRAW_LEGEND_ITEMS.size() > 0)) {
+            //create legend
+            legend = new Legend(p);
+            legend.setAllowLabelClash(allowLabelClashLegend);
+            legend.setBackgroundOpacity(0.5f);
+            legend.setFont(legendFont);
+            legend.setPosition(legendPosition);
+            if (colorScheme == REGULAR) {
+                legend.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+                legend.setFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+            } else if (colorScheme == INVERSE) {
+                legend.setBackgroundColor((Color) MAP_ITEM_COLORS_INVERSE.get("background"));
+                legend.setFontColor((Color) MAP_ITEM_COLORS_INVERSE.get("titleFont"));
+            }
+
+            LegendItem legendItem;
+
+            Enumeration legendEntries = DRAW_LEGEND_ITEMS.keys();
+            ArrayList list = new ArrayList();
+            while (legendEntries.hasMoreElements()) {
+                list.add(legendEntries.nextElement());
+            }
+            Collections.sort(list);
+            Iterator i = list.iterator();
+
+            while (i.hasNext()) {
+                String key = (String) i.next();
+                legendItem = new LegendItem(legend);
+		legendItem.setDrawSwatch(SWATCH_SHOW);
+                legendItem.setLabel((String) LEGEND_ITEM_NAMES.get(key));
+                if (colorScheme == REGULAR) {
+                    legendItem.setSwatchColor((Color) FEATURE_COLORS.get(key));
+                } else if (colorScheme == INVERSE) {
+                    legendItem.setSwatchColor((Color) FEATURE_COLORS_INVERSE.get(key));
+                }
+            }
+        }
+
+        //set message
+        if (showMessage) {
+            legend = new Legend(p);
+            legend.setAllowLabelClash(false);
+            legend.setBackgroundOpacity(0.5f);
+            legend.setFont(messageFont);
+            legend.setPosition(LEGEND_LOWER_RIGHT);
+            LegendItem legendItem;
+
+            if (colorScheme == REGULAR) {
+                legend.setBackgroundColor((Color) MAP_ITEM_COLORS.get("background"));
+                legend.setFontColor((Color) MAP_ITEM_COLORS.get("titleFont"));
+                legendItem = new LegendItem(legend);
+                legendItem.setLabel(message);
+                legendItem.setDrawSwatch(SWATCH_NO_SHOW);
+            } else if (colorScheme == INVERSE) {
+                legend.setBackgroundColor((Color) MAP_ITEM_COLORS_INVERSE.get("background"));
+                legend.setFontColor((Color) MAP_ITEM_COLORS_INVERSE.get("titleFont"));
+                legendItem = new LegendItem(legend);
+                legendItem.setLabel(message);
+                legendItem.setDrawSwatch(SWATCH_NO_SHOW);
+            }
+
+        }
+    }
+
+    /**
+     * Writes this map to a PNG file.
+     *
+     * @param filename the path and name of the file to create.
+     */
+    public void writeToPNGFile(String filename) throws IOException {
+
+        this.prepareToDraw();
+
+        BufferedImage buffImage = new BufferedImage(p.getWidth(), p.getHeight(), BufferedImage.TYPE_INT_RGB);
+        Graphics2D graphics2D = buffImage.createGraphics();
+        try {
+            p.draw(graphics2D);
+            System.out.println("Writing picture to " + filename);
+            ImageIO.write(buffImage, "PNG", new File(filename));
+        } finally {
+            graphics2D.dispose();
+        }
+    }
+
+    /**
+     * Writes this map to a JPG file.
+     *
+     * @param filename the path and name of the file to create.
+     */
+    public void writeToJPGFile(String filename) throws IOException {
+
+        this.prepareToDraw();
+
+        BufferedImage buffImage = new BufferedImage(p.getWidth(), p.getHeight(), BufferedImage.TYPE_INT_RGB);
+        Graphics2D graphics2D = buffImage.createGraphics();
+        try {
+            p.draw(graphics2D);
+            System.out.println("Writing picture to " + filename);
+            ImageIO.write(buffImage, "JPG", new File(filename));
+        } finally {
+            graphics2D.dispose();
+        }
+    }
+
+    /**
+     * Writes this map to an SVG file. You may use the simpler methods provided below, instead of this method.
+     *
+     * @param filename       the path and name of the file to create.
+     * @param embedFonts     whether to embed fonts. Embedded fonts give a nicer map but yield larger file sizes.
+     * @param useCompression whether to write this as an SVGZ file.
+     */
+    public void writeToSVGFile(String filename, boolean embedFonts, boolean useCompression) throws FileNotFoundException, IOException, UnsupportedEncodingException, SVGGraphics2DIOException {
+
+        this.prepareToDraw();
+
+        DOMImplementation domImpl = GenericDOMImplementation.getDOMImplementation();
+
+        // Create an instance of org.w3c.dom.Document
+        Document document = domImpl.createDocument(null, "svg", null);
+
+        SVGGeneratorContext ctx = SVGGeneratorContext.createDefault(document);
+        ctx.setComment("Generated by CG-view with the Batik SVG Generator");
+        ctx.setPrecision(12);
+
+        SVGGraphics2D graphics2D;
+
+        if (embedFonts) {
+            graphics2D = new SVGGraphics2D(ctx, true);
+        } else {
+            graphics2D = new SVGGraphics2D(ctx, false);
+        }
+        try {
+            p.setMinimumFeatureLength(0.02d);
+            p.draw(graphics2D);
+            p.setMinimumFeatureLength(1.0d);
+
+            System.out.println("Writing picture to " + filename);
+            boolean useCSS = true;
+
+            FileOutputStream fileOutputStream = new FileOutputStream(new File(filename));
+
+            if (useCompression) {
+                GZIPOutputStream gzipOut = new GZIPOutputStream(fileOutputStream);
+                Writer out = new OutputStreamWriter(gzipOut, "UTF-8");
+                graphics2D.stream(out, useCSS);
+                out.flush();
+                gzipOut.flush();
+                out.close();
+                gzipOut.close();
+            } else {
+                Writer out = new OutputStreamWriter(fileOutputStream, "UTF-8");
+                graphics2D.stream(out, useCSS);
+                out.flush();
+                out.close();
+            }
+        } finally {
+            graphics2D.dispose();
+        }
+    }
+
+    /**
+     * Writes this map to an SVG file. No compression is used, and fonts are embedded.
+     *
+     * @param filename the path and name of the file to create.
+     */
+    public void writeToSVGFile(String filename) throws FileNotFoundException, IOException, UnsupportedEncodingException, SVGGraphics2DIOException {
+        writeToSVGFile(filename, true, false);
+    }
+
+    /**
+     * Writes this map to an SVGZ file (a zipped SVG file).
+     *
+     * @param filename the path and name of the file to create.
+     */
+    public void writeToSVGZFile(String filename) throws FileNotFoundException, IOException, UnsupportedEncodingException, SVGGraphics2DIOException {
+        writeToSVGFile(filename, true, true);
+    }
+
+    public static void main(String ars[]) {
+
+        BufferedImage bi;
+        Graphics2D big;
+        int no_strand = 0;
+        int forward = 1;
+        int reverse = 2;
+
+        Plasmid plasmid = new Plasmid(4921);
+
+        plasmid.setUseColoredLabelBackground(false);
+        plasmid.setColorScheme(Plasmid.REGULAR);
+        plasmid.setTitle("pGFP-1");
+        plasmid.setShowTitle(true);
+        //plasmid.setDrawTickMarks(false);
+        //plasmid.setUseColoredLabels(false);
+        plasmid.setAddCategoryInfo(true);
+        //plasmid.setLegendPosition("none");
+        //plasmid.setShowLabels(false);
+
+        plasmid.setImageWidth(1200);
+        plasmid.setImageHeight(1000);
+
+        plasmid.addFeature("restriction_site", "KpnI", 4624, 4624, no_strand);
+        plasmid.addFeature("restriction_site", "RsaI", 4622, 4622, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 4704, 4704, no_strand);
+        plasmid.addFeature("restriction_site", "MboI", 4704, 4704, no_strand);
+        plasmid.addFeature("restriction_site", "HinfI", 4756, 4756, no_strand);
+        plasmid.addFeature("restriction_site", "HpaI", 4774, 4774, no_strand);
+        plasmid.addFeature("restriction_site", "HincII", 4774, 4774, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 4793, 4793, no_strand);
+        plasmid.addFeature("restriction_site", "MboI", 4793, 4793, no_strand);
+
+        plasmid.addFeature("restriction_site", "SpeI", 4842, 4842, no_strand);
+        plasmid.addFeature("restriction_site", "HinfI", 4888, 4888, no_strand);
+        plasmid.addFeature("restriction_site", "AluI", 4905, 4905, no_strand);
+        plasmid.addFeature("restriction_site", "TaqI", 4957, 4957, no_strand);
+        plasmid.addFeature("restriction_site", "MspI", 4968, 4968, no_strand);
+        plasmid.addFeature("restriction_site", "HpaII", 4968, 4968, no_strand);
+
+        plasmid.addFeature("restriction_site", "BglII", 8, 8, no_strand);
+        plasmid.addFeature("restriction_site", "MboI", 8, 8, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 8, 8, no_strand);
+        plasmid.addFeature("restriction_site", "HinfI", 14, 14, no_strand);
+        plasmid.addFeature("restriction_site", "HinfI", 41, 41, no_strand);
+        plasmid.addFeature("restriction_site", "RsaI", 78, 78, no_strand);
+        plasmid.addFeature("restriction_site", "MspI", 87, 87, no_strand);
+        plasmid.addFeature("restriction_site", "HpaII", 87, 87, no_strand);
+        plasmid.addFeature("restriction_site", "TaqI", 113, 113, no_strand);
+        plasmid.addFeature("restriction_site", "MboI", 158, 158, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 158, 158, no_strand);
+
+        plasmid.addFeature("restriction_site", "MboI", 247, 247, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 247, 247, no_strand);
+        plasmid.addFeature("restriction_site", "TaqI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "ClaI", 250, 250, no_strand);
+
+        plasmid.addFeature("restriction_site", "PvuI", 276, 276, no_strand);
+        plasmid.addFeature("restriction_site", "MboI", 273, 273, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 273, 273, no_strand);
+        plasmid.addFeature("restriction_site", "BglII", 288, 288, no_strand);
+        plasmid.addFeature("restriction_site", "MboI", 288, 288, no_strand);
+        plasmid.addFeature("restriction_site", "NdeII", 288, 288, no_strand);
+
+        plasmid.addFeature("restriction_site", "PstI", 310, 310, no_strand);
+
+
+        //plasmid.addFeature("open_reading_frame", "ORF", 310, 1010, reverse);
+
+
+
+
+
+        //plasmid.addFeature("origin_of_replication", "my origin", 950, 1210, reverse);
+
+        //plasmid.addFeature("origin_of_replication", "my origin", 950, 1210, reverse);
+
+        //plasmid.addFeature("origin_of_replication", "my origin", 950, 1210, reverse);
+
+        //plasmid.addFeature("origin_of_replication", "f1 replication origin", 400, 900, reverse);
+
+        plasmid.addFeature("promoter", "the promoter", 4000, 4050, forward);
+
+        plasmid.addFeature("terminator", "T7 term", 6780, 100, forward);
+
+        plasmid.addFeature("selectable_marker", "AmpR", 1500, 2500, forward);
+
+        plasmid.addFeature("selectable_marker", "a longer marker label a longg label extending long", 700, 750, reverse);
+
+        plasmid.addFeature("reporter_gene", "GFP", 750, 800, forward);
+
+        plasmid.addFeature("regulatory_sequence", "regulatory", 300, 342, reverse);
+
+        plasmid.addFeature("tag", "tag", 30, 50, forward);
+
+        plasmid.addFeature("other_gene", "other gene", 70, 150, reverse);
+
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+
+        plasmid.addFeature("restriction_site", "EcoRI", 32, 32, no_strand);
+
+        plasmid.addFeature("unique_restriction_site", "XmaI", 578, 578, no_strand);
+
+        plasmid.addFeature("unique_restriction_site", "SmaI", 578, 578, no_strand);
+
+        plasmid.addFeature("unique_restriction_site", "XmeII", 578, 578, no_strand);
+
+
+
+        //label testing
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 20, 20, no_strand);
+
+
+        //more label testing
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 250, 250, no_strand);
+
+        //more label testing
+        plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 500, 500, no_strand);
+
+        //and more label testing
+        plasmid.addFeature("restriction_site", "BamHI", 750, 750, no_strand);
+        plasmid.addFeature("restriction_site", "XhoI", 757, 757, no_strand);
+        plasmid.addFeature("restriction_site", "BglII", 777, 777, no_strand);
+        plasmid.addFeature("restriction_site", "NotI", 785, 785, no_strand);
+        plasmid.addFeature("restriction_site", "PstI", 792, 792, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 750, 750, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 750, 750, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 750, 750, no_strand);
+        //plasmid.addFeature("restriction_site", "BamHI", 750, 750, no_strand);
+        plasmid.setMessage("This is a message");
+        try {
+            plasmid.writeToPNGFile("output.png");
+        } catch (Exception e) {
+            System.err.println("Exception thrown in main");
+        }
+
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SeriesImage.class b/cgview/src/ca/ualberta/stothard/cgview/SeriesImage.class
new file mode 100644
index 0000000..3dd15cb
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/SeriesImage.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SeriesImage.java b/cgview/src/ca/ualberta/stothard/cgview/SeriesImage.java
new file mode 100644
index 0000000..a3c2519
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/SeriesImage.java
@@ -0,0 +1,194 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+
+/**
+ * This class is used to encapsulate Cgview map information when a series of images is linked together.
+ *
+ * @author Paul Stothard
+ */
+
+public class SeriesImage implements CgviewConstants {
+
+    int zoomValue;
+    int zoomCenter;
+
+    /**
+     * Constructs a SeriesImage object.
+     *
+     * @param zoomValue  the zoom value of the Cgview map.
+     * @param zoomCenter the zoom center value of the Cgview map.
+     */
+    public SeriesImage(int zoomValue, int zoomCenter) {
+        this.zoomValue = zoomValue;
+        this.zoomCenter = zoomCenter;
+    }
+
+    /**
+     * Returns the zoom value of this SeriesImage.
+     *
+     * @return the zoom value.
+     */
+    public int getZoomValue() {
+        return zoomValue;
+    }
+
+    /**
+     * Returns the zoom center value of this SeriesImage.
+     *
+     * @return the zoom center value.
+     */
+    public int getZoomCenter() {
+        return zoomCenter;
+    }
+
+    /**
+     * Compares a SeriesImage object to this SeriesImage and returns true if they are equal.
+     *
+     * @param seriesImage the SeriesImage to compare with this SeriesImage.
+     * @return whether or not the SeriesImage objects are equal.
+     */
+    public boolean isEqual(SeriesImage seriesImage) {
+        if ((seriesImage.getZoomValue() == zoomValue) && (seriesImage.getZoomCenter() == zoomCenter)) {
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * Examines the ArrayList of LabelBounds objects of type {@link CgviewConstants#BOUNDS_RULER} and determines which
+     * is the middle one. A string intended to serve as part of a file name is constructed from the middle item's zoom
+     * value and zoom center value.
+     *
+     * @param labelBounds   the collection of LabelBounds objects to examine.
+     * @param nextZoomValue the zoom value of the next zoomed Cgview map.
+     * @return a file name prefix consisting of the next zoom value and the zoom center value from the middle
+     *         LabelBounds entry of type {@link CgviewConstants#BOUNDS_RULER}.
+     */
+    protected String getZoomInFilePrefix(ArrayList labelBounds, int nextZoomValue) {
+
+        if (labelBounds.size() == 0) {
+            return null;
+        } else {
+            //if seriesImage is centered on base 1, it should zoom to the next base 1 image
+            if (this.zoomCenter == 1) {
+                return Integer.toString(nextZoomValue) + "_" + Integer.toString(1);
+            }
+
+            //need to determine middle RULER_BOUNDS entry
+            ArrayList rulerBounds = new ArrayList();
+            LabelBounds currentLabelBounds;
+            for (int k = 0; k < labelBounds.size(); k++) {
+                currentLabelBounds = (LabelBounds) labelBounds.get(k);
+                if (currentLabelBounds.getType() == BOUNDS_RULER) {
+                    rulerBounds.add(currentLabelBounds);
+                }
+            }
+            if (rulerBounds.size() == 0) {
+                return null;
+            } else {
+		//go through each rulerBounds and find one with closest base value to this.
+		int closestDistance = Math.abs(((LabelBounds) rulerBounds.get(0)).getBase() - this.zoomCenter);
+		int closestBase = ((LabelBounds) rulerBounds.get(0)).getBase();
+
+		for (int k = 0; k < rulerBounds.size(); k++) {
+		    currentLabelBounds = (LabelBounds) rulerBounds.get(k);
+		    if (Math.abs(currentLabelBounds.getBase() - this.zoomCenter) < closestDistance) {
+			closestDistance = Math.abs(currentLabelBounds.getBase() - this.zoomCenter);
+			closestBase = currentLabelBounds.getBase();
+		    }
+		}
+                return Integer.toString(nextZoomValue) + "_" + Integer.toString(closestBase);
+            }
+        }
+    }
+
+    /**
+     * Determines which SeriesImage should be linked to this SeriesImage using a zoom out button.
+     *
+     * @param previousSeriesImages a collection of SeriesImage objects.
+     * @param previousZoom         the zoom value used for the previous set of Cgview images.
+     * @return a file name prefix to be used for linking purposes.
+     */
+    protected String getZoomOutFilePrefix(ArrayList previousSeriesImages, int previousZoom) {
+
+        int bestDistance = 0;
+        int bestDistanceZoomCenter = 0;
+
+        SeriesImage currentSeriesImage;
+
+        if (previousSeriesImages.size() == 0) {
+            return null;
+        } else {
+            //if seriesImage is centered on base 1, it should zoom out to the previous base 1 image
+            if (this.zoomCenter == 1) {
+                return Integer.toString(previousZoom) + "_" + Integer.toString(1);
+            }
+
+            //find previous SeriesImage with zoomCenter closest to this one.
+            for (int k = 0; k < previousSeriesImages.size(); k++) {
+                currentSeriesImage = (SeriesImage) previousSeriesImages.get(k);
+                if (k == 0) {
+                    bestDistance = Math.abs(currentSeriesImage.getZoomCenter() - this.getZoomCenter());
+                    bestDistanceZoomCenter = currentSeriesImage.getZoomCenter();
+                    previousZoom = currentSeriesImage.getZoomValue();
+                } else {
+                    if (Math.abs(currentSeriesImage.getZoomCenter() - this.getZoomCenter()) < bestDistance) {
+                        bestDistance = Math.abs(currentSeriesImage.getZoomCenter() - this.getZoomCenter());
+                        bestDistanceZoomCenter = currentSeriesImage.getZoomCenter();
+                    }
+                }
+            }
+        }
+        return Integer.toString(previousZoom) + "_" + Integer.toString(bestDistanceZoomCenter);
+    }
+
+    /**
+     * Determines which SeriesImage is adjacent to this SeriesImage in the clockwise direction.
+     *
+     * @param toDrawCurrentZoom a collection of SeriesImages drawn at the same zoom level as this SeriesImage.
+     * @return a file name prefix to be used for linking purposes.
+     */
+    public String getClockwiseFilePrefix(ArrayList toDrawCurrentZoom) {
+        if (toDrawCurrentZoom.size() <= 1) {
+            return Integer.toString(this.zoomValue) + "_" + Integer.toString(this.zoomCenter);
+        } else {
+            //get the index of this object
+            int index = toDrawCurrentZoom.indexOf(this);
+            SeriesImage imageToLink;
+            if (index == toDrawCurrentZoom.size() - 1) {
+                imageToLink = (SeriesImage) toDrawCurrentZoom.get(0);
+            } else {
+                imageToLink = (SeriesImage) toDrawCurrentZoom.get(index + 1);
+            }
+
+            return Integer.toString(imageToLink.getZoomValue()) + "_" + Integer.toString(imageToLink.getZoomCenter());
+        }
+    }
+
+    /**
+     * Determines which SeriesImage is adjacent to this SeriesImage in the counterclockwise direction.
+     *
+     * @param toDrawCurrentZoom a collection of SeriesImages drawn at the same zoom level as this SeriesImage.
+     * @return a file name prefix to be used for linking purposes.
+     */
+    public String getCounterclockwiseFilePrefix(ArrayList toDrawCurrentZoom) {
+        if (toDrawCurrentZoom.size() <= 1) {
+            return Integer.toString(this.zoomValue) + "_" + Integer.toString(this.zoomCenter);
+        } else {
+            //get the index of this object
+            int index = toDrawCurrentZoom.indexOf(this);
+            SeriesImage imageToLink;
+            if (index == 0) {
+                imageToLink = (SeriesImage) toDrawCurrentZoom.get(toDrawCurrentZoom.size() - 1);
+            } else {
+                imageToLink = (SeriesImage) toDrawCurrentZoom.get(index - 1);
+            }
+
+            return Integer.toString(imageToLink.getZoomValue()) + "_" + Integer.toString(imageToLink.getZoomCenter());
+        }
+    }
+
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.class b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.class
new file mode 100644
index 0000000..4306929
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.java b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.java
new file mode 100644
index 0000000..53476af
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByForceLabel.java
@@ -0,0 +1,26 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+/**
+ * Sorts Label objects so that those where {@link Label#getForceLabel()} returns <code>true</code> are last.
+ */
+public class SortLabelsByForceLabel implements Comparator {
+
+    public int compare(Object o1, Object o2) {
+        Label label1 = (Label) o1;
+        Label label2 = (Label) o2;
+
+        if (label1.getForceLabel() == label2.getForceLabel()) {
+            return 0;
+        } else if (label1.getForceLabel()) {
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
+    public boolean equals(Object obj) {
+        return obj.equals(this);
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadians.class b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadians.class
new file mode 100644
index 0000000..e4945b1
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadians.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadians.java b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadians.java
new file mode 100644
index 0000000..7eead0c
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadians.java
@@ -0,0 +1,26 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+/**
+ * Sorts Label objects so that those with smaller {@link Label#getLineStartRadians()} values are first.
+ */
+public class SortLabelsByRadians implements Comparator {
+
+    public int compare(Object o1, Object o2) {
+        Label label1 = (Label) o1;
+        Label label2 = (Label) o2;
+
+        if (label1.getLineStartRadians() == label2.getLineStartRadians()) {
+            return 0;
+        } else if (label2.getLineStartRadians() < label1.getLineStartRadians()) {
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
+    public boolean equals(Object obj) {
+        return obj.equals(this);
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.class b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.class
new file mode 100644
index 0000000..1dcfff6
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.java b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.java
new file mode 100644
index 0000000..ed46a87
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadiansShift.java
@@ -0,0 +1,27 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+/**
+ * Sorts Label objects so that those that those with the smallest absolute difference between {@link
+ * Label#getLineStartRadians()} and {@link Label#getLineEndRadians()} are first.
+ */
+public class SortLabelsByRadiansShift implements Comparator {
+
+    public int compare(Object o1, Object o2) {
+        Label label1 = (Label) o1;
+        Label label2 = (Label) o2;
+
+        if (Math.abs(label1.getLineStartRadians() - label1.getLineEndRadians()) == Math.abs(label2.getLineStartRadians() - label2.getLineEndRadians())) {
+            return 0;
+        } else if (Math.abs(label1.getLineStartRadians() - label1.getLineEndRadians()) < Math.abs(label2.getLineStartRadians() - label2.getLineEndRadians())) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    public boolean equals(Object obj) {
+        return obj.equals(this);
+    }
+} 
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadius.class b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadius.class
new file mode 100644
index 0000000..e6e0093
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadius.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadius.java b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadius.java
new file mode 100644
index 0000000..37e7829
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/SortLabelsByRadius.java
@@ -0,0 +1,44 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+/**
+ * Sorts Label objects so that those that those furthest from the sequence backbone are first.
+ */
+public class SortLabelsByRadius implements Comparator {
+
+    public int compare(Object o1, Object o2) {
+        Label label1 = (Label) o1;
+        Label label2 = (Label) o2;
+
+        double label1Radius;
+        double label2Radius;
+
+        double label1StartRadius = label1.getLineStartRadius();
+        double label2StartRadius = label2.getLineStartRadius();
+
+        if (label1.isExtendedRadius()) {
+            label1Radius = label1.getExtendedLineEndRadius();
+        } else {
+            label1Radius = label1.getLineEndRadius();
+        }
+
+        if (label2.isExtendedRadius()) {
+            label2Radius = label2.getExtendedLineEndRadius();
+        } else {
+            label2Radius = label2.getLineEndRadius();
+        }
+
+        if (Math.abs(label1Radius - label1StartRadius) == Math.abs(label2Radius - label2StartRadius)) {
+            return 0;
+        } else if (Math.abs(label2Radius - label2StartRadius) < Math.abs(label1Radius - label1StartRadius)) {
+            return -1;
+        } else {
+            return 1;
+        }
+    }
+
+    public boolean equals(Object obj) {
+        return obj.equals(this);
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.class b/cgview/src/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.class
new file mode 100644
index 0000000..a49121a
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.class differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.java b/cgview/src/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.java
new file mode 100644
index 0000000..432ef15
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/SortSeriesImageByZoomCenter.java
@@ -0,0 +1,26 @@
+package ca.ualberta.stothard.cgview;
+
+import java.util.*;
+
+/**
+ * Sorts SeriesImage objects so that those with the lowest zoom center value are first.
+ */
+public class SortSeriesImageByZoomCenter implements Comparator {
+
+    public int compare(Object o1, Object o2) {
+        SeriesImage seriesImage1 = (SeriesImage) o1;
+        SeriesImage seriesImage2 = (SeriesImage) o2;
+
+        if (seriesImage1.getZoomCenter() == seriesImage2.getZoomCenter()) {
+            return 0;
+        } else if (seriesImage2.getZoomCenter() < seriesImage1.getZoomCenter()) {
+            return 1;
+        } else {
+            return -1;
+        }
+    }
+
+    public boolean equals(Object obj) {
+        return obj.equals(this);
+    }
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/as_png.png b/cgview/src/ca/ualberta/stothard/cgview/includes/as_png.png
new file mode 100644
index 0000000..376f608
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/as_png.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/as_svg.png b/cgview/src/ca/ualberta/stothard/cgview/includes/as_svg.png
new file mode 100644
index 0000000..f2283f0
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/as_svg.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/expand_in.png b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_in.png
new file mode 100644
index 0000000..a89e8f0
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_in.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/expand_in_g.png b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_in_g.png
new file mode 100644
index 0000000..387d289
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_in_g.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/expand_out.png b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_out.png
new file mode 100644
index 0000000..d47a2e9
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_out.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/expand_out_g.png b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_out_g.png
new file mode 100644
index 0000000..4aa0023
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/expand_out_g.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/full.png b/cgview/src/ca/ualberta/stothard/cgview/includes/full.png
new file mode 100644
index 0000000..536da90
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/full.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/full_g.png b/cgview/src/ca/ualberta/stothard/cgview/includes/full_g.png
new file mode 100644
index 0000000..d6c1ab7
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/full_g.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/help.html b/cgview/src/ca/ualberta/stothard/cgview/includes/help.html
new file mode 100644
index 0000000..cda90e2
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/includes/help.html
@@ -0,0 +1,153 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en">
+<head>
+<title>Map Navigation</title>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<link rel="stylesheet" href="stylesheet.css"  type="text/css" />
+</head>
+<body>
+
+<div class="title">
+Map Navigation
+</div>
+
+<table border="0" cellspacing="2" cellpadding="2" align="left">
+<tbody>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Buttons
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_out.png" alt="[Expand -]" />
+</td>
+<td class="left">
+View more of the map, at a reduced size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_in.png" alt="[Expand +]" />
+</td>
+<td class="left">
+View less of the map, at an expanded size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="full.png" alt="[Full view]" />
+</td>
+<td class="left">
+View the entire map.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_back.png" alt="[Rotate -]" />
+</td>
+<td class="left">
+Shift the current view in the counterclockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_forward.png" alt="[Rotate +]" />
+</td>
+<td class="left">
+Shift the current view in the clockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="as_png.png" alt="[View as PNG]" />
+</td>
+<td class="left">
+View the map in PNG (Portable Network Graphics) format. PNG raster images can be viewed in most current browsers.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="as_svg.png" alt="[View as SVG]" />
+</td>
+<td class="left">
+View the map in SVG (Scalable Vector Graphics) format. SVG is an XML grammar for defining vector-based 2D graphics. SVG images can be viewed in most current web browsers using the <a href="http://www.adobe.com/svg/viewer/install/main.html">Adobe SVG plugin</a>.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="comment">
+Note: The file size of the current view in SVG and PNG format is given in the lower right of the map window.
+</span>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Using Tick Marks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+A region of interest can be expanded by clicking on the nearest tick mark. 
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Hyperlinks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Some feature labels may be linked to other resources. To access a linked resource, click on the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Mouseover
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Additional information may be viewed for some features by pointing to the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="validInfo">
+Contact: Paul Stothard stothard at ualberta.ca
+</span><br />
+<span class="validInfo">
+<a href="http://validator.w3.org/check/referer">Valid XHTML 1.0;</a> <a href="http://jigsaw.w3.org/css-validator/check/referer">Valid CSS.</a>
+</span>
+</td>
+</tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/help.png b/cgview/src/ca/ualberta/stothard/cgview/includes/help.png
new file mode 100644
index 0000000..4ca5189
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/help.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/help_png.html b/cgview/src/ca/ualberta/stothard/cgview/includes/help_png.html
new file mode 100644
index 0000000..f1410ba
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/includes/help_png.html
@@ -0,0 +1,135 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html lang="en">
+<head>
+<title>Map Navigation</title>
+<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
+<link rel="stylesheet" href="stylesheet.css"  type="text/css" />
+</head>
+<body>
+
+<div class="title">
+Map Navigation
+</div>
+
+<table border="0" cellspacing="2" cellpadding="2" align="left">
+<tbody>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Buttons
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_out.png" alt="[Expand -]" />
+</td>
+<td class="left">
+View more of the map, at a reduced size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="expand_in.png" alt="[Expand +]" />
+</td>
+<td class="left">
+View less of the map, at an expanded size.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="full.png" alt="[Full view]" />
+</td>
+<td class="left">
+View the entire map.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_back.png" alt="[Rotate -]" />
+</td>
+<td class="left">
+Shift the current view in the counterclockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="right">
+<img style="border:0" src="move_forward.png" alt="[Rotate +]" />
+</td>
+<td class="left">
+Shift the current view in the clockwise direction.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="comment">
+Note: The file size of the current view in PNG format is given in the lower right of the map window.
+</span>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Navigation Using Tick Marks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+A region of interest can be expanded by clicking on the nearest tick mark. 
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Hyperlinks
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Some feature labels may be linked to other resources. To access a linked resource, click on the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<div class="heading">
+Label Mouseover
+</div>
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+Additional information may be viewed for some features by pointing to the feature label.
+</td>
+</tr>
+
+<tr>
+<td class="left" colspan="2">
+<span class="validInfo">
+Contact: Paul Stothard stothard at ualberta.ca
+</span><br />
+<span class="validInfo">
+<a href="http://validator.w3.org/check/referer">Valid XHTML 1.0;</a> <a href="http://jigsaw.w3.org/css-validator/check/referer">Valid CSS.</a>
+</span>
+</td>
+</tr>
+
+</tbody>
+</table>
+
+</body>
+</html>
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/info.js b/cgview/src/ca/ualberta/stothard/cgview/includes/info.js
new file mode 100644
index 0000000..0c69ea7
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/includes/info.js
@@ -0,0 +1,73 @@
+//Written by Paul Stothard, University of Alberta, Canada 2004
+
+function showMouseover(evt, message) {
+
+	var PADDING = 8;
+	var X_SHIFT = 20;
+	var Y_SHIFT = 20;
+
+	var svgDoc = evt.target.ownerDocument; 
+
+	var translateX = svgDoc.rootElement.currentTranslate.x;
+	var translateY = svgDoc.rootElement.currentTranslate.y;
+	var scale = 1 / svgDoc.rootElement.currentScale;
+
+	var effectiveDocWidth = svgDoc.rootElement.getAttribute("width") - translateX;
+	var effectiveDocHeight = svgDoc.rootElement.getAttribute("height") - translateY;
+
+	var targetText = svgDoc.getElementById("mouseoverBox");
+	var x = evt.clientX - translateX + X_SHIFT;
+	var y = evt.clientY - translateY + Y_SHIFT;
+
+	var newText = svgDoc.createTextNode(message); 
+	targetText.replaceChild(newText, targetText.firstChild); 
+	var textBounds = targetText.getBBox(); 
+
+	y = y + textBounds.height;
+
+	if (x + textBounds.width + PADDING > effectiveDocWidth) {
+		x = x - (x + textBounds.width + PADDING - effectiveDocWidth); 
+		if (y > effectiveDocWidth / 2) {
+			y = y - Y_SHIFT - Y_SHIFT - textBounds.height;
+		}
+		else {
+
+		}
+	} 
+
+	if (y + textBounds.height + PADDING > effectiveDocHeight) {
+		y = y - (y + textBounds.height + PADDING - effectiveDocHeight); 
+	} 
+
+	if (x - PADDING < 0) {
+		x = 0 + PADDING;
+	} 
+	if (y - textBounds.height - PADDING < 0) {
+		y = 0 + textBounds.height + PADDING;
+	}
+
+	targetText.setAttribute("x", x);
+	targetText.setAttribute("y", y);
+	textBounds = targetText.getBBox();
+	targetTextBackground = svgDoc.getElementById("mouseoverBoxBackground");
+	targetTextBackground.setAttribute("transform", "scale(" + scale + "," + scale + ")");
+	targetTextBackground.setAttribute("x", textBounds.x - PADDING / 2);
+	targetTextBackground.setAttribute("y", textBounds.y - PADDING / 2);
+	targetTextBackground.setAttribute("width", textBounds.width + PADDING); 
+	targetTextBackground.setAttribute("height", textBounds.height + PADDING);
+	targetText.setAttribute("transform", "scale(" + scale + "," + scale + ")");
+} 
+
+function showMouseout(evt) {
+	var svgDoc = evt.target.ownerDocument;
+	var targetText = svgDoc.getElementById("mouseoverBox");
+	var newText = svgDoc.createTextNode("");
+	targetText.setAttribute("x", 0);
+	targetText.setAttribute("y", 0);
+	targetText.replaceChild(newText, targetText.firstChild);
+	targetTextBackground = svgDoc.getElementById("mouseoverBoxBackground");
+	targetTextBackground.setAttribute("x", 0);
+	targetTextBackground.setAttribute("y", 0);
+	targetTextBackground.setAttribute("width", 0);
+	targetTextBackground.setAttribute("height", 0);
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/move_back.png b/cgview/src/ca/ualberta/stothard/cgview/includes/move_back.png
new file mode 100644
index 0000000..b612959
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/move_back.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/move_back_g.png b/cgview/src/ca/ualberta/stothard/cgview/includes/move_back_g.png
new file mode 100644
index 0000000..89252a8
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/move_back_g.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/move_forward.png b/cgview/src/ca/ualberta/stothard/cgview/includes/move_forward.png
new file mode 100644
index 0000000..acbd440
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/move_forward.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/move_forward_g.png b/cgview/src/ca/ualberta/stothard/cgview/includes/move_forward_g.png
new file mode 100644
index 0000000..260d6b0
Binary files /dev/null and b/cgview/src/ca/ualberta/stothard/cgview/includes/move_forward_g.png differ
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/overlib.js b/cgview/src/ca/ualberta/stothard/cgview/includes/overlib.js
new file mode 100644
index 0000000..3c6bfd6
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/includes/overlib.js
@@ -0,0 +1,1491 @@
+//\/////
+//\  overLIB 4.21 - You may not remove or change this notice.
+//\  Copyright Erik Bosrup 1998-2004. All rights reserved.
+//\
+//\  Contributors are listed on the homepage.
+//\  This file might be old, always check for the latest version at:
+//\  http://www.bosrup.com/web/overlib/
+//\
+//\  Please read the license agreement (available through the link above)
+//\  before using overLIB. Direct any licensing questions to erik at bosrup.com.
+//\
+//\  Do not sell this as your own work or remove this copyright notice. 
+//\  For full details on copying or changing this script please read the
+//\  license agreement at the link above. Please give credit on sites that
+//\  use overLIB and submit changes of the script so other people can use
+//\  them as well.
+//   $Revision: 1.3 $                $Date: 2006/05/08 17:05:34 $
+//\/////
+//\mini
+
+////////
+// PRE-INIT
+// Ignore these lines, configuration is below.
+////////
+var olLoaded = 0;var pmStart = 10000000; var pmUpper = 10001000; var pmCount = pmStart+1; var pmt=''; var pms = new Array(); var olInfo = new Info('4.21', 1);
+var FREPLACE = 0; var FBEFORE = 1; var FAFTER = 2; var FALTERNATE = 3; var FCHAIN=4;
+var olHideForm=0;  // parameter for hiding SELECT and ActiveX elements in IE5.5+ 
+var olHautoFlag = 0;  // flags for over-riding VAUTO and HAUTO if corresponding
+var olVautoFlag = 0;  // positioning commands are used on the command line
+var hookPts = new Array(), postParse = new Array(), cmdLine = new Array(), runTime = new Array();
+// for plugins
+registerCommands('donothing,inarray,caparray,sticky,background,noclose,caption,left,right,center,offsetx,offsety,fgcolor,bgcolor,textcolor,capcolor,closecolor,width,border,cellpad,status,autostatus,autostatuscap,height,closetext,snapx,snapy,fixx,fixy,relx,rely,fgbackground,bgbackground,padx,pady,fullhtml,above,below,capicon,textfont,captionfont,closefont,textsize,captionsize,closesize,timeout,function,delay,hauto,vauto,closeclick,wrap,followmouse,mouseoff,closetitle,cssoff,compatmode,css [...]
+
+////////
+// DEFAULT CONFIGURATION
+// Settings you want everywhere are set here. All of this can also be
+// changed on your html page or through an overLIB call.
+////////
+if (typeof ol_fgcolor=='undefined') var ol_fgcolor="#CCCCFF";
+if (typeof ol_bgcolor=='undefined') var ol_bgcolor="#333399";
+if (typeof ol_textcolor=='undefined') var ol_textcolor="#000000";
+if (typeof ol_capcolor=='undefined') var ol_capcolor="#FFFFFF";
+if (typeof ol_closecolor=='undefined') var ol_closecolor="#9999FF";
+if (typeof ol_textfont=='undefined') var ol_textfont="Verdana,Arial,Helvetica";
+if (typeof ol_captionfont=='undefined') var ol_captionfont="Verdana,Arial,Helvetica";
+if (typeof ol_closefont=='undefined') var ol_closefont="Verdana,Arial,Helvetica";
+if (typeof ol_textsize=='undefined') var ol_textsize="1";
+if (typeof ol_captionsize=='undefined') var ol_captionsize="1";
+if (typeof ol_closesize=='undefined') var ol_closesize="1";
+if (typeof ol_width=='undefined') var ol_width="200";
+if (typeof ol_border=='undefined') var ol_border="1";
+if (typeof ol_cellpad=='undefined') var ol_cellpad=2;
+if (typeof ol_offsetx=='undefined') var ol_offsetx=10;
+if (typeof ol_offsety=='undefined') var ol_offsety=10;
+if (typeof ol_text=='undefined') var ol_text="Default Text";
+if (typeof ol_cap=='undefined') var ol_cap="";
+if (typeof ol_sticky=='undefined') var ol_sticky=0;
+if (typeof ol_background=='undefined') var ol_background="";
+if (typeof ol_close=='undefined') var ol_close="Close";
+if (typeof ol_hpos=='undefined') var ol_hpos=RIGHT;
+if (typeof ol_status=='undefined') var ol_status="";
+if (typeof ol_autostatus=='undefined') var ol_autostatus=0;
+if (typeof ol_height=='undefined') var ol_height=-1;
+if (typeof ol_snapx=='undefined') var ol_snapx=0;
+if (typeof ol_snapy=='undefined') var ol_snapy=0;
+if (typeof ol_fixx=='undefined') var ol_fixx=-1;
+if (typeof ol_fixy=='undefined') var ol_fixy=-1;
+if (typeof ol_relx=='undefined') var ol_relx=null;
+if (typeof ol_rely=='undefined') var ol_rely=null;
+if (typeof ol_fgbackground=='undefined') var ol_fgbackground="";
+if (typeof ol_bgbackground=='undefined') var ol_bgbackground="";
+if (typeof ol_padxl=='undefined') var ol_padxl=1;
+if (typeof ol_padxr=='undefined') var ol_padxr=1;
+if (typeof ol_padyt=='undefined') var ol_padyt=1;
+if (typeof ol_padyb=='undefined') var ol_padyb=1;
+if (typeof ol_fullhtml=='undefined') var ol_fullhtml=0;
+if (typeof ol_vpos=='undefined') var ol_vpos=BELOW;
+if (typeof ol_aboveheight=='undefined') var ol_aboveheight=0;
+if (typeof ol_capicon=='undefined') var ol_capicon="";
+if (typeof ol_frame=='undefined') var ol_frame=self;
+if (typeof ol_timeout=='undefined') var ol_timeout=0;
+if (typeof ol_function=='undefined') var ol_function=null;
+if (typeof ol_delay=='undefined') var ol_delay=0;
+if (typeof ol_hauto=='undefined') var ol_hauto=0;
+if (typeof ol_vauto=='undefined') var ol_vauto=0;
+if (typeof ol_closeclick=='undefined') var ol_closeclick=0;
+if (typeof ol_wrap=='undefined') var ol_wrap=0;
+if (typeof ol_followmouse=='undefined') var ol_followmouse=1;
+if (typeof ol_mouseoff=='undefined') var ol_mouseoff=0;
+if (typeof ol_closetitle=='undefined') var ol_closetitle='Close';
+if (typeof ol_compatmode=='undefined') var ol_compatmode=0;
+if (typeof ol_css=='undefined') var ol_css=CSSOFF;
+if (typeof ol_fgclass=='undefined') var ol_fgclass="";
+if (typeof ol_bgclass=='undefined') var ol_bgclass="";
+if (typeof ol_textfontclass=='undefined') var ol_textfontclass="";
+if (typeof ol_captionfontclass=='undefined') var ol_captionfontclass="";
+if (typeof ol_closefontclass=='undefined') var ol_closefontclass="";
+
+////////
+// ARRAY CONFIGURATION
+////////
+
+// You can use these arrays to store popup text here instead of in the html.
+if (typeof ol_texts=='undefined') var ol_texts = new Array("Text 0", "Text 1");
+if (typeof ol_caps=='undefined') var ol_caps = new Array("Caption 0", "Caption 1");
+
+////////
+// END OF CONFIGURATION
+// Don't change anything below this line, all configuration is above.
+////////
+
+
+
+
+
+////////
+// INIT
+////////
+// Runtime variables init. Don't change for config!
+var o3_text="";
+var o3_cap="";
+var o3_sticky=0;
+var o3_background="";
+var o3_close="Close";
+var o3_hpos=RIGHT;
+var o3_offsetx=2;
+var o3_offsety=2;
+var o3_fgcolor="";
+var o3_bgcolor="";
+var o3_textcolor="";
+var o3_capcolor="";
+var o3_closecolor="";
+var o3_width=100;
+var o3_border=1;
+var o3_cellpad=2;
+var o3_status="";
+var o3_autostatus=0;
+var o3_height=-1;
+var o3_snapx=0;
+var o3_snapy=0;
+var o3_fixx=-1;
+var o3_fixy=-1;
+var o3_relx=null;
+var o3_rely=null;
+var o3_fgbackground="";
+var o3_bgbackground="";
+var o3_padxl=0;
+var o3_padxr=0;
+var o3_padyt=0;
+var o3_padyb=0;
+var o3_fullhtml=0;
+var o3_vpos=BELOW;
+var o3_aboveheight=0;
+var o3_capicon="";
+var o3_textfont="Verdana,Arial,Helvetica";
+var o3_captionfont="Verdana,Arial,Helvetica";
+var o3_closefont="Verdana,Arial,Helvetica";
+var o3_textsize="1";
+var o3_captionsize="1";
+var o3_closesize="1";
+var o3_frame=self;
+var o3_timeout=0;
+var o3_timerid=0;
+var o3_allowmove=0;
+var o3_function=null; 
+var o3_delay=0;
+var o3_delayid=0;
+var o3_hauto=0;
+var o3_vauto=0;
+var o3_closeclick=0;
+var o3_wrap=0;
+var o3_followmouse=1;
+var o3_mouseoff=0;
+var o3_closetitle='';
+var o3_compatmode=0;
+var o3_css=CSSOFF;
+var o3_fgclass="";
+var o3_bgclass="";
+var o3_textfontclass="";
+var o3_captionfontclass="";
+var o3_closefontclass="";
+
+// Display state variables
+var o3_x = 0;
+var o3_y = 0;
+var o3_showingsticky = 0;
+var o3_removecounter = 0;
+
+// Our layer
+var over = null;
+var fnRef, hoveringSwitch = false;
+var olHideDelay;
+
+// Decide browser version
+var isMac = (navigator.userAgent.indexOf("Mac") != -1);
+var olOp = (navigator.userAgent.toLowerCase().indexOf('opera') > -1 && document.createTextNode);  // Opera 7
+var olNs4 = (navigator.appName=='Netscape' && parseInt(navigator.appVersion) == 4);
+var olNs6 = (document.getElementById) ? true : false;
+var olKq = (olNs6 && /konqueror/i.test(navigator.userAgent));
+var olIe4 = (document.all) ? true : false;
+var olIe5 = false; 
+var olIe55 = false; // Added additional variable to identify IE5.5+
+var docRoot = 'document.body';
+
+// Resize fix for NS4.x to keep track of layer
+if (olNs4) {
+	var oW = window.innerWidth;
+	var oH = window.innerHeight;
+	window.onresize = function() { if (oW != window.innerWidth || oH != window.innerHeight) location.reload(); }
+}
+
+// Microsoft Stupidity Check(tm).
+if (olIe4) {
+	var agent = navigator.userAgent;
+	if (/MSIE/.test(agent)) {
+		var versNum = parseFloat(agent.match(/MSIE[ ](\d\.\d+)\.*/i)[1]);
+		if (versNum >= 5){
+			olIe5=true;
+			olIe55=(versNum>=5.5&&!olOp) ? true : false;
+			if (olNs6) olNs6=false;
+		}
+	}
+	if (olNs6) olIe4 = false;
+}
+
+// Check for compatability mode.
+if (document.compatMode && document.compatMode == 'CSS1Compat') {
+	docRoot= ((olIe4 && !olOp) ? 'document.documentElement' : docRoot);
+}
+
+// Add window onload handlers to indicate when all modules have been loaded
+// For Netscape 6+ and Mozilla, uses addEventListener method on the window object
+// For IE it uses the attachEvent method of the window object and for Netscape 4.x
+// it sets the window.onload handler to the OLonload_handler function for Bubbling
+if(window.addEventListener) window.addEventListener("load",OLonLoad_handler,false);
+else if (window.attachEvent) window.attachEvent("onload",OLonLoad_handler);
+
+var capExtent;
+
+////////
+// PUBLIC FUNCTIONS
+////////
+
+// overlib(arg0,...,argN)
+// Loads parameters into global runtime variables.
+function overlib() {
+	if (!olLoaded || isExclusive(overlib.arguments)) return true;
+	if (olCheckMouseCapture) olMouseCapture();
+	if (over) {
+		over = (typeof over.id != 'string') ? o3_frame.document.all['overDiv'] : over;
+		cClick();
+	}
+
+	// Load defaults to runtime.
+  olHideDelay=0;
+	o3_text=ol_text;
+	o3_cap=ol_cap;
+	o3_sticky=ol_sticky;
+	o3_background=ol_background;
+	o3_close=ol_close;
+	o3_hpos=ol_hpos;
+	o3_offsetx=ol_offsetx;
+	o3_offsety=ol_offsety;
+	o3_fgcolor=ol_fgcolor;
+	o3_bgcolor=ol_bgcolor;
+	o3_textcolor=ol_textcolor;
+	o3_capcolor=ol_capcolor;
+	o3_closecolor=ol_closecolor;
+	o3_width=ol_width;
+	o3_border=ol_border;
+	o3_cellpad=ol_cellpad;
+	o3_status=ol_status;
+	o3_autostatus=ol_autostatus;
+	o3_height=ol_height;
+	o3_snapx=ol_snapx;
+	o3_snapy=ol_snapy;
+	o3_fixx=ol_fixx;
+	o3_fixy=ol_fixy;
+	o3_relx=ol_relx;
+	o3_rely=ol_rely;
+	o3_fgbackground=ol_fgbackground;
+	o3_bgbackground=ol_bgbackground;
+	o3_padxl=ol_padxl;
+	o3_padxr=ol_padxr;
+	o3_padyt=ol_padyt;
+	o3_padyb=ol_padyb;
+	o3_fullhtml=ol_fullhtml;
+	o3_vpos=ol_vpos;
+	o3_aboveheight=ol_aboveheight;
+	o3_capicon=ol_capicon;
+	o3_textfont=ol_textfont;
+	o3_captionfont=ol_captionfont;
+	o3_closefont=ol_closefont;
+	o3_textsize=ol_textsize;
+	o3_captionsize=ol_captionsize;
+	o3_closesize=ol_closesize;
+	o3_timeout=ol_timeout;
+	o3_function=ol_function;
+	o3_delay=ol_delay;
+	o3_hauto=ol_hauto;
+	o3_vauto=ol_vauto;
+	o3_closeclick=ol_closeclick;
+	o3_wrap=ol_wrap;	
+	o3_followmouse=ol_followmouse;
+	o3_mouseoff=ol_mouseoff;
+	o3_closetitle=ol_closetitle;
+	o3_css=ol_css;
+	o3_compatmode=ol_compatmode;
+	o3_fgclass=ol_fgclass;
+	o3_bgclass=ol_bgclass;
+	o3_textfontclass=ol_textfontclass;
+	o3_captionfontclass=ol_captionfontclass;
+	o3_closefontclass=ol_closefontclass;
+	
+	setRunTimeVariables();
+	
+	fnRef = '';
+	
+	// Special for frame support, over must be reset...
+	o3_frame = ol_frame;
+	
+	if(!(over=createDivContainer())) return false;
+
+	parseTokens('o3_', overlib.arguments);
+	if (!postParseChecks()) return false;
+
+	if (o3_delay == 0) {
+		return runHook("olMain", FREPLACE);
+ 	} else {
+		o3_delayid = setTimeout("runHook('olMain', FREPLACE)", o3_delay);
+		return false;
+	}
+}
+
+// Clears popups if appropriate
+function nd(time) {
+	if (olLoaded && !isExclusive()) {
+		hideDelay(time);  // delay popup close if time specified
+
+		if (o3_removecounter >= 1) { o3_showingsticky = 0 };
+		
+		if (o3_showingsticky == 0) {
+			o3_allowmove = 0;
+			if (over != null && o3_timerid == 0) runHook("hideObject", FREPLACE, over);
+		} else {
+			o3_removecounter++;
+		}
+	}
+	
+	return true;
+}
+
+// The Close onMouseOver function for stickies
+function cClick() {
+	if (olLoaded) {
+		runHook("hideObject", FREPLACE, over);
+		o3_showingsticky = 0;	
+	}	
+	return false;
+}
+
+// Method for setting page specific defaults.
+function overlib_pagedefaults() {
+	parseTokens('ol_', overlib_pagedefaults.arguments);
+}
+
+
+////////
+// OVERLIB MAIN FUNCTION
+////////
+
+// This function decides what it is we want to display and how we want it done.
+function olMain() {
+	var layerhtml, styleType;
+ 	runHook("olMain", FBEFORE);
+ 	
+	if (o3_background!="" || o3_fullhtml) {
+		// Use background instead of box.
+		layerhtml = runHook('ol_content_background', FALTERNATE, o3_css, o3_text, o3_background, o3_fullhtml);
+	} else {
+		// They want a popup box.
+		styleType = (pms[o3_css-1-pmStart] == "cssoff" || pms[o3_css-1-pmStart] == "cssclass");
+
+		// Prepare popup background
+		if (o3_fgbackground != "") o3_fgbackground = "background=\""+o3_fgbackground+"\"";
+		if (o3_bgbackground != "") o3_bgbackground = (styleType ? "background=\""+o3_bgbackground+"\"" : o3_bgbackground);
+
+		// Prepare popup colors
+		if (o3_fgcolor != "") o3_fgcolor = (styleType ? "bgcolor=\""+o3_fgcolor+"\"" : o3_fgcolor);
+		if (o3_bgcolor != "") o3_bgcolor = (styleType ? "bgcolor=\""+o3_bgcolor+"\"" : o3_bgcolor);
+
+		// Prepare popup height
+		if (o3_height > 0) o3_height = (styleType ? "height=\""+o3_height+"\"" : o3_height);
+		else o3_height = "";
+
+		// Decide which kinda box.
+		if (o3_cap=="") {
+			// Plain
+			layerhtml = runHook('ol_content_simple', FALTERNATE, o3_css, o3_text);
+		} else {
+			// With caption
+			if (o3_sticky) {
+				// Show close text
+				layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, o3_close);
+			} else {
+				// No close text
+				layerhtml = runHook('ol_content_caption', FALTERNATE, o3_css, o3_text, o3_cap, "");
+			}
+		}
+	}	
+
+	// We want it to stick!
+	if (o3_sticky) {
+		if (o3_timerid > 0) {
+			clearTimeout(o3_timerid);
+			o3_timerid = 0;
+		}
+		o3_showingsticky = 1;
+		o3_removecounter = 0;
+	}
+
+	// Created a separate routine to generate the popup to make it easier
+	// to implement a plugin capability
+	if (!runHook("createPopup", FREPLACE, layerhtml)) return false;
+
+	// Prepare status bar
+	if (o3_autostatus > 0) {
+		o3_status = o3_text;
+		if (o3_autostatus > 1) o3_status = o3_cap;
+	}
+
+	// When placing the layer the first time, even stickies may be moved.
+	o3_allowmove = 0;
+
+	// Initiate a timer for timeout
+	if (o3_timeout > 0) {          
+		if (o3_timerid > 0) clearTimeout(o3_timerid);
+		o3_timerid = setTimeout("cClick()", o3_timeout);
+	}
+
+	// Show layer
+	runHook("disp", FREPLACE, o3_status);
+	runHook("olMain", FAFTER);
+
+	return (olOp && event && event.type == 'mouseover' && !o3_status) ? '' : (o3_status != '');
+}
+
+////////
+// LAYER GENERATION FUNCTIONS
+////////
+// These functions just handle popup content with tags that should adhere to the W3C standards specification.
+
+// Makes simple table without caption
+function ol_content_simple(text) {
+	var cpIsMultiple = /,/.test(o3_cellpad);
+	var txt = '<table width="'+o3_width+ '" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass ? 'class="'+o3_bgclass+'"' : o3_bgcolor+' '+o3_height)+'><tr><td><table width="100%" border="0" '+((olNs4||!cpIsMultiple) ? 'cellpadding="'+o3_cellpad+'" ' : '')+'cellspacing="0" '+(o3_fgclass ? 'class="'+o3_fgclass+'"' : o3_fgcolor+' '+o3_fgbackground+' '+o3_height)+'><tr><td valign="TOP"'+(o3_textfontclass ? ' class="'+o3_textfontclass+'">' : ((!olNs4&&cpIsMultiple) ? ' style=" [...]
+
+	set_background("");
+	return txt;
+}
+
+// Makes table with caption and optional close link
+function ol_content_caption(text,title,close) {
+	var nameId, txt, cpIsMultiple = /,/.test(o3_cellpad);
+	var closing, closeevent;
+
+	closing = "";
+	closeevent = "onmouseover";
+	if (o3_closeclick == 1) closeevent = (o3_closetitle ? "title='" + o3_closetitle +"'" : "") + " onclick";
+	if (o3_capicon != "") {
+	  nameId = ' hspace = \"5\"'+' align = \"middle\" alt = \"\"';
+	  if (typeof o3_dragimg != 'undefined' && o3_dragimg) nameId =' hspace=\"5\"'+' name=\"'+o3_dragimg+'\" id=\"'+o3_dragimg+'\" align=\"middle\" alt=\"Drag Enabled\" title=\"Drag Enabled\"';
+	  o3_capicon = '<img src=\"'+o3_capicon+'\"'+nameId+' />';
+	}
+
+	if (close != "")
+		closing = '<td '+(!o3_compatmode && o3_closefontclass ? 'class="'+o3_closefontclass : 'align="RIGHT')+'"><a href="javascript:return '+fnRef+'cClick();"'+((o3_compatmode && o3_closefontclass) ? ' class="' + o3_closefontclass + '" ' : ' ')+closeevent+'="return '+fnRef+'cClick();">'+(o3_closefontclass ? '' : wrapStr(0,o3_closesize,'close'))+close+(o3_closefontclass ? '' : wrapStr(1,o3_closesize,'close'))+'</a></td>';
+	txt = '<table width="'+o3_width+ '" border="0" cellpadding="'+o3_border+'" cellspacing="0" '+(o3_bgclass ? 'class="'+o3_bgclass+'"' : o3_bgcolor+' '+o3_bgbackground+' '+o3_height)+'><tr><td><table width="100%" border="0" cellpadding="2" cellspacing="0"><tr><td'+(o3_captionfontclass ? ' class="'+o3_captionfontclass+'">' : '>')+(o3_captionfontclass ? '' : '<b>'+wrapStr(0,o3_captionsize,'caption'))+o3_capicon+title+(o3_captionfontclass ? '' : wrapStr(1,o3_captionsize)+'</b>')+'</td>'+closi [...]
+
+	set_background("");
+	return txt;
+}
+
+// Sets the background picture,padding and lots more. :)
+function ol_content_background(text,picture,hasfullhtml) {
+	if (hasfullhtml) {
+		txt=text;
+	} else {
+		txt='<table width="'+o3_width+'" border="0" cellpadding="0" cellspacing="0" height="'+o3_height+'"><tr><td colspan="3" height="'+o3_padyt+'"></td></tr><tr><td width="'+o3_padxl+'"></td><td valign="TOP" width="'+(o3_width-o3_padxl-o3_padxr)+(o3_textfontclass ? '" class="'+o3_textfontclass : '')+'">'+(o3_textfontclass ? '' : wrapStr(0,o3_textsize,'text'))+text+(o3_textfontclass ? '' : wrapStr(1,o3_textsize))+'</td><td width="'+o3_padxr+'"></td></tr><tr><td colspan="3" height="'+o3_padyb+ [...]
+	}
+
+	set_background(picture);
+	return txt;
+}
+
+// Loads a picture into the div.
+function set_background(pic) {
+	if (pic == "") {
+		if (olNs4) {
+			over.background.src = null; 
+		} else if (over.style) {
+			over.style.backgroundImage = "none";
+		}
+	} else {
+		if (olNs4) {
+			over.background.src = pic;
+		} else if (over.style) {
+			over.style.width=o3_width + 'px';
+			over.style.backgroundImage = "url("+pic+")";
+		}
+	}
+}
+
+////////
+// HANDLING FUNCTIONS
+////////
+var olShowId=-1;
+
+// Displays the popup
+function disp(statustext) {
+	runHook("disp", FBEFORE);
+	
+	if (o3_allowmove == 0) {
+		runHook("placeLayer", FREPLACE);
+		(olNs6&&olShowId<0) ? olShowId=setTimeout("runHook('showObject', FREPLACE, over)", 1) : runHook("showObject", FREPLACE, over);
+		o3_allowmove = (o3_sticky || o3_followmouse==0) ? 0 : 1;
+	}
+	
+	runHook("disp", FAFTER);
+
+	if (statustext != "") self.status = statustext;
+}
+
+// Creates the actual popup structure
+function createPopup(lyrContent){
+	runHook("createPopup", FBEFORE);
+	
+	if (o3_wrap) {
+		var wd,ww,theObj = (olNs4 ? over : over.style);
+		theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);
+		layerWrite(lyrContent);
+		wd = (olNs4 ? over.clip.width : over.offsetWidth);
+		if (wd > (ww=windowWidth())) {
+			lyrContent=lyrContent.replace(/\ /g, ' ');
+			o3_width=ww;
+			o3_wrap=0;
+		} 
+	}
+
+	layerWrite(lyrContent);
+	
+	// Have to set o3_width for placeLayer() routine if o3_wrap is turned on
+	if (o3_wrap) o3_width=(olNs4 ? over.clip.width : over.offsetWidth);
+	
+	runHook("createPopup", FAFTER, lyrContent);
+
+	return true;
+}
+
+// Decides where we want the popup.
+function placeLayer() {
+	var placeX, placeY, widthFix = 0;
+	
+	// HORIZONTAL PLACEMENT, re-arranged to work in Safari
+	if (o3_frame.innerWidth) widthFix=18; 
+	iwidth = windowWidth();
+
+	// Horizontal scroll offset
+	winoffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollLeft') : o3_frame.pageXOffset;
+
+	placeX = runHook('horizontalPlacement',FCHAIN,iwidth,winoffset,widthFix);
+
+	// VERTICAL PLACEMENT, re-arranged to work in Safari
+	if (o3_frame.innerHeight) {
+		iheight=o3_frame.innerHeight;
+	} else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientHeight=='number'")&&eval('o3_frame.'+docRoot+'.clientHeight')) { 
+		iheight=eval('o3_frame.'+docRoot+'.clientHeight');
+	}			
+
+	// Vertical scroll offset
+	scrolloffset=(olIe4) ? eval('o3_frame.'+docRoot+'.scrollTop') : o3_frame.pageYOffset;
+	placeY = runHook('verticalPlacement',FCHAIN,iheight,scrolloffset);
+
+	// Actually move the object.
+	repositionTo(over, placeX, placeY);
+}
+
+// Moves the layer
+function olMouseMove(e) {
+	var e = (e) ? e : event;
+
+	if (e.pageX) {
+		o3_x = e.pageX;
+		o3_y = e.pageY;
+	} else if (e.clientX) {
+		o3_x = eval('e.clientX+o3_frame.'+docRoot+'.scrollLeft');
+		o3_y = eval('e.clientY+o3_frame.'+docRoot+'.scrollTop');
+	}
+	
+	if (o3_allowmove == 1) runHook("placeLayer", FREPLACE);
+
+	// MouseOut handler
+	if (hoveringSwitch && !olNs4 && runHook("cursorOff", FREPLACE)) {
+		(olHideDelay ? hideDelay(olHideDelay) : cClick());
+		hoveringSwitch = !hoveringSwitch;
+	}
+}
+
+// Fake function for 3.0 users.
+function no_overlib() { return ver3fix; }
+
+// Capture the mouse and chain other scripts.
+function olMouseCapture() {
+	capExtent = document;
+	var fN, str = '', l, k, f, wMv, sS, mseHandler = olMouseMove;
+	var re = /function[ ]*(\w*)\(/;
+	
+	wMv = (!olIe4 && window.onmousemove);
+	if (document.onmousemove || wMv) {
+		if (wMv) capExtent = window;
+		f = capExtent.onmousemove.toString();
+		fN = f.match(re);
+		if (fN == null) {
+			str = f+'(e); ';
+		} else if (fN[1] == 'anonymous' || fN[1] == 'olMouseMove' || (wMv && fN[1] == 'onmousemove')) {
+			if (!olOp && wMv) {
+				l = f.indexOf('{')+1;
+				k = f.lastIndexOf('}');
+				sS = f.substring(l,k);
+				if ((l = sS.indexOf('(')) != -1) {
+					sS = sS.substring(0,l).replace(/^\s+/,'').replace(/\s+$/,'');
+					if (eval("typeof " + sS + " == 'undefined'")) window.onmousemove = null;
+					else str = sS + '(e);';
+				}
+			}
+			if (!str) {
+				olCheckMouseCapture = false;
+				return;
+			}
+		} else {
+			if (fN[1]) str = fN[1]+'(e); ';
+			else {
+				l = f.indexOf('{')+1;
+				k = f.lastIndexOf('}');
+				str = f.substring(l,k) + '\n';
+			}
+		}
+		str += 'olMouseMove(e); ';
+		mseHandler = new Function('e', str);
+	}
+
+	capExtent.onmousemove = mseHandler;
+	if (olNs4) capExtent.captureEvents(Event.MOUSEMOVE);
+}
+
+////////
+// PARSING FUNCTIONS
+////////
+
+// Does the actual command parsing.
+function parseTokens(pf, ar) {
+	// What the next argument is expected to be.
+	var v, i, mode=-1, par = (pf != 'ol_');	
+	var fnMark = (par && !ar.length ? 1 : 0);
+
+	for (i = 0; i < ar.length; i++) {
+		if (mode < 0) {
+			// Arg is maintext,unless its a number between pmStart and pmUpper
+			// then its a command.
+			if (typeof ar[i] == 'number' && ar[i] > pmStart && ar[i] < pmUpper) {
+				fnMark = (par ? 1 : 0);
+				i--;   // backup one so that the next block can parse it
+			} else {
+				switch(pf) {
+					case 'ol_':
+						ol_text = ar[i].toString();
+						break;
+					default:
+						o3_text=ar[i].toString();  
+				}
+			}
+			mode = 0;
+		} else {
+			// Note: NS4 doesn't like switch cases with vars.
+			if (ar[i] >= pmCount || ar[i]==DONOTHING) { continue; }
+			if (ar[i]==INARRAY) { fnMark = 0; eval(pf+'text=ol_texts['+ar[++i]+'].toString()'); continue; }
+			if (ar[i]==CAPARRAY) { eval(pf+'cap=ol_caps['+ar[++i]+'].toString()'); continue; }
+			if (ar[i]==STICKY) { if (pf!='ol_') eval(pf+'sticky=1'); continue; }
+			if (ar[i]==BACKGROUND) { eval(pf+'background="'+ar[++i]+'"'); continue; }
+			if (ar[i]==NOCLOSE) { if (pf!='ol_') opt_NOCLOSE(); continue; }
+			if (ar[i]==CAPTION) { eval(pf+"cap='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CENTER || ar[i]==LEFT || ar[i]==RIGHT) { eval(pf+'hpos='+ar[i]); if(pf!='ol_') olHautoFlag=1; continue; }
+			if (ar[i]==OFFSETX) { eval(pf+'offsetx='+ar[++i]); continue; }
+			if (ar[i]==OFFSETY) { eval(pf+'offsety='+ar[++i]); continue; }
+			if (ar[i]==FGCOLOR) { eval(pf+'fgcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==BGCOLOR) { eval(pf+'bgcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TEXTCOLOR) { eval(pf+'textcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CAPCOLOR) { eval(pf+'capcolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CLOSECOLOR) { eval(pf+'closecolor="'+ar[++i]+'"'); continue; }
+			if (ar[i]==WIDTH) { eval(pf+'width='+ar[++i]); continue; }
+			if (ar[i]==BORDER) { eval(pf+'border='+ar[++i]); continue; }
+			if (ar[i]==CELLPAD) { i=opt_MULTIPLEARGS(++i,ar,(pf+'cellpad')); continue; }
+			if (ar[i]==STATUS) { eval(pf+"status='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==AUTOSTATUS) { eval(pf +'autostatus=('+pf+'autostatus == 1) ? 0 : 1'); continue; }
+			if (ar[i]==AUTOSTATUSCAP) { eval(pf +'autostatus=('+pf+'autostatus == 2) ? 0 : 2'); continue; }
+			if (ar[i]==HEIGHT) { eval(pf+'height='+pf+'aboveheight='+ar[++i]); continue; } // Same param again.
+			if (ar[i]==CLOSETEXT) { eval(pf+"close='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==SNAPX) { eval(pf+'snapx='+ar[++i]); continue; }
+			if (ar[i]==SNAPY) { eval(pf+'snapy='+ar[++i]); continue; }
+			if (ar[i]==FIXX) { eval(pf+'fixx='+ar[++i]); continue; }
+			if (ar[i]==FIXY) { eval(pf+'fixy='+ar[++i]); continue; }
+			if (ar[i]==RELX) { eval(pf+'relx='+ar[++i]); continue; }
+			if (ar[i]==RELY) { eval(pf+'rely='+ar[++i]); continue; }
+			if (ar[i]==FGBACKGROUND) { eval(pf+'fgbackground="'+ar[++i]+'"'); continue; }
+			if (ar[i]==BGBACKGROUND) { eval(pf+'bgbackground="'+ar[++i]+'"'); continue; }
+			if (ar[i]==PADX) { eval(pf+'padxl='+ar[++i]); eval(pf+'padxr='+ar[++i]); continue; }
+			if (ar[i]==PADY) { eval(pf+'padyt='+ar[++i]); eval(pf+'padyb='+ar[++i]); continue; }
+			if (ar[i]==FULLHTML) { if (pf!='ol_') eval(pf+'fullhtml=1'); continue; }
+			if (ar[i]==BELOW || ar[i]==ABOVE) { eval(pf+'vpos='+ar[i]); if (pf!='ol_') olVautoFlag=1; continue; }
+			if (ar[i]==CAPICON) { eval(pf+'capicon="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TEXTFONT) { eval(pf+"textfont='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CAPTIONFONT) { eval(pf+"captionfont='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CLOSEFONT) { eval(pf+"closefont='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==TEXTSIZE) { eval(pf+'textsize="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CAPTIONSIZE) { eval(pf+'captionsize="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CLOSESIZE) { eval(pf+'closesize="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TIMEOUT) { eval(pf+'timeout='+ar[++i]); continue; }
+			if (ar[i]==FUNCTION) { if (pf=='ol_') { if (typeof ar[i+1]!='number') { v=ar[++i]; ol_function=(typeof v=='function' ? v : null); }} else {fnMark = 0; v = null; if (typeof ar[i+1]!='number') v = ar[++i];  opt_FUNCTION(v); } continue; }
+			if (ar[i]==DELAY) { eval(pf+'delay='+ar[++i]); continue; }
+			if (ar[i]==HAUTO) { eval(pf+'hauto=('+pf+'hauto == 0) ? 1 : 0'); continue; }
+			if (ar[i]==VAUTO) { eval(pf+'vauto=('+pf+'vauto == 0) ? 1 : 0'); continue; }
+			if (ar[i]==CLOSECLICK) { eval(pf +'closeclick=('+pf+'closeclick == 0) ? 1 : 0'); continue; }
+			if (ar[i]==WRAP) { eval(pf +'wrap=('+pf+'wrap == 0) ? 1 : 0'); continue; }
+			if (ar[i]==FOLLOWMOUSE) { eval(pf +'followmouse=('+pf+'followmouse == 1) ? 0 : 1'); continue; }
+			if (ar[i]==MOUSEOFF) { eval(pf +'mouseoff=('+pf+'mouseoff==0) ? 1 : 0'); v=ar[i+1]; if (pf != 'ol_' && eval(pf+'mouseoff') && typeof v == 'number' && (v < pmStart || v > pmUpper)) olHideDelay=ar[++i]; continue; }
+			if (ar[i]==CLOSETITLE) { eval(pf+"closetitle='"+escSglQuote(ar[++i])+"'"); continue; }
+			if (ar[i]==CSSOFF||ar[i]==CSSCLASS) { eval(pf+'css='+ar[i]); continue; }
+			if (ar[i]==COMPATMODE) { eval(pf+'compatmode=('+pf+'compatmode==0) ? 1 : 0'); continue; }
+			if (ar[i]==FGCLASS) { eval(pf+'fgclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==BGCLASS) { eval(pf+'bgclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==TEXTFONTCLASS) { eval(pf+'textfontclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CAPTIONFONTCLASS) { eval(pf+'captionfontclass="'+ar[++i]+'"'); continue; }
+			if (ar[i]==CLOSEFONTCLASS) { eval(pf+'closefontclass="'+ar[++i]+'"'); continue; }
+			i = parseCmdLine(pf, i, ar);
+		}
+	}
+
+	if (fnMark && o3_function) o3_text = o3_function();
+	
+	if ((pf == 'o3_') && o3_wrap) {
+		o3_width = 0;
+		
+		var tReg=/<.*\n*>/ig;
+		if (!tReg.test(o3_text)) o3_text = o3_text.replace(/[ ]+/g, ' ');
+		if (!tReg.test(o3_cap))o3_cap = o3_cap.replace(/[ ]+/g, ' ');
+	}
+	if ((pf == 'o3_') && o3_sticky) {
+		if (!o3_close && (o3_frame != ol_frame)) o3_close = ol_close;
+		if (o3_mouseoff && (o3_frame == ol_frame)) opt_NOCLOSE(' ');
+	}
+}
+
+
+////////
+// LAYER FUNCTIONS
+////////
+
+// Writes to a layer
+function layerWrite(txt) {
+	txt += "\n";
+	if (olNs4) {
+		var lyr = o3_frame.document.layers['overDiv'].document
+		lyr.write(txt)
+		lyr.close()
+	} else if (typeof over.innerHTML != 'undefined') {
+		if (olIe5 && isMac) over.innerHTML = '';
+		over.innerHTML = txt;
+	} else {
+		range = o3_frame.document.createRange();
+		range.setStartAfter(over);
+		domfrag = range.createContextualFragment(txt);
+		
+		while (over.hasChildNodes()) {
+			over.removeChild(over.lastChild);
+		}
+		
+		over.appendChild(domfrag);
+	}
+}
+
+// Make an object visible
+function showObject(obj) {
+	runHook("showObject", FBEFORE);
+
+	var theObj=(olNs4 ? obj : obj.style);
+	theObj.visibility = 'visible';
+
+	runHook("showObject", FAFTER);
+}
+
+// Hides an object
+function hideObject(obj) {
+	runHook("hideObject", FBEFORE);
+
+	var theObj=(olNs4 ? obj : obj.style);
+	if (olNs6 && olShowId>0) { clearTimeout(olShowId); olShowId=0; }
+	theObj.visibility = 'hidden';
+	theObj.top = theObj.left = ((olIe4&&!olOp) ? 0 : -10000) + (!olNs4 ? 'px' : 0);
+
+	if (o3_timerid > 0) clearTimeout(o3_timerid);
+	if (o3_delayid > 0) clearTimeout(o3_delayid);
+
+	o3_timerid = 0;
+	o3_delayid = 0;
+	self.status = "";
+
+	if (obj.onmouseout||obj.onmouseover) {
+		if (olNs4) obj.releaseEvents(Event.MOUSEOUT || Event.MOUSEOVER);
+		obj.onmouseout = obj.onmouseover = null;
+	}
+
+	runHook("hideObject", FAFTER);
+}
+
+// Move a layer
+function repositionTo(obj, xL, yL) {
+	var theObj=(olNs4 ? obj : obj.style);
+	theObj.left = xL + (!olNs4 ? 'px' : 0);
+	theObj.top = yL + (!olNs4 ? 'px' : 0);
+}
+
+// Check position of cursor relative to overDiv DIVision; mouseOut function
+function cursorOff() {
+	var left = parseInt(over.style.left);
+	var top = parseInt(over.style.top);
+	var right = left + (over.offsetWidth >= parseInt(o3_width) ? over.offsetWidth : parseInt(o3_width));
+	var bottom = top + (over.offsetHeight >= o3_aboveheight ? over.offsetHeight : o3_aboveheight);
+
+	if (o3_x < left || o3_x > right || o3_y < top || o3_y > bottom) return true;
+
+	return false;
+}
+
+
+////////
+// COMMAND FUNCTIONS
+////////
+
+// Calls callme or the default function.
+function opt_FUNCTION(callme) {
+	o3_text = (callme ? (typeof callme=='string' ? (/.+\(.*\)/.test(callme) ? eval(callme) : callme) : callme()) : (o3_function ? o3_function() : 'No Function'));
+
+	return 0;
+}
+
+// Handle hovering
+function opt_NOCLOSE(unused) {
+	if (!unused) o3_close = "";
+
+	if (olNs4) {
+		over.captureEvents(Event.MOUSEOUT || Event.MOUSEOVER);
+		over.onmouseover = function () { if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid = 0; } }
+		over.onmouseout = function (e) { if (olHideDelay) hideDelay(olHideDelay); else cClick(e); }
+	} else {
+		over.onmouseover = function () {hoveringSwitch = true; if (o3_timerid > 0) { clearTimeout(o3_timerid); o3_timerid =0; } }
+	}
+
+	return 0;
+}
+
+// Function to scan command line arguments for multiples
+function opt_MULTIPLEARGS(i, args, parameter) {
+  var k=i, re, pV, str='';
+
+  for(k=i; k<args.length; k++) {
+		if(typeof args[k] == 'number' && args[k]>pmStart) break;
+		str += args[k] + ',';
+	}
+	if (str) str = str.substring(0,--str.length);
+
+	k--;  // reduce by one so the for loop this is in works correctly
+	pV=(olNs4 && /cellpad/i.test(parameter)) ? str.split(',')[0] : str;
+	eval(parameter + '="' + pV + '"');
+
+	return k;
+}
+
+// Remove   in texts when done.
+function nbspCleanup() {
+	if (o3_wrap) {
+		o3_text = o3_text.replace(/\ /g, ' ');
+		o3_cap = o3_cap.replace(/\ /g, ' ');
+	}
+}
+
+// Escape embedded single quotes in text strings
+function escSglQuote(str) {
+  return str.toString().replace(/'/g,"\\'");
+}
+
+// Onload handler for window onload event
+function OLonLoad_handler(e) {
+	var re = /\w+\(.*\)[;\s]+/g, olre = /overlib\(|nd\(|cClick\(/, fn, l, i;
+
+	if(!olLoaded) olLoaded=1;
+
+  // Remove it for Gecko based browsers
+	if(window.removeEventListener && e.eventPhase == 3) window.removeEventListener("load",OLonLoad_handler,false);
+	else if(window.detachEvent) { // and for IE and Opera 4.x but execute calls to overlib, nd, or cClick()
+		window.detachEvent("onload",OLonLoad_handler);
+		var fN = document.body.getAttribute('onload');
+		if (fN) {
+			fN=fN.toString().match(re);
+			if (fN && fN.length) {
+				for (i=0; i<fN.length; i++) {
+					if (/anonymous/.test(fN[i])) continue;
+					while((l=fN[i].search(/\)[;\s]+/)) != -1) {
+						fn=fN[i].substring(0,l+1);
+						fN[i] = fN[i].substring(l+2);
+						if (olre.test(fn)) eval(fn);
+					}
+				}
+			}
+		}
+	}
+}
+
+// Wraps strings in Layer Generation Functions with the correct tags
+//    endWrap true(if end tag) or false if start tag
+//    fontSizeStr - font size string such as '1' or '10px'
+//    whichString is being wrapped -- 'text', 'caption', or 'close'
+function wrapStr(endWrap,fontSizeStr,whichString) {
+	var fontStr, fontColor, isClose=((whichString=='close') ? 1 : 0), hasDims=/[%\-a-z]+$/.test(fontSizeStr);
+	fontSizeStr = (olNs4) ? (!hasDims ? fontSizeStr : '1') : fontSizeStr;
+	if (endWrap) return (hasDims&&!olNs4) ? (isClose ? '</span>' : '</div>') : '</font>';
+	else {
+		fontStr='o3_'+whichString+'font';
+		fontColor='o3_'+((whichString=='caption')? 'cap' : whichString)+'color';
+		return (hasDims&&!olNs4) ? (isClose ? '<span style="font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';">' : '<div style="font-family: '+quoteMultiNameFonts(eval(fontStr))+'; color: '+eval(fontColor)+'; font-size: '+fontSizeStr+';">') : '<font face="'+eval(fontStr)+'" color="'+eval(fontColor)+'" size="'+(parseInt(fontSizeStr)>7 ? '7' : fontSizeStr)+'">';
+	}
+}
+
+// Quotes Multi word font names; needed for CSS Standards adherence in font-family
+function quoteMultiNameFonts(theFont) {
+	var v, pM=theFont.split(',');
+	for (var i=0; i<pM.length; i++) {
+		v=pM[i];
+		v=v.replace(/^\s+/,'').replace(/\s+$/,'');
+		if(/\s/.test(v) && !/['"]/.test(v)) {
+			v="\'"+v+"\'";
+			pM[i]=v;
+		}
+	}
+	return pM.join();
+}
+
+// dummy function which will be overridden 
+function isExclusive(args) {
+	return false;
+}
+
+// Sets cellpadding style string value
+function setCellPadStr(parameter) {
+	var Str='', j=0, ary = new Array(), top, bottom, left, right;
+
+	Str+='padding: ';
+	ary=parameter.replace(/\s+/g,'').split(',');
+
+	switch(ary.length) {
+		case 2:
+			top=bottom=ary[j];
+			left=right=ary[++j];
+			break;
+		case 3:
+			top=ary[j];
+			left=right=ary[++j];
+			bottom=ary[++j];
+			break;
+		case 4:
+			top=ary[j];
+			right=ary[++j];
+			bottom=ary[++j];
+			left=ary[++j];
+			break;
+	}
+
+	Str+= ((ary.length==1) ? ary[0] + 'px;' : top + 'px ' + right + 'px ' + bottom + 'px ' + left + 'px;');
+
+	return Str;
+}
+
+// function will delay close by time milliseconds
+function hideDelay(time) {
+	if (time&&!o3_delay) {
+		if (o3_timerid > 0) clearTimeout(o3_timerid);
+
+		o3_timerid=setTimeout("cClick()",(o3_timeout=time));
+	}
+}
+
+// Was originally in the placeLayer() routine; separated out for future ease
+function horizontalPlacement(browserWidth, horizontalScrollAmount, widthFix) {
+	var placeX, iwidth=browserWidth, winoffset=horizontalScrollAmount;
+	var parsedWidth = parseInt(o3_width);
+
+	if (o3_fixx > -1 || o3_relx != null) {
+		// Fixed position
+		placeX=(o3_relx != null ? ( o3_relx < 0 ? winoffset +o3_relx+ iwidth - parsedWidth - widthFix : winoffset+o3_relx) : o3_fixx);
+	} else {  
+		// If HAUTO, decide what to use.
+		if (o3_hauto == 1) {
+			if ((o3_x - winoffset) > (iwidth / 2)) {
+				o3_hpos = LEFT;
+			} else {
+				o3_hpos = RIGHT;
+			}
+		}  		
+
+		// From mouse
+		if (o3_hpos == CENTER) { // Center
+			placeX = o3_x+o3_offsetx-(parsedWidth/2);
+
+			if (placeX < winoffset) placeX = winoffset;
+		}
+
+		if (o3_hpos == RIGHT) { // Right
+			placeX = o3_x+o3_offsetx;
+
+			if ((placeX+parsedWidth) > (winoffset+iwidth - widthFix)) {
+				placeX = iwidth+winoffset - parsedWidth - widthFix;
+				if (placeX < 0) placeX = 0;
+			}
+		}
+		if (o3_hpos == LEFT) { // Left
+			placeX = o3_x-o3_offsetx-parsedWidth;
+			if (placeX < winoffset) placeX = winoffset;
+		}  	
+
+		// Snapping!
+		if (o3_snapx > 1) {
+			var snapping = placeX % o3_snapx;
+
+			if (o3_hpos == LEFT) {
+				placeX = placeX - (o3_snapx+snapping);
+			} else {
+				// CENTER and RIGHT
+				placeX = placeX+(o3_snapx - snapping);
+			}
+
+			if (placeX < winoffset) placeX = winoffset;
+		}
+	}	
+
+	return placeX;
+}
+
+// was originally in the placeLayer() routine; separated out for future ease
+function verticalPlacement(browserHeight,verticalScrollAmount) {
+	var placeY, iheight=browserHeight, scrolloffset=verticalScrollAmount;
+	var parsedHeight=(o3_aboveheight ? parseInt(o3_aboveheight) : (olNs4 ? over.clip.height : over.offsetHeight));
+
+	if (o3_fixy > -1 || o3_rely != null) {
+		// Fixed position
+		placeY=(o3_rely != null ? (o3_rely < 0 ? scrolloffset+o3_rely+iheight - parsedHeight : scrolloffset+o3_rely) : o3_fixy);
+	} else {
+		// If VAUTO, decide what to use.
+		if (o3_vauto == 1) {
+			if ((o3_y - scrolloffset) > (iheight / 2) && o3_vpos == BELOW && (o3_y + parsedHeight + o3_offsety - (scrolloffset + iheight) > 0)) {
+				o3_vpos = ABOVE;
+			} else if (o3_vpos == ABOVE && (o3_y - (parsedHeight + o3_offsety) - scrolloffset < 0)) {
+				o3_vpos = BELOW;
+			}
+		}
+
+		// From mouse
+		if (o3_vpos == ABOVE) {
+			if (o3_aboveheight == 0) o3_aboveheight = parsedHeight; 
+
+			placeY = o3_y - (o3_aboveheight+o3_offsety);
+			if (placeY < scrolloffset) placeY = scrolloffset;
+		} else {
+			// BELOW
+			placeY = o3_y+o3_offsety;
+		} 
+
+		// Snapping!
+		if (o3_snapy > 1) {
+			var snapping = placeY % o3_snapy;  			
+
+			if (o3_aboveheight > 0 && o3_vpos == ABOVE) {
+				placeY = placeY - (o3_snapy+snapping);
+			} else {
+				placeY = placeY+(o3_snapy - snapping);
+			} 			
+
+			if (placeY < scrolloffset) placeY = scrolloffset;
+		}
+	}
+
+	return placeY;
+}
+
+// checks positioning flags
+function checkPositionFlags() {
+	if (olHautoFlag) olHautoFlag = o3_hauto=0;
+	if (olVautoFlag) olVautoFlag = o3_vauto=0;
+	return true;
+}
+
+// get Browser window width
+function windowWidth() {
+	var w;
+	if (o3_frame.innerWidth) w=o3_frame.innerWidth;
+	else if (eval('o3_frame.'+docRoot)&&eval("typeof o3_frame."+docRoot+".clientWidth=='number'")&&eval('o3_frame.'+docRoot+'.clientWidth')) 
+		w=eval('o3_frame.'+docRoot+'.clientWidth');
+	return w;			
+}
+
+// create the div container for popup content if it doesn't exist
+function createDivContainer(id,frm,zValue) {
+	id = (id || 'overDiv'), frm = (frm || o3_frame), zValue = (zValue || 1000);
+	var objRef, divContainer = layerReference(id);
+
+	if (divContainer == null) {
+		if (olNs4) {
+			divContainer = frm.document.layers[id] = new Layer(window.innerWidth, frm);
+			objRef = divContainer;
+		} else {
+			var body = (olIe4 ? frm.document.all.tags('BODY')[0] : frm.document.getElementsByTagName("BODY")[0]);
+			if (olIe4&&!document.getElementById) {
+				body.insertAdjacentHTML("beforeEnd",'<div id="'+id+'"></div>');
+				divContainer=layerReference(id);
+			} else {
+				divContainer = frm.document.createElement("DIV");
+				divContainer.id = id;
+				body.appendChild(divContainer);
+			}
+			objRef = divContainer.style;
+		}
+
+		objRef.position = 'absolute';
+		objRef.visibility = 'hidden';
+		objRef.zIndex = zValue;
+		if (olIe4&&!olOp) objRef.left = objRef.top = '0px';
+		else objRef.left = objRef.top =  -10000 + (!olNs4 ? 'px' : 0);
+	}
+
+	return divContainer;
+}
+
+// get reference to a layer with ID=id
+function layerReference(id) {
+	return (olNs4 ? o3_frame.document.layers[id] : (document.all ? o3_frame.document.all[id] : o3_frame.document.getElementById(id)));
+}
+////////
+//  UTILITY FUNCTIONS
+////////
+
+// Checks if something is a function.
+function isFunction(fnRef) {
+	var rtn = true;
+
+	if (typeof fnRef == 'object') {
+		for (var i = 0; i < fnRef.length; i++) {
+			if (typeof fnRef[i]=='function') continue;
+			rtn = false;
+			break;
+		}
+	} else if (typeof fnRef != 'function') {
+		rtn = false;
+	}
+	
+	return rtn;
+}
+
+// Converts an array into an argument string for use in eval.
+function argToString(array, strtInd, argName) {
+	var jS = strtInd, aS = '', ar = array;
+	argName=(argName ? argName : 'ar');
+	
+	if (ar.length > jS) {
+		for (var k = jS; k < ar.length; k++) aS += argName+'['+k+'], ';
+		aS = aS.substring(0, aS.length-2);
+	}
+	
+	return aS;
+}
+
+// Places a hook in the correct position in a hook point.
+function reOrder(hookPt, fnRef, order) {
+	var newPt = new Array(), match, i, j;
+
+	if (!order || typeof order == 'undefined' || typeof order == 'number') return hookPt;
+	
+	if (typeof order=='function') {
+		if (typeof fnRef=='object') {
+			newPt = newPt.concat(fnRef);
+		} else {
+			newPt[newPt.length++]=fnRef;
+		}
+		
+		for (i = 0; i < hookPt.length; i++) {
+			match = false;
+			if (typeof fnRef == 'function' && hookPt[i] == fnRef) {
+				continue;
+			} else {
+				for(j = 0; j < fnRef.length; j++) if (hookPt[i] == fnRef[j]) {
+					match = true;
+					break;
+				}
+			}
+			if (!match) newPt[newPt.length++] = hookPt[i];
+		}
+
+		newPt[newPt.length++] = order;
+
+	} else if (typeof order == 'object') {
+		if (typeof fnRef == 'object') {
+			newPt = newPt.concat(fnRef);
+		} else {
+			newPt[newPt.length++] = fnRef;
+		}
+		
+		for (j = 0; j < hookPt.length; j++) {
+			match = false;
+			if (typeof fnRef == 'function' && hookPt[j] == fnRef) {
+				continue;
+			} else {
+				for (i = 0; i < fnRef.length; i++) if (hookPt[j] == fnRef[i]) {
+					match = true;
+					break;
+				}
+			}
+			if (!match) newPt[newPt.length++]=hookPt[j];
+		}
+
+		for (i = 0; i < newPt.length; i++) hookPt[i] = newPt[i];
+		newPt.length = 0;
+		
+		for (j = 0; j < hookPt.length; j++) {
+			match = false;
+			for (i = 0; i < order.length; i++) {
+				if (hookPt[j] == order[i]) {
+					match = true;
+					break;
+				}
+			}
+			if (!match) newPt[newPt.length++] = hookPt[j];
+		}
+		newPt = newPt.concat(order);
+	}
+
+	hookPt = newPt;
+
+	return hookPt;
+}
+
+////////
+//  PLUGIN ACTIVATION FUNCTIONS
+////////
+
+// Runs plugin functions to set runtime variables.
+function setRunTimeVariables(){
+	if (typeof runTime != 'undefined' && runTime.length) {
+		for (var k = 0; k < runTime.length; k++) {
+			runTime[k]();
+		}
+	}
+}
+
+// Runs plugin functions to parse commands.
+function parseCmdLine(pf, i, args) {
+	if (typeof cmdLine != 'undefined' && cmdLine.length) { 
+		for (var k = 0; k < cmdLine.length; k++) { 
+			var j = cmdLine[k](pf, i, args);
+			if (j >- 1) {
+				i = j;
+				break;
+			}
+		}
+	}
+
+	return i;
+}
+
+// Runs plugin functions to do things after parse.
+function postParseChecks(pf,args){
+	if (typeof postParse != 'undefined' && postParse.length) {
+		for (var k = 0; k < postParse.length; k++) {
+			if (postParse[k](pf,args)) continue;
+			return false;  // end now since have an error
+		}
+	}
+	return true;
+}
+
+
+////////
+//  PLUGIN REGISTRATION FUNCTIONS
+////////
+
+// Registers commands and creates constants.
+function registerCommands(cmdStr) {
+	if (typeof cmdStr!='string') return;
+
+	var pM = cmdStr.split(',');
+	pms = pms.concat(pM);
+
+	for (var i = 0; i< pM.length; i++) {
+		eval(pM[i].toUpperCase()+'='+pmCount++);
+	}
+}
+
+// Registers no-parameter commands
+function registerNoParameterCommands(cmdStr) {
+	if (!cmdStr && typeof cmdStr != 'string') return;
+	pmt=(!pmt) ? cmdStr : pmt + ',' + cmdStr;
+}
+
+// Register a function to hook at a certain point.
+function registerHook(fnHookTo, fnRef, hookType, optPm) {
+	var hookPt, last = typeof optPm;
+	
+	if (fnHookTo == 'plgIn'||fnHookTo == 'postParse') return;
+	if (typeof hookPts[fnHookTo] == 'undefined') hookPts[fnHookTo] = new FunctionReference();
+
+	hookPt = hookPts[fnHookTo];
+
+	if (hookType != null) {
+		if (hookType == FREPLACE) {
+			hookPt.ovload = fnRef;  // replace normal overlib routine
+			if (fnHookTo.indexOf('ol_content_') > -1) hookPt.alt[pms[CSSOFF-1-pmStart]]=fnRef; 
+
+		} else if (hookType == FBEFORE || hookType == FAFTER) {
+			var hookPt=(hookType == 1 ? hookPt.before : hookPt.after);
+
+			if (typeof fnRef == 'object') {
+				hookPt = hookPt.concat(fnRef);
+			} else {
+				hookPt[hookPt.length++] = fnRef;
+			}
+
+			if (optPm) hookPt = reOrder(hookPt, fnRef, optPm);
+
+		} else if (hookType == FALTERNATE) {
+			if (last=='number') hookPt.alt[pms[optPm-1-pmStart]] = fnRef;
+		} else if (hookType == FCHAIN) {
+			hookPt = hookPt.chain; 
+			if (typeof fnRef=='object') hookPt=hookPt.concat(fnRef); // add other functions 
+			else hookPt[hookPt.length++]=fnRef;
+		}
+
+		return;
+	}
+}
+
+// Register a function that will set runtime variables.
+function registerRunTimeFunction(fn) {
+	if (isFunction(fn)) {
+		if (typeof fn == 'object') {
+			runTime = runTime.concat(fn);
+		} else {
+			runTime[runTime.length++] = fn;
+		}
+	}
+}
+
+// Register a function that will handle command parsing.
+function registerCmdLineFunction(fn){
+	if (isFunction(fn)) {
+		if (typeof fn == 'object') {
+			cmdLine = cmdLine.concat(fn);
+		} else {
+			cmdLine[cmdLine.length++] = fn;
+		}
+	}
+}
+
+// Register a function that does things after command parsing. 
+function registerPostParseFunction(fn){
+	if (isFunction(fn)) {
+		if (typeof fn == 'object') {
+			postParse = postParse.concat(fn);
+		} else {
+			postParse[postParse.length++] = fn;
+		}
+	}
+}
+
+////////
+//  PLUGIN REGISTRATION FUNCTIONS
+////////
+
+// Runs any hooks registered.
+function runHook(fnHookTo, hookType) {
+	var l = hookPts[fnHookTo], k, rtnVal = null, optPm, arS, ar = runHook.arguments;
+
+	if (hookType == FREPLACE) {
+		arS = argToString(ar, 2);
+
+		if (typeof l == 'undefined' || !(l = l.ovload)) rtnVal = eval(fnHookTo+'('+arS+')');
+		else rtnVal = eval('l('+arS+')');
+
+	} else if (hookType == FBEFORE || hookType == FAFTER) {
+		if (typeof l != 'undefined') {
+			l=(hookType == 1 ? l.before : l.after);
+	
+			if (l.length) {
+				arS = argToString(ar, 2);
+				for (var k = 0; k < l.length; k++) eval('l[k]('+arS+')');
+			}
+		}
+	} else if (hookType == FALTERNATE) {
+		optPm = ar[2];
+		arS = argToString(ar, 3);
+
+		if (typeof l == 'undefined' || (l = l.alt[pms[optPm-1-pmStart]]) == 'undefined') {
+			rtnVal = eval(fnHookTo+'('+arS+')');
+		} else {
+			rtnVal = eval('l('+arS+')');
+		}
+	} else if (hookType == FCHAIN) {
+		arS=argToString(ar,2);
+		l=l.chain;
+
+		for (k=l.length; k > 0; k--) if((rtnVal=eval('l[k-1]('+arS+')'))!=void(0)) break;
+	}
+
+	return rtnVal;
+}
+
+////////
+// OBJECT CONSTRUCTORS
+////////
+
+// Object for handling hooks.
+function FunctionReference() {
+	this.ovload = null;
+	this.before = new Array();
+	this.after = new Array();
+	this.alt = new Array();
+	this.chain = new Array();
+}
+
+// Object for simple access to the overLIB version used.
+// Examples: simpleversion:351 major:3 minor:5 revision:1
+function Info(version, prerelease) {
+	this.version = version;
+	this.prerelease = prerelease;
+
+	this.simpleversion = Math.round(this.version*100);
+	this.major = parseInt(this.simpleversion / 100);
+	this.minor = parseInt(this.simpleversion / 10) - this.major * 10;
+	this.revision = parseInt(this.simpleversion) - this.major * 100 - this.minor * 10;
+	this.meets = meets;
+}
+
+// checks for Core Version required
+function meets(reqdVersion) {
+	return (!reqdVersion) ? false : this.simpleversion >= Math.round(100*parseFloat(reqdVersion));
+}
+
+
+////////
+// STANDARD REGISTRATIONS
+////////
+registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSOFF);
+registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSOFF);
+registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSOFF);
+registerHook("ol_content_simple", ol_content_simple, FALTERNATE, CSSCLASS);
+registerHook("ol_content_caption", ol_content_caption, FALTERNATE, CSSCLASS);
+registerHook("ol_content_background", ol_content_background, FALTERNATE, CSSCLASS);
+registerPostParseFunction(checkPositionFlags);
+registerHook("hideObject", nbspCleanup, FAFTER);
+registerHook("horizontalPlacement", horizontalPlacement, FCHAIN);
+registerHook("verticalPlacement", verticalPlacement, FCHAIN);
+if (olNs4||(olIe5&&isMac)||olKq) olLoaded=1;
+registerNoParameterCommands('sticky,autostatus,autostatuscap,fullhtml,hauto,vauto,closeclick,wrap,followmouse,mouseoff,compatmode');
+///////
+// ESTABLISH MOUSECAPTURING
+///////
+
+// Capture events, alt. diffuses the overlib function.
+var olCheckMouseCapture=true;
+if ((olNs4 || olNs6 || olIe4)) {
+	olMouseCapture();
+} else {
+	overlib = no_overlib;
+	nd = no_overlib;
+	ver3fix = true;
+}
diff --git a/cgview/src/ca/ualberta/stothard/cgview/includes/stylesheet.css b/cgview/src/ca/ualberta/stothard/cgview/includes/stylesheet.css
new file mode 100644
index 0000000..67304a8
--- /dev/null
+++ b/cgview/src/ca/ualberta/stothard/cgview/includes/stylesheet.css
@@ -0,0 +1,19 @@
+/* Paul Stothard, University of Alberta 2004 */
+
+body {background-color: #FFFFFF; font-family: arial, sans-serif; color: #000000;}
+span.note {font-size: medium; font-style: italic; font-weight: bold;}
+span.comment {font-size: small; font-style: italic;}
+span.validInfo {font-size: x-small;}
+span.fileSize {font-size: x-small;}
+span.warning {font-size: x-small; color: red;}
+div.heading {color: #FFFFFF; background-color: #6666FF; font-size: large; padding: 0.1cm;}
+div.title {font-size: x-large; text-align: center;}
+table.noBorder {border-style: none;}
+table.border {border-style: solid;}
+td.center {text-align: center; font-size: small;}
+td.left {text-align: left; font-size: small;}
+td.right {text-align: right; font-size: small;}	
+a:link {color: #000099; text-decoration: none;}
+a:visited {color: #000099; text-decoration: none;}
+a:active {color: #FF0000; text-decoration: underline;}
+a:hover {color: #FF0000; text-decoration: underline;}
diff --git a/default-BRIG.xml b/default-BRIG.xml
new file mode 100644
index 0000000..8b77527
--- /dev/null
+++ b/default-BRIG.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/errorlog.xml b/errorlog.xml
new file mode 100644
index 0000000..b12d3f4
--- /dev/null
+++ b/errorlog.xml
@@ -0,0 +1,760 @@
+2011/06/27 11:40:56
+free memory: 15,120
+2011/06/27 11:40:56
+allocated memory: 15,872
+2011/06/27 11:40:56
+max memory: 253,440
+2011/06/27 11:40:56
+total free memory: 252,688
+2011/06/27 11:40:57
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
+2011/06/27 11:41:00
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
+2011/06/27 11:41:03
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+</BRIG>
+
+2011/06/27 11:41:10
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+</BRIG>
+
+2011/06/27 11:41:10
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="null" />
+</BRIG>
+
+2011/06/27 11:41:10
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="null" />
+</BRIG>
+
+2011/06/27 11:41:16
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="null" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:16
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="null" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:23
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:23
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="null" position="1" />
+</BRIG>
+
+2011/06/27 11:41:23
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="null" position="1" />
+</BRIG>
+
+2011/06/27 11:41:23
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="null" position="1" />
+</BRIG>
+
+2011/06/27 11:41:23
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="null" position="1" />
+</BRIG>
+
+2011/06/27 11:41:28
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:28
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="null" position="2" />
+</BRIG>
+
+2011/06/27 11:41:28
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="null" position="2" />
+</BRIG>
+
+2011/06/27 11:41:29
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="null" position="2" />
+</BRIG>
+
+2011/06/27 11:41:29
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="null" position="2" />
+</BRIG>
+
+2011/06/27 11:41:37
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:37
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:39
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:41:39
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:42:18
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:42:18
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:42:26
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+</BRIG>
+
+2011/06/27 11:42:26
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="161,221,231" name="null" position="3" />
+</BRIG>
+
+2011/06/27 11:42:26
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="161,221,231" name="null" position="3" />
+</BRIG>
+
+2011/06/27 11:44:04
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="161,221,231" name="null" position="3">
+    <feature label="ECs0350" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="368426" stop="369520" label="368426" />
+    </feature>
+    <feature label="ECs0362" colour="red" decoration="clockwise-arrow">
+      <featureRange start="379734" stop="383717" />
+    </feature>
+    <feature label="ECs0548" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="606274" stop="607290" />
+    </feature>
+    <feature label="ECs1360" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="1418370" stop="1420460" />
+    </feature>
+    <feature label="ECs1396" colour="red" decoration="clockwise-arrow">
+      <featureRange start="1444150" stop="1446999" />
+    </feature>
+    <feature label="ECs2107" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2108065" stop="2108979" />
+    </feature>
+    <feature label="ECs2116" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2116580" stop="2117980" />
+    </feature>
+    <feature label="ECs2567" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2543482" stop="2544468" />
+    </feature>
+    <feature label="ECs5279" colour="red" decoration="clockwise-arrow">
+      <featureRange start="5403699" stop="5404601" />
+    </feature>
+  </ring>
+</BRIG>
+
+2011/06/27 11:44:04
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="161,221,231" name="null" position="3">
+    <feature label="ECs0350" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="368426" stop="369520" label="368426" />
+    </feature>
+    <feature label="ECs0362" colour="red" decoration="clockwise-arrow">
+      <featureRange start="379734" stop="383717" />
+    </feature>
+    <feature label="ECs0548" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="606274" stop="607290" />
+    </feature>
+    <feature label="ECs1360" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="1418370" stop="1420460" />
+    </feature>
+    <feature label="ECs1396" colour="red" decoration="clockwise-arrow">
+      <featureRange start="1444150" stop="1446999" />
+    </feature>
+    <feature label="ECs2107" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2108065" stop="2108979" />
+    </feature>
+    <feature label="ECs2116" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2116580" stop="2117980" />
+    </feature>
+    <feature label="ECs2567" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2543482" stop="2544468" />
+    </feature>
+    <feature label="ECs5279" colour="red" decoration="clockwise-arrow">
+      <featureRange start="5403699" stop="5404601" />
+    </feature>
+  </ring>
+  <ring colour="49,34,221" name="null" position="4" />
+</BRIG>
+
+2011/06/27 11:44:04
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" outputFolder="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples" blastPlus="yes">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="172,14,225" Ring2="222,149,220" Ring3="161,221,231" Ring4="49,34,221" Ring5="116,152,226" Ring6="224,206,38" Ring7="40,191,140" Ring8="158,223,139" Ring9="226,38,122" Ring10="211,41,77" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk,gb,genbank" fastaFiles="fna,faa,fas,fasta,fa" emblFiles="embl" blastLocation="" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+  <refDir location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples">
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\BRIGExample.graph" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\Ecoli_O126.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\EHEC_vir.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_CFT073.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_HS.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_O157H7Sakai.gbk" />
+    <refFile location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_UTI89.fna" />
+  </refDir>
+  <ring position="0" colour="172,14,225" name="K12 MG1665" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn">
+    <sequence location="C:\BRIG_examples\Chapter5_6_8_wholeGenomeExamples\E_coli_K12MG1655.fna" />
+  </ring>
+  <ring colour="172,14,225" name="CFT073" position="1" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="222,149,220" name="UTI89" position="2" upperInt="70" lowerInt="50" legend="yes" size="30" labels="no" blastType="blastn" />
+  <ring colour="161,221,231" name="null" position="3">
+    <feature label="ECs0350" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="368426" stop="369520" label="368426" />
+    </feature>
+    <feature label="ECs0362" colour="red" decoration="clockwise-arrow">
+      <featureRange start="379734" stop="383717" />
+    </feature>
+    <feature label="ECs0548" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="606274" stop="607290" />
+    </feature>
+    <feature label="ECs1360" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="1418370" stop="1420460" />
+    </feature>
+    <feature label="ECs1396" colour="red" decoration="clockwise-arrow">
+      <featureRange start="1444150" stop="1446999" />
+    </feature>
+    <feature label="ECs2107" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2108065" stop="2108979" />
+    </feature>
+    <feature label="ECs2116" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2116580" stop="2117980" />
+    </feature>
+    <feature label="ECs2567" colour="red" decoration="counterclockwise-arrow">
+      <featureRange start="2543482" stop="2544468" />
+    </feature>
+    <feature label="ECs5279" colour="red" decoration="clockwise-arrow">
+      <featureRange start="5403699" stop="5404601" />
+    </feature>
+  </ring>
+  <ring colour="49,34,221" name="null" position="4" />
+</BRIG>
+
diff --git a/profiles/Eight_rings.xml b/profiles/Eight_rings.xml
new file mode 100644
index 0000000..cd4897d
--- /dev/null
+++ b/profiles/Eight_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2300" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Eight_rings.xml.jpg b/profiles/Eight_rings.xml.jpg
new file mode 100644
index 0000000..13bd96c
Binary files /dev/null and b/profiles/Eight_rings.xml.jpg differ
diff --git a/profiles/Fifteen_rings.xml b/profiles/Fifteen_rings.xml
new file mode 100644
index 0000000..9e0774a
--- /dev/null
+++ b/profiles/Fifteen_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="3600" isLinear="false" labelFont="SansSerif,plain,30" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="60" defaultMinimum="60" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Fifteen_rings.xml.jpg b/profiles/Fifteen_rings.xml.jpg
new file mode 100644
index 0000000..ea06b74
Binary files /dev/null and b/profiles/Fifteen_rings.xml.jpg differ
diff --git a/profiles/Five_rings.xml b/profiles/Five_rings.xml
new file mode 100644
index 0000000..5cfa6fa
--- /dev/null
+++ b/profiles/Five_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2200" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Five_rings.xml.jpg b/profiles/Five_rings.xml.jpg
new file mode 100644
index 0000000..971236d
Binary files /dev/null and b/profiles/Five_rings.xml.jpg differ
diff --git a/profiles/Four_rings.xml b/profiles/Four_rings.xml
new file mode 100644
index 0000000..79c0fab
--- /dev/null
+++ b/profiles/Four_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2000" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Four_rings.xml.jpg b/profiles/Four_rings.xml.jpg
new file mode 100644
index 0000000..ac296cd
Binary files /dev/null and b/profiles/Four_rings.xml.jpg differ
diff --git a/profiles/Nine_rings.xml b/profiles/Nine_rings.xml
new file mode 100644
index 0000000..77f1918
--- /dev/null
+++ b/profiles/Nine_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2400" isLinear="false" labelFont="SansSerif,plain,30" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Nine_rings.xml.jpg b/profiles/Nine_rings.xml.jpg
new file mode 100644
index 0000000..596d369
Binary files /dev/null and b/profiles/Nine_rings.xml.jpg differ
diff --git a/profiles/One_ring.xml b/profiles/One_ring.xml
new file mode 100644
index 0000000..e17f856
--- /dev/null
+++ b/profiles/One_ring.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="1700" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/One_ring.xml.jpg b/profiles/One_ring.xml.jpg
new file mode 100644
index 0000000..470a3a2
Binary files /dev/null and b/profiles/One_ring.xml.jpg differ
diff --git a/profiles/Seven_rings.xml b/profiles/Seven_rings.xml
new file mode 100644
index 0000000..5cfa6fa
--- /dev/null
+++ b/profiles/Seven_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2200" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Seven_rings.xml.jpg b/profiles/Seven_rings.xml.jpg
new file mode 100644
index 0000000..330f13a
Binary files /dev/null and b/profiles/Seven_rings.xml.jpg differ
diff --git a/profiles/Six_rings.xml b/profiles/Six_rings.xml
new file mode 100644
index 0000000..5cfa6fa
--- /dev/null
+++ b/profiles/Six_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2200" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Six_rings.xml.jpg b/profiles/Six_rings.xml.jpg
new file mode 100644
index 0000000..cc0f033
Binary files /dev/null and b/profiles/Six_rings.xml.jpg differ
diff --git a/profiles/Ten_rings.xml b/profiles/Ten_rings.xml
new file mode 100644
index 0000000..9145423
--- /dev/null
+++ b/profiles/Ten_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="2500" isLinear="false" labelFont="SansSerif,plain,30" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Ten_rings.xml.jpg b/profiles/Ten_rings.xml.jpg
new file mode 100644
index 0000000..cc6b483
Binary files /dev/null and b/profiles/Ten_rings.xml.jpg differ
diff --git a/profiles/Three_rings.xml b/profiles/Three_rings.xml
new file mode 100644
index 0000000..9c41e4f
--- /dev/null
+++ b/profiles/Three_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="1900" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Three_rings.xml.jpg b/profiles/Three_rings.xml.jpg
new file mode 100644
index 0000000..5802c52
Binary files /dev/null and b/profiles/Three_rings.xml.jpg differ
diff --git a/profiles/Twenty_rings.xml b/profiles/Twenty_rings.xml
new file mode 100644
index 0000000..50b90d8
--- /dev/null
+++ b/profiles/Twenty_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="700" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="4500" isLinear="false" labelFont="SansSerif,plain,30" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="60" defaultMinimum="60" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Twenty_rings.xml.jpg b/profiles/Twenty_rings.xml.jpg
new file mode 100644
index 0000000..fc043d9
Binary files /dev/null and b/profiles/Twenty_rings.xml.jpg differ
diff --git a/profiles/Two_ring.xml b/profiles/Two_ring.xml
new file mode 100644
index 0000000..c185ecb
--- /dev/null
+++ b/profiles/Two_ring.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="1700" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="/Users/nabil/bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Two_rings.xml b/profiles/Two_rings.xml
new file mode 100644
index 0000000..e17f856
--- /dev/null
+++ b/profiles/Two_rings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<BRIG blastOptions="" legendPosition="upper-right" queryFile="" outputFolder="">
+  <cgview_settings arrowheadLength="medium" backboneColor="black" backboneRadius="600" backboneThickness="medium" backgroundColor="white" borderColor="black" featureSlotSpacing="medium" featureThickness="30" giveFeaturePositions="false" globalLabel="true" height="1700" isLinear="false" labelFont="SansSerif,plain,25" labelLineLength="medium" labelLineThickness="medium" labelPlacementQuality="best" labelsToKeep="1000" longTickColor="black" minimumFeatureLength="medium" moveInnerLabelsToOut [...]
+  <brig_settings Ring1="102,0,102" Ring2="0,102,102" Ring3="0,102,0" Ring4="0,0,153" Ring5="102,102,0" Ring6="0,153,0" Ring7="204,51,0" Ring8="0,102,102" Ring9="0,153,102" Ring10="204,0,51" defaultUpper="70" defaultLower="50" defaultMinimum="50" genbankFiles="gbk" fastaFiles="fna,faa,fas" emblFiles="embl" blastLocation="C:\PHD\source\BRIG\bin" divider="3" multiplier="3" memory="1500" defaultSpacer="0" />
+  <special value="GC Content" />
+  <special value="GC Skew" />
+</BRIG>
+
diff --git a/profiles/Two_rings.xml.jpg b/profiles/Two_rings.xml.jpg
new file mode 100644
index 0000000..ee4d83d
Binary files /dev/null and b/profiles/Two_rings.xml.jpg differ
diff --git a/proteins.txt b/proteins.txt
new file mode 100644
index 0000000..7a942ba
--- /dev/null
+++ b/proteins.txt
@@ -0,0 +1,64 @@
+TTT	F	Phe
+TCT	S	Ser
+TAT	Y	Tyr
+TGT	C	Cys
+TTC	F	Phe
+TCC	S	Ser
+TAC	Y	Tyr
+TGC	C	Cys
+TTA	L	Leu
+TCA	S	Ser
+TAA	*	STOP
+TGA	*	STOP
+TTG	L	Leu
+TCG	S	Ser
+TAG	*	STOP
+TGG	W	Trp
+CTT	L	Leu
+CCT	P	Pro
+CAT	H	His
+CGT	R	Arg
+CTC	L	Leu
+CCC	P	Pro
+CAC	H	His
+CGC	R	Arg
+CTA	L	Leu
+CCA	P	Pro
+CAA	Q	Gln
+CGA	R	Arg
+CTG	L	Leu
+CCG	P	Pro
+CAG	Q	Gln
+CGG	R	Arg
+ATT	I	Ile
+ACT	T	Thr
+AAT	N	Asn
+AGT	S	Ser
+ATC	I	Ile
+ACC	T	Thr
+AAC	N	Asn
+AGC	S	Ser
+ATA	I	Ile
+ACA	T	Thr
+AAA	K	Lys
+AGA	R	Arg
+ATG	M	Met
+ACG	T	Thr
+AAG	K	Lys
+AGG	R	Arg
+GTT	V	Val
+GCT	A	Ala
+GAT	N	Asp
+GGT	G	Gly
+GTC	V	Val
+GCC	A	Ala
+GAC	D	Asp
+GGC	G	Gly
+GTA	V	Val
+GCA	A	Ala
+GAA	E	Glu
+GGA	G	Gly
+GTG	V	Val
+GCG	A	Ala
+GAG	E	Glu
+GGG	G	Gly
\ No newline at end of file

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/brig.git



More information about the debian-med-commit mailing list